1

I like to display an NSPopupButton that has no arrows. I like to use that space where the arrows would be for the label text. That doesn't seem to work by default.

Here's the text (which is "01234567890") with the arrows enabled:

enter image description here

And here with no arrows:

enter image description here

As you can see, the space the arrows would occupy is not used by the text.

How can I use the full content width for the text?

I've inspected the control with F-Script but found that the control's subviews array appears to be empty - I had expected to find two subviews, and if that were the case, I'd remove the one for the arrows and make the one for the text wider.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149

1 Answers1

1

One way to accomplish this is to create an NSPopupButtonCell subclass and draw the text yourself in its drawTitle:withFrame:inView: method.

Here's the essence of it:

@interface MyCell : NSPopUpButtonCell
    @property NSDictionary<NSString*,id> *attrs;
@end

@implementation MyCell

-(NSRect)drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView
{
    CGSize cs = controlView.bounds.size;
    CGPoint or = frame.origin;
    CGSize fs = frame.size;
    const int th = fs.height;
    const int inset = th * 2 / 3;
    const int indent = self.image ? th+6 : 0; // assuming the img is on the left of the text, we'll indent the text
    frame = CGRectMake (inset+indent, or.y, cs.width-2*inset-indent, fs.height);
    return [super drawTitle:title withFrame:frame inView:controlView];
}

@end

Note: This code does not cover all possible cases of adding an icon to the menu items - it only handles the most common case of having a fitting icon on the left, and that's still a bit wonky because of using indenting values I found by trial-and-error. Adjust them yourself as needed.

See also the comment below by @NSGod about setting up the cell's class in your nib or storyboard.

Update: Optimized the code to need only a subclass of the NSPopUpButtonCell but not of NSPopUpButton, thanks to @NSGod.

Update 2: Instead of implementing drawTitleWithFrame:inView: I now overwrite drawTitle:withFrame:inView: because that gives me the correctly centered frame for drawing and makes the whole code shorter.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
  • 1
    You should be able to set the custom class name of the `NSPopUpButtonCell` inside the nib file. Select the `NSPopUpButton` in the nib file, then click again to select the cell (verify that the cell is selected by using the nib hierarchy outline view to the left). In the Identity inspector, set Custom Class to `MyCell`. You can then set up all the properties of the cell and they should be preserved. When nib loads, this will call `MyCell`'s `initWithCoder:` method, so if you've overridden it, make sure to call `[super initWithCoder:coder]` before any customizing.... – NSGod May 24 '16 at 18:16
  • @NSGod I had never noticed before that a second click would select the cell, though I noticed that *something* changed. Now the only thing left to figure out is to vertically center the text correctly, though that should be easy. In theory. – Thomas Tempelmann May 24 '16 at 19:57