I have an NSSegmentedControl on my UI with 4 buttons. The control is connected to a method that will call different methods depending on which segment is clicked:
Subclass NSSegmentedCell, override method below, and replace the cell class in IB. (Requires no private APIs).
- (SEL)action
{
//this allows connected menu to popup instantly (because no action is returned for menu button)
if ([self tagForSegment:[self selectedSegment]]==0) {
return nil;
} else {
return [super action];
}
}
This is the Swift version of the answer by J Hoover and the mod by Adam Treble. The override was not as intuitive as I thought it would be, so this will hopefully help someone else.
override var action : Selector {
get {
if self.menuForSegment(self.selectedSegment) != nil {
return nil
}
return super.action
}
set {
super.action = newValue
}
}
widthForSegment: returns zero if the segment auto-sizes. If you're not concerned about undocumented APIs, there is a rectForSegment:
But to answer the original question, an easier way to get the menu to pop up immediately is to subclass NSSegmentedCell and return 0 for (again, undocumented)
I'm not sure of any built-in way to do this (though it really is a glaring hole in the NSSegmentedControl API).
My recommendation is to continue doing what you're doing popping up the context menu. However, instead of just using the segmented control's origin, you could position it directly under the segment (like you want) by doing the following:
NSPoint menuOrigin = [segmentedControl frame].origin;
menuOrigin.x = NSMaxX([segmentedControl frame]) - [segmentedControl widthForSegment:4];
// Use menuOrigin where you _were_ just using [segmentedControl frame].origin
It's not perfect or ideal, but it should get the job done and give the appearance/behavior your users expect.
(as an aside, NSSegmentedControl really needs a -rectForSegment:
method)