mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-05-03 13:10:58 +00:00
* Reduce code duplication in drawViewCell:... method * Further reduce code duplication, add common private method for calculating starting and ending column * Use the tableView in the method that calculates the starting and ending rows * Add code to properly handle prototypeViews, the XIB is NOT split, I was confused * Call awakeFromNib on view as well * Refactor so that the outlineColumn drawing code is shared * Adjust the image drawing and the clickable area to be more aligned also make it easier to expand or collapse an item in the outline view
4054 lines
104 KiB
Objective-C
4054 lines
104 KiB
Objective-C
/** <title>GSThemeDrawing</title>
|
|
|
|
<abstract>The theme methods for drawing controls</abstract>
|
|
|
|
Copyright (C) 2004-2023 Free Software Foundation, Inc.
|
|
|
|
Author: Adam Fedor <fedor@gnu.org>
|
|
Date: Jan 2004
|
|
|
|
This file is part of the GNU Objective C User interface library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; see the file COPYING.LIB.
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#import "GSThemePrivate.h"
|
|
|
|
#import "Foundation/NSUserDefaults.h"
|
|
#import "Foundation/NSIndexSet.h"
|
|
|
|
#import "AppKit/NSAttributedString.h"
|
|
#import "AppKit/NSBezierPath.h"
|
|
#import "AppKit/NSButton.h"
|
|
#import "AppKit/NSButtonCell.h"
|
|
#import "AppKit/NSBrowser.h"
|
|
#import "AppKit/NSBrowserCell.h"
|
|
#import "AppKit/NSCell.h"
|
|
#import "AppKit/NSColor.h"
|
|
#import "AppKit/NSColorList.h"
|
|
#import "AppKit/NSColorWell.h"
|
|
#import "AppKit/NSGraphics.h"
|
|
#import "AppKit/NSImage.h"
|
|
#import "AppKit/NSImageView.h"
|
|
#import "AppKit/NSMenuView.h"
|
|
#import "AppKit/NSMenuItemCell.h"
|
|
#import "AppKit/NSOutlineView.h"
|
|
#import "AppKit/NSParagraphStyle.h"
|
|
#import "AppKit/NSPopUpButtonCell.h"
|
|
#import "AppKit/NSProgressIndicator.h"
|
|
#import "AppKit/NSScroller.h"
|
|
#import "AppKit/NSScrollView.h"
|
|
#import "AppKit/NSStringDrawing.h"
|
|
#import "AppKit/NSTableView.h"
|
|
#import "AppKit/NSTableCellView.h"
|
|
#import "AppKit/NSTableColumn.h"
|
|
#import "AppKit/NSTableHeaderCell.h"
|
|
#import "AppKit/NSTableHeaderView.h"
|
|
#import "AppKit/NSTableView.h"
|
|
#import "AppKit/NSView.h"
|
|
#import "AppKit/NSTabView.h"
|
|
#import "AppKit/NSTabViewItem.h"
|
|
#import "AppKit/PSOperators.h"
|
|
#import "AppKit/NSSliderCell.h"
|
|
#import "AppKit/NSPathCell.h"
|
|
#import "AppKit/NSPathControl.h"
|
|
#import "AppKit/NSPathComponentCell.h"
|
|
|
|
#import "GNUstepGUI/GSToolbarView.h"
|
|
#import "GNUstepGUI/GSTitleView.h"
|
|
|
|
/* a border width of 5 gives a reasonable compromise between Cocoa metrics and looking good */
|
|
/* 7.0 gives us the NeXT Look (which is 8 pix wide including the shadow) */
|
|
#define COLOR_WELL_BORDER_WIDTH 7.0
|
|
|
|
@interface NSTableView (Private)
|
|
- (CGFloat *)_columnOrigins;
|
|
- (void) _willDisplayCell: (NSCell*)cell
|
|
forTableColumn: (NSTableColumn *)tb
|
|
row: (NSInteger)index;
|
|
- (id)_objectValueForTableColumn: (NSTableColumn *)tb
|
|
row: (NSInteger)index;
|
|
- (NSView *) _renderedViewForPath: (NSIndexPath *)path;
|
|
- (void) _setRenderedView: (NSView *)view forPath: (NSIndexPath *)path;
|
|
@end
|
|
|
|
@interface NSTableColumn (Private)
|
|
- (NSArray *) _prototypeCellViews;
|
|
@end
|
|
|
|
@interface NSCell (Private)
|
|
- (void) _setInEditing: (BOOL)flag;
|
|
- (BOOL) _inEditing;
|
|
- (void) _drawEditorWithFrame: (NSRect)cellFrame
|
|
inView: (NSView *)controlView;
|
|
- (void) _drawAttributedText: (NSAttributedString*)aString
|
|
inFrame: (NSRect)aRect;
|
|
@end
|
|
|
|
@implementation GSTheme (Drawing)
|
|
- (void) setKeyEquivalent: (NSString *)key
|
|
forButtonCell: (NSButtonCell *)cell
|
|
{
|
|
if([cell image] == nil && ([key isEqualToString:@"\r"] ||
|
|
[key isEqualToString:@"\n"]))
|
|
{
|
|
[cell setImagePosition: NSImageRight];
|
|
[cell setImage: [NSImage imageNamed:@"common_ret"]];
|
|
[cell setAlternateImage: [NSImage imageNamed:@"common_retH"]];
|
|
}
|
|
else if([key isEqualToString:@"\r"] == NO &&
|
|
[key isEqualToString:@"\n"] == NO)
|
|
{
|
|
NSImage *cellImage = [cell image];
|
|
if(cellImage == [NSImage imageNamed:@"common_ret"])
|
|
{
|
|
[cell setImage: nil];
|
|
[cell setAlternateImage: nil];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) drawButton: (NSRect)frame
|
|
in: (NSCell*)cell
|
|
view: (NSView*)view
|
|
style: (int)style
|
|
state: (GSThemeControlState)state
|
|
{
|
|
GSDrawTiles *tiles = nil;
|
|
NSColor *color = nil;
|
|
NSString *name = [self nameForElement: cell];
|
|
|
|
if (name == nil)
|
|
{
|
|
name = GSStringFromBezelStyle(style);
|
|
}
|
|
|
|
color = [self colorNamed: name state: state];
|
|
if (color == nil)
|
|
{
|
|
if (state == GSThemeNormalState)
|
|
{
|
|
color = [NSColor controlBackgroundColor];
|
|
}
|
|
else if (state == GSThemeHighlightedState
|
|
|| state == GSThemeHighlightedFirstResponderState)
|
|
{
|
|
color = [NSColor selectedControlColor];
|
|
}
|
|
else if (state == GSThemeSelectedState
|
|
|| state == GSThemeSelectedFirstResponderState)
|
|
{
|
|
color = [NSColor selectedControlColor];
|
|
}
|
|
else
|
|
{
|
|
color = [NSColor controlBackgroundColor];
|
|
}
|
|
}
|
|
|
|
tiles = [self tilesNamed: name state: state];
|
|
if (tiles == nil)
|
|
{
|
|
tiles = [self tilesNamed: @"NSButton" state: state];
|
|
}
|
|
|
|
if (tiles == nil)
|
|
{
|
|
switch (style)
|
|
{
|
|
case NSRoundRectBezelStyle:
|
|
case NSTexturedRoundedBezelStyle:
|
|
case NSRoundedBezelStyle:
|
|
[self drawRoundBezel: frame withColor: color];
|
|
break;
|
|
case NSTexturedSquareBezelStyle:
|
|
frame = NSInsetRect(frame, 0, 1);
|
|
case NSSmallSquareBezelStyle:
|
|
case NSRegularSquareBezelStyle:
|
|
case NSShadowlessSquareBezelStyle:
|
|
[color set];
|
|
NSRectFill(frame);
|
|
[[NSColor controlShadowColor] set];
|
|
NSFrameRectWithWidth(frame, 1);
|
|
break;
|
|
case NSThickSquareBezelStyle:
|
|
[color set];
|
|
NSRectFill(frame);
|
|
[[NSColor controlShadowColor] set];
|
|
NSFrameRectWithWidth(frame, 1.5);
|
|
break;
|
|
case NSThickerSquareBezelStyle:
|
|
[color set];
|
|
NSRectFill(frame);
|
|
[[NSColor controlShadowColor] set];
|
|
NSFrameRectWithWidth(frame, 2);
|
|
break;
|
|
case NSCircularBezelStyle:
|
|
frame = NSInsetRect(frame, 3, 3);
|
|
[self drawCircularBezel: frame withColor: color];
|
|
break;
|
|
case NSHelpButtonBezelStyle:
|
|
[self drawCircularBezel: frame withColor: color];
|
|
{
|
|
NSDictionary *attributes = [NSDictionary dictionaryWithObject: [NSFont controlContentFontOfSize: 0]
|
|
forKey: NSFontAttributeName];
|
|
NSAttributedString *questionMark = [[[NSAttributedString alloc]
|
|
initWithString: _(@"?")
|
|
attributes: attributes] autorelease];
|
|
|
|
NSRect textRect;
|
|
textRect.size = [questionMark size];
|
|
textRect.origin.x = NSMidX(frame) - (textRect.size.width / 2);
|
|
textRect.origin.y = NSMidY(frame) - (textRect.size.height / 2);
|
|
|
|
[questionMark drawInRect: textRect];
|
|
}
|
|
break;
|
|
case NSDisclosureBezelStyle:
|
|
case NSRoundedDisclosureBezelStyle:
|
|
case NSRecessedBezelStyle:
|
|
// FIXME
|
|
break;
|
|
default:
|
|
[color set];
|
|
NSRectFill(frame);
|
|
|
|
if (state == GSThemeNormalState || state == GSThemeHighlightedState)
|
|
{
|
|
[self drawButton: frame withClip: NSZeroRect];
|
|
}
|
|
else if (state == GSThemeSelectedState || state == GSThemeSelectedFirstResponderState)
|
|
{
|
|
[self drawGrayBezel: frame withClip: NSZeroRect];
|
|
}
|
|
else
|
|
{
|
|
[self drawButton: frame withClip: NSZeroRect];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Use tiles to draw button border with central part filled with color
|
|
*/
|
|
[self fillRect: frame
|
|
withTiles: tiles
|
|
background: color];
|
|
}
|
|
}
|
|
|
|
- (GSThemeMargins) buttonMarginsForCell: (NSCell*)cell
|
|
style: (int)style
|
|
state: (GSThemeControlState)state
|
|
{
|
|
GSDrawTiles *tiles = nil;
|
|
NSString *name = [self nameForElement: cell];
|
|
GSThemeMargins margins;
|
|
|
|
if (name == nil)
|
|
{
|
|
name = GSStringFromBezelStyle(style);
|
|
}
|
|
|
|
tiles = [self tilesNamed: name state: state];
|
|
if (tiles == nil)
|
|
{
|
|
tiles = [self tilesNamed: @"NSButton" state: state];
|
|
}
|
|
|
|
if (tiles == nil)
|
|
{
|
|
switch (style)
|
|
{
|
|
case NSRoundRectBezelStyle:
|
|
case NSTexturedRoundedBezelStyle:
|
|
case NSRoundedBezelStyle:
|
|
margins.left = 5; margins.top = 5; margins.right = 5; margins.bottom = 5;
|
|
return margins;
|
|
case NSTexturedSquareBezelStyle:
|
|
margins.left = 3; margins.top = 3; margins.right = 3; margins.bottom = 3;
|
|
return margins;
|
|
case NSSmallSquareBezelStyle:
|
|
case NSRegularSquareBezelStyle:
|
|
case NSShadowlessSquareBezelStyle:
|
|
margins.left = 2; margins.top = 2; margins.right = 2; margins.bottom = 2;
|
|
return margins;
|
|
case NSThickSquareBezelStyle:
|
|
margins.left = 3; margins.top = 3; margins.right = 3; margins.bottom = 3;
|
|
return margins;
|
|
case NSThickerSquareBezelStyle:
|
|
margins.left = 4; margins.top = 4; margins.right = 4; margins.bottom = 4;
|
|
return margins;
|
|
case NSCircularBezelStyle:
|
|
margins.left = 5; margins.top = 5; margins.right = 5; margins.bottom = 5;
|
|
return margins;
|
|
case NSHelpButtonBezelStyle:
|
|
margins.left = 2; margins.top = 2; margins.right = 2; margins.bottom = 2;
|
|
return margins;
|
|
case NSDisclosureBezelStyle:
|
|
case NSRoundedDisclosureBezelStyle:
|
|
case NSRecessedBezelStyle:
|
|
// FIXME
|
|
margins.left = 0; margins.top = 0; margins.right = 0; margins.bottom = 0;
|
|
return margins;
|
|
default:
|
|
margins.left = 2; margins.top = 2; margins.right = 3; margins.bottom = 3;
|
|
return margins;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
margins = [tiles themeMargins];
|
|
return margins;
|
|
}
|
|
}
|
|
|
|
- (void) drawFocusFrame: (NSRect) frame view: (NSView*) view
|
|
{
|
|
GSDrawTiles *tiles = [self tilesNamed: @"NSFocusRing" state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
NSDottedFrameRect(frame);
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: frame
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (void) drawWindowBackground: (NSRect) frame view: (NSView*) view
|
|
{
|
|
NSColor *c;
|
|
|
|
c = [[view window] backgroundColor];
|
|
[c set];
|
|
NSRectFill (frame);
|
|
}
|
|
|
|
- (void) drawBorderType: (NSBorderType)aType
|
|
frame: (NSRect)frame
|
|
view: (NSView*)view
|
|
{
|
|
NSString *name = GSStringFromBorderType(aType);
|
|
GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
switch (aType)
|
|
{
|
|
case NSLineBorder:
|
|
[[NSColor controlDarkShadowColor] set];
|
|
NSFrameRect(frame);
|
|
break;
|
|
case NSGrooveBorder:
|
|
[self drawGroove: frame withClip: NSZeroRect];
|
|
break;
|
|
case NSBezelBorder:
|
|
[self drawWhiteBezel: frame withClip: NSZeroRect];
|
|
break;
|
|
case NSNoBorder:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: frame
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (NSSize) sizeForBorderType: (NSBorderType)aType
|
|
{
|
|
NSString *name = GSStringFromBorderType(aType);
|
|
GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
// Returns the size of a border
|
|
switch (aType)
|
|
{
|
|
case NSLineBorder:
|
|
return NSMakeSize(1, 1);
|
|
case NSGrooveBorder:
|
|
case NSBezelBorder:
|
|
return NSMakeSize(2, 2);
|
|
case NSNoBorder:
|
|
default:
|
|
return NSZeroSize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// FIXME: We assume the button's top and right padding are the same as
|
|
// its bottom and left.
|
|
|
|
GSThemeMargins margins = [tiles themeMargins];
|
|
return NSMakeSize(margins.left, margins.bottom);
|
|
}
|
|
}
|
|
|
|
- (void) drawBorderForImageFrameStyle: (NSImageFrameStyle)frameStyle
|
|
frame: (NSRect)frame
|
|
view: (NSView*)view
|
|
{
|
|
NSString *name = GSStringFromImageFrameStyle(frameStyle);
|
|
GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
switch (frameStyle)
|
|
{
|
|
case NSImageFrameNone:
|
|
// do nothing
|
|
break;
|
|
case NSImageFramePhoto:
|
|
[self drawFramePhoto: frame withClip: NSZeroRect];
|
|
break;
|
|
case NSImageFrameGrayBezel:
|
|
[self drawGrayBezel: frame withClip: NSZeroRect];
|
|
break;
|
|
case NSImageFrameGroove:
|
|
[self drawGroove: frame withClip: NSZeroRect];
|
|
break;
|
|
case NSImageFrameButton:
|
|
[self drawButton: frame withClip: NSZeroRect];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: frame
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (NSSize) sizeForImageFrameStyle: (NSImageFrameStyle)frameStyle
|
|
{
|
|
// Get border size
|
|
switch (frameStyle)
|
|
{
|
|
case NSImageFrameNone:
|
|
default:
|
|
return NSZeroSize;
|
|
case NSImageFramePhoto:
|
|
// FIXME
|
|
return NSMakeSize(2, 2);
|
|
case NSImageFrameGrayBezel:
|
|
case NSImageFrameGroove:
|
|
case NSImageFrameButton:
|
|
return NSMakeSize(2, 2);
|
|
}
|
|
}
|
|
|
|
|
|
/* NSScroller themeing.
|
|
*/
|
|
- (BOOL) scrollerArrowsSameEndForScroller: (NSScroller *)aScroller
|
|
{
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
if ([defs objectForKey: @"GSScrollerArrowsSameEnd"] != nil)
|
|
{
|
|
return [defs boolForKey: @"GSScrollerArrowsSameEnd"];
|
|
}
|
|
else
|
|
{
|
|
NSInterfaceStyle interfaceStyle =
|
|
NSInterfaceStyleForKey(@"NSScrollerInterfaceStyle", aScroller);
|
|
|
|
if ((interfaceStyle == NSNextStepInterfaceStyle
|
|
|| interfaceStyle == NSMacintoshInterfaceStyle
|
|
|| interfaceStyle == GSWindowMakerInterfaceStyle))
|
|
{
|
|
return YES;
|
|
}
|
|
else
|
|
{
|
|
return NO;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL) scrollerScrollsByPageForScroller: (NSScroller *)aScroller
|
|
{
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
if ([defs objectForKey: @"GSScrollerScrollsByPage"] != nil)
|
|
{
|
|
return [defs boolForKey: @"GSScrollerScrollsByPage"];
|
|
}
|
|
else
|
|
{
|
|
NSInterfaceStyle interfaceStyle =
|
|
NSInterfaceStyleForKey(@"NSScrollerInterfaceStyle", aScroller);
|
|
|
|
if (interfaceStyle == NSNextStepInterfaceStyle
|
|
|| interfaceStyle == NSMacintoshInterfaceStyle
|
|
|| interfaceStyle == GSWindowMakerInterfaceStyle)
|
|
{
|
|
/* NeXTstep style is to scroll to point.
|
|
*/
|
|
return NO;
|
|
}
|
|
else
|
|
{
|
|
/* Windows style is to scroll by a page.
|
|
*/
|
|
return YES;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSButtonCell*) cellForScrollerArrow: (NSScrollerArrow)arrow
|
|
horizontal: (BOOL)horizontal
|
|
{
|
|
NSButtonCell *cell;
|
|
NSString *name;
|
|
|
|
cell = [NSButtonCell new];
|
|
if (horizontal)
|
|
{
|
|
if (arrow == NSScrollerDecrementArrow)
|
|
{
|
|
[cell setHighlightsBy:
|
|
NSChangeBackgroundCellMask | NSContentsCellMask];
|
|
[cell setImage: [NSImage imageNamed: @"common_ArrowLeft"]];
|
|
[cell setAlternateImage: [NSImage imageNamed: @"common_ArrowLeftH"]];
|
|
[cell setImagePosition: NSImageOnly];
|
|
name = GSScrollerLeftArrow;
|
|
}
|
|
else
|
|
{
|
|
[cell setHighlightsBy:
|
|
NSChangeBackgroundCellMask | NSContentsCellMask];
|
|
[cell setImage: [NSImage imageNamed: @"common_ArrowRight"]];
|
|
[cell setAlternateImage: [NSImage imageNamed: @"common_ArrowRightH"]];
|
|
[cell setImagePosition: NSImageOnly];
|
|
name = GSScrollerRightArrow;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (arrow == NSScrollerDecrementArrow)
|
|
{
|
|
[cell setHighlightsBy:
|
|
NSChangeBackgroundCellMask | NSContentsCellMask];
|
|
[cell setImage: [NSImage imageNamed: @"common_ArrowUp"]];
|
|
[cell setAlternateImage: [NSImage imageNamed: @"common_ArrowUpH"]];
|
|
[cell setImagePosition: NSImageOnly];
|
|
name = GSScrollerUpArrow;
|
|
}
|
|
else
|
|
{
|
|
[cell setHighlightsBy:
|
|
NSChangeBackgroundCellMask | NSContentsCellMask];
|
|
[cell setImage: [NSImage imageNamed: @"common_ArrowDown"]];
|
|
[cell setAlternateImage: [NSImage imageNamed: @"common_ArrowDownH"]];
|
|
[cell setImagePosition: NSImageOnly];
|
|
name = GSScrollerDownArrow;
|
|
}
|
|
}
|
|
[self setName: name forElement: cell temporary: YES];
|
|
RELEASE(cell);
|
|
return cell;
|
|
}
|
|
|
|
- (NSCell*) cellForScrollerKnob: (BOOL)horizontal
|
|
{
|
|
NSButtonCell *cell;
|
|
|
|
cell = [NSButtonCell new];
|
|
[cell setButtonType: NSMomentaryChangeButton];
|
|
[cell setImagePosition: NSImageOnly];
|
|
if (horizontal)
|
|
{
|
|
[self setName: GSScrollerHorizontalKnob forElement: cell temporary: YES];
|
|
[cell setImage: [NSImage imageNamed: @"common_DimpleHoriz"]];
|
|
}
|
|
else
|
|
{
|
|
[self setName: GSScrollerVerticalKnob forElement: cell temporary: YES];
|
|
[cell setImage: [NSImage imageNamed: @"common_Dimple"]];
|
|
|
|
}
|
|
RELEASE(cell);
|
|
return cell;
|
|
}
|
|
|
|
- (NSCell*) cellForScrollerKnobSlot: (BOOL)horizontal
|
|
{
|
|
GSDrawTiles *tiles;
|
|
NSButtonCell *cell;
|
|
NSColor *color;
|
|
NSString *name;
|
|
|
|
if (horizontal)
|
|
{
|
|
name = GSScrollerHorizontalSlot;
|
|
}
|
|
else
|
|
{
|
|
name = GSScrollerVerticalSlot;
|
|
}
|
|
|
|
tiles = [self tilesNamed: name state: GSThemeNormalState];
|
|
color = [self colorNamed: name state: GSThemeNormalState];
|
|
|
|
cell = [NSButtonCell new];
|
|
[cell setBordered: (tiles != nil)];
|
|
[cell setTitle: nil];
|
|
|
|
[self setName: name forElement: cell temporary: YES];
|
|
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor scrollBarColor];
|
|
}
|
|
[cell setBackgroundColor: color];
|
|
RELEASE(cell);
|
|
return cell;
|
|
}
|
|
|
|
- (float) defaultScrollerWidth
|
|
{
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
float defaultScrollerWidth;
|
|
|
|
if ([defs objectForKey: @"GSScrollerDefaultWidth"] != nil)
|
|
{
|
|
defaultScrollerWidth = [defs floatForKey: @"GSScrollerDefaultWidth"];
|
|
}
|
|
else
|
|
{
|
|
defaultScrollerWidth = 18.0;
|
|
}
|
|
return defaultScrollerWidth;
|
|
}
|
|
|
|
- (BOOL) scrollViewUseBottomCorner
|
|
{
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
if ([defs objectForKey: @"GSScrollViewUseBottomCorner"] != nil)
|
|
{
|
|
return [defs boolForKey: @"GSScrollViewUseBottomCorner"];
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL) scrollViewScrollersOverlapBorders
|
|
{
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
if ([defs objectForKey: @"GSScrollViewScrollersOverlapBorders"] != nil)
|
|
{
|
|
return [defs boolForKey: @"GSScrollViewScrollersOverlapBorders"];
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
- (NSColor *) toolbarBackgroundColor
|
|
{
|
|
NSColor *color;
|
|
|
|
color = [self colorNamed: @"toolbarBackgroundColor"
|
|
state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor clearColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (NSColor *) toolbarBorderColor
|
|
{
|
|
NSColor *color;
|
|
|
|
color = [self colorNamed: @"toolbarBorderColor"
|
|
state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor darkGrayColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (NSColor *) badgeBackgroundColor
|
|
{
|
|
NSColor *color;
|
|
|
|
color = [self colorNamed: @"badgeColor"
|
|
state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor redColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (NSColor *) badgeDecorationColor
|
|
{
|
|
NSColor *color;
|
|
|
|
color = [self colorNamed: @"badgeColor"
|
|
state: GSThemeSelectedState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor lightGrayColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (NSColor *) badgeTextColor
|
|
{
|
|
NSColor *color;
|
|
|
|
color = [self colorNamed: @"badgeColor"
|
|
state: GSThemeHighlightedState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor whiteColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (void) drawToolbarRect: (NSRect)aRect
|
|
frame: (NSRect)viewFrame
|
|
borderMask: (unsigned int)borderMask
|
|
{
|
|
// We draw the background
|
|
[[self toolbarBackgroundColor] set];
|
|
[NSBezierPath fillRect: aRect];
|
|
|
|
// We draw the border
|
|
[[self toolbarBorderColor] set];
|
|
if (borderMask & GSToolbarViewBottomBorder)
|
|
{
|
|
[NSBezierPath strokeLineFromPoint: NSMakePoint(0, 0.5)
|
|
toPoint: NSMakePoint(viewFrame.size.width, 0.5)];
|
|
}
|
|
if (borderMask & GSToolbarViewTopBorder)
|
|
{
|
|
[NSBezierPath strokeLineFromPoint: NSMakePoint(0,
|
|
viewFrame.size.height - 0.5)
|
|
toPoint: NSMakePoint(viewFrame.size.width,
|
|
viewFrame.size.height - 0.5)];
|
|
}
|
|
if (borderMask & GSToolbarViewLeftBorder)
|
|
{
|
|
[NSBezierPath strokeLineFromPoint: NSMakePoint(0.5, 0)
|
|
toPoint: NSMakePoint(0.5, viewFrame.size.height)];
|
|
}
|
|
if (borderMask & GSToolbarViewRightBorder)
|
|
{
|
|
[NSBezierPath strokeLineFromPoint: NSMakePoint(viewFrame.size.width - 0.5,0)
|
|
toPoint: NSMakePoint(viewFrame.size.width - 0.5,
|
|
viewFrame.size.height)];
|
|
}
|
|
}
|
|
|
|
- (BOOL) toolbarIsOpaque
|
|
{
|
|
if ([[self toolbarBackgroundColor] alphaComponent] < 1.0)
|
|
{
|
|
return NO;
|
|
}
|
|
else
|
|
{
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
- (NSRect) stepperUpButtonRectWithFrame: (NSRect)frame
|
|
{
|
|
NSSize size = [[NSImage imageNamed: @"common_StepperUp"] size];
|
|
NSRect upRect = {{NSMinX(frame), NSMinY(frame)}, {size.width, size.height}};
|
|
|
|
upRect.origin.x += ((int)frame.size.width / 2) - ((int)size.width / 2);
|
|
upRect.origin.y += ((int)frame.size.height / 2);
|
|
return upRect;
|
|
}
|
|
|
|
- (NSRect) stepperDownButtonRectWithFrame: (NSRect)frame
|
|
{
|
|
NSSize size = [[NSImage imageNamed: @"common_StepperDown"] size];
|
|
NSRect downRect = {{NSMinX(frame), NSMinY(frame)}, {size.width, size.height}};
|
|
|
|
downRect.origin.x += ((int)frame.size.width / 2) - ((int)size.width / 2);
|
|
downRect.origin.y += ((int)frame.size.height / 2) - size.height;
|
|
return downRect;
|
|
}
|
|
|
|
- (void) drawStepperBorder: (NSRect)frame
|
|
{
|
|
}
|
|
|
|
- (NSRect) drawStepperLightButton: (NSRect)border : (NSRect)clip
|
|
{
|
|
return NSZeroRect;
|
|
}
|
|
|
|
- (void) drawStepperUpButton: (NSRect)aRect
|
|
{
|
|
NSImage *image = [NSImage imageNamed: @"common_StepperUp"];
|
|
[image drawInRect: aRect
|
|
fromRect: NSZeroRect
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1
|
|
respectFlipped: YES
|
|
hints: nil];
|
|
}
|
|
|
|
- (void) drawStepperHighlightUpButton: (NSRect)aRect
|
|
{
|
|
NSImage *image = [NSImage imageNamed: @"common_StepperUpHighlighted"];
|
|
[image drawInRect: aRect
|
|
fromRect: NSZeroRect
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1
|
|
respectFlipped: YES
|
|
hints: nil];
|
|
}
|
|
|
|
- (void) drawStepperDownButton: (NSRect)aRect
|
|
{
|
|
NSImage *image = [NSImage imageNamed: @"common_StepperDown"];
|
|
[image drawInRect: aRect
|
|
fromRect: NSZeroRect
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1
|
|
respectFlipped: YES
|
|
hints: nil];
|
|
}
|
|
|
|
- (void) drawStepperHighlightDownButton: (NSRect)aRect
|
|
{
|
|
NSImage *image = [NSImage imageNamed: @"common_StepperDownHighlighted"];
|
|
[image drawInRect: aRect
|
|
fromRect: NSZeroRect
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1
|
|
respectFlipped: YES
|
|
hints: nil];
|
|
}
|
|
|
|
- (void) drawStepperCell: (NSCell*)cell
|
|
withFrame: (NSRect)cellFrame
|
|
inView: (NSView*)controlView
|
|
highlightUp: (BOOL)highlightUp
|
|
highlightDown: (BOOL)highlightDown
|
|
{
|
|
const NSRect upRect = [self stepperUpButtonRectWithFrame: cellFrame];
|
|
const NSRect downRect = [self stepperDownButtonRectWithFrame: cellFrame];
|
|
|
|
[self drawStepperBorder: cellFrame];
|
|
|
|
if (highlightUp)
|
|
[self drawStepperHighlightUpButton: upRect];
|
|
else
|
|
[self drawStepperUpButton: upRect];
|
|
|
|
if (highlightDown)
|
|
[self drawStepperHighlightDownButton: downRect];
|
|
else
|
|
[self drawStepperDownButton: downRect];
|
|
}
|
|
|
|
// NSSwitch drawing methods
|
|
|
|
- (void) drawSwitchBezel: (NSRect)frame
|
|
forState: (NSControlStateValue)v
|
|
enabled: (BOOL)enabled
|
|
{
|
|
NSBezierPath *p;
|
|
NSPoint point;
|
|
CGFloat radius;
|
|
NSColor *backgroundColor;
|
|
|
|
if (enabled == NO)
|
|
{
|
|
backgroundColor = [NSColor disabledControlTextColor];
|
|
}
|
|
else if (NSControlStateValueOn != v)
|
|
{
|
|
backgroundColor = [NSColor windowBackgroundColor]; // offColor
|
|
}
|
|
else
|
|
{
|
|
backgroundColor = [NSColor selectedControlColor]; // onColor
|
|
}
|
|
|
|
// make smaller than enclosing frame
|
|
frame = NSInsetRect(frame, 4, 4);
|
|
radius = frame.size.height / 2.0;
|
|
point = frame.origin;
|
|
point.x += radius;
|
|
point.y += radius - 0.5;
|
|
|
|
// Draw initial path to enclose the button...
|
|
// left half-circle
|
|
p = [NSBezierPath bezierPath];
|
|
[p appendBezierPathWithArcWithCenter: point
|
|
radius: radius
|
|
startAngle: 90.0
|
|
endAngle: 270.0];
|
|
|
|
// line to first point and right halfcircle
|
|
point.x += frame.size.width - frame.size.height;
|
|
[p appendBezierPathWithArcWithCenter: point
|
|
radius: radius
|
|
startAngle: 270.0
|
|
endAngle: 90.0];
|
|
[p closePath];
|
|
|
|
// fill with background color
|
|
[backgroundColor set];
|
|
[p fill];
|
|
|
|
// and stroke rounded button
|
|
[[NSColor shadowColor] set];
|
|
[p stroke];
|
|
|
|
// Add highlights...
|
|
point = frame.origin;
|
|
point.x += radius - 0.5;
|
|
point.y += radius - 0.5;
|
|
p = [NSBezierPath bezierPath];
|
|
[p setLineWidth: 1.0];
|
|
[p appendBezierPathWithArcWithCenter: point
|
|
radius: radius
|
|
startAngle: 135.0
|
|
endAngle: 270.0];
|
|
|
|
// line to first point and right halfcircle
|
|
point.x += frame.size.width - frame.size.height;
|
|
[p appendBezierPathWithArcWithCenter: point
|
|
radius: radius
|
|
startAngle: 270.0
|
|
endAngle: 315.0];
|
|
[[NSColor controlLightHighlightColor] set];
|
|
[p stroke];
|
|
}
|
|
|
|
- (void) drawSwitchKnob: (NSRect)frame
|
|
forState: (NSControlStateValue)value
|
|
enabled: (BOOL)enabled
|
|
{
|
|
NSColor *backgroundColor = enabled ? [NSColor windowBackgroundColor] : [NSColor disabledControlTextColor];
|
|
NSBezierPath *oval;
|
|
NSRect rect = NSZeroRect;
|
|
CGFloat w = (frame.size.width / 2) - 2;
|
|
CGFloat h = frame.size.height - 6;
|
|
CGFloat y = frame.origin.y + 2;
|
|
CGFloat radius = frame.size.height / 2.0;
|
|
|
|
[backgroundColor set];
|
|
if (value == NSControlStateValueOff)
|
|
{
|
|
rect = NSMakeRect(frame.origin.x + 4,
|
|
y,
|
|
w,
|
|
h);
|
|
}
|
|
else
|
|
{
|
|
rect = NSMakeRect(frame.origin.x + ((frame.size.width - 2 * radius) + 2), // ((frame.size.width - w) - 2)
|
|
y,
|
|
w,
|
|
h);
|
|
}
|
|
|
|
|
|
oval = [NSBezierPath bezierPathWithOvalInRect: NSInsetRect(rect, 1, 1)];
|
|
|
|
// fill oval with background color
|
|
[backgroundColor set];
|
|
[oval fill];
|
|
|
|
// and stroke rounded button
|
|
[[NSColor shadowColor] set];
|
|
[oval stroke];
|
|
}
|
|
|
|
- (void) drawSwitchInRect: (NSRect)rect
|
|
forState: (NSControlStateValue)state
|
|
enabled: (BOOL)enabled
|
|
{
|
|
// Draw the well bezel
|
|
[self drawSwitchBezel: rect
|
|
forState: state
|
|
enabled: enabled];
|
|
|
|
// Draw the knob
|
|
[self drawSwitchKnob: rect
|
|
forState: state
|
|
enabled: enabled];
|
|
|
|
}
|
|
|
|
// NSPathComponentCell
|
|
|
|
- (void) drawPathComponentCellWithFrame: (NSRect)frame
|
|
inView: (NSPathControl *)pc
|
|
withCell: (NSPathComponentCell *)cell
|
|
isLastComponent: (BOOL)last
|
|
{
|
|
NSImage *img = [cell image];
|
|
NSURL *url = [cell URL];
|
|
NSString *string = [[url path] lastPathComponent];
|
|
NSRect textFrame = frame;
|
|
NSRect imgFrame = frame;
|
|
NSRect arrowFrame = frame;
|
|
NSImage *arrowImage = [NSImage imageNamed: @"NSMenuArrow"];
|
|
NSPathStyle style= [pc pathStyle];
|
|
NSRect newFrame = frame;
|
|
|
|
if (style == NSPathStylePopUp)
|
|
{
|
|
newFrame = [pc frame];
|
|
|
|
// Reset coodinates.
|
|
newFrame.origin.x = 0.0;
|
|
newFrame.origin.y = 0.0;
|
|
|
|
// Use control frame...
|
|
textFrame = newFrame;
|
|
imgFrame = newFrame;
|
|
arrowFrame = newFrame;
|
|
}
|
|
|
|
// Modify positions...
|
|
imgFrame.size.width = 17.0;
|
|
imgFrame.size.height = 17.0;
|
|
imgFrame.origin.x += 2.0;
|
|
imgFrame.origin.y += 2.0;
|
|
textFrame.origin.x += imgFrame.size.width + 5.0; // the width of the image plus a few pixels.
|
|
textFrame.origin.y += 5.0; // center with the image...
|
|
arrowFrame.origin.x += newFrame.size.width - 17.0;
|
|
arrowFrame.size.width = 8.0;
|
|
arrowFrame.size.height = 8.0;
|
|
arrowFrame.origin.y += 5.0;
|
|
|
|
if (style== NSPathStyleStandard || style== NSPathStyleNavigationBar)
|
|
{
|
|
// Draw the image...
|
|
[img drawInRect: imgFrame];
|
|
|
|
// Draw the text...
|
|
[[NSColor textColor] set];
|
|
[string drawAtPoint: textFrame.origin
|
|
withAttributes: nil];
|
|
|
|
// Draw the arrow...
|
|
if (last == NO)
|
|
{
|
|
[arrowImage drawInRect: arrowFrame];
|
|
}
|
|
}
|
|
else if (style == NSPathStylePopUp)
|
|
{
|
|
if (last == YES)
|
|
{
|
|
arrowImage = [NSImage imageNamed: @"common_ArrowDown"];
|
|
|
|
// Draw border...
|
|
[[NSColor controlShadowColor] set];
|
|
NSFrameRectWithWidth(newFrame, 1.0);
|
|
|
|
// Draw the image...
|
|
[img drawInRect: imgFrame];
|
|
|
|
// Draw the text...
|
|
[[NSColor textColor] set];
|
|
[string drawAtPoint: textFrame.origin
|
|
withAttributes: nil];
|
|
|
|
// Draw the arrow...
|
|
[arrowImage drawInRect: arrowFrame];
|
|
}
|
|
}
|
|
}
|
|
|
|
// NSSegmentedControl drawing methods
|
|
|
|
- (void) drawSegmentedControlSegment: (NSCell *)cell
|
|
withFrame: (NSRect)cellFrame
|
|
inView: (NSView *)controlView
|
|
style: (NSSegmentStyle)style
|
|
state: (GSThemeControlState)state
|
|
roundedLeft: (BOOL)roundedLeft
|
|
roundedRight: (BOOL)roundedRight
|
|
{
|
|
GSDrawTiles *tiles;
|
|
NSString *name = GSStringFromSegmentStyle(style);
|
|
if (roundedLeft)
|
|
{
|
|
name = [name stringByAppendingString: @"RoundedLeft"];
|
|
}
|
|
if (roundedRight)
|
|
{
|
|
name = [name stringByAppendingString: @"RoundedRight"];
|
|
}
|
|
|
|
tiles = [self tilesNamed: name state: state];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
[self drawButton: cellFrame
|
|
in: cell
|
|
view: controlView
|
|
style: NSRegularSquareBezelStyle
|
|
state: state];
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: cellFrame
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (NSColor *) menuBackgroundColor
|
|
{
|
|
NSColor *color = [self colorNamed: @"menuBackgroundColor"
|
|
state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor windowBackgroundColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (NSColor *) menuItemBackgroundColor
|
|
{
|
|
NSColor *color = [self colorNamed: @"menuItemBackgroundColor"
|
|
state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor controlBackgroundColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (NSColor *) menuBorderColor
|
|
{
|
|
NSColor *color = [self colorNamed: @"menuBorderColor"
|
|
state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor darkGrayColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (NSColor *) menuBarBackgroundColor
|
|
{
|
|
NSColor *color = [self colorNamed: @"menuBarBackgroundColor"
|
|
state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [self menuBackgroundColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (NSColor *) menuBarBorderColor
|
|
{
|
|
NSColor *color = [self colorNamed: @"menuBarBorderColor"
|
|
state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [self menuBorderColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (NSColor *) menuBorderColorForEdge: (NSRectEdge)edge isHorizontal: (BOOL)horizontal
|
|
{
|
|
if (horizontal && edge == NSMinYEdge)
|
|
{
|
|
return [self menuBorderColor];
|
|
}
|
|
else if (edge == NSMinXEdge || edge == NSMaxYEdge)
|
|
{
|
|
// Draw the dark gray upper left lines.
|
|
return [self menuBorderColor];
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (void) drawBackgroundForMenuView: (NSMenuView*)menuView
|
|
withFrame: (NSRect)bounds
|
|
dirtyRect: (NSRect)dirtyRect
|
|
horizontal: (BOOL)horizontal
|
|
{
|
|
NSString *name = horizontal ? GSMenuHorizontalBackground :
|
|
GSMenuVerticalBackground;
|
|
GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
NSRectEdge sides[4] = { NSMinXEdge, NSMaxYEdge, NSMaxXEdge, NSMinYEdge };
|
|
NSColor *colors[] = {[self menuBorderColorForEdge: NSMinXEdge isHorizontal: horizontal],
|
|
[self menuBorderColorForEdge: NSMaxYEdge isHorizontal: horizontal],
|
|
[self menuBorderColorForEdge: NSMaxXEdge isHorizontal: horizontal],
|
|
[self menuBorderColorForEdge: NSMinYEdge isHorizontal: horizontal]};
|
|
|
|
[[self menuBackgroundColor] set];
|
|
NSRectFill(NSIntersectionRect(bounds, dirtyRect));
|
|
NSDrawColorTiledRects(bounds, dirtyRect, sides, colors, 4);
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: bounds
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (BOOL) drawsBorderForMenuItemCell: (NSMenuItemCell *)cell
|
|
state: (GSThemeControlState)state
|
|
isHorizontal: (BOOL)horizontal
|
|
{
|
|
return [cell isBordered];
|
|
}
|
|
|
|
- (void) drawBorderAndBackgroundForMenuItemCell: (NSMenuItemCell *)cell
|
|
withFrame: (NSRect)cellFrame
|
|
inView: (NSView *)controlView
|
|
state: (GSThemeControlState)state
|
|
isHorizontal: (BOOL)isHorizontal
|
|
{
|
|
NSString *name = isHorizontal ? GSMenuHorizontalItem :
|
|
GSMenuVerticalItem;
|
|
GSDrawTiles *tiles = [self tilesNamed: name state: state];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
NSColor *backgroundColor = [cell backgroundColor];
|
|
|
|
if (isHorizontal)
|
|
{
|
|
cellFrame = [cell drawingRectForBounds: cellFrame];
|
|
[backgroundColor set];
|
|
NSRectFill(cellFrame);
|
|
return;
|
|
}
|
|
|
|
// Set cell's background color
|
|
[backgroundColor set];
|
|
NSRectFill(cellFrame);
|
|
|
|
if (![self drawsBorderForMenuItemCell: cell
|
|
state: state
|
|
isHorizontal: isHorizontal])
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (state == GSThemeSelectedState)
|
|
{
|
|
[self drawGrayBezel: cellFrame withClip: NSZeroRect];
|
|
}
|
|
else
|
|
{
|
|
[self drawButton: cellFrame withClip: NSZeroRect];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: cellFrame
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (NSColor *) menuSeparatorColor
|
|
{
|
|
NSColor *color = [self colorNamed: @"menuSeparatorColor"
|
|
state: GSThemeNormalState];
|
|
NSInterfaceStyle style = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil);
|
|
|
|
// TODO: Remove the style check... Windows theming should be in a subclass
|
|
// probably
|
|
if (color == nil && style == NSWindows95InterfaceStyle)
|
|
{
|
|
color = [NSColor blackColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (CGFloat) menuSeparatorInset
|
|
{
|
|
return 3.0;
|
|
}
|
|
|
|
- (CGFloat) menuSubmenuHorizontalOverlap
|
|
{
|
|
return [[NSUserDefaults standardUserDefaults]
|
|
floatForKey: @"GSMenuSubmenuHorizontalOverlap"];
|
|
}
|
|
|
|
- (CGFloat) menuSubmenuVerticalOverlap
|
|
{
|
|
return [[NSUserDefaults standardUserDefaults]
|
|
floatForKey: @"GSMenuSubmenuVerticalOverlap"];
|
|
}
|
|
|
|
- (void) drawSeparatorItemForMenuItemCell: (NSMenuItemCell *)cell
|
|
withFrame: (NSRect)cellFrame
|
|
inView: (NSView *)controlView
|
|
isHorizontal: (BOOL)isHorizontal
|
|
{
|
|
GSDrawTiles *tiles;
|
|
|
|
tiles = [self tilesNamed: GSMenuSeparatorItem state: GSThemeNormalState];
|
|
if (tiles == nil)
|
|
{
|
|
NSBezierPath *path = [NSBezierPath bezierPath];
|
|
CGFloat inset = [self menuSeparatorInset];
|
|
NSPoint start = NSMakePoint(inset, cellFrame.size.height / 2 +
|
|
cellFrame.origin.y + 0.5);
|
|
NSPoint end = NSMakePoint(cellFrame.size.width - inset,
|
|
cellFrame.size.height / 2 + cellFrame.origin.y + 0.5);
|
|
|
|
[[self menuSeparatorColor] set];
|
|
|
|
[path setLineWidth: 0.0];
|
|
[path moveToPoint: start];
|
|
[path lineToPoint: end];
|
|
|
|
[path stroke];
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: cellFrame
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (void) drawTitleForMenuItemCell: (NSMenuItemCell *)cell
|
|
withFrame: (NSRect)cellFrame
|
|
inView: (NSView *)controlView
|
|
state: (GSThemeControlState)state
|
|
isHorizontal: (BOOL)isHorizontal
|
|
{
|
|
[cell _drawText: [[cell menuItem] title]
|
|
inFrame: [cell titleRectForBounds: cellFrame]];
|
|
}
|
|
|
|
- (Class) titleViewClassForMenuView: (NSMenuView *)aMenuView
|
|
{
|
|
return [GSTitleView class];
|
|
}
|
|
|
|
- (NSRect) drawMenuTitleBackground: (GSTitleView *)aTitleView
|
|
withBounds: (NSRect)bounds
|
|
withClip: (NSRect)clipRect
|
|
{
|
|
GSDrawTiles *tiles = [self tilesNamed: GSMenuTitleBackground state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
NSRect workRect = bounds;
|
|
NSRectEdge top_left[] = {NSMinXEdge, NSMaxYEdge};
|
|
CGFloat darkGrays[] = {NSDarkGray, NSDarkGray};
|
|
NSColor *titleColor;
|
|
|
|
titleColor = [self colorNamed: @"GSMenuBar" state: GSThemeNormalState];
|
|
if (titleColor == nil)
|
|
{
|
|
titleColor = [NSColor blackColor];
|
|
}
|
|
|
|
// Draw the dark gray upper left lines for menu and black for others.
|
|
// Rectangle 1
|
|
workRect = NSDrawTiledRects(workRect, workRect, top_left, darkGrays, 2);
|
|
|
|
// Rectangle 2
|
|
// Draw the title box's button.
|
|
[self drawButton: workRect withClip: workRect];
|
|
|
|
// Overdraw white top and left lines with light gray lines for window title
|
|
workRect.origin.y += 1;
|
|
workRect.size.height -= 1;
|
|
workRect.size.width -= 1;
|
|
|
|
// Rectangle 3
|
|
// Paint background
|
|
workRect.origin.x += 1;
|
|
workRect.origin.y += 1;
|
|
workRect.size.height -= 2;
|
|
workRect.size.width -= 2;
|
|
|
|
[titleColor set];
|
|
NSRectFill(workRect);
|
|
|
|
return workRect;
|
|
}
|
|
else
|
|
{
|
|
return [self fillRect: bounds
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (CGFloat) menuBarHeight
|
|
{
|
|
CGFloat height = [[NSUserDefaults standardUserDefaults]
|
|
floatForKey: @"GSMenuBarHeight"];
|
|
if (height <= 0)
|
|
{
|
|
return 22;
|
|
}
|
|
return height;
|
|
}
|
|
|
|
- (CGFloat) menuItemHeight
|
|
{
|
|
CGFloat height = [[NSUserDefaults standardUserDefaults]
|
|
floatForKey: @"GSMenuItemHeight"];
|
|
if (height <= 0)
|
|
{
|
|
return 20;
|
|
}
|
|
return height;
|
|
}
|
|
|
|
- (CGFloat) menuSeparatorHeight
|
|
{
|
|
CGFloat height = [[NSUserDefaults standardUserDefaults]
|
|
floatForKey: @"GSMenuSeparatorHeight"];
|
|
if (height <= 0)
|
|
{
|
|
return 20;
|
|
}
|
|
return height;
|
|
}
|
|
|
|
// NSColorWell drawing method
|
|
- (NSRect) drawColorWellBorder: (NSColorWell*)well
|
|
withBounds: (NSRect)bounds
|
|
withClip: (NSRect)clipRect
|
|
{
|
|
NSRect aRect = bounds;
|
|
|
|
if ([well isBordered])
|
|
{
|
|
GSThemeControlState state;
|
|
GSDrawTiles *tiles;
|
|
|
|
if ([[well cell] isHighlighted] || [well isActive])
|
|
{
|
|
state = GSThemeHighlightedState;
|
|
}
|
|
else
|
|
{
|
|
state = GSThemeNormalState;
|
|
}
|
|
|
|
tiles = [self tilesNamed: GSColorWell state: state];
|
|
if (tiles == nil)
|
|
{
|
|
/*
|
|
* Draw border.
|
|
*/
|
|
[self drawButton: aRect withClip: clipRect];
|
|
|
|
/*
|
|
* Fill in control color.
|
|
*/
|
|
if (state == GSThemeHighlightedState)
|
|
{
|
|
[[NSColor selectedControlColor] set];
|
|
}
|
|
else
|
|
{
|
|
[[NSColor controlColor] set];
|
|
}
|
|
aRect = NSInsetRect(aRect, 2.0, 2.0);
|
|
NSRectFill(NSIntersectionRect(aRect, clipRect));
|
|
}
|
|
else
|
|
{
|
|
aRect = [self fillRect: aRect
|
|
withTiles: tiles];
|
|
}
|
|
|
|
/*
|
|
* Set an inset rect for the color area
|
|
*/
|
|
aRect = NSInsetRect(bounds, COLOR_WELL_BORDER_WIDTH, COLOR_WELL_BORDER_WIDTH);
|
|
}
|
|
|
|
/*
|
|
* OpenStep 4.2 behavior is to omit the inner border for
|
|
* non-enabled NSColorWell objects.
|
|
*/
|
|
if ([well isEnabled])
|
|
{
|
|
GSDrawTiles *tiles = [self tilesNamed: GSColorWellInnerBorder state: GSThemeNormalState];
|
|
if (tiles == nil)
|
|
{
|
|
/*
|
|
* Draw inner frame.
|
|
*/
|
|
[self drawGrayBezel: aRect withClip: clipRect];
|
|
aRect = NSInsetRect(aRect, 2.0, 2.0);
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: aRect
|
|
withTiles: tiles];
|
|
|
|
aRect = [tiles contentRectForRect: aRect isFlipped: [well isFlipped]];
|
|
}
|
|
}
|
|
|
|
return aRect;
|
|
}
|
|
|
|
// progress indicator drawing methods
|
|
static NSColor *fillColour = nil;
|
|
#define MaxCount 10
|
|
static int indeterminateMaxCount = MaxCount;
|
|
static int spinningMaxCount = MaxCount;
|
|
static NSColor *indeterminateColors[MaxCount];
|
|
static NSImage *spinningImages[MaxCount];
|
|
|
|
- (void) initProgressIndicatorDrawing
|
|
{
|
|
int i;
|
|
|
|
// FIXME: Should come from defaults and should be reset when defaults change
|
|
// FIXME: Should probably get the color from the color extension list (see NSToolbar)
|
|
fillColour = RETAIN([NSColor controlShadowColor]);
|
|
|
|
// Load images for indeterminate style
|
|
for (i = 0; i < MaxCount; i++)
|
|
{
|
|
NSString *imgName = [NSString stringWithFormat: @"common_ProgressIndeterminate_%d", i + 1];
|
|
NSImage *image = [NSImage imageNamed: imgName];
|
|
|
|
if (image == nil)
|
|
{
|
|
indeterminateMaxCount = i;
|
|
break;
|
|
}
|
|
indeterminateColors[i] = RETAIN([NSColor colorWithPatternImage: image]);
|
|
}
|
|
|
|
// Load images for spinning style
|
|
for (i = 0; i < MaxCount; i++)
|
|
{
|
|
NSString *imgName = [NSString stringWithFormat: @"common_ProgressSpinning_%d", i + 1];
|
|
NSImage *image = [NSImage imageNamed: imgName];
|
|
|
|
if (image == nil)
|
|
{
|
|
spinningMaxCount = i;
|
|
break;
|
|
}
|
|
spinningImages[i] = RETAIN(image);
|
|
}
|
|
}
|
|
|
|
- (void) drawProgressIndicator: (NSProgressIndicator*)progress
|
|
withBounds: (NSRect)bounds
|
|
withClip: (NSRect)rect
|
|
atCount: (int)count
|
|
forValue: (double)val
|
|
{
|
|
NSRect r;
|
|
|
|
if (fillColour == nil)
|
|
{
|
|
[self initProgressIndicatorDrawing];
|
|
}
|
|
|
|
// Draw the Bezel
|
|
if ([progress isBezeled])
|
|
{
|
|
// Calc the inside rect to be drawn
|
|
r = [self drawProgressIndicatorBezel: bounds withClip: rect];
|
|
}
|
|
else
|
|
{
|
|
r = bounds;
|
|
}
|
|
|
|
if ([progress style] == NSProgressIndicatorSpinningStyle)
|
|
{
|
|
NSRect imgBox = {{0,0}, {0,0}};
|
|
|
|
if (spinningMaxCount != 0)
|
|
{
|
|
count = count % spinningMaxCount;
|
|
imgBox.size = [spinningImages[count] size];
|
|
[spinningImages[count] drawInRect: r
|
|
fromRect: imgBox
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1.0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ([progress isIndeterminate])
|
|
{
|
|
if (indeterminateMaxCount != 0)
|
|
{
|
|
count = count % indeterminateMaxCount;
|
|
[indeterminateColors[count] set];
|
|
NSRectFill(r);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Draw determinate
|
|
if ([progress isVertical])
|
|
{
|
|
float height = NSHeight(r) * val;
|
|
|
|
if ([progress isFlipped])
|
|
{
|
|
// Compensate for the flip
|
|
r.origin.y += NSHeight(r) - height;
|
|
}
|
|
r.size.height = height;
|
|
}
|
|
else
|
|
{
|
|
r.size.width = NSWidth(r) * val;
|
|
}
|
|
r = NSIntersectionRect(r, rect);
|
|
if (!NSIsEmptyRect(r))
|
|
{
|
|
[self drawProgressIndicatorBarDeterminate: (NSRect)r];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSRect) drawProgressIndicatorBezel: (NSRect)bounds withClip: (NSRect) rect
|
|
{
|
|
GSDrawTiles *tiles = [self tilesNamed: GSProgressIndicatorBezel
|
|
state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
return [self drawGrayBezel: bounds withClip: rect];
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: bounds
|
|
withTiles: tiles];
|
|
|
|
return [tiles contentRectForRect: bounds
|
|
isFlipped: [[NSView focusView] isFlipped]];
|
|
}
|
|
}
|
|
|
|
- (void) drawProgressIndicatorBarDeterminate: (NSRect)bounds
|
|
{
|
|
GSDrawTiles *tiles = [self tilesNamed: GSProgressIndicatorBarDeterminate
|
|
state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
[fillColour set];
|
|
NSRectFill(bounds);
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: bounds
|
|
withTiles: tiles
|
|
background: fillColour];
|
|
}
|
|
}
|
|
|
|
// Table drawing methods
|
|
|
|
- (NSColor *) tableHeaderTextColorForState: (GSThemeControlState)state
|
|
{
|
|
NSColor *color;
|
|
|
|
color = [self colorNamed: @"tableHeaderTextColor"
|
|
state: state];
|
|
if (color == nil)
|
|
{
|
|
if (state == GSThemeHighlightedState)
|
|
color = [NSColor controlTextColor];
|
|
else
|
|
color = [NSColor windowFrameTextColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (void) drawTableCornerView: (NSView*)cornerView
|
|
withClip: (NSRect)aRect
|
|
{
|
|
NSRect divide;
|
|
NSRect rect;
|
|
GSDrawTiles *tiles = [self tilesNamed: GSTableCorner state: GSThemeNormalState];
|
|
|
|
if ([cornerView isFlipped])
|
|
{
|
|
NSDivideRect(aRect, ÷, &rect, 1.0, NSMaxYEdge);
|
|
}
|
|
else
|
|
{
|
|
NSDivideRect(aRect, ÷, &rect, 1.0, NSMinYEdge);
|
|
}
|
|
|
|
if (tiles == nil)
|
|
{
|
|
rect = [self drawDarkButton: rect withClip: aRect];
|
|
[[NSColor controlShadowColor] set];
|
|
NSRectFill(rect);
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: aRect
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (void) drawTableHeaderCell: (NSTableHeaderCell *)cell
|
|
withFrame: (NSRect)cellFrame
|
|
inView: (NSView *)controlView
|
|
state: (GSThemeControlState)state
|
|
{
|
|
GSDrawTiles *tiles = [self tilesNamed: GSTableHeader state: state];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
NSRect rect;
|
|
|
|
// Leave a 1pt thick horizontal line underneath the header
|
|
if (![controlView isFlipped])
|
|
{
|
|
cellFrame.origin.y++;
|
|
}
|
|
cellFrame.size.height--;
|
|
|
|
if (state == GSThemeHighlightedState)
|
|
{
|
|
rect = [self drawButton: cellFrame withClip: cellFrame];
|
|
[[NSColor controlColor] set];
|
|
NSRectFill(rect);
|
|
}
|
|
else
|
|
{
|
|
rect = [self drawDarkButton: cellFrame withClip: cellFrame];
|
|
[[NSColor controlShadowColor] set];
|
|
NSRectFill(rect);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: cellFrame
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
|
|
// Window decoration drawing methods
|
|
/* These include the black border. */
|
|
#define TITLE_HEIGHT 23.0
|
|
#define RESIZE_HEIGHT 9.0
|
|
#define RESIZE_NOTCH_WIDTH 30.0
|
|
#define TITLEBAR_BUTTON_SIZE 15.0
|
|
#define TITLEBAR_PADDING_TOP 4.0
|
|
#define TITLEBAR_PADDING_RIGHT 4.0
|
|
#define TITLEBAR_PADDING_LEFT 4.0
|
|
|
|
- (float) titlebarHeight
|
|
{
|
|
return TITLE_HEIGHT;
|
|
}
|
|
|
|
- (float) resizebarHeight
|
|
{
|
|
return RESIZE_HEIGHT;
|
|
}
|
|
|
|
- (float) resizebarNotchWidth
|
|
{
|
|
return RESIZE_NOTCH_WIDTH;
|
|
}
|
|
|
|
- (float) titlebarButtonSize
|
|
{
|
|
return TITLEBAR_BUTTON_SIZE;
|
|
}
|
|
|
|
- (float) titlebarPaddingRight
|
|
{
|
|
return TITLEBAR_PADDING_RIGHT;
|
|
}
|
|
|
|
- (float) titlebarPaddingTop
|
|
{
|
|
return TITLEBAR_PADDING_TOP;
|
|
}
|
|
|
|
- (float) titlebarPaddingLeft
|
|
{
|
|
return TITLEBAR_PADDING_LEFT;
|
|
}
|
|
|
|
static NSDictionary *titleTextAttributes[3] = {nil, nil, nil};
|
|
|
|
- (void) drawTitleBarRect: (NSRect)titleBarRect
|
|
forStyleMask: (unsigned int)styleMask
|
|
state: (int)inputState
|
|
andTitle: (NSString*)title
|
|
{
|
|
static const NSRectEdge edges[4] = {NSMinXEdge, NSMaxYEdge,
|
|
NSMaxXEdge, NSMinYEdge};
|
|
CGFloat grays[3][4] =
|
|
{{NSLightGray, NSLightGray, NSDarkGray, NSDarkGray},
|
|
{NSWhite, NSWhite, NSDarkGray, NSDarkGray},
|
|
{NSLightGray, NSLightGray, NSBlack, NSBlack}};
|
|
NSRect workRect;
|
|
GSDrawTiles *tiles = nil;
|
|
|
|
if (!titleTextAttributes[0])
|
|
{
|
|
NSMutableParagraphStyle *p;
|
|
NSColor *keyColor, *normalColor, *mainColor;
|
|
|
|
p = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
|
[p setLineBreakMode: NSLineBreakByClipping];
|
|
|
|
// FIXME: refine color names based on style mask
|
|
// (HUD or textured or regular window)
|
|
|
|
keyColor = [self colorNamed: @"keyWindowFrameTextColor"
|
|
state: GSThemeNormalState];
|
|
if (nil == keyColor)
|
|
{
|
|
keyColor = [NSColor windowFrameTextColor];
|
|
}
|
|
|
|
normalColor = [self colorNamed: @"normalWindowFrameTextColor"
|
|
state: GSThemeNormalState];
|
|
if (nil == normalColor)
|
|
{
|
|
normalColor = [NSColor blackColor];
|
|
}
|
|
|
|
mainColor = [self colorNamed: @"mainWindowFrameTextColor"
|
|
state: GSThemeNormalState];
|
|
if (nil == mainColor)
|
|
{
|
|
mainColor = [NSColor windowFrameTextColor];
|
|
}
|
|
|
|
titleTextAttributes[0] = [[NSMutableDictionary alloc]
|
|
initWithObjectsAndKeys:
|
|
[NSFont titleBarFontOfSize: 0], NSFontAttributeName,
|
|
keyColor, NSForegroundColorAttributeName,
|
|
p, NSParagraphStyleAttributeName,
|
|
nil];
|
|
|
|
titleTextAttributes[1] = [[NSMutableDictionary alloc]
|
|
initWithObjectsAndKeys:
|
|
[NSFont titleBarFontOfSize: 0], NSFontAttributeName,
|
|
normalColor, NSForegroundColorAttributeName,
|
|
p, NSParagraphStyleAttributeName,
|
|
nil];
|
|
|
|
titleTextAttributes[2] = [[NSMutableDictionary alloc]
|
|
initWithObjectsAndKeys:
|
|
[NSFont titleBarFontOfSize: 0], NSFontAttributeName,
|
|
mainColor, NSForegroundColorAttributeName,
|
|
p, NSParagraphStyleAttributeName,
|
|
nil];
|
|
|
|
RELEASE(p);
|
|
}
|
|
|
|
tiles = [self tilesNamed: @"GSWindowTitleBar" state: GSThemeNormalState];
|
|
if (tiles == nil)
|
|
{
|
|
/*
|
|
Draw the black border towards the rest of the window. (The outer black
|
|
border is drawn in -drawRect: since it might be drawn even if we don't have
|
|
a title bar.
|
|
*/
|
|
NSColor *borderColor = [self colorNamed: @"windowBorderColor"
|
|
state: GSThemeNormalState];
|
|
if (nil == borderColor)
|
|
{
|
|
borderColor = [NSColor blackColor];
|
|
}
|
|
[borderColor set];
|
|
|
|
PSmoveto(0, NSMinY(titleBarRect) + 0.5);
|
|
PSrlineto(titleBarRect.size.width, 0);
|
|
PSstroke();
|
|
|
|
/*
|
|
Draw the button-like border.
|
|
*/
|
|
workRect = titleBarRect;
|
|
workRect.origin.x += 1;
|
|
workRect.origin.y += 1;
|
|
workRect.size.width -= 2;
|
|
workRect.size.height -= 2;
|
|
|
|
workRect = NSDrawTiledRects(workRect, workRect, edges, grays[inputState], 4);
|
|
|
|
/*
|
|
Draw the background.
|
|
*/
|
|
switch (inputState)
|
|
{
|
|
default:
|
|
case 0:
|
|
[[NSColor windowFrameColor] set];
|
|
break;
|
|
case 1:
|
|
[[NSColor lightGrayColor] set];
|
|
break;
|
|
case 2:
|
|
[[NSColor darkGrayColor] set];
|
|
break;
|
|
}
|
|
NSRectFill(workRect);
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: titleBarRect
|
|
withTiles: tiles
|
|
background: [NSColor windowFrameColor]];
|
|
workRect = titleBarRect;
|
|
}
|
|
/* Draw the title. */
|
|
if (styleMask & NSTitledWindowMask)
|
|
{
|
|
NSSize titleSize;
|
|
|
|
if (styleMask & NSMiniaturizableWindowMask)
|
|
{
|
|
workRect.origin.x += 17;
|
|
workRect.size.width -= 17;
|
|
}
|
|
if (styleMask & NSClosableWindowMask)
|
|
{
|
|
workRect.size.width -= 17;
|
|
}
|
|
|
|
titleSize = [title sizeWithAttributes: titleTextAttributes[inputState]];
|
|
if (titleSize.width <= workRect.size.width)
|
|
workRect.origin.x = NSMidX(workRect) - titleSize.width / 2;
|
|
workRect.origin.y = NSMidY(workRect) - titleSize.height / 2;
|
|
workRect.size.height = titleSize.height;
|
|
[title drawInRect: workRect
|
|
withAttributes: titleTextAttributes[inputState]];
|
|
}
|
|
}
|
|
|
|
// FIXME: Would be good if this took the window as a param
|
|
- (void) drawResizeBarRect: (NSRect)resizeBarRect
|
|
{
|
|
GSDrawTiles *tiles;
|
|
float resizebarNotchWidth = [self resizebarNotchWidth];
|
|
|
|
tiles = [self tilesNamed: @"GSWindowResizeBar" state: GSThemeNormalState];
|
|
if (tiles == nil)
|
|
{
|
|
[[NSColor lightGrayColor] set];
|
|
PSrectfill(1.0, 1.0, resizeBarRect.size.width - 2.0, RESIZE_HEIGHT - 3.0);
|
|
|
|
PSsetlinewidth(1.0);
|
|
|
|
[[NSColor blackColor] set];
|
|
PSmoveto(0.0, 0.5);
|
|
PSlineto(resizeBarRect.size.width, 0.5);
|
|
PSstroke();
|
|
|
|
[[NSColor darkGrayColor] set];
|
|
PSmoveto(1.0, RESIZE_HEIGHT - 0.5);
|
|
PSlineto(resizeBarRect.size.width - 1.0, RESIZE_HEIGHT - 0.5);
|
|
PSstroke();
|
|
|
|
[[NSColor whiteColor] set];
|
|
PSmoveto(1.0, RESIZE_HEIGHT - 1.5);
|
|
PSlineto(resizeBarRect.size.width - 1.0, RESIZE_HEIGHT - 1.5);
|
|
PSstroke();
|
|
|
|
|
|
/* Only draw the notches if there's enough space. */
|
|
if (resizeBarRect.size.width < resizebarNotchWidth * 2)
|
|
return;
|
|
|
|
[[NSColor darkGrayColor] set];
|
|
PSmoveto(resizebarNotchWidth - 3 + 0.5, 1.0);
|
|
PSlineto(resizebarNotchWidth - 3 + 0.5, RESIZE_HEIGHT - 2.0);
|
|
PSmoveto(resizeBarRect.size.width - (resizebarNotchWidth - 2 + 0.5), 1.0);
|
|
PSlineto(resizeBarRect.size.width - (resizebarNotchWidth - 2 + 0.5), RESIZE_HEIGHT - 2.0);
|
|
PSstroke();
|
|
|
|
[[NSColor whiteColor] set];
|
|
PSmoveto(resizebarNotchWidth - 2 + 0.5, 1.0);
|
|
PSlineto(resizebarNotchWidth - 2 + 0.5, RESIZE_HEIGHT - 2.0);
|
|
PSmoveto(resizeBarRect.size.width - (resizebarNotchWidth - 3 + 0.5), 1.0);
|
|
PSlineto(resizeBarRect.size.width - (resizebarNotchWidth - 3 + 0.5), RESIZE_HEIGHT - 2.0);
|
|
PSstroke();
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: resizeBarRect
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (void) drawWindowBorder: (NSRect)rect
|
|
withFrame: (NSRect)frame
|
|
forStyleMask: (unsigned int)styleMask
|
|
state: (int)inputState
|
|
andTitle: (NSString*)title
|
|
{
|
|
if (styleMask & (NSTitledWindowMask | NSClosableWindowMask
|
|
| NSMiniaturizableWindowMask))
|
|
{
|
|
NSRect titleBarRect;
|
|
|
|
titleBarRect = NSMakeRect(0.0, frame.size.height - TITLE_HEIGHT,
|
|
frame.size.width, TITLE_HEIGHT);
|
|
if (NSIntersectsRect(rect, titleBarRect))
|
|
[self drawTitleBarRect: titleBarRect
|
|
forStyleMask: styleMask
|
|
state: inputState
|
|
andTitle: title];
|
|
}
|
|
|
|
if (styleMask & NSResizableWindowMask)
|
|
{
|
|
NSRect resizeBarRect;
|
|
|
|
resizeBarRect = NSMakeRect(0.0, 0.0, frame.size.width, RESIZE_HEIGHT);
|
|
if (NSIntersectsRect(rect, resizeBarRect))
|
|
[self drawResizeBarRect: resizeBarRect];
|
|
}
|
|
|
|
if (styleMask & (NSTitledWindowMask | NSClosableWindowMask
|
|
| NSMiniaturizableWindowMask | NSResizableWindowMask))
|
|
{
|
|
NSColor *borderColor = [self colorNamed: @"windowBorderColor"
|
|
state: GSThemeNormalState];
|
|
if (nil == borderColor)
|
|
{
|
|
borderColor = [NSColor blackColor];
|
|
}
|
|
[borderColor set];
|
|
PSsetlinewidth(1.0);
|
|
if (NSMinX(rect) < 1.0)
|
|
{
|
|
PSmoveto(0.5, 0.0);
|
|
PSlineto(0.5, frame.size.height);
|
|
PSstroke();
|
|
}
|
|
if (NSMaxX(rect) > frame.size.width - 1.0)
|
|
{
|
|
PSmoveto(frame.size.width - 0.5, 0.0);
|
|
PSlineto(frame.size.width - 0.5, frame.size.height);
|
|
PSstroke();
|
|
}
|
|
if (NSMaxY(rect) > frame.size.height - 1.0)
|
|
{
|
|
PSmoveto(0.0, frame.size.height - 0.5);
|
|
PSlineto(frame.size.width, frame.size.height - 0.5);
|
|
PSstroke();
|
|
}
|
|
if (NSMinY(rect) < 1.0)
|
|
{
|
|
PSmoveto(0.0, 0.5);
|
|
PSlineto(frame.size.width, 0.5);
|
|
PSstroke();
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) setFrameForCloseButton: (NSButton *)closeButton
|
|
viewSize: (NSSize)viewSize
|
|
{
|
|
NSSize buttonSize = [[closeButton image] size];
|
|
buttonSize = NSMakeSize(buttonSize.width + 3, buttonSize.height + 3);
|
|
|
|
[closeButton setFrame: NSMakeRect(viewSize.width - buttonSize.width - 4,
|
|
(viewSize.height - buttonSize.height) / 2,
|
|
buttonSize.width,
|
|
buttonSize.height)];
|
|
}
|
|
|
|
- (NSRect) closeButtonFrameForBounds: (NSRect)bounds
|
|
{
|
|
GSTheme *theme = [GSTheme theme];
|
|
|
|
return NSMakeRect(bounds.size.width - [theme titlebarButtonSize] -
|
|
[theme titlebarPaddingRight], bounds.size.height -
|
|
[theme titlebarButtonSize] - [theme titlebarPaddingTop],
|
|
[theme titlebarButtonSize], [theme titlebarButtonSize]);
|
|
}
|
|
|
|
- (NSRect) miniaturizeButtonFrameForBounds: (NSRect)bounds
|
|
{
|
|
GSTheme *theme = [GSTheme theme];
|
|
|
|
return NSMakeRect([theme titlebarPaddingLeft],
|
|
bounds.size.height - [theme titlebarButtonSize] - [theme titlebarPaddingTop],
|
|
[theme titlebarButtonSize],
|
|
[theme titlebarButtonSize]);
|
|
}
|
|
|
|
- (NSColor *) browserHeaderTextColor
|
|
{
|
|
NSColor *color;
|
|
|
|
color = [self colorNamed: @"browserHeaderTextColor"
|
|
state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor windowFrameTextColor];
|
|
}
|
|
return color;
|
|
}
|
|
|
|
- (void) drawBrowserHeaderCell: (NSTableHeaderCell*)cell
|
|
withFrame: (NSRect)rect
|
|
inView: (NSView*)view;
|
|
{
|
|
GSDrawTiles *tiles;
|
|
tiles = [self tilesNamed: GSBrowserHeader state: GSThemeNormalState];
|
|
if (tiles == nil)
|
|
{
|
|
[self drawGrayBezel: rect withClip: NSZeroRect];
|
|
[cell _drawBackgroundWithFrame: rect inView: view];
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: rect
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (NSRect) browserHeaderDrawingRectForCell: (NSTableHeaderCell*)cell
|
|
withFrame: (NSRect)rect
|
|
{
|
|
GSDrawTiles *tiles;
|
|
tiles = [self tilesNamed: GSBrowserHeader state: GSThemeNormalState];
|
|
if (tiles == nil)
|
|
{
|
|
return NSInsetRect(rect, 2, 2);
|
|
}
|
|
else
|
|
{
|
|
const BOOL flipped = [[cell controlView] isFlipped];
|
|
NSRect result = [tiles contentRectForRect: rect
|
|
isFlipped: flipped];
|
|
return result;
|
|
}
|
|
}
|
|
|
|
- (NSImage *)imageForTabPart: (GSTabPart)part type: (NSTabViewType)type
|
|
{
|
|
NSMutableString *imageName = [NSMutableString stringWithCapacity: 32];
|
|
NSString *typeString = nil;
|
|
NSString *partString = nil;
|
|
|
|
switch (type)
|
|
{
|
|
case NSTopTabsBezelBorder:
|
|
typeString = @"";
|
|
break;
|
|
case NSBottomTabsBezelBorder:
|
|
typeString = @"Down";
|
|
break;
|
|
case NSLeftTabsBezelBorder:
|
|
typeString = @"Left";
|
|
break;
|
|
case NSRightTabsBezelBorder:
|
|
typeString = @"Right";
|
|
break;
|
|
default:
|
|
return nil;
|
|
}
|
|
|
|
switch (part)
|
|
{
|
|
case GSTabSelectedLeft:
|
|
partString = @"SelectedLeft";
|
|
break;
|
|
case GSTabSelectedRight:
|
|
partString = @"SelectedRight";
|
|
break;
|
|
case GSTabSelectedToUnSelectedJunction:
|
|
partString = @"SelectedToUnSelectedJunction";
|
|
break;
|
|
case GSTabSelectedFill:
|
|
return nil;
|
|
case GSTabUnSelectedLeft:
|
|
partString = @"UnSelectedLeft";
|
|
break;
|
|
case GSTabUnSelectedRight:
|
|
partString = @"UnSelectedRight";
|
|
break;
|
|
case GSTabUnSelectedToSelectedJunction:
|
|
partString = @"UnSelectedToSelectedJunction";
|
|
break;
|
|
case GSTabUnSelectedJunction:
|
|
partString = @"UnSelectedJunction";
|
|
break;
|
|
case GSTabUnSelectedFill:
|
|
case GSTabBackgroundFill:
|
|
return nil;
|
|
}
|
|
|
|
[imageName appendString: @"common_Tab"];
|
|
[imageName appendString: typeString];
|
|
[imageName appendString: partString];
|
|
|
|
return [NSImage imageNamed: imageName];
|
|
}
|
|
|
|
- (GSDrawTiles *)tilesForTabPart: (GSTabPart)part type: (NSTabViewType)type
|
|
{
|
|
NSString *name = nil;
|
|
|
|
if (type == NSTopTabsBezelBorder)
|
|
{
|
|
if (part == GSTabSelectedFill)
|
|
name = GSTabViewSelectedTabFill;
|
|
else if (part == GSTabUnSelectedFill)
|
|
name = GSTabViewUnSelectedTabFill;
|
|
else if (part == GSTabBackgroundFill)
|
|
name = GSTabViewBackgroundTabFill;
|
|
}
|
|
else if (type == NSBottomTabsBezelBorder)
|
|
{
|
|
if (part == GSTabSelectedFill)
|
|
name = GSTabViewBottomSelectedTabFill;
|
|
else if (part == GSTabUnSelectedFill)
|
|
name = GSTabViewBottomUnSelectedTabFill;
|
|
else if (part == GSTabBackgroundFill)
|
|
name = GSTabViewBottomBackgroundTabFill;
|
|
}
|
|
else if (type == NSLeftTabsBezelBorder)
|
|
{
|
|
if (part == GSTabSelectedFill)
|
|
name = GSTabViewLeftSelectedTabFill;
|
|
else if (part == GSTabUnSelectedFill)
|
|
name = GSTabViewLeftUnSelectedTabFill;
|
|
else if (part == GSTabBackgroundFill)
|
|
name = GSTabViewLeftBackgroundTabFill;
|
|
}
|
|
else if (type == NSRightTabsBezelBorder)
|
|
{
|
|
if (part == GSTabSelectedFill)
|
|
name = GSTabViewRightSelectedTabFill;
|
|
else if (part == GSTabUnSelectedFill)
|
|
name = GSTabViewRightUnSelectedTabFill;
|
|
else if (part == GSTabBackgroundFill)
|
|
name = GSTabViewRightBackgroundTabFill;
|
|
}
|
|
|
|
return [self tilesNamed: name state: GSThemeNormalState];
|
|
}
|
|
|
|
- (void) frameTabRectTopAndBottom: (NSRect)aRect
|
|
topColor: (NSColor *)topColor
|
|
bottomColor: (NSColor *)bottomColor
|
|
{
|
|
NSRect bottom = aRect;
|
|
NSRect top = aRect;
|
|
|
|
top.size.height = 1;
|
|
bottom.origin.y = NSMaxY(aRect) - 1;
|
|
bottom.size.height = 1;
|
|
|
|
[topColor set];
|
|
NSRectFill(top);
|
|
|
|
[bottomColor set];
|
|
NSRectFill(bottom);
|
|
}
|
|
|
|
- (void) drawTabFillInRect: (NSRect)aRect forPart: (GSTabPart)part type: (NSTabViewType)type
|
|
{
|
|
GSDrawTiles *tiles = [self tilesForTabPart: part type: type];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
if (type == NSBottomTabsBezelBorder)
|
|
{
|
|
switch (part)
|
|
{
|
|
case GSTabSelectedFill:
|
|
[self frameTabRectTopAndBottom: aRect
|
|
topColor: [NSColor clearColor]
|
|
bottomColor: [NSColor whiteColor]];
|
|
break;
|
|
case GSTabUnSelectedFill:
|
|
[self frameTabRectTopAndBottom: aRect
|
|
topColor: [NSColor darkGrayColor]
|
|
bottomColor: [NSColor whiteColor]];
|
|
break;
|
|
case GSTabBackgroundFill:
|
|
{
|
|
const NSRect clip = aRect;
|
|
aRect.origin.x -= 2;
|
|
aRect.origin.y = NSMinY(aRect) - 2;
|
|
aRect.size.width += 2;
|
|
aRect.size.height = 4;
|
|
[self drawButton: aRect withClip: clip];
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if (type == NSTopTabsBezelBorder)
|
|
{
|
|
switch (part)
|
|
{
|
|
case GSTabSelectedFill:
|
|
[self frameTabRectTopAndBottom: aRect
|
|
topColor: [NSColor whiteColor]
|
|
bottomColor: [NSColor clearColor]];
|
|
break;
|
|
case GSTabUnSelectedFill:
|
|
[self frameTabRectTopAndBottom: aRect
|
|
topColor: [NSColor whiteColor]
|
|
bottomColor: [NSColor whiteColor]];
|
|
break;
|
|
case GSTabBackgroundFill:
|
|
{
|
|
const NSRect clip = aRect;
|
|
aRect.origin.x -= 2;
|
|
aRect.origin.y = NSMaxY(aRect) - 1;
|
|
aRect.size.width += 2;
|
|
aRect.size.height = 4;
|
|
[self drawButton: aRect withClip: clip];
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: aRect
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (CGFloat) tabHeightForType: (NSTabViewType)type
|
|
{
|
|
NSImage *img = [self imageForTabPart: GSTabUnSelectedLeft type: type];
|
|
if (img == nil)
|
|
{
|
|
return 0;
|
|
}
|
|
return [img size].height;
|
|
}
|
|
|
|
- (NSRect) tabViewBackgroundRectForBounds: (NSRect)aRect
|
|
tabViewType: (NSTabViewType)type
|
|
{
|
|
const CGFloat tabHeight = [self tabHeightForType: type];
|
|
|
|
switch (type)
|
|
{
|
|
default:
|
|
case NSTopTabsBezelBorder:
|
|
aRect.size.height -= tabHeight;
|
|
aRect.origin.y += tabHeight;
|
|
break;
|
|
|
|
case NSBottomTabsBezelBorder:
|
|
aRect.size.height -= tabHeight;
|
|
break;
|
|
|
|
case NSLeftTabsBezelBorder:
|
|
aRect.size.width -= tabHeight;
|
|
aRect.origin.x += tabHeight;
|
|
break;
|
|
|
|
case NSRightTabsBezelBorder:
|
|
aRect.size.width -= tabHeight;
|
|
break;
|
|
|
|
case NSNoTabsBezelBorder:
|
|
case NSNoTabsLineBorder:
|
|
case NSNoTabsNoBorder:
|
|
break;
|
|
}
|
|
|
|
return aRect;
|
|
}
|
|
|
|
|
|
- (NSRect) tabViewContentRectForBounds: (NSRect)aRect
|
|
tabViewType: (NSTabViewType)type
|
|
tabView: (NSTabView *)view
|
|
{
|
|
NSRect cRect = [self tabViewBackgroundRectForBounds: aRect
|
|
tabViewType: type];
|
|
NSString *name = GSStringFromTabViewType(type);
|
|
GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
switch (type)
|
|
{
|
|
case NSBottomTabsBezelBorder:
|
|
cRect.origin.x += 1;
|
|
cRect.origin.y += 1;
|
|
cRect.size.width -= 3;
|
|
cRect.size.height -= 2;
|
|
break;
|
|
case NSNoTabsBezelBorder:
|
|
cRect.origin.x += 1;
|
|
cRect.origin.y += 1;
|
|
cRect.size.width -= 3;
|
|
cRect.size.height -= 2;
|
|
break;
|
|
case NSNoTabsLineBorder:
|
|
cRect.origin.y += 1;
|
|
cRect.origin.x += 1;
|
|
cRect.size.width -= 2;
|
|
cRect.size.height -= 2;
|
|
break;
|
|
case NSTopTabsBezelBorder:
|
|
cRect.origin.x += 1;
|
|
cRect.origin.y += 1;
|
|
cRect.size.width -= 3;
|
|
cRect.size.height -= 2;
|
|
break;
|
|
case NSLeftTabsBezelBorder:
|
|
cRect.origin.x += 1;
|
|
cRect.origin.y += 1;
|
|
cRect.size.width -= 3;
|
|
cRect.size.height -= 2;
|
|
break;
|
|
case NSRightTabsBezelBorder:
|
|
cRect.origin.x += 1;
|
|
cRect.origin.y += 1;
|
|
cRect.size.width -= 3;
|
|
cRect.size.height -= 2;
|
|
break;
|
|
case NSNoTabsNoBorder:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cRect = [tiles contentRectForRect: cRect
|
|
isFlipped: [view isFlipped]];
|
|
}
|
|
return cRect;
|
|
}
|
|
|
|
|
|
- (void) drawTabViewBezelRect: (NSRect)aRect
|
|
tabViewType: (NSTabViewType)type
|
|
inView: (NSView *)view
|
|
{
|
|
NSString *name = GSStringFromTabViewType(type);
|
|
GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
switch (type)
|
|
{
|
|
default:
|
|
case NSTopTabsBezelBorder:
|
|
{
|
|
const NSRect clip = aRect;
|
|
aRect.size.height += 1;
|
|
aRect.origin.y -= 1;
|
|
[self drawButton: aRect withClip: clip];
|
|
break;
|
|
}
|
|
case NSBottomTabsBezelBorder:
|
|
{
|
|
const NSRect clip = aRect;
|
|
aRect.size.height += 2;
|
|
[self drawButton: aRect withClip: clip];
|
|
break;
|
|
}
|
|
case NSLeftTabsBezelBorder:
|
|
case NSRightTabsBezelBorder:
|
|
[self drawButton: aRect withClip: NSZeroRect];
|
|
break;
|
|
case NSNoTabsBezelBorder:
|
|
break;
|
|
case NSNoTabsLineBorder:
|
|
[[NSColor controlDarkShadowColor] set];
|
|
NSFrameRect(aRect);
|
|
break;
|
|
case NSNoTabsNoBorder:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: aRect
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (void) drawTabViewRect: (NSRect)rect
|
|
inView: (NSView *)view
|
|
withItems: (NSArray *)items
|
|
selectedItem: (NSTabViewItem *)selected
|
|
{
|
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
|
const NSUInteger howMany = [items count];
|
|
int i;
|
|
int previousState = 0;
|
|
const NSTabViewType type = [(NSTabView *)view tabViewType];
|
|
const NSRect bounds = [view bounds];
|
|
NSRect aRect = [self tabViewBackgroundRectForBounds: bounds tabViewType: type];
|
|
|
|
const BOOL truncate = [(NSTabView *)view allowsTruncatedLabels];
|
|
const CGFloat tabHeight = [self tabHeightForType: type];
|
|
|
|
DPSgsave(ctxt);
|
|
|
|
[self drawTabViewBezelRect: aRect
|
|
tabViewType: type
|
|
inView: view];
|
|
|
|
if (type == NSBottomTabsBezelBorder
|
|
|| type == NSTopTabsBezelBorder)
|
|
{
|
|
NSPoint iP;
|
|
if (type == NSTopTabsBezelBorder)
|
|
iP = bounds.origin;
|
|
else
|
|
iP = NSMakePoint(aRect.origin.x, NSMaxY(aRect));
|
|
|
|
for (i = 0; i < howMany; i++)
|
|
{
|
|
NSRect r;
|
|
NSTabViewItem *anItem = [items objectAtIndex: i];
|
|
const NSTabState itemState = [anItem tabState];
|
|
const NSSize s = [anItem sizeOfLabel: truncate];
|
|
|
|
// Draw the left image
|
|
|
|
if (i == 0)
|
|
{
|
|
NSImage *part = nil;
|
|
if (itemState == NSSelectedTab)
|
|
{
|
|
part = [self imageForTabPart: GSTabSelectedLeft type: type];
|
|
}
|
|
else if (itemState == NSBackgroundTab)
|
|
{
|
|
part = [self imageForTabPart: GSTabUnSelectedLeft type: type];
|
|
}
|
|
else
|
|
NSLog(@"Not finished yet. Luff ya.\n");
|
|
|
|
[part drawInRect: NSMakeRect(iP.x, iP.y, [part size].width, [part size].height)
|
|
fromRect: NSZeroRect
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1.0
|
|
respectFlipped: YES
|
|
hints: nil];
|
|
|
|
iP.x += [part size].width;
|
|
}
|
|
else
|
|
{
|
|
NSImage *part = nil;
|
|
if (itemState == NSSelectedTab)
|
|
{
|
|
part = [self imageForTabPart: GSTabUnSelectedToSelectedJunction type: type];
|
|
}
|
|
else if (itemState == NSBackgroundTab)
|
|
{
|
|
if (previousState == NSSelectedTab)
|
|
{
|
|
part = [self imageForTabPart: GSTabSelectedToUnSelectedJunction type: type];
|
|
}
|
|
else
|
|
{
|
|
part = [self imageForTabPart: GSTabUnSelectedJunction type: type];
|
|
}
|
|
}
|
|
else
|
|
NSLog(@"Not finished yet. Luff ya.\n");
|
|
|
|
[part drawInRect: NSMakeRect(iP.x, iP.y, [part size].width, [part size].height)
|
|
fromRect: NSZeroRect
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1.0
|
|
respectFlipped: YES
|
|
hints: nil];
|
|
|
|
iP.x += [part size].width;
|
|
}
|
|
|
|
// Draw the middle fill part of the tab
|
|
|
|
r.origin = iP;
|
|
r.size.width = s.width;
|
|
r.size.height = tabHeight;
|
|
|
|
if (itemState == NSSelectedTab)
|
|
{
|
|
[self drawTabFillInRect: r forPart: GSTabSelectedFill type: type];
|
|
}
|
|
else if (itemState == NSBackgroundTab)
|
|
{
|
|
[self drawTabFillInRect: r forPart: GSTabUnSelectedFill type: type];
|
|
}
|
|
else
|
|
NSLog(@"Not finished yet. Luff ya.\n");
|
|
|
|
// Label
|
|
[anItem drawLabel: truncate inRect: r];
|
|
|
|
iP.x += s.width;
|
|
previousState = itemState;
|
|
|
|
// For the rightmost tab, draw the right side
|
|
|
|
if (i == howMany - 1)
|
|
{
|
|
NSImage *part = nil;
|
|
if ([anItem tabState] == NSSelectedTab)
|
|
{
|
|
part = [self imageForTabPart: GSTabSelectedRight type: type];
|
|
}
|
|
else if ([anItem tabState] == NSBackgroundTab)
|
|
{
|
|
part = [self imageForTabPart: GSTabUnSelectedRight type: type];
|
|
}
|
|
else
|
|
NSLog(@"Not finished yet. Luff ya.\n");
|
|
|
|
[part drawInRect: NSMakeRect(iP.x, iP.y, [part size].width, [part size].height)
|
|
fromRect: NSZeroRect
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1.0
|
|
respectFlipped: YES
|
|
hints: nil];
|
|
|
|
iP.x += [part size].width;
|
|
|
|
// Draw the background fill
|
|
if (iP.x < NSMaxX(bounds))
|
|
{
|
|
r.origin = iP;
|
|
r.size.width = NSMaxX(bounds) - iP.x;
|
|
r.size.height = tabHeight;
|
|
|
|
[self drawTabFillInRect: r forPart: GSTabBackgroundFill type: type];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// FIXME: Missing drawing code for other cases
|
|
|
|
DPSgrestore(ctxt);
|
|
}
|
|
|
|
- (void) drawScrollerRect: (NSRect)rect
|
|
inView: (NSView *)view
|
|
hitPart: (NSScrollerPart)hitPart
|
|
isHorizontal: (BOOL)isHorizontal
|
|
{
|
|
NSRect rectForPartIncrementLine;
|
|
NSRect rectForPartDecrementLine;
|
|
NSRect rectForPartKnobSlot;
|
|
NSScroller *scroller = (NSScroller *)view;
|
|
|
|
rectForPartIncrementLine = [scroller rectForPart: NSScrollerIncrementLine];
|
|
rectForPartDecrementLine = [scroller rectForPart: NSScrollerDecrementLine];
|
|
rectForPartKnobSlot = [scroller rectForPart: NSScrollerKnobSlot];
|
|
|
|
/*
|
|
[[[view window] backgroundColor] set];
|
|
NSRectFill (rect);
|
|
*/
|
|
|
|
if (NSIntersectsRect (rect, rectForPartKnobSlot) == YES)
|
|
{
|
|
[scroller drawKnobSlot];
|
|
[scroller drawKnob];
|
|
}
|
|
|
|
if (NSIntersectsRect (rect, rectForPartDecrementLine) == YES)
|
|
{
|
|
[scroller drawArrow: NSScrollerDecrementArrow
|
|
highlight: hitPart == NSScrollerDecrementLine];
|
|
}
|
|
if (NSIntersectsRect (rect, rectForPartIncrementLine) == YES)
|
|
{
|
|
[scroller drawArrow: NSScrollerIncrementArrow
|
|
highlight: hitPart == NSScrollerIncrementLine];
|
|
}
|
|
}
|
|
|
|
- (void) drawBrowserRect: (NSRect)rect
|
|
inView: (NSView *)view
|
|
withScrollerRect: (NSRect)scrollerRect
|
|
columnSize: (NSSize)columnSize
|
|
{
|
|
NSBrowser *browser = (NSBrowser *)view;
|
|
NSRect bounds = [view bounds];
|
|
|
|
// Load the first column if not already done
|
|
if (![browser isLoaded])
|
|
{
|
|
[browser loadColumnZero];
|
|
}
|
|
|
|
// Draws titles
|
|
if ([browser isTitled])
|
|
{
|
|
int i;
|
|
|
|
for (i = [browser firstVisibleColumn];
|
|
i <= [browser lastVisibleColumn];
|
|
++i)
|
|
{
|
|
NSRect titleRect = [browser titleFrameOfColumn: i];
|
|
if (NSIntersectsRect (titleRect, rect) == YES)
|
|
{
|
|
[browser drawTitleOfColumn: i
|
|
inRect: titleRect];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draws scroller border
|
|
|
|
if ([self browserUseBezels])
|
|
{
|
|
if ([browser hasHorizontalScroller] &&
|
|
[browser separatesColumns])
|
|
{
|
|
NSRect scrollerBorderRect = scrollerRect;
|
|
NSSize bs = [self sizeForBorderType: NSBezelBorder];
|
|
|
|
scrollerBorderRect.origin.x = 0;
|
|
scrollerBorderRect.origin.y = 0;
|
|
scrollerBorderRect.size.width += 2 * bs.width;
|
|
scrollerBorderRect.size.height += (2 * bs.height) - 1;
|
|
|
|
if ((NSIntersectsRect (scrollerBorderRect, rect) == YES) && [view window])
|
|
{
|
|
[self drawGrayBezel: scrollerBorderRect withClip: rect];
|
|
}
|
|
}
|
|
|
|
if (![browser separatesColumns])
|
|
{
|
|
NSPoint p1,p2;
|
|
int i, visibleColumns;
|
|
float hScrollerWidth = [browser hasHorizontalScroller] ?
|
|
[NSScroller scrollerWidth] : 0;
|
|
|
|
// Columns borders
|
|
[self drawGrayBezel: bounds withClip: rect];
|
|
|
|
[[NSColor blackColor] set];
|
|
visibleColumns = [browser numberOfVisibleColumns];
|
|
for (i = 1; i < visibleColumns; i++)
|
|
{
|
|
p1 = NSMakePoint((columnSize.width * i) + 2 + (i-1),
|
|
columnSize.height + hScrollerWidth + 2);
|
|
p2 = NSMakePoint((columnSize.width * i) + 2 + (i-1),
|
|
hScrollerWidth + 2);
|
|
[NSBezierPath strokeLineFromPoint: p1 toPoint: p2];
|
|
}
|
|
|
|
// Horizontal scroller border
|
|
if ([browser hasHorizontalScroller])
|
|
{
|
|
p1 = NSMakePoint(2, hScrollerWidth + 2);
|
|
p2 = NSMakePoint(rect.size.width - 2, hScrollerWidth + 2);
|
|
[NSBezierPath strokeLineFromPoint: p1 toPoint: p2];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (![self browserUseBezels]
|
|
&& [self scrollViewScrollersOverlapBorders])
|
|
{
|
|
NSRect baseRect = NSMakeRect(0, 0, bounds.size.width, 1);
|
|
NSRect colFrame = [browser frameOfColumn: [browser firstVisibleColumn]];
|
|
NSRect scrollViewRect = NSUnionRect(baseRect, colFrame);
|
|
|
|
GSDrawTiles *tiles = [self tilesNamed: @"NSScrollView"
|
|
state: GSThemeNormalState];
|
|
|
|
[self fillRect: scrollViewRect
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
|
|
- (CGFloat) browserColumnSeparation
|
|
{
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
if ([defs objectForKey: @"GSBrowserColumnSeparation"] != nil)
|
|
{
|
|
return [defs floatForKey: @"GSBrowserColumnSeparation"];
|
|
}
|
|
else
|
|
{
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
- (CGFloat) browserVerticalPadding
|
|
{
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
if ([defs objectForKey: @"GSBrowserVerticalPadding"] != nil)
|
|
{
|
|
return [defs floatForKey: @"GSBrowserVerticalPadding"];
|
|
}
|
|
else
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
- (BOOL) browserUseBezels
|
|
{
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
if ([defs objectForKey: @"GSBrowserUseBezels"] != nil)
|
|
{
|
|
return [defs boolForKey: @"GSBrowserUseBezels"];
|
|
}
|
|
else
|
|
{
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
- (void) drawMenuRect: (NSRect)rect
|
|
inView: (NSView *)view
|
|
isHorizontal: (BOOL)horizontal
|
|
itemCells: (NSArray *)itemCells
|
|
{
|
|
int i = 0;
|
|
int howMany = [itemCells count];
|
|
NSMenuView *menuView = (NSMenuView *)view;
|
|
NSRect bounds = [view bounds];
|
|
|
|
[self drawBackgroundForMenuView: menuView
|
|
withFrame: bounds
|
|
dirtyRect: rect
|
|
horizontal: horizontal];
|
|
|
|
// Draw the menu cells.
|
|
for (i = 0; i < howMany; i++)
|
|
{
|
|
NSRect aRect;
|
|
NSMenuItemCell *aCell;
|
|
|
|
aRect = [menuView rectOfItemAtIndex: i];
|
|
if (NSIntersectsRect(rect, aRect) == YES)
|
|
{
|
|
aCell = [menuView menuItemCellForItemAtIndex: i];
|
|
[aCell drawWithFrame: aRect inView: menuView];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) drawScrollViewRect: (NSRect)rect
|
|
inView: (NSView *)view
|
|
{
|
|
NSScrollView *scrollView = (NSScrollView *)view;
|
|
GSTheme *theme = [GSTheme theme];
|
|
NSColor *color;
|
|
NSString *name;
|
|
NSBorderType borderType = [scrollView borderType];
|
|
NSRect bounds = [view bounds];
|
|
BOOL hasInnerBorder = ![[NSUserDefaults standardUserDefaults]
|
|
boolForKey: @"GSScrollViewNoInnerBorder"];
|
|
GSDrawTiles *tiles = nil;
|
|
|
|
name = [theme nameForElement: self];
|
|
if (name == nil)
|
|
{
|
|
name = @"NSScrollView";
|
|
}
|
|
color = [theme colorNamed: name state: GSThemeNormalState];
|
|
tiles = [theme tilesNamed: name state: GSThemeNormalState];
|
|
if (color == nil)
|
|
{
|
|
color = [NSColor controlDarkShadowColor];
|
|
}
|
|
|
|
if (tiles == nil)
|
|
{
|
|
switch (borderType)
|
|
{
|
|
case NSNoBorder:
|
|
break;
|
|
|
|
case NSLineBorder:
|
|
[color set];
|
|
NSFrameRect(bounds);
|
|
break;
|
|
|
|
case NSBezelBorder:
|
|
[theme drawGrayBezel: bounds withClip: rect];
|
|
break;
|
|
|
|
case NSGrooveBorder:
|
|
[theme drawGroove: bounds withClip: rect];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[self fillRect: bounds
|
|
withTiles: tiles];
|
|
}
|
|
|
|
if (hasInnerBorder)
|
|
{
|
|
NSScroller *vertScroller = [scrollView verticalScroller];
|
|
NSScroller *horizScroller = [scrollView horizontalScroller];
|
|
CGFloat scrollerWidth = [NSScroller scrollerWidth];
|
|
NSRect scrollerFrame;
|
|
|
|
[color set];
|
|
|
|
if ([scrollView hasVerticalScroller])
|
|
{
|
|
NSInterfaceStyle style;
|
|
CGFloat xpos;
|
|
|
|
scrollerFrame = [vertScroller frame];
|
|
|
|
style = NSInterfaceStyleForKey(@"NSScrollViewInterfaceStyle", nil);
|
|
if (style == NSMacintoshInterfaceStyle
|
|
|| style == NSWindows95InterfaceStyle)
|
|
{
|
|
xpos = scrollerFrame.origin.x - 1.0;
|
|
}
|
|
else
|
|
{
|
|
xpos = scrollerFrame.origin.x + scrollerWidth;
|
|
}
|
|
NSRectFill(NSMakeRect(xpos, scrollerFrame.origin.y,
|
|
1.0, scrollerFrame.size.height));
|
|
}
|
|
|
|
if ([scrollView hasHorizontalScroller])
|
|
{
|
|
CGFloat ypos;
|
|
|
|
scrollerFrame = [horizScroller frame];
|
|
|
|
if ([scrollView isFlipped])
|
|
{
|
|
ypos = scrollerFrame.origin.y - 1.0;
|
|
}
|
|
else
|
|
{
|
|
ypos = scrollerFrame.origin.y + scrollerWidth + 1.0;
|
|
}
|
|
NSRectFill(NSMakeRect([horizScroller frame].origin.x, ypos,
|
|
scrollerFrame.size.width, 1.0));
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) drawSliderBorderAndBackground: (NSBorderType)aType
|
|
frame: (NSRect)cellFrame
|
|
inCell: (NSCell *)cell
|
|
isHorizontal: (BOOL)horizontal
|
|
{
|
|
NSSliderType type = [(NSSliderCell *)cell sliderType];
|
|
if (type == NSLinearSlider)
|
|
{
|
|
NSString *partName = (horizontal ? GSSliderHorizontalTrack : GSSliderVerticalTrack);
|
|
GSDrawTiles *tiles = [self tilesNamed: partName
|
|
state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
[[GSTheme theme] drawBorderType: aType
|
|
frame: cellFrame
|
|
view: [cell controlView]];
|
|
}
|
|
else
|
|
{
|
|
// FIXME: This code could be factored out
|
|
NSSize tilesNaturalSize = [tiles size];
|
|
NSRect tilesRect;
|
|
|
|
// Only stretch the tiles in one direction
|
|
if (horizontal)
|
|
{
|
|
tilesRect.size = NSMakeSize(cellFrame.size.width, tilesNaturalSize.height);
|
|
}
|
|
else
|
|
{
|
|
tilesRect.size = NSMakeSize(tilesNaturalSize.width, cellFrame.size.height);
|
|
}
|
|
tilesRect.origin = NSMakePoint((cellFrame.size.width - tilesRect.size.width) / 2.0,
|
|
(cellFrame.size.height - tilesRect.size.height) / 2.0);
|
|
|
|
if ([cell controlView] != nil)
|
|
{
|
|
tilesRect = [[cell controlView] centerScanRect: tilesRect];
|
|
}
|
|
|
|
[self fillRect: tilesRect
|
|
withTiles: tiles];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) drawBarInside: (NSRect)rect
|
|
inCell: (NSCell *)cell
|
|
flipped: (BOOL)flipped
|
|
{
|
|
NSSliderType type = [(NSSliderCell *)cell sliderType];
|
|
if (type == NSLinearSlider)
|
|
{
|
|
BOOL horizontal = (rect.size.width > rect.size.height);
|
|
NSString *partName = (horizontal ? GSSliderHorizontalTrack : GSSliderVerticalTrack);
|
|
GSDrawTiles *tiles = [self tilesNamed: partName
|
|
state: GSThemeNormalState];
|
|
|
|
if (tiles == nil)
|
|
{
|
|
[[NSColor scrollBarColor] set];
|
|
NSRectFill(rect);
|
|
}
|
|
// Don't draw anything if we have tiles, they are drawn
|
|
// in -drawSliderBorderAndBackground:...
|
|
}
|
|
}
|
|
|
|
- (void) drawKnobInCell: (NSCell *)cell
|
|
{
|
|
NSView *controlView = [cell controlView];
|
|
NSSliderCell *sliderCell = (NSSliderCell *)cell;
|
|
|
|
[sliderCell drawKnob:
|
|
[sliderCell knobRectFlipped:
|
|
[controlView isFlipped]]];
|
|
}
|
|
|
|
- (NSRect) tableHeaderCellDrawingRectForBounds: (NSRect)theRect
|
|
{
|
|
NSSize borderSize;
|
|
|
|
// This adjustment must match the drawn border
|
|
borderSize = NSMakeSize(1, 1);
|
|
|
|
return NSInsetRect(theRect, borderSize.width, borderSize.height);
|
|
}
|
|
|
|
- (void)drawTableHeaderRect: (NSRect)aRect
|
|
inView: (NSView *)view
|
|
{
|
|
NSTableHeaderView *tableHeaderView = (NSTableHeaderView *)view;
|
|
NSTableView *tableView = [tableHeaderView tableView];
|
|
NSArray *columns;
|
|
int firstColumnToDraw;
|
|
int lastColumnToDraw;
|
|
NSRect drawingRect;
|
|
NSTableColumn *column;
|
|
NSTableColumn *highlightedTableColumn;
|
|
float width;
|
|
int i;
|
|
NSCell *cell;
|
|
|
|
if (tableView == nil)
|
|
return;
|
|
|
|
firstColumnToDraw = [tableHeaderView columnAtPoint: NSMakePoint (aRect.origin.x,
|
|
aRect.origin.y)];
|
|
if (firstColumnToDraw == -1)
|
|
firstColumnToDraw = 0;
|
|
|
|
lastColumnToDraw = [tableHeaderView columnAtPoint: NSMakePoint (NSMaxX (aRect),
|
|
aRect.origin.y)];
|
|
if (lastColumnToDraw == -1)
|
|
lastColumnToDraw = [tableView numberOfColumns] - 1;
|
|
|
|
drawingRect = [tableHeaderView headerRectOfColumn: firstColumnToDraw];
|
|
|
|
columns = [tableView tableColumns];
|
|
highlightedTableColumn = [tableView highlightedTableColumn];
|
|
|
|
for (i = firstColumnToDraw; i <= lastColumnToDraw; i++)
|
|
{
|
|
column = [columns objectAtIndex: i];
|
|
width = [column width];
|
|
drawingRect.size.width = width;
|
|
cell = [column headerCell];
|
|
if ((column == highlightedTableColumn)
|
|
|| [tableView isColumnSelected: i])
|
|
{
|
|
[cell setHighlighted: YES];
|
|
}
|
|
else
|
|
{
|
|
[cell setHighlighted: NO];
|
|
}
|
|
[cell drawWithFrame: drawingRect
|
|
inView: tableHeaderView];
|
|
drawingRect.origin.x += width;
|
|
}
|
|
}
|
|
|
|
- (void) drawPopUpButtonCellInteriorWithFrame: (NSRect)cellFrame
|
|
withCell: (NSCell *)cell
|
|
inView: (NSView *)controlView
|
|
{
|
|
// Default implementation of this method does nothing.
|
|
}
|
|
|
|
- (void) drawTableViewBackgroundInClipRect: (NSRect)aRect
|
|
inView: (NSView *)view
|
|
withBackgroundColor: (NSColor *)backgroundColor
|
|
{
|
|
NSTableView *tableView = (NSTableView *)view;
|
|
|
|
[backgroundColor set];
|
|
NSRectFill (aRect);
|
|
|
|
if ([tableView usesAlternatingRowBackgroundColors])
|
|
{
|
|
const CGFloat rowHeight = [tableView rowHeight];
|
|
NSInteger startingRow = [tableView rowAtPoint: NSMakePoint(0, NSMinY(aRect))];
|
|
NSInteger endingRow;
|
|
NSInteger i;
|
|
|
|
NSArray *rowColors = [NSColor controlAlternatingRowBackgroundColors];
|
|
const NSUInteger rowColorCount = [rowColors count];
|
|
|
|
NSRect rowRect;
|
|
|
|
if (rowHeight <= 0
|
|
|| rowColorCount == 0
|
|
|| aRect.size.height <= 0)
|
|
return;
|
|
|
|
if (startingRow <= 0)
|
|
startingRow = 0;
|
|
|
|
rowRect = [tableView rectOfRow: startingRow];
|
|
rowRect.origin.x = aRect.origin.x;
|
|
rowRect.size.width = aRect.size.width;
|
|
|
|
endingRow = startingRow + ceil(aRect.size.height / rowHeight);
|
|
|
|
for (i = startingRow; i <= endingRow; i++)
|
|
{
|
|
NSColor *color = [rowColors objectAtIndex: (i % rowColorCount)];
|
|
|
|
[color set];
|
|
NSRectFill(rowRect);
|
|
|
|
rowRect.origin.y += rowHeight;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) drawTableViewGridInClipRect: (NSRect)aRect
|
|
inView: (NSView *)view
|
|
{
|
|
NSTableView *tableView = (NSTableView *)view;
|
|
|
|
// Cache some constants
|
|
const CGFloat minX = NSMinX(aRect);
|
|
const CGFloat maxX = NSMaxX(aRect);
|
|
const CGFloat minY = NSMinY(aRect);
|
|
const CGFloat maxY = NSMaxY(aRect);
|
|
const NSInteger numberOfColumns = [tableView numberOfColumns];
|
|
const NSInteger numberOfRows = [tableView numberOfRows];
|
|
|
|
NSInteger startingRow = [tableView rowAtPoint: NSMakePoint(minX, minY)];
|
|
NSInteger endingRow = [tableView rowAtPoint: NSMakePoint(minX, maxY)];
|
|
NSInteger startingColumn = [tableView columnAtPoint: NSMakePoint(minX, minY)];
|
|
NSInteger endingColumn = [tableView columnAtPoint: NSMakePoint(maxX, minY)];
|
|
|
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
|
NSColor *gridColor = [tableView gridColor];
|
|
|
|
|
|
if (startingRow == -1)
|
|
startingRow = 0;
|
|
if (endingRow == -1)
|
|
endingRow = numberOfRows - 1;
|
|
|
|
if (startingColumn == -1)
|
|
startingColumn = 0;
|
|
if (endingColumn == -1)
|
|
endingColumn = numberOfColumns - 1;
|
|
|
|
|
|
DPSgsave(ctxt);
|
|
[gridColor set];
|
|
|
|
// Draw horizontal lines
|
|
if (numberOfRows > 0)
|
|
{
|
|
NSInteger i;
|
|
for (i = startingRow; i <= endingRow; i++)
|
|
{
|
|
NSRect rowRect = [tableView rectOfRow: i];
|
|
rowRect.origin.y += rowRect.size.height - 1;
|
|
rowRect.size.height = 1;
|
|
NSRectFill(rowRect);
|
|
}
|
|
}
|
|
|
|
// Draw vertical lines
|
|
if (numberOfColumns > 0)
|
|
{
|
|
NSInteger i;
|
|
for (i = startingColumn; i <= endingColumn; i++)
|
|
{
|
|
NSRect colRect = [tableView rectOfColumn: i];
|
|
colRect.origin.x += colRect.size.width - 1;
|
|
colRect.size.width = 1;
|
|
NSRectFill(colRect);
|
|
}
|
|
}
|
|
|
|
DPSgrestore (ctxt);
|
|
}
|
|
|
|
- (void) drawTableViewRect: (NSRect)aRect
|
|
inView: (NSView *)view
|
|
{
|
|
NSInteger startingRow;
|
|
NSInteger endingRow;
|
|
NSInteger i;
|
|
NSTableView *tableView = (NSTableView *)view;
|
|
NSInteger numberOfRows = [tableView numberOfRows];
|
|
NSInteger numberOfColumns = [tableView numberOfColumns];
|
|
BOOL drawsGrid = [tableView drawsGrid];
|
|
|
|
/* Draw background */
|
|
[tableView drawBackgroundInClipRect: aRect];
|
|
|
|
if ((numberOfRows == 0) || (numberOfColumns == 0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Draw selection */
|
|
[tableView highlightSelectionInClipRect: aRect];
|
|
|
|
/* Draw grid */
|
|
if (drawsGrid)
|
|
{
|
|
[tableView drawGridInClipRect: aRect];
|
|
}
|
|
|
|
/* Draw visible cells */
|
|
/* Using rowAtPoint: here calls them only twice per drawn rect */
|
|
startingRow = [tableView rowAtPoint: NSMakePoint (0, NSMinY (aRect))];
|
|
endingRow = [tableView rowAtPoint: NSMakePoint (0, NSMaxY (aRect))];
|
|
|
|
if (startingRow == -1)
|
|
{
|
|
startingRow = 0;
|
|
}
|
|
if (endingRow == -1)
|
|
{
|
|
endingRow = numberOfRows - 1;
|
|
}
|
|
// NSLog(@"drawRect : %d-%d", startingRow, endingRow);
|
|
{
|
|
SEL sel = @selector(drawRow:clipRect:);
|
|
void (*imp)(id, SEL, NSInteger, NSRect);
|
|
|
|
imp = (void (*)(id, SEL, NSInteger, NSRect))[tableView methodForSelector: sel];
|
|
|
|
for (i = startingRow; i <= endingRow; i++)
|
|
{
|
|
imp(tableView, sel, i, aRect);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) highlightTableViewSelectionInClipRect: (NSRect)clipRect
|
|
inView: (NSView *)view
|
|
selectingColumns: (BOOL)selectingColumns
|
|
{
|
|
NSTableView *tableView = (NSTableView *)view;
|
|
NSInteger numberOfRows = [tableView numberOfRows];
|
|
NSInteger numberOfColumns = [tableView numberOfColumns];
|
|
NSIndexSet *selectedRows = [tableView selectedRowIndexes];
|
|
NSIndexSet *selectedColumns = [tableView selectedColumnIndexes];
|
|
|
|
// Set the fill color
|
|
{
|
|
NSColor *selectionColor;
|
|
|
|
selectionColor = [self colorNamed: @"highlightedTableRowBackgroundColor"
|
|
state: GSThemeNormalState];
|
|
|
|
if (selectionColor == nil)
|
|
{
|
|
selectionColor = [NSColor colorWithCalibratedRed: 0.86
|
|
green: 0.92
|
|
blue: 0.99
|
|
alpha: 1.0];
|
|
}
|
|
[selectionColor set];
|
|
}
|
|
|
|
if (selectingColumns == NO)
|
|
{
|
|
NSInteger selectedRowsCount;
|
|
NSUInteger row;
|
|
NSInteger startingRow, endingRow;
|
|
|
|
selectedRowsCount = [selectedRows count];
|
|
if (selectedRowsCount == 0)
|
|
return;
|
|
|
|
/* highlight selected rows */
|
|
startingRow = [tableView rowAtPoint: NSMakePoint(0, NSMinY(clipRect))];
|
|
endingRow = [tableView rowAtPoint: NSMakePoint(0, NSMaxY(clipRect))];
|
|
|
|
if (startingRow == -1)
|
|
startingRow = 0;
|
|
if (endingRow == -1)
|
|
endingRow = numberOfRows - 1;
|
|
|
|
row = [selectedRows indexGreaterThanOrEqualToIndex: startingRow];
|
|
while ((row != NSNotFound) && (row <= endingRow))
|
|
{
|
|
NSRectFill(NSIntersectionRect([tableView rectOfRow: row], clipRect));
|
|
row = [selectedRows indexGreaterThanIndex: row];
|
|
}
|
|
}
|
|
else // Selecting columns
|
|
{
|
|
NSUInteger selectedColumnsCount;
|
|
NSUInteger column;
|
|
NSInteger startingColumn, endingColumn;
|
|
|
|
selectedColumnsCount = [selectedColumns count];
|
|
|
|
if (selectedColumnsCount == 0)
|
|
return;
|
|
|
|
/* highlight selected columns */
|
|
startingColumn = [tableView columnAtPoint: NSMakePoint(NSMinX(clipRect), 0)];
|
|
endingColumn = [tableView columnAtPoint: NSMakePoint(NSMaxX(clipRect), 0)];
|
|
|
|
if (startingColumn == -1)
|
|
startingColumn = 0;
|
|
if (endingColumn == -1)
|
|
endingColumn = numberOfColumns - 1;
|
|
|
|
column = [selectedColumns indexGreaterThanOrEqualToIndex: startingColumn];
|
|
while ((column != NSNotFound) && (column <= endingColumn))
|
|
{
|
|
NSRectFill(NSIntersectionRect([tableView rectOfColumn: column],
|
|
clipRect));
|
|
column = [selectedColumns indexGreaterThanIndex: column];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) _calculatedStartingColumn: (NSInteger *)startingColumn
|
|
endingColumn: (NSInteger *)endingColumn
|
|
withTableView: (NSTableView *)tableView
|
|
inClipRect: (NSRect)clipRect
|
|
|
|
{
|
|
CGFloat x_pos = 0.0;
|
|
NSInteger i = 0;
|
|
NSInteger numberOfColumns = [tableView numberOfColumns];
|
|
CGFloat *columnOrigins = [tableView _columnOrigins];
|
|
|
|
/* Using columnAtPoint: here would make it called twice per row per drawn
|
|
rect - so we avoid it and do it natively */
|
|
|
|
/* Determine starting column as fast as possible */
|
|
x_pos = NSMinX (clipRect);
|
|
i = 0;
|
|
while ((i < numberOfColumns) && (x_pos > columnOrigins[i]))
|
|
{
|
|
i++;
|
|
}
|
|
*startingColumn = (i - 1);
|
|
|
|
if (*startingColumn == -1)
|
|
*startingColumn = 0;
|
|
|
|
/* Determine ending column as fast as possible */
|
|
x_pos = NSMaxX (clipRect);
|
|
// Nota Bene: we do *not* reset i
|
|
while ((i < numberOfColumns) && (x_pos > columnOrigins[i]))
|
|
{
|
|
i++;
|
|
}
|
|
*endingColumn = (i - 1);
|
|
|
|
if (*endingColumn == -1)
|
|
*endingColumn = numberOfColumns - 1;
|
|
}
|
|
|
|
- (void) drawTableViewRow: (NSInteger)rowIndex
|
|
clipRect: (NSRect)clipRect
|
|
inView: (NSTableView *)tableView
|
|
{
|
|
NSInteger editedRow = [tableView editedRow];
|
|
NSInteger editedColumn = [tableView editedColumn];
|
|
NSArray *tableColumns = [tableView tableColumns];
|
|
NSInteger startingColumn;
|
|
NSInteger endingColumn;
|
|
NSTableColumn *tb;
|
|
NSRect drawingRect;
|
|
NSCell *cell;
|
|
NSInteger i;
|
|
const BOOL rowSelected = [[tableView selectedRowIndexes] containsIndex: rowIndex];
|
|
NSColor *tempColor = nil;
|
|
NSColor *selectedTextColor = [self colorNamed: @"highlightedTableRowTextColor"
|
|
state: GSThemeNormalState];
|
|
|
|
[self _calculatedStartingColumn: &startingColumn
|
|
endingColumn: &endingColumn
|
|
withTableView: tableView
|
|
inClipRect: clipRect];
|
|
|
|
/* Draw the row between startingColumn and endingColumn */
|
|
for (i = startingColumn; i <= endingColumn; i++)
|
|
{
|
|
const BOOL columnSelected = [tableView isColumnSelected: i];
|
|
const BOOL cellSelected = (rowSelected || columnSelected);
|
|
tb = [tableColumns objectAtIndex: i];
|
|
cell = [tb dataCellForRow: rowIndex];
|
|
[tableView _willDisplayCell: cell
|
|
forTableColumn: tb
|
|
row: rowIndex];
|
|
if (i == editedColumn && rowIndex == editedRow)
|
|
{
|
|
[cell _setInEditing: YES];
|
|
}
|
|
else
|
|
{
|
|
[cell setObjectValue: [tableView _objectValueForTableColumn: tb
|
|
row: rowIndex]];
|
|
}
|
|
drawingRect = [tableView frameOfCellAtColumn: i
|
|
row: rowIndex];
|
|
|
|
// Set the cell text color if the theme provides a custom highlighted
|
|
// row color.
|
|
//
|
|
// FIXME: This could probably be done in a cleaner way. We should
|
|
// probably do -setHighlighted: YES, and the implementation of
|
|
// -textColor in NSCell could use that to return a highlighted text color.
|
|
if (cellSelected && (selectedTextColor != nil)
|
|
&& [cell isKindOfClass: [NSTextFieldCell class]])
|
|
{
|
|
tempColor = [cell textColor];
|
|
[(NSTextFieldCell *)cell setTextColor: selectedTextColor];
|
|
}
|
|
|
|
[cell drawWithFrame: drawingRect inView: tableView];
|
|
|
|
if (cellSelected && (selectedTextColor != nil)
|
|
&& [cell isKindOfClass: [NSTextFieldCell class]])
|
|
{
|
|
// Restore the cell's text color if we changed it
|
|
[(NSTextFieldCell *)cell setTextColor: tempColor];
|
|
}
|
|
|
|
if (i == editedColumn && rowIndex == editedRow)
|
|
[cell _setInEditing: NO];
|
|
}
|
|
}
|
|
|
|
- (NSRect) _drawOutlineTableColumn: (NSTableColumn *)tb
|
|
outlineView: (NSOutlineView *)outlineView
|
|
item: (id)item
|
|
drawingRect: (NSRect)inputRect
|
|
rowIndex: (NSInteger)rowIndex
|
|
{
|
|
NSRect drawingRect = inputRect;
|
|
NSImage *image = nil;
|
|
NSInteger level = 0;
|
|
CGFloat indentationFactor = 0.0;
|
|
CGFloat indentationPerLevel = [outlineView indentationPerLevel];
|
|
NSCell *imageCell = nil;
|
|
NSRect imageRect;
|
|
id delegate = [outlineView delegate];
|
|
|
|
// display the correct arrow...
|
|
if ([outlineView isItemExpanded: item])
|
|
{
|
|
image = [NSImage imageNamed: @"common_ArrowDownH"];
|
|
}
|
|
else
|
|
{
|
|
image = [NSImage imageNamed: @"common_ArrowRightH"];
|
|
}
|
|
|
|
if (![outlineView isExpandable: item])
|
|
{
|
|
image = AUTORELEASE([[NSImage alloc] initWithSize: NSMakeSize(14.0,14.0)]);
|
|
}
|
|
|
|
level = [outlineView levelForItem: item];
|
|
indentationFactor = indentationPerLevel * level;
|
|
imageCell = [[NSCell alloc] initImageCell: image];
|
|
imageRect = [outlineView frameOfOutlineCellAtRow: rowIndex];
|
|
|
|
if ([delegate respondsToSelector: @selector(outlineView:willDisplayOutlineCell:forTableColumn:item:)])
|
|
{
|
|
[delegate outlineView: outlineView
|
|
willDisplayOutlineCell: imageCell
|
|
forTableColumn: tb
|
|
item: item];
|
|
}
|
|
|
|
/* Do not indent if the delegate set the image to nil. */
|
|
if ([imageCell image])
|
|
{
|
|
imageRect.size.width = [image size].width;
|
|
imageRect.size.height = [image size].height + 5;
|
|
[imageCell drawWithFrame: imageRect inView: outlineView];
|
|
drawingRect.origin.x
|
|
+= indentationFactor + imageRect.size.width + 5;
|
|
drawingRect.size.width
|
|
-= indentationFactor + imageRect.size.width + 5;
|
|
}
|
|
else
|
|
{
|
|
drawingRect.origin.x += indentationFactor;
|
|
drawingRect.size.width -= indentationFactor;
|
|
}
|
|
|
|
RELEASE(imageCell);
|
|
|
|
return drawingRect;
|
|
}
|
|
|
|
- (void) drawOutlineViewRow: (NSInteger)rowIndex
|
|
clipRect: (NSRect)clipRect
|
|
inView: (NSOutlineView *)outlineView
|
|
{
|
|
NSInteger editedRow = [outlineView editedRow];
|
|
NSInteger editedColumn = [outlineView editedColumn];
|
|
NSArray *tableColumns = [outlineView tableColumns];
|
|
NSInteger numberOfRows = [outlineView numberOfRows];
|
|
NSInteger startingColumn;
|
|
NSInteger endingColumn;
|
|
NSRect drawingRect;
|
|
NSInteger i;
|
|
id dataSource = [outlineView dataSource];
|
|
NSTableColumn *outlineTableColumn = [outlineView outlineTableColumn];
|
|
|
|
if (dataSource == nil)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Using columnAtPoint: here would make it called twice per row per drawn
|
|
rect - so we avoid it and do it natively */
|
|
|
|
if (rowIndex >= numberOfRows)
|
|
{
|
|
return;
|
|
}
|
|
|
|
[self _calculatedStartingColumn: &startingColumn
|
|
endingColumn: &endingColumn
|
|
withTableView: outlineView
|
|
inClipRect: clipRect];
|
|
|
|
/* Draw the row between startingColumn and endingColumn */
|
|
for (i = startingColumn; i <= endingColumn; i++)
|
|
{
|
|
id item = [outlineView itemAtRow: rowIndex];
|
|
NSTableColumn *tb = [tableColumns objectAtIndex: i];
|
|
NSCell *cell = [outlineView preparedCellAtColumn: i row: rowIndex];
|
|
|
|
[outlineView _willDisplayCell: cell
|
|
forTableColumn: tb
|
|
row: rowIndex];
|
|
if (i == editedColumn && rowIndex == editedRow)
|
|
{
|
|
[cell _setInEditing: YES];
|
|
[cell setShowsFirstResponder: YES];
|
|
}
|
|
else
|
|
{
|
|
[cell setObjectValue: [dataSource outlineView: outlineView
|
|
objectValueForTableColumn: tb
|
|
byItem: item]];
|
|
}
|
|
|
|
drawingRect = [outlineView frameOfCellAtColumn: i
|
|
row: rowIndex];
|
|
|
|
if (tb == outlineTableColumn)
|
|
{
|
|
drawingRect = [self _drawOutlineTableColumn: tb
|
|
outlineView: outlineView
|
|
item: item
|
|
drawingRect: drawingRect
|
|
rowIndex: rowIndex];
|
|
}
|
|
|
|
[cell drawWithFrame: drawingRect inView: outlineView];
|
|
if (i == editedColumn && rowIndex == editedRow)
|
|
{
|
|
[cell _setInEditing: NO];
|
|
[cell setShowsFirstResponder: NO];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (id) _prototypeCellViewFromTableColumn: (NSTableColumn *)tb
|
|
{
|
|
NSArray *protoCellViews = [tb _prototypeCellViews];
|
|
id view = nil;
|
|
|
|
// it seems there is always one prototype...
|
|
if ([protoCellViews count] > 0)
|
|
{
|
|
view = [protoCellViews objectAtIndex: 0];
|
|
view = [view copy]; // instantiate the prototype...
|
|
}
|
|
|
|
return view;
|
|
}
|
|
|
|
- (void) drawCellViewRow: (NSInteger)rowIndex
|
|
clipRect: (NSRect)clipRect
|
|
inView: (NSTableView *)v
|
|
{
|
|
NSArray *tableColumns = [v tableColumns];
|
|
NSInteger numberOfRows = [v numberOfRows];
|
|
NSInteger startingColumn;
|
|
NSInteger endingColumn;
|
|
NSInteger i;
|
|
id dataSource = [v dataSource];
|
|
id delegate = [v delegate];
|
|
BOOL hasMethod = NO;
|
|
NSTableColumn *outlineTableColumn = nil;
|
|
NSOutlineView *ov = nil;
|
|
|
|
// If we have no data source, there is nothing to do...
|
|
if (dataSource == nil)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If the rowIndex is greater than the numberOfRows, done...
|
|
if (rowIndex >= numberOfRows)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Check the delegate method...
|
|
hasMethod = [delegate respondsToSelector: @selector(outlineView:viewForTableColumn:item:)];
|
|
if (hasMethod)
|
|
{
|
|
ov = (NSOutlineView *)v;
|
|
outlineTableColumn = [ov outlineTableColumn];
|
|
}
|
|
else
|
|
{
|
|
hasMethod = [delegate respondsToSelector: @selector(tableView:viewForTableColumn:row:)];
|
|
}
|
|
|
|
[self _calculatedStartingColumn: &startingColumn
|
|
endingColumn: &endingColumn
|
|
withTableView: v
|
|
inClipRect: clipRect];
|
|
|
|
/* Draw the row between startingColumn and endingColumn */
|
|
for (i = startingColumn; i <= endingColumn; i++)
|
|
{
|
|
NSRect drawingRect = [v frameOfCellAtColumn: i
|
|
row: rowIndex];
|
|
NSTableColumn *tb = [tableColumns objectAtIndex: i];
|
|
NSIndexPath *path = [NSIndexPath indexPathForItem: i
|
|
inSection: rowIndex];
|
|
NSView *view = [v _renderedViewForPath: path];
|
|
|
|
if (ov != nil)
|
|
{
|
|
id item = [ov itemAtRow: rowIndex];
|
|
|
|
if (tb == outlineTableColumn)
|
|
{
|
|
drawingRect = [self _drawOutlineTableColumn: tb
|
|
outlineView: ov
|
|
item: item
|
|
drawingRect: drawingRect
|
|
rowIndex: rowIndex];
|
|
}
|
|
|
|
if (view == nil)
|
|
{
|
|
if (hasMethod)
|
|
{
|
|
view = [delegate outlineView: ov
|
|
viewForTableColumn: tb
|
|
item: item];
|
|
}
|
|
else
|
|
{
|
|
view = [self _prototypeCellViewFromTableColumn: tb];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If the view has been stored use it, if not
|
|
// then grab it.
|
|
if (view == nil)
|
|
{
|
|
if (hasMethod)
|
|
{
|
|
view = [delegate tableView: v
|
|
viewForTableColumn: tb
|
|
row: rowIndex];
|
|
}
|
|
else
|
|
{
|
|
view = [self _prototypeCellViewFromTableColumn: tb];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Store the object...
|
|
[v _setRenderedView: view forPath: path];
|
|
[v addSubview: view];
|
|
|
|
// Place the view...
|
|
[view setFrame: drawingRect];
|
|
}
|
|
}
|
|
|
|
- (BOOL) isBoxOpaque: (NSBox *)box
|
|
{
|
|
if ([box boxType] == NSBoxCustom)
|
|
{
|
|
return ![box isTransparent];
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (void) drawBoxInClipRect: (NSRect)clipRect
|
|
boxType: (NSBoxType)boxType
|
|
borderType: (NSBorderType)borderType
|
|
inView: (NSBox *)box
|
|
{
|
|
NSColor *color;
|
|
BOOL drawTitleBackground = YES;
|
|
|
|
if (boxType == NSBoxCustom)
|
|
{
|
|
if (![box isOpaque])
|
|
{
|
|
color = [NSColor clearColor];
|
|
}
|
|
else
|
|
{
|
|
color = [box fillColor];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
color = [[box window] backgroundColor];
|
|
}
|
|
|
|
// Draw separator boxes
|
|
|
|
if (boxType == NSBoxSeparator)
|
|
{
|
|
color = [box borderColor];
|
|
if (!color || [color isEqual:[NSColor clearColor]])
|
|
{
|
|
color = [NSColor controlShadowColor];
|
|
}
|
|
[color set];
|
|
NSRectFill([box borderRect]);
|
|
return;
|
|
}
|
|
|
|
// Draw border
|
|
|
|
GSDrawTiles *tiles = [[GSTheme theme] tilesNamed: GSBoxBorder state: GSThemeNormalState];
|
|
if (tiles == nil
|
|
|| borderType == NSNoBorder
|
|
|| boxType == NSBoxOldStyle
|
|
|| boxType == NSBoxCustom)
|
|
{
|
|
// Fill inside
|
|
[color set];
|
|
NSRectFill(clipRect);
|
|
|
|
switch (borderType)
|
|
{
|
|
case NSNoBorder:
|
|
break;
|
|
case NSLineBorder:
|
|
if (boxType == NSBoxCustom)
|
|
{
|
|
[[box borderColor] set];
|
|
NSFrameRectWithWidth([box borderRect], [box borderWidth]);
|
|
}
|
|
else
|
|
{
|
|
[[NSColor controlDarkShadowColor] set];
|
|
NSFrameRect([box borderRect]);
|
|
}
|
|
break;
|
|
case NSBezelBorder:
|
|
[[GSTheme theme] drawDarkBezel: [box borderRect] withClip: clipRect];
|
|
break;
|
|
case NSGrooveBorder:
|
|
[[GSTheme theme] drawGroove: [box borderRect] withClip: clipRect];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
drawTitleBackground = NO;
|
|
|
|
// If the title is on the border, clip a hole in the later
|
|
|
|
[NSGraphicsContext saveGraphicsState];
|
|
|
|
if ((borderType != NSNoBorder)
|
|
&& (([box titlePosition] == NSAtTop) || ([box titlePosition] == NSAtBottom)))
|
|
{
|
|
const NSRect borderRect = [box borderRect];
|
|
const NSRect titleRect = [box titleRect];
|
|
NSBezierPath *path = [NSBezierPath bezierPath];
|
|
|
|
// Left
|
|
if (NSMinX(titleRect) > NSMinX(borderRect))
|
|
{
|
|
NSRect left = borderRect;
|
|
left.size.width = NSMinX(titleRect) - NSMinX(borderRect);
|
|
[path appendBezierPathWithRect: left];
|
|
}
|
|
|
|
// Right
|
|
if (NSMaxX(borderRect) > NSMaxX(titleRect))
|
|
{
|
|
NSRect right = borderRect;
|
|
right.size.width = NSMaxX(borderRect) - NSMaxX(titleRect);
|
|
right.origin.x = NSMaxX(titleRect);
|
|
[path appendBezierPathWithRect: right];
|
|
}
|
|
|
|
// MinY
|
|
if (NSMinY(titleRect) > NSMinY(borderRect))
|
|
{
|
|
NSRect minY = borderRect;
|
|
minY.size.height = NSMinY(titleRect) - NSMinY(borderRect);
|
|
[path appendBezierPathWithRect: minY];
|
|
}
|
|
|
|
// MaxY
|
|
if (NSMaxY(borderRect) > NSMaxY(titleRect))
|
|
{
|
|
NSRect maxY = borderRect;
|
|
maxY.size.height = NSMaxY(borderRect) - NSMaxY(titleRect);
|
|
maxY.origin.y = NSMaxY(titleRect);
|
|
[path appendBezierPathWithRect: maxY];
|
|
}
|
|
|
|
if (![path isEmpty])
|
|
{
|
|
[path addClip];
|
|
}
|
|
}
|
|
|
|
|
|
[[GSTheme theme] fillRect: [box borderRect]
|
|
withTiles: tiles];
|
|
|
|
// Restore clipping path
|
|
[NSGraphicsContext restoreGraphicsState];
|
|
}
|
|
|
|
|
|
// Draw title
|
|
if ([box titlePosition] != NSNoTitle)
|
|
{
|
|
// If the title is on the border, clip a hole in the later
|
|
if (drawTitleBackground
|
|
&& (borderType != NSNoBorder)
|
|
&& (([box titlePosition] == NSAtTop) || ([box titlePosition] == NSAtBottom)))
|
|
{
|
|
[color set];
|
|
NSRectFill([box titleRect]);
|
|
}
|
|
|
|
[[box titleCell] drawWithFrame: [box titleRect] inView: box];
|
|
}
|
|
}
|
|
|
|
- (void) drawEditorForCell: (NSCell *)cell
|
|
withFrame: (NSRect)cellFrame
|
|
inView: (NSView *)view
|
|
{
|
|
[cell _drawEditorWithFrame: cellFrame
|
|
inView: view];
|
|
}
|
|
|
|
|
|
- (void) drawInCell: (NSCell *)cell
|
|
attributedText: (NSAttributedString *)stringValue
|
|
inFrame: (NSRect)cellFrame
|
|
{
|
|
[cell _drawAttributedText: stringValue
|
|
inFrame: cellFrame];
|
|
}
|
|
|
|
// NSBrowserCell
|
|
- (void) drawBrowserInteriorWithFrame: (NSRect)cellFrame
|
|
withCell: (NSBrowserCell *)cell
|
|
inView: (NSView *)controlView
|
|
withImage: (NSImage *)theImage
|
|
alternateImage: (NSImage *)alternateImage
|
|
isHighlighted: (BOOL)isHighlighted
|
|
state: (int)state
|
|
isLeaf: (BOOL)isLeaf
|
|
{
|
|
NSRect title_rect = cellFrame;
|
|
NSImage *branch_image = nil;
|
|
NSImage *cell_image = theImage;
|
|
|
|
if (isHighlighted || state)
|
|
{
|
|
if (!isLeaf)
|
|
branch_image = [self highlightedBranchImage];
|
|
if (nil != alternateImage)
|
|
[cell setImage: alternateImage];
|
|
|
|
// If we are highlighted, fill the background
|
|
[[cell highlightColorInView: controlView] setFill];
|
|
NSRectFill(cellFrame);
|
|
}
|
|
else
|
|
{
|
|
if (!isLeaf)
|
|
branch_image = [self branchImage];
|
|
|
|
// (Don't fill the background)
|
|
}
|
|
|
|
// Draw the branch image if there is one
|
|
if (branch_image)
|
|
{
|
|
NSRect imgRect;
|
|
|
|
imgRect.size = [branch_image size];
|
|
imgRect.origin.x = MAX(NSMaxX(title_rect) - imgRect.size.width - 4.0, 0.);
|
|
imgRect.origin.y = MAX(NSMidY(title_rect) - (imgRect.size.height/2.), 0.);
|
|
|
|
if (controlView != nil)
|
|
{
|
|
imgRect = [controlView centerScanRect: imgRect];
|
|
}
|
|
|
|
[branch_image drawInRect: imgRect
|
|
fromRect: NSZeroRect
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1.0
|
|
respectFlipped: YES
|
|
hints: nil];
|
|
|
|
title_rect.size.width -= imgRect.size.width + 8;
|
|
}
|
|
|
|
// Skip 2 points from the left border
|
|
title_rect.origin.x += 2;
|
|
title_rect.size.width -= 2;
|
|
|
|
// Draw the cell image if there is one
|
|
if (cell_image)
|
|
{
|
|
NSRect imgRect;
|
|
|
|
imgRect.size = [cell_image size];
|
|
imgRect.origin.x = NSMinX(title_rect);
|
|
imgRect.origin.y = MAX(NSMidY(title_rect) - (imgRect.size.height/2.),0.);
|
|
|
|
if (controlView != nil)
|
|
{
|
|
imgRect = [controlView centerScanRect: imgRect];
|
|
}
|
|
|
|
[cell_image drawInRect: imgRect
|
|
fromRect: NSZeroRect
|
|
operation: NSCompositeSourceOver
|
|
fraction: 1.0
|
|
respectFlipped: YES
|
|
hints: nil];
|
|
|
|
title_rect.origin.x += imgRect.size.width + 4;
|
|
title_rect.size.width -= imgRect.size.width + 4;
|
|
}
|
|
|
|
// Draw the body of the cell
|
|
if ([cell _inEditing])
|
|
{
|
|
[self drawEditorForCell: cell
|
|
withFrame: cellFrame
|
|
inView: controlView];
|
|
}
|
|
else
|
|
{
|
|
[self drawInCell: cell
|
|
attributedText: [cell attributedStringValue]
|
|
inFrame: title_rect];
|
|
}
|
|
}
|
|
|
|
- (NSImage *) branchImage
|
|
{
|
|
return [NSImage imageNamed: @"common_3DArrowRight"];
|
|
}
|
|
|
|
- (NSImage *) highlightedBranchImage
|
|
{
|
|
return [NSImage imageNamed: @"common_3DArrowRightH"];
|
|
}
|
|
@end
|