Cocoa validate menu items in multiple windows - objective-c

I have a menu item "foobar" that i need to enable on my main window (app delegate), but disable on all other windows. I'd like to know how to do that, because the first responder business is very confusing to me. Here's what i have now:
"foobar" item is connected to first responder's "foobar:" custom action in MainMenu.xib
there is a "foobar:" action in the main app delegate so the menu item is enabled and works
now i load and "makeKeyAndOrderFront" another window
i focus some control on that new window
this is the place where my "foobar" item should be disabled, but it's not
I can see that the "validateMenuItem" is being called in the app delegate, but it's not being called in the second window's controller.
Could someone explain it to me in very simple terms why this is happening and what options i have to solve this?
Thanks for your thoughts

Set your app delegate as delegate of the main window, and implement these method:
- (void)windowDidBecomeKey:(NSNotification *)notification
{
[foobar setEnabled: YES];
}
- (void)windowDidResignKey:(NSNotification *)notification
{
[foobar setEnabled: NO];
}
About first responder
The first responder is a NSControl that is inside the window.For example on a particular window you have two text fields: textField1 and textField2.When you type the input goes just to the first responder (one between all the controls that accept the first responder).So what you need is to know which window is key, you don't need to know who is the first responder in your specific case.
EDIT
There is also another (maybe faster, but depends on personal preferences) way to do it: through interface builder, select the menu item that you want to make enabled only when a certain window is key.Let's suppose that this window is an ivar of the app delegate named window1.Then click on that menu item, go to the bindings inspector, under "enabled" select bind to: app delegate, model key path: self.window.isKeyWindow.
A little image hint:

Related

Apple Watch (WatchKit) push action

I am developing an app for the Apple Watch and I would like to use the action demonstrated at the launch event where the user pushes into the screen (rather than a tap). Do you know what this is called and how I can access this?
You can only show a menu on that action. You use addMenuItem methods on WKInterfaceController.
The gesture you are referring to is called a Force Touch.
It is possible to use Force Touch as an input method in third party apps. You cannot register to receive notifications of Force Touch events however; there is nothing equivalent to a UIGestureRecogniser in WatchKit at present.
When you have a contextual menu in the current screen of your WatchKit app, it will automatically be activated by the OS when the user initiates a force touch. You can simulate this in the Apple Watch simulator by a click and hold with the mouse... the resulting animation will make it clear when a Force Touch even has been initiated, even on screens that do not have a contextual menu enabled.
To utilise this via Interface Builder, you simply:
Drag a menu into the relevant Watch App scene in interface builder.
Add between one and four menu items to the menu by dragging those into the menu.
Set names and images for those menu items.
Wire those menu items to IBActions in your WatchKit Extension.
Alternatively, you can set and clear menu items programatically from your WatchKit Extension, as outlined in the WatchKit API documentation. There are four relevant WKInterfaceController methods. In Swift:
func addMenuItemWithItemIcon(_ itemIcon: WKMenuItemIcon,
title title: String,
action action: Selector)
func addMenuItemWithImageNamed(_ imageName: String,
title title: String,
action action: Selector)
func addMenuItemWithImage(_ image: UIImage,
title title: String,
action action: Selector)
func clearAllMenuItems()
In Objective-C:
- (void)addMenuItemWithItemIcon:(WKMenuItemIcon)itemIcon
title:(NSString *)title
action:(SEL)action
- (void)addMenuItemWithImageNamed:(NSString *)imageName
title:(NSString *)title
action:(SEL)action
- (void)addMenuItemWithImage:(UIImage *)image
title:(NSString *)title
action:(SEL)action
- (void)clearAllMenuItems
Full information is in the API documentation for Configuring the Contextual Menu in WatchKit.
The first time you do create one of these menus, particularly if you do it in Interface Builder, it may well feel like you must have missed a step, since you did not have to connect the menu to something equivalent to a force touch gesture recogniser, but when you try it, you'll just find it works. It may well be that this will continue to be the only access third party developers have to force touch, even after we have the ability to make native apps for the Watch later in 2015.
it is called a contextual menu. you can do that using addMenuItem or in storyboards you add a menu which comes with an item, and then add additional items.

View Controllers, Popup buttons, AppDelegates, Status Menus, and headaches

This is kinda long but I want to give as many details as possible.
I have created a status bar app. One of the things I've done is made it to where there is a "Settings" menu item that if you click on, an NSWindow pops up with 5 different buttons -- these buttons are tied to their own custom NSViewController so that if you click them, the View Controller changes, but the window remains the same, just like any other StatusBar app.
On one of the view controllers is a popup button with several user selectable options. If I add a button to the specific VC (view controller) and link that to an ibaction that pulls the selected index of the popup button, it works just fine (i.e. I select item 2, it logs item 2).
Now here's where things get. . . odd. I've created a submenu that would in theory allow the user to quickly change the selected item of the popup linked to my custom view controller. Think of this submenu as being labeled 1-4 and clicking one of those items would change the index of the popup button, however every time I try this and follow it up with a NSLog to ensure the button has changed, it ALWAYS reads zero, in other words, it NEVER changes.
Here's what I tried.
Just like with every other view controller I've ever used, I create a new object of my view controller (alloc, init), and reference the popup button object that i've created as a property. This compiles just fine, but returns only zero no matter what is selected.
I've tried calling the method that I know works (the button that is on the view controller containing the popup), but again, this returns only zero no matter what is selected.
Any advice would be greatly appreciated.
tl;dr: can't change a popupbutton on a view controller from the app delegate or nsstatusmenu item, it just always returns zero.
EDIT: I have found a work around since I can communicate to my app delegate just fine, I created an int property and set it to zero. From there, whenever my popupbutton on my VC changes, I change the value of the app delegate int property and just ensure that whenever the nib launches, it set's the selected item to the app delegate property. I feel there has to be a more straight forward way to just get the value of the popup and change it from the app delegate.
EDIT 2: Some code as requested. I realized I needed to point the the view controller by using initwithnibname from the app delegate and then load the view. Doing so allows me to pull the first object in the popup button, any subsequent changes are not recognized unless I do so via my test button on the view controller itself. Also, I'm adding values to my popup in my awakefromnib in the view controller.
searches_VC = [[Searches_ViewController alloc] initWithNibName:#"Searches_ViewController" bundle:nil];
[searches_VC loadView];
NSLog(#"Selected Title: %#",[[searches_VC profilePopupOutlet] titleOfSelectedItem]);

How to display or not a NIB-created view based on a condition

Currently, I have the following situation: I have a nib file that opens a menu, and has a unique main window. When this NIB-created view finishes the startup, the window is already initialized and displayed.
Besides starting the application with its normal way, I also want to start it in a particular way in which the window nor the menu are displayed.
I other words, I need to be able to define a condition at the startup of my application and based on that condition, I want to open/initialize/display the app using the normal view/nib or I want not to display them (but I may need to create/initialize the view).
Any ideas how can I do this?
Thanks
in the IB, go into the inspector and turn off 'visible at launch' for the main window.
THEN in your AppDelegate, check what to do: show the main window or make let it remain invisible and show the special window!
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
if (myCondition == TRUE) {
//do something else...
} else {
[[NSApp mainWindow] makeKeyAndOrderFront:nil];
}
}

Get Tab Selection Event from UITabBar in a ViewController

The structure of my MainStoryboard is:
->Tab Bar Controller -> Navigation Controller -> View Controller (Search)
The behaviour I want to have is that when the user re-selects the Search tab, the UIScrollView on it scrolls to the top. I am unsure how to get the event from the TabBarController, however.
I've been looking at a lot of stuff about UITabBarDelegate, particularly:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
I have, not quite managed to get this to work properly though. I am very unsure about how to go about setting the delegate (assuming that is the way it's done). I've tried hooking it up in IB, but it wouldn't let me. I also tried to get the UITabBar from the AppDelegate (after looking at some seemingly-related answers).
Any pointers will be greatly appreciated (unless they're null).
UITabBar *aTabBar = [UITabBarItem alloc] init];
....Any other modifications you want to make to aTabBar....
[aTabBar setDelegate:self]
Don't forget to add "<UITabBarDelegate>" to the "#interface" part of whatever object you're trying to designate as the delegate.
For my own code, I usually use some object that isn't the application delegate (as the app delegate is usually meant for application level events like "application is suspending" or "application is coming back into foreground"). If you add "<UITabBarDelegate>" to your Search view controller, make sure that whatever you do with the "didSelectItem" method is applicable only to the Search view controller. Otherwise instantiate some different object if you want to do actions on various view controllers based on which tab bar item is being displayed.

Objective-C NSWindow remove window from key

Hi need a little help, i have a window which is set to always show in the top right corner but it is not set to always key. The window has a few buttons on it and when a button is clicked the window becomes key, but what i want it to do is when a button is clicked i want the window to remove itself from being key.
So ideally the window becomes key when a button is clicked and in the method which the button calls i want to write a statement which will then perform the action of the button and remove the window from key.
However the window is declared under the app delegate and the method linked to the button is declared in a separate header file.
Anyone have any ideas how i can do this, any help would be much appreciated.
Thanks in advance, Sami.
There are a few solutions depending on the architecture of your application.
Send [[NSApp mainWindow] makeKeyWindow], which will make the main window become key.
Your application delegate could have a reference to the main window. In the action method that handles the button click, you could ask the application delegate to make the main window become key. The application delegate would send [mainWindow makeKeyWindow].
Your application delegate could have a reference to the window controller that manages the main window. In the action method that handles the button click, you could ask the application delegate to make the main window become key. The application delegate would ask the main window controller to do that, and the main window controller would send [[self window] makeKeyWindow].
Your application delegate could listen to the NSWindowDidResignKeyNotification notification and keep a reference to the last window that resigned being key. In the action method that handles the button click, you could ask the application delegate to return key status to that previous window. The application delegate would need to ignore NSWindowDidResignKeyNotification notifications when the window is your auxiliary window. This solution is better when there’s no single main window.
If the first solution is not applicable, a) your application delegate could conform to a protocol that declares a method responsible for restoring key status to the proper window, or b) your action method could post a notification informing the application that your action method has completed, and have the application delegate listen to that notification and restore key status to the proper window.
Note that even though I’ve suggested that the application delegate would implement the behaviour of restoring key status, other objects could be responsible for that. This is particularly easier when notifications are used since there’s no need to grab a reference to the object that will restore key status due to the inherent loose coupling provided by notifications.