views:

305

answers:

1

Basically I want to create the effect of that provided in the system's menu bar. A user presses on one of the menu headings, and as he moves across the different headings, the menus open up automatically.

The snag is that if I open a pop-up menu for a button, the user has to click again to dismiss it. The entire runloop is on hold as I believe the pop-up menu is modal. How do I go about being able to send a [somePopUpMenu cancelTracking] when the user moves to the next button?

Here's code I'm currently trying out in my NSWindow subclass. The point is that once the mouse exits a button, the mouse is automatically clicked (leftdown/leftup) on the next button, the timer is invalidated and the popup menu is cancelled.

Assuming a popup menu is open and the mouse exists, the leftdown/leftup events are fired (I know this works as I log them in NSLog's for mouseDown and mouseUp), the timer is invalidated, but the pop up menu is still showing, and the other button "clicked" on by the fake events doesn't show anything. Also, the whole thing gets into a loop and there's frantic mouseDown/mouseUp being sent for some reason.

Worth noting the the popup menu is created in another object, though the hookToMenu has a proper reference to it (I confirmed via debug/stepping through).

Dunno if I'm borking the event tracking timer or doing it the wrong way. I did try it via a window controller as well but got the same results.

Any help on this would be appreciated.

-(void)stopTimer
{
    [timer invalidate];
    [hookToMenu cancelTracking]; //hookToMenu is NSMenu*
}

-startFireDateTimer
{
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
    timer = [[NSTimer alloc] initWithFireDate:nil interval:0 target:self selector:@selector(targetMethod)      userInfo:nil  repeats:YES];

    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:timer forMode:NSEventTrackingRunLoopMode];
    [timer release];
}

-(void)targetMethod
{
    NSEvent *newEvent;

    newEvent=[NSApp nextEventMatchingMask:NSMouseExitedMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:NO];

    if ([newEvent type]==NSMouseExited)
    {
        NSPoint mouseLoc;

        mouseLoc=[newEvent locationInWindow];

        int type=NSLeftMouseDown;
        int type2=NSLeftMouseUp;
        int windowNumber=[self windowNumber];

        id fakeMouseUpEvent=[NSEvent mouseEventWithType:type
                                               location:mouseLoc
                                          modifierFlags:nil 
                                              timestamp:[NSDate timeIntervalSinceReferenceDate]
                                           windowNumber:windowNumber 
                                                context:nil
                                            eventNumber:nil 
                                             clickCount:1 
                                               pressure:1];

        id fakeMouseUpEvent2=[NSEvent mouseEventWithType:type2
                                                location:mouseLoc
                                           modifierFlags:nil 
                                               timestamp:[NSDate timeIntervalSinceReferenceDate]
                                            windowNumber:windowNumber 
                                                 context:nil
                                             eventNumber:nil 
                                              clickCount:1 
                                                pressure:1];

        [NSApp sendEvent:fakeMouseUpEvent];
        [NSApp sendEvent:fakeMouseUpEvent2];

        [self stopTimer];
    }
}

-(void)mouseDown:(NSEvent *)theEvent
{    
    [self startFireDateTimer];

    NSLog(@"WINDOW: mouse down in window!");

    [super mouseDown:theEvent];
}

-(void)mouseUp:(NSEvent *)theEvent
{    
    NSLog(@"WINDOW: mouse up in window!");

    [super mouseUp:theEvent];
}
A: 

How do I go about being able to send a [somePopUpMenu cancelTracking] when the user moves to the next button?

Do exactly that. NSMenu responds to a cancelTracking message since Mac OS X 10.5.

Peter Hosey
I tried doing so. I can't. My app will not process further while it's displaying the pop-up.
hishamk
“The entire runloop is on hold as I believe the pop-up menu is modal.” No, it's running in `NSEventTrackingRunLoopMode`. If you're running a timer or something, that's the mode to schedule it in.
Peter Hosey
Can you please take a gander at the code I posted and see what I'm doing wrong? The main issue is that the popup is persisting and cannot be cancelled for some reason!I appreciate your help and advice.Thanks
hishamk