2 // AIHoveringPopUpButton.m
5 // Created by Evan Schoenberg on 12/16/05.
8 #import "AIHoveringPopUpButton.h"
9 #import "AIHoveringPopUpButtonCell.h"
11 @implementation AIHoveringPopUpButton
14 [self setCellClass:[AIHoveringPopUpButtonCell class]];
17 - (void)initHoveringPopUpButton
19 [[NSNotificationCenter defaultCenter] addObserver:self
20 selector:@selector(frameDidChange:)
21 name:NSViewFrameDidChangeNotification
23 [self setPostsFrameChangedNotifications:YES];
26 [self resetCursorRects];
28 highlightOnHoverAndClick = YES;
31 - (id)initWithFrame:(NSRect)inFrame
33 if ((self = [super initWithFrame:inFrame])) {
34 [self initHoveringPopUpButton];
42 if ([[AIHoveringPopUpButton superclass] instancesRespondToSelector:@selector(awakeFromNib)]) {
46 [self initHoveringPopUpButton];
50 - (id)copyWithZone:(NSZone *)zone
52 AIHoveringPopUpButton *newButton = [[[self class] allocWithZone:zone] initWithFrame:[self frame]];
54 [newButton setMenu:[[[self menu] copy] autorelease]];
60 - (void)setMenu:(NSMenu *)menu {
62 [[self cell] setMenu:menu];
65 - (void)setDoubleAction:(SEL)inDoubleAction
67 doubleAction = inDoubleAction;
72 [[NSNotificationCenter defaultCenter] removeObserver:self];
74 if (trackingTag != -1) {
75 [self removeTrackingRect:trackingTag];
82 //Mouse Tracking -------------------------------------------------------------------------------------------------------
83 #pragma mark Mouse Tracking
84 //Custom mouse down tracking to display our menu and highlight
85 - (void)mouseDown:(NSEvent *)theEvent
88 if (doubleAction && (([theEvent clickCount] % 2) == 0)) {
89 [[self target] performSelector:doubleAction
92 [super mouseDown:theEvent];
96 if ([self isEnabled]) {
99 [self setNeedsDisplay:YES];
101 //2 pt down, 1 pt to the left.
102 NSPoint point = [self convertPoint:[self bounds].origin toView:nil];
103 point.y -= NSHeight([self frame]) + 2;
106 NSEvent *event = [NSEvent mouseEventWithType:[theEvent type]
108 modifierFlags:[theEvent modifierFlags]
109 timestamp:[theEvent timestamp]
110 windowNumber:[[theEvent window] windowNumber]
111 context:[theEvent context]
112 eventNumber:[theEvent eventNumber]
113 clickCount:[theEvent clickCount]
114 pressure:[theEvent pressure]];
115 [NSMenu popUpContextMenu:[self menu] withEvent:event forView:self];
117 [self mouseUp:[[NSApplication sharedApplication] currentEvent]];
123 * @brief Only pass on a highlight message if we're highlighting on click or this is turning off a highlight
125 - (void)highlight:(BOOL)inFlag
127 if (!inFlag || highlightOnHoverAndClick) {
128 [super highlight:inFlag];
132 //Remove highlight on mouse up
133 - (void)mouseUp:(NSEvent *)theEvent
136 [super mouseUp:theEvent];
140 - (void)mouseDragged:(NSEvent *)theEvent
145 - (NSView *)hitTest:(NSPoint)aPoint
147 NSRect myFrame = [self frame];
148 myFrame.size.width = [[self cell] trackingWidth];
150 if (NSPointInRect(aPoint, myFrame)) {
151 return [super hitTest:aPoint];
158 * @brief Set the title
160 - (void)setTitle:(NSString *)inTitle
162 [[self cell] setTitle:inTitle];
163 [self setNeedsDisplay:YES];
165 [self resetCursorRects];
168 - (void)setFont:(NSFont *)inFont
170 [[self cell] setFont:inFont];
171 [self setNeedsDisplay:YES];
174 - (void)setImage:(NSImage *)inImage
176 [[self cell] setImage:inImage];
177 [self setNeedsDisplay:YES];
179 [self resetCursorRects];
182 - (void)setHighlightOnHoverAndClick:(BOOL)inHighlightOnHoverAndClick
184 highlightOnHoverAndClick = inHighlightOnHoverAndClick;
186 //If we are not going to highlight, ensure we're not currently doing so
187 if (!highlightOnHoverAndClick) {
188 [[self cell] setHovered:NO animate:NO];
189 [self setNeedsDisplay:YES];
193 #pragma mark Tracking rects
194 //Remove old tracking rects when we change superviews
195 - (void)viewWillMoveToSuperview:(NSView *)newSuperview
197 if (trackingTag != -1) {
198 [self removeTrackingRect:trackingTag];
202 [super viewWillMoveToSuperview:newSuperview];
205 - (void)viewDidMoveToSuperview
207 [super viewDidMoveToSuperview];
209 [self resetCursorRects];
212 - (void)viewWillMoveToWindow:(NSWindow *)newWindow
214 if (trackingTag != -1) {
215 [self removeTrackingRect:trackingTag];
219 [super viewWillMoveToWindow:newWindow];
222 - (void)viewDidMoveToWindow
224 [super viewDidMoveToWindow];
226 [self resetCursorRects];
229 - (void)frameDidChange:(NSNotification *)inNotification
231 [self resetCursorRects];
234 - (NSRect)trackingRect
236 return NSMakeRect(0, 0, [[self cell] trackingWidth], [self frame].size.height);
239 //Reset our cursor tracking
240 - (void)resetCursorRects
242 //Stop any existing tracking
243 if (trackingTag != -1) {
244 [self removeTrackingRect:trackingTag];
248 //Add a tracking rect if our superview and window are ready
249 if ([self superview] && [self window]) {
250 NSRect myFrame = [self frame];
251 NSRect trackRect = [self trackingRect];
253 if (trackRect.size.width > myFrame.size.width) {
254 trackRect.size.width = myFrame.size.width;
257 NSPoint localPoint = [self convertPoint:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
259 BOOL mouseInside = NSPointInRect(localPoint, trackRect);
261 trackingTag = [self addTrackingRect:trackRect owner:self userData:nil assumeInside:mouseInside];
263 [self mouseEntered:nil];
265 [self mouseExited:nil];
270 //Cursor entered our view
271 - (void)mouseEntered:(NSEvent *)theEvent
273 if (highlightOnHoverAndClick && ![[self cell] hovered]) {
274 [[self cell] setHovered:YES animate:YES];
275 [self setNeedsDisplay:YES];
278 [super mouseEntered:theEvent];
282 //Cursor left our view
283 - (void)mouseExited:(NSEvent *)theEvent
285 if (highlightOnHoverAndClick && [[self cell] hovered]) {
286 [[self cell] setHovered:NO animate:YES];
287 [self setNeedsDisplay:YES];
290 [super mouseExited:theEvent];