Cocoa HUD window - how to turn off topmost? - objective-c

I've wrote some small cocoa app and it's main window has HUD style.
The problem is - when I set HUD style Interface Builder automatically also sets Utility style - which make the main window topmost (always visible over every other windows). Is there a way to get HUD style panel/window but without making it topmost?

As it turns out - there's a pretty simple solution for my topmost problem:
[hudPanel setLevel: NSNormalWindowLevel];
Makes it act like a normal window that isn't topmost.

If you can't do it in IB, you'll have to do it programmatically. In this case, that means creating the window programmatically. (You'll want to move the window's views into a separate top-level view in the nib, and set that view as the programmatically-created window's content view.)
You should also file a bug report, as it doesn't seem from the NSPanel documentation that the HUD style necessarily implies the utility-window nature.

Related

OSX Cocoa using tab to navigate between child controls within a view not working

I am new to Xcode/OSX UI so there is probably something silly I'm overlooking. This is XCode 5.11 targeting OSX 10.10 desktop.
I have inherited some code with a few views where navigating among child controls within the view using the tab key does not work.
In researching this almost everything says to be sure to set the first responder and then chain your controls using nextKeyView.
I followed the steps in this video https://www.youtube.com/watch?v=SRrE8eqp0dU (XCode 4, but all the functionality seemed to be the same for 5.11) to no avail.
I also had a look at this solution How to make child controls of view will get focus on Tab and Shift+Tab in NSViewController which sounds like a similar issue to what I am seeing, but one of the classes I inherited uses NSWindowController vs. NSViewController as the base and there is no loadView to override and the other which did derive from NSViewController did not behave any differently with the changes made to loadView.
When my window launches my first responder control (NSTextField in this case) has focus (blue highlight) but tab key is ignored and focus will not change unless I use the mouse.
So it's really not a tab ordering issue initially, it seems like a tab ignored issue and who knows what the ordering is. I tried setting focus to a NSButtonCell and NSPopUpButton using the mouse and then tab navigate from those to see if there was some issue with my NSTextField but they exhibit the same behavior. None of the controls are set to "Refuses First Responder" which was another setting it was recommended to check.
I'm at a loss and looking for any other things to try or check.
The first view I am having an issue with is: Window / Child View / Multiple Child Boxes / Multiple controls per box in case that matters or complicates things. It is basically for setting application Preferences.
The second view seems like it may be more complicated in that there is a single Window that swaps out its child view in a next/back progression (wizard interface). The initial window nib is "blank" so I didn't see how to associate a first responder from IB like I did with the Preferences window since all the controls are on their own individual view nibs (these all show as "Custom View" vs. just "View" for Preferences).
The resolution for me was to ensure that the "Auto Recalculates View Loop" setting in the Attributes Inspector was enabled for the windows hosting these views. This corresponds to the autorecalculatesKeyViewLoop property of NSWindow.

NSWindow levels and modal dialogs

I have an application that needs to display a window on top of anythings else. To achieve this I call [window setLevel:NSStatusWindowLevel] on my main window.
This works fine except that I can't use any modal dialogs or alerts from this window. The problem seems to be that [NSWindow beginSheet...] internally calls setLevel: on the target modal window with a value lower than NSStatusWindowLevel, so the modal dialog is displayed behind its parent window. The same happens when using an NSAlert from a window with higher window level, the alert is displayed behind.
The only [ugly] workaround I found is to inherit NSWindow, override setLevel: and prevent setting a lower level value on these modal windows but this only works when I have control over the window and doesn't work for NSAlerts.
Is there a more elegant solution for displaying modal dialogs from a NSWindow with high window level value that will also work with NSAlerts? Or I will be unable to use NSAlert with this approach?
one thing that comes to mind is to check if NSAlert uses a special NSWindow subclass you could make a category on it and hook the setLevel: method via swizzling (here is an example of extending an existing method via swizzling). there is nothing stopping you from doing this in a plain NSWindow subclass either.
I know its not the "elegant solution" you'd hoped for, but its the only one I know off the top of my head. I suppose it is slightly more elegant in that you don't have to insert your custom subclass everywhere throughout your program, but less elegant in that you are messing with the objective-c runtime using code that simply seems wrong.

HUD window to stay within Application? Xcode

I will like a HUD window to be only dragged around in my application and it can not go out of it. Is there anyway or any other component that will allow me to have a sub-window and not be able to be dragged out of the applications boundaries.
Thanks.
Your question is a bit vague but it sounds like you want to constrain a window's frame so that it is never outside the boundaries of another window.
To do this you'd need to make your HUD window a custom subclass of NSWindow. You would then override ‑setFrame:display: and call super's implementation, passing in the frame that you want the window to use.

Drawing an "NSView" to a Custom-View - How? Am I taking the right approach?

I'm using Objective-C and Cocoa, whilst developing for Mac OS X - so not the iPhone/Cocoa Touch. (That said, I'd be interested if it was the same procedure for the iPhone)
I'm working on a preferences window for a simple app. I have a NSWindow with a toolbar - there are 5 different items on the toolbar, all of which need to bring up a different set of options.
So I set the NSToolbar and its items in Interface Builder, and then placed a custom view underneath the menu - taking up the rest of the window. My plan is to work out the interface too each of the NSToolbarItems options, and then draw the corresponding view on to the custom view when the specified NSToolbarItem is clicked.
I'm guessing that I simply create a NSView sub-class for each view, an empty xib in Interface Builder - set the xib to my custom NSView, code it as usual... But here's a few problems;
1 - Just how can I get the xib file to appear on the custom-view then? I have looked around and most articles don't seem to have this situation, or a situation I can relate too.
2 - When the window comes up, I want the default view to appear on the custom view. Once again, I'm guessing I just write that in the initialisation code for the NSWindow - its no big deal. It just goes back to question 1 though - how do I draw my NSView to the custom-view specified in Interface Builder?
I'd be really grateful for any help!
Cheers in advance.
So I set the NSToolbar and its items in Interface Builder, and then placed a custom view underneath the menu - taking up the rest of the window.
You can't have a menu inside of a window. You can have a pop-up button, which has a menu, but not a menu directly. Did you mean “toolbar” here?
You don't need to create a custom view for this. Make a tab view and set it to be tabless. Give it as many tab view items as you have toolbar items. In your controller, write an action method for each of the toolbar items, and in each action method, switch the active tab of the tab view.
You can activate different tabs in IB to populate them with views in IB. The active tab is saved in the nib, so make sure you set it back to the first tab before saving, so that the first tab is the one that's initially active when your app runs.
Just how can I get the xib file to appear on the custom-view then?
That question doesn't make sense.
Once again, I'm guessing I just write that in the initialisation code for the NSWindow - its no big deal.
You would only be able to do that if you have your own initialization code for the window, which you would only have if you have subclassed NSWindow. There are very few reasons to do that; unless you're making the window itself look different (not making an Aqua or HUD window), you should move that initialization code elsewhere, probably to the aforementioned controller (which should be the File's Owner of the nib).
It just goes back to question 1 though - how do I draw my NSView to the custom-view specified in Interface Builder?
A custom view in Interface Builder is a plain NSView (unless you explicitly change it to a subclass of NSView you create). However, you do not need one for anything you have described in your question.

How can I make an undecorated window in Cocoa?

I like to create a Cocoa window without any chrome whatsoever. The only thing the user should see is what I draw.
I've discovered I can create a custom NSView but does this have to be in an NSWindow to display? If not, how can I display it without putting it in an NSWindow? If it does have to be in an NSWindow, how do I stop the window from drawing a title bar and other chrome?
Check out the sample:
http://developer.apple.com/samplecode/RoundTransparentWindow/index.html
I've discovered I can create a custom NSView but does this have to be in an NSWindow to display?
Yes.
If it does have to be in an NSWindow, how do I stop the window from drawing a title bar and other chrome?
Use NSBorderlessWindowMask when you create your window. (Assuming you aren't using a custom subclass of NSWindow, this means not creating the window instance in a nib. If you want to lay out your view hierarchy in a nib, do that in a top-level custom view, then load the nib and set that view as the window's content view.)