2
votes

I have a NSView with nested NSView's if I'm not dragging mouse events get triggered on all subviews using NSTracking area...fine.

But when I drag from a parent NSView over a child NSView, the mouse events are not fired and then only way I get them to respond to events is by hacking and it feels dirty.

NSView *hit = [self findViewUnderPoint:loc];
if (hit != nil)
{
    if (hit != last)
    {
        [last mouseExited:event]; // This looks terrible to me
    } else {
        [hit mouseEntered:event]; // This looks terrible to me
    }
    last = hit;
}

If you comment out the code above, the sub-view events are not triggered, if you leave it in they are...but I'm calling them directly.

I've uploaded a video showing you how it works first, then with dragging (with my hacks) - I've also included my source code.

I'm ideally after "the right way" of doing this

https://www.dropbox.com/s/b6ps8tz0jvg2gwy/Designable.zip?dl=0

2
Are you using NSTrackingEnabledDuringMouseDrag? - Ssswift
BTW, your dropbox.com link isn't working for me. - Ssswift
@Ssswift - Yes NSTrackingEnabledDuringMouseDrag is enabled. - Chris

2 Answers

2
votes

As explained in Handling Mouse Dragging Operations, there are two ways to implement dragging. Your solution short-circuits the application’s normal event loop and you have to call mouseEntered: and mouseExited:. If you don't want to do this, implement the three method approach which has other drawbacks.

0
votes

Perhaps the problem might be related to the way you are subclassing. Are you calling super methods in your overridden class methods? Are you sublcassing a specific pre-existing control or right away from NSView? Do you get any warning in XCode?

Edit:

Hi, I was playing a bit with a simplified thing like yours.

Have you looked at your hitTest: override in the CableView subclass? Maybe it should return differently: return self == hitView ? self:nil;

This is my silly implementation of a view subclass which draws a guide while dragging:

#import "MYSimpleScratchPad.h"

@implementation MYSimpleScratchPad
{
    NSPoint start;
    NSPoint finish;
    BOOL dragging;
}

- (instancetype)initWithFrame:(NSRect)frameRect {
    self = [super initWithFrame:frameRect];
    if (self) {
        _path = [NSBezierPath bezierPath];
        dragging = NO;
    }
    return self;
}

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];

    [[NSColor redColor] set];
    [_path removeAllPoints];
    if (dragging) {
        [_path setLineWidth:5.0];
        [_path setLineCapStyle:NSRoundLineCapStyle];
        [_path moveToPoint:start];
        [_path lineToPoint:finish];
        [_path stroke];
    }

}

- (void)mouseDown:(NSEvent *)event {
    start = [event locationInWindow];
    NSRect theFrame = [self frame];
    start.x -= theFrame.origin.x;
    start.y -= theFrame.origin.y;
    _path = [NSBezierPath bezierPath];
}

- (void)mouseDragged:(NSEvent *)event {
    finish = [event locationInWindow];
    NSRect theFrame = [self frame];
    finish.x -= theFrame.origin.x;
    finish.y -= theFrame.origin.y;
    dragging = YES;
    [self setNeedsDisplay:YES];
}

- (void)mouseUp:(NSEvent *)event {
    start = NSMakePoint(0.0, 0.0);
    finish = NSMakePoint(0.0, 0.0);
    dragging = NO;
    [self setNeedsDisplay:YES];
}

- (NSView *)hitTest:(NSPoint)point {
    NSView *hitView = [super hitTest:point];
    return self == hitView ? self:nil;
}

@end