If anyone else needs it, here my solution is based on a simple NSButton, not a segmented control.
Subclass NSButton and implement a custom mouseDown that starts a timer in the current execution loop. In mouseUp check if the timer is off. In this case, cancel it and perform the default action.
This is a very simple approach, it works with any NSButton that you can use in IB.
Code below:
- (void)mouseDown:(NSEvent *)theEvent { [self setHighlighted:YES]; [self setNeedsDisplay:YES]; _menuShown = NO; _timer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(showContextMenu:) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode]; } - (void)mouseUp:(NSEvent *)theEvent { [self setHighlighted:NO]; [self setNeedsDisplay:YES]; [_timer invalidate]; _timer = nil; if(!_menuShown) { [NSApp sendAction:[self action] to:[self target] from:self]; } _menuShown = NO; } - (void)showContextMenu:(NSTimer*)timer { if(!_timer) { return; } _timer = nil; _menuShown = YES; NSMenu *theMenu = [[NSMenu alloc] initWithTitle:@"Contextual Menu"]; [[theMenu addItemWithTitle:@"Beep" action:@selector(beep:) keyEquivalent:@""] setTarget:self]; [[theMenu addItemWithTitle:@"Honk" action:@selector(honk:) keyEquivalent:@""] setTarget:self]; [theMenu popUpMenuPositioningItem:nil atLocation:NSMakePoint(self.bounds.size.width-8, self.bounds.size.height-1) inView:self]; NSWindow* window = [self window]; NSEvent* fakeMouseUp = [NSEvent mouseEventWithType:NSLeftMouseUp location:self.bounds.origin modifierFlags:0 timestamp:[NSDate timeIntervalSinceReferenceDate] windowNumber:[window windowNumber] context:[NSGraphicsContext currentContext] eventNumber:0 clickCount:1 pressure:0.0]; [window postEvent:fakeMouseUp atStart:YES]; [self setState:NSOnState]; }
I published the desktop on my github.
evgeny
source share