// // NSPathCell.m // AppKit // // Created by Fabian Spillner on 27.11.07. // Copyright 2007 Golden Delicious Computers GmbH&Co. KG. All rights reserved. // // Implemented by Nikolaus Schaller on 03.03.08. // #import @implementation NSPathCell + (Class) pathComponentCellClass; { return [NSPathComponentCell class]; } // which one is the designated initializer? - (id) init; { return [self initTextCell:@""]; } - (id) initTextCell:(NSString *) title { if(self=[super initTextCell:title]) { [self setStringValue:title]; _needsSizing=YES; } return self; } - (void) dealloc; { [_pathComponentCells release]; [_backgroundColor release]; if(_rects) objc_free(_rects); // others [super dealloc]; } - (void) drawWithFrame:(NSRect) cellFrame inView:(NSView *) controlView { [(_backgroundColor?_backgroundColor:[NSColor controlHighlightColor]) set]; NSRectFill(cellFrame); if(_pathStyle != NSPathStylePopUp) ; // draw popup icon if([_pathComponentCells count] > 0 && _pathStyle == NSPathStyleStandard) { // draw cells NSEnumerator *e=[_pathComponentCells objectEnumerator]; NSPathComponentCell *cell; while((cell = [e nextObject])) { NSRect m = [self rectOfPathComponentCell:cell withFrame:cellFrame inView:controlView]; [cell drawWithFrame:m inView:controlView]; // draw item separator(s) if (cell != nil) { // draw the separator... NSBezierPath *theSeparator = [NSBezierPath bezierPath]; NSSize cellSize = m.size; NSRect sepRect = NSMakeRect(m.origin.x+cellSize.width, (cellFrame.size.height/2)-3.0, 6.0,6.0); [[NSColor grayColor] setFill]; [theSeparator moveToPoint:NSMakePoint(sepRect.origin.x, sepRect.origin.y)]; [theSeparator lineToPoint:NSMakePoint(sepRect.origin.x, sepRect.origin.y + sepRect.size.height)]; [theSeparator lineToPoint:NSMakePoint(sepRect.origin.x + sepRect.size.width, sepRect.origin.y + (sepRect.size.height /2))]; [theSeparator lineToPoint:NSMakePoint(sepRect.origin.x, sepRect.origin.y)]; [theSeparator closePath]; [theSeparator fill]; } } } if([_pathComponentCells count] > 0 && _pathStyle == NSPathStyleNavigationBar) { // draw cells NSEnumerator *e=[_pathComponentCells objectEnumerator]; NSPathComponentCell *cell; while((cell = [e nextObject])) { NSRect m = [self rectOfPathComponentCell:cell withFrame:cellFrame inView:controlView]; NSBezierPath *bezierPath = [NSBezierPath bezierPath]; NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:[NSColor blueColor] endingColor:[NSColor whiteColor]]; [cell drawWithFrame:m inView:controlView]; [[NSColor yellowColor] setFill]; [[NSColor blackColor] setStroke]; [bezierPath moveToPoint:m.origin]; [bezierPath lineToPoint:NSMakePoint(m.origin.x, (m.origin.y+m.size.height))]; [bezierPath lineToPoint:NSMakePoint(m.origin.x+(m.size.width - 20), (m.origin.y+m.size.height))]; [bezierPath lineToPoint:NSMakePoint(m.origin.x+m.size.width, (m.origin.y+m.size.height)/2)]; [bezierPath lineToPoint:NSMakePoint(m.origin.x+(m.size.width - 20), m.origin.y)]; [bezierPath lineToPoint:m.origin]; [bezierPath closePath]; [gradient drawInBezierPath:bezierPath angle:90]; [bezierPath stroke]; [gradient release]; } } else [super drawWithFrame:cellFrame inView:controlView]; // this should automatically handle placeholder string } - (NSArray *) allowedTypes; { return _allowedTypes; } - (NSColor *) backgroundColor; { return _backgroundColor; } - (NSPathComponentCell *) clickedPathComponentCell; { return _clickedPathComponentCell; } - (id) delegate; { return _delegate; } - (SEL) doubleAction; { return _doubleAction; } - (void) mouseEntered:(NSEvent *) evt withFrame:(NSRect) frame inView:(NSView *) view; { #if 1 NSLog(@"Mouse entered!"); #endif BOOL state=[[view window] acceptsMouseMovedEvents]; [[view window] setAcceptsMouseMovedEvents:YES]; while(YES) { NSPoint event_location = [evt locationInWindow]; NSPoint local_point = [view convertPoint:event_location fromView:nil]; _dontTruncateCell = [self pathComponentCellAtPoint: local_point withFrame:frame inView:view]; _needsSizing=YES; // must recalculate cell positions [view setNeedsDisplay:YES]; #if 1 if (_dontTruncateCell) { NSLog(@"Cell gefunden"); } #endif evt = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:YES]; [NSApp sendEvent:evt]; // dispatch event if([evt type] == NSMouseExited) break; } if(!state) [[view window] setAcceptsMouseMovedEvents:NO]; } - (void) mouseExited:(NSEvent *) evt withFrame:(NSRect) frame inView:(NSView *) view; { _dontTruncateCell=nil; _needsSizing=YES; [view setNeedsDisplay:YES]; #if 1 NSLog(@"Mouse exited!"); #endif } - (NSPathComponentCell *) pathComponentCellAtPoint:(NSPoint) pt withFrame:(NSRect) rect inView:(NSView *) view; { // locate the cell we have clicked onto NSEnumerator *e=[_pathComponentCells objectEnumerator]; NSPathComponentCell *cell; while((cell = [e nextObject])) if(NSMouseInRect(pt, [self rectOfPathComponentCell:cell withFrame:rect inView:view], [view isFlipped])) return cell; return nil; } - (NSArray *) pathComponentCells; { return _pathComponentCells; } - (NSPathStyle) pathStyle; { return _pathStyle; } - (NSString *) placeholderString; { return ([_placeholderString isKindOfClass:[NSString class]])?_placeholderString:nil; } - (void) setPlaceholderString:(NSString *) string; { ASSIGN(_placeholderString, string); } - (NSAttributedString *) placeholderAttributedString; { return ([_placeholderString isKindOfClass:[NSAttributedString class]])?_placeholderString:nil; } - (void) setPlaceholderAttributedString:(NSAttributedString *) string; { ASSIGN(_placeholderString, string); } - (NSRect) rectOfPathComponentCell:(NSPathComponentCell *) c withFrame:(NSRect) rect inView:(NSView *) view; { unsigned idx=[_pathComponentCells indexOfObjectIdenticalTo:c]; if(idx == NSNotFound) return NSZeroRect; if(_needsSizing) { // (re)calculate cell positions unsigned int i; unsigned int cnt=[_pathComponentCells count]; NSRect r=rect; _rects=(NSRect *) objc_realloc(_rects, sizeof(_rects[0])*MAX(cnt, 1)); for(i=0; i 0 && NSMaxX(_rects[cnt-1]) > NSMaxX(rect)) { // total width of cells is wider than our cell frame float oversize=NSMaxX(_rects[cnt-1]) - NSMaxX(rect); if(cnt > 1 && _dontTruncateCell) oversize /= (cnt-2); // how much we have to reduce each cell except the cell where the mouse is currently over else oversize /= (cnt-1); // how much we have to reduce each cell for(i=0; i) obj; { if([(NSObject *) obj isKindOfClass:[NSString class]]) [self setURL:[NSURL fileURLWithPath:(NSString *) obj]]; // convert to file URL and calls [super setObjectValue] else { NSAssert([(id) obj isKindOfClass:[NSURL class]], @"setObjectValue expects NSURL or NSString"); [self setURL:(NSURL *) obj]; // calls [super setObjectValue] } } - (void) setPathComponentCells:(NSArray *) cells; { ASSIGN(_pathComponentCells, cells); _needsSizing=YES; } - (void) setPathStyle:(NSPathStyle) pathStyle; { _pathStyle=pathStyle; _needsSizing=YES; // resize for new style if(pathStyle == NSPathStyleNavigationBar) [self setControlSize:NSSmallControlSize]; // enforce } - (void) setURL:(NSURL *) url; { int i; if (url != nil) { BOOL isFile=[url isFileURL]; NSArray *pathComponents = [[url path] pathComponents]; // get Array of Path parts unsigned cnt = [pathComponents count]; NSMutableArray *cells=[NSMutableArray arrayWithCapacity:cnt]; NSString *partialURLString=@"/"; for(i=0; i