forked from dgrijalva/gitx
/
PBSourceViewCell.m
150 lines (115 loc) · 5.07 KB
/
PBSourceViewCell.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//
// PBSourceViewCell.m
// GitX
//
// Created by Nathan Kinsinger on 1/7/10.
// Copyright 2010 Nathan Kinsinger. All rights reserved.
//
#import "PBSourceViewCell.h"
#import "PBGitSidebarController.h"
#import "PBSourceViewBadge.h"
@interface PBSourceViewCell()
- (NSRect)infoButtonRectForBounds:(NSRect)bounds;
- (void)mouseEntered:(NSEvent *)event;
- (void)mouseExited:(NSEvent *)event;
@end
@implementation PBSourceViewCell
@synthesize iInfoButtonAction;
@synthesize showsActionButton;
@synthesize badge;
# pragma mark context menu delegate methods
- init {
if ((self = [super init])) {
}
return self;
}
- (NSMenu *) menuForEvent:(NSEvent *)event inRect:(NSRect)rect ofView:(NSOutlineView *)view
{
NSPoint point = [self.controlView convertPoint:[event locationInWindow] fromView:nil];
NSInteger row = [view rowAtPoint:point];
PBGitSidebarController *controller = (PBGitSidebarController*)[view delegate];
return [controller menuForRow:row];
}
#pragma mark drawing
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)outlineView
{
if(badge){
NSImage *checkedOutImage = [PBSourceViewBadge badge:badge forCell:self];
NSSize imageSize = [checkedOutImage size];
NSRect imageFrame;
NSDivideRect(cellFrame, &imageFrame, &cellFrame, imageSize.width + 3, NSMaxXEdge);
imageFrame.size = imageSize;
if ([outlineView isFlipped])
imageFrame.origin.y += floor((cellFrame.size.height + imageFrame.size.height) / 2);
else
imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
[checkedOutImage compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
}
[super drawWithFrame:cellFrame inView:outlineView];
}
#pragma mark -
#pragma mark Button support
- (NSRect)infoButtonRectForBounds:(NSRect)bounds {
CGFloat infoButtonWidth = 17.0f;
CGFloat infoButtonHeight = 11.0f;
return NSMakeRect(NSMaxX(bounds) - infoButtonWidth, NSMinY(bounds) + (NSHeight(bounds) - infoButtonHeight)/2.0f, infoButtonWidth, infoButtonHeight);
}
- (NSImage *)infoButtonImage {
// Construct an image name based on our current state
NSString *imageName = [NSString stringWithFormat:@"sourceListAction%@.png",
//[self isHighlighted] ? @"selected" : @"normal",
iMouseDownInInfoButton ? @"Over" :
iMouseHoveredInInfoButton ? @"Over" : @""];
return [NSImage imageNamed:imageName];
}
- (void)drawInteriorWithFrame:(NSRect)bounds inView:(NSView *)controlView {
[super drawInteriorWithFrame:bounds inView:controlView];
if (showsActionButton) {
NSRect infoButtonRect = [self infoButtonRectForBounds:bounds];
NSImage *anImage = [self infoButtonImage];
[anImage setFlipped:[controlView isFlipped]];
[anImage drawInRect:infoButtonRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
}
}
// Mouse tracking -- the only part we want to track is the "info" button
- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag {
NSPoint locationOfTouch = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
BOOL mouseInButton = NSMouseInRect(locationOfTouch, [self infoButtonRectForBounds:cellFrame], [controlView isFlipped]);
if (mouseInButton) {
[self mouseEntered:theEvent];
// show menu
NSMenu *menu = [self menuForEvent:theEvent inRect:cellFrame ofView:controlView];
if (menu){
[NSMenu popUpContextMenu:menu withEvent:theEvent forView:controlView];
return YES;
}
}
if (iMouseDownInInfoButton) {
// Send the action, and redisplay
iMouseDownInInfoButton = NO;
[controlView setNeedsDisplayInRect:cellFrame];
}
return [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:flag];
}
// Mouse movement tracking -- we have a custom NSOutlineView subclass that automatically lets us add mouseEntered:/mouseExited: support to any cell!
- (void)addTrackingAreasForView:(NSView *)controlView inRect:(NSRect)cellFrame withUserInfo:(NSDictionary *)userInfo mouseLocation:(NSPoint)mouseLocation {
NSRect infoButtonRect = [self infoButtonRectForBounds:cellFrame];
NSTrackingAreaOptions options = NSTrackingEnabledDuringMouseDrag | NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways;
BOOL mouseIsInside = NSMouseInRect(mouseLocation, infoButtonRect, [controlView isFlipped]);
if (mouseIsInside) {
options |= NSTrackingAssumeInside;
[controlView setNeedsDisplayInRect:cellFrame];
}
// We make the view the owner, and it delegates the calls back to the cell after it is properly setup for the corresponding row/column in the outlineview
NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect:infoButtonRect options:options owner:controlView userInfo:userInfo];
[controlView addTrackingArea:area];
}
- (void)mouseEntered:(NSEvent *)event {
iMouseHoveredInInfoButton = YES;
[(NSControl *)[self controlView] updateCell:self];
}
- (void)mouseExited:(NSEvent *)event {
iMouseHoveredInInfoButton = NO;
[(NSControl *)[self controlView] updateCell:self];
}
@end