1/** <title>GSThemeDrawing</title> 2 3 <abstract>The theme methods for drawing controls</abstract> 4 5 Copyright (C) 2004-2010 Free Software Foundation, Inc. 6 7 Author: Adam Fedor <fedor@gnu.org> 8 Date: Jan 2004 9 10 This file is part of the GNU Objective C User interface library. 11 12 This library is free software; you can redistribute it and/or 13 modify it under the terms of the GNU Lesser General Public 14 License as published by the Free Software Foundation; either 15 version 2 of the License, or (at your option) any later version. 16 17 This library is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public 23 License along with this library; see the file COPYING.LIB. 24 If not, see <http://www.gnu.org/licenses/> or write to the 25 Free Software Foundation, 51 Franklin Street, Fifth Floor, 26 Boston, MA 02110-1301, USA. 27*/ 28 29#import "GSThemePrivate.h" 30 31#import "Foundation/NSUserDefaults.h" 32#import "Foundation/NSIndexSet.h" 33 34#import "AppKit/NSAttributedString.h" 35#import "AppKit/NSBezierPath.h" 36#import "AppKit/NSButtonCell.h" 37#import "AppKit/NSBrowser.h" 38#import "AppKit/NSBrowserCell.h" 39#import "AppKit/NSCell.h" 40#import "AppKit/NSColor.h" 41#import "AppKit/NSColorList.h" 42#import "AppKit/NSColorWell.h" 43#import "AppKit/NSGraphics.h" 44#import "AppKit/NSImage.h" 45#import "AppKit/NSMenuView.h" 46#import "AppKit/NSMenuItemCell.h" 47#import "AppKit/NSParagraphStyle.h" 48#import "AppKit/NSPopUpButtonCell.h" 49#import "AppKit/NSProgressIndicator.h" 50#import "AppKit/NSScroller.h" 51#import "AppKit/NSScrollView.h" 52#import "AppKit/NSStringDrawing.h" 53#import "AppKit/NSTableView.h" 54#import "AppKit/NSTableColumn.h" 55#import "AppKit/NSTableHeaderCell.h" 56#import "AppKit/NSTableHeaderView.h" 57#import "AppKit/NSView.h" 58#import "AppKit/NSTabView.h" 59#import "AppKit/NSTabViewItem.h" 60#import "AppKit/PSOperators.h" 61#import "AppKit/NSSliderCell.h" 62 63#import "GNUstepGUI/GSToolbarView.h" 64#import "GNUstepGUI/GSTitleView.h" 65 66/* a border width of 5 gives a reasonable compromise between Cocoa metrics and looking good */ 67/* 7.0 gives us the NeXT Look (which is 8 pix wide including the shadow) */ 68#define COLOR_WELL_BORDER_WIDTH 7.0 69 70@interface NSTableView (Private) 71- (CGFloat *)_columnOrigins; 72- (void) _willDisplayCell: (NSCell*)cell 73 forTableColumn: (NSTableColumn *)tb 74 row: (NSInteger)index; 75- (id)_objectValueForTableColumn: (NSTableColumn *)tb 76 row: (NSInteger)index; 77@end 78 79@interface NSCell (Private) 80- (void) _setInEditing: (BOOL)flag; 81- (BOOL) _inEditing; 82- (void) _drawEditorWithFrame: (NSRect)cellFrame 83 inView: (NSView *)controlView; 84- (void) _drawAttributedText: (NSAttributedString*)aString 85 inFrame: (NSRect)aRect; 86@end 87 88@implementation GSTheme (Drawing) 89- (void) setKeyEquivalent: (NSString *)key 90 forButtonCell: (NSButtonCell *)cell 91{ 92 if([cell image] == nil && ([key isEqualToString:@"\r"] || 93 [key isEqualToString:@"\n"])) 94 { 95 [cell setImagePosition: NSImageRight]; 96 [cell setImage: [NSImage imageNamed:@"common_ret"]]; 97 [cell setAlternateImage: [NSImage imageNamed:@"common_retH"]]; 98 } 99 else if([key isEqualToString:@"\r"] == NO && 100 [key isEqualToString:@"\n"] == NO) 101 { 102 NSImage *cellImage = [cell image]; 103 if(cellImage == [NSImage imageNamed:@"common_ret"]) 104 { 105 [cell setImage: nil]; 106 [cell setAlternateImage: nil]; 107 } 108 } 109} 110 111- (void) drawButton: (NSRect)frame 112 in: (NSCell*)cell 113 view: (NSView*)view 114 style: (int)style 115 state: (GSThemeControlState)state 116{ 117 GSDrawTiles *tiles = nil; 118 NSColor *color = nil; 119 NSString *name = [self nameForElement: cell]; 120 121 if (name == nil) 122 { 123 name = GSStringFromBezelStyle(style); 124 } 125 126 color = [self colorNamed: name state: state]; 127 if (color == nil) 128 { 129 if (state == GSThemeNormalState) 130 { 131 color = [NSColor controlBackgroundColor]; 132 } 133 else if (state == GSThemeHighlightedState 134 || state == GSThemeHighlightedFirstResponderState) 135 { 136 color = [NSColor selectedControlColor]; 137 } 138 else if (state == GSThemeSelectedState 139 || state == GSThemeSelectedFirstResponderState) 140 { 141 color = [NSColor selectedControlColor]; 142 } 143 else 144 { 145 color = [NSColor controlBackgroundColor]; 146 } 147 } 148 149 tiles = [self tilesNamed: name state: state]; 150 if (tiles == nil) 151 { 152 tiles = [self tilesNamed: @"NSButton" state: state]; 153 } 154 155 if (tiles == nil) 156 { 157 switch (style) 158 { 159 case NSRoundRectBezelStyle: 160 case NSTexturedRoundedBezelStyle: 161 case NSRoundedBezelStyle: 162 [self drawRoundBezel: frame withColor: color]; 163 break; 164 case NSTexturedSquareBezelStyle: 165 frame = NSInsetRect(frame, 0, 1); 166 case NSSmallSquareBezelStyle: 167 case NSRegularSquareBezelStyle: 168 case NSShadowlessSquareBezelStyle: 169 [color set]; 170 NSRectFill(frame); 171 [[NSColor controlShadowColor] set]; 172 NSFrameRectWithWidth(frame, 1); 173 break; 174 case NSThickSquareBezelStyle: 175 [color set]; 176 NSRectFill(frame); 177 [[NSColor controlShadowColor] set]; 178 NSFrameRectWithWidth(frame, 1.5); 179 break; 180 case NSThickerSquareBezelStyle: 181 [color set]; 182 NSRectFill(frame); 183 [[NSColor controlShadowColor] set]; 184 NSFrameRectWithWidth(frame, 2); 185 break; 186 case NSCircularBezelStyle: 187 frame = NSInsetRect(frame, 3, 3); 188 [self drawCircularBezel: frame withColor: color]; 189 break; 190 case NSHelpButtonBezelStyle: 191 [self drawCircularBezel: frame withColor: color]; 192 { 193 NSDictionary *attributes = [NSDictionary dictionaryWithObject: [NSFont controlContentFontOfSize: 0] 194 forKey: NSFontAttributeName]; 195 NSAttributedString *questionMark = [[[NSAttributedString alloc] 196 initWithString: _(@"?") 197 attributes: attributes] autorelease]; 198 199 NSRect textRect; 200 textRect.size = [questionMark size]; 201 textRect.origin.x = NSMidX(frame) - (textRect.size.width / 2); 202 textRect.origin.y = NSMidY(frame) - (textRect.size.height / 2); 203 204 [questionMark drawInRect: textRect]; 205 } 206 break; 207 case NSDisclosureBezelStyle: 208 case NSRoundedDisclosureBezelStyle: 209 case NSRecessedBezelStyle: 210 // FIXME 211 break; 212 default: 213 [color set]; 214 NSRectFill(frame); 215 216 if (state == GSThemeNormalState || state == GSThemeHighlightedState) 217 { 218 [self drawButton: frame withClip: NSZeroRect]; 219 } 220 else if (state == GSThemeSelectedState || state == GSThemeSelectedFirstResponderState) 221 { 222 [self drawGrayBezel: frame withClip: NSZeroRect]; 223 } 224 else 225 { 226 [self drawButton: frame withClip: NSZeroRect]; 227 } 228 } 229 } 230 else 231 { 232 /* Use tiles to draw button border with central part filled with color 233 */ 234 [self fillRect: frame 235 withTiles: tiles 236 background: color]; 237 } 238} 239 240- (GSThemeMargins) buttonMarginsForCell: (NSCell*)cell 241 style: (int)style 242 state: (GSThemeControlState)state 243{ 244 GSDrawTiles *tiles = nil; 245 NSString *name = [self nameForElement: cell]; 246 GSThemeMargins margins; 247 248 if (name == nil) 249 { 250 name = GSStringFromBezelStyle(style); 251 } 252 253 tiles = [self tilesNamed: name state: state]; 254 if (tiles == nil) 255 { 256 tiles = [self tilesNamed: @"NSButton" state: state]; 257 } 258 259 if (tiles == nil) 260 { 261 switch (style) 262 { 263 case NSRoundRectBezelStyle: 264 case NSTexturedRoundedBezelStyle: 265 case NSRoundedBezelStyle: 266 margins.left = 5; margins.top = 5; margins.right = 5; margins.bottom = 5; 267 return margins; 268 case NSTexturedSquareBezelStyle: 269 margins.left = 3; margins.top = 3; margins.right = 3; margins.bottom = 3; 270 return margins; 271 case NSSmallSquareBezelStyle: 272 case NSRegularSquareBezelStyle: 273 case NSShadowlessSquareBezelStyle: 274 margins.left = 2; margins.top = 2; margins.right = 2; margins.bottom = 2; 275 return margins; 276 case NSThickSquareBezelStyle: 277 margins.left = 3; margins.top = 3; margins.right = 3; margins.bottom = 3; 278 return margins; 279 case NSThickerSquareBezelStyle: 280 margins.left = 4; margins.top = 4; margins.right = 4; margins.bottom = 4; 281 return margins; 282 case NSCircularBezelStyle: 283 margins.left = 5; margins.top = 5; margins.right = 5; margins.bottom = 5; 284 return margins; 285 case NSHelpButtonBezelStyle: 286 margins.left = 2; margins.top = 2; margins.right = 2; margins.bottom = 2; 287 return margins; 288 case NSDisclosureBezelStyle: 289 case NSRoundedDisclosureBezelStyle: 290 case NSRecessedBezelStyle: 291 // FIXME 292 margins.left = 0; margins.top = 0; margins.right = 0; margins.bottom = 0; 293 return margins; 294 default: 295 margins.left = 2; margins.top = 2; margins.right = 3; margins.bottom = 3; 296 return margins; 297 } 298 } 299 else 300 { 301 margins = [tiles themeMargins]; 302 return margins; 303 } 304} 305 306- (void) drawFocusFrame: (NSRect) frame view: (NSView*) view 307{ 308 GSDrawTiles *tiles = [self tilesNamed: @"NSFocusRing" state: GSThemeNormalState]; 309 310 if (tiles == nil) 311 { 312 NSDottedFrameRect(frame); 313 } 314 else 315 { 316 [self fillRect: frame 317 withTiles: tiles]; 318 } 319} 320 321- (void) drawWindowBackground: (NSRect) frame view: (NSView*) view 322{ 323 NSColor *c; 324 325 c = [[view window] backgroundColor]; 326 [c set]; 327 NSRectFill (frame); 328} 329 330- (void) drawBorderType: (NSBorderType)aType 331 frame: (NSRect)frame 332 view: (NSView*)view 333{ 334 NSString *name = GSStringFromBorderType(aType); 335 GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState]; 336 337 if (tiles == nil) 338 { 339 switch (aType) 340 { 341 case NSLineBorder: 342 [[NSColor controlDarkShadowColor] set]; 343 NSFrameRect(frame); 344 break; 345 case NSGrooveBorder: 346 [self drawGroove: frame withClip: NSZeroRect]; 347 break; 348 case NSBezelBorder: 349 [self drawWhiteBezel: frame withClip: NSZeroRect]; 350 break; 351 case NSNoBorder: 352 default: 353 break; 354 } 355 } 356 else 357 { 358 [self fillRect: frame 359 withTiles: tiles]; 360 } 361} 362 363- (NSSize) sizeForBorderType: (NSBorderType)aType 364{ 365 NSString *name = GSStringFromBorderType(aType); 366 GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState]; 367 368 if (tiles == nil) 369 { 370 // Returns the size of a border 371 switch (aType) 372 { 373 case NSLineBorder: 374 return NSMakeSize(1, 1); 375 case NSGrooveBorder: 376 case NSBezelBorder: 377 return NSMakeSize(2, 2); 378 case NSNoBorder: 379 default: 380 return NSZeroSize; 381 } 382 } 383 else 384 { 385 // FIXME: We assume the button's top and right padding are the same as 386 // its bottom and left. 387 388 GSThemeMargins margins = [tiles themeMargins]; 389 return NSMakeSize(margins.left, margins.bottom); 390 } 391} 392 393- (void) drawBorderForImageFrameStyle: (NSImageFrameStyle)frameStyle 394 frame: (NSRect)frame 395 view: (NSView*)view 396{ 397 NSString *name = GSStringFromImageFrameStyle(frameStyle); 398 GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState]; 399 400 if (tiles == nil) 401 { 402 switch (frameStyle) 403 { 404 case NSImageFrameNone: 405 // do nothing 406 break; 407 case NSImageFramePhoto: 408 [self drawFramePhoto: frame withClip: NSZeroRect]; 409 break; 410 case NSImageFrameGrayBezel: 411 [self drawGrayBezel: frame withClip: NSZeroRect]; 412 break; 413 case NSImageFrameGroove: 414 [self drawGroove: frame withClip: NSZeroRect]; 415 break; 416 case NSImageFrameButton: 417 [self drawButton: frame withClip: NSZeroRect]; 418 break; 419 } 420 } 421 else 422 { 423 [self fillRect: frame 424 withTiles: tiles]; 425 } 426} 427 428- (NSSize) sizeForImageFrameStyle: (NSImageFrameStyle)frameStyle 429{ 430 // Get border size 431 switch (frameStyle) 432 { 433 case NSImageFrameNone: 434 default: 435 return NSZeroSize; 436 case NSImageFramePhoto: 437 // FIXME 438 return NSMakeSize(2, 2); 439 case NSImageFrameGrayBezel: 440 case NSImageFrameGroove: 441 case NSImageFrameButton: 442 return NSMakeSize(2, 2); 443 } 444} 445 446 447/* NSScroller themeing. 448 */ 449- (BOOL) scrollerArrowsSameEndForScroller: (NSScroller *)aScroller 450{ 451 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 452 453 if ([defs objectForKey: @"GSScrollerArrowsSameEnd"] != nil) 454 { 455 return [defs boolForKey: @"GSScrollerArrowsSameEnd"]; 456 } 457 else 458 { 459 NSInterfaceStyle interfaceStyle = 460 NSInterfaceStyleForKey(@"NSScrollerInterfaceStyle", aScroller); 461 462 if ((interfaceStyle == NSNextStepInterfaceStyle 463 || interfaceStyle == NSMacintoshInterfaceStyle 464 || interfaceStyle == GSWindowMakerInterfaceStyle)) 465 { 466 return YES; 467 } 468 else 469 { 470 return NO; 471 } 472 } 473} 474 475- (BOOL) scrollerScrollsByPageForScroller: (NSScroller *)aScroller 476{ 477 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 478 479 if ([defs objectForKey: @"GSScrollerScrollsByPage"] != nil) 480 { 481 return [defs boolForKey: @"GSScrollerScrollsByPage"]; 482 } 483 else 484 { 485 NSInterfaceStyle interfaceStyle = 486 NSInterfaceStyleForKey(@"NSScrollerInterfaceStyle", aScroller); 487 488 if (interfaceStyle == NSNextStepInterfaceStyle 489 || interfaceStyle == NSMacintoshInterfaceStyle 490 || interfaceStyle == GSWindowMakerInterfaceStyle) 491 { 492 /* NeXTstep style is to scroll to point. 493 */ 494 return NO; 495 } 496 else 497 { 498 /* Windows style is to scroll by a page. 499 */ 500 return YES; 501 } 502 } 503} 504 505- (NSButtonCell*) cellForScrollerArrow: (NSScrollerArrow)arrow 506 horizontal: (BOOL)horizontal 507{ 508 NSButtonCell *cell; 509 NSString *name; 510 511 cell = [NSButtonCell new]; 512 if (horizontal) 513 { 514 if (arrow == NSScrollerDecrementArrow) 515 { 516 [cell setHighlightsBy: 517 NSChangeBackgroundCellMask | NSContentsCellMask]; 518 [cell setImage: [NSImage imageNamed: @"common_ArrowLeft"]]; 519 [cell setAlternateImage: [NSImage imageNamed: @"common_ArrowLeftH"]]; 520 [cell setImagePosition: NSImageOnly]; 521 name = GSScrollerLeftArrow; 522 } 523 else 524 { 525 [cell setHighlightsBy: 526 NSChangeBackgroundCellMask | NSContentsCellMask]; 527 [cell setImage: [NSImage imageNamed: @"common_ArrowRight"]]; 528 [cell setAlternateImage: [NSImage imageNamed: @"common_ArrowRightH"]]; 529 [cell setImagePosition: NSImageOnly]; 530 name = GSScrollerRightArrow; 531 } 532 } 533 else 534 { 535 if (arrow == NSScrollerDecrementArrow) 536 { 537 [cell setHighlightsBy: 538 NSChangeBackgroundCellMask | NSContentsCellMask]; 539 [cell setImage: [NSImage imageNamed: @"common_ArrowUp"]]; 540 [cell setAlternateImage: [NSImage imageNamed: @"common_ArrowUpH"]]; 541 [cell setImagePosition: NSImageOnly]; 542 name = GSScrollerUpArrow; 543 } 544 else 545 { 546 [cell setHighlightsBy: 547 NSChangeBackgroundCellMask | NSContentsCellMask]; 548 [cell setImage: [NSImage imageNamed: @"common_ArrowDown"]]; 549 [cell setAlternateImage: [NSImage imageNamed: @"common_ArrowDownH"]]; 550 [cell setImagePosition: NSImageOnly]; 551 name = GSScrollerDownArrow; 552 } 553 } 554 [self setName: name forElement: cell temporary: YES]; 555 RELEASE(cell); 556 return cell; 557} 558 559- (NSCell*) cellForScrollerKnob: (BOOL)horizontal 560{ 561 NSButtonCell *cell; 562 563 cell = [NSButtonCell new]; 564 [cell setButtonType: NSMomentaryChangeButton]; 565 [cell setImagePosition: NSImageOnly]; 566 if (horizontal) 567 { 568 [self setName: GSScrollerHorizontalKnob forElement: cell temporary: YES]; 569 [cell setImage: [NSImage imageNamed: @"common_DimpleHoriz"]]; 570 } 571 else 572 { 573 [self setName: GSScrollerVerticalKnob forElement: cell temporary: YES]; 574 [cell setImage: [NSImage imageNamed: @"common_Dimple"]]; 575 576 } 577 RELEASE(cell); 578 return cell; 579} 580 581- (NSCell*) cellForScrollerKnobSlot: (BOOL)horizontal 582{ 583 GSDrawTiles *tiles; 584 NSButtonCell *cell; 585 NSColor *color; 586 NSString *name; 587 588 if (horizontal) 589 { 590 name = GSScrollerHorizontalSlot; 591 } 592 else 593 { 594 name = GSScrollerVerticalSlot; 595 } 596 597 tiles = [self tilesNamed: name state: GSThemeNormalState]; 598 color = [self colorNamed: name state: GSThemeNormalState]; 599 600 cell = [NSButtonCell new]; 601 [cell setBordered: (tiles != nil)]; 602 [cell setTitle: nil]; 603 604 [self setName: name forElement: cell temporary: YES]; 605 606 if (color == nil) 607 { 608 color = [NSColor scrollBarColor]; 609 } 610 [cell setBackgroundColor: color]; 611 RELEASE(cell); 612 return cell; 613} 614 615- (float) defaultScrollerWidth 616{ 617 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 618 float defaultScrollerWidth; 619 620 if ([defs objectForKey: @"GSScrollerDefaultWidth"] != nil) 621 { 622 defaultScrollerWidth = [defs floatForKey: @"GSScrollerDefaultWidth"]; 623 } 624 else 625 { 626 defaultScrollerWidth = 18.0; 627 } 628 return defaultScrollerWidth; 629} 630 631- (BOOL) scrollViewUseBottomCorner 632{ 633 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 634 if ([defs objectForKey: @"GSScrollViewUseBottomCorner"] != nil) 635 { 636 return [defs boolForKey: @"GSScrollViewUseBottomCorner"]; 637 } 638 return YES; 639} 640 641- (BOOL) scrollViewScrollersOverlapBorders 642{ 643 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 644 if ([defs objectForKey: @"GSScrollViewScrollersOverlapBorders"] != nil) 645 { 646 return [defs boolForKey: @"GSScrollViewScrollersOverlapBorders"]; 647 } 648 return NO; 649} 650 651- (NSColor *) toolbarBackgroundColor 652{ 653 NSColor *color; 654 655 color = [self colorNamed: @"toolbarBackgroundColor" 656 state: GSThemeNormalState]; 657 if (color == nil) 658 { 659 color = [NSColor clearColor]; 660 } 661 return color; 662} 663 664- (NSColor *) toolbarBorderColor 665{ 666 NSColor *color; 667 668 color = [self colorNamed: @"toolbarBorderColor" 669 state: GSThemeNormalState]; 670 if (color == nil) 671 { 672 color = [NSColor darkGrayColor]; 673 } 674 return color; 675} 676 677- (void) drawToolbarRect: (NSRect)aRect 678 frame: (NSRect)viewFrame 679 borderMask: (unsigned int)borderMask 680{ 681 // We draw the background 682 [[self toolbarBackgroundColor] set]; 683 [NSBezierPath fillRect: aRect]; 684 685 // We draw the border 686 [[self toolbarBorderColor] set]; 687 if (borderMask & GSToolbarViewBottomBorder) 688 { 689 [NSBezierPath strokeLineFromPoint: NSMakePoint(0, 0.5) 690 toPoint: NSMakePoint(viewFrame.size.width, 0.5)]; 691 } 692 if (borderMask & GSToolbarViewTopBorder) 693 { 694 [NSBezierPath strokeLineFromPoint: NSMakePoint(0, 695 viewFrame.size.height - 0.5) 696 toPoint: NSMakePoint(viewFrame.size.width, 697 viewFrame.size.height - 0.5)]; 698 } 699 if (borderMask & GSToolbarViewLeftBorder) 700 { 701 [NSBezierPath strokeLineFromPoint: NSMakePoint(0.5, 0) 702 toPoint: NSMakePoint(0.5, viewFrame.size.height)]; 703 } 704 if (borderMask & GSToolbarViewRightBorder) 705 { 706 [NSBezierPath strokeLineFromPoint: NSMakePoint(viewFrame.size.width - 0.5,0) 707 toPoint: NSMakePoint(viewFrame.size.width - 0.5, 708 viewFrame.size.height)]; 709 } 710} 711 712- (BOOL) toolbarIsOpaque 713{ 714 if ([[self toolbarBackgroundColor] alphaComponent] < 1.0) 715 { 716 return NO; 717 } 718 else 719 { 720 return YES; 721 } 722} 723 724- (NSRect) stepperUpButtonRectWithFrame: (NSRect)frame 725{ 726 NSSize size = [[NSImage imageNamed: @"common_StepperUp"] size]; 727 NSRect upRect = {{NSMinX(frame), NSMinY(frame)}, {size.width, size.height}}; 728 729 upRect.origin.x += ((int)frame.size.width / 2) - ((int)size.width / 2); 730 upRect.origin.y += ((int)frame.size.height / 2); 731 return upRect; 732} 733 734- (NSRect) stepperDownButtonRectWithFrame: (NSRect)frame 735{ 736 NSSize size = [[NSImage imageNamed: @"common_StepperDown"] size]; 737 NSRect downRect = {{NSMinX(frame), NSMinY(frame)}, {size.width, size.height}}; 738 739 downRect.origin.x += ((int)frame.size.width / 2) - ((int)size.width / 2); 740 downRect.origin.y += ((int)frame.size.height / 2) - size.height; 741 return downRect; 742} 743 744- (void) drawStepperBorder: (NSRect)frame 745{ 746} 747 748- (NSRect) drawStepperLightButton: (NSRect)border : (NSRect)clip 749{ 750 return NSZeroRect; 751} 752 753- (void) drawStepperUpButton: (NSRect)aRect 754{ 755 NSImage *image = [NSImage imageNamed: @"common_StepperUp"]; 756 [image drawInRect: aRect 757 fromRect: NSZeroRect 758 operation: NSCompositeSourceOver 759 fraction: 1 760 respectFlipped: YES 761 hints: nil]; 762} 763 764- (void) drawStepperHighlightUpButton: (NSRect)aRect 765{ 766 NSImage *image = [NSImage imageNamed: @"common_StepperUpHighlighted"]; 767 [image drawInRect: aRect 768 fromRect: NSZeroRect 769 operation: NSCompositeSourceOver 770 fraction: 1 771 respectFlipped: YES 772 hints: nil]; 773} 774 775- (void) drawStepperDownButton: (NSRect)aRect 776{ 777 NSImage *image = [NSImage imageNamed: @"common_StepperDown"]; 778 [image drawInRect: aRect 779 fromRect: NSZeroRect 780 operation: NSCompositeSourceOver 781 fraction: 1 782 respectFlipped: YES 783 hints: nil]; 784} 785 786- (void) drawStepperHighlightDownButton: (NSRect)aRect 787{ 788 NSImage *image = [NSImage imageNamed: @"common_StepperDownHighlighted"]; 789 [image drawInRect: aRect 790 fromRect: NSZeroRect 791 operation: NSCompositeSourceOver 792 fraction: 1 793 respectFlipped: YES 794 hints: nil]; 795} 796 797- (void) drawStepperCell: (NSCell*)cell 798 withFrame: (NSRect)cellFrame 799 inView: (NSView*)controlView 800 highlightUp: (BOOL)highlightUp 801 highlightDown: (BOOL)highlightDown 802{ 803 const NSRect upRect = [self stepperUpButtonRectWithFrame: cellFrame]; 804 const NSRect downRect = [self stepperDownButtonRectWithFrame: cellFrame]; 805 806 [self drawStepperBorder: cellFrame]; 807 808 if (highlightUp) 809 [self drawStepperHighlightUpButton: upRect]; 810 else 811 [self drawStepperUpButton: upRect]; 812 813 if (highlightDown) 814 [self drawStepperHighlightDownButton: downRect]; 815 else 816 [self drawStepperDownButton: downRect]; 817} 818 819// NSSegmentedControl drawing methods 820 821- (void) drawSegmentedControlSegment: (NSCell *)cell 822 withFrame: (NSRect)cellFrame 823 inView: (NSView *)controlView 824 style: (NSSegmentStyle)style 825 state: (GSThemeControlState)state 826 roundedLeft: (BOOL)roundedLeft 827 roundedRight: (BOOL)roundedRight 828{ 829 GSDrawTiles *tiles; 830 NSString *name = GSStringFromSegmentStyle(style); 831 if (roundedLeft) 832 { 833 name = [name stringByAppendingString: @"RoundedLeft"]; 834 } 835 if (roundedRight) 836 { 837 name = [name stringByAppendingString: @"RoundedRight"]; 838 } 839 840 tiles = [self tilesNamed: name state: state]; 841 842 if (tiles == nil) 843 { 844 [self drawButton: cellFrame 845 in: cell 846 view: controlView 847 style: NSRegularSquareBezelStyle 848 state: state]; 849 } 850 else 851 { 852 [self fillRect: cellFrame 853 withTiles: tiles]; 854 } 855} 856 857- (NSColor *) menuBackgroundColor 858{ 859 NSColor *color = [self colorNamed: @"menuBackgroundColor" 860 state: GSThemeNormalState]; 861 if (color == nil) 862 { 863 color = [NSColor windowBackgroundColor]; 864 } 865 return color; 866} 867 868- (NSColor *) menuItemBackgroundColor 869{ 870 NSColor *color = [self colorNamed: @"menuItemBackgroundColor" 871 state: GSThemeNormalState]; 872 if (color == nil) 873 { 874 color = [NSColor controlBackgroundColor]; 875 } 876 return color; 877} 878 879- (NSColor *) menuBorderColor 880{ 881 NSColor *color = [self colorNamed: @"menuBorderColor" 882 state: GSThemeNormalState]; 883 if (color == nil) 884 { 885 color = [NSColor darkGrayColor]; 886 } 887 return color; 888} 889 890- (NSColor *) menuBarBackgroundColor 891{ 892 NSColor *color = [self colorNamed: @"menuBarBackgroundColor" 893 state: GSThemeNormalState]; 894 if (color == nil) 895 { 896 color = [self menuBackgroundColor]; 897 } 898 return color; 899} 900 901- (NSColor *) menuBarBorderColor 902{ 903 NSColor *color = [self colorNamed: @"menuBarBorderColor" 904 state: GSThemeNormalState]; 905 if (color == nil) 906 { 907 color = [self menuBorderColor]; 908 } 909 return color; 910} 911 912- (NSColor *) menuBorderColorForEdge: (NSRectEdge)edge isHorizontal: (BOOL)horizontal 913{ 914 if (horizontal && edge == NSMinYEdge) 915 { 916 return [self menuBorderColor]; 917 } 918 else if (edge == NSMinXEdge || edge == NSMaxYEdge) 919 { 920 // Draw the dark gray upper left lines. 921 return [self menuBorderColor]; 922 } 923 return nil; 924} 925 926- (void) drawBackgroundForMenuView: (NSMenuView*)menuView 927 withFrame: (NSRect)bounds 928 dirtyRect: (NSRect)dirtyRect 929 horizontal: (BOOL)horizontal 930{ 931 NSString *name = horizontal ? GSMenuHorizontalBackground : 932 GSMenuVerticalBackground; 933 GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState]; 934 935 if (tiles == nil) 936 { 937 NSRectEdge sides[4] = { NSMinXEdge, NSMaxYEdge, NSMaxXEdge, NSMinYEdge }; 938 NSColor *colors[] = {[self menuBorderColorForEdge: NSMinXEdge isHorizontal: horizontal], 939 [self menuBorderColorForEdge: NSMaxYEdge isHorizontal: horizontal], 940 [self menuBorderColorForEdge: NSMaxXEdge isHorizontal: horizontal], 941 [self menuBorderColorForEdge: NSMinYEdge isHorizontal: horizontal]}; 942 943 [[self menuBackgroundColor] set]; 944 NSRectFill(NSIntersectionRect(bounds, dirtyRect)); 945 NSDrawColorTiledRects(bounds, dirtyRect, sides, colors, 4); 946 } 947 else 948 { 949 [self fillRect: bounds 950 withTiles: tiles]; 951 } 952} 953 954- (BOOL) drawsBorderForMenuItemCell: (NSMenuItemCell *)cell 955 state: (GSThemeControlState)state 956 isHorizontal: (BOOL)horizontal 957{ 958 return [cell isBordered]; 959} 960 961- (void) drawBorderAndBackgroundForMenuItemCell: (NSMenuItemCell *)cell 962 withFrame: (NSRect)cellFrame 963 inView: (NSView *)controlView 964 state: (GSThemeControlState)state 965 isHorizontal: (BOOL)isHorizontal 966{ 967 NSString *name = isHorizontal ? GSMenuHorizontalItem : 968 GSMenuVerticalItem; 969 GSDrawTiles *tiles = [self tilesNamed: name state: state]; 970 971 if (tiles == nil) 972 { 973 NSColor *backgroundColor = [cell backgroundColor]; 974 975 if (isHorizontal) 976 { 977 cellFrame = [cell drawingRectForBounds: cellFrame]; 978 [backgroundColor set]; 979 NSRectFill(cellFrame); 980 return; 981 } 982 983 // Set cell's background color 984 [backgroundColor set]; 985 NSRectFill(cellFrame); 986 987 if (![self drawsBorderForMenuItemCell: cell 988 state: state 989 isHorizontal: isHorizontal]) 990 { 991 return; 992 } 993 994 if (state == GSThemeSelectedState) 995 { 996 [self drawGrayBezel: cellFrame withClip: NSZeroRect]; 997 } 998 else 999 { 1000 [self drawButton: cellFrame withClip: NSZeroRect]; 1001 } 1002 } 1003 else 1004 { 1005 [self fillRect: cellFrame 1006 withTiles: tiles]; 1007 } 1008} 1009 1010- (NSColor *) menuSeparatorColor 1011{ 1012 NSColor *color = [self colorNamed: @"menuSeparatorColor" 1013 state: GSThemeNormalState]; 1014 NSInterfaceStyle style = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil); 1015 1016 // TODO: Remove the style check... Windows theming should be in a subclass 1017 // probably 1018 if (color == nil && style == NSWindows95InterfaceStyle) 1019 { 1020 color = [NSColor blackColor]; 1021 } 1022 return color; 1023} 1024 1025- (CGFloat) menuSeparatorInset 1026{ 1027 return 3.0; 1028} 1029 1030- (CGFloat) menuSubmenuHorizontalOverlap 1031{ 1032 return [[NSUserDefaults standardUserDefaults] 1033 floatForKey: @"GSMenuSubmenuHorizontalOverlap"]; 1034} 1035 1036- (CGFloat) menuSubmenuVerticalOverlap 1037{ 1038 return [[NSUserDefaults standardUserDefaults] 1039 floatForKey: @"GSMenuSubmenuVerticalOverlap"]; 1040} 1041 1042- (void) drawSeparatorItemForMenuItemCell: (NSMenuItemCell *)cell 1043 withFrame: (NSRect)cellFrame 1044 inView: (NSView *)controlView 1045 isHorizontal: (BOOL)isHorizontal 1046{ 1047 GSDrawTiles *tiles; 1048 1049 tiles = [self tilesNamed: GSMenuSeparatorItem state: GSThemeNormalState]; 1050 if (tiles == nil) 1051 { 1052 NSBezierPath *path = [NSBezierPath bezierPath]; 1053 CGFloat inset = [self menuSeparatorInset]; 1054 NSPoint start = NSMakePoint(inset, cellFrame.size.height / 2 + 1055 cellFrame.origin.y + 0.5); 1056 NSPoint end = NSMakePoint(cellFrame.size.width - inset, 1057 cellFrame.size.height / 2 + cellFrame.origin.y + 0.5); 1058 1059 [[self menuSeparatorColor] set]; 1060 1061 [path setLineWidth: 0.0]; 1062 [path moveToPoint: start]; 1063 [path lineToPoint: end]; 1064 1065 [path stroke]; 1066 } 1067 else 1068 { 1069 [self fillRect: cellFrame 1070 withTiles: tiles]; 1071 } 1072} 1073 1074- (void) drawTitleForMenuItemCell: (NSMenuItemCell *)cell 1075 withFrame: (NSRect)cellFrame 1076 inView: (NSView *)controlView 1077 state: (GSThemeControlState)state 1078 isHorizontal: (BOOL)isHorizontal 1079{ 1080 [cell _drawText: [[cell menuItem] title] 1081 inFrame: [cell titleRectForBounds: cellFrame]]; 1082} 1083 1084- (Class) titleViewClassForMenuView: (NSMenuView *)aMenuView 1085{ 1086 return [GSTitleView class]; 1087} 1088 1089- (NSRect) drawMenuTitleBackground: (GSTitleView *)aTitleView 1090 withBounds: (NSRect)bounds 1091 withClip: (NSRect)clipRect 1092{ 1093 GSDrawTiles *tiles = [self tilesNamed: GSMenuTitleBackground state: GSThemeNormalState]; 1094 1095 if (tiles == nil) 1096 { 1097 NSRect workRect = bounds; 1098 NSRectEdge top_left[] = {NSMinXEdge, NSMaxYEdge}; 1099 CGFloat darkGrays[] = {NSDarkGray, NSDarkGray}; 1100 NSColor *titleColor; 1101 1102 titleColor = [self colorNamed: @"GSMenuBar" state: GSThemeNormalState]; 1103 if (titleColor == nil) 1104 { 1105 titleColor = [NSColor blackColor]; 1106 } 1107 1108 // Draw the dark gray upper left lines for menu and black for others. 1109 // Rectangle 1 1110 workRect = NSDrawTiledRects(workRect, workRect, top_left, darkGrays, 2); 1111 1112 // Rectangle 2 1113 // Draw the title box's button. 1114 [self drawButton: workRect withClip: workRect]; 1115 1116 // Overdraw white top and left lines with light gray lines for window title 1117 workRect.origin.y += 1; 1118 workRect.size.height -= 1; 1119 workRect.size.width -= 1; 1120 1121 // Rectangle 3 1122 // Paint background 1123 workRect.origin.x += 1; 1124 workRect.origin.y += 1; 1125 workRect.size.height -= 2; 1126 workRect.size.width -= 2; 1127 1128 [titleColor set]; 1129 NSRectFill(workRect); 1130 1131 return workRect; 1132 } 1133 else 1134 { 1135 return [self fillRect: bounds 1136 withTiles: tiles]; 1137 } 1138} 1139 1140- (CGFloat) menuBarHeight 1141{ 1142 CGFloat height = [[NSUserDefaults standardUserDefaults] 1143 floatForKey: @"GSMenuBarHeight"]; 1144 if (height <= 0) 1145 { 1146 return 22; 1147 } 1148 return height; 1149} 1150 1151- (CGFloat) menuItemHeight 1152{ 1153 CGFloat height = [[NSUserDefaults standardUserDefaults] 1154 floatForKey: @"GSMenuItemHeight"]; 1155 if (height <= 0) 1156 { 1157 return 20; 1158 } 1159 return height; 1160} 1161 1162- (CGFloat) menuSeparatorHeight 1163{ 1164 CGFloat height = [[NSUserDefaults standardUserDefaults] 1165 floatForKey: @"GSMenuSeparatorHeight"]; 1166 if (height <= 0) 1167 { 1168 return 20; 1169 } 1170 return height; 1171} 1172 1173// NSColorWell drawing method 1174- (NSRect) drawColorWellBorder: (NSColorWell*)well 1175 withBounds: (NSRect)bounds 1176 withClip: (NSRect)clipRect 1177{ 1178 NSRect aRect = bounds; 1179 1180 if ([well isBordered]) 1181 { 1182 GSThemeControlState state; 1183 GSDrawTiles *tiles; 1184 1185 if ([[well cell] isHighlighted] || [well isActive]) 1186 { 1187 state = GSThemeHighlightedState; 1188 } 1189 else 1190 { 1191 state = GSThemeNormalState; 1192 } 1193 1194 tiles = [self tilesNamed: GSColorWell state: state]; 1195 if (tiles == nil) 1196 { 1197 /* 1198 * Draw border. 1199 */ 1200 [self drawButton: aRect withClip: clipRect]; 1201 1202 /* 1203 * Fill in control color. 1204 */ 1205 if (state == GSThemeHighlightedState) 1206 { 1207 [[NSColor selectedControlColor] set]; 1208 } 1209 else 1210 { 1211 [[NSColor controlColor] set]; 1212 } 1213 aRect = NSInsetRect(aRect, 2.0, 2.0); 1214 NSRectFill(NSIntersectionRect(aRect, clipRect)); 1215 } 1216 else 1217 { 1218 aRect = [self fillRect: aRect 1219 withTiles: tiles]; 1220 } 1221 1222 /* 1223 * Set an inset rect for the color area 1224 */ 1225 aRect = NSInsetRect(bounds, COLOR_WELL_BORDER_WIDTH, COLOR_WELL_BORDER_WIDTH); 1226 } 1227 1228 /* 1229 * OpenStep 4.2 behavior is to omit the inner border for 1230 * non-enabled NSColorWell objects. 1231 */ 1232 if ([well isEnabled]) 1233 { 1234 GSDrawTiles *tiles = [self tilesNamed: GSColorWellInnerBorder state: GSThemeNormalState]; 1235 if (tiles == nil) 1236 { 1237 /* 1238 * Draw inner frame. 1239 */ 1240 [self drawGrayBezel: aRect withClip: clipRect]; 1241 aRect = NSInsetRect(aRect, 2.0, 2.0); 1242 } 1243 else 1244 { 1245 [self fillRect: aRect 1246 withTiles: tiles]; 1247 1248 aRect = [tiles contentRectForRect: aRect isFlipped: [well isFlipped]]; 1249 } 1250 } 1251 1252 return aRect; 1253} 1254 1255// progress indicator drawing methods 1256static NSColor *fillColour = nil; 1257#define MaxCount 10 1258static int indeterminateMaxCount = MaxCount; 1259static int spinningMaxCount = MaxCount; 1260static NSColor *indeterminateColors[MaxCount]; 1261static NSImage *spinningImages[MaxCount]; 1262 1263- (void) initProgressIndicatorDrawing 1264{ 1265 int i; 1266 1267 // FIXME: Should come from defaults and should be reset when defaults change 1268 // FIXME: Should probably get the color from the color extension list (see NSToolbar) 1269 fillColour = RETAIN([NSColor controlShadowColor]); 1270 1271 // Load images for indeterminate style 1272 for (i = 0; i < MaxCount; i++) 1273 { 1274 NSString *imgName = [NSString stringWithFormat: @"common_ProgressIndeterminate_%d", i + 1]; 1275 NSImage *image = [NSImage imageNamed: imgName]; 1276 1277 if (image == nil) 1278 { 1279 indeterminateMaxCount = i; 1280 break; 1281 } 1282 indeterminateColors[i] = RETAIN([NSColor colorWithPatternImage: image]); 1283 } 1284 1285 // Load images for spinning style 1286 for (i = 0; i < MaxCount; i++) 1287 { 1288 NSString *imgName = [NSString stringWithFormat: @"common_ProgressSpinning_%d", i + 1]; 1289 NSImage *image = [NSImage imageNamed: imgName]; 1290 1291 if (image == nil) 1292 { 1293 spinningMaxCount = i; 1294 break; 1295 } 1296 spinningImages[i] = RETAIN(image); 1297 } 1298} 1299 1300- (void) drawProgressIndicator: (NSProgressIndicator*)progress 1301 withBounds: (NSRect)bounds 1302 withClip: (NSRect)rect 1303 atCount: (int)count 1304 forValue: (double)val 1305{ 1306 NSRect r; 1307 1308 if (fillColour == nil) 1309 { 1310 [self initProgressIndicatorDrawing]; 1311 } 1312 1313 // Draw the Bezel 1314 if ([progress isBezeled]) 1315 { 1316 // Calc the inside rect to be drawn 1317 r = [self drawProgressIndicatorBezel: bounds withClip: rect]; 1318 } 1319 else 1320 { 1321 r = bounds; 1322 } 1323 1324 if ([progress style] == NSProgressIndicatorSpinningStyle) 1325 { 1326 NSRect imgBox = {{0,0}, {0,0}}; 1327 1328 if (spinningMaxCount != 0) 1329 { 1330 count = count % spinningMaxCount; 1331 imgBox.size = [spinningImages[count] size]; 1332 [spinningImages[count] drawInRect: r 1333 fromRect: imgBox 1334 operation: NSCompositeSourceOver 1335 fraction: 1.0]; 1336 } 1337 } 1338 else 1339 { 1340 if ([progress isIndeterminate]) 1341 { 1342 if (indeterminateMaxCount != 0) 1343 { 1344 count = count % indeterminateMaxCount; 1345 [indeterminateColors[count] set]; 1346 NSRectFill(r); 1347 } 1348 } 1349 else 1350 { 1351 // Draw determinate 1352 if ([progress isVertical]) 1353 { 1354 float height = NSHeight(r) * val; 1355 1356 if ([progress isFlipped]) 1357 { 1358 // Compensate for the flip 1359 r.origin.y += NSHeight(r) - height; 1360 } 1361 r.size.height = height; 1362 } 1363 else 1364 { 1365 r.size.width = NSWidth(r) * val; 1366 } 1367 r = NSIntersectionRect(r, rect); 1368 if (!NSIsEmptyRect(r)) 1369 { 1370 [self drawProgressIndicatorBarDeterminate: (NSRect)r]; 1371 } 1372 } 1373 } 1374} 1375 1376- (NSRect) drawProgressIndicatorBezel: (NSRect)bounds withClip: (NSRect) rect 1377{ 1378 GSDrawTiles *tiles = [self tilesNamed: GSProgressIndicatorBezel 1379 state: GSThemeNormalState]; 1380 1381 if (tiles == nil) 1382 { 1383 return [self drawGrayBezel: bounds withClip: rect]; 1384 } 1385 else 1386 { 1387 [self fillRect: bounds 1388 withTiles: tiles]; 1389 1390 return [tiles contentRectForRect: bounds 1391 isFlipped: [[NSView focusView] isFlipped]]; 1392 } 1393} 1394 1395- (void) drawProgressIndicatorBarDeterminate: (NSRect)bounds 1396{ 1397 GSDrawTiles *tiles = [self tilesNamed: GSProgressIndicatorBarDeterminate 1398 state: GSThemeNormalState]; 1399 1400 if (tiles == nil) 1401 { 1402 [fillColour set]; 1403 NSRectFill(bounds); 1404 } 1405 else 1406 { 1407 [self fillRect: bounds 1408 withTiles: tiles 1409 background: fillColour]; 1410 } 1411} 1412 1413// Table drawing methods 1414 1415- (NSColor *) tableHeaderTextColorForState: (GSThemeControlState)state 1416{ 1417 NSColor *color; 1418 1419 color = [self colorNamed: @"tableHeaderTextColor" 1420 state: state]; 1421 if (color == nil) 1422 { 1423 if (state == GSThemeHighlightedState) 1424 color = [NSColor controlTextColor]; 1425 else 1426 color = [NSColor windowFrameTextColor]; 1427 } 1428 return color; 1429} 1430 1431- (void) drawTableCornerView: (NSView*)cornerView 1432 withClip: (NSRect)aRect 1433{ 1434 NSRect divide; 1435 NSRect rect; 1436 GSDrawTiles *tiles = [self tilesNamed: GSTableCorner state: GSThemeNormalState]; 1437 1438 if ([cornerView isFlipped]) 1439 { 1440 NSDivideRect(aRect, ÷, &rect, 1.0, NSMaxYEdge); 1441 } 1442 else 1443 { 1444 NSDivideRect(aRect, ÷, &rect, 1.0, NSMinYEdge); 1445 } 1446 1447 if (tiles == nil) 1448 { 1449 rect = [self drawDarkButton: rect withClip: aRect]; 1450 [[NSColor controlShadowColor] set]; 1451 NSRectFill(rect); 1452 } 1453 else 1454 { 1455 [self fillRect: aRect 1456 withTiles: tiles]; 1457 } 1458} 1459 1460- (void) drawTableHeaderCell: (NSTableHeaderCell *)cell 1461 withFrame: (NSRect)cellFrame 1462 inView: (NSView *)controlView 1463 state: (GSThemeControlState)state 1464{ 1465 GSDrawTiles *tiles = [self tilesNamed: GSTableHeader state: state]; 1466 1467 if (tiles == nil) 1468 { 1469 NSRect rect; 1470 1471 // Leave a 1pt thick horizontal line underneath the header 1472 if (![controlView isFlipped]) 1473 { 1474 cellFrame.origin.y++; 1475 } 1476 cellFrame.size.height--; 1477 1478 if (state == GSThemeHighlightedState) 1479 { 1480 rect = [self drawButton: cellFrame withClip: cellFrame]; 1481 [[NSColor controlColor] set]; 1482 NSRectFill(rect); 1483 } 1484 else 1485 { 1486 rect = [self drawDarkButton: cellFrame withClip: cellFrame]; 1487 [[NSColor controlShadowColor] set]; 1488 NSRectFill(rect); 1489 } 1490 } 1491 else 1492 { 1493 [self fillRect: cellFrame 1494 withTiles: tiles]; 1495 } 1496} 1497 1498 1499// Window decoration drawing methods 1500/* These include the black border. */ 1501#define TITLE_HEIGHT 23.0 1502#define RESIZE_HEIGHT 9.0 1503#define TITLEBAR_BUTTON_SIZE 15.0 1504#define TITLEBAR_PADDING_TOP 4.0 1505#define TITLEBAR_PADDING_RIGHT 4.0 1506#define TITLEBAR_PADDING_LEFT 4.0 1507 1508- (float) titlebarHeight 1509{ 1510 return TITLE_HEIGHT; 1511} 1512 1513- (float) resizebarHeight 1514{ 1515 return RESIZE_HEIGHT; 1516} 1517 1518- (float) titlebarButtonSize 1519{ 1520 return TITLEBAR_BUTTON_SIZE; 1521} 1522 1523- (float) titlebarPaddingRight 1524{ 1525 return TITLEBAR_PADDING_RIGHT; 1526} 1527 1528- (float) titlebarPaddingTop 1529{ 1530 return TITLEBAR_PADDING_TOP; 1531} 1532 1533- (float) titlebarPaddingLeft 1534{ 1535 return TITLEBAR_PADDING_LEFT; 1536} 1537 1538static NSDictionary *titleTextAttributes[3] = {nil, nil, nil}; 1539 1540- (void) drawTitleBarRect: (NSRect)titleBarRect 1541 forStyleMask: (unsigned int)styleMask 1542 state: (int)inputState 1543 andTitle: (NSString*)title 1544{ 1545 static const NSRectEdge edges[4] = {NSMinXEdge, NSMaxYEdge, 1546 NSMaxXEdge, NSMinYEdge}; 1547 CGFloat grays[3][4] = 1548 {{NSLightGray, NSLightGray, NSDarkGray, NSDarkGray}, 1549 {NSWhite, NSWhite, NSDarkGray, NSDarkGray}, 1550 {NSLightGray, NSLightGray, NSBlack, NSBlack}}; 1551 NSRect workRect; 1552 GSDrawTiles *tiles = nil; 1553 1554 if (!titleTextAttributes[0]) 1555 { 1556 NSMutableParagraphStyle *p; 1557 NSColor *keyColor, *normalColor, *mainColor; 1558 1559 p = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; 1560 [p setLineBreakMode: NSLineBreakByClipping]; 1561 1562 // FIXME: refine color names based on style mask 1563 // (HUD or textured or regular window) 1564 1565 keyColor = [self colorNamed: @"keyWindowFrameTextColor" 1566 state: GSThemeNormalState]; 1567 if (nil == keyColor) 1568 { 1569 keyColor = [NSColor windowFrameTextColor]; 1570 } 1571 1572 normalColor = [self colorNamed: @"normalWindowFrameTextColor" 1573 state: GSThemeNormalState]; 1574 if (nil == normalColor) 1575 { 1576 normalColor = [NSColor blackColor]; 1577 } 1578 1579 mainColor = [self colorNamed: @"mainWindowFrameTextColor" 1580 state: GSThemeNormalState]; 1581 if (nil == mainColor) 1582 { 1583 mainColor = [NSColor windowFrameTextColor]; 1584 } 1585 1586 titleTextAttributes[0] = [[NSMutableDictionary alloc] 1587 initWithObjectsAndKeys: 1588 [NSFont titleBarFontOfSize: 0], NSFontAttributeName, 1589 keyColor, NSForegroundColorAttributeName, 1590 p, NSParagraphStyleAttributeName, 1591 nil]; 1592 1593 titleTextAttributes[1] = [[NSMutableDictionary alloc] 1594 initWithObjectsAndKeys: 1595 [NSFont titleBarFontOfSize: 0], NSFontAttributeName, 1596 normalColor, NSForegroundColorAttributeName, 1597 p, NSParagraphStyleAttributeName, 1598 nil]; 1599 1600 titleTextAttributes[2] = [[NSMutableDictionary alloc] 1601 initWithObjectsAndKeys: 1602 [NSFont titleBarFontOfSize: 0], NSFontAttributeName, 1603 mainColor, NSForegroundColorAttributeName, 1604 p, NSParagraphStyleAttributeName, 1605 nil]; 1606 1607 RELEASE(p); 1608 } 1609 1610 tiles = [self tilesNamed: @"GSWindowTitleBar" state: GSThemeNormalState]; 1611 if (tiles == nil) 1612 { 1613 /* 1614 Draw the black border towards the rest of the window. (The outer black 1615 border is drawn in -drawRect: since it might be drawn even if we don't have 1616 a title bar. 1617 */ 1618 NSColor *borderColor = [self colorNamed: @"windowBorderColor" 1619 state: GSThemeNormalState]; 1620 if (nil == borderColor) 1621 { 1622 borderColor = [NSColor blackColor]; 1623 } 1624 [borderColor set]; 1625 1626 PSmoveto(0, NSMinY(titleBarRect) + 0.5); 1627 PSrlineto(titleBarRect.size.width, 0); 1628 PSstroke(); 1629 1630 /* 1631 Draw the button-like border. 1632 */ 1633 workRect = titleBarRect; 1634 workRect.origin.x += 1; 1635 workRect.origin.y += 1; 1636 workRect.size.width -= 2; 1637 workRect.size.height -= 2; 1638 1639 workRect = NSDrawTiledRects(workRect, workRect, edges, grays[inputState], 4); 1640 1641 /* 1642 Draw the background. 1643 */ 1644 switch (inputState) 1645 { 1646 default: 1647 case 0: 1648 [[NSColor windowFrameColor] set]; 1649 break; 1650 case 1: 1651 [[NSColor lightGrayColor] set]; 1652 break; 1653 case 2: 1654 [[NSColor darkGrayColor] set]; 1655 break; 1656 } 1657 NSRectFill(workRect); 1658 } 1659 else 1660 { 1661 [self fillRect: titleBarRect 1662 withTiles: tiles 1663 background: [NSColor windowFrameColor]]; 1664 workRect = titleBarRect; 1665 } 1666 /* Draw the title. */ 1667 if (styleMask & NSTitledWindowMask) 1668 { 1669 NSSize titleSize; 1670 1671 if (styleMask & NSMiniaturizableWindowMask) 1672 { 1673 workRect.origin.x += 17; 1674 workRect.size.width -= 17; 1675 } 1676 if (styleMask & NSClosableWindowMask) 1677 { 1678 workRect.size.width -= 17; 1679 } 1680 1681 titleSize = [title sizeWithAttributes: titleTextAttributes[inputState]]; 1682 if (titleSize.width <= workRect.size.width) 1683 workRect.origin.x = NSMidX(workRect) - titleSize.width / 2; 1684 workRect.origin.y = NSMidY(workRect) - titleSize.height / 2; 1685 workRect.size.height = titleSize.height; 1686 [title drawInRect: workRect 1687 withAttributes: titleTextAttributes[inputState]]; 1688 } 1689} 1690 1691// FIXME: Would be good if this took the window as a param 1692- (void) drawResizeBarRect: (NSRect)resizeBarRect 1693{ 1694 GSDrawTiles *tiles; 1695 tiles = [self tilesNamed: @"GSWindowResizeBar" state: GSThemeNormalState]; 1696 if (tiles == nil) 1697 { 1698 [[NSColor lightGrayColor] set]; 1699 PSrectfill(1.0, 1.0, resizeBarRect.size.width - 2.0, RESIZE_HEIGHT - 3.0); 1700 1701 PSsetlinewidth(1.0); 1702 1703 [[NSColor blackColor] set]; 1704 PSmoveto(0.0, 0.5); 1705 PSlineto(resizeBarRect.size.width, 0.5); 1706 PSstroke(); 1707 1708 [[NSColor darkGrayColor] set]; 1709 PSmoveto(1.0, RESIZE_HEIGHT - 0.5); 1710 PSlineto(resizeBarRect.size.width - 1.0, RESIZE_HEIGHT - 0.5); 1711 PSstroke(); 1712 1713 [[NSColor whiteColor] set]; 1714 PSmoveto(1.0, RESIZE_HEIGHT - 1.5); 1715 PSlineto(resizeBarRect.size.width - 1.0, RESIZE_HEIGHT - 1.5); 1716 PSstroke(); 1717 1718 1719 /* Only draw the notches if there's enough space. */ 1720 if (resizeBarRect.size.width < 30 * 2) 1721 return; 1722 1723 [[NSColor darkGrayColor] set]; 1724 PSmoveto(27.5, 1.0); 1725 PSlineto(27.5, RESIZE_HEIGHT - 2.0); 1726 PSmoveto(resizeBarRect.size.width - 28.5, 1.0); 1727 PSlineto(resizeBarRect.size.width - 28.5, RESIZE_HEIGHT - 2.0); 1728 PSstroke(); 1729 1730 [[NSColor whiteColor] set]; 1731 PSmoveto(28.5, 1.0); 1732 PSlineto(28.5, RESIZE_HEIGHT - 2.0); 1733 PSmoveto(resizeBarRect.size.width - 27.5, 1.0); 1734 PSlineto(resizeBarRect.size.width - 27.5, RESIZE_HEIGHT - 2.0); 1735 PSstroke(); 1736 } 1737 else 1738 { 1739 [self fillRect: resizeBarRect 1740 withTiles: tiles]; 1741 } 1742} 1743 1744- (void) drawWindowBorder: (NSRect)rect 1745 withFrame: (NSRect)frame 1746 forStyleMask: (unsigned int)styleMask 1747 state: (int)inputState 1748 andTitle: (NSString*)title 1749{ 1750 if (styleMask & (NSTitledWindowMask | NSClosableWindowMask 1751 | NSMiniaturizableWindowMask)) 1752 { 1753 NSRect titleBarRect; 1754 1755 titleBarRect = NSMakeRect(0.0, frame.size.height - TITLE_HEIGHT, 1756 frame.size.width, TITLE_HEIGHT); 1757 if (NSIntersectsRect(rect, titleBarRect)) 1758 [self drawTitleBarRect: titleBarRect 1759 forStyleMask: styleMask 1760 state: inputState 1761 andTitle: title]; 1762 } 1763 1764 if (styleMask & NSResizableWindowMask) 1765 { 1766 NSRect resizeBarRect; 1767 1768 resizeBarRect = NSMakeRect(0.0, 0.0, frame.size.width, RESIZE_HEIGHT); 1769 if (NSIntersectsRect(rect, resizeBarRect)) 1770 [self drawResizeBarRect: resizeBarRect]; 1771 } 1772 1773 if (styleMask & (NSTitledWindowMask | NSClosableWindowMask 1774 | NSMiniaturizableWindowMask | NSResizableWindowMask)) 1775 { 1776 NSColor *borderColor = [self colorNamed: @"windowBorderColor" 1777 state: GSThemeNormalState]; 1778 if (nil == borderColor) 1779 { 1780 borderColor = [NSColor blackColor]; 1781 } 1782 [borderColor set]; 1783 PSsetlinewidth(1.0); 1784 if (NSMinX(rect) < 1.0) 1785 { 1786 PSmoveto(0.5, 0.0); 1787 PSlineto(0.5, frame.size.height); 1788 PSstroke(); 1789 } 1790 if (NSMaxX(rect) > frame.size.width - 1.0) 1791 { 1792 PSmoveto(frame.size.width - 0.5, 0.0); 1793 PSlineto(frame.size.width - 0.5, frame.size.height); 1794 PSstroke(); 1795 } 1796 if (NSMaxY(rect) > frame.size.height - 1.0) 1797 { 1798 PSmoveto(0.0, frame.size.height - 0.5); 1799 PSlineto(frame.size.width, frame.size.height - 0.5); 1800 PSstroke(); 1801 } 1802 if (NSMinY(rect) < 1.0) 1803 { 1804 PSmoveto(0.0, 0.5); 1805 PSlineto(frame.size.width, 0.5); 1806 PSstroke(); 1807 } 1808 } 1809} 1810 1811- (NSColor *) browserHeaderTextColor 1812{ 1813 NSColor *color; 1814 1815 color = [self colorNamed: @"browserHeaderTextColor" 1816 state: GSThemeNormalState]; 1817 if (color == nil) 1818 { 1819 color = [NSColor windowFrameTextColor]; 1820 } 1821 return color; 1822} 1823 1824- (void) drawBrowserHeaderCell: (NSTableHeaderCell*)cell 1825 withFrame: (NSRect)rect 1826 inView: (NSView*)view; 1827{ 1828 GSDrawTiles *tiles; 1829 tiles = [self tilesNamed: GSBrowserHeader state: GSThemeNormalState]; 1830 if (tiles == nil) 1831 { 1832 [self drawGrayBezel: rect withClip: NSZeroRect]; 1833 [cell _drawBackgroundWithFrame: rect inView: view]; 1834 } 1835 else 1836 { 1837 [self fillRect: rect 1838 withTiles: tiles]; 1839 } 1840} 1841 1842- (NSRect) browserHeaderDrawingRectForCell: (NSTableHeaderCell*)cell 1843 withFrame: (NSRect)rect 1844{ 1845 GSDrawTiles *tiles; 1846 tiles = [self tilesNamed: GSBrowserHeader state: GSThemeNormalState]; 1847 if (tiles == nil) 1848 { 1849 return NSInsetRect(rect, 2, 2); 1850 } 1851 else 1852 { 1853 const BOOL flipped = [[cell controlView] isFlipped]; 1854 NSRect result = [tiles contentRectForRect: rect 1855 isFlipped: flipped]; 1856 return result; 1857 } 1858} 1859 1860typedef enum { 1861 GSTabSelectedLeft, 1862 GSTabSelectedRight, 1863 GSTabSelectedToUnSelectedJunction, 1864 GSTabSelectedFill, 1865 GSTabUnSelectedLeft, 1866 GSTabUnSelectedRight, 1867 GSTabUnSelectedToSelectedJunction, 1868 GSTabUnSelectedJunction, 1869 GSTabUnSelectedFill, 1870 GSTabBackgroundFill 1871} GSTabPart; 1872 1873- (NSImage *)imageForTabPart: (GSTabPart)part type: (NSTabViewType)type 1874{ 1875 NSMutableString *imageName = [NSMutableString stringWithCapacity: 32]; 1876 NSString *typeString = nil; 1877 NSString *partString = nil; 1878 1879 switch (type) 1880 { 1881 case NSTopTabsBezelBorder: 1882 typeString = @""; 1883 break; 1884 case NSBottomTabsBezelBorder: 1885 typeString = @"Down"; 1886 break; 1887 case NSLeftTabsBezelBorder: 1888 typeString = @"Left"; 1889 break; 1890 case NSRightTabsBezelBorder: 1891 typeString = @"Right"; 1892 break; 1893 default: 1894 return nil; 1895 } 1896 1897 switch (part) 1898 { 1899 case GSTabSelectedLeft: 1900 partString = @"SelectedLeft"; 1901 break; 1902 case GSTabSelectedRight: 1903 partString = @"SelectedRight"; 1904 break; 1905 case GSTabSelectedToUnSelectedJunction: 1906 partString = @"SelectedToUnSelectedJunction"; 1907 break; 1908 case GSTabSelectedFill: 1909 return nil; 1910 case GSTabUnSelectedLeft: 1911 partString = @"UnSelectedLeft"; 1912 break; 1913 case GSTabUnSelectedRight: 1914 partString = @"UnSelectedRight"; 1915 break; 1916 case GSTabUnSelectedToSelectedJunction: 1917 partString = @"UnSelectedToSelectedJunction"; 1918 break; 1919 case GSTabUnSelectedJunction: 1920 partString = @"UnSelectedJunction"; 1921 break; 1922 case GSTabUnSelectedFill: 1923 case GSTabBackgroundFill: 1924 return nil; 1925 } 1926 1927 [imageName appendString: @"common_Tab"]; 1928 [imageName appendString: typeString]; 1929 [imageName appendString: partString]; 1930 1931 return [NSImage imageNamed: imageName]; 1932} 1933 1934- (GSDrawTiles *)tilesForTabPart: (GSTabPart)part type: (NSTabViewType)type 1935{ 1936 NSString *name = nil; 1937 1938 if (type == NSTopTabsBezelBorder) 1939 { 1940 if (part == GSTabSelectedFill) 1941 name = GSTabViewSelectedTabFill; 1942 else if (part == GSTabUnSelectedFill) 1943 name = GSTabViewUnSelectedTabFill; 1944 else if (part == GSTabBackgroundFill) 1945 name = GSTabViewBackgroundTabFill; 1946 } 1947 else if (type == NSBottomTabsBezelBorder) 1948 { 1949 if (part == GSTabSelectedFill) 1950 name = GSTabViewBottomSelectedTabFill; 1951 else if (part == GSTabUnSelectedFill) 1952 name = GSTabViewBottomUnSelectedTabFill; 1953 else if (part == GSTabBackgroundFill) 1954 name = GSTabViewBottomBackgroundTabFill; 1955 } 1956 else if (type == NSLeftTabsBezelBorder) 1957 { 1958 if (part == GSTabSelectedFill) 1959 name = GSTabViewLeftSelectedTabFill; 1960 else if (part == GSTabUnSelectedFill) 1961 name = GSTabViewLeftUnSelectedTabFill; 1962 else if (part == GSTabBackgroundFill) 1963 name = GSTabViewLeftBackgroundTabFill; 1964 } 1965 else if (type == NSRightTabsBezelBorder) 1966 { 1967 if (part == GSTabSelectedFill) 1968 name = GSTabViewRightSelectedTabFill; 1969 else if (part == GSTabUnSelectedFill) 1970 name = GSTabViewRightUnSelectedTabFill; 1971 else if (part == GSTabBackgroundFill) 1972 name = GSTabViewRightBackgroundTabFill; 1973 } 1974 1975 return [self tilesNamed: name state: GSThemeNormalState]; 1976} 1977 1978- (void) frameTabRectTopAndBottom: (NSRect)aRect 1979 topColor: (NSColor *)topColor 1980 bottomColor: (NSColor *)bottomColor 1981{ 1982 NSRect bottom = aRect; 1983 NSRect top = aRect; 1984 1985 top.size.height = 1; 1986 bottom.origin.y = NSMaxY(aRect) - 1; 1987 bottom.size.height = 1; 1988 1989 [topColor set]; 1990 NSRectFill(top); 1991 1992 [bottomColor set]; 1993 NSRectFill(bottom); 1994} 1995 1996- (void) drawTabFillInRect: (NSRect)aRect forPart: (GSTabPart)part type: (NSTabViewType)type 1997{ 1998 GSDrawTiles *tiles = [self tilesForTabPart: part type: type]; 1999 2000 if (tiles == nil) 2001 { 2002 if (type == NSBottomTabsBezelBorder) 2003 { 2004 switch (part) 2005 { 2006 case GSTabSelectedFill: 2007 [self frameTabRectTopAndBottom: aRect 2008 topColor: [NSColor clearColor] 2009 bottomColor: [NSColor whiteColor]]; 2010 break; 2011 case GSTabUnSelectedFill: 2012 [self frameTabRectTopAndBottom: aRect 2013 topColor: [NSColor darkGrayColor] 2014 bottomColor: [NSColor whiteColor]]; 2015 break; 2016 case GSTabBackgroundFill: 2017 { 2018 const NSRect clip = aRect; 2019 aRect.origin.x -= 2; 2020 aRect.origin.y = NSMinY(aRect) - 2; 2021 aRect.size.width += 2; 2022 aRect.size.height = 4; 2023 [self drawButton: aRect withClip: clip]; 2024 break; 2025 } 2026 default: 2027 break; 2028 } 2029 } 2030 else if (type == NSTopTabsBezelBorder) 2031 { 2032 switch (part) 2033 { 2034 case GSTabSelectedFill: 2035 [self frameTabRectTopAndBottom: aRect 2036 topColor: [NSColor whiteColor] 2037 bottomColor: [NSColor clearColor]]; 2038 break; 2039 case GSTabUnSelectedFill: 2040 [self frameTabRectTopAndBottom: aRect 2041 topColor: [NSColor whiteColor] 2042 bottomColor: [NSColor whiteColor]]; 2043 break; 2044 case GSTabBackgroundFill: 2045 { 2046 const NSRect clip = aRect; 2047 aRect.origin.x -= 2; 2048 aRect.origin.y = NSMaxY(aRect) - 1; 2049 aRect.size.width += 2; 2050 aRect.size.height = 4; 2051 [self drawButton: aRect withClip: clip]; 2052 break; 2053 } 2054 default: 2055 break; 2056 } 2057 } 2058 } 2059 else 2060 { 2061 [self fillRect: aRect 2062 withTiles: tiles]; 2063 } 2064} 2065 2066- (CGFloat) tabHeightForType: (NSTabViewType)type 2067{ 2068 NSImage *img = [self imageForTabPart: GSTabUnSelectedLeft type: type]; 2069 if (img == nil) 2070 { 2071 return 0; 2072 } 2073 return [img size].height; 2074} 2075 2076- (NSRect) tabViewBackgroundRectForBounds: (NSRect)aRect 2077 tabViewType: (NSTabViewType)type 2078{ 2079 const CGFloat tabHeight = [self tabHeightForType: type]; 2080 2081 switch (type) 2082 { 2083 default: 2084 case NSTopTabsBezelBorder: 2085 aRect.size.height -= tabHeight; 2086 aRect.origin.y += tabHeight; 2087 break; 2088 2089 case NSBottomTabsBezelBorder: 2090 aRect.size.height -= tabHeight; 2091 break; 2092 2093 case NSLeftTabsBezelBorder: 2094 aRect.size.width -= tabHeight; 2095 aRect.origin.x += tabHeight; 2096 break; 2097 2098 case NSRightTabsBezelBorder: 2099 aRect.size.width -= tabHeight; 2100 break; 2101 2102 case NSNoTabsBezelBorder: 2103 case NSNoTabsLineBorder: 2104 case NSNoTabsNoBorder: 2105 break; 2106 } 2107 2108 return aRect; 2109} 2110 2111 2112- (NSRect) tabViewContentRectForBounds: (NSRect)aRect 2113 tabViewType: (NSTabViewType)type 2114 tabView: (NSTabView *)view 2115{ 2116 NSRect cRect = [self tabViewBackgroundRectForBounds: aRect 2117 tabViewType: type]; 2118 NSString *name = GSStringFromTabViewType(type); 2119 GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState]; 2120 2121 if (tiles == nil) 2122 { 2123 switch (type) 2124 { 2125 case NSBottomTabsBezelBorder: 2126 cRect.origin.x += 1; 2127 cRect.origin.y += 1; 2128 cRect.size.width -= 3; 2129 cRect.size.height -= 2; 2130 break; 2131 case NSNoTabsBezelBorder: 2132 cRect.origin.x += 1; 2133 cRect.origin.y += 1; 2134 cRect.size.width -= 3; 2135 cRect.size.height -= 2; 2136 break; 2137 case NSNoTabsLineBorder: 2138 cRect.origin.y += 1; 2139 cRect.origin.x += 1; 2140 cRect.size.width -= 2; 2141 cRect.size.height -= 2; 2142 break; 2143 case NSTopTabsBezelBorder: 2144 cRect.origin.x += 1; 2145 cRect.origin.y += 1; 2146 cRect.size.width -= 3; 2147 cRect.size.height -= 2; 2148 break; 2149 case NSLeftTabsBezelBorder: 2150 cRect.origin.x += 1; 2151 cRect.origin.y += 1; 2152 cRect.size.width -= 3; 2153 cRect.size.height -= 2; 2154 break; 2155 case NSRightTabsBezelBorder: 2156 cRect.origin.x += 1; 2157 cRect.origin.y += 1; 2158 cRect.size.width -= 3; 2159 cRect.size.height -= 2; 2160 break; 2161 case NSNoTabsNoBorder: 2162 default: 2163 break; 2164 } 2165 } 2166 else 2167 { 2168 cRect = [tiles contentRectForRect: cRect 2169 isFlipped: [view isFlipped]]; 2170 } 2171 return cRect; 2172} 2173 2174 2175- (void) drawTabViewBezelRect: (NSRect)aRect 2176 tabViewType: (NSTabViewType)type 2177 inView: (NSView *)view 2178{ 2179 NSString *name = GSStringFromTabViewType(type); 2180 GSDrawTiles *tiles = [self tilesNamed: name state: GSThemeNormalState]; 2181 2182 if (tiles == nil) 2183 { 2184 switch (type) 2185 { 2186 default: 2187 case NSTopTabsBezelBorder: 2188 { 2189 const NSRect clip = aRect; 2190 aRect.size.height += 1; 2191 aRect.origin.y -= 1; 2192 [self drawButton: aRect withClip: clip]; 2193 break; 2194 } 2195 case NSBottomTabsBezelBorder: 2196 { 2197 const NSRect clip = aRect; 2198 aRect.size.height += 2; 2199 [self drawButton: aRect withClip: clip]; 2200 break; 2201 } 2202 case NSLeftTabsBezelBorder: 2203 case NSRightTabsBezelBorder: 2204 [self drawButton: aRect withClip: NSZeroRect]; 2205 break; 2206 case NSNoTabsBezelBorder: 2207 break; 2208 case NSNoTabsLineBorder: 2209 [[NSColor controlDarkShadowColor] set]; 2210 NSFrameRect(aRect); 2211 break; 2212 case NSNoTabsNoBorder: 2213 break; 2214 } 2215 } 2216 else 2217 { 2218 [self fillRect: aRect 2219 withTiles: tiles]; 2220 } 2221} 2222 2223- (void) drawTabViewRect: (NSRect)rect 2224 inView: (NSView *)view 2225 withItems: (NSArray *)items 2226 selectedItem: (NSTabViewItem *)selected 2227{ 2228 NSGraphicsContext *ctxt = GSCurrentContext(); 2229 const NSUInteger howMany = [items count]; 2230 int i; 2231 int previousState = 0; 2232 const NSTabViewType type = [(NSTabView *)view tabViewType]; 2233 const NSRect bounds = [view bounds]; 2234 NSRect aRect = [self tabViewBackgroundRectForBounds: bounds tabViewType: type]; 2235 2236 const BOOL truncate = [(NSTabView *)view allowsTruncatedLabels]; 2237 const CGFloat tabHeight = [self tabHeightForType: type]; 2238 2239 DPSgsave(ctxt); 2240 2241 [self drawTabViewBezelRect: aRect 2242 tabViewType: type 2243 inView: view]; 2244 2245 if (type == NSBottomTabsBezelBorder 2246 || type == NSTopTabsBezelBorder) 2247 { 2248 NSPoint iP; 2249 if (type == NSTopTabsBezelBorder) 2250 iP = bounds.origin; 2251 else 2252 iP = NSMakePoint(aRect.origin.x, NSMaxY(aRect)); 2253 2254 for (i = 0; i < howMany; i++) 2255 { 2256 NSRect r; 2257 NSTabViewItem *anItem = [items objectAtIndex: i]; 2258 const NSTabState itemState = [anItem tabState]; 2259 const NSSize s = [anItem sizeOfLabel: truncate]; 2260 2261 // Draw the left image 2262 2263 if (i == 0) 2264 { 2265 NSImage *part = nil; 2266 if (itemState == NSSelectedTab) 2267 { 2268 part = [self imageForTabPart: GSTabSelectedLeft type: type]; 2269 } 2270 else if (itemState == NSBackgroundTab) 2271 { 2272 part = [self imageForTabPart: GSTabUnSelectedLeft type: type]; 2273 } 2274 else 2275 NSLog(@"Not finished yet. Luff ya.\n"); 2276 2277 [part drawInRect: NSMakeRect(iP.x, iP.y, [part size].width, [part size].height) 2278 fromRect: NSZeroRect 2279 operation: NSCompositeSourceOver 2280 fraction: 1.0 2281 respectFlipped: YES 2282 hints: nil]; 2283 2284 iP.x += [part size].width; 2285 } 2286 else 2287 { 2288 NSImage *part = nil; 2289 if (itemState == NSSelectedTab) 2290 { 2291 part = [self imageForTabPart: GSTabUnSelectedToSelectedJunction type: type]; 2292 } 2293 else if (itemState == NSBackgroundTab) 2294 { 2295 if (previousState == NSSelectedTab) 2296 { 2297 part = [self imageForTabPart: GSTabSelectedToUnSelectedJunction type: type]; 2298 } 2299 else 2300 { 2301 part = [self imageForTabPart: GSTabUnSelectedJunction type: type]; 2302 } 2303 } 2304 else 2305 NSLog(@"Not finished yet. Luff ya.\n"); 2306 2307 [part drawInRect: NSMakeRect(iP.x, iP.y, [part size].width, [part size].height) 2308 fromRect: NSZeroRect 2309 operation: NSCompositeSourceOver 2310 fraction: 1.0 2311 respectFlipped: YES 2312 hints: nil]; 2313 2314 iP.x += [part size].width; 2315 } 2316 2317 // Draw the middle fill part of the tab 2318 2319 r.origin = iP; 2320 r.size.width = s.width; 2321 r.size.height = tabHeight; 2322 2323 if (itemState == NSSelectedTab) 2324 { 2325 [self drawTabFillInRect: r forPart: GSTabSelectedFill type: type]; 2326 } 2327 else if (itemState == NSBackgroundTab) 2328 { 2329 [self drawTabFillInRect: r forPart: GSTabUnSelectedFill type: type]; 2330 } 2331 else 2332 NSLog(@"Not finished yet. Luff ya.\n"); 2333 2334 // Label 2335 [anItem drawLabel: truncate inRect: r]; 2336 2337 iP.x += s.width; 2338 previousState = itemState; 2339 2340 // For the rightmost tab, draw the right side 2341 2342 if (i == howMany - 1) 2343 { 2344 NSImage *part = nil; 2345 if ([anItem tabState] == NSSelectedTab) 2346 { 2347 part = [self imageForTabPart: GSTabSelectedRight type: type]; 2348 } 2349 else if ([anItem tabState] == NSBackgroundTab) 2350 { 2351 part = [self imageForTabPart: GSTabUnSelectedRight type: type]; 2352 } 2353 else 2354 NSLog(@"Not finished yet. Luff ya.\n"); 2355 2356 [part drawInRect: NSMakeRect(iP.x, iP.y, [part size].width, [part size].height) 2357 fromRect: NSZeroRect 2358 operation: NSCompositeSourceOver 2359 fraction: 1.0 2360 respectFlipped: YES 2361 hints: nil]; 2362 2363 iP.x += [part size].width; 2364 2365 // Draw the background fill 2366 if (iP.x < NSMaxX(bounds)) 2367 { 2368 r.origin = iP; 2369 r.size.width = NSMaxX(bounds) - iP.x; 2370 r.size.height = tabHeight; 2371 2372 [self drawTabFillInRect: r forPart: GSTabBackgroundFill type: type]; 2373 } 2374 } 2375 } 2376 } 2377 // FIXME: Missing drawing code for other cases 2378 2379 DPSgrestore(ctxt); 2380} 2381 2382- (void) drawScrollerRect: (NSRect)rect 2383 inView: (NSView *)view 2384 hitPart: (NSScrollerPart)hitPart 2385 isHorizontal: (BOOL)isHorizontal 2386{ 2387 NSRect rectForPartIncrementLine; 2388 NSRect rectForPartDecrementLine; 2389 NSRect rectForPartKnobSlot; 2390 NSScroller *scroller = (NSScroller *)view; 2391 2392 rectForPartIncrementLine = [scroller rectForPart: NSScrollerIncrementLine]; 2393 rectForPartDecrementLine = [scroller rectForPart: NSScrollerDecrementLine]; 2394 rectForPartKnobSlot = [scroller rectForPart: NSScrollerKnobSlot]; 2395 2396 /* 2397 [[[view window] backgroundColor] set]; 2398 NSRectFill (rect); 2399 */ 2400 2401 if (NSIntersectsRect (rect, rectForPartKnobSlot) == YES) 2402 { 2403 [scroller drawKnobSlot]; 2404 [scroller drawKnob]; 2405 } 2406 2407 if (NSIntersectsRect (rect, rectForPartDecrementLine) == YES) 2408 { 2409 [scroller drawArrow: NSScrollerDecrementArrow 2410 highlight: hitPart == NSScrollerDecrementLine]; 2411 } 2412 if (NSIntersectsRect (rect, rectForPartIncrementLine) == YES) 2413 { 2414 [scroller drawArrow: NSScrollerIncrementArrow 2415 highlight: hitPart == NSScrollerIncrementLine]; 2416 } 2417} 2418 2419- (void) drawBrowserRect: (NSRect)rect 2420 inView: (NSView *)view 2421 withScrollerRect: (NSRect)scrollerRect 2422 columnSize: (NSSize)columnSize 2423{ 2424 NSBrowser *browser = (NSBrowser *)view; 2425 NSRect bounds = [view bounds]; 2426 2427 // Load the first column if not already done 2428 if (![browser isLoaded]) 2429 { 2430 [browser loadColumnZero]; 2431 } 2432 2433 // Draws titles 2434 if ([browser isTitled]) 2435 { 2436 int i; 2437 2438 for (i = [browser firstVisibleColumn]; 2439 i <= [browser lastVisibleColumn]; 2440 ++i) 2441 { 2442 NSRect titleRect = [browser titleFrameOfColumn: i]; 2443 if (NSIntersectsRect (titleRect, rect) == YES) 2444 { 2445 [browser drawTitleOfColumn: i 2446 inRect: titleRect]; 2447 } 2448 } 2449 } 2450 2451 // Draws scroller border 2452 2453 if ([self browserUseBezels]) 2454 { 2455 if ([browser hasHorizontalScroller] && 2456 [browser separatesColumns]) 2457 { 2458 NSRect scrollerBorderRect = scrollerRect; 2459 NSSize bs = [self sizeForBorderType: NSBezelBorder]; 2460 2461 scrollerBorderRect.origin.x = 0; 2462 scrollerBorderRect.origin.y = 0; 2463 scrollerBorderRect.size.width += 2 * bs.width; 2464 scrollerBorderRect.size.height += (2 * bs.height) - 1; 2465 2466 if ((NSIntersectsRect (scrollerBorderRect, rect) == YES) && [view window]) 2467 { 2468 [self drawGrayBezel: scrollerBorderRect withClip: rect]; 2469 } 2470 } 2471 2472 if (![browser separatesColumns]) 2473 { 2474 NSPoint p1,p2; 2475 int i, visibleColumns; 2476 float hScrollerWidth = [browser hasHorizontalScroller] ? 2477 [NSScroller scrollerWidth] : 0; 2478 2479 // Columns borders 2480 [self drawGrayBezel: bounds withClip: rect]; 2481 2482 [[NSColor blackColor] set]; 2483 visibleColumns = [browser numberOfVisibleColumns]; 2484 for (i = 1; i < visibleColumns; i++) 2485 { 2486 p1 = NSMakePoint((columnSize.width * i) + 2 + (i-1), 2487 columnSize.height + hScrollerWidth + 2); 2488 p2 = NSMakePoint((columnSize.width * i) + 2 + (i-1), 2489 hScrollerWidth + 2); 2490 [NSBezierPath strokeLineFromPoint: p1 toPoint: p2]; 2491 } 2492 2493 // Horizontal scroller border 2494 if ([browser hasHorizontalScroller]) 2495 { 2496 p1 = NSMakePoint(2, hScrollerWidth + 2); 2497 p2 = NSMakePoint(rect.size.width - 2, hScrollerWidth + 2); 2498 [NSBezierPath strokeLineFromPoint: p1 toPoint: p2]; 2499 } 2500 } 2501 } 2502 2503 if (![self browserUseBezels] 2504 && [self scrollViewScrollersOverlapBorders]) 2505 { 2506 NSRect baseRect = NSMakeRect(0, 0, bounds.size.width, 1); 2507 NSRect colFrame = [browser frameOfColumn: [browser firstVisibleColumn]]; 2508 NSRect scrollViewRect = NSUnionRect(baseRect, colFrame); 2509 2510 GSDrawTiles *tiles = [self tilesNamed: @"NSScrollView" 2511 state: GSThemeNormalState]; 2512 2513 [self fillRect: scrollViewRect 2514 withTiles: tiles]; 2515 } 2516} 2517 2518- (CGFloat) browserColumnSeparation 2519{ 2520 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 2521 2522 if ([defs objectForKey: @"GSBrowserColumnSeparation"] != nil) 2523 { 2524 return [defs floatForKey: @"GSBrowserColumnSeparation"]; 2525 } 2526 else 2527 { 2528 return 4; 2529 } 2530} 2531 2532- (CGFloat) browserVerticalPadding 2533{ 2534 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 2535 2536 if ([defs objectForKey: @"GSBrowserVerticalPadding"] != nil) 2537 { 2538 return [defs floatForKey: @"GSBrowserVerticalPadding"]; 2539 } 2540 else 2541 { 2542 return 2; 2543 } 2544} 2545 2546- (BOOL) browserUseBezels 2547{ 2548 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 2549 2550 if ([defs objectForKey: @"GSBrowserUseBezels"] != nil) 2551 { 2552 return [defs boolForKey: @"GSBrowserUseBezels"]; 2553 } 2554 else 2555 { 2556 return YES; 2557 } 2558} 2559 2560- (void) drawMenuRect: (NSRect)rect 2561 inView: (NSView *)view 2562 isHorizontal: (BOOL)horizontal 2563 itemCells: (NSArray *)itemCells 2564{ 2565 int i = 0; 2566 int howMany = [itemCells count]; 2567 NSMenuView *menuView = (NSMenuView *)view; 2568 NSRect bounds = [view bounds]; 2569 2570 [self drawBackgroundForMenuView: menuView 2571 withFrame: bounds 2572 dirtyRect: rect 2573 horizontal: horizontal]; 2574 2575 // Draw the menu cells. 2576 for (i = 0; i < howMany; i++) 2577 { 2578 NSRect aRect; 2579 NSMenuItemCell *aCell; 2580 2581 aRect = [menuView rectOfItemAtIndex: i]; 2582 if (NSIntersectsRect(rect, aRect) == YES) 2583 { 2584 aCell = [menuView menuItemCellForItemAtIndex: i]; 2585 [aCell drawWithFrame: aRect inView: menuView]; 2586 } 2587 } 2588} 2589 2590- (void) drawScrollViewRect: (NSRect)rect 2591 inView: (NSView *)view 2592{ 2593 NSScrollView *scrollView = (NSScrollView *)view; 2594 GSTheme *theme = [GSTheme theme]; 2595 NSColor *color; 2596 NSString *name; 2597 NSBorderType borderType = [scrollView borderType]; 2598 NSRect bounds = [view bounds]; 2599 BOOL hasInnerBorder = ![[NSUserDefaults standardUserDefaults] 2600 boolForKey: @"GSScrollViewNoInnerBorder"]; 2601 GSDrawTiles *tiles = nil; 2602 2603 name = [theme nameForElement: self]; 2604 if (name == nil) 2605 { 2606 name = @"NSScrollView"; 2607 } 2608 color = [theme colorNamed: name state: GSThemeNormalState]; 2609 tiles = [theme tilesNamed: name state: GSThemeNormalState]; 2610 if (color == nil) 2611 { 2612 color = [NSColor controlDarkShadowColor]; 2613 } 2614 2615 if (tiles == nil) 2616 { 2617 switch (borderType) 2618 { 2619 case NSNoBorder: 2620 break; 2621 2622 case NSLineBorder: 2623 [color set]; 2624 NSFrameRect(bounds); 2625 break; 2626 2627 case NSBezelBorder: 2628 [theme drawGrayBezel: bounds withClip: rect]; 2629 break; 2630 2631 case NSGrooveBorder: 2632 [theme drawGroove: bounds withClip: rect]; 2633 break; 2634 } 2635 } 2636 else 2637 { 2638 [self fillRect: bounds 2639 withTiles: tiles]; 2640 } 2641 2642 if (hasInnerBorder) 2643 { 2644 NSScroller *vertScroller = [scrollView verticalScroller]; 2645 NSScroller *horizScroller = [scrollView horizontalScroller]; 2646 CGFloat scrollerWidth = [NSScroller scrollerWidth]; 2647 NSRect scrollerFrame; 2648 2649 [color set]; 2650 2651 if ([scrollView hasVerticalScroller]) 2652 { 2653 NSInterfaceStyle style; 2654 CGFloat xpos; 2655 2656 scrollerFrame = [vertScroller frame]; 2657 2658 style = NSInterfaceStyleForKey(@"NSScrollViewInterfaceStyle", nil); 2659 if (style == NSMacintoshInterfaceStyle 2660 || style == NSWindows95InterfaceStyle) 2661 { 2662 xpos = scrollerFrame.origin.x - 1.0; 2663 } 2664 else 2665 { 2666 xpos = scrollerFrame.origin.x + scrollerWidth; 2667 } 2668 NSRectFill(NSMakeRect(xpos, scrollerFrame.origin.y, 2669 1.0, scrollerFrame.size.height)); 2670 } 2671 2672 if ([scrollView hasHorizontalScroller]) 2673 { 2674 CGFloat ypos; 2675 2676 scrollerFrame = [horizScroller frame]; 2677 2678 if ([scrollView isFlipped]) 2679 { 2680 ypos = scrollerFrame.origin.y - 1.0; 2681 } 2682 else 2683 { 2684 ypos = scrollerFrame.origin.y + scrollerWidth + 1.0; 2685 } 2686 NSRectFill(NSMakeRect([horizScroller frame].origin.x, ypos, 2687 scrollerFrame.size.width, 1.0)); 2688 } 2689 } 2690} 2691 2692- (void) drawSliderBorderAndBackground: (NSBorderType)aType 2693 frame: (NSRect)cellFrame 2694 inCell: (NSCell *)cell 2695 isHorizontal: (BOOL)horizontal 2696{ 2697 NSSliderType type = [(NSSliderCell *)cell sliderType]; 2698 if (type == NSLinearSlider) 2699 { 2700 NSString *partName = (horizontal ? GSSliderHorizontalTrack : GSSliderVerticalTrack); 2701 GSDrawTiles *tiles = [self tilesNamed: partName 2702 state: GSThemeNormalState]; 2703 2704 if (tiles == nil) 2705 { 2706 [[GSTheme theme] drawBorderType: aType 2707 frame: cellFrame 2708 view: [cell controlView]]; 2709 } 2710 else 2711 { 2712 // FIXME: This code could be factored out 2713 NSSize tilesNaturalSize = [tiles size]; 2714 NSRect tilesRect; 2715 2716 // Only stretch the tiles in one direction 2717 if (horizontal) 2718 { 2719 tilesRect.size = NSMakeSize(cellFrame.size.width, tilesNaturalSize.height); 2720 } 2721 else 2722 { 2723 tilesRect.size = NSMakeSize(tilesNaturalSize.width, cellFrame.size.height); 2724 } 2725 tilesRect.origin = NSMakePoint((cellFrame.size.width - tilesRect.size.width) / 2.0, 2726 (cellFrame.size.height - tilesRect.size.height) / 2.0); 2727 2728 if ([cell controlView] != nil) 2729 { 2730 tilesRect = [[cell controlView] centerScanRect: tilesRect]; 2731 } 2732 2733 [self fillRect: tilesRect 2734 withTiles: tiles]; 2735 } 2736 } 2737} 2738 2739- (void) drawBarInside: (NSRect)rect 2740 inCell: (NSCell *)cell 2741 flipped: (BOOL)flipped 2742{ 2743 NSSliderType type = [(NSSliderCell *)cell sliderType]; 2744 if (type == NSLinearSlider) 2745 { 2746 BOOL horizontal = (rect.size.width > rect.size.height); 2747 NSString *partName = (horizontal ? GSSliderHorizontalTrack : GSSliderVerticalTrack); 2748 GSDrawTiles *tiles = [self tilesNamed: partName 2749 state: GSThemeNormalState]; 2750 2751 if (tiles == nil) 2752 { 2753 [[NSColor scrollBarColor] set]; 2754 NSRectFill(rect); 2755 } 2756 // Don't draw anything if we have tiles, they are drawn 2757 // in -drawSliderBorderAndBackground:... 2758 } 2759} 2760 2761- (void) drawKnobInCell: (NSCell *)cell 2762{ 2763 NSView *controlView = [cell controlView]; 2764 NSSliderCell *sliderCell = (NSSliderCell *)cell; 2765 2766 [sliderCell drawKnob: 2767 [sliderCell knobRectFlipped: 2768 [controlView isFlipped]]]; 2769} 2770 2771- (NSRect) tableHeaderCellDrawingRectForBounds: (NSRect)theRect 2772{ 2773 NSSize borderSize; 2774 2775 // This adjustment must match the drawn border 2776 borderSize = NSMakeSize(1, 1); 2777 2778 return NSInsetRect(theRect, borderSize.width, borderSize.height); 2779} 2780 2781- (void)drawTableHeaderRect: (NSRect)aRect 2782 inView: (NSView *)view 2783{ 2784 NSTableHeaderView *tableHeaderView = (NSTableHeaderView *)view; 2785 NSTableView *tableView = [tableHeaderView tableView]; 2786 NSArray *columns; 2787 int firstColumnToDraw; 2788 int lastColumnToDraw; 2789 NSRect drawingRect; 2790 NSTableColumn *column; 2791 NSTableColumn *highlightedTableColumn; 2792 float width; 2793 int i; 2794 NSCell *cell; 2795 2796 if (tableView == nil) 2797 return; 2798 2799 firstColumnToDraw = [tableHeaderView columnAtPoint: NSMakePoint (aRect.origin.x, 2800 aRect.origin.y)]; 2801 if (firstColumnToDraw == -1) 2802 firstColumnToDraw = 0; 2803 2804 lastColumnToDraw = [tableHeaderView columnAtPoint: NSMakePoint (NSMaxX (aRect), 2805 aRect.origin.y)]; 2806 if (lastColumnToDraw == -1) 2807 lastColumnToDraw = [tableView numberOfColumns] - 1; 2808 2809 drawingRect = [tableHeaderView headerRectOfColumn: firstColumnToDraw]; 2810 2811 columns = [tableView tableColumns]; 2812 highlightedTableColumn = [tableView highlightedTableColumn]; 2813 2814 for (i = firstColumnToDraw; i <= lastColumnToDraw; i++) 2815 { 2816 column = [columns objectAtIndex: i]; 2817 width = [column width]; 2818 drawingRect.size.width = width; 2819 cell = [column headerCell]; 2820 if ((column == highlightedTableColumn) 2821 || [tableView isColumnSelected: i]) 2822 { 2823 [cell setHighlighted: YES]; 2824 } 2825 else 2826 { 2827 [cell setHighlighted: NO]; 2828 } 2829 [cell drawWithFrame: drawingRect 2830 inView: tableHeaderView]; 2831 drawingRect.origin.x += width; 2832 } 2833} 2834 2835- (void) drawPopUpButtonCellInteriorWithFrame: (NSRect)cellFrame 2836 withCell: (NSCell *)cell 2837 inView: (NSView *)controlView 2838{ 2839 // Default implementation of this method does nothing. 2840} 2841 2842- (void) drawTableViewBackgroundInClipRect: (NSRect)aRect 2843 inView: (NSView *)view 2844 withBackgroundColor: (NSColor *)backgroundColor 2845{ 2846 NSTableView *tableView = (NSTableView *)view; 2847 2848 [backgroundColor set]; 2849 NSRectFill (aRect); 2850 2851 if ([tableView usesAlternatingRowBackgroundColors]) 2852 { 2853 const CGFloat rowHeight = [tableView rowHeight]; 2854 NSInteger startingRow = [tableView rowAtPoint: NSMakePoint(0, NSMinY(aRect))]; 2855 NSInteger endingRow; 2856 NSInteger i; 2857 2858 NSArray *rowColors = [NSColor controlAlternatingRowBackgroundColors]; 2859 const NSUInteger rowColorCount = [rowColors count]; 2860 2861 NSRect rowRect; 2862 2863 if (rowHeight <= 0 2864 || rowColorCount == 0 2865 || aRect.size.height <= 0) 2866 return; 2867 2868 if (startingRow <= 0) 2869 startingRow = 0; 2870 2871 rowRect = [tableView rectOfRow: startingRow]; 2872 rowRect.origin.x = aRect.origin.x; 2873 rowRect.size.width = aRect.size.width; 2874 2875 endingRow = startingRow + ceil(aRect.size.height / rowHeight); 2876 2877 for (i = startingRow; i <= endingRow; i++) 2878 { 2879 NSColor *color = [rowColors objectAtIndex: (i % rowColorCount)]; 2880 2881 [color set]; 2882 NSRectFill(rowRect); 2883 2884 rowRect.origin.y += rowHeight; 2885 } 2886 } 2887} 2888 2889- (void) drawTableViewGridInClipRect: (NSRect)aRect 2890 inView: (NSView *)view 2891{ 2892 NSTableView *tableView = (NSTableView *)view; 2893 2894 // Cache some constants 2895 const CGFloat minX = NSMinX(aRect); 2896 const CGFloat maxX = NSMaxX(aRect); 2897 const CGFloat minY = NSMinY(aRect); 2898 const CGFloat maxY = NSMaxY(aRect); 2899 const NSInteger numberOfColumns = [tableView numberOfColumns]; 2900 const NSInteger numberOfRows = [tableView numberOfRows]; 2901 2902 NSInteger startingRow = [tableView rowAtPoint: NSMakePoint(minX, minY)]; 2903 NSInteger endingRow = [tableView rowAtPoint: NSMakePoint(minX, maxY)]; 2904 NSInteger startingColumn = [tableView columnAtPoint: NSMakePoint(minX, minY)]; 2905 NSInteger endingColumn = [tableView columnAtPoint: NSMakePoint(maxX, minY)]; 2906 2907 NSGraphicsContext *ctxt = GSCurrentContext(); 2908 NSColor *gridColor = [tableView gridColor]; 2909 2910 2911 if (startingRow == -1) 2912 startingRow = 0; 2913 if (endingRow == -1) 2914 endingRow = numberOfRows - 1; 2915 2916 if (startingColumn == -1) 2917 startingColumn = 0; 2918 if (endingColumn == -1) 2919 endingColumn = numberOfColumns - 1; 2920 2921 2922 DPSgsave(ctxt); 2923 [gridColor set]; 2924 2925 // Draw horizontal lines 2926 if (numberOfRows > 0) 2927 { 2928 NSInteger i; 2929 for (i = startingRow; i <= endingRow; i++) 2930 { 2931 NSRect rowRect = [tableView rectOfRow: i]; 2932 rowRect.origin.y += rowRect.size.height - 1; 2933 rowRect.size.height = 1; 2934 NSRectFill(rowRect); 2935 } 2936 } 2937 2938 // Draw vertical lines 2939 if (numberOfColumns > 0) 2940 { 2941 NSInteger i; 2942 for (i = startingColumn; i <= endingColumn; i++) 2943 { 2944 NSRect colRect = [tableView rectOfColumn: i]; 2945 colRect.origin.x += colRect.size.width - 1; 2946 colRect.size.width = 1; 2947 NSRectFill(colRect); 2948 } 2949 } 2950 2951 DPSgrestore (ctxt); 2952} 2953 2954- (void) drawTableViewRect: (NSRect)aRect 2955 inView: (NSView *)view 2956{ 2957 NSInteger startingRow; 2958 NSInteger endingRow; 2959 NSInteger i; 2960 NSTableView *tableView = (NSTableView *)view; 2961 NSInteger numberOfRows = [tableView numberOfRows]; 2962 NSInteger numberOfColumns = [tableView numberOfColumns]; 2963 BOOL drawsGrid = [tableView drawsGrid]; 2964 2965 /* Draw background */ 2966 [tableView drawBackgroundInClipRect: aRect]; 2967 2968 if ((numberOfRows == 0) || (numberOfColumns == 0)) 2969 { 2970 return; 2971 } 2972 2973 /* Draw selection */ 2974 [tableView highlightSelectionInClipRect: aRect]; 2975 2976 /* Draw grid */ 2977 if (drawsGrid) 2978 { 2979 [tableView drawGridInClipRect: aRect]; 2980 } 2981 2982 /* Draw visible cells */ 2983 /* Using rowAtPoint: here calls them only twice per drawn rect */ 2984 startingRow = [tableView rowAtPoint: NSMakePoint (0, NSMinY (aRect))]; 2985 endingRow = [tableView rowAtPoint: NSMakePoint (0, NSMaxY (aRect))]; 2986 2987 if (startingRow == -1) 2988 { 2989 startingRow = 0; 2990 } 2991 if (endingRow == -1) 2992 { 2993 endingRow = numberOfRows - 1; 2994 } 2995 // NSLog(@"drawRect : %d-%d", startingRow, endingRow); 2996 { 2997 SEL sel = @selector(drawRow:clipRect:); 2998 void (*imp)(id, SEL, NSInteger, NSRect); 2999 3000 imp = (void (*)(id, SEL, NSInteger, NSRect))[tableView methodForSelector: sel]; 3001 3002 for (i = startingRow; i <= endingRow; i++) 3003 { 3004 imp(tableView, sel, i, aRect); 3005 } 3006 } 3007} 3008 3009- (void) highlightTableViewSelectionInClipRect: (NSRect)clipRect 3010 inView: (NSView *)view 3011 selectingColumns: (BOOL)selectingColumns 3012{ 3013 NSTableView *tableView = (NSTableView *)view; 3014 NSInteger numberOfRows = [tableView numberOfRows]; 3015 NSInteger numberOfColumns = [tableView numberOfColumns]; 3016 NSIndexSet *selectedRows = [tableView selectedRowIndexes]; 3017 NSIndexSet *selectedColumns = [tableView selectedColumnIndexes]; 3018 NSColor *backgroundColor = [tableView backgroundColor]; 3019 3020 // Set the fill color 3021 { 3022 NSColor *selectionColor; 3023 3024 selectionColor = [self colorNamed: @"highlightedTableRowBackgroundColor" 3025 state: GSThemeNormalState]; 3026 3027 if (selectionColor == nil) 3028 { 3029 // Switch to the alternate color of the backgroundColor is white. 3030 if([backgroundColor isEqual: [NSColor whiteColor]]) 3031 { 3032 selectionColor = [NSColor colorWithCalibratedRed: 0.86 3033 green: 0.92 3034 blue: 0.99 3035 alpha: 1.0]; 3036 } 3037 else 3038 { 3039 selectionColor = [NSColor whiteColor]; 3040 } 3041 } 3042 [selectionColor set]; 3043 } 3044 3045 if (selectingColumns == NO) 3046 { 3047 NSInteger selectedRowsCount; 3048 NSUInteger row; 3049 NSInteger startingRow, endingRow; 3050 3051 selectedRowsCount = [selectedRows count]; 3052 if (selectedRowsCount == 0) 3053 return; 3054 3055 /* highlight selected rows */ 3056 startingRow = [tableView rowAtPoint: NSMakePoint(0, NSMinY(clipRect))]; 3057 endingRow = [tableView rowAtPoint: NSMakePoint(0, NSMaxY(clipRect))]; 3058 3059 if (startingRow == -1) 3060 startingRow = 0; 3061 if (endingRow == -1) 3062 endingRow = numberOfRows - 1; 3063 3064 row = [selectedRows indexGreaterThanOrEqualToIndex: startingRow]; 3065 while ((row != NSNotFound) && (row <= endingRow)) 3066 { 3067 NSRectFill(NSIntersectionRect([tableView rectOfRow: row], clipRect)); 3068 row = [selectedRows indexGreaterThanIndex: row]; 3069 } 3070 } 3071 else // Selecting columns 3072 { 3073 NSUInteger selectedColumnsCount; 3074 NSUInteger column; 3075 NSInteger startingColumn, endingColumn; 3076 3077 selectedColumnsCount = [selectedColumns count]; 3078 3079 if (selectedColumnsCount == 0) 3080 return; 3081 3082 /* highlight selected columns */ 3083 startingColumn = [tableView columnAtPoint: NSMakePoint(NSMinX(clipRect), 0)]; 3084 endingColumn = [tableView columnAtPoint: NSMakePoint(NSMaxX(clipRect), 0)]; 3085 3086 if (startingColumn == -1) 3087 startingColumn = 0; 3088 if (endingColumn == -1) 3089 endingColumn = numberOfColumns - 1; 3090 3091 column = [selectedColumns indexGreaterThanOrEqualToIndex: startingColumn]; 3092 while ((column != NSNotFound) && (column <= endingColumn)) 3093 { 3094 NSRectFill(NSIntersectionRect([tableView rectOfColumn: column], 3095 clipRect)); 3096 column = [selectedColumns indexGreaterThanIndex: column]; 3097 } 3098 } 3099} 3100 3101- (void) drawTableViewRow: (NSInteger)rowIndex 3102 clipRect: (NSRect)clipRect 3103 inView: (NSView *)view 3104{ 3105 NSTableView *tableView = (NSTableView *)view; 3106 // NSInteger numberOfRows = [tableView numberOfRows]; 3107 NSInteger numberOfColumns = [tableView numberOfColumns]; 3108 // NSIndexSet *selectedRows = [tableView selectedRowIndexes]; 3109 // NSColor *backgroundColor = [tableView backgroundColor]; 3110 CGFloat *columnOrigins = [tableView _columnOrigins]; 3111 NSInteger editedRow = [tableView editedRow]; 3112 NSInteger editedColumn = [tableView editedColumn]; 3113 NSArray *tableColumns = [tableView tableColumns]; 3114 NSInteger startingColumn; 3115 NSInteger endingColumn; 3116 NSTableColumn *tb; 3117 NSRect drawingRect; 3118 NSCell *cell; 3119 NSInteger i; 3120 CGFloat x_pos; 3121 const BOOL rowSelected = [[tableView selectedRowIndexes] containsIndex: rowIndex]; 3122 NSColor *tempColor = nil; 3123 NSColor *selectedTextColor = [self colorNamed: @"highlightedTableRowTextColor" 3124 state: GSThemeNormalState]; 3125 3126 /* Using columnAtPoint: here would make it called twice per row per drawn 3127 rect - so we avoid it and do it natively */ 3128 3129 /* Determine starting column as fast as possible */ 3130 x_pos = NSMinX (clipRect); 3131 i = 0; 3132 while ((i < numberOfColumns) && (x_pos > columnOrigins[i])) 3133 { 3134 i++; 3135 } 3136 startingColumn = (i - 1); 3137 3138 if (startingColumn == -1) 3139 startingColumn = 0; 3140 3141 /* Determine ending column as fast as possible */ 3142 x_pos = NSMaxX (clipRect); 3143 // Nota Bene: we do *not* reset i 3144 while ((i < numberOfColumns) && (x_pos > columnOrigins[i])) 3145 { 3146 i++; 3147 } 3148 endingColumn = (i - 1); 3149 3150 if (endingColumn == -1) 3151 endingColumn = numberOfColumns - 1; 3152 3153 /* Draw the row between startingColumn and endingColumn */ 3154 for (i = startingColumn; i <= endingColumn; i++) 3155 { 3156 const BOOL columnSelected = [tableView isColumnSelected: i]; 3157 const BOOL cellSelected = (rowSelected || columnSelected); 3158 tb = [tableColumns objectAtIndex: i]; 3159 cell = [tb dataCellForRow: rowIndex]; 3160 [tableView _willDisplayCell: cell 3161 forTableColumn: tb 3162 row: rowIndex]; 3163 if (i == editedColumn && rowIndex == editedRow) 3164 { 3165 [cell _setInEditing: YES]; 3166 } 3167 else 3168 { 3169 [cell setObjectValue: [tableView _objectValueForTableColumn: tb 3170 row: rowIndex]]; 3171 } 3172 drawingRect = [tableView frameOfCellAtColumn: i 3173 row: rowIndex]; 3174 3175 // Set the cell text color if the theme provides a custom highlighted 3176 // row color. 3177 // 3178 // FIXME: This could probably be done in a cleaner way. We should 3179 // probably do -setHighlighted: YES, and the implementation of 3180 // -textColor in NSCell could use that to return a highlighted text color. 3181 if (cellSelected && (selectedTextColor != nil) 3182 && [cell isKindOfClass: [NSTextFieldCell class]]) 3183 { 3184 tempColor = [cell textColor]; 3185 [(NSTextFieldCell *)cell setTextColor: selectedTextColor]; 3186 } 3187 3188 [cell drawWithFrame: drawingRect inView: tableView]; 3189 3190 if (cellSelected && (selectedTextColor != nil) 3191 && [cell isKindOfClass: [NSTextFieldCell class]]) 3192 { 3193 // Restore the cell's text color if we changed it 3194 [(NSTextFieldCell *)cell setTextColor: tempColor]; 3195 } 3196 3197 if (i == editedColumn && rowIndex == editedRow) 3198 [cell _setInEditing: NO]; 3199 } 3200} 3201 3202- (void) drawBoxInClipRect: (NSRect)clipRect 3203 boxType: (NSBoxType)boxType 3204 borderType: (NSBorderType)borderType 3205 inView: (NSBox *)box 3206{ 3207 NSColor *color; 3208 BOOL drawTitleBackground = YES; 3209 3210 if (boxType == NSBoxCustom) 3211 { 3212 if (![box isOpaque]) 3213 { 3214 color = [NSColor clearColor]; 3215 } 3216 else 3217 { 3218 color = [box fillColor]; 3219 } 3220 } 3221 else 3222 { 3223 color = [[box window] backgroundColor]; 3224 } 3225 3226 // Draw separator boxes 3227 3228 if (boxType == NSBoxSeparator) 3229 { 3230 color = [box borderColor]; 3231 if (!color || [color isEqual:[NSColor clearColor]]) 3232 { 3233 color = [NSColor controlShadowColor]; 3234 } 3235 [color set]; 3236 NSRectFill([box borderRect]); 3237 return; 3238 } 3239 3240 // Draw border 3241 3242 GSDrawTiles *tiles = [[GSTheme theme] tilesNamed: GSBoxBorder state: GSThemeNormalState]; 3243 if (tiles == nil 3244 || borderType == NSNoBorder 3245 || boxType == NSBoxOldStyle 3246 || boxType == NSBoxCustom) 3247 { 3248 // Fill inside 3249 [color set]; 3250 NSRectFill(clipRect); 3251 3252 switch (borderType) 3253 { 3254 case NSNoBorder: 3255 break; 3256 case NSLineBorder: 3257 if (boxType == NSBoxCustom) 3258 { 3259 [[box borderColor] set]; 3260 NSFrameRectWithWidth([box borderRect], [box borderWidth]); 3261 } 3262 else 3263 { 3264 [[NSColor controlDarkShadowColor] set]; 3265 NSFrameRect([box borderRect]); 3266 } 3267 break; 3268 case NSBezelBorder: 3269 [[GSTheme theme] drawDarkBezel: [box borderRect] withClip: clipRect]; 3270 break; 3271 case NSGrooveBorder: 3272 [[GSTheme theme] drawGroove: [box borderRect] withClip: clipRect]; 3273 break; 3274 } 3275 } 3276 else 3277 { 3278 drawTitleBackground = NO; 3279 3280 // If the title is on the border, clip a hole in the later 3281 3282 [NSGraphicsContext saveGraphicsState]; 3283 3284 if ((borderType != NSNoBorder) 3285 && (([box titlePosition] == NSAtTop) || ([box titlePosition] == NSAtBottom))) 3286 { 3287 const NSRect borderRect = [box borderRect]; 3288 const NSRect titleRect = [box titleRect]; 3289 NSBezierPath *path = [NSBezierPath bezierPath]; 3290 3291 // Left 3292 if (NSMinX(titleRect) > NSMinX(borderRect)) 3293 { 3294 NSRect left = borderRect; 3295 left.size.width = NSMinX(titleRect) - NSMinX(borderRect); 3296 [path appendBezierPathWithRect: left]; 3297 } 3298 3299 // Right 3300 if (NSMaxX(borderRect) > NSMaxX(titleRect)) 3301 { 3302 NSRect right = borderRect; 3303 right.size.width = NSMaxX(borderRect) - NSMaxX(titleRect); 3304 right.origin.x = NSMaxX(titleRect); 3305 [path appendBezierPathWithRect: right]; 3306 } 3307 3308 // MinY 3309 if (NSMinY(titleRect) > NSMinY(borderRect)) 3310 { 3311 NSRect minY = borderRect; 3312 minY.size.height = NSMinY(titleRect) - NSMinY(borderRect); 3313 [path appendBezierPathWithRect: minY]; 3314 } 3315 3316 // MaxY 3317 if (NSMaxY(borderRect) > NSMaxY(titleRect)) 3318 { 3319 NSRect maxY = borderRect; 3320 maxY.size.height = NSMaxY(borderRect) - NSMaxY(titleRect); 3321 maxY.origin.y = NSMaxY(titleRect); 3322 [path appendBezierPathWithRect: maxY]; 3323 } 3324 3325 if (![path isEmpty]) 3326 { 3327 [path addClip]; 3328 } 3329 } 3330 3331 3332 [[GSTheme theme] fillRect: [box borderRect] 3333 withTiles: tiles]; 3334 3335 // Restore clipping path 3336 [NSGraphicsContext restoreGraphicsState]; 3337 } 3338 3339 3340 // Draw title 3341 if ([box titlePosition] != NSNoTitle) 3342 { 3343 // If the title is on the border, clip a hole in the later 3344 if (drawTitleBackground 3345 && (borderType != NSNoBorder) 3346 && (([box titlePosition] == NSAtTop) || ([box titlePosition] == NSAtBottom))) 3347 { 3348 [color set]; 3349 NSRectFill([box titleRect]); 3350 } 3351 3352 [[box titleCell] drawWithFrame: [box titleRect] inView: box]; 3353 } 3354} 3355 3356- (void) drawEditorForCell: (NSCell *)cell 3357 withFrame: (NSRect)cellFrame 3358 inView: (NSView *)view 3359{ 3360 [cell _drawEditorWithFrame: cellFrame 3361 inView: view]; 3362} 3363 3364 3365- (void) drawInCell: (NSCell *)cell 3366 attributedText: (NSAttributedString *)stringValue 3367 inFrame: (NSRect)cellFrame 3368{ 3369 [cell _drawAttributedText: stringValue 3370 inFrame: cellFrame]; 3371} 3372 3373// NSBrowserCell 3374- (void) drawBrowserInteriorWithFrame: (NSRect)cellFrame 3375 withCell: (NSBrowserCell *)cell 3376 inView: (NSView *)controlView 3377 withImage: (NSImage *)theImage 3378 alternateImage: (NSImage *)alternateImage 3379 isHighlighted: (BOOL)isHighlighted 3380 state: (int)state 3381 isLeaf: (BOOL)isLeaf 3382{ 3383 NSRect title_rect = cellFrame; 3384 NSImage *branch_image = nil; 3385 NSImage *cell_image = theImage; 3386 3387 if (isHighlighted || state) 3388 { 3389 if (!isLeaf) 3390 branch_image = [self highlightedBranchImage]; 3391 if (nil != alternateImage) 3392 [cell setImage: alternateImage]; 3393 3394 // If we are highlighted, fill the background 3395 [[cell highlightColorInView: controlView] setFill]; 3396 NSRectFill(cellFrame); 3397 } 3398 else 3399 { 3400 if (!isLeaf) 3401 branch_image = [self branchImage]; 3402 3403 // (Don't fill the background) 3404 } 3405 3406 // Draw the branch image if there is one 3407 if (branch_image) 3408 { 3409 NSRect imgRect; 3410 3411 imgRect.size = [branch_image size]; 3412 imgRect.origin.x = MAX(NSMaxX(title_rect) - imgRect.size.width - 4.0, 0.); 3413 imgRect.origin.y = MAX(NSMidY(title_rect) - (imgRect.size.height/2.), 0.); 3414 3415 if (controlView != nil) 3416 { 3417 imgRect = [controlView centerScanRect: imgRect]; 3418 } 3419 3420 [branch_image drawInRect: imgRect 3421 fromRect: NSZeroRect 3422 operation: NSCompositeSourceOver 3423 fraction: 1.0 3424 respectFlipped: YES 3425 hints: nil]; 3426 3427 title_rect.size.width -= imgRect.size.width + 8; 3428 } 3429 3430 // Skip 2 points from the left border 3431 title_rect.origin.x += 2; 3432 title_rect.size.width -= 2; 3433 3434 // Draw the cell image if there is one 3435 if (cell_image) 3436 { 3437 NSRect imgRect; 3438 3439 imgRect.size = [cell_image size]; 3440 imgRect.origin.x = NSMinX(title_rect); 3441 imgRect.origin.y = MAX(NSMidY(title_rect) - (imgRect.size.height/2.),0.); 3442 3443 if (controlView != nil) 3444 { 3445 imgRect = [controlView centerScanRect: imgRect]; 3446 } 3447 3448 [cell_image drawInRect: imgRect 3449 fromRect: NSZeroRect 3450 operation: NSCompositeSourceOver 3451 fraction: 1.0 3452 respectFlipped: YES 3453 hints: nil]; 3454 3455 title_rect.origin.x += imgRect.size.width + 4; 3456 title_rect.size.width -= imgRect.size.width + 4; 3457 } 3458 3459 // Draw the body of the cell 3460 if ([cell _inEditing]) 3461 { 3462 [self drawEditorForCell: cell 3463 withFrame: cellFrame 3464 inView: controlView]; 3465 } 3466 else 3467 { 3468 [self drawInCell: cell 3469 attributedText: [cell attributedStringValue] 3470 inFrame: title_rect]; 3471 } 3472} 3473 3474- (NSImage *) branchImage 3475{ 3476 return [NSImage imageNamed: @"common_3DArrowRight"]; 3477} 3478 3479- (NSImage *) highlightedBranchImage 3480{ 3481 return [NSImage imageNamed: @"common_3DArrowRightH"]; 3482} 3483@end 3484