On 03/02/2010, at 2:12 AM, Eric Gorr wrote:
> This method is generally not overridden
> I have filed a bug requesting that trackMouse:inRect:ofView:untilMouseUp:
> call continueTracking:at:inView: and stopTracking:at:inView:mouseIsUp: ... or
> is there a reason why it shouldn't?
Note that it says is GENERALLY not overridden, not that it is NEVER overridden.
I've noticed that quite a few built-in cell classes override at this level,
where others override the more fine-grained methods. I guess it's just a
question of what makes the most sense or is easiest for a given implementation.
NSButtonCell does call -startTrackingAt:inView:, but not the others, I think.
It appears to run a modal loop within -startTrackingAt:...
I've only written one or two custom cell classes but have overridden at both
levels. I did find that for 'button-like' tracking behaviour, overriding
-trackMouse:... or -startTrackingAt:... was simplest, because you can keep
control in an event-fetching loop until the mouse goes up before returning. For
many controls, that's way easier than dealing with three other methods called
at different times.
Back to your original question, you want to show a menu after a delay. I do
this in a custom button cell (subclass of NSButtonCell). Here's my code FWIW,
which unfortunately is a bit hackish. I don't bother cancelling the timer on
mouse up, but I decide whether to actually show the menu based on whether the
cell is still highlighted at the time, otherwise the timer callback does
nothing. I also found it necessary to "fake up" a mouse up event when the menu
tracking has completed to ensure the cell tracking is forced to return, because
otherwise the pop-up menu tracking has swallowed the mouse-up event and so the
button would otherwise remain stuck in its tracking loop waiting for a mouse-up
that will never arrive. There may well be a far less hackish way to do that,
but this does work:
(I note that KBPopUpToolbarItem doesn't do something similar because it
implements its own tracking loop in its entirety, so has full control over when
it returns. My code relies on inheriting more of NSButtonCell's standard
behaviour, so the mouse-up event was needed.)
- (BOOL) startTrackingAt:(NSPoint) startPoint inView:(NSView*)
controlView
{
// if there is a menu and show after delay is YES, start a timer for
showing the menu
if([self menu] && [self showsMenuAfterDelay] && mMenuTimer == nil)
{
mMenuTimer = [[NSTimer timerWithTimeInterval:[self menuDelay]
target:self selector:@selector(menuDelayCallback:) userInfo:nil repeats:NO]
retain];
[[NSRunLoop currentRunLoop] addTimer:mMenuTimer
forMode:NSEventTrackingRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:mMenuTimer
forMode:NSDefaultRunLoopMode];
// make a note of the mouse location for faking the mouse-up at
the end:
mMouseDownPoint = [controlView convertPoint:startPoint
toView:nil];
}
return [super startTrackingAt:startPoint inView:controlView];
}
- (void) menuDelayCallback:(NSTimer*) timer
{
#pragma unused(timer)
// show the cell's menu if the button is still highlighted (if user let
go, it won't be)
if([self isHighlighted])
{
// pop up the menu and switch tracking to it.
NSMenu* menu = [self menu];
NSEvent* event = [NSApp currentEvent];
// menu tracking keeps control until a choice is made:
[NSMenu popUpContextMenu:menu withEvent:event forView:[self
controlView]];
// on return, post a mouse-up so that the cell tracking
completes as normal. The mouse location
// was recorded at the time it went down and the callback was
scheduled
NSWindow* window = [[self controlView] window];
NSEvent* fakeMouseUp = [NSEvent mouseEventWithType:NSLeftMouseUp
location:mMouseDownPoint
modifierFlags:0
timestamp:[NSDate
timeIntervalSinceReferenceDate]
windowNumber:[window
windowNumber]
context:[NSGraphicsContext currentContext]
eventNumber:0
clickCount:1
pressure:0.0];
[window postEvent:fakeMouseUp atStart:YES];
// after a menu selection, ensure the button is set to its ON
state:
[(NSControl*)[self controlView] selectCell:self];
[self setState:NSOnState];
}
[mMenuTimer release];
mMenuTimer = nil;
}
--Graham
_______________________________________________
Cocoa-dev mailing list ([email protected])
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]