NSPopUpButton arrow color

2.1k Views Asked by At

Is there a way to customize the color of a NSPopUpButton arrow? I've looked around but I've not found an answer yet

5

There are 5 best solutions below

0
On

I really dont think there is an "easy" way to do this. If you look at the API description, it even states that it doesnt respond to the setImage routine. I have done quite a bit of work sub-classing button objects, etc... and I think this is where you would have to go in order to do what you are asking.

0
On

I have changed arrow color by using "False Color" filter without using any image. So far it is the easiest way to change cocoa control to me.

class RLPopUpButton: NSPopUpButton {
init() {
    super.init(frame: NSZeroRect, pullsDown: false)
    addFilter()
}

required init?(coder: NSCoder) {
    super.init(coder: coder)
    addFilter()
}

func addFilter() {
    let colorFilter = CIFilter(name: "CIFalseColor")!
    colorFilter.setDefaults()
    colorFilter.setValue(CIColor(cgColor: NSColor.black.cgColor), forKey: "inputColor0")
    colorFilter.setValue(CIColor(cgColor: NSColor.white.cgColor), forKey: "inputColor1")

//        colorFilter.setValue(CIColor(cgColor: NSColor.yellow.cgColor), forKey: "inputColor0")
//        colorFilter.setValue(CIColor(cgColor: NSColor.property.cgColor), forKey: "inputColor1")

    self.contentFilters = [colorFilter]
}
}
0
On

Swift 5

In interface builder, remove default arrow setting. Then, apply this subclass for cell, which will add an NSImageView to the right side of the NSPopUpButton.

This way you have complete control over what you set as your custom button and how you position it.

import Cocoa

@IBDesignable class NSPopUpButtonCellBase: NSPopUpButtonCell {
    
    let textColor = NSColor(named: "white")!
    let leftPadding: CGFloat = 16
    let rightPadding: CGFloat = 30

    override func awakeFromNib() {
        super.awakeFromNib()
        
        let imageView = NSImageView()
        imageView.image = NSImage(named: "ic_chevron_down")!

        controlView!.addSubview(imageView)
        
        imageView.translatesAutoresizingMaskIntoConstraints = false
        
        imageView.widthAnchor.constraint(equalToConstant: CGFloat(20)).isActive = true
        imageView.heightAnchor.constraint(equalToConstant: CGFloat(20)).isActive = true
        imageView.trailingAnchor.constraint(equalTo: controlView!.trailingAnchor).isActive = true
        imageView.centerYAnchor.constraint(equalTo: controlView!.centerYAnchor).isActive = true
    }
    
    // overriding this removes the white container
    override func drawBezel(withFrame frame: NSRect, in controlView: NSView) {
        
    }
    
    // overriding this allows us to modify paddings to text
    override func titleRect(forBounds cellFrame: NSRect) -> NSRect {
        // this gets rect, which has title's height, not the whole control's height
        // also, it's origin.y is such that it centers title
        let processedTitleFrame = super.titleRect(forBounds: cellFrame)

        let paddedFrame = NSRect(
            x: cellFrame.origin.x + leftPadding,
            y: processedTitleFrame.origin.y,
            width: cellFrame.size.width - leftPadding - rightPadding,
            height: processedTitleFrame.size.height
        )

        return paddedFrame
    }

    // overriding this allows us to style text
    override func drawTitle(_ title: NSAttributedString, withFrame frame: NSRect, in controlView: NSView) -> NSRect {
        let attributedTitle = NSMutableAttributedString.init(attributedString: title)
        let range = NSMakeRange(0, attributedTitle.length)
        attributedTitle.addAttributes([NSAttributedString.Key.foregroundColor : textColor], range: range)

        return super.drawTitle(attributedTitle, withFrame: frame, in: controlView)
    }
}
0
On

i did this and its worked for me.

(void)drawImageWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    NSPopUpButton *temp = (NSPopUpButton*)controlView;

    NSString *strtile = temp.title;

    AppDelegate *appdel = (AppDelegate*)[NSApplication sharedApplication].delegate;
    NSFont *font = [NSFont systemFontOfSize:13.5];
   NSSize size = NSMakeSize(40, 10);// string size

    CGRect rect = controlView.frame;
    rect = CGRectMake((size.width + temp.frame.size.width)/2, rect.origin.y, 8, 17);

    [self drawImage:[NSImage imageNamed:@"icon_downArrow_white.png"] withFrame:rect inView:self.
}
0
On

Like too many of these controls, I did it by subclassing NSPopupButton(Cell) and then doing all my own drawing in drawRect...I cheated a little though, and used an image do the actual triangle rather than trying to do it via primitives.

- (void)drawRect:(NSRect)dirtyRect 
{
  //...Insert button draw code here...
  //Admittedly the above statement includes more work than we probably want to do.
  //Assumes triangleIcon is a cached NSImage...I also make assumptions about location

  CGFloat iconSize = 6.0;
  CGFloat iconYLoc = (dirtyRect.size.height - iconSize) / 2.0;
  CGFloat iconXLoc = (dirtyRect.size.width - (iconSize + 8));

  CGRect triRect = {iconXLoc, iconYLoc, iconSize, iconSize};
  [triangleIcon drawInRect:triRect];
}