/** <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/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, &divide, &rect, 1.0, NSMaxYEdge);
    }
  else
    {
      NSDivideRect(aRect, &divide, &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
