NSMenuItem with custom view dose not respond after leaving application - objective-c

My application resides in the status bar. When the application first starts my search field responds fine, and allows me to click and enter text and look like this.
But after clicking out of the application into another application like "xcode" and back into my menu the search field and the rest of the custom view appears dim and does not respond unless I click multiple times.
In my applicationDidFinishLaunching I set up the statusItem and the NSMenuItem with the custom view.
//set up hotkeys
[self registerHotKeys];
_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
NSImage *menuIcon = [NSImage imageNamed:#"Menu Icon"];
NSImage *highlightIcon = [NSImage imageNamed:#"Menu Icon"];
[highlightIcon setTemplate:YES];
[[self statusItem] setImage:menuIcon];
[[self statusItem] setAlternateImage:highlightIcon];
[[self statusItem] setMenu:[self menu]];
[[self statusItem] setHighlightMode:YES];
// search menu item
NSMenuItem *searchMenuItem = [[NSMenuItem alloc] initWithTitle:#"search" action:nil keyEquivalent:#""];
self.searchMenuItemView = [[SearchMenuItemView alloc] initWithNibName:#"SearchMenuItemView" bundle:nil];
self.searchMenuItemView.delegate = self;
[searchMenuItem setView:self.searchMenuItemView.view];
[searchMenuItem setTarget:self];
[searchMenuItem setEnabled:YES];
[_menu insertItem:searchMenuItem atIndex:0];
The view is coming from an UIViewController, but I have tried setting the view from just an NSView with no luck using "this" from someone with a similar issue but this did not solve mine. Auto enable is on.
Is there a way to bring the NSMenuItem back to the state it was in when the application is first lunched?

Related

NSMenu with views in a modal NSWindow

I have an issue with selectors not being performed for custom views inside an NSMenuItem when they are displayed from a button within a modal NSWindow.
This appears to be a reproducible issue and I've simplified the issue as much as I can.
Modal window is displayed via.
[NSApp runModalForWindow:_modalWindow];
The modal window only has a button, and the button is attached to the following selector.
- (IBAction)modalButtonClicked:(id)sender
{
NSMenu* aMenu = [[NSMenu alloc] initWithTitle:#"Menu"];
NSMenuItem* aItemA = [[NSMenuItem alloc] initWithTitle:#"" action:nil keyEquivalent:#""];
NSMenuItem* aItemB = [[NSMenuItem alloc] initWithTitle:#"" action:nil keyEquivalent:#""];
NSMenuItem* aItemC = [[NSMenuItem alloc] initWithTitle:#"" action:nil keyEquivalent:#""];
[aItemA setView:[NSButton buttonWithTitle:#"Item A" target:self action:#selector(menuButtonClicked:)]];
[aItemB setView:[NSButton buttonWithTitle:#"Item B" target:self action:#selector(menuButtonClicked:)]];
[aItemC setView:[NSButton buttonWithTitle:#"Item C" target:self action:#selector(menuButtonClicked:)]];
[aMenu addItem:aItemA];
[aMenu addItem:aItemB];
[aMenu addItem:aItemC];
[NSMenu popUpContextMenu:aMenu withEvent:[NSApp currentEvent] forView:sender];
}
and the menu click event with a breakpoint:
- (void)menuButtonClicked:(id)sender
{
NSLog(#"%#", sender);
}
Clicking on the button will display a menu with 3 buttons, however nothing happens when you click any of those buttons. #(menuButtonClicked:) is never called. This is only an issue with modal windows but there's no obvious reason why.
The documention https://developer.apple.com/documentation/appkit/nsmenuitem/1514843-target?language=objc states:
To ensure that a menu item’s target can receive commands while a modal
dialog is open, the target object should return YES in worksWhenModal.
And indeed if one adds:
- (BOOL)worksWhenModal {
return YES;
}
then it works and your method menuButtonClicked gives out something like:
2019-10-03 22:47:27.892005+0200 MenuTest[12876:454071] <NSButton: 0x600003505760>

NSMenuItem's not selectable after opening window

I'm having an issue very similar to this thread.
I am programatically creating a NSMenu and adding my items. One selection of an item it shows a window. This works as intended. However, when I close the window I can no longer select any of the options in the menu.
AppDelegate.m
- (void)createMenu {
NSMenu *statusMenu = [[NSMenu alloc] initWithTitle:#""];
NSMenuItem *historyItem = [[NSMenuItem alloc] initWithTitle:#"History" action:#selector(onHistory:) keyEquivalent:#""];
[statusMenu addItem:historyItem];
NSImage *statusImage = [NSImage imageNamed:#"icon.png"];
[_item setImage:statusImage];
[_item setMenu:statusMenu];
}
- (void)onHistory:(id)sender {
OBHistoryWindowController *historyWindowController = [[OBHistoryWindowController alloc] initWithWindowNibName:#"OBHistoryWindowController"];
historyWindowController.managedContext = self.managedObjectContext;
[historyWindowController showWindow];
}
OBHistoryWindowController.m
- (void)showWindow {
[NSApp runModalForWindow:self.window];
}
I'm guessing I need to somehow on close of the window give focus back to the menu but I can't for the life of me figure out how.
It sounds like you haven't stopped the modal loop. As the docs for runModalForWindow: say, "You can exit the modal loop by calling the stopModal, stopModalWithCode:, or abortModal methods from your modal window code."

Showing UIImagePickerController in UIPopoverController with existing UINavigationController (adding back button)

So I have a UIPopoverController what houses my UINavigationController where I have my UITableViewController however one of my options on the UITableView is to go and select an image with the UIImagePickerController... Now on the iPhone I can simply use presentModalViewController:animated: however calling that from within a UIPopoverController causes a crash so thats not possible...
I also know the UIImagePickerController needs its own UINavigationController so I can't just push pushViewController:animated: either...
So I figured out that if I keep a link to the UIPopoverController I created, I can then use setContentViewController:animated: to switch to the UIImagePickerController's viewController...
However, I am now stuck at giving the user a way to go back to the previous UINavigationController as I need to be able to add a cancel button to the UIImagePickerController but when I try to do this the cancel button won't get added...
Heres my code that i'm using
-(void)doPhotoalbums {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setDelegate:self];
[imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
[imagePicker setContentSizeForViewInPopover:CGSizeMake(320, 480)];
UIBarButtonItem *cancel = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:nil];
[imagePicker.navigationItem setLeftBarButtonItem:cancel];
//[self presentModalViewController:imagePicker animated:YES];
[[self parentPopoverController] setContentViewController:imagePicker animated:YES];
} else {
[UIAlertView showMessage:#"This device does not have any photo albums."];
}
}
So my question is.. Does anybody know how I can get around this? either by adding a cancel/back button what I can hook up to make the navigationControllers switch back or another way to present this (i'd like to avoid switching between two UIPopoverControllers but I don't know what else I can do..
Thanks
Liam
Ahh.. after a little break I found this: https://discussions.apple.com/thread/1710435?start=0&tstart=0
using the UINavigationControllerDelegate you can use the navigationController:willShowViewController:animated: method to access the navigationBar.. then with some code (below) you can add a button.
if ([navigationController isKindOfClass:[UIImagePickerController class]]) {
UINavigationBar *bar = navigationController.navigationBar;
UINavigationItem *top = bar.topItem;
UIBarButtonItem *cancel = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(imagePickerControllerDidCancel:)];
[top setLeftBarButtonItem:cancel];
} else {
//do non imagePickerController things
}

Custom view in NSMenuItem disables the NSPopUpButton selection

I want to customize an an NSPopUpButton so I have implemented an CustomMenuItemView which right now only has the following code (for testing purposes):
- (void)drawRect:(NSRect)dirtyRect
{
[[NSColor redColor] set];
NSRectFill(dirtyRect);
}
Now, for every NSMenuItem i add to the NSMenu in myPopUpButton.menu I set the view to my custom view:
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:#"Some title" action:NULL keyEquivalent:#""];
menuItem.view = [[CustomMenuItemView alloc] initWithFrame:NSMakeRect(0, 0, 100, 25)];
When I run my program and open the popup button the menuitem selection seems disabled (i.e. nothing happens when I click on it).
I am guessing that it is not actually disabled; it just doesn't respond to events anymore. Do I need to add some event handling in my custom view? If so, how?
I solved the problem by adding the mouseUp method to my CustomMenuItemView:
- (void)mouseUp:(NSEvent*) event
{
NSMenu *menu = self.enclosingMenuItem.menu;
[menu cancelTracking];
[menu performActionForItemAtIndex:[menu indexOfItem:self.enclosingMenuItem]];
}

Create NSMenu for NSStatusBar.systemStatusBar programmatically

I'm trying to create a simple menu in the System Status Bar using code only. I'm not receiving any compilation or runtime errors but I see no effect at all.
- (void)awakeFromNib
{
NSMenu *stackMenu = [[NSMenu alloc] initWithTitle:#"Status Menu"];
NSMenuItem *soMenuItem =
[[NSMenuItem alloc] initWithTitle:#"Status Menu Item" action:nil keyEquivalent:#"S"];
[soMenuItem setEnabled:YES];
[stackMenu addItem:soMenuItem];
statusItem = [[[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength]
retain];
[statusItem setMenu:stackMenu];
}
I don't believe the NSStatusItem will implicitly take on the title of the NSMenu associated with it (which is what I am guessing you want to happen.) Try explicitly setting the NSStatusItem's title (and/or its image).
e.x.
[statusItem setTitle:[stackMenu title]];