// // ColumnCell.m // Perforce // // Created by Adam Czubernat on 24.05.2013. // Copyright (c) 2013 PolSource. All rights reserved. // #import "ColumnCell.h" #define SPACING 4.0f @interface ColumnCell () - (void)drawOverlay:(CGRect)frame; - (void)drawUnreadBadge:(CGRect)frame; - (void)drawTagBadge:(CGRect)frame; - (void)drawGradientInFrame:(CGRect)frame color:(NSColor *)color; @end @implementation ColumnCell @synthesize image=_image, selectedImage=_selectedImage, overlayColor, unread, tag; static NSColor *backgroundColor; static NSColor *selectionColor; static NSColor *textColor; static NSColor *textColorSelected; static NSImage *indicatorImage; static NSImage *selectedIndicatorImage; static NSImage *unreadBadgeImage; static NSImage *tagBadgeImage; - (id)init { if (self = [super init]) { [self setLineBreakMode:NSLineBreakByTruncatingTail]; [self setEditable:YES]; // Load images and colors static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ backgroundColor = [NSUserDefaults colorForKey:kColorBackgroundColumn]; selectionColor = [NSUserDefaults colorForKey:kColorBackgroundColumnSelected]; textColor = [NSUserDefaults colorForKey:kColorTextColumn]; textColorSelected = [NSUserDefaults colorForKey:kColorTextColumnSelected]; indicatorImage = [NSImage imageNamed:@"ColumnArrow.png"]; selectedIndicatorImage = [NSImage imageNamed:@"ColumnArrowSelected.png"]; unreadBadgeImage = [NSImage imageNamed:@"UnreadIndicator.png"]; tagBadgeImage = [NSImage imageNamed:@"TagIndicator.png"]; }); } return self; } #pragma mark - Overrides - (NSRect)imageRectForBounds:(NSRect)frame { frame.origin.x = SPACING; frame.size.width = frame.size.height; return frame; } - (NSRect)titleRectForBounds:(NSRect)frame { CGFloat spacing = SPACING; CGSize size = self.titleSize; frame.origin.x = frame.size.height + 2.0f * spacing; frame.origin.y += truncf((frame.size.height - size.height) * 0.5f); frame.size.width = frame.size.width - frame.origin.x - spacing; frame.size.height -= truncf(frame.size.height - size.height); if (!self.isLeaf) frame.size.width -= indicatorImage.size.width; if (unread) frame.size.width -= frame.size.height + 2.0f; if (tag) frame.size.width -= frame.size.height + 2.0f; return frame; } - (void)drawWithFrame:(NSRect)frame inView:(NSView *)controlView { NSImage *image; NSColor *color; BOOL selected = self.isHighlighted; frame.size.width = controlView.frame.size.width; // Maximize cell's size // Clear selection from NSBrowser drawing [backgroundColor setFill]; NSRectFill(frame); frame.size.width -= 2.0f; // Offset to allow wspace for column divider // Draw selection if (selected) { // if (self.backgroundStyle) ... [selectionColor setFill]; NSRectFill(frame); } [self drawOverlay:frame]; // Draw image image = selected ? _selectedImage : _image; [image drawInRect:[self imageRectForBounds:frame] fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f respectFlipped:YES hints:nil]; // Draw title if (!_cFlags.currentlyEditing) { NSMutableDictionary *titleAttributes = [[self attributedStringValue] attributesAtIndex:0 effectiveRange:0].mutableCopy; color = selected ? textColorSelected : textColor; [titleAttributes setObject:color forKey:NSForegroundColorAttributeName]; [self.title drawInRect:[self titleRectForBounds:frame] withAttributes:titleAttributes]; } [self drawUnreadBadge:frame]; [self drawTagBadge:frame]; if (self.isLeaf) // Don't draw indicator when it's not a directory return; // Draw an arrow indicator image = selected ? selectedIndicatorImage : indicatorImage; [image drawInRect:(CGRect) { frame.size.width - image.size.width, frame.origin.y + truncf((frame.size.height - image.size.height) * 0.5f), image.size, } fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f respectFlipped:YES hints:nil]; } - (void)editWithFrame:(NSRect)frame inView:(NSView *)controlView editor:(NSTextView *)editor delegate:(id)anObject event:(NSEvent *)theEvent { frame = [self titleRectForBounds:frame]; [editor setFrame:(CGRect) { --frame.origin.x, frame.origin.y, frame.size }]; [editor setTextContainerInset:(NSSize) { 0.0f, 1.0f }]; [[editor textContainer] setLineFragmentPadding:1.0f]; [editor setAutoresizingMask:NSViewWidthSizable]; [editor setDrawsBackground:YES]; [editor setBackgroundColor:[NSColor whiteColor]]; editor.font = self.font; editor.string = self.title; editor.textColor = textColor; editor.delegate = (id)controlView; NSString *ext = [editor.string stringByDeletingPathExtension]; [editor setSelectedRange:(NSRange) { 0, ext.length ?: self.title.length }]; [controlView addSubview:editor]; [[controlView window] makeFirstResponder:editor]; } #pragma mark - Private - (void)drawOverlay:(CGRect)frame { if (!overlayColor) return; [self drawGradientInFrame:self.isHighlighted ? (CGRect) { frame.size.width - frame.size.height - 1.0f, frame.origin.y + 1.0f, frame.size.height, frame.size.height - 1.0f, } : (CGRect) { frame.origin.x, frame.origin.y + 1.0f, frame.size.width - frame.origin.x - 1.0f, frame.size.height - 1.0f, } color:overlayColor]; } - (void)drawUnreadBadge:(CGRect)frame { if (!unread) return; CGSize size = unreadBadgeImage.size; [unreadBadgeImage drawInRect:(CGRect) { self.isLeaf ? frame.size.width - (frame.size.height + size.width) * 0.5f - 1.0f : (frame.size.height - size.height) * 0.5f + SPACING, frame.origin.y + (self.isLeaf ? 0.0f : 1.0f) + (frame.size.height - size.height) * 0.5f, size } fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f respectFlipped:YES hints:nil]; } - (void)drawTagBadge:(CGRect)frame { if (!tag) return; CGSize size = tagBadgeImage.size; CGRect rect = { self.isLeaf ? frame.size.width - (frame.size.height + size.width) * 0.5f - 1.0f : (frame.size.height - size.height) * 0.5f + SPACING, frame.origin.y + (self.isLeaf ? 0.0f : 1.0f) + (frame.size.height - size.height) * 0.5f, size }; if (unread) rect.origin.x -= size.height; [tagBadgeImage drawInRect:rect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f respectFlipped:YES hints:nil]; } - (void)drawGradientInFrame:(CGRect)frame color:(NSColor *)color { NSInteger cornerSize = frame.size.height / 2.0f; NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:[color colorWithAlphaComponent:0.5f] endingColor:color]; NSBezierPath *bezier = [NSBezierPath bezierPathWithRoundedRect:frame xRadius:cornerSize yRadius:cornerSize]; [gradient drawInBezierPath:bezier angle:90.0f]; } #pragma mark - Public - (CGSize)titleSize { return [[self attributedStringValue] size]; } @end