How to auto-activate cocoa window so you don't need to click twice? - macos

I have two windows: A main window and an inspector panel. Both have sliders and draggable items.
You have to click twice every time you work in the other window. First click activates the window. Second click allows a drag to start.
Is it possible to have a click in a window automatically activate it AND allow the event to pass through to the controls so you don't need to do it twice all the time when switching between an inspector panel and main window?

The first thing to try is to set the panel's becomesKeyOnlyIfNeeded property to true. That way, you main window will remain key even if the user clicks and drags on controls within the panel.
Otherwise, you have to handle this in each different view class. A view should override -acceptsFirstMouse: to return true if it wants to handle the same mouse event that activates the window. For custom view classes, this is straightforward. If you're using standard controls and they don't already implement -acceptsFirstMouse: to return true, you'll need to subclass them and use those subclasses instead.

Related

Drop-down menu in NSToolbar like Mail.app

I'd like a toolbar button with an attached dropdown menu, like the "Flag" button in the toolbar in Mail.app:
I'd hoped that making a normal NSMenuItem and adding a menu as the menuFormRepresentation would do the trick, but that menu only appears when the button goes into overflow mode.
I had also hoped that adding an NSPopupButton as a custom view would work, but that makes the whole view a menu, whereas I want the left part of the component to behave like a normal button, and the right dropdown part bring up the menu.
Is there some trick to making the NSToolbarItem show a component like this, or is this two custom views stuck together?
There's nothing magical about NSToolbar here. That's just one of the ways you can set up NSSegmentedControl, regardless of whether it appears as a toolbar item's custom view or on its own.
You can't set this up in Interface Builder (storyboard), but NSSegmentedControl has APIs for assigning menus to segments:
segmentControl.setMenu(myMenu, forSegment: 1)
segmentControl.setShowsMenuIndicator(true, forSegment: 1) // for the little arrow
You probably want to set the tracking mode to momentary, since your segment control is acting as a set of visually-connected buttons, not a choose-one-of-N selector.
When the user clicks either segment, your action method will need to use the selectedSegment to decide whether to perform the action associated with the "button" side or ignore the click (letting the menu show for the other side).

Close borderless floating NSWindow on click outside

I want to create a borderless window floating above the main window. The main window should be the key window (I want it to handle the keyboard and mouse events). Also, the floating window should close as the user clicks outside of it. Basically, I'm creating a very custom context menu, just like NSMenu. It should behave likewise.
So I created my window this way:
NSWindow *menuWindow = [NSWindow windowWithContentViewController:menuViewController];
menuWindow.styleMask = NSBorderlessWindowMask;
menuWindow.level = NSFloatingWindowLevel;
[menuWindow makeKeyAndOrderFront:self];
That works perfectly, but how do I handle clicks outside to close it? The window doesn't invoke delegate's windowDidResignKey, because it's not a key window. If it does overload canBecomeKeyWindow (so that it returns YES), then the floating window grabs the user input, which is not what I want.
So, is there any way to automatically close a borderless window? Can NSPanel help? I tried using it, but with no success (the becomesKeyOnlyIfNeeded selector doesn't do what I need).
To detect clicks outside the window but within your app, you could install an event monitor using +[NSEvent addLocalMonitorForEventsMatchingMask:handler:]. If you also want to close the window when the user clicks in a different app, you could observe the NSApplicationDidResignActiveNotification notification.
NSWindow has a property hidesOnDeactivate that should do this for you.
From the Apple Docs:
The value of this property is true if the window is removed from the
screen when its application is deactivated; false if it remains
onscreen. The default value for NSWindow is false; the default value
for NSPanel is true.

How make button in NSWindow clickable while a sheet's on top of it

I have created a custom (themed) NSWindow, by creating a borderless window and then recreating all elements of the window border/background inside the content view. I've created the window widgets (close box, zoom box, minimize box) on top of my own fake title bar using -standardWindowButton:forStyleMask:.
Trouble is, when a sheet is presented on top of my custom window (e.g. "save changes...", those buttons do not receive the clicks.
Does anybody know how I can tell NSWindow not to intercept the clicks in my minimize box? It works with a standard NSWindow. When a sheet is up, I can still send both of them to the dock, or zoom the window out.
I thought maybe there's special code in the content view that ignores clicks in subviews while a sheet is up. But it seems as if -hitTest: is called on the content view and returns the minimize widget, but the widget's action never gets triggered.
I guess I could just replace the content view and perform the action in the content view's hitTest if it is the minimize widget ... but that seems a bit ugly.

How to make a keyboard shortcut to close dialog with Xcode/Interface Builder?

This seems awfully basic but here goes. If you are keyboard-oriented you get used to using Command-W to close windows all the time in OS X. I'd like to add that capability to the dialogs I am creating in Interface Builder for my program. I can see how to add a keyboard equivalent to a button action but what if I don't have a button?
Should I add an invisible button and put the shortcut on that? Seems clunky. Surely there is just some method I can override but what I've tried so far isn't working.
When you press Command + W, it's the exact same as choosing File -> Close from the menu bar. What Close does is send a performClose: message to the first responder. That, in turn, will check if the receiver or if the receiver's delegate implements windowShouldClose:, and the window will close if it returns YES (otherwise, it will call the close method).
So really, it depends on what type of dialog you've got here. If it's non-modal (essentially, if you can access the menu bar while it's running) and is an instance or subclass of NSWindow, then all you need to do is override the windowShouldClose: method in your dialog's delegate (or your dialog class, if you subclassed NSWindow or something) and make it return YES.
However, if the dialog is a modal dialog (you can't access the menu bar, switch windows, etc. while the dialog is running), then you can't do it this way. You could add an invisible button, but in all honesty, a modal dialog should not be closed by hitting Command-W, for that most certainly violates some Apple interface guideline out there. (Especially since, as Ande noted, it's standard practice to have Esc close/cancel a dialog.)
Adding an invisible button works just fine.
Is the dialog an NSWindow? Because by default the File->Close menu option is set to the performClose: action of the first responder, and already wired to command-w
If the dialog isn't a window simply make your dialog first responder and implement the performClose: action.
why don't you try this:
-(void)keyDown:(NSEvent *)theEvent{
//If the key is X or x it just closes the window
if ([theEvent.characters.uppercaseString isEqualToString:#"X"]) {
[self.window performClose:self];
}
}
or if you want to show a window you can instanciate and show it there instead of the performClose
Jasper was right about the code part. For interface builder(storyboard), there is a quick fix:
In your storyboard, hit "CMD+Shift+L" to bring up the components lib, select File Menu Item.
Add the file menu item to the Application Scene's Main Menu Node. (Remove unwanted file menus)
Now you have a keyboard shortcut to close a window.

Launch window from NSView subclass in cocoa

Is it possible to launch a window in an NSView subclass by clicking a NSRect? I have tried makeKeyAndOrderFront but this doesn't work.
You can't click on a rectangle. A rectangle is just four numbers.
You can have an NSView that responds to clicks, but you should consider using NSButton instead. If you really want a custom view, you can both create the button and add it as a subview of your view programmatically. Then, set the button's target to yourself and its action to the selector of a message you'll respond to by opening the window.
One more thing: You don't launch a window. Windows aren't applications and applications aren't windows. On Mac OS X, applications have windows—always more than one (counting at least the About panel). So, you'll load the window from a nib, then make it key (respond to events) and order it front.
On that point: You probably should not have your view owning a window. Consider making a controller object to own the window instead, and having your view simply forward the message to the controller object (or even hook the button up to the controller directly).

Resources