Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom NSControl classes in OS X 10.10

Tags:

macos

cocoa

I need to develop a new custom NSControl. All of the guides and examples I can find (including Apple's Subclassing NSControl article) are built around NSCell. But as of 10.10, all of the cell-related messages on NSControl have been deprecated.

I tried just creating a subclass and adding to my project via a custom view in IB, but I can't get the control to accept first responder despite being enabled, setting refusesFirstResponder to NO, and return YES from acceptsFirstResponder. And I'm sure I'm missing a lot of functionality (value change notifications, etc.) that are supposed to be there.

Is there are newer reference around that shows how controls are now supposed to be developed? My Google-fu is letting me down if there is. Thanks!

like image 203
J. Perkins Avatar asked Dec 05 '14 19:12

J. Perkins


1 Answers

Your problem likely was that you never actually set the control to be first responder. Simply clicking on it won't do it automatically. Below is a quick example which accepts first responder status (and becomes so on click too), and draws a focus ring. Be sure to enable the control and set its target and action.

class MyControl: NSControl {


    override var acceptsFirstResponder: Bool {
        return true
    }


    override func becomeFirstResponder() -> Bool {
        return true
    }


    override func mouseDown(with event: NSEvent) {
        window?.makeFirstResponder(self)
    }

    override func mouseUp(with event: NSEvent) {
        if let action = action {
            NSApp.sendAction(action, to: target, from: self)
        }
    }


    override func draw(_ dirtyRect: NSRect) {
        NSColor.white.set()
        NSBezierPath(roundedRect: bounds.insetBy(dx: 1, dy: 1), xRadius: 3, yRadius: 3).fill()

        if window?.firstResponder == self {
            NSColor.keyboardFocusIndicatorColor.set()
        } else {
            NSColor.black.set()
        }
        NSBezierPath(roundedRect: bounds.insetBy(dx: 1, dy: 1), xRadius: 3, yRadius: 3).stroke()
    }


    override var focusRingMaskBounds: NSRect {
        return bounds.insetBy(dx: 1, dy: 1)
    }


    override func drawFocusRingMask() {
        NSBezierPath(roundedRect: bounds.insetBy(dx: 1, dy: 1), xRadius: 3, yRadius: 3).fill()
    }

}
like image 193
seth Avatar answered Nov 10 '22 07:11

seth