Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force the cursor to be an "arrowCursor" when it hovers a NSButton that is inside a NSTextView?

Okay, here is the problem:
I have a NSTextView and I add my custom NSButton using:

[_textView addSubview:button];

Then, inside my NSButton subclass, I have (along with the NSTrackingArea stuff):

- (void)mouseEntered:(NSEvent *)event{
     [[NSCursor arrowCursor] set];
}

- (void)mouseExited:(NSEvent *)theEvent{
     [[NSCursor arrowCursor] set];
}

- (void)mouseDown:(NSEvent *)theEvent{
     [[NSCursor arrowCursor] set];
}

- (void)mouseUp:(NSEvent *)theEvent{
     [[NSCursor arrowCursor] set];
}

But when I hover it, the cursor remains the same IBeamCursor (because it's a NSTextView). Only when I press the button, the cursor gets updated. And then, when I move the mouse, still inside the button, the cursor goes back to the IBeamCursor.

Any ideas on how to do this? Thank you!

like image 788
Pedro Vieira Avatar asked Apr 29 '13 20:04

Pedro Vieira


2 Answers

Adding a tracking area that only tracks enter/exit events seems to be not enough for NSTextView subviews. Somehow the textview always wins and sets it's IBeamCursor.

You can try to always enable tracking for mouse move events (NSTrackingMouseMoved) when adding the tracking area in your NSButton subclass:

#import "SSWHoverButton.h"

@interface SSWHoverButton()
{
    NSTrackingArea* trackingArea;
}

@end

@implementation SSWHoverButton

- (void)mouseMoved:(NSEvent*)theEvent
{
    [[NSCursor arrowCursor] set];
}

- (void)updateTrackingAreas
{
    if(trackingArea != nil)
    {
        [self removeTrackingArea:trackingArea];
    }
    NSTrackingAreaOptions opts = (NSTrackingMouseMoved|NSTrackingActiveAlways);
    trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
                                                 options:opts
                                                   owner:self
                                                userInfo:nil];
    [self addTrackingArea:trackingArea];
}

- (void)dealloc
{
    [self removeTrackingArea:trackingArea];
}

@end
like image 52
Thomas Zoechling Avatar answered Nov 02 '22 14:11

Thomas Zoechling


Swift 5 variant:

import Cocoa

class InsideTextButton: NSButton {

    var trackingArea: NSTrackingArea?

    override func mouseMoved(with event: NSEvent) {
        NSCursor.arrow.set()
    }

    override func updateTrackingAreas() {
        if let area = trackingArea {
            removeTrackingArea(area)
        }

        trackingArea = NSTrackingArea(rect: self.bounds, options: [.mouseMoved, .activeAlways], owner: self, userInfo: nil)

        if let area = trackingArea {
            addTrackingArea(area)
        }
    }

    deinit {
        if let area = trackingArea {
            removeTrackingArea(area)
        }
    }
}
like image 35
Ely Avatar answered Nov 02 '22 12:11

Ely