mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-24 21:58:51 +00:00
3701 lines
95 KiB
Objective-C
3701 lines
95 KiB
Objective-C
/** <title>GSThemeDrawing</title>
|
|
|
|
<abstract>The theme methods for drawing controls</abstract>
|
|
|
|
Copyright (C) 2004-2010 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/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/NSMenuView.h"
|
|
#import "AppKit/NSMenuItemCell.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/NSTableColumn.h"
|
|
#import "AppKit/NSTableHeaderCell.h"
|
|
#import "AppKit/NSTableHeaderView.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;
|
|
@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;
|
|
}
|
|
|
|
- (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 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) 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;
|
|
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 < 30 * 2)
|
|
return;
|
|
|
|
[[NSColor darkGrayColor] set];
|
|
PSmoveto(27.5, 1.0);
|
|
PSlineto(27.5, RESIZE_HEIGHT - 2.0);
|
|
PSmoveto(resizeBarRect.size.width - 28.5, 1.0);
|
|
PSlineto(resizeBarRect.size.width - 28.5, RESIZE_HEIGHT - 2.0);
|
|
PSstroke();
|
|
|
|
[[NSColor whiteColor] set];
|
|
PSmoveto(28.5, 1.0);
|
|
PSlineto(28.5, RESIZE_HEIGHT - 2.0);
|
|
PSmoveto(resizeBarRect.size.width - 27.5, 1.0);
|
|
PSlineto(resizeBarRect.size.width - 27.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();
|
|
}
|
|
}
|
|
}
|
|
|
|
- (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;
|
|
}
|
|
}
|
|
|
|
typedef enum {
|
|
GSTabSelectedLeft,
|
|
GSTabSelectedRight,
|
|
GSTabSelectedToUnSelectedJunction,
|
|
GSTabSelectedFill,
|
|
GSTabUnSelectedLeft,
|
|
GSTabUnSelectedRight,
|
|
GSTabUnSelectedToSelectedJunction,
|
|
GSTabUnSelectedJunction,
|
|
GSTabUnSelectedFill,
|
|
GSTabBackgroundFill
|
|
} GSTabPart;
|
|
|
|
- (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];
|
|
NSColor *backgroundColor = [tableView backgroundColor];
|
|
|
|
// Set the fill color
|
|
{
|
|
NSColor *selectionColor;
|
|
|
|
selectionColor = [self colorNamed: @"highlightedTableRowBackgroundColor"
|
|
state: GSThemeNormalState];
|
|
|
|
if (selectionColor == nil)
|
|
{
|
|
// Switch to the alternate color of the backgroundColor is white.
|
|
if([backgroundColor isEqual: [NSColor whiteColor]])
|
|
{
|
|
selectionColor = [NSColor colorWithCalibratedRed: 0.86
|
|
green: 0.92
|
|
blue: 0.99
|
|
alpha: 1.0];
|
|
}
|
|
else
|
|
{
|
|
selectionColor = [NSColor whiteColor];
|
|
}
|
|
}
|
|
[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) drawTableViewRow: (NSInteger)rowIndex
|
|
clipRect: (NSRect)clipRect
|
|
inView: (NSView *)view
|
|
{
|
|
NSTableView *tableView = (NSTableView *)view;
|
|
// NSInteger numberOfRows = [tableView numberOfRows];
|
|
NSInteger numberOfColumns = [tableView numberOfColumns];
|
|
// NSIndexSet *selectedRows = [tableView selectedRowIndexes];
|
|
// NSColor *backgroundColor = [tableView backgroundColor];
|
|
CGFloat *columnOrigins = [tableView _columnOrigins];
|
|
NSInteger editedRow = [tableView editedRow];
|
|
NSInteger editedColumn = [tableView editedColumn];
|
|
NSArray *tableColumns = [tableView tableColumns];
|
|
NSInteger startingColumn;
|
|
NSInteger endingColumn;
|
|
NSTableColumn *tb;
|
|
NSRect drawingRect;
|
|
NSCell *cell;
|
|
NSInteger i;
|
|
CGFloat x_pos;
|
|
const BOOL rowSelected = [[tableView selectedRowIndexes] containsIndex: rowIndex];
|
|
NSColor *tempColor = nil;
|
|
NSColor *selectedTextColor = [self colorNamed: @"highlightedTableRowTextColor"
|
|
state: GSThemeNormalState];
|
|
|
|
/* 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;
|
|
|
|
/* 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];
|
|
}
|
|
}
|
|
|
|
- (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
|