mirror of
https://github.com/kennethreitz-archive/gitx.git
synced 2026-06-05 23:40:18 +00:00
4a9abd2d8c
If there are a large number of refs pointing to a commit, then they may be drawn on top of or behind the other columns. This will not show any labels that don't fit.
307 lines
9.0 KiB
Objective-C
307 lines
9.0 KiB
Objective-C
//
|
|
// PBGitRevisionCell.m
|
|
// GitX
|
|
//
|
|
// Created by Pieter de Bie on 17-06-08.
|
|
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
|
//
|
|
|
|
#import "PBGitRevisionCell.h"
|
|
#import "PBGitRef.h"
|
|
#import "RoundedRectangle.h"
|
|
|
|
@implementation PBGitRevisionCell
|
|
|
|
|
|
- (id) initWithCoder: (id) coder
|
|
{
|
|
self = [super initWithCoder:coder];
|
|
textCell = [[NSTextFieldCell alloc] initWithCoder:coder];
|
|
return self;
|
|
}
|
|
|
|
- (NSArray*) colors
|
|
{
|
|
return [NSArray arrayWithObjects:
|
|
[NSColor colorWithCalibratedRed: 0X4e/256.0 green:0X9A/256.0 blue: 0X06/256.0 alpha: 1.0],
|
|
[NSColor colorWithCalibratedRed: 0X20/256.0 green:0X4A/256.0 blue: 0X87/256.0 alpha: 1.0],
|
|
[NSColor colorWithCalibratedRed: 0XC4/256.0 green:0XA0/256.0 blue: 0 alpha: 1.0],
|
|
[NSColor colorWithCalibratedRed: 0X5C/256.0 green:0X35/256.0 blue: 0X66/256.0 alpha: 1.0],
|
|
[NSColor colorWithCalibratedRed: 0XA4/256.0 green:0X00/256.0 blue: 0X00/256.0 alpha: 1.0],
|
|
[NSColor colorWithCalibratedRed: 0XCE/256.0 green:0X5C/256.0 blue: 0 alpha: 1.0],
|
|
nil];
|
|
}
|
|
|
|
- (void) drawLineFromColumn: (int) from toColumn: (int) to inRect: (NSRect) r offset: (int) offset color: (int) c
|
|
{
|
|
|
|
int columnWidth = 10;
|
|
NSPoint origin = r.origin;
|
|
|
|
NSPoint source = NSMakePoint(origin.x + columnWidth* from, origin.y + offset);
|
|
NSPoint center = NSMakePoint( origin.x + columnWidth * to, origin.y + r.size.height * 0.5 + 0.5);
|
|
|
|
// Just use red for now.
|
|
NSArray* colors = [self colors];
|
|
[[colors objectAtIndex: c % [colors count]] set];
|
|
|
|
NSBezierPath * path = [NSBezierPath bezierPath];
|
|
[path setLineWidth:2];
|
|
|
|
[path moveToPoint: source];
|
|
[path lineToPoint: center];
|
|
[path stroke];
|
|
|
|
}
|
|
|
|
- (void) drawCircleInRect: (NSRect) r
|
|
{
|
|
|
|
int c = cellInfo.position;
|
|
int columnWidth = 10;
|
|
NSPoint origin = r.origin;
|
|
NSPoint columnOrigin = { origin.x + columnWidth * c, origin.y};
|
|
|
|
NSRect oval = { columnOrigin.x - 5, columnOrigin.y + r.size.height * 0.5 - 5, 10, 10};
|
|
|
|
|
|
NSBezierPath * path = [NSBezierPath bezierPathWithOvalInRect:oval];
|
|
|
|
[[NSColor blackColor] set];
|
|
[path fill];
|
|
|
|
NSRect smallOval = { columnOrigin.x - 3, columnOrigin.y + r.size.height * 0.5 - 3, 6, 6};
|
|
[[NSColor whiteColor] set];
|
|
path = [NSBezierPath bezierPathWithOvalInRect:smallOval];
|
|
[path fill];
|
|
}
|
|
|
|
- (void) drawTriangleInRect: (NSRect) r sign: (char) sign
|
|
{
|
|
int c = cellInfo.position;
|
|
int columnHeight = 10;
|
|
int columnWidth = 8;
|
|
|
|
NSPoint top;
|
|
if (sign == '<')
|
|
top.x = round(r.origin.x) + 10 * c + 4;
|
|
else {
|
|
top.x = round(r.origin.x) + 10 * c - 4;
|
|
columnWidth *= -1;
|
|
}
|
|
top.y = r.origin.y + (r.size.height - columnHeight) / 2;
|
|
|
|
NSBezierPath * path = [NSBezierPath bezierPath];
|
|
// Start at top
|
|
[path moveToPoint: NSMakePoint(top.x, top.y)];
|
|
// Go down
|
|
[path lineToPoint: NSMakePoint(top.x, top.y + columnHeight)];
|
|
// Go left top
|
|
[path lineToPoint: NSMakePoint(top.x - columnWidth, top.y + columnHeight / 2)];
|
|
// Go to top again
|
|
[path closePath];
|
|
|
|
[[NSColor whiteColor] set];
|
|
[path fill];
|
|
[[NSColor blackColor] set];
|
|
[path setLineWidth: 2];
|
|
[path stroke];
|
|
}
|
|
|
|
- (NSMutableDictionary*) attributesForRefLabelSelected: (BOOL) selected
|
|
{
|
|
NSMutableDictionary *attributes = [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
|
|
NSMutableParagraphStyle* style = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
|
|
|
|
[style setAlignment:NSCenterTextAlignment];
|
|
[attributes setObject:style forKey:NSParagraphStyleAttributeName];
|
|
[attributes setObject:[NSFont fontWithName:@"Helvetica" size:9] forKey:NSFontAttributeName];
|
|
|
|
//if (selected)
|
|
// [attributes setObject:[NSColor alternateSelectedControlTextColor] forKey:NSForegroundColorAttributeName];
|
|
|
|
return attributes;
|
|
}
|
|
|
|
- (NSColor*) colorForRef: (PBGitRef*) ref
|
|
{
|
|
BOOL isHEAD = [ref.ref isEqualToString:[[[controller repository] headRef] simpleRef]];
|
|
|
|
if (isHEAD)
|
|
return [NSColor colorWithCalibratedRed: 0Xfc/256.0 green:0Xa6/256.0 blue: 0X4f/256.0 alpha: 1.0];
|
|
|
|
NSString* type = [ref type];
|
|
if ([type isEqualToString:@"head"])
|
|
return [NSColor colorWithCalibratedRed: 0Xaa/256.0 green:0Xf2/256.0 blue: 0X54/256.0 alpha: 1.0];
|
|
else if ([type isEqualToString:@"remote"])
|
|
return [NSColor colorWithCalibratedRed: 0xb2/256.0 green:0Xdf/256.0 blue: 0Xff/256.0 alpha: 1.0];
|
|
else if ([type isEqualToString:@"tag"])
|
|
return [NSColor colorWithCalibratedRed: 0Xfc/256.0 green:0Xed/256.0 blue: 0X4f/256.0 alpha: 1.0];
|
|
|
|
return [NSColor yellowColor];
|
|
}
|
|
|
|
-(NSArray *)rectsForRefsinRect:(NSRect) rect;
|
|
{
|
|
NSMutableArray *array = [NSMutableArray array];
|
|
|
|
static const int ref_padding = 10;
|
|
static const int ref_spacing = 2;
|
|
|
|
NSRect lastRect = rect;
|
|
lastRect.origin.x = round(lastRect.origin.x) + 0.5;
|
|
lastRect.origin.y = round(lastRect.origin.y) + 0.5;
|
|
|
|
for (PBGitRef *ref in self.objectValue.refs) {
|
|
NSMutableDictionary* attributes = [self attributesForRefLabelSelected:NO];
|
|
NSSize textSize = [[ref shortName] sizeWithAttributes:attributes];
|
|
|
|
NSRect newRect = lastRect;
|
|
newRect.size.width = textSize.width + ref_padding;
|
|
newRect.size.height = textSize.height;
|
|
newRect.origin.y = rect.origin.y + (rect.size.height - newRect.size.height) / 2;
|
|
|
|
if (NSContainsRect(rect, newRect)) {
|
|
[array addObject:[NSValue valueWithRect:newRect]];
|
|
lastRect = newRect;
|
|
lastRect.origin.x += (int)lastRect.size.width + ref_spacing;
|
|
}
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
- (void) drawLabelAtIndex:(int)index inRect:(NSRect)rect
|
|
{
|
|
NSArray *refs = self.objectValue.refs;
|
|
PBGitRef *ref = [refs objectAtIndex:index];
|
|
|
|
NSMutableDictionary* attributes = [self attributesForRefLabelSelected:[self isHighlighted]];
|
|
NSBezierPath *border = [NSBezierPath bezierPathWithRoundedRect:rect cornerRadius: 2.0];
|
|
[[self colorForRef:ref] set];
|
|
[border fill];
|
|
|
|
[[ref shortName] drawInRect:rect withAttributes:attributes];
|
|
[border stroke];
|
|
}
|
|
|
|
- (void) drawRefsInRect: (NSRect *)refRect
|
|
{
|
|
[[NSColor blackColor] setStroke];
|
|
|
|
NSRect lastRect;
|
|
int index = 0;
|
|
for (NSValue *rectValue in [self rectsForRefsinRect:*refRect])
|
|
{
|
|
NSRect rect = [rectValue rectValue];
|
|
[self drawLabelAtIndex:index inRect:rect];
|
|
lastRect = rect;
|
|
++index;
|
|
}
|
|
refRect->size.width -= lastRect.origin.x - refRect->origin.x + lastRect.size.width;
|
|
refRect->origin.x = lastRect.origin.x + lastRect.size.width;
|
|
}
|
|
|
|
- (void) drawWithFrame: (NSRect) rect inView:(NSView *)view
|
|
{
|
|
cellInfo = [self.objectValue lineInfo];
|
|
|
|
if (cellInfo && ![controller hasNonlinearPath]) {
|
|
float pathWidth = 10 + 10 * cellInfo.numColumns;
|
|
|
|
NSRect ownRect;
|
|
NSDivideRect(rect, &ownRect, &rect, pathWidth, NSMinXEdge);
|
|
|
|
int i;
|
|
struct PBGitGraphLine *lines = cellInfo.lines;
|
|
for (i = 0; i < cellInfo.nLines; i++) {
|
|
if (lines[i].upper == 0)
|
|
[self drawLineFromColumn: lines[i].from toColumn: lines[i].to inRect:ownRect offset: ownRect.size.height color: lines[i].colorIndex];
|
|
else
|
|
[self drawLineFromColumn: lines[i].from toColumn: lines[i].to inRect:ownRect offset: 0 color:lines[i].colorIndex];
|
|
}
|
|
|
|
if (cellInfo.sign == '<' || cellInfo.sign == '>')
|
|
[self drawTriangleInRect: ownRect sign: cellInfo.sign];
|
|
else
|
|
[self drawCircleInRect: ownRect];
|
|
}
|
|
|
|
|
|
if ([self.objectValue refs] && [[self.objectValue refs] count])
|
|
[self drawRefsInRect:&rect];
|
|
|
|
// Still use this superclass because of hilighting differences
|
|
//_contents = [self.objectValue subject];
|
|
//[super drawWithFrame:rect inView:view];
|
|
[textCell setObjectValue: [self.objectValue subject]];
|
|
[textCell setHighlighted: [self isHighlighted]];
|
|
[textCell drawWithFrame:rect inView: view];
|
|
}
|
|
|
|
- (void) setObjectValue: (PBGitCommit*)object {
|
|
[super setObjectValue:[NSValue valueWithNonretainedObject:object]];
|
|
}
|
|
|
|
- (PBGitCommit*) objectValue {
|
|
return [[super objectValue] nonretainedObjectValue];
|
|
}
|
|
|
|
- (int) indexAtX:(float)x
|
|
{
|
|
cellInfo = [self.objectValue lineInfo];
|
|
float pathWidth = 0;
|
|
if (cellInfo && ![controller hasNonlinearPath])
|
|
pathWidth = 10 + 10 * cellInfo.numColumns;
|
|
|
|
int index = 0;
|
|
NSRect refRect = NSMakeRect(pathWidth, 0, 1000, 10000);
|
|
for (NSValue *rectValue in [self rectsForRefsinRect:refRect])
|
|
{
|
|
NSRect rect = [rectValue rectValue];
|
|
if (x >= rect.origin.x && x <= (rect.origin.x + rect.size.width))
|
|
return index;
|
|
++index;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
- (NSRect) rectAtIndex:(int)index
|
|
{
|
|
cellInfo = [self.objectValue lineInfo];
|
|
float pathWidth = 0;
|
|
if (cellInfo && ![controller hasNonlinearPath])
|
|
pathWidth = 10 + 10 * cellInfo.numColumns;
|
|
NSRect refRect = NSMakeRect(pathWidth, 0, 1000, 10000);
|
|
|
|
return [[[self rectsForRefsinRect:refRect] objectAtIndex:index] rectValue];
|
|
}
|
|
|
|
# pragma mark context menu delegate methods
|
|
|
|
- (NSMenu *) menuForEvent:(NSEvent *)event inRect:(NSRect)rect ofView:(NSView *)view
|
|
{
|
|
if (!contextMenuDelegate)
|
|
return [self menu];
|
|
|
|
int i = [self indexAtX:[view convertPointFromBase:[event locationInWindow]].x - rect.origin.x];
|
|
|
|
id ref = nil;
|
|
if (i >= 0)
|
|
ref = [[[self objectValue] refs] objectAtIndex:i];
|
|
|
|
NSArray *items = nil;
|
|
if (ref)
|
|
items = [contextMenuDelegate menuItemsForRef:ref];
|
|
else
|
|
items = [contextMenuDelegate menuItemsForCommit:[self objectValue]];
|
|
|
|
NSMenu *menu = [[NSMenu alloc] init];
|
|
[menu setAutoenablesItems:NO];
|
|
for (NSMenuItem *item in items)
|
|
[menu addItem:item];
|
|
return menu;
|
|
}
|
|
@end
|