How to disable text color in NSTextView? - macos

I have setup a NSColorPanel which I use to change the background color of a window. In the window there is also a NSTextView with some text in. The problem is that is that when I change the color of the background, the text color gets changed to into the same. I've tried finding ways to prevent this but with no success.

Override the NSTextView changeColor: method and in that method, keep a outlet to the backgeoundView and instead of changing the textView's own color send it to the outlet:
IBOutlet NSView *changeColorTarget;
...
- (IBAction)changeColor:(id)sender {
if(self.changeColorTarget) {
[NSApp sendAction:#selector(changeColor:) target:self.changeColorTarget forEvent:nil];
} else {
[super changeColor:sender];
}
}
--> that way the textview retains its original functionality except if you set the outlet

Related

How to change the action of NSColorWell?

I can use NSColorWell as button to change the color of selected text. Since NSColorWell is object of an NSControl it has target and action. I guess, the action is implementing the code to change the color of the selected text in NSTextView. Where can I find this code for NSColorWell action? I would like to change it in away that I can use NSColorWell to change the background of the selected text, and ultimately to have in ToolBar two NSColorWell buttons: one to change text's foreground color and second one for text's background color.
NSColorWell is just a rectangular control to change a color.
You can either create an IBAction and connect it to the action of the color well in the Connections Inspector (⌥⌘6) of Interface Builder
#IBAction func changeColor(_ sender : NSColorWell)
{
let color = sender.color
// do something with the color
}
Or bind the value in Bindings Inspector (⌥⌘7) of Interface Builder to a dynamic property, this example will set the color well to a default value of green.
dynamic var color : NSColor = .green {
didSet {
// do something with the color
}
}

NSTableView and scrolling background NSColor : Automatic Elasticity Color

I have succesfully changed the background NSColor of my NSTableView using setBackgroundColor: for both the NSTableView and the NSCell (using tableView: willDisplayCell:forTableColumn:row:). Now, I would like the background to also have this color when scrolling out (either top or bottom), which is currently white as pictured below.
I found this link which seems to indicate the need to subclass NSTableView and implement - (void)drawBackgroundInClipRect:(NSRect)clipRect, any suggestion on that ?
Source : Themeing NSTableView
I finally found the answer at the question by looking at the header file for the NSTableView class NSTableView.h and found a mention to this method :
/* Override to customize background drawing.
*/
- (void)drawBackgroundInClipRect:(NSRect)clipRect;
I then subclassed NSTableView and overrode the previous method :
#implementation MyColoredTableView
/**
Sets the color of the background for elastic scrollers
*/
- (void)drawBackgroundInClipRect:(NSRect)clipRect
{
[[NSColor redColor]set]; //Set your color here
NSRectFill(clipRect);
}
#end
Change the class of your NSTableView in InterfaceBuilder to MyColoredTableView, and you are done.
> Now, I would like the background to also have this color when > scrolling out (either top or bottom),
For this you need to have one method which will called when you scroll your scroll view. So for that just include this notification below:-
-(void)viewDidLoad
{
// This notification will called when you scroll your scrollview
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(boundsDidChange:) name:NSViewBoundsDidChangeNotification
object:[yourScrollView contentView]];
}
-(void)boundsDidChange:(NSNotification*)not
{
//Write your code for changing background colors of tableview
}

scrollRectToVisible UITextField doesn't scroll with Autolayout

[self.scrollView scrollRectToVisible:textField.bounds animated:YES];
I can't seem to get my UIScrollView to scroll at all so that it doesn't obscure my UITextField. I thought that scrollRectToVisible would be my savior but it looks like a no go. Maybe I'm missing something like translating the coordinates of my textField to my scrollView. Either way check out my sample project.
https://github.com/stevemoser/Programming-iOS-Book-Examples/tree/master/ch20p573scrollViewAutoLayout2
Oh, and this project might be missing the delegate connection but I checked that and it still doesn't scroll.
I've seen other questions similar to this but none that mention Autolayout.
I was having issues with scrollRectToVisible:: as well after converting to Auto Layout. I just changed it to a direct call to setContentOffset:: and it started working again.
I had the same problem, I wanted to scroll an autolayouted UITextEdit into view without making it the first responder.
For me the issue was that the bounds of the UITextField were set later on during the auto layout pass, so if you do it immediately after setting up the layout the bounds are not valid yet.
To workaround I did create a descendant of UITextField, did overwrite setBounds: and added a 0 timer to scroll into view "later on" (You can't scroll in that moment because the auto layout pass of the system might no be finished at that point)
#interface MyTextField: UITextField
{
bool _scrollIntoView;
}
..
#end
#implementation MyTextField
-(void)setBounds:(CGRect)bounds
{
bool empty=CGRectIsEmpty(self.bounds);
bool isFirstResponder=self.isFirstResponder;
[super setBounds:bounds];
if (empty && !isFirstResponder && _scrollIntoView)
[self performSelector:#selector(scrollIntoViewLater) withObject:nil afterDelay:0];
else if (empty && isFirstResponder)
[self performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0];
}
-(void)scrollIntoViewLater
{
CGRect r=[scrollView convertRect:self.bounds fromView:self];
[scrollView scrollRectToVisible:r animated:TRUE];
}
#end
If the field should be additionally editable with the on screen keyboard, simply call becomeFirstResponder later on: it scrolls automagically into view above the keyboard using the private scrollTextFieldToVisible API which in turn calls scrollRectToVisible:animated: of the scrollview.
Your sample link is broken btw...

How to disable white text color in selection in view-based NSTableView?

I'm using a view-based table view and don't want it to draw NSTextFields with white text color when it is selected.
I was not able to find a working solution. So any help is very appreciated.
Here is my problem:
I want the "Selection is white" text also be drawn in the default text color.
So far I figured out that
Setting attributes in tableView:viewForTableColumn:item: does not really help
Setting NSTextField color to a custom color, which is something different than the control default color, will prevent from drawing in white but it still looses font style (bold, italic, etc).
Setting NSTableView's selectionHighlightStyle attribute to NSTableViewSelectionHighlightStyleNone does the trick but it will not redraw NSTableRowView. Also the select style is not what I want. I want the first click to select the row and the second click to edit the text field. When you use NSTableViewSelectionHighlightStyleNone your first click starts editing the text field.
The text color does not change if the NSTextField is bordered. But I don't want bordered text fields (As shown in the screenshot. The text fields are editable)
I couldn't figure out 'how' the text field gets the white color. I have overridden setTextColor: and realized that it is never called when selection is changed. So I guess an NSAttributedString is built somewhere inside the NSTableView drawing/selecting routine.
Any help is very much appreciated.
I found the answer. I had to subclass NSTableCellView and override setBackgroundStyle:. That's all!
- (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle {
[super setBackgroundStyle: NSBackgroundStyleLight];
}
Instead of overriding NSTableCellView's backgroundStyle, I found it more convenient to override viewWillDraw() in NSTableRowView instead. This is actually the method that by default changes your cell view's background style during selection.
You would disable this behavior by:
class TableViewDelegate: NSObject, NSTableViewDelegate {
func tableView(tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
return TableRowView(frame: NSRect.zero)
}
}
class TableRowView : NSTableRowView {
private override func viewWillDraw() {
// By do nothing we prevent the super method to be called. It would otherwise change the selected cell view's backgroundStyle property.
}
}
I set cell colour in my table view delegate's -tableView:willDisplayCell:forTableColumn:row: method.
-(void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell
forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
if(tableView==<table view id of interest>)
{
...
[cell setTextColor:<colour appropriate for this cell>];
...
}
...
}
This does not affect font size or styling.

How to disable NSBox from code

I put several controls (button,textfield,...) in a NSBox. is it possible to disable NSBox that user can't access controls (means can't click on button or write in textfield)?
how about nsview ?
An NSBox is basically just a view with a border, there's no way to "disable" it. If you want to disable all the controls in a box, you could loop through all its subviews and disable them , or another way I've done this is to put an overlay view over the whole box and override mouseDown in that overlay (to capture any mouseDown events so they aren't queued in the event loop). You can also give the overlay a semi-transparent white color so the box has a disabled appearance.
Or, if you have a custom NSBox, you can override NSView's -hitTest: (conditionally)
- (NSView *)hitTest:(NSPoint)aPoint {
if (!enabled) return nil;
else return [super hitTest:aPoint];
}
To stop the window from sending events to all your subviews.
To provide visual feedback, conditionally drawing some sort of overlay in the custom NSBox's -drawRect method would work.
Yes, you just need to look at the subviews of the NSBox, which is typically just one NSView, and then your actual controls will be under the subviews of that.
Here's a quick C-style function I wrote to enable/disable most common UI controls, including NSBox...
void SetObjEnabled(NSObject * Obj, bool Enabled)
{
//Universal way to enable/disable a UI object, including NSBox contents
NSControl * C = (NSControl *)Obj;
if([C respondsToSelector:#selector(setEnabled:)])
[C setEnabled:Enabled];
if([C.className compare:#"NSTextField"] == NSOrderedSame)
{
NSTextField * Ct = (NSTextField*)C;
if(!Enabled)
[Ct setTextColor:[NSColor disabledControlTextColor]];
else //Enabled
[Ct setTextColor:[NSColor controlTextColor]];
}
else if([C.className compare:#"NSBox"] == NSOrderedSame)
{
NSBox * Cb = (NSBox*)C;
//There is typically just one subview at this level
for(NSView * Sub in Cb.subviews)
{
//Here is where we'll get the actual objects within the NSBox
for(NSView * SubSub in Sub.subviews)
SetObjEnabled(SubSub, Enabled);
}
}
}

Resources