Files
textmate/Frameworks/Find/src/FFFilePathCell.mm
2013-02-04 19:38:00 +01:00

143 lines
5.0 KiB
Plaintext

#import "FFFilePathCell.h"
#import <OakAppKit/NSImage Additions.h>
#import <OakFoundation/NSString Additions.h>
#import <text/tokenize.h>
#import <cf/cf.h>
#import <ns/ns.h>
#import "attr_string.h"
#import <io/path.h>
static NSImage* ImageForBadgeCounter (NSInteger count)
{
static const NSInteger BADGE_BUFFER_LEFT = 4;
static const NSInteger BADGE_BUFFER_SIDE = 3;
static const NSInteger BADGE_BUFFER_LEFT_SMALL = 3;
static const NSInteger BADGE_CIRCLE_BUFFER_RIGHT = 5;
static const NSInteger BADGE_TEXT_HEIGHT = 14;
static const NSInteger BADGE_X_RADIUS = 7;
static const NSInteger BADGE_Y_RADIUS = 8;
static const NSInteger BADGE_TEXT_MINI = 8;
static const NSInteger BADGE_TEXT_SMALL = 20;
if(count == 0)
return nil;
static NSDictionary* attrs = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
[NSFont fontWithName:@"Helvetica-Bold" size:11], NSFontAttributeName,
[NSColor whiteColor], NSForegroundColorAttributeName,
nil];
NSString* badgeText = [NSString stringWithFormat:@"%ld", count];
NSSize badgeNumSize = [badgeText sizeWithAttributes:nil];
NSInteger badgeWidth = badgeNumSize.width + BADGE_BUFFER_SIDE * 2;
if(badgeNumSize.width < BADGE_TEXT_MINI)
badgeWidth = BADGE_TEXT_SMALL;
NSInteger badgeX = BADGE_CIRCLE_BUFFER_RIGHT;
NSInteger badgeNumX = badgeX + BADGE_BUFFER_LEFT;
if(badgeNumSize.width < BADGE_TEXT_MINI)
badgeNumX += BADGE_BUFFER_LEFT_SMALL;
NSRect badgeRect = NSMakeRect(badgeX, 0, badgeWidth, BADGE_TEXT_HEIGHT);
NSImage* badge = [[[NSImage alloc] initWithSize:NSMakeSize(badgeRect.size.width + BADGE_X_RADIUS, badgeRect.size.height)] autorelease];
[badge lockFocus];
NSBezierPath *badgePath = [NSBezierPath bezierPathWithRoundedRect:badgeRect xRadius:BADGE_X_RADIUS yRadius:BADGE_Y_RADIUS];
[[NSColor disabledControlTextColor] set];
[badgePath fill];
[badgeText drawAtPoint:NSMakePoint(badgeNumX, 0) withAttributes:attrs];
[badge unlockFocus];
return badge;
}
static NSAttributedString* PathComponentString (std::string const& path, std::string const& base)
{
std::vector<std::string> components;
std::string str = path::relative_to(path, base);
citerate(component, text::tokenize(str.begin(), str.end(), '/'))
components.push_back(*component);
if(components.front() == "")
components.front() = path::display_name("/");
components.back() = "";
return ns::attr_string_t()
<< ns::style::line_break(NSLineBreakByTruncatingMiddle)
<< [NSFont systemFontOfSize:11]
<< [NSColor darkGrayColor]
<< text::join(std::vector<std::string>(components.begin(), components.end()), " ▸ ")
<< [NSFont boldSystemFontOfSize:11]
<< [NSColor blackColor]
<< (path.empty() || path[0] != '/' ? path : path::display_name(path));
}
@interface FFFilePathCell ()
{
NSImage* icon;
NSString* path;
NSString* base;
NSUInteger count;
BOOL mouseDownInIcon;
}
@end
@implementation FFFilePathCell
@synthesize icon, path, base, count;
- (NSRect)iconFrameInCellFrame:(NSRect)cellFrame
{
NSRect iconRect, pathRect;
NSDivideRect(NSInsetRect(cellFrame, 5, 0), &iconRect, &pathRect, NSWidth(cellFrame) / 2, NSMinXEdge);
iconRect.origin.y = iconRect.origin.y + (iconRect.size.height - 16) / 2;
iconRect.size = NSMakeSize(16, 16);
return iconRect;
}
- (void)drawWithFrame:(NSRect)frame inView:(NSView*)view
{
NSAttributedString* fileString = PathComponentString(to_s(path), to_s(base));
NSPoint iconOrigin = frame.origin;
iconOrigin.x += 5;
iconOrigin.y = frame.origin.y + (frame.size.height - icon.size.height) / 2;
[icon drawAdjustedAtPoint:iconOrigin fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:mouseDownInIcon ? 0.5 : 1.0];
NSRect textFrame = NSInsetRect(frame, 5, 0);
textFrame.origin.y += (textFrame.size.height - fileString.size.height) / 2;
textFrame.origin.x += 20;
textFrame.size.width -= 21;
if(NSImage* badge = ImageForBadgeCounter(count))
{
NSPoint badgeOrigin = textFrame.origin;
badgeOrigin.x += (([fileString size].width < textFrame.size.width) ? [fileString size].width : textFrame.size.width) + 5;
[badge drawAdjustedAtPoint:badgeOrigin fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
textFrame.size.width -= badge.size.width + 5;
}
[fileString drawInRect:textFrame];
}
- (BOOL)trackMouse:(NSEvent*)theEvent inRect:(NSRect)cellFrame ofView:(NSView*)controlView untilMouseUp:(BOOL)untilMouseUp
{
NSPoint initialMouseDown = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
if(!NSMouseInRect(initialMouseDown, [self iconFrameInCellFrame:cellFrame], [controlView isFlipped]))
return NO;
mouseDownInIcon = YES;
[controlView setNeedsDisplayInRect:cellFrame];
theEvent = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask|NSLeftMouseUpMask) untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:YES];
mouseDownInIcon = NO;
[controlView setNeedsDisplayInRect:cellFrame];
if([theEvent type] == NSLeftMouseDragged)
[controlView dragFile:path fromRect:[self iconFrameInCellFrame:cellFrame] slideBack:YES event:theEvent];
return YES;
}
@end