/** GSThemeDrawing The theme methods for drawing controls Copyright (C) 2004-2010 Free Software Foundation, Inc. Author: Adam Fedor 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 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/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/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 "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) - (float *)_columnOrigins; - (void) _willDisplayCell: (NSCell*)cell forTableColumn: (NSTableColumn *)tb row: (int)index; @end @interface NSCell (Private) - (void) _setInEditing: (BOOL)flag; @end @implementation GSTheme (Drawing) - (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) { color = [NSColor selectedControlColor]; } else if (state == GSThemeSelectedState) { 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); case NSHelpButtonBezelStyle: [self drawCircularBezel: frame withColor: color]; 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) { [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]; } } - (NSSize) buttonBorderForCell: (NSCell*)cell style: (int)style state: (GSThemeControlState)state { GSDrawTiles *tiles = nil; NSString *name = [self nameForElement: cell]; 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: return NSMakeSize(5, 5); case NSTexturedSquareBezelStyle: return NSMakeSize(3, 3); case NSSmallSquareBezelStyle: case NSRegularSquareBezelStyle: case NSShadowlessSquareBezelStyle: return NSMakeSize(2, 2); case NSThickSquareBezelStyle: return NSMakeSize(3, 3); case NSThickerSquareBezelStyle: return NSMakeSize(4, 4); case NSCircularBezelStyle: return NSMakeSize(5, 5); case NSHelpButtonBezelStyle: return NSMakeSize(2, 2); case NSDisclosureBezelStyle: case NSRoundedDisclosureBezelStyle: case NSRecessedBezelStyle: // FIXME return NSMakeSize(0, 0); default: return NSMakeSize(3, 3); } } else { // FIXME: We assume the button's top and right padding are the same as // its bottom and left. return NSMakeSize(tiles->contentRect.origin.x, tiles->contentRect.origin.y); } } - (void) drawFocusFrame: (NSRect) frame view: (NSView*) view { NSDottedFrameRect(frame); } - (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 background: [NSColor clearColor]]; } } - (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. return NSMakeSize(tiles->contentRect.origin.x, tiles->contentRect.origin.y); } } - (void) drawBorderForImageFrameStyle: (NSImageFrameStyle)frameStyle frame: (NSRect)frame view: (NSView*)view { 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; } } - (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. */ - (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 { return 18.0; } - (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 grayColor]; } 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; } } // NSStepperCell drawing // Hard coded values for button sizes #define STEPPER_WIDTH 15 #define STEPPER_HEIGHT 11 - (NSRect) stepperUpButtonRectWithFrame: (NSRect)frame { NSRect upRect; upRect.size.width = STEPPER_WIDTH; upRect.size.height = STEPPER_HEIGHT; upRect.origin.x = NSMaxX(frame) - STEPPER_WIDTH - 1; upRect.origin.y = NSMinY(frame) + ((int)frame.size.height / 2) + 1; return upRect; } - (NSRect) stepperDownButtonRectWithFrame: (NSRect)frame { NSRect downRect; downRect.size.width = STEPPER_WIDTH; downRect.size.height = STEPPER_HEIGHT; downRect.origin.x = NSMaxX(frame) - STEPPER_WIDTH - 1; downRect.origin.y = NSMinY(frame) + ((int)frame.size.height / 2) - STEPPER_HEIGHT + 1; return downRect; } - (void) drawStepperBorder: (NSRect)frame { NSRectEdge up_sides[] = {NSMaxXEdge, NSMinYEdge}; NSColor *black = [NSColor controlDarkShadowColor]; NSColor *grays[] = {black, black}; NSRect twoButtons; twoButtons.origin.x = NSMaxX(frame) - STEPPER_WIDTH - 1; twoButtons.origin.y = NSMinY(frame) + ((int)frame.size.height / 2) - STEPPER_HEIGHT; twoButtons.size.width = STEPPER_WIDTH + 1; twoButtons.size.height = 2 * STEPPER_HEIGHT + 1; NSDrawColorTiledRects(twoButtons, NSZeroRect, up_sides, grays, 2); } - (NSRect) drawStepperLightButton: (NSRect)border : (NSRect)clip { /* NSRect highlightRect = NSInsetRect(border, 1., 1.); [[GSTheme theme] drawButton: border : clip]; return highlightRect; */ NSRectEdge up_sides[] = {NSMaxXEdge, NSMinYEdge, NSMinXEdge, NSMaxYEdge}; NSRectEdge dn_sides[] = {NSMaxXEdge, NSMaxYEdge, NSMinXEdge, NSMinYEdge}; // These names are role names not the actual colours NSColor *dark = [NSColor controlShadowColor]; NSColor *white = [NSColor controlLightHighlightColor]; NSColor *colors[] = {dark, dark, white, white}; if ([[NSView focusView] isFlipped] == YES) { return NSDrawColorTiledRects(border, clip, dn_sides, colors, 4); } else { return NSDrawColorTiledRects(border, clip, up_sides, colors, 4); } } - (void) drawStepperUpButton: (NSRect)aRect { NSRect unHighlightRect = [self drawStepperLightButton: aRect : NSZeroRect]; [[NSColor controlBackgroundColor] set]; NSRectFill(unHighlightRect); PSsetlinewidth(1.0); [[NSColor controlShadowColor] set]; PSmoveto(NSMaxX(aRect) - 5, NSMinY(aRect) + 3); PSlineto(NSMaxX(aRect) - 8, NSMinY(aRect) + 9); PSstroke(); [[NSColor controlDarkShadowColor] set]; PSmoveto(NSMaxX(aRect) - 8, NSMinY(aRect) + 9); PSlineto(NSMaxX(aRect) - 11, NSMinY(aRect) + 4); PSstroke(); [[NSColor controlLightHighlightColor] set]; PSmoveto(NSMaxX(aRect) - 11, NSMinY(aRect) + 3); PSlineto(NSMaxX(aRect) - 5, NSMinY(aRect) + 3); PSstroke(); } - (void) drawStepperHighlightUpButton: (NSRect)aRect { NSRect highlightRect = [self drawStepperLightButton: aRect : NSZeroRect]; [[NSColor selectedControlColor] set]; NSRectFill(highlightRect); PSsetlinewidth(1.0); [[NSColor controlHighlightColor] set]; PSmoveto(NSMaxX(aRect) - 5, NSMinY(aRect) + 3); PSlineto(NSMaxX(aRect) - 8, NSMinY(aRect) + 9); PSstroke(); [[NSColor controlDarkShadowColor] set]; PSmoveto(NSMaxX(aRect) - 8, NSMinY(aRect) + 9); PSlineto(NSMaxX(aRect) - 11, NSMinY(aRect) + 4); PSstroke(); [[NSColor controlHighlightColor] set]; PSmoveto(NSMaxX(aRect) - 11, NSMinY(aRect) + 3); PSlineto(NSMaxX(aRect) - 5, NSMinY(aRect) + 3); PSstroke(); } - (void) drawStepperDownButton: (NSRect)aRect { NSRect unHighlightRect = [self drawStepperLightButton: aRect : NSZeroRect]; [[NSColor controlBackgroundColor] set]; NSRectFill(unHighlightRect); PSsetlinewidth(1.0); [[NSColor controlShadowColor] set]; PSmoveto(NSMinX(aRect) + 4, NSMaxY(aRect) - 3); PSlineto(NSMinX(aRect) + 7, NSMaxY(aRect) - 8); PSstroke(); [[NSColor controlLightHighlightColor] set]; PSmoveto(NSMinX(aRect) + 7, NSMaxY(aRect) - 8); PSlineto(NSMinX(aRect) + 10, NSMaxY(aRect) - 3); PSstroke(); [[NSColor controlDarkShadowColor] set]; PSmoveto(NSMinX(aRect) + 10, NSMaxY(aRect) - 2); PSlineto(NSMinX(aRect) + 4, NSMaxY(aRect) - 2); PSstroke(); } - (void) drawStepperHighlightDownButton: (NSRect)aRect { NSRect highlightRect = [self drawStepperLightButton: aRect : NSZeroRect]; [[NSColor selectedControlColor] set]; NSRectFill(highlightRect); PSsetlinewidth(1.0); [[NSColor controlHighlightColor] set]; PSmoveto(NSMinX(aRect) + 4, NSMaxY(aRect) - 3); PSlineto(NSMinX(aRect) + 7, NSMaxY(aRect) - 8); PSstroke(); [[NSColor controlHighlightColor] set]; PSmoveto(NSMinX(aRect) + 7, NSMaxY(aRect) - 8); PSlineto(NSMinX(aRect) + 10, NSMaxY(aRect) - 3); PSstroke(); [[NSColor controlDarkShadowColor] set]; PSmoveto(NSMinX(aRect) + 10, NSMaxY(aRect) - 2); PSlineto(NSMinX(aRect) + 4, NSMaxY(aRect) - 2); PSstroke(); } - (void) drawStepperCell: (NSCell*)cell withFrame: (NSRect)cellFrame inView: (NSView*)controlView highlightUp: (BOOL)highlightUp highlightDown: (BOOL)highlightDown { NSRect upRect; NSRect downRect; [self drawStepperBorder: cellFrame]; upRect = [self stepperUpButtonRectWithFrame: cellFrame]; downRect = [self stepperDownButtonRectWithFrame: cellFrame]; if (highlightUp) [self drawStepperHighlightUpButton: upRect]; else [self drawStepperUpButton: upRect]; if (highlightDown) [self drawStepperHighlightDownButton: downRect]; else [self drawStepperDownButton: downRect]; } // 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 background: [NSColor clearColor]]; } } - (void) drawImage: (NSImage *)image inButtonCell: (NSButtonCell *) cell withFrame: (NSRect) aRect position: (NSPoint) position { BOOL enabled = [cell isEnabled]; BOOL dims = [cell imageDimsWhenDisabled]; if (!enabled && dims) { [image dissolveToPoint: position fraction: 0.5]; } else { [image compositeToPoint: position operation: NSCompositeSourceOver]; } } - (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[2]; float grays[] = {NSDarkGray, NSDarkGray}; [[NSColor windowBackgroundColor] set]; NSRectFill(NSIntersectionRect(bounds, dirtyRect)); if (horizontal == YES) { sides[0] = NSMinYEdge; sides[1] = NSMinYEdge; NSDrawTiledRects(bounds, dirtyRect, sides, grays, 2); } else { sides[0] = NSMinXEdge; sides[1] = NSMaxYEdge; // Draw the dark gray upper left lines. NSDrawTiledRects(bounds, dirtyRect, sides, grays, 2); } } else { [self fillRect: bounds withTiles: tiles background: [NSColor clearColor]]; } } - (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 (![cell isBordered]) return; if (state == GSThemeSelectedState) { [self drawGrayBezel: cellFrame withClip: NSZeroRect]; } else { [self drawButton: cellFrame withClip: NSZeroRect]; } } else { [self fillRect: cellFrame withTiles: tiles background: [NSColor clearColor]]; } } - (Class) titleViewClassForMenuView: (NSMenuView *)aMenuView { return [GSTitleView class]; } // 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 background: [NSColor clearColor]]; } /* * 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]) { /* * Draw inner frame. */ [self drawGrayBezel: aRect withClip: clipRect]; aRect = NSInsetRect(aRect, 2.0, 2.0); } 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 { return [self drawGrayBezel: bounds withClip: rect]; } - (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 - (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) { [[NSColor blackColor] set]; NSRectFill(divide); rect = [self drawDarkButton: rect withClip: aRect]; [[NSColor controlShadowColor] set]; NSRectFill(rect); } else { [self fillRect: aRect withTiles: tiles background: [NSColor clearColor]]; } } - (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 background: [NSColor clearColor]]; } } // Window decoration drawing methods /* These include the black border. */ #define TITLE_HEIGHT 23.0 #define RESIZE_HEIGHT 9.0 - (float) titlebarHeight { return TITLE_HEIGHT; } - (float) resizebarHeight { return RESIZE_HEIGHT; } 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}; float 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 background: [NSColor clearColor]]; } } - (void) drawWindowBorder: (NSRect)rect withFrame: (NSRect)frame forStyleMask: (unsigned int)styleMask state: (int)inputState andTitle: (NSString*)title { if (styleMask & (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)) { NSRect titleBarRect; titleBarRect = NSMakeRect(0.0, frame.size.height - TITLE_HEIGHT, frame.size.width, TITLE_HEIGHT); if (NSIntersectsRect(rect, titleBarRect)) [self drawTitleBarRect: titleBarRect forStyleMask: styleMask state: inputState andTitle: title]; } if (styleMask & NSResizableWindowMask) { NSRect resizeBarRect; resizeBarRect = NSMakeRect(0.0, 0.0, frame.size.width, RESIZE_HEIGHT); if (NSIntersectsRect(rect, resizeBarRect)) [self drawResizeBarRect: resizeBarRect]; } if (styleMask & (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)) { NSColor *borderColor = [self colorNamed: @"windowBorderColor" state: GSThemeNormalState]; if (nil == borderColor) { borderColor = [NSColor blackColor]; } [borderColor set]; PSsetlinewidth(1.0); if (NSMinX(rect) < 1.0) { PSmoveto(0.5, 0.0); PSlineto(0.5, frame.size.height); PSstroke(); } if (NSMaxX(rect) > frame.size.width - 1.0) { PSmoveto(frame.size.width - 0.5, 0.0); PSlineto(frame.size.width - 0.5, frame.size.height); PSstroke(); } if (NSMaxY(rect) > frame.size.height - 1.0) { PSmoveto(0.0, frame.size.height - 0.5); PSlineto(frame.size.width, frame.size.height - 0.5); PSstroke(); } if (NSMinY(rect) < 1.0) { PSmoveto(0.0, 0.5); PSlineto(frame.size.width, 0.5); PSstroke(); } } } - (void) 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 background: [NSColor clearColor]]; } } - (NSRect) browserHeaderDrawingRectForCell: (NSTableHeaderCell*)cell withFrame: (NSRect)rect { GSDrawTiles *tiles; tiles = [self tilesNamed: GSBrowserHeader state: GSThemeNormalState]; if (tiles == nil) { return NSInsetRect(rect, 2, 2); } else { // FIXME: We assume the button's top and right padding are the same as // its bottom and left. return NSInsetRect(rect, tiles->contentRect.origin.x, tiles->contentRect.origin.y); } } - (void) drawTabViewRect: (NSRect)rect inView: (NSView *)view withItems: (NSArray *)items selectedItem: (NSTabViewItem *)selected { NSGraphicsContext *ctxt = GSCurrentContext(); int howMany = [items count]; int i; int previousState = 0; NSRect bounds = [view bounds]; NSRect aRect = bounds; NSColor *lineColour = [NSColor highlightColor]; NSColor *backgroundColour = [[view window] backgroundColor]; BOOL truncate = [(NSTabView *)view allowsTruncatedLabels]; NSTabViewType type = [(NSTabView *)view tabViewType]; // Make sure some tab is selected if (!selected && howMany > 0) [(NSTabView *)view selectFirstTabViewItem: nil]; DPSgsave(ctxt); switch (type) { default: case NSTopTabsBezelBorder: aRect.size.height -= 16; [self drawButton: aRect withClip: rect]; break; case NSBottomTabsBezelBorder: aRect.size.height -= 16; aRect.origin.y += 16; [self drawButton: aRect withClip: rect]; aRect.origin.y -= 16; break; case NSLeftTabsBezelBorder: aRect.size.width -= 18; aRect.origin.x += 18; [self drawButton: aRect withClip: rect]; break; case NSRightTabsBezelBorder: aRect.size.width -= 18; [self drawButton: aRect withClip: rect]; break; case NSNoTabsBezelBorder: [self drawButton: aRect withClip: rect]; break; case NSNoTabsLineBorder: [[NSColor controlDarkShadowColor] set]; NSFrameRect(aRect); break; case NSNoTabsNoBorder: break; } if (type == NSBottomTabsBezelBorder) { NSPoint iP; iP.x = bounds.origin.x; iP.y = bounds.origin.y; for (i = 0; i < howMany; i++) { NSRect r; NSRect fRect; NSTabViewItem *anItem = [items objectAtIndex: i]; NSTabState itemState = [anItem tabState]; NSSize s = [anItem sizeOfLabel: truncate]; [backgroundColour set]; if (i == 0) { if (itemState == NSSelectedTab) { iP.y += 1; NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabDownSelectedLeft"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y -= 1; } else if (itemState == NSBackgroundTab) { NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabDownUnSelectedLeft"] compositeToPoint: iP operation: NSCompositeSourceOver]; } else NSLog(@"Not finished yet. Luff ya.\n"); } else { if (itemState == NSSelectedTab) { iP.y += 1; NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabDownUnSelectedToSelectedJunction"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y -= 1; } else if (itemState == NSBackgroundTab) { if (previousState == NSSelectedTab) { iP.y += 1; NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabDownSelectedToUnSelectedJunction"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y -= 1; } else { NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabDownUnSelectedJunction"] compositeToPoint: iP operation: NSCompositeSourceOver]; } } else NSLog(@"Not finished yet. Luff ya.\n"); } r.origin.x = iP.x + 13; r.origin.y = iP.y + 2; r.size.width = s.width; r.size.height = 15; fRect = r; if (itemState == NSSelectedTab) { // Undraw the line that separates the tab from its view. fRect.origin.y += 1; fRect.size.height += 1; } NSRectFill(fRect); // Draw the line at the bottom of the item [lineColour set]; DPSsetlinewidth(ctxt, 1); DPSmoveto(ctxt, r.origin.x, r.origin.y - 1); DPSrlineto(ctxt, r.size.width, 0); DPSstroke(ctxt); // Label [anItem drawLabel: truncate inRect: r]; iP.x += s.width + 13; previousState = itemState; if (i == howMany - 1) { [backgroundColour set]; if ([anItem tabState] == NSSelectedTab) { iP.y += 1; NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabDownSelectedRight"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y -= 1; } else if ([anItem tabState] == NSBackgroundTab) { NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabDownUnSelectedRight"] compositeToPoint: iP operation: NSCompositeSourceOver]; } else NSLog(@"Not finished yet. Luff ya.\n"); } } } else if (type == NSTopTabsBezelBorder) { NSPoint iP; iP.x = bounds.origin.x; // FIXME: Why not NSMaxY(bounds)? iP.y = bounds.size.height - 16; for (i = 0; i < howMany; i++) { NSRect r; NSRect fRect; NSTabViewItem *anItem = [items objectAtIndex: i]; NSTabState itemState = [anItem tabState]; NSSize s = [anItem sizeOfLabel: truncate]; [backgroundColour set]; if (i == 0) { if (itemState == NSSelectedTab) { iP.y -= 1; NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabSelectedLeft"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y += 1; } else if (itemState == NSBackgroundTab) { NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabUnSelectedLeft"] compositeToPoint: iP operation: NSCompositeSourceOver]; } else NSLog(@"Not finished yet. Luff ya.\n"); } else { if (itemState == NSSelectedTab) { iP.y -= 1; NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabUnSelectToSelectedJunction"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y += 1; } else if (itemState == NSBackgroundTab) { if (previousState == NSSelectedTab) { iP.y -= 1; NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabSelectedToUnSelectedJunction"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y += 1; } else { NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabUnSelectedJunction"] compositeToPoint: iP operation: NSCompositeSourceOver]; } } else NSLog(@"Not finished yet. Luff ya.\n"); } r.origin.x = iP.x + 13; r.origin.y = iP.y; r.size.width = s.width; r.size.height = 15; fRect = r; if (itemState == NSSelectedTab) { // Undraw the line that separates the tab from its view. fRect.origin.y -= 1; fRect.size.height += 1; } NSRectFill(fRect); // Draw the line at the top of the item [lineColour set]; DPSsetlinewidth(ctxt, 1); DPSmoveto(ctxt, r.origin.x, r.origin.y + 16); DPSrlineto(ctxt, r.size.width, 0); DPSstroke(ctxt); // Label [anItem drawLabel: truncate inRect: r]; iP.x += s.width + 13; previousState = itemState; if (i == howMany - 1) { [backgroundColour set]; if ([anItem tabState] == NSSelectedTab) { iP.y -= 1; NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabSelectedRight"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y += 1; } else if ([anItem tabState] == NSBackgroundTab) { NSRectFill(NSMakeRect(iP.x, iP.y, 14, 17)); [[NSImage imageNamed: @"common_TabUnSelectedRight"] compositeToPoint: iP operation: NSCompositeSourceOver]; } else NSLog(@"Not finished yet. Luff ya.\n"); } } } // 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 ([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]; } } } - (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; NSGraphicsContext *ctxt = GSCurrentContext(); GSTheme *theme = [GSTheme theme]; NSColor *color; NSString *name; NSBorderType borderType = [scrollView borderType]; NSRect bounds = [view bounds]; BOOL hasInnerBorder = ![[NSUserDefaults standardUserDefaults] boolForKey: @"GSScrollViewNoInnerBorder"]; name = [theme nameForElement: self]; if (name == nil) { name = @"NSScrollView"; } color = [theme colorNamed: name state: GSThemeNormalState]; if (color == nil) { color = [NSColor controlDarkShadowColor]; } 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; } if (hasInnerBorder) { NSScroller *vertScroller = [scrollView verticalScroller]; NSScroller *horizScroller = [scrollView horizontalScroller]; CGFloat scrollerWidth = [NSScroller scrollerWidth]; [color set]; DPSsetlinewidth(ctxt, 1); if ([scrollView hasVerticalScroller]) { NSInterfaceStyle style; style = NSInterfaceStyleForKey(@"NSScrollViewInterfaceStyle", nil); if (style == NSMacintoshInterfaceStyle || style == NSWindows95InterfaceStyle) { DPSmoveto(ctxt, [vertScroller frame].origin.x - 1, [vertScroller frame].origin.y - 1); } else { DPSmoveto(ctxt, [vertScroller frame].origin.x + scrollerWidth, [vertScroller frame].origin.y - 1); } DPSrlineto(ctxt, 0, [vertScroller frame].size.height + 1); DPSstroke(ctxt); } if ([scrollView hasHorizontalScroller]) { float ypos; float scrollerY = [horizScroller frame].origin.y; if ([scrollView isFlipped]) { ypos = scrollerY - 1; } else { ypos = scrollerY + scrollerWidth + 1; } DPSmoveto(ctxt, [horizScroller frame].origin.x - 1, ypos); DPSrlineto(ctxt, [horizScroller frame].size.width + 1, 0); DPSstroke(ctxt); } } } - (void) drawBarInside: (NSRect)rect inCell: (NSCell *)cell flipped: (BOOL)flipped { NSSliderType type = [(NSSliderCell *)cell sliderType]; if (type == NSLinearSlider) { [[NSColor scrollBarColor] set]; NSRectFill(rect); } } - (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; } if (lastColumnToDraw == [tableView numberOfColumns] - 1) { column = [columns objectAtIndex: lastColumnToDraw]; width = [column width] - 1; drawingRect.size.width = width; cell = [column headerCell]; if ((column == highlightedTableColumn) || [tableView isColumnSelected: lastColumnToDraw]) { [cell setHighlighted: YES]; } else { [cell setHighlighted: NO]; } [cell drawWithFrame: drawingRect inView: tableHeaderView]; drawingRect.origin.x += width; } else { column = [columns objectAtIndex: lastColumnToDraw]; width = [column width]; drawingRect.size.width = width; cell = [column headerCell]; if ((column == highlightedTableColumn) || [tableView isColumnSelected: lastColumnToDraw]) { [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)clipRect inView: (NSView *)view withBackgroundColor: (NSColor *)backgroundColor { [backgroundColor set]; NSRectFill (clipRect); } - (void) drawTableViewGridInClipRect: (NSRect)aRect inView: (NSView *)view { NSTableView *tableView = (NSTableView *)view; NSRect bounds = [view bounds]; float minX = NSMinX (aRect); float maxX = NSMaxX (aRect); float minY = NSMinY (aRect); float maxY = NSMaxY (aRect); int i; float x_pos; int startingColumn; int endingColumn; int numberOfColumns = [tableView numberOfColumns]; NSArray *tableColumns = [tableView tableColumns]; NSGraphicsContext *ctxt = GSCurrentContext (); float position = 0.0; float *columnOrigins = [tableView _columnOrigins]; int startingRow = [tableView rowAtPoint: NSMakePoint (bounds.origin.x, minY)]; int endingRow = [tableView rowAtPoint: NSMakePoint (bounds.origin.x, maxY)]; NSColor *gridColor = [tableView gridColor]; int rowHeight = [tableView rowHeight]; int numberOfRows = [tableView numberOfRows]; /* Using columnAtPoint:, rowAtPoint: here calls them only twice per drawn rect */ x_pos = minX; i = 0; while ((i < numberOfColumns) && (x_pos > columnOrigins[i])) { i++; } startingColumn = (i - 1); x_pos = maxX; // Nota Bene: we do *not* reset i while ((i < numberOfColumns) && (x_pos > columnOrigins[i])) { i++; } endingColumn = (i - 1); if (endingColumn == -1) endingColumn = numberOfColumns - 1; /* int startingColumn = [tableView columnAtPoint: NSMakePoint (minX, bounds.origin.y)]; int endingColumn = [tableView columnAtPoint: NSMakePoint (maxX, bounds.origin.y)]; */ DPSgsave (ctxt); DPSsetlinewidth (ctxt, 1); [gridColor set]; if (numberOfRows > 0) { /* Draw horizontal lines */ if (startingRow == -1) startingRow = 0; if (endingRow == -1) endingRow = numberOfRows - 1; position = bounds.origin.y; position += startingRow * rowHeight; for (i = startingRow; i <= endingRow + 1; i++) { DPSmoveto (ctxt, minX, position); DPSlineto (ctxt, maxX, position); DPSstroke (ctxt); position += rowHeight; } } if (numberOfColumns > 0) { int lastRowPosition = position - rowHeight; /* Draw vertical lines */ if (startingColumn == -1) startingColumn = 0; if (endingColumn == -1) endingColumn = numberOfColumns - 1; for (i = startingColumn; i <= endingColumn; i++) { DPSmoveto (ctxt, columnOrigins[i], minY); DPSlineto (ctxt, columnOrigins[i], lastRowPosition); DPSstroke (ctxt); } position = columnOrigins[endingColumn]; position += [[tableColumns objectAtIndex: endingColumn] width]; /* Last vertical line must moved a pixel to the left */ if (endingColumn == (numberOfColumns - 1)) position -= 1; DPSmoveto (ctxt, position, minY); DPSlineto (ctxt, position, lastRowPosition); DPSstroke (ctxt); } DPSgrestore (ctxt); } - (void) drawTableViewRect: (NSRect)aRect inView: (NSView *)view { int startingRow; int endingRow; int i; NSTableView *tableView = (NSTableView *)view; int numberOfRows = [tableView numberOfRows]; int 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:); IMP imp = [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; int numberOfRows = [tableView numberOfRows]; int numberOfColumns = [tableView numberOfColumns]; NSIndexSet *selectedRows = [tableView selectedRowIndexes]; NSIndexSet *selectedColumns = [tableView selectedColumnIndexes]; NSColor *backgroundColor = [tableView backgroundColor]; if (selectingColumns == NO) { int selectedRowsCount; int row; int 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)) { NSColor *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]; } //NSHighlightRect(NSIntersectionRect([tableView rectOfRow: row], // clipRect)); [selectionColor set]; NSRectFill(NSIntersectionRect([tableView rectOfRow: row], clipRect)); row = [selectedRows indexGreaterThanIndex: row]; } } else // Selecting columns { unsigned int selectedColumnsCount; unsigned int column; int 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)) { NSHighlightRect(NSIntersectionRect([tableView rectOfColumn: column], clipRect)); column = [selectedColumns indexGreaterThanIndex: column]; } } } - (void) drawTableViewRow: (int)rowIndex clipRect: (NSRect)clipRect inView: (NSView *)view { NSTableView *tableView = (NSTableView *)view; // int numberOfRows = [tableView numberOfRows]; int numberOfColumns = [tableView numberOfColumns]; // NSIndexSet *selectedRows = [tableView selectedRowIndexes]; // NSColor *backgroundColor = [tableView backgroundColor]; id dataSource = [tableView dataSource]; float *columnOrigins = [tableView _columnOrigins]; int editedRow = [tableView editedRow]; int editedColumn = [tableView editedColumn]; NSArray *tableColumns = [tableView tableColumns]; int startingColumn; int endingColumn; NSTableColumn *tb; NSRect drawingRect; NSCell *cell; int i; float x_pos; if (dataSource == nil) { return; } /* Using columnAtPoint: here would make it called twice per row per drawn rect - so we avoid it and do it natively */ /* 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++) { tb = [tableColumns objectAtIndex: i]; cell = [tb dataCellForRow: rowIndex]; if (i == editedColumn && rowIndex == editedRow) [cell _setInEditing: YES]; [tableView _willDisplayCell: cell forTableColumn: tb row: rowIndex]; [cell setObjectValue: [dataSource tableView: tableView objectValueForTableColumn: tb row: rowIndex]]; drawingRect = [tableView frameOfCellAtColumn: i row: rowIndex]; [cell drawWithFrame: drawingRect inView: tableView]; if (i == editedColumn && rowIndex == editedRow) [cell _setInEditing: NO]; } } @end