1
votes

I'm creating a view that has rounded corners and I want the view to highlight when the mouse hovers over it. The problem is that the NSTrackingArea registers a mouseEntered: event when the mouse is outside of the corners. Is there a way to override how it determines if it's in the view?

I've tried:

  • Adding .inVisibleRect to the NSTrackingArea.Options
  • Overriding isMousePoint:in:

If necessary, I can implement mouseEntered: to ignore all events whose points aren't within the rectangle, but I was wondering if there was a more elegant way (i.e where mouseEntered: gets called only when the mouse actually enters the view).

This is the code I use for drawing (it works for me):

...

override func draw(_ dirtyRect: NSRect)
{
    let path = NSBezierPath(roundedRect: dirtyRect, xRadius: radius, yRadius: radius)
    path.addClip()

    backgroundColor.setFill()
    dirtyRect.fill()
}

...

override func mouseEntered(with event: NSEvent) 
{
    print("Mouse entered!")
}

Let me know if I can clarify anything. Thanks for the help!

2
Not related to the question but dirtyRect is "A rectangle defining the portion of the view that requires redrawing.".Willeke

2 Answers

1
votes

First of all, if your rounded corners are small enough, I'd say don't worry about it and just stick with the rectangular tracking area. Most users are unlikely to notice, so in my opinion it's probably not worth your time to create.

If you still want to do this, as Victor mentioned, you should be checking using whatever bezier path describes the shape of your view, but it's a little more complicated than just checking that inside mouseEntered() and mouseExited(). You also need to implement mouseMoved() and do the same path checking there in order to respond properly when the cursor moves in and out of the path within the tracking area. Don't forget to configure your tracking area to actually send you those mouseMoved events.

You might also need to start thinking about performance. If you end up implementing mouseMoved, then your testing code will be running every single frame of cursor motion through your tracking area, which could potentially reduce the responsiveness of your UI. There are a number of optimizations you could use if this winds up being an issue, such as using an inner tracking area (inside the rounded edges) that doesn't use mouseMoved or increasing the flatness of the path to reduce the complexity of the testing calculation. As you might imagine, optimizing this gets complicated really quick.

1
votes

You could possibly save the path and check whether the point of the event is inside or not by using containsPoint(point: CGPoint). For more see here.