NSTextField set disabled text color - cocoa

I have a NSTextField which is enabled or disabled. I can set the textColor but this only has an effect on the color of the text while the text field is enabled.
Any ideas how to set the text color for the disabled state?
I already tried to subclass NSTextField and override the enable methods as suggested in Disable NSTextField without changing color of multi-colored text ... but that doesn't work for me. I guess because of the latest SDK supporting dark mode.

Simple approach is to override resignFirstResponder:
override func resignFirstResponder() -> Bool {
//change text color here...
return super.resignFirstResponder()
}
You can simply add your colour change code for whichever controls you like here...
As stated by Apple:
The default implementation returns true, resigning first responder status. You can override this method in your custom responders to update your object's state or perform other actions, such as removing the highlight from a selection. You can also return false, refusing to relinquish first responder status. If you override this method, you must call super (the superclass implementation) at some point in your code.

Related

How to detach NSTextView's undo manager from NSDocument?

I have an NSDocument that is in a non-directly editable format, it's a description of something in XML. The NSWindow has a settings view controller associated with it which manipulates the data in the document just fine, undo works as expected, save, etc. Now also in the NSWindow is an NSTextView, which the user can enter some text into, but is not part of the content of the document, it's used only as temporary text. Of course I want to support undo for this text too, so I have the "Undo" checkmark enabled in Interface Builder for this NSTextView, and undo works just fine.
Now comes the rub: the NSDocument is getting marked as dirty when the NSTextView is modified. Because this is temporary text, I don't want the user to be nagged to save changes to the document, that really are not part of the document.
How do I detach the NSTextView from the responder chain leading up to the NSDocument's undo manager instance? Simply providing a new instance of NSUndoManager doesn't solve it, because it just goes up the responder chain to NSDocument as well.
extension InputViewController: NSTextViewDelegate {
func undoManager(for view: NSTextView) -> UndoManager? {
return myUndoManager
}
}
I'm pretty sure you'd need to override the undoManager property of the window's view controller, not the text field's delegate.
However, to simply make your document/window permanently non-editable all you need to do is override either the documentEdited property so it always returns false, or override updateChangeCount so it ignores requests to record changes.
Thanks to James Bucanek's comment about overriding updateChangeCount, I was able to do something like this in my NSDocument subclass:
override func updateChangeCount(_ change: NSDocument.ChangeType) {
if !suppressChangeCount {
super.updateChangeCount(change)
} else {
suppressChangeCount = false
}
}
Thus allowing undo/redo to work in my InputViewController keycode handler without dirtying the document.

Incorrect NSCursor originating from background NSView

I wanted to change the cursor in my cocoa application. I've followed the example in this answer, with success.
I have an NSView, let's call it NSViewA, behind another NSView, NSViewB. NSViewA contains a subclassed NSButton where the cursor has been changed. NSViewA and NSViewB have the same superview. So something like this:
- NSWindow
- NSViewA
- NSButtonSubclass
- NSViewB
My problem is that when NSViewB is shown, and the cursor is ontop of NSViewB, but in the same x y coordinates of the NSButton behind NSViewB, the cursor changes to that specified in the NSButton subclass.
How do I stop this behaviour?
The reason for this layout is that I'm creating a 'lightbox' control. If you think something along the lines of the NSWindow greying out, and a centred box appearing showing an error message. That sort of thing.
I previously had a problem where you could still click buttons, etc, behind NSViewB. This was solved by suppressing mouseDown: and mouseUp:. I've tried doing something similar with other mouse-related events, such as mouseEntered: and mouseExited: with no luck.
Could you make the addition of your custom cursor rectangle contingent on the enabled status of your button? In other words, your resetCursorRects would look like this:
// MyButton.swift
override func resetCursorRects() {
if enabled {
addCursorRect(bounds, cursor: NSCursor.pointingHandCursor())
}
}
Whenever viewB is about to be shown, disable the button, and call for the rects belonging to your button to be invalidated. If you're using Swift, you could do this second bit in a property observer attached to the enabled property itself:
// MyButton.swift
override var enabled: Bool {
didSet {
window!.invalidateCursorRectsForView(self)
}
}
If you don't want your button to take on a disabled look, make the addCursorRect call contingent on some other flag.

Disable editing in NSTextView

I am trying to disable editing in NSTextView but there doesn't seem to be any option there.All the other types have enabled property which when set to false are non editable but is there any for NSTextView?
Please do not forget that a class inherits the methods of its superClass. The superClass of NSTextView is NSText. And there you find the method
(void)setEditable:(BOOL)flag
with the comment:
Controls whether the receiver allows the user to edit its text.
For SWIFT3, you need to set isEditable to false.
var isEditable: Bool
A Boolean value that controls whether the text views sharing the receiver’s layout manager allow the user to edit text.
https://developer.apple.com/documentation/appkit/nstextview#overview

How to get the source lists selection highlight to use the Dark Vibrancy appearance in OS X 10.10?

In OS X 10.10 source lists seem to use the light vibrancy appearance. In the Finder (and in some other third party applications, Things.app for example) the selected item in the source list is indicated by a dark vibrancy appearance. For example, see the Desktop row in the image below.
How can I replicate this behaviour? Do I need to use the delegate methods to specify the table row view,
-outlineView:rowViewForItem:
and attempt custom drawing myself or is there a more straight forward approach? If you make a standard source list UI in Xcode the default highlighting is remain the standard blue rectangle that we have seen in previous version of OS X.
After playing around for a while I found a way to accomplish this.
It turned out that I would get the "Finder highlight" style when using NSTableViewSelectionHighlightStyleSourceList and clicking outside my NSOutlineView. So I figured it would stay that way if you refuse making it first responder.
Simply make your NSOutlineView a subclass and override this method:
-(BOOL)acceptsFirstResponder{
return NO;
}
It works, but with some downsides. For example, using arrow keys in the NSOutlineView will no longer work. I downloaded the Things app, and it does not allow use of arrow keys either, so it's very likely that this is how they are doing it. If anyone finds a better way, please post it.
Here is the Swift equivalent :
func outlineView(_ outlineView: NSOutlineView, rowViewForItem item: Any) -> NSTableRowView? {
return CustomTableRowView(frame: NSZeroRect);
}
And the subclass of NSTableRowView
import Cocoa
class CustomTableRowView: NSTableRowView {
override var isEmphasized: Bool {
set {}
get {
return false;
}
}
}
If you would like to keep arrow keys working, you can subclass NSTableRowView and override the following method:
- (BOOL)isEmphasized
{
return NO;
}
I am not sure, this is "Dark Vibrancy".
I would rather try setting the background color to something like "Alternate Selected Control Text Color"
Have a look at an NSTextField in InterfaceBuilder. there are many "Control Text" colors, which have a special appearance on visual effect views.
and for setting the selection color see this answer (untested):
NSTableview Change the highlight colour

Override key equivalent for NSButton in NSTextField

I have a window with two NSButtons and an NSTextField along with several views and several other controls. I assign the right and left arrows keys to each of the two NSButtons. The two buttons respond to the right and left arrow keys. However, when in the NSTextField, I want the arrow keys to perform as the normally would in a text field and not trigger the NSButtons. I have tried reading through the Cocoa Key Handling documentation and other questions regarding key events, but I could not find an example of trying change the key equivalent behavior in one control. I tried subclassing the NSTextField but couldn't trap the arrow keys. How can this be implemented?
You can override becomeFirstResponder: and in your implementation call setKeyEquivalent:. If you want to remove the key equivalent when the button loses first responder status, override resignFirstResponder:.
Do this in the control whose first-responder status you want to affect the button's equivalent. For example, if you have a view as a container and it can become first responder, you'd override -becomeFirstResponder: (calling super) then manage the button's equivalent there. If you don't yet understand these topics, you have a lot of prerequisite reading to do because a simple answer isn't possible here.
You could subclass NSButton and override performKeyEquivalent: like so:
override func performKeyEquivalent(event: NSEvent) -> Bool {
guard
let window = window where window.firstResponder.isKindOfClass(NSText.self) == false
else {
return false
}
return super.performKeyEquivalent(event)
}
This essentially disables the key equivalent if the first responder is a text field/view.

Resources