GitIndex: add commit notifications
[GitX.git] / PBIconAndTextCell.m
blobc2c00520604117d179f8e781c6f935eb3d2b80c4
1 //
2 //  PBIconAndTextCell.m
3 //  GitX
4 //
5 //  Created by CiarĂ¡n Walsh on 23/09/2008.
6 //  Copyright 2008 __MyCompanyName__. All rights reserved.
7 //
8 // Adopted from http://www.cocoadev.com/index.pl?NSTableViewImagesAndText
10 #import "PBIconAndTextCell.h"
13 @implementation PBIconAndTextCell
14 @synthesize image;
16 - (void)dealloc
18         self.image = nil;
19         [super dealloc];
22 - (id)copyWithZone:(NSZone *)zone
24         PBIconAndTextCell *cell = [super copyWithZone:zone];
25         cell.image              = image;
26         return cell;
29 - (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength
31         NSRect textFrame, imageFrame;
32         NSDivideRect (aRect, &imageFrame, &textFrame, 3 + [image size].width, NSMinXEdge);
33         [super selectWithFrame: textFrame inView: controlView editor:textObj delegate:anObject start:selStart length:selLength];
36 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
38         if (image) {
39                 NSSize  imageSize;
40                 NSRect  imageFrame;
42                 imageSize = [image size];
43                 NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
44                 if ([self drawsBackground]) {
45                         [[self backgroundColor] set];
46                         NSRectFill(imageFrame);
47                 }
48                 imageFrame.origin.x += 3;
49                 imageFrame.size = imageSize;
51                 if ([controlView isFlipped])
52                         imageFrame.origin.y += floor((cellFrame.size.height + imageFrame.size.height) / 2);
53                 else
54                         imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
56                 [image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
57         }
58         [super drawWithFrame:cellFrame inView:controlView];
61 - (NSSize)cellSize
63         NSSize cellSize = [super cellSize];
64         cellSize.width += (image ? [image size].width : 0) + 3;
65         return cellSize;
68 // ===============
69 // = Hit testing =
70 // ===============
71 // Adopted from PhotoSearch Apple sample code
73 - (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView
75         NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil];
77         NSRect textFrame, imageFrame;
78         NSDivideRect (cellFrame, &imageFrame, &textFrame, 3 + [image size].width, NSMinXEdge);
79         if (NSMouseInRect(point, imageFrame, [controlView isFlipped]))
80                 return NSCellHitContentArea | NSCellHitTrackableArea;
82         return [super hitTestForEvent:event inRect:cellFrame ofView:controlView];
85 + (BOOL)prefersTrackingUntilMouseUp
87         // NSCell returns NO for this by default. If you want to have trackMouse:inRect:ofView:untilMouseUp: always track until the mouse is up, then you MUST return YES. Otherwise, strange things will happen.
88         return YES;
91 - (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag
93         [self setControlView:controlView];
95         NSRect textFrame, imageFrame;
96         NSDivideRect (cellFrame, &imageFrame, &textFrame, 3 + [image size].width, NSMinXEdge);
97         while ([theEvent type] != NSLeftMouseUp) {
98                 // This is VERY simple event tracking. We simply check to see if the mouse is in the "i" button or not and dispatch entered/exited mouse events
99                 NSPoint point = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
100                 BOOL mouseInButton = NSMouseInRect(point, imageFrame, [controlView isFlipped]);
101                 if (mouseDownInButton != mouseInButton) {
102                         mouseDownInButton = mouseInButton;
103                         [controlView setNeedsDisplayInRect:cellFrame];
104                 }
105                 if ([theEvent type] == NSMouseEntered || [theEvent type] == NSMouseExited)
106                         [NSApp sendEvent:theEvent];
107                 // Note that we process mouse entered and exited events and dispatch them to properly handle updates
108                 theEvent = [[controlView window] nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask | NSMouseEnteredMask | NSMouseExitedMask)];
109         }
111         // Another way of implementing the above code would be to keep an NSButtonCell as an ivar, and simply call trackMouse:inRect:ofView:untilMouseUp: on it, if the tracking area was inside of it.
112         if (mouseDownInButton) {
113                 // Send the action, and redisplay
114                 mouseDownInButton = NO;
115                 [controlView setNeedsDisplayInRect:cellFrame];
116                 if (self.action)
117                         [NSApp sendAction:self.action to:self.target from:self];
118         }
120         // We return YES since the mouse was released while we were tracking. Not returning YES when you processed the mouse up is an easy way to introduce bugs!
121         return YES;
124 @end