NSButtonCell highlighting in Mojave

I have a class derived from `NSButtonCell` where I draw bezel:


    override func drawBezel(withFrame frame: NSRect, in controlView: NSView) {
            let path = NSBezierPath(bound: frame.insetBy(dx: CGFloat(config.buttonInset), dy: CGFloat(config.buttonInset)), withCorners: corners, withRadius: CGFloat(config.cornerRadius), flip: flipIt)
           
            path.lineWidth = config.borderWidth
            if(isEnabled)
            {
                if(isHighlighted)
                {
                    print("isHighlighted true")
                    let fillColor: NSColor = colorMap.buttonHighlightColor
                    let strokeColor: NSColor = colorMap.buttonBorderColor
                    fillColor.setFill()
                    strokeColor.setStroke()
                    path.fill()
                    path.stroke()
                }
                else
                {
                    print("isHighlighted false")
                    if(showsStateBy.contains(.changeGrayCellMask))
                    {
                        print(".changeGrayCellMask")
                        if(state == .on)
                        {
                            print(".on")
                            let fillColor: NSColor = colorMap.buttonOnColor
                            let strokeColor: NSColor = colorMap.buttonBorderColor
                            fillColor.setFill()
                            strokeColor.setStroke()
                            path.fill()
                            path.stroke()
                        }
                        else
                        {
                            print(".off")
                            let fillColor: NSColor = colorMap.buttonBackgroundColor
                            let strokeColor: NSColor = colorMap.buttonBorderColor
                            fillColor.setFill()
                            strokeColor.setStroke()
                            path.fill()
                            path.stroke()
                        }
                    }
                    else
                    {
                        print("!.changeGrayCellMask")
                        let fillColor: NSColor = colorMap.buttonBackgroundColor
                        let strokeColor: NSColor = colorMap.buttonBorderColor
                        fillColor.setFill()
                        strokeColor.setStroke()
                        path.fill()
                        path.stroke()
                    }
                }
            }
            else
            {
                let fillColor: NSColor = colorMap.buttonBackgroundDisabledColor
                let strokeColor: NSColor = colorMap.buttonBorderColor
                fillColor.setFill()
                strokeColor.setStroke()
                path.fill()
                path.stroke()
            }
        }


Additionally I have `keyEquivalent` assigned to the button with my custom cell.


This works perfectly fine either using mouse click or keypress on **macOS High Sierra**. The highlight is shown only when the mouse or key is down.


Log output looks like this:


    **after click with mouse**
    isHighlighted true
    isHighlighted false
    !.changeGrayCellMask
  
    **after shortcut key**
    isHighlighted true
    isHighlighted false
    !.changeGrayCellMask


However, on **Mojave** the behaviour on keypress is different. After keypress the highlighted state remains, while when using mouse, the highlight acts as expected.


The log output from Mojave:


    **Mojave click with mouse**
    isHighlighted true
    isHighlighted false
    !.changeGrayCellMask
  
    **Mojave after shortcut key**
    isHighlighted false
    !.changeGrayCellMask
    isHighlighted true <----- this is odd


So is there something that has been changed in Mojave. As you can see `drawBezel` call order is totally unexpected. Strange thing is why it happens only when using keyboard.


How to achieve button highlight behaviour with keyboard similar to mouse click on Mojave?


UPDATE


Here is small XCode playground project, showing the problem on Mojave.

Replies

Could you show the code where you detect and react to keyPress of mouseClick ?

In my NSButton subclass I had target and action. I've commented out the code reacting to mouse / keyboard event. The problem still remains.

Could you post the code of the NSButton subclass ?

here you go:


class CalcButton: NSButton
{
    weak var delegate: ButtonActionDelegate?
    var buttonIdentifier: CKey = .undefined
   
    convenience init(frame frameRect: NSRect, corners roundCorners: Corners, buttonType: NSButton.ButtonType, withLabel label: String, withColorMap colorMap: ButtonColorMapProtocol, withConfig configuration: KeypadConfigurationProtocol) {
        self.init(frame: frameRect)
       
        cell = FunkyCell(textCell: label, withColorMap:colorMap, withConfig: configuration)
        if let c = cell as? FunkyCell
        {
            c.imageScaling = .scaleNone
            c.flipIt = isFlipped
            c.corners = roundCorners
            c.font = NSFont.labelFont(ofSize: CGFloat(configuration.fontSize))
            c.state = .off
        }

        setButtonType(buttonType)
        bezelStyle = .smallSquare
       
        // target = self
        // action = #selector(self.react(_:))
    }
   
    convenience init(frame frameRect: NSRect, corners roundCorners: Corners, buttonType: NSButton.ButtonType, withIcon iconName: String, withColorMap colorMap: ButtonColorMapProtocol, withConfig configuration: KeypadConfigurationProtocol) {
        self.init(frame: frameRect)
       
        cell = FunkyCell(imageCell: NSImage(named: NSImage.Name(iconName)), withColorMap:colorMap, withConfig: configuration)
        if let c = cell as? FunkyCell
        {
            c.imageScaling = .scaleNone
            c.flipIt = isFlipped
            c.corners = roundCorners
            c.state = .off
        }
       
        setButtonType(buttonType)
        bezelStyle = .smallSquare
       
        //target = self
        //action = #selector(self.react(_:))
    }
   
   
    @objc func react(_ sender: NSButton)
    {
        delegate?.buttonPressed(btn: buttonIdentifier)
    }
   
    required override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
    }
   
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}


additionally I've tried different button types, but problem remains.

Here is small XCode playground project, showing the problem on Mojave.

Hello,

Did you find the solution to this problem? I am facing similar issue.