diff --git a/Info.plist b/Info.plist index a5b7c5953..675bda8f4 100644 --- a/Info.plist +++ b/Info.plist @@ -401,7 +401,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.06 + 0.08 CFBundleSignature ???? CFBundleVersion diff --git a/ThirdParty/GCWindowMenu/GCOneShotEffectTimer.h b/ThirdParty/GCWindowMenu/GCOneShotEffectTimer.h new file mode 100644 index 000000000..eecf5aeeb --- /dev/null +++ b/ThirdParty/GCWindowMenu/GCOneShotEffectTimer.h @@ -0,0 +1,53 @@ +///********************************************************************************************************************************** +/// GCOneShotEffectTimer.h +/// GCDrawKit +/// +/// Created by graham on 24/04/2007. +/// Released under the Creative Commons license 2007 Apptree.net. +/// +/// +/// This work is licensed under the Creative Commons Attribution-ShareAlike 2.5 License. +/// To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.5/ or send a letter to +/// Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. +/// +///********************************************************************************************************************************** + +#import + + +@interface GCOneShotEffectTimer : NSObject +{ + NSTimer* _timer; + NSTimeInterval _start; + NSTimeInterval _total; + id _delegate; +} + ++ (id) oneShotWithTime:(NSTimeInterval) t forDelegate:(id) del; + +@end + + + +@interface NSObject (OneShotDelegate) + +- (void) oneShotHasReached:(float) relpos; +- (void) oneShotHasReachedInverse:(float) relpos; +- (void) oneShotComplete; + +@end + + +/* This class wraps up a very simple piece of timer functionality. It sets up a timer that will call the + delegate frequently with a value from 0..1. Once 1 is reached, it stops. + + This is useful for one-shot type animations such as fading out a window or similar. + + The inverse method is called with interval 1..0. + + The timer starts as soon as it is created. + + The timer attempts to maintain a 30fps rate, and is capped at this value. On slower systems, it will drop + frames as needed. + +*/ \ No newline at end of file diff --git a/ThirdParty/GCWindowMenu/GCOneShotEffectTimer.m b/ThirdParty/GCWindowMenu/GCOneShotEffectTimer.m new file mode 100644 index 000000000..122184220 --- /dev/null +++ b/ThirdParty/GCWindowMenu/GCOneShotEffectTimer.m @@ -0,0 +1,106 @@ +///********************************************************************************************************************************** +/// GCOneShotEffectTimer.m +/// GCDrawKit +/// +/// Created by graham on 24/04/2007. +/// Released under the Creative Commons license 2007 Apptree.net. +/// +/// +/// This work is licensed under the Creative Commons Attribution-ShareAlike 2.5 License. +/// To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.5/ or send a letter to +/// Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. +/// +///********************************************************************************************************************************** + +#import "GCOneShotEffectTimer.h" + +@interface GCOneShotEffectTimer (Private) + +- (id) initWithTimeInterval:(NSTimeInterval) t forDelegate:(id) del; +- (void) setDelegate:(id) del; +- (id) delegate; +- (void) osfx_callback:(NSTimer*) timer; + +@end + + +@implementation GCOneShotEffectTimer + ++ (id) oneShotWithTime:(NSTimeInterval) t forDelegate:(id) del +{ + GCOneShotEffectTimer* ft = [[GCOneShotEffectTimer alloc] initWithTimeInterval:t forDelegate:del]; + + // unlike the usual case, this is returned retained (by self, effectively). The one-shot releases + // itself when it's complete + + return ft; +} + + +- (id) initWithTimeInterval:(NSTimeInterval) t forDelegate:(id) del +{ + [super init]; + [self setDelegate:del]; + + _total = t; + _timer = [NSTimer scheduledTimerWithTimeInterval:1/60.0f target:self selector:@selector(osfx_callback:) userInfo:nil repeats:YES]; + _start = [NSDate timeIntervalSinceReferenceDate]; + + return self; +} + + +- (void) dealloc +{ + [_timer invalidate]; + [_delegate release]; + [super dealloc]; +} + + +- (void) setDelegate:(id) del +{ + // delegate is retained and released when one-shot completes. This allows some effects to work even + // though the original delegate might be released by the caller. + + [del retain]; + [_delegate release]; + _delegate = del; +} + + +- (id) delegate +{ + return _delegate; +} + + +- (void) osfx_callback:(NSTimer*) timer +{ + NSTimeInterval elapsed = [NSDate timeIntervalSinceReferenceDate] - _start; + float val = elapsed / _total; + + //NSLog(@"t = %f", val ); + + if ( elapsed > _total ) + { + [timer invalidate]; + _timer = nil; + + if ( _delegate && [_delegate respondsToSelector:@selector(oneShotComplete)]) + [_delegate oneShotComplete]; + + [self release]; + } + else + { + if ( _delegate && [_delegate respondsToSelector:@selector(oneShotHasReached:)]) + [_delegate oneShotHasReached:val]; + + if ( _delegate && [_delegate respondsToSelector:@selector(oneShotHasReachedInverse:)]) + [_delegate oneShotHasReachedInverse:1.0 - val]; + } +} + + +@end diff --git a/ThirdParty/GCWindowMenu/GCWindowMenu.h b/ThirdParty/GCWindowMenu/GCWindowMenu.h new file mode 100644 index 000000000..37dcb7b28 --- /dev/null +++ b/ThirdParty/GCWindowMenu/GCWindowMenu.h @@ -0,0 +1,44 @@ +///********************************************************************************************************************************** +/// GCWindowMenu.h +/// GCDrawKitUI +/// +/// Created by graham on 27/03/07. +/// Released under the Creative Commons license 2006 Apptree.net. +/// +/// +/// This work is licensed under the Creative Commons Attribution-ShareAlike 2.5 License. +/// To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.5/ or send a letter to +/// Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. +/// +///********************************************************************************************************************************** + +#import + + +@interface GCWindowMenu : NSWindow +{ + NSView* _mainView; + BOOL _passFirstClick; + BOOL _oneShotTracking; +} + ++ (GCWindowMenu*) windowMenu; ++ (GCWindowMenu*) windowMenuWithContentView:(NSView*) view; + +- (void) popUpAtPoint:(NSPoint) p withEvent:(NSEvent*) event; +- (void) popUpWithEvent:(NSEvent*) event; + +- (void) setMainView:(NSView*) aView sizeToFit:(BOOL) stf; +- (NSView*) mainView; + +- (void) setMainViewWantsFirstClick:(BOOL) firstClick; +- (void) setShouldCloseWhenViewTrackingReturns:(BOOL) cmup; + +@end + + +@interface NSEvent (GCAdditions) + +- (BOOL) isMouseEventType; + +@end \ No newline at end of file diff --git a/ThirdParty/GCWindowMenu/GCWindowMenu.m b/ThirdParty/GCWindowMenu/GCWindowMenu.m new file mode 100644 index 000000000..de1ebecac --- /dev/null +++ b/ThirdParty/GCWindowMenu/GCWindowMenu.m @@ -0,0 +1,610 @@ +///********************************************************************************************************************************** +/// GCWindowMenu.m +/// GCDrawKitUI +/// +/// Created by graham on 27/03/07. +/// Released under the Creative Commons license 2006 Apptree.net. +/// +/// +/// This work is licensed under the Creative Commons Attribution-ShareAlike 2.5 License. +/// To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.5/ or send a letter to +/// Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. +/// +///********************************************************************************************************************************** + +#import "GCWindowMenu.h" +#import "GCOneShotEffectTimer.h" + +@interface GCWindowMenu (Private) + ++ (void) popUpWindowMenu:(GCWindowMenu*) menu withEvent:(NSEvent*) event; ++ (void) popUpWindowMenu:(GCWindowMenu*) menu atPoint:(NSPoint) loc withEvent:(NSEvent*) event; + +- (void) trackWithEvent:(NSEvent*) event; +- (NSEvent*) transmogrify:(NSEvent*) event; + +@end + + +#define kGCDefaultWindowMenuSize (NSMakeRect(0, 0, 100, 28 )) +#define kGCMenuContentInset 2 + + +@implementation GCWindowMenu + +///********************************************************************************************************************* +/// +/// method: popUpWindowMenu:withEvent:forView: +/// scope: private class method +/// overrides: +/// description: pops up a custom popup menu, tracks it, then hides it again with a fadeout +/// +/// parameters: the custom popup window to display +/// the event to start the display with (usually from a mouse down) +/// result: none +/// +/// notes: the menu is positioned with its top, left point just to the left of, and slightly below, the +/// point given in the event +/// +///******************************************************************************************************************** + ++ (void) popUpWindowMenu:(GCWindowMenu*) menu withEvent:(NSEvent*) event +{ + NSPoint loc = [event locationInWindow]; + loc.x -= 10; + loc.y -= 5; + + [self popUpWindowMenu:menu atPoint:loc withEvent:event]; +} + + +///********************************************************************************************************************* +/// +/// method: popUpWindowMenu:atPoint:withEvent:forView: +/// scope: private class method +/// overrides: +/// description: pops up a custom popup menu, tracks it, then hides it again with a fadeout +/// +/// parameters: the custom popup window to display +/// the location within the window at which to display the menu (top, left of menu) +/// the event to start the display with (usually from a mouse down) +/// result: none +/// +/// notes: +/// +///******************************************************************************************************************** + ++ (void) popUpWindowMenu:(GCWindowMenu*) menu atPoint:(NSPoint) loc withEvent:(NSEvent*) event +{ + if ( menu == nil ) + menu = [GCWindowMenu windowMenu]; + + [menu retain]; + + loc = [[event window] convertBaseToScreen:loc]; + [menu setFrameTopLeftPoint:loc]; + [[event window] addChildWindow:menu ordered:NSWindowAbove]; + + // show the "menu" + + [menu orderFront:self]; + + // track the menu (keeps control in its own event loop): + + [menu trackWithEvent:event]; + + // all done, tear down - remove with a fade effect + + [GCOneShotEffectTimer oneShotWithTime:0.15 forDelegate:menu]; + [menu release]; +} + + + +///********************************************************************************************************************* +/// +/// method: windowMenu +/// scope: public class method +/// overrides: +/// description: makes a window menu that can be popped up using the above methods. +/// +/// parameters: none +/// result: a new poppable window menu +/// +/// notes: this method just makes an empy window with the default size. It's up to you to add some useful +/// content before displaying it +/// +///******************************************************************************************************************** + ++ (GCWindowMenu*) windowMenu +{ + GCWindowMenu* fi = [[GCWindowMenu alloc] initWithContentRect:NSZeroRect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:YES]; + + // note - because windows are all sent a -close message at quit time, set it + // not to be released at that time, otherwise the release from the autorelease pool + // will cause a crash due to the stale reference + + [fi setReleasedWhenClosed:NO]; // **** important!! **** + return [fi autorelease]; +} + + +///********************************************************************************************************************* +/// +/// method: windowMenuWithContentView: +/// scope: public class method +/// overrides: +/// description: makes a window menu that can be popped up using the above methods. +/// +/// parameters: the view to display within the menu +/// result: a new poppable window menu containing the given view +/// +/// notes: the window is sized to fit the frame of the view you pass. +/// +///******************************************************************************************************************** + ++ (GCWindowMenu*) windowMenuWithContentView:(NSView*) view +{ + GCWindowMenu* menu = [self windowMenu]; + + [menu setMainView:view sizeToFit:YES]; + return menu; +} + + +///********************************************************************************************************************* +/// +/// method: popUpAtPoint:withEvent:forView: +/// scope: public instance method +/// overrides: +/// description: pops up a custom popup menu, tracks it, then hides it again with a fadeout +/// +/// parameters:

the location within the window at which to display the menu (top, left of menu) +/// the event to start the display with (usually from a mouse down in some view) +/// result: none +/// +/// notes: +/// +///******************************************************************************************************************** + +- (void) popUpAtPoint:(NSPoint) p withEvent:(NSEvent*) event +{ + [[self class] popUpWindowMenu:self atPoint:p withEvent:event]; +} + + +///********************************************************************************************************************* +/// +/// method: popUpWithEvent:forView: +/// scope: public instance method +/// overrides: +/// description: pops up a custom popup menu, tracks it, then hides it again with a fadeout +/// +/// parameters: the event to start the display with (usually from a mouse down in some view) +/// result: none +/// +/// notes: +/// +///******************************************************************************************************************** + +- (void) popUpWithEvent:(NSEvent*) event +{ + [[self class] popUpWindowMenu:self withEvent:event]; +} + + + +///********************************************************************************************************************* +/// +/// method: initWithContentRect:styleMask:backing:defer: +/// scope: public instance method +/// overrides: NSWindow +/// description: designated initializer. +/// +/// parameters: <> see NSWindow +/// result: the window +/// +/// notes: +/// +///******************************************************************************************************************** + +- (id) initWithContentRect:(NSRect) contentRect + styleMask:(unsigned int) styleMask + backing:(NSBackingStoreType) bufferingType + defer:(BOOL) deferCreation +{ + if ((self = [super initWithContentRect:contentRect + styleMask:styleMask + backing:bufferingType + defer:deferCreation]) != nil ) + { + [self setLevel:NSPopUpMenuWindowLevel]; + [self setHasShadow:YES]; + [self setAlphaValue:0.95]; + [self setReleasedWhenClosed:YES]; + [self setFrame:kGCDefaultWindowMenuSize display:NO]; + + _mainView = nil; + _passFirstClick = YES; + _oneShotTracking = YES; + } + + return self; +} + + + +///********************************************************************************************************************* +/// +/// method: trackWithEvent: +/// scope: public instance method +/// overrides: +/// description: track the mouse in the menu +/// +/// parameters: the initial starting event (will usually be a mouse down) +/// result: none +/// +/// notes: tracking calls the main view's usual mouseDown/dragged/up methods, and tries to do so as compatibly +/// as possible with the usual view behaviours. +/// +///******************************************************************************************************************** + +- (void) trackWithEvent:(NSEvent*) event +{ + // tracks the "menu" by keeping control until a mouse up (or down, if menu 'clicked' into being) + + NSLog(@"starting tracking; initial event = %@", event); + + //[NSEvent startPeriodicEventsAfterDelay:1.0 withPeriod:0.1]; + + NSTimeInterval startTime = [event timestamp]; + + [self setAcceptsMouseMovedEvents:YES]; + + if ( _passFirstClick ) + { + [[self mainView] mouseDown:[self transmogrify:event]]; + + // the view may have trapped the mouse down and implemented its own tracking. + // Standard NSControls do that for example. In that case we don't want to track + // ourselves, so need to detect that and abort. + + if ([[self currentEvent] timestamp] - startTime > 0.25 ) + return; + } + + NSEvent* theEvent; + BOOL keepOn = YES; + unsigned int mask; + BOOL invertedTracking = NO; + + mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask | + NSRightMouseUpMask | NSRightMouseDraggedMask | + NSAppKitDefinedMask | NSFlagsChangedMask | + NSScrollWheelMask; + + while (keepOn) + { + theEvent = [self transmogrify:[self nextEventMatchingMask:mask]]; + + switch ([theEvent type]) + { + case NSMouseMovedMask: + [[self mainView] mouseMoved:theEvent]; + break; + + case NSRightMouseDragged: + case NSLeftMouseDragged: + [[self mainView] mouseDragged:theEvent]; + break; + + case NSRightMouseUp: + case NSLeftMouseUp: + // if this is within a very short time of the mousedown, leave the menu up but track it + // using mouse moved and mouse down to end. + + if ([theEvent timestamp] - startTime < 0.25 || !_passFirstClick ) + { + invertedTracking = YES; + mask |= ( NSLeftMouseDownMask | NSRightMouseDownMask | NSMouseMovedMask ); + } + else + { + [[self mainView] mouseUp:theEvent]; + keepOn = NO; + } + break; + + case NSRightMouseDown: + case NSLeftMouseDown: + if ( ! NSPointInRect([theEvent locationInWindow], [[self mainView] frame])) + keepOn = NO; + else + { + [[self mainView] mouseDown:theEvent]; + + if ( _oneShotTracking ) + keepOn = NO; + } + break; + + case NSPeriodic: + break; + + case NSFlagsChanged: + [[self mainView] flagsChanged:theEvent]; + break; + + case NSAppKitDefined: + if([theEvent subtype] == NSApplicationDeactivatedEventType ) + keepOn = NO; + break; + + case NSScrollWheel: + [[self mainView] scrollWheel:theEvent]; + break; + + default: + /* Ignore any other kind of event. */ + break; + } + } + + [self discardEventsMatchingMask:NSAnyEventMask beforeEvent:theEvent]; + + //[NSEvent stopPeriodicEvents]; + NSLog(@"tracking ended"); +} + + + +///********************************************************************************************************************* +/// +/// method: transmogrify: +/// scope: private instance method +/// overrides: +/// description: convert the event to the local window if necessary +/// +/// parameters: an event +/// result: the same event, or a modified version +/// +/// notes: ensures that events received while tracking are always targetted at the right window +/// +///******************************************************************************************************************** + +- (NSEvent*) transmogrify:(NSEvent*) event +{ + if(([event window] != self) && [event isMouseEventType]) + { + NSPoint glob = [[event window] convertBaseToScreen:[event locationInWindow]]; + + return [NSEvent mouseEventWithType: [event type] + location: [self convertScreenToBase:glob] + modifierFlags: [event modifierFlags] + timestamp: [event timestamp] + windowNumber: [self windowNumber] + context: [event context] + eventNumber: [event eventNumber] + clickCount: [event clickCount] + pressure: [event pressure]]; + } + else + return event; +} + + +///********************************************************************************************************************* +/// +/// method: canBecomeMainWindow +/// scope: public instance method +/// overrides: NSWindow +/// description: +/// +/// parameters: none +/// result: return YES +/// +/// notes: +/// +///******************************************************************************************************************** + +- (BOOL) canBecomeMainWindow +{ + return NO; +} + + +///********************************************************************************************************************* +/// +/// method: setMainView:sizeToFit: +/// scope: public instance method +/// overrides: +/// description: sets the pop-up window's content to the given view, and optionally sizes the window to fit +/// +/// parameters: any view already created to be displayed in the menu +/// if YES, window is sized to the view's frame. If NO, the window size is not changed +/// result: none +/// +/// notes: main view is additionally retained so outlet from NIB may be directly passed in +/// +///******************************************************************************************************************** + +- (void) setMainView:(NSView*) aView sizeToFit:(BOOL) stf +{ + [aView retain]; + [_mainView release]; + _mainView = aView; + + // add as a subview which retains it as well + + [[self contentView] addSubview:aView]; + + // if stf, position the view at top, left corner of the window and + // make the window the size of the view + + if ( stf ) + { + NSRect fr = [self frameRectForContentRect:NSInsetRect( [aView frame], -kGCMenuContentInset, -kGCMenuContentInset )]; + + fr.origin = NSZeroPoint; + [aView setFrameOrigin:NSMakePoint( kGCMenuContentInset, kGCMenuContentInset )]; + [self setFrame:fr display:YES]; + } + + [_mainView setNeedsDisplay:YES]; + + // if the view added is an NSControl, set first click to NO by default + + if ([aView isKindOfClass:[NSControl class]]) + [self setMainViewWantsFirstClick:NO]; +} + + +///********************************************************************************************************************* +/// +/// method: mainView +/// scope: public instance method +/// overrides: +/// description: get the main view +/// +/// parameters: none +/// result: the main view +/// +/// notes: +/// +///******************************************************************************************************************** + +- (NSView*) mainView +{ + return _mainView; +} + + +///********************************************************************************************************************* +/// +/// method: setMainViewWantsFirstClick: +/// scope: public instance method +/// overrides: +/// description: sets whether the main view should receive a mouse down on entry to the tracking loop +/// +/// parameters: YES to get the first click +/// result: none +/// +/// notes: normally should be YES (the default). However views such as NSControl derivatives that implement +/// their own tracking should set NO. If NO, the popup can only be operated by clicking to open, then +/// clicking and dragging within - the continuous click to open, drag through and release operation +/// wont work because the control doesn't get a mouse down to start with. +/// +///******************************************************************************************************************** + +- (void) setMainViewWantsFirstClick:(BOOL) firstClick +{ + _passFirstClick = firstClick; +} + + +///********************************************************************************************************************* +/// +/// method: setShouldCloseWhenViewTrackingReturns: +/// scope: public instance method +/// overrides: +/// description: sets whether popup should close or remain visible after main view completes its own tracking +/// +/// parameters: YES close on return from view tracking, NO to remain visble +/// result: none +/// +/// notes: this affects tracking with views that implement their own tracking, such as NSControl. If YES, you +/// get one shot at the control - after operating it, it will be hidden. If NO, the control may be +/// changed as often as you want but you must manually click outside the menu to close it. +/// +///******************************************************************************************************************** + +- (void) setShouldCloseWhenViewTrackingReturns:(BOOL) cmup +{ + _oneShotTracking = cmup; +} + + +///********************************************************************************************************************* +/// +/// method: oneShotHasReachedInverse: +/// scope: public instance method +/// overrides: NSObject (OneShotDelegate) +/// description: callback from fade out effect +/// +/// parameters: goes from 1..0 +/// result: none +/// +/// notes: +/// +///******************************************************************************************************************** + +- (void) oneShotHasReachedInverse:(float) relpos +{ + [self setAlphaValue:relpos]; +} + + +///********************************************************************************************************************* +/// +/// method: oneShotComplete +/// scope: public instance method +/// overrides: NSObject (OneShotDelegate) +/// description: callback from fade out effect +/// +/// parameters: none +/// result: none +/// +/// notes: removes the window from screen - oneshot will then release it +/// +///******************************************************************************************************************** + +- (void) oneShotComplete +{ + [[self parentWindow] removeChildWindow:self]; + [self orderOut:self]; +} + + + + + +@end + + +@implementation NSEvent (GCAdditions) + +///********************************************************************************************************************* +/// +/// method: isMouseEventType: +/// scope: public instance method +/// overrides: +/// description: checks event to see if it's any mouse event +/// +/// parameters: none +/// result: YES if the event is a mouse event of any kind +/// +/// notes: +/// +///******************************************************************************************************************** + +- (BOOL) isMouseEventType +{ + // returns YES if type is any mouse type + + NSEventType t = [self type]; + + return ( t == NSLeftMouseDown || + t == NSLeftMouseUp || + t == NSRightMouseDown || + t == NSRightMouseUp || + t == NSLeftMouseDragged || + t == NSRightMouseDragged || + t == NSOtherMouseDown || + t == NSOtherMouseUp || + t == NSOtherMouseDragged ); +} + +@end diff --git a/ThirdParty/GCWindowMenu/PopupButton.h b/ThirdParty/GCWindowMenu/PopupButton.h new file mode 100644 index 000000000..d9e20412c --- /dev/null +++ b/ThirdParty/GCWindowMenu/PopupButton.h @@ -0,0 +1,19 @@ +// +// GCPopTestView.h +// GCWindowMenuTest +// +// Created by Graham on Tue Apr 24 2007. Modified from NSView to NSButton by Vincent Spader. +// Copyright (c) 2007 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface PopupButton : NSButton +{ + NSImage* _popButton; + IBOutlet NSView *_popView; + BOOL _hilited; +} + +@end diff --git a/ThirdParty/GCWindowMenu/PopupButton.m b/ThirdParty/GCWindowMenu/PopupButton.m new file mode 100644 index 000000000..7fdd76092 --- /dev/null +++ b/ThirdParty/GCWindowMenu/PopupButton.m @@ -0,0 +1,39 @@ +// +// GCPopTestView.m +// GCWindowMenuTest +// +// Created by Graham on Tue Apr 24 2007. +// Copyright (c) 2007 __MyCompanyName__. All rights reserved. +// + +#import "PopupButton.h" +#import "GCWindowMenu.h" + + +@implementation PopupButton + +- (void) mouseDown:(NSEvent*) event +{ + // create the menu to pop up using the view connected to the _popView outlet + + GCWindowMenu* menu = [GCWindowMenu windowMenuWithContentView:_popView]; + [menu setShouldCloseWhenViewTrackingReturns:YES]; + + // place the menu relative to our window + NSPoint p = [self bounds].origin; + p.y += [self bounds].size.height; + p.x += ([self bounds].size.width - [[[_popView window] contentView] bounds].size.width)/2.0; + p = [self convertPoint:p toView:nil]; + + // draw self highlighted + [self highlight:YES]; + + // pop up and track the menu + [menu popUpAtPoint:p withEvent:event]; + + // unhighlight self + [self highlight:NO]; +} + + +@end