Don't change NSButton appearance when pressed or disabled - objective-c

I have two NSButtons with images for both their on states and off states. Only one should be active at a time; click one and then click the other to change a property back and forth.
The problem is that if I disable a button when it's clicked so it cannot be clicked again, then the image is dimmed when the button is disabled--and I don't want it dimmed, I just want to use the alternate image.
On the other hand, if I just leave the button enabled, but programmatically just don't run any code when it is clicked, then there's a flashing effect as the mouse clicks--which is distracting, when the button should not do anything.
So I either need to prevent the button from being dimmed when it is disabled, or prevent it from changing the button appearance while the mouse button is held down.
After reading up, it sounds like I need to subclass NSButtonCell and override - (BOOL)imageDimsWhenDisabled to do the former. But I can't figure out exactly how to subclass it (what sort of NSButtonCell class I should inherit from) and if the "setCell" method of NSButton is enough to use the new NSButtonCell class, or if I need to subclass NSButton as well.
Some tips on that would be appreciated, or perhaps there's a completely different approach that would achieve my objectives.

Check this out:
[btnInfo.cell setImageDimsWhenDisabled:NO];

When you want to disable it without changing appearance do this:
On MacOS - NSButton:
Only option is to subclass NSButton and override mouseDown function
class RadioButton: NSButton {
override func mouseDown(with event: NSEvent) {}
}
On iOS - UIButton:
Simple disable UserInteraction
mybutton.isUserInteractionEnabled = false

For a more up to date answer in Swift, this works for me:
(theButton.cell! as! NSButtonCell).imageDimsWhenDisabled = false

Related

Vertical UICollectionView to UIButton focus in tvOS

I have a UICollectionView that scrolls vertically with about 15 cells. Then directly below this UICollectionView I have a UIButton. I can successfully focus the UIButton, but only if I scroll down through all of the UICollectionViewCells. I am wondering if it is possible to transition focus from the first UICollectionViewCell down to the UIButton without having to scroll through all of the UICollectionView's items?
A diagram of the desired behavior:
If you really want that behavior then you can return the button in the following function,
override var preferredFocusEnvironments: [UIFocusEnvironment]
And then subclass the following function,
override func shouldUpdateFocus(in context: UIFocusUpdateContext) -> Bool {
and return false when the focus is about to go to second cell and before returning call setNeedsFocusUpdate() which will make system check for preferred focus element and moves the focus to the button.
Really wonder why you are after this behavior 🤔, but its doable.
Did you try with canFocusAtItem to all other collectionView cells to false.
Then directly the focus will go the UIButton.

Show NSWindow on right click in NSTableView

I'd like to display an NSWindow when right clicking an item in an NSTableView, similarly to how the available outlets are shown in Interface Builder when you right click an object:
Unfortunately you can only use an NSMenu subclass as the menu property.
I also didn't find a delegate method of NSTableView that notifies about right clicks.
I was able to subclass NSTableView and implement rightMouseDown: and rightMouseUp: to be notified about those events, but if I set the menu property of the row cells to nil, they are not highlighted when right clicked, even though I call the super implementation):
- (void)rightMouseDown:(NSEvent *)theEvent {
[super rightMouseDown:theEvent];
NSPoint eventLocation = [theEvent locationInWindow];
eventLocation = [self convertPoint:eventLocation fromView:nil];
NSInteger rowIndex = [self rowAtPoint:eventLocation];
NSLog(#"Right clicked at row index %d", rowIndex);
}
I would like to have the highlight effect in the image below but display a window instead of the context menu:
First for the right click: explicitly select the row on right click (e.g. via this message). Then create your own NSWindow descendant, set an own NSView class as contentView and in the view you can draw the black background, rounded borders and what not. Show this window in your right click handler.
You can use an NSPopover, which works quite nicely. A popover creates a window for you, even if it is somewhat hidden. You'll get it from your controls if you send them the window message, and can register to listen for events, for instance.
The whole popover can be created in IB, and just have to implement the showRelativeToRect:ofView:preferredEdge: method in code.
To catch the right click event, you can use rightMouseDown:, which is originally defined in NSResponder, but is overridden in NSView to simply catch the event and show menu and it doesn't pass the event upwards in the responder chain (or the inheritance chain, for that matter). Hence, you simply implement that method to call showRelativeToRect:ofView:preferredEdge:.
You will typically need to have the contents in an NSViewController and its own accompanying nib file.
The NSPopover's contentViewController property can be set in IB, too.
All in all, not much code needed.
This tutorial is useful.

How to attach an object to the NSCursor? OSX

I want to attach a WebView to the cursor when the user hovers a button. And remove it when the mouse exits.
Even when the cursor moves inside the button I want to WebView to keep following the cursor.
Any ideas on how to perform this?
Here's an example on how it should be:
so you have a NSButton ... subclass THAT so you attach a view:
#interface ButtonWithWebViewOnHover : NSButton
#property(strong) WebView *webView;
#end
override mouseEntered and mouseExited there and toggle hidden
...... wait.... we seem to be reinventing the wheel
use NSPopover (from apple directly, but not as graphically flexible as the next:)
or MAAttachedWindow (http://mattgemmell.com/2007/10/03/maattachedwindow-nswindow-subclass/)
You can subclass WebView, and consider that to draw it this method is called:
- (void)drawRect:(NSRect)dirtyRect;
Ao if you call [super drawInRect: dirctyRect] in this method, the view will be normally drawn, otherwise nothing will be drawn.So you can see if the mouse is over the view and decide if to draw it or not.
To resize it, instead you can use this method:
- (void)setBounds:(NSRect)boundsRect;
To detect mouse events you shall implement methods like mouseDown (see NSResponder) in your main view.

NSStepper in NSTableCellView has no effect

I’m using a regular (not subclassed) NSTableCellView in a view-based table view. It has the initial image and text field views. I added an NSStepper to the view.
The text field is bound to tableCellView.objectValue.quantity.
The stepper’s value is bound to tableCellView.objectValue.quantity too.
The problem is that when running the app, when I click the stepper it doesn’t seem to get the mouse event, neither arrow gets highlighted, the value is not incremented or decremented.
If I set the double action of the table view it gets triggered if I double-click the stepper as if it was transparent.
What am I missing?
Thanks!
You should look at the documentation but easiest is that you need to subclass NSTableView and override this method to validate the proposed first responder. As the document states NSTableViews disallow some controls to be used unless the row is first selected. Even then it still may discard some.
- (BOOL)validateProposedFirstResponder:(NSResponder *)responder forEvent:(NSEvent *)event {
return YES;
}
Further to the correct answer from Robert Payne, with Swift you could add an extension to NSTableView and not subclass it.
extension NSTableView {
override public func validateProposedFirstResponder(responder: NSResponder, forEvent event: NSEvent?) -> Bool {
return true
}
}
And I'd like to emphasis that it's the NSTableView not the NSTableViewCell.

Click on NSTextField Label to emulate hyperlink to a folder

I have an NSTextField label and I want something to happen when a user clicks on it.
I thought I could create an IBAction and link this to the label but nothing seems to happen.
Any suggestions?
Intentions:
The reason why I am doing this is because I want a label that is a hyperlink to a folder. Perhaps I am taking the wrong approach altogether?
IBAction definition in my PersonController.m
- (IBAction)surnameLabelSelected:(id)sender {
NSLog(#"This should do something!");
}
XIB File
In the XIB file I have made a Received Actions connection between surnameLabelSelected and the StaticText NSTextField label.
You've got a couple options. Francis's answer is one option. Another option is to subclass NSTextField and override -mouseDown:. Something like this (written off the top of my head, not tested):
#interface ClickableTextField : NSTextField
#end
#implementation ClickableTextField
- (void)mouseDown:(NSEvent *)theEvent
{
[self sendAction:[self action] to:[self target]];
}
#end
If NSTextField is closer in style to the appearance you need, this might be the better approach. If you need NSButton's features (highlight upon click, etc) go with Francis's solution.
Labels are non-editable text fields thus don't send actions to their targets. You want to use an NSButton and turn off its border-drawing and size it to fit its text as best as possible to simulate a label.
Another option is to create a transparent button (without title/image/border, momentary push in) in front of the label, with the same frame as label's. And set button's action accordingly.