1/** <title>GSThemeTools</title> 2 3 <abstract>Useful/configurable drawing functions</abstract> 4 5 Copyright (C) 2004 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 <Foundation/NSException.h> 30#import "AppKit/NSBezierPath.h" 31#import "AppKit/NSGraphics.h" 32#import "AppKit/NSImage.h" 33#import "AppKit/PSOperators.h" 34#import "GSThemePrivate.h" 35 36#include <math.h> 37#include <float.h> 38 39 40@implementation GSTheme (MidLevelDrawing) 41 42- (NSRect) drawButton: (NSRect)border withClip: (NSRect)clip 43{ 44 NSRectEdge up_sides[] = {NSMaxXEdge, NSMinYEdge, 45 NSMinXEdge, NSMaxYEdge, 46 NSMaxXEdge, NSMinYEdge}; 47 NSRectEdge dn_sides[] = {NSMaxXEdge, NSMaxYEdge, 48 NSMinXEdge, NSMinYEdge, 49 NSMaxXEdge, NSMaxYEdge}; 50 // These names are role names not the actual colours 51 NSColor *black = [NSColor controlDarkShadowColor]; 52 NSColor *dark = [NSColor controlShadowColor]; 53 NSColor *white = [NSColor controlLightHighlightColor]; 54 NSColor *colors[] = {black, black, white, white, dark, dark}; 55 56 if ([[NSView focusView] isFlipped] == YES) 57 { 58 return NSDrawColorTiledRects(border, clip, dn_sides, colors, 6); 59 } 60 else 61 { 62 return NSDrawColorTiledRects(border, clip, up_sides, colors, 6); 63 } 64} 65 66- (NSRect) drawDarkBezel: (NSRect)border withClip: (NSRect)clip 67{ 68 NSRectEdge up_sides[] = {NSMaxXEdge, NSMinYEdge, NSMinXEdge, NSMaxYEdge, 69 NSMinXEdge, NSMaxYEdge, NSMaxXEdge, NSMinYEdge}; 70 NSRectEdge dn_sides[] = {NSMaxXEdge, NSMaxYEdge, NSMinXEdge, NSMinYEdge, 71 NSMinXEdge, NSMinYEdge, NSMaxXEdge, NSMaxYEdge}; 72 // These names are role names not the actual colours 73 NSColor *black = [NSColor controlDarkShadowColor]; 74 NSColor *dark = [NSColor controlShadowColor]; 75 NSColor *light = [NSColor controlColor]; 76 NSColor *white = [NSColor controlLightHighlightColor]; 77 NSColor *colors[] = {white, white, dark, dark, black, black, light, light}; 78 NSRect rect; 79 80 if ([[NSView focusView] isFlipped] == YES) 81 { 82 rect = NSDrawColorTiledRects(border, clip, dn_sides, colors, 8); 83 84 [dark set]; 85 PSrectfill(NSMinX(border) + 1., NSMinY(border) - 2., 1., 1.); 86 PSrectfill(NSMaxX(border) - 2., NSMaxY(border) + 1., 1., 1.); 87 } 88 else 89 { 90 rect = NSDrawColorTiledRects(border, clip, up_sides, colors, 8); 91 92 [dark set]; 93 PSrectfill(NSMinX(border) + 1., NSMinY(border) + 1., 1., 1.); 94 PSrectfill(NSMaxX(border) - 2., NSMaxY(border) - 2., 1., 1.); 95 } 96 return rect; 97} 98 99- (NSRect) drawDarkButton: (NSRect)border withClip: (NSRect)clip 100{ 101 NSRectEdge up_sides[] = {NSMaxXEdge, NSMinYEdge, 102 NSMinXEdge, NSMaxYEdge}; 103 NSRectEdge dn_sides[] = {NSMaxXEdge, NSMaxYEdge, 104 NSMinXEdge, NSMinYEdge}; 105 // These names are role names not the actual colours 106 NSColor *black = [NSColor controlDarkShadowColor]; 107 NSColor *white = [NSColor controlHighlightColor]; 108 NSColor *colors[] = {black, black, white, white}; 109 110 if ([[NSView focusView] isFlipped] == YES) 111 { 112 return NSDrawColorTiledRects(border, clip, dn_sides, colors, 4); 113 } 114 else 115 { 116 return NSDrawColorTiledRects(border, clip, up_sides, colors, 4); 117 } 118} 119 120- (NSRect) drawFramePhoto: (NSRect)border withClip: (NSRect)clip 121{ 122 NSRectEdge up_sides[] = {NSMaxXEdge, NSMinYEdge, 123 NSMinXEdge, NSMaxYEdge, 124 NSMaxXEdge, NSMinYEdge}; 125 NSRectEdge dn_sides[] = {NSMaxXEdge, NSMaxYEdge, 126 NSMinXEdge, NSMinYEdge, 127 NSMaxXEdge, NSMaxYEdge}; 128 // These names are role names not the actual colours 129 NSColor *black = [NSColor controlDarkShadowColor]; 130 NSColor *dark = [NSColor controlShadowColor]; 131 NSColor *colors[] = {dark, dark, dark, dark, black,black}; 132 133 if ([[NSView focusView] isFlipped] == YES) 134 { 135 return NSDrawColorTiledRects(border, clip, dn_sides, colors, 6); 136 } 137 else 138 { 139 return NSDrawColorTiledRects(border, clip, up_sides, colors, 6); 140 } 141} 142 143#if 1 144- (NSRect) drawGradientBorder: (NSGradientType)gradientType 145 inRect: (NSRect)border 146 withClip: (NSRect)clip 147{ 148 NSRectEdge up_sides[] = {NSMaxXEdge, NSMinYEdge, 149 NSMinXEdge, NSMaxYEdge}; 150 NSRectEdge dn_sides[] = {NSMaxXEdge, NSMaxYEdge, 151 NSMinXEdge, NSMinYEdge}; 152 NSColor *black = [NSColor controlDarkShadowColor]; 153 NSColor *dark = [NSColor controlShadowColor]; 154 NSColor *light = [NSColor controlColor]; 155 NSColor **colors; 156 NSColor *concaveWeak[] = {dark, dark, light, light}; 157 NSColor *concaveStrong[] = {black, black, light, light}; 158 NSColor *convexWeak[] = {light, light, dark, dark}; 159 NSColor *convexStrong[] = {light, light, black, black}; 160 NSRect rect; 161 162 switch (gradientType) 163 { 164 case NSGradientConcaveWeak: 165 colors = concaveWeak; 166 break; 167 case NSGradientConcaveStrong: 168 colors = concaveStrong; 169 break; 170 case NSGradientConvexWeak: 171 colors = convexWeak; 172 break; 173 case NSGradientConvexStrong: 174 colors = convexStrong; 175 break; 176 case NSGradientNone: 177 default: 178 return border; 179 } 180 181 if ([[NSView focusView] isFlipped] == YES) 182 { 183 rect = NSDrawColorTiledRects(border, clip, dn_sides, colors, 4); 184 } 185 else 186 { 187 rect = NSDrawColorTiledRects(border, clip, up_sides, colors, 4); 188 } 189 190 return rect; 191} 192 193#else 194// FIXME: I think this method is wrong. 195- (NSRect) drawGradientBorder: (NSGradientType)gradientType 196 inRect: (NSRect)cellFrame 197 withClip: (NSRect)clip 198{ 199 float start_white = 0.0; 200 float end_white = 0.0; 201 float white = 0.0; 202 float white_step = 0.0; 203 float h, s, v, a; 204 NSPoint p1, p2; 205 NSColor *gray = nil; 206 NSColor *darkGray = nil; 207 NSColor *lightGray = nil; 208 209 lightGray = [NSColor colorWithDeviceRed: NSLightGray 210 green: NSLightGray 211 blue: NSLightGray 212 alpha:1.0]; 213 gray = [NSColor colorWithDeviceRed: NSGray 214 green: NSGray 215 blue: NSGray 216 alpha:1.0]; 217 darkGray = [NSColor colorWithDeviceRed: NSDarkGray 218 green: NSDarkGray 219 blue: NSDarkGray 220 alpha:1.0]; 221 222 switch (gradientType) 223 { 224 case NSGradientNone: 225 return NSZeroRect; 226 break; 227 228 case NSGradientConcaveWeak: 229 [gray getHue: &h saturation: &s brightness: &v alpha: &a]; 230 start_white = [lightGray brightnessComponent]; 231 end_white = [gray brightnessComponent]; 232 break; 233 234 case NSGradientConvexWeak: 235 [darkGray getHue: &h saturation: &s brightness: &v alpha: &a]; 236 start_white = [gray brightnessComponent]; 237 end_white = [lightGray brightnessComponent]; 238 break; 239 240 case NSGradientConcaveStrong: 241 [lightGray getHue: &h saturation: &s brightness: &v alpha: &a]; 242 start_white = [lightGray brightnessComponent]; 243 end_white = [darkGray brightnessComponent]; 244 break; 245 246 case NSGradientConvexStrong: 247 [darkGray getHue: &h saturation: &s brightness: &v alpha: &a]; 248 start_white = [darkGray brightnessComponent]; 249 end_white = [lightGray brightnessComponent]; 250 break; 251 252 default: 253 break; 254 } 255 256 white = start_white; 257 white_step = fabs(start_white - end_white) 258 / (cellFrame.size.width + cellFrame.size.height); 259 260 // Start from top left 261 p1 = NSMakePoint(cellFrame.origin.x, 262 cellFrame.size.height + cellFrame.origin.y); 263 p2 = NSMakePoint(cellFrame.origin.x, 264 cellFrame.size.height + cellFrame.origin.y); 265 266 // Move by Y 267 while (p1.y > cellFrame.origin.y) 268 { 269 [[NSColor 270 colorWithDeviceHue: h saturation: s brightness: white alpha: 1.0] set]; 271 [NSBezierPath strokeLineFromPoint: p1 toPoint: p2]; 272 273 if (start_white > end_white) 274 white -= white_step; 275 else 276 white += white_step; 277 278 p1.y -= 1.0; 279 if (p2.x < (cellFrame.size.width + cellFrame.origin.x)) 280 p2.x += 1.0; 281 else 282 p2.y -= 1.0; 283 } 284 285 // Move by X 286 while (p1.x < (cellFrame.size.width + cellFrame.origin.x)) 287 { 288 [[NSColor 289 colorWithDeviceHue: h saturation: s brightness: white alpha: 1.0] set]; 290 [NSBezierPath strokeLineFromPoint: p1 toPoint: p2]; 291 292 if (start_white > end_white) 293 white -= white_step; 294 else 295 white += white_step; 296 297 p1.x += 1.0; 298 if (p2.x >= (cellFrame.size.width + cellFrame.origin.x)) 299 p2.y -= 1.0; 300 else 301 p2.x += 1.0; 302 } 303 304 return NSZeroRect; 305} 306 307#endif 308 309- (NSRect) drawGrayBezel: (NSRect)border withClip: (NSRect)clip 310{ 311 NSRectEdge up_sides[] = {NSMaxXEdge, NSMinYEdge, NSMinXEdge, NSMaxYEdge, 312 NSMaxXEdge, NSMinYEdge, NSMinXEdge, NSMaxYEdge}; 313 NSRectEdge dn_sides[] = {NSMaxXEdge, NSMaxYEdge, NSMinXEdge, NSMinYEdge, 314 NSMaxXEdge, NSMaxYEdge, NSMinXEdge, NSMinYEdge}; 315 // These names are role names not the actual colours 316 NSColor *black = [NSColor controlDarkShadowColor]; 317 NSColor *dark = [NSColor controlShadowColor]; 318 NSColor *light = [NSColor controlColor]; 319 NSColor *white = [NSColor controlLightHighlightColor]; 320 NSColor *colors[] = {white, white, dark, dark, 321 light, light, black, black}; 322 NSRect rect; 323 324 if ([[NSView focusView] isFlipped] == YES) 325 { 326 rect = NSDrawColorTiledRects(border, clip, dn_sides, colors, 8); 327 [dark set]; 328 PSrectfill(NSMinX(border) + 1., NSMaxY(border) - 2., 1., 1.); 329 PSrectfill(NSMaxX(border) - 2., NSMinY(border) + 1., 1., 1.); 330 } 331 else 332 { 333 rect = NSDrawColorTiledRects(border, clip, up_sides, colors, 8); 334 [dark set]; 335 PSrectfill(NSMinX(border) + 1., NSMinY(border) + 1., 1., 1.); 336 PSrectfill(NSMaxX(border) - 2., NSMaxY(border) - 2., 1., 1.); 337 } 338 return rect; 339} 340 341- (NSRect) drawGroove: (NSRect)border withClip: (NSRect)clip 342{ 343 // go clockwise from the top twice -- makes the groove come out right 344 NSRectEdge up_sides[] = {NSMaxYEdge, NSMaxXEdge, NSMinYEdge, NSMinXEdge, 345 NSMaxYEdge, NSMaxXEdge, NSMinYEdge, NSMinXEdge}; 346 NSRectEdge dn_sides[] = {NSMinYEdge, NSMaxXEdge, NSMaxYEdge, NSMinXEdge, 347 NSMinYEdge, NSMaxXEdge, NSMaxYEdge, NSMinXEdge}; 348 // These names are role names not the actual colours 349 NSColor *dark = [NSColor controlShadowColor]; 350 NSColor *white = [NSColor controlLightHighlightColor]; 351 NSColor *colors[] = {dark, white, white, dark, 352 white, dark, dark, white}; 353 354 if ([[NSView focusView] isFlipped] == YES) 355 { 356 return NSDrawColorTiledRects(border, clip, dn_sides, colors, 8); 357 } 358 else 359 { 360 return NSDrawColorTiledRects(border, clip, up_sides, colors, 8); 361 } 362} 363 364- (NSRect) drawLightBezel: (NSRect)border withClip: (NSRect)clip 365{ 366 NSRectEdge up_sides[] = {NSMaxXEdge, NSMinYEdge, NSMinXEdge, NSMaxYEdge, 367 NSMaxXEdge, NSMinYEdge, NSMinXEdge, NSMaxYEdge}; 368 NSRectEdge dn_sides[] = {NSMaxXEdge, NSMaxYEdge, NSMinXEdge, NSMinYEdge, 369 NSMaxXEdge, NSMaxYEdge, NSMinXEdge, NSMinYEdge}; 370 // These names are role names not the actual colours 371 NSColor *dark = [NSColor controlShadowColor]; 372 NSColor *light = [NSColor controlColor]; 373 NSColor *white = [NSColor controlLightHighlightColor]; 374 NSColor *colors[] = {white, white, dark, dark, 375 light, light, dark, dark}; 376 377 if ([[NSView focusView] isFlipped] == YES) 378 { 379 return NSDrawColorTiledRects(border, clip, dn_sides, colors, 8); 380 } 381 else 382 { 383 return NSDrawColorTiledRects(border, clip, up_sides, colors, 8); 384 } 385} 386 387- (NSRect) drawWhiteBezel: (NSRect)border withClip: (NSRect)clip 388{ 389 NSRectEdge up_sides[] = {NSMaxYEdge, NSMaxXEdge, NSMinYEdge, NSMinXEdge, 390 NSMaxYEdge, NSMaxXEdge, NSMinYEdge, NSMinXEdge}; 391 NSRectEdge dn_sides[] = {NSMinYEdge, NSMaxXEdge, NSMaxYEdge, NSMinXEdge, 392 NSMinYEdge, NSMaxXEdge, NSMaxYEdge, NSMinXEdge}; 393 // These names are role names not the actual colours 394 NSColor *dark = [NSColor controlShadowColor]; 395 NSColor *light = [NSColor controlColor]; 396 NSColor *white = [NSColor controlLightHighlightColor]; 397 NSColor *colors[] = {dark, white, white, dark, 398 dark, light, light, dark}; 399 400 if ([[NSView focusView] isFlipped] == YES) 401 { 402 return NSDrawColorTiledRects(border, clip, dn_sides, colors, 8); 403 } 404 else 405 { 406 return NSDrawColorTiledRects(border, clip, up_sides, colors, 8); 407 } 408} 409 410- (void) drawRoundBezel: (NSRect)cellFrame withColor: (NSColor*)backgroundColor 411{ 412 NSBezierPath *p; 413 NSPoint point; 414 CGFloat radius; 415 416 // make smaller than enclosing frame 417 cellFrame = NSInsetRect(cellFrame, 4, 4); 418 radius = cellFrame.size.height / 2.0; 419 point = cellFrame.origin; 420 point.x += radius; 421 point.y += radius - 0.5; 422 423 // Draw initial path to enclose the button... 424 // left half-circle 425 p = [NSBezierPath bezierPath]; 426 [p appendBezierPathWithArcWithCenter: point 427 radius: radius 428 startAngle: 90.0 429 endAngle: 270.0]; 430 431 // line to first point and right halfcircle 432 point.x += cellFrame.size.width - cellFrame.size.height; 433 [p appendBezierPathWithArcWithCenter: point 434 radius: radius 435 startAngle: 270.0 436 endAngle: 90.0]; 437 [p closePath]; 438 439 // fill with background color 440 [backgroundColor set]; 441 [p fill]; 442 443 // and stroke rounded button 444 [[NSColor shadowColor] set]; 445 [p stroke]; 446 447 // Add highlights... 448 point = cellFrame.origin; 449 point.x += radius - 0.5; 450 point.y += radius - 0.5; 451 p = [NSBezierPath bezierPath]; 452 [p setLineWidth: 1.0]; 453 [p appendBezierPathWithArcWithCenter: point 454 radius: radius 455 startAngle: 135.0 456 endAngle: 270.0]; 457 458 // line to first point and right halfcircle 459 point.x += cellFrame.size.width - cellFrame.size.height; 460 [p appendBezierPathWithArcWithCenter: point 461 radius: radius 462 startAngle: 270.0 463 endAngle: 315.0]; 464 [[NSColor controlLightHighlightColor] set]; 465 [p stroke]; 466} 467 468- (void) drawCircularBezel: (NSRect)cellFrame 469 withColor: (NSColor*)backgroundColor 470{ 471 // make smaller so that it does not touch frame 472 NSBezierPath *oval; 473 474 oval = [NSBezierPath bezierPathWithOvalInRect: NSInsetRect(cellFrame, 1, 1)]; 475 476 // fill oval with background color 477 [backgroundColor set]; 478 [oval fill]; 479 480 // and stroke rounded button 481 [[NSColor shadowColor] set]; 482 [oval stroke]; 483} 484 485@end 486 487 488 489@implementation GSTheme (LowLevelDrawing) 490 491- (void) fillHorizontalRect: (NSRect)rect 492 withImage: (NSImage*)image 493 fromRect: (NSRect)source 494 flipped: (BOOL)flipped 495{ 496 NSGraphicsContext *ctxt = GSCurrentContext(); 497 NSBezierPath *path; 498 unsigned repetitions; 499 float remainder; 500 unsigned count; 501 NSPoint p; 502 float y; 503 504 if (rect.size.width <= 0.0) 505 [NSException raise: NSInvalidArgumentException 506 format: @"[%@-%@] rect width is not positive", 507 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 508 if (rect.size.height <= 0.0) 509 [NSException raise: NSInvalidArgumentException 510 format: @"[%@-%@] rect height is not positive", 511 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 512 if (source.size.width <= 0.0) 513 [NSException raise: NSInvalidArgumentException 514 format: @"[%@-%@] source width is not positive", 515 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 516 if (source.size.height <= 0.0) 517 [NSException raise: NSInvalidArgumentException 518 format: @"[%@-%@] source height is not positive", 519 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 520 if (image == nil) 521 [NSException raise: NSInvalidArgumentException 522 format: @"[%@-%@] image is nil", 523 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 524 525 ctxt = GSCurrentContext(); 526 DPSgsave (ctxt); 527 path = [NSBezierPath bezierPathWithRect: rect]; 528 [path addClip]; 529 repetitions = rect.size.width / source.size.width; 530 remainder = rect.size.width - repetitions * source.size.width; 531 y = rect.origin.y; 532 533 if (flipped) y = rect.origin.y + rect.size.height; 534 535 for (count = 0; count < repetitions; count++) 536 { 537 p = NSMakePoint (rect.origin.x + count * source.size.width, y); 538 [image compositeToPoint: p 539 fromRect: source 540 operation: NSCompositeSourceOver]; 541 } 542 if (remainder > 0) 543 { 544 p = NSMakePoint (rect.origin.x + repetitions * source.size.width, y); 545 source.size.width = remainder; 546 [image compositeToPoint: p 547 fromRect: source 548 operation: NSCompositeSourceOver]; 549 } 550 DPSgrestore (ctxt); 551} 552 553- (void) fillRect: (NSRect)rect 554withRepeatedImage: (NSImage*)image 555 fromRect: (NSRect)source 556 center: (BOOL)center 557{ 558 NSGraphicsContext *ctxt; 559 NSBezierPath *path; 560 NSSize size; 561 unsigned xrepetitions; 562 unsigned yrepetitions; 563 unsigned x; 564 unsigned y; 565 566 if (rect.size.width <= 0.0) 567 [NSException raise: NSInvalidArgumentException 568 format: @"[%@-%@] rect width is not positive", 569 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 570 if (rect.size.height <= 0.0) 571 [NSException raise: NSInvalidArgumentException 572 format: @"[%@-%@] rect height is not positive", 573 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 574 if (source.size.width <= 0.0) 575 [NSException raise: NSInvalidArgumentException 576 format: @"[%@-%@] source width is not positive", 577 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 578 if (source.size.height <= 0.0) 579 [NSException raise: NSInvalidArgumentException 580 format: @"[%@-%@] source height is not positive", 581 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 582 if (image == nil) 583 [NSException raise: NSInvalidArgumentException 584 format: @"[%@-%@] image is nil", 585 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 586 587 ctxt = GSCurrentContext (); 588 DPSgsave (ctxt); 589 path = [NSBezierPath bezierPathWithRect: rect]; 590 [path addClip]; 591 size = [image size]; 592 xrepetitions = (rect.size.width / size.width) + 1; 593 yrepetitions = (rect.size.height / size.height) + 1; 594 595 for (x = 0; x < xrepetitions; x++) 596 { 597 for (y = 0; y < yrepetitions; y++) 598 { 599 NSPoint p; 600 601 p = NSMakePoint (rect.origin.x + x * size.width, 602 rect.origin.y + y * size.height); 603 [image compositeToPoint: p 604 fromRect: source 605 operation: NSCompositeSourceOver]; 606 } 607 } 608 DPSgrestore (ctxt); 609} 610 611- (NSRect) fillRect: (NSRect)rect 612 withTiles: (GSDrawTiles*)tiles 613 background: (NSColor*)color 614{ 615 return [self fillRect: rect 616 withTiles: tiles 617 background: color 618 fillStyle: [tiles fillStyle]]; 619} 620 621- (NSRect) fillRect: (NSRect)rect 622 withTiles: (GSDrawTiles*)tiles 623{ 624 return [self fillRect: rect 625 withTiles: tiles 626 background: [NSColor clearColor] 627 fillStyle: [tiles fillStyle]]; 628} 629 630- (NSRect) fillRect: (NSRect)rect 631 withTiles: (GSDrawTiles*)tiles 632 background: (NSColor*)color 633 fillStyle: (GSThemeFillStyle)style 634{ 635 if (rect.size.width <= 0.0) 636 [NSException raise: NSInvalidArgumentException 637 format: @"[%@-%@] rect width is not positive", 638 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 639 if (rect.size.height <= 0.0) 640 [NSException raise: NSInvalidArgumentException 641 format: @"[%@-%@] rect height is not positive", 642 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 643 if (tiles == nil) 644 [NSException raise: NSInvalidArgumentException 645 format: @"[%@-%@] tiles is nil", 646 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 647 648 return [tiles fillRect: rect background: color fillStyle: style]; 649} 650 651- (void) fillVerticalRect: (NSRect)rect 652 withImage: (NSImage*)image 653 fromRect: (NSRect)source 654 flipped: (BOOL)flipped 655{ 656 NSGraphicsContext *ctxt; 657 NSBezierPath *path; 658 unsigned repetitions; 659 float remainder; 660 unsigned count; 661 NSPoint p; 662 663 if (rect.size.width <= 0.0) 664 [NSException raise: NSInvalidArgumentException 665 format: @"[%@-%@] rect width is not positive", 666 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 667 if (rect.size.height <= 0.0) 668 [NSException raise: NSInvalidArgumentException 669 format: @"[%@-%@] rect height is not positive", 670 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 671 if (source.size.width <= 0.0) 672 [NSException raise: NSInvalidArgumentException 673 format: @"[%@-%@] source width is not positive", 674 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 675 if (source.size.height <= 0.0) 676 [NSException raise: NSInvalidArgumentException 677 format: @"[%@-%@] source height is not positive", 678 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 679 if (image == nil) 680 [NSException raise: NSInvalidArgumentException 681 format: @"[%@-%@] image is nil", 682 NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; 683 ctxt = GSCurrentContext(); 684 DPSgsave (ctxt); 685 path = [NSBezierPath bezierPathWithRect: rect]; 686 [path addClip]; 687 repetitions = rect.size.height / source.size.height; 688 remainder = rect.size.height - repetitions * source.size.height; 689 690 if (flipped) 691 { 692 for (count = 0; count < repetitions; count++) 693 { 694 p = NSMakePoint (rect.origin.x, 695 rect.origin.y + rect.size.height - count * source.size.height); 696 [image compositeToPoint: p 697 fromRect: source 698 operation: NSCompositeSourceOver]; 699 } 700 if (remainder > 0) 701 { 702 p = NSMakePoint (rect.origin.x, 703 rect.origin.y + rect.size.height 704 - repetitions * source.size.height); 705 source.origin.y += source.size.height - remainder; 706 source.size.height = remainder; 707 [image compositeToPoint: p 708 fromRect: source 709 operation: NSCompositeSourceOver]; 710 } 711 } 712 else 713 { 714 for (count = 0; count < repetitions; count++) 715 { 716 p = NSMakePoint (rect.origin.x, 717 rect.origin.y + count * source.size.height); 718 [image compositeToPoint: p 719 fromRect: source 720 operation: NSCompositeSourceOver]; 721 } 722 if (remainder > 0) 723 { 724 p = NSMakePoint (rect.origin.x, 725 rect.origin.y + repetitions * source.size.height); 726 source.size.height = remainder; 727 [image compositeToPoint: p 728 fromRect: source 729 operation: NSCompositeSourceOver]; 730 } 731 } 732 DPSgrestore (ctxt); 733} 734 735@end 736 737 738 739@implementation GSDrawTiles 740- (id) copyWithZone: (NSZone*)zone 741{ 742 GSDrawTiles *c = (GSDrawTiles*)NSCopyObject(self, 0, zone); 743 unsigned i; 744 745 for (i = 0; i < 9; i++) 746 { 747 c->images[i] = [images[i] copyWithZone: zone]; 748 } 749 c->style = style; 750 return c; 751} 752 753- (void) dealloc 754{ 755 unsigned i; 756 757 for (i = 0; i < 9; i++) 758 { 759 RELEASE(images[i]); 760 } 761 [super dealloc]; 762} 763 764- (NSString*) description 765{ 766 NSMutableString *d = [[[super description] mutableCopy] autorelease]; 767 unsigned i; 768 769 for (i = 0; i < 9; i++) 770 { 771 [d appendFormat: @"\n %@ %@", NSStringFromRect(rects[i]), images[i]]; 772 } 773 774 return d; 775} 776 777/** 778 * Simple initialiser, assume the single image is split into nine equal tiles. 779 * If the image size is not divisible by three, the corners are made equal 780 * in size and the central parts slightly smaller. 781 */ 782- (id) initWithImage: (NSImage*)image 783{ 784 NSSize s = [image size]; 785 786 return [self initWithImage: image 787 horizontal: s.width / 3.0 788 vertical: s.height / 3.0]; 789} 790 791- (id) initWithNinePatchImage: (NSImage*)image 792{ 793 int i; 794 CGFloat r,g,b,a; 795 int x1 = -1; // x1, x2, y1, y2, are in flipped coordinates 796 int x2 = -1; // 0,0 is the top-left pixel 797 int y1 = -1; 798 int y2 = -1; 799 NSSize s = [image size]; 800 NSBitmapImageRep* rep = [[image representations] objectAtIndex: 0]; 801 802 for (i = 0; i < s.width; i++) 803 { 804 NSColor *pixelColor = [rep colorAtX: i y: 0]; 805 806 [pixelColor getRed: &r green: &g blue: &b alpha: &a]; 807 if (a > 0 && x1 == -1) 808 { 809 x1 = i; 810 } 811 else if (a == 0 && x1 != -1) 812 { 813 x2 = i - 1; 814 break; 815 } 816 } 817 818 for (i = 0; i < s.height; i++) 819 { 820 NSColor *pixelColor = [rep colorAtX: 0 y: i]; 821 822 [pixelColor getRed: &r green: &g blue: &b alpha: &a]; 823 if (a > 0 && y1 == -1) 824 { 825 y1 = i; 826 } 827 else if (a == 0 && y1 != -1) 828 { 829 y2 = i - 1; 830 break; 831 } 832 } 833 834 scaleFactor = 1.0f; 835 style = GSThemeFillStyleScaleAll; 836 837 // These are all in _unflipped_ coordinates 838 rects[TileTL] = NSMakeRect(1, s.height - y1, x1 - 1, y1 - 1); 839 rects[TileTM] = NSMakeRect(x1, s.height - y1, 1 + x2 - x1, y1 - 1); 840 rects[TileTR] = NSMakeRect(x2 + 1, s.height - y1, s.width - x2 - 2, y1 - 1); 841 rects[TileCL] = NSMakeRect(1, s.height - y2 - 1, x1 - 1, 1 + y2 - y1); 842 rects[TileCM] = NSMakeRect(x1, s.height - y2 - 1, 1 + x2 - x1, 1 + y2 - y1); 843 rects[TileCR] = NSMakeRect(x2 + 1, s.height - y2 - 1, s.width - x2 - 2, 1 + y2 - y1); 844 rects[TileBL] = NSMakeRect(1, 1, x1 - 1, s.height - y2 - 2); 845 rects[TileBM] = NSMakeRect(x1, 1, 1 + x2 - x1, s.height - y2 - 2); 846 rects[TileBR] = NSMakeRect(x2 + 1, 1, s.width - x2 - 2, s.height - y2 - 2); 847 848 // Measure the content rect (the right and bottom edges of the nine-patch 849 // data) 850 851 x1 = -1; 852 x2 = -1; 853 y1 = -1; 854 y2 = -1; 855 856 for (i = 0; i < s.width; i++) 857 { 858 NSColor *pixelColor = [rep colorAtX: i y: s.height - 1]; 859 860 [pixelColor getRed: &r green: &g blue: &b alpha: &a]; 861 if ((a == 1 && r == 0 && g == 0 && b == 0) && x1 == -1) 862 { 863 x1 = i; 864 } 865 else if (!(a == 1 && r == 0 && g == 0 && b == 0) && x1 != -1) 866 { 867 x2 = i - 1; 868 break; 869 } 870 } 871 872 for (i = 0; i < s.height; i++) 873 { 874 NSColor *pixelColor = [rep colorAtX: s.width - 1 y: i]; 875 876 [pixelColor getRed: &r green: &g blue: &b alpha: &a]; 877 if ((a == 1 && r == 0 && g == 0 && b == 0) && y1 == -1) 878 { 879 y1 = i; 880 } 881 else if (!(a == 1 && r == 0 && g == 0 && b == 0) && y1 != -1) 882 { 883 y2 = i - 1; 884 break; 885 } 886 } 887 888 // Specifying the content rect part of the nine-patch image is optional 889 // ; if either the horizontal or vertical information is missing, use the 890 // geometry from rects[TileCM] 891 892 // contentRect is in unflipped coordinates, like rects[] 893 894 if (x1 == -1) 895 { 896 contentRect.origin.x = rects[TileCM].origin.x; 897 contentRect.size.width = rects[TileCM].size.width; 898 } 899 else 900 { 901 contentRect.origin.x = x1; 902 contentRect.size.width = 1 + x2 - x1; 903 } 904 905 if (y1 == -1) 906 { 907 contentRect.origin.y = rects[TileCM].origin.y; 908 contentRect.size.height = rects[TileCM].size.height; 909 } 910 else 911 { 912 contentRect.origin.y = s.height - y2 - 1; 913 contentRect.size.height = 1 + y2 - y1; 914 } 915 916 // Measure the layout rect (the right and bottom edges of the nine-patch 917 // data which _isn't_ red pixels) 918 919 x1 = -1; 920 x2 = -1; 921 y1 = -1; 922 y2 = -1; 923 924 for (i = 1; i < (s.width - 1); i++) 925 { 926 NSColor *pixelColor = [rep colorAtX: i y: s.height - 1]; 927 928 [pixelColor getRed: &r green: &g blue: &b alpha: &a]; 929 if (!(a == 1 && r == 1 && g == 0 && b == 0) && x1 == -1) 930 { 931 x1 = i; 932 } 933 else if ((a == 1 && r == 1 && g == 0 && b == 0) && x1 != -1) 934 { 935 x2 = i - 1; 936 break; 937 } 938 } 939 940 for (i = 1; i < (s.height - 1); i++) 941 { 942 NSColor *pixelColor = [rep colorAtX: s.width - 1 y: i]; 943 944 [pixelColor getRed: &r green: &g blue: &b alpha: &a]; 945 if (!(a == 1 && r == 1 && g == 0 && b == 0) && y1 == -1) 946 { 947 y1 = i; 948 } 949 else if ((a == 1 && r == 1 && g == 0 && b == 0) && y1 != -1) 950 { 951 y2 = i - 1; 952 break; 953 } 954 } 955 956 957 if (x2 == -1) 958 { 959 x2 = s.width - 2; 960 } 961 962 if (y2 == -1) 963 { 964 y2 = s.height - 2; 965 } 966 967 layoutRect = NSMakeRect(x1, s.height - y2 - 1, 1 + x2 - x1, 1 + y2 - y1); 968 969 [self validateTilesSizeWithImage: image]; 970 return self; 971} 972 973- (NSImage*) extractImageFrom: (NSImage*) image withRect: (NSRect) rect 974{ 975 NSImage *img = [[NSImage alloc] initWithSize: rect.size]; 976 977 [img lockFocus]; 978 [image drawAtPoint: NSMakePoint(0, 0) 979 fromRect: rect 980 operation: NSCompositeSourceOver 981 fraction: 1.0]; 982 [img unlockFocus]; 983 [img TIFFRepresentation]; // creates a proper NSBitmapImageRep 984 return [img autorelease]; 985} 986 987- (void) validateTilesSizeWithImage: (NSImage*)image 988{ 989 int i; 990 991 originalRectCM = rects[TileCM]; 992 993 for (i = 0; i < 9; i++) 994 { 995 if (rects[i].origin.x < 0.0 || rects[i].origin.y < 0.0 996 || rects[i].size.width <= 0.0 || rects[i].size.height <= 0.0) 997 { 998 images[i] = nil; 999 rects[i] = NSZeroRect; 1000 } 1001 else 1002 { 1003 images[i] 1004 = [[self extractImageFrom: image withRect: rects[i]] retain]; 1005 // FIXME: This makes no sense to me, why not leave the 1006 // rect origins at their original values? 1007 rects[i].origin.x = 0; 1008 rects[i].origin.y = 0; 1009 } 1010 } 1011 1012 if (contentRect.origin.x < 0.0 || contentRect.origin.y < 0.0 1013 || contentRect.size.width <= 0.0 || contentRect.size.height <= 0.0) 1014 { 1015 contentRect = rects[TileCM]; 1016 } 1017} 1018 1019- (id) initWithImage: (NSImage*)image horizontal: (float)x vertical: (float)y 1020{ 1021 NSSize s = [image size]; 1022 1023 x = floor(x); 1024 y = floor(y); 1025 1026 scaleFactor = 1.0; 1027 1028 rects[TileTL] = NSMakeRect(0.0, s.height - y, x, y); 1029 rects[TileTM] = NSMakeRect(x, s.height - y, s.width - 2.0 * x, y); 1030 rects[TileTR] = NSMakeRect(s.width - x, s.height - y, x, y); 1031 rects[TileCL] = NSMakeRect(0.0, y, x, s.height - 2.0 * y); 1032 rects[TileCM] = NSMakeRect(x, y, s.width - 2.0 * x, s.height - 2.0 * y); 1033 rects[TileCR] = NSMakeRect(s.width - x, y, x, s.height - 2.0 * y); 1034 rects[TileBL] = NSMakeRect(0.0, 0.0, x, y); 1035 rects[TileBM] = NSMakeRect(x, 0.0, s.width - 2.0 * x, y); 1036 rects[TileBR] = NSMakeRect(s.width - x, 0.0, x, y); 1037 contentRect = rects[TileCM]; 1038 1039 style = GSThemeFillStyleNone; 1040 1041 [self validateTilesSizeWithImage: image]; 1042 return self; 1043} 1044 1045- (void) scaleTo: (float)scale 1046{ 1047 unsigned i; 1048 NSSize s; 1049 1050 if (scale == scaleFactor) 1051 { 1052 return; 1053 } 1054 1055 [images[0] setScalesWhenResized: YES]; 1056 s = [images[0] size]; 1057 s.width *= scale; 1058 s.height *= scale; 1059 [images[0] setSize: s]; 1060 rects[0].size.height *= scale; 1061 rects[0].size.width *= scale; 1062 rects[0].origin.x *= scale; 1063 rects[0].origin.y *= scale; 1064 for (i = 1; i < 9; i++) 1065 { 1066 unsigned j; 1067 1068 for (j = 0; j < i; j++) 1069 { 1070 if (images[i] == images[j]) 1071 { 1072 break; 1073 } 1074 } 1075 if (j == i) 1076 { 1077 [images[i] setScalesWhenResized: YES]; 1078 s = [images[i] size]; 1079 s.width *= scale; 1080 s.height *= scale; 1081 [images[i] setSize: s]; 1082 } 1083 rects[i].size.height *= scale; 1084 rects[i].size.width *= scale; 1085 rects[i].origin.x *= scale; 1086 rects[i].origin.y *= scale; 1087 } 1088 contentRect.size.height *= scale; 1089 contentRect.size.width *= scale; 1090 contentRect.origin.x *= scale; 1091 contentRect.origin.y *= scale; 1092} 1093 1094- (NSRect) fillRect: (NSRect)rect 1095 background: (NSColor*)color 1096{ 1097 return [self fillRect: rect background: color fillStyle: style]; 1098} 1099 1100- (NSRect) fillRect: (NSRect)rect 1101 background: (NSColor*)color 1102 fillStyle: (GSThemeFillStyle)aStyle 1103{ 1104 if (color == nil) 1105 { 1106 [[NSColor redColor] set]; 1107 } 1108 else 1109 { 1110 [color set]; 1111 } 1112// NSRectFill(rect); 1113 1114 switch (aStyle) 1115 { 1116 case GSThemeFillStyleNone: 1117 return [self noneStyleFillRect: rect]; 1118 case GSThemeFillStyleScale: 1119 return [self scaleStyleFillRect: rect]; 1120 case GSThemeFillStyleRepeat: 1121 return [self repeatStyleFillRect: rect]; 1122 case GSThemeFillStyleCenter: 1123 return [self centerStyleFillRect: rect]; 1124 case GSThemeFillStyleMatrix: 1125 return [self matrixStyleFillRect: rect]; 1126 case GSThemeFillStyleScaleAll: 1127 return [self scaleAllStyleFillRect: rect]; 1128 } 1129 1130 return NSZeroRect; 1131} 1132 1133- (NSSize) computeTotalTilesSize 1134{ 1135 NSSize tsz; 1136 1137 tsz.width = rects[TileTL].size.width + rects[TileTR].size.width; 1138 if (images[TileTM] != nil) 1139 { 1140 tsz.width += rects[TileTM].size.width; 1141 } 1142 tsz.height = rects[TileTL].size.height + rects[TileBL].size.height; 1143 if (images[TileCL] != nil) 1144 { 1145 tsz.height += rects[TileCL].size.height; 1146 } 1147 return tsz; 1148} 1149 1150- (GSThemeMargins) themeMargins 1151{ 1152 NSRect cm = originalRectCM; 1153 GSThemeMargins margins; 1154 1155 margins.left = rects[TileCL].size.width; 1156 margins.right = rects[TileCR].size.width; 1157 margins.top = rects[TileTM].size.height; 1158 margins.bottom = rects[TileBM].size.height; 1159 1160 // Adjust for contentRect != cm 1161 1162 margins.left += (contentRect.origin.x - cm.origin.x); 1163 margins.bottom += (contentRect.origin.y - cm.origin.y); 1164 1165 margins.right += (NSMaxX(cm) - NSMaxX(contentRect)); 1166 margins.top += (NSMaxY(cm) - NSMaxY(contentRect)); 1167 1168 return margins; 1169} 1170 1171- (NSRect) contentRectForRect: (NSRect)rect 1172 isFlipped: (BOOL)flipped 1173{ 1174 GSThemeMargins margins = [self themeMargins]; 1175 1176 rect.origin.x += margins.left; 1177 rect.origin.y += flipped ? margins.top : margins.bottom; 1178 1179 rect.size.width -= (margins.left + margins.right); 1180 rect.size.height -= (margins.top + margins.bottom); 1181 1182 return rect; 1183} 1184 1185- (NSRect) noneStyleFillRect: (NSRect)rect 1186{ 1187 NSRect inFill = [self contentRectForRect: rect isFlipped: NO]; 1188 [self repeatFillRect: rect]; 1189 [self drawCornersRect: rect]; 1190 return inFill; 1191} 1192 1193- (NSRect) centerStyleFillRect: (NSRect)rect 1194{ 1195 BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; 1196 1197 NSRect r = rects[TileCM]; 1198 NSRect inFill = [self contentRectForRect: rect isFlipped: flipped]; 1199 [self repeatFillRect: rect]; 1200 [self drawCornersRect: rect]; 1201 1202 r.origin.x = inFill.origin.x + (inFill.size.width - r.size.width) / 2; 1203 r.origin.y = inFill.origin.y + (inFill.size.height - r.size.height) / 2; 1204 1205 if (flipped) 1206 { 1207 r.origin.y += r.size.height; 1208 } 1209 1210 [images[TileCM] compositeToPoint: r.origin 1211 fromRect: rects[TileCM] 1212 operation: NSCompositeSourceOver]; 1213 1214 return inFill; 1215} 1216 1217- (NSRect) repeatStyleFillRect: (NSRect)rect 1218{ 1219 BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; 1220 1221 NSSize tsz = [self computeTotalTilesSize]; 1222 NSRect inFill = [self contentRectForRect: rect isFlipped: flipped]; 1223 [self repeatFillRect: rect]; 1224 [self drawCornersRect: rect]; 1225 1226 [[GSTheme theme] fillRect: inFill 1227 withRepeatedImage: images[TileCM] 1228 fromRect: rects[TileCM] 1229 center: !flipped]; 1230 1231 NSLog(@"rect %@ too small for tiles %@", 1232 NSStringFromSize(rect.size), NSStringFromSize(tsz)); 1233 1234 return inFill; 1235} 1236 1237- (NSRect) scaleStyleFillRect: (NSRect)rect 1238{ 1239 BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; 1240 1241 NSRect inFill = [self contentRectForRect: rect isFlipped: flipped]; 1242 1243 NSImage *im = [images[TileCM] copy]; 1244 NSRect r = rects[TileCM]; 1245 NSSize s = [images[TileCM] size]; 1246 NSPoint p = inFill.origin; 1247 float sx = inFill.size.width / r.size.width; 1248 float sy = inFill.size.height / r.size.height; 1249 1250 [self repeatFillRect: rect]; 1251 [self drawCornersRect: rect]; 1252 1253 r.size.width = inFill.size.width; 1254 r.size.height = inFill.size.height; 1255 r.origin.x *= sx; 1256 r.origin.y *= sy; 1257 s.width *= sx; 1258 s.height *= sy; 1259 1260 if (flipped) 1261 { 1262 p.y += inFill.size.height; 1263 } 1264 1265 [im setScalesWhenResized: YES]; 1266 [im setSize: s]; 1267 [im compositeToPoint: p 1268 fromRect: r 1269 operation: NSCompositeSourceOver]; 1270 RELEASE(im); 1271 1272 return inFill; 1273} 1274 1275- (NSRect) scaleAllStyleFillRect: (NSRect)rect 1276{ 1277 BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; 1278 NSSize cls = rects[TileCL].size; 1279 NSSize bms = rects[TileBM].size; 1280 NSSize crs = rects[TileCR].size; 1281 NSSize tms = rects[TileTM].size; 1282 NSImage *img; 1283 NSRect imgRect; 1284 1285 NSRect inFill = [self contentRectForRect: rect isFlipped: flipped]; 1286 [self scaleFillRect: rect]; 1287 [self drawCornersRect: rect]; 1288 1289 // Draw center scaled 1290 1291 img = images[TileCM]; 1292 imgRect = NSMakeRect(0, 0, 1293 rect.size.width - cls.width - crs.width, 1294 rect.size.height - tms.height - bms.height); 1295 1296 if (imgRect.size.width > 0 && imgRect.size.height > 0) 1297 { 1298 NSPoint p; 1299 1300 [img setScalesWhenResized: YES]; 1301 [img setSize: imgRect.size]; 1302 p = NSMakePoint(rect.origin.x + cls.width, 1303 rect.origin.y + bms.height); 1304 if (flipped) 1305 { 1306 p.y = rect.origin.y + rect.size.height - bms.height; 1307 } 1308 [img compositeToPoint: p 1309 fromRect: imgRect 1310 operation: NSCompositeSourceOver]; 1311 } 1312 1313 return inFill; 1314} 1315 1316- (NSRect) matrixStyleFillRect: (NSRect)rect 1317{ 1318 NSSize tsz = [self computeTotalTilesSize]; 1319 NSRect grid = NSZeroRect; 1320 float x; 1321 float y; 1322 float space = 3.0; 1323 float scale; 1324 BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; 1325 1326 if (images[TileTM] == nil) 1327 { 1328 grid.size.width = tsz.width + space * 3.0; 1329 } 1330 else 1331 { 1332 grid.size.width = tsz.width + space * 4.0; 1333 } 1334 scale = rect.size.width / grid.size.width; 1335 1336 if (images[TileCL] == nil) 1337 { 1338 grid.size.height = tsz.height + space * 3.0; 1339 } 1340 else 1341 { 1342 grid.size.height = tsz.height + space * 4.0; 1343 } 1344 1345 if ((rect.size.height / grid.size.height) < scale) 1346 { 1347 scale = rect.size.height / grid.size.height; 1348 } 1349 1350 if (floor(scale) >= 1) 1351 { 1352 scale = floor(scale); 1353 } 1354 1355 if (scale != 1) 1356 { 1357 // We need to scale the tiles down to fit. 1358 grid.size.width *= scale; 1359 grid.size.height *= scale; 1360 space *= scale; 1361 [self scaleTo: scale]; 1362 } 1363 1364 grid.origin.x = rect.origin.x + (rect.size.width - grid.size.width) / 2; 1365 x = grid.origin.x; 1366 if (flipped) 1367 { 1368 grid.origin.y = NSMaxY(rect) - (rect.size.height - grid.size.height) / 2; 1369 y = NSMaxY(grid); 1370 } 1371 else 1372 { 1373 grid.origin.y = rect.origin.y + (rect.size.height - grid.size.height) / 2; 1374 y = grid.origin.y; 1375 } 1376 1377 // Draw bottom row 1378 if (flipped) 1379 { 1380 y -= (rects[TileBL].size.height + space); 1381 } 1382 else 1383 { 1384 y += space; 1385 } 1386 [images[TileBL] compositeToPoint: NSMakePoint(x, y) 1387 fromRect: rects[TileBL] 1388 operation: NSCompositeSourceOver]; 1389 x += rects[TileBL].size.width + space; 1390 if (images[TileBM] != nil) 1391 { 1392 [images[TileBM] compositeToPoint: NSMakePoint(x, y) 1393 fromRect: rects[TileBM] 1394 operation: NSCompositeSourceOver]; 1395 x += rects[TileBM].size.width + space; 1396 } 1397 [images[TileBR] compositeToPoint: NSMakePoint(x, y) 1398 fromRect: rects[TileBR] 1399 operation: NSCompositeSourceOver]; 1400 if (!flipped) 1401 { 1402 y += rects[TileBL].size.height; 1403 } 1404 1405 // Draw middle row 1406 if (images[TileCL] != nil) 1407 { 1408 x = grid.origin.x; 1409 if (flipped) 1410 { 1411 y -= (rects[TileCL].size.height + space); 1412 } 1413 else 1414 { 1415 y += space; 1416 } 1417 [images[TileCL] compositeToPoint: NSMakePoint(x, y) 1418 fromRect: rects[TileCL] 1419 operation: NSCompositeSourceOver]; 1420 x += rects[TileCL].size.width + space; 1421 if (images[TileCM] != nil) 1422 { 1423 [images[TileCM] compositeToPoint: NSMakePoint(x, y) 1424 fromRect: rects[TileCM] 1425 operation: NSCompositeSourceOver]; 1426 x += rects[TileCM].size.width + space; 1427 } 1428 [images[TileCR] compositeToPoint: NSMakePoint(x, y) 1429 fromRect: rects[TileCR] 1430 operation: NSCompositeSourceOver]; 1431 if (!flipped) 1432 { 1433 y += rects[TileCL].size.height; 1434 } 1435 } 1436 1437 // Draw top row 1438 x = grid.origin.x; 1439 if (flipped) 1440 { 1441 y -= (rects[TileTL].size.height + space); 1442 } 1443 else 1444 { 1445 y += space; 1446 } 1447 [images[TileTL] compositeToPoint: NSMakePoint(x, y) 1448 fromRect: rects[TileTL] 1449 operation: NSCompositeSourceOver]; 1450 x += rects[TileTL].size.width + space; 1451 if (images[TileTM] != nil) 1452 { 1453 [images[TileTM] compositeToPoint: NSMakePoint(x, y) 1454 fromRect: rects[TileTM] 1455 operation: NSCompositeSourceOver]; 1456 x += rects[TileTM].size.width + space; 1457 } 1458 [images[TileTR] compositeToPoint: NSMakePoint(x, y) 1459 fromRect: rects[TileTR] 1460 operation: NSCompositeSourceOver]; 1461 if (scale != 1) 1462 { 1463 [self scaleTo: 1.0f/scale]; 1464 } 1465 return NSZeroRect; 1466} 1467 1468- (void) repeatFillRect: (NSRect)rect 1469{ 1470 BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; 1471 1472 NSSize tls = rects[TileTL].size; 1473 NSSize tms = rects[TileTM].size; 1474 NSSize trs = rects[TileTR].size; 1475 NSSize cls = rects[TileCL].size; 1476 NSSize crs = rects[TileCR].size; 1477 NSSize bls = rects[TileBL].size; 1478 NSSize bms = rects[TileBM].size; 1479 NSSize brs = rects[TileBR].size; 1480 1481 // Draw Top-Middle image repeated 1482 if (rect.size.width > tls.width + trs.width && tms.height > 0) 1483 { 1484 float y = rect.origin.y + rect.size.height - tms.height; 1485 1486 if (flipped) 1487 { 1488 y = rect.origin.y; 1489 } 1490 1491 [[GSTheme theme] fillHorizontalRect: 1492 NSMakeRect (rect.origin.x + tls.width, y, 1493 rect.size.width - tls.width - trs.width, 1494 tms.height) 1495 withImage: images[TileTM] 1496 fromRect: rects[TileTM] 1497 flipped: flipped]; 1498 } 1499 1500 // Draw Bottom-Middle image repeated 1501 if (rect.size.width > bls.width + brs.width && bms.height > 0) 1502 { 1503 float y = rect.origin.y; 1504 1505 if (flipped) 1506 { 1507 y = rect.origin.y + rect.size.height - bms.height; 1508 } 1509 [[GSTheme theme] fillHorizontalRect: 1510 NSMakeRect (rect.origin.x + bls.width, y, 1511 rect.size.width - bls.width - brs.width, 1512 bms.height) 1513 withImage: images[TileBM] 1514 fromRect: rects[TileBM] 1515 flipped: flipped]; 1516 } 1517 1518 // Draw Center-Left image repeated 1519 1520 if (rect.size.height > bls.height + tls.height && cls.width > 0) 1521 { 1522 [[GSTheme theme] fillVerticalRect: 1523 NSMakeRect (rect.origin.x, 1524 rect.origin.y + bls.height, 1525 cls.width, 1526 rect.size.height - bls.height - tls.height) 1527 withImage: images[TileCL] 1528 fromRect: rects[TileCL] 1529 flipped: flipped]; 1530 } 1531 1532 // Draw Center-Right image repeated 1533 1534 if (rect.size.height > brs.height + trs.height && crs.width > 0) 1535 { 1536 [[GSTheme theme] fillVerticalRect: 1537 NSMakeRect (rect.origin.x + rect.size.width - crs.width, 1538 rect.origin.y + brs.height, 1539 crs.width, 1540 rect.size.height - brs.height - trs.height) 1541 withImage: images[TileCR] 1542 fromRect: rects[TileCR] 1543 flipped: flipped]; 1544 } 1545} 1546 1547- (void) scaleFillRect: (NSRect)rect 1548{ 1549 BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; 1550 NSImage *img; 1551 NSRect imgRect; 1552 NSPoint p; 1553 1554 NSSize tls = rects[TileTL].size; 1555 NSSize tms = rects[TileTM].size; 1556 NSSize trs = rects[TileTR].size; 1557 NSSize cls = rects[TileCL].size; 1558 NSSize crs = rects[TileCR].size; 1559 NSSize bls = rects[TileBL].size; 1560 NSSize bms = rects[TileBM].size; 1561 NSSize brs = rects[TileBR].size; 1562 1563 // Draw Top-Middle image scaled 1564 1565 img = images[TileTM]; 1566 imgRect = NSMakeRect(0, 0, 1567 rect.size.width - tls.width - trs.width, tms.height); 1568 if (imgRect.size.width > 0 && imgRect.size.height > 0) 1569 { 1570 [img setScalesWhenResized: YES]; 1571 [img setSize: imgRect.size]; 1572 p = NSMakePoint(rect.origin.x + tls.width, 1573 rect.origin.y + rect.size.height - tms.height); 1574 if (flipped) 1575 { 1576 p.y = rect.origin.y + tms.height; 1577 } 1578 [img compositeToPoint: p 1579 fromRect: imgRect 1580 operation: NSCompositeSourceOver]; 1581 } 1582 1583 // Draw Bottom-Middle image scaled 1584 1585 img = images[TileBM]; 1586 imgRect = NSMakeRect(0, 0, 1587 rect.size.width - bls.width - brs.width, bms.height); 1588 if (imgRect.size.width > 0 && imgRect.size.height > 0) 1589 { 1590 [img setScalesWhenResized: YES]; 1591 [img setSize: imgRect.size]; 1592 p = NSMakePoint(rect.origin.x + bls.width, rect.origin.y); 1593 if (flipped) 1594 { 1595 p.y = rect.origin.y + rect.size.height; 1596 } 1597 [img compositeToPoint: p 1598 fromRect: imgRect 1599 operation: NSCompositeSourceOver]; 1600 } 1601 1602 // Draw Center-Left image scaled 1603 1604 img = images[TileCL]; 1605 imgRect = NSMakeRect(0, 0, 1606 cls.width, rect.size.height - tls.height - bls.height); 1607 if (imgRect.size.width > 0 && imgRect.size.height > 0) 1608 { 1609 [img setScalesWhenResized: YES]; 1610 [img setSize: imgRect.size]; 1611 p = NSMakePoint(rect.origin.x, rect.origin.y + bls.height); 1612 if (flipped) 1613 { 1614 p.y = rect.origin.y + rect.size.height - bls.height; 1615 } 1616 [img compositeToPoint: p 1617 fromRect: imgRect 1618 operation: NSCompositeSourceOver]; 1619 } 1620 1621 // Draw Center-Right image scaled 1622 1623 img = images[TileCR]; 1624 imgRect = NSMakeRect(0, 0, 1625 crs.width, rect.size.height - trs.height - brs.height); 1626 if (imgRect.size.width > 0 && imgRect.size.height > 0) 1627 { 1628 [img setScalesWhenResized: YES]; 1629 [img setSize: imgRect.size]; 1630 p = NSMakePoint(rect.origin.x + rect.size.width - crs.width, 1631 rect.origin.y + brs.height); 1632 if (flipped) 1633 { 1634 p.y = rect.origin.y + rect.size.height - brs.height; 1635 } 1636 [img compositeToPoint: p 1637 fromRect: imgRect 1638 operation: NSCompositeSourceOver]; 1639 } 1640} 1641 1642 1643- (void) drawCornersRect: (NSRect)rect 1644{ 1645 BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; 1646 1647 NSSize tls = rects[TileTL].size; 1648 NSSize trs = rects[TileTR].size; 1649 NSSize brs = rects[TileBR].size; 1650 NSPoint p; 1651 1652 p = NSMakePoint (rect.origin.x, 1653 rect.origin.y + rect.size.height - tls.height); 1654 if (flipped) 1655 { 1656 p.y = rect.origin.y + tls.height; 1657 } 1658 [images[TileTL] compositeToPoint: p 1659 fromRect: rects[TileTL] 1660 operation: NSCompositeSourceOver]; 1661// Is this right? 1662// p = NSMakePoint(rect.origin.x + rect.size.width - trs.width + 1, 1663 p = NSMakePoint(rect.origin.x + rect.size.width - trs.width, 1664 rect.origin.y + rect.size.height - trs.height); 1665 if (flipped) 1666 { 1667 p.y = rect.origin.y + tls.height; 1668 } 1669 [images[TileTR] compositeToPoint: p 1670 fromRect: rects[TileTR] 1671 operation: NSCompositeSourceOver]; 1672 1673 p = NSMakePoint(rect.origin.x, rect.origin.y); 1674 if (flipped) 1675 { 1676 p.y = rect.origin.y + rect.size.height; 1677 } 1678 [images[TileBL] compositeToPoint: p 1679 fromRect: rects[TileBL] 1680 operation: NSCompositeSourceOver]; 1681 1682// Is this right? 1683// p = NSMakePoint(rect.origin.x + rect.size.width - brs.width + 1, 1684 p = NSMakePoint(rect.origin.x + rect.size.width - brs.width, 1685 rect.origin.y); 1686 if (flipped) 1687 { 1688 p.y = rect.origin.y + rect.size.height; 1689 } 1690 [images[TileBR] compositeToPoint: p 1691 fromRect: rects[TileBR] 1692 operation: NSCompositeSourceOver]; 1693} 1694 1695- (GSThemeFillStyle) fillStyle 1696{ 1697 return style; 1698} 1699 1700- (void) setFillStyle: (GSThemeFillStyle)aStyle 1701{ 1702 style = aStyle; 1703} 1704 1705- (NSSize) size 1706{ 1707 const CGFloat width = rects[TileCL].size.width 1708 + rects[TileCM].size.width 1709 + rects[TileCR].size.width; 1710 1711 const CGFloat height = rects[TileTM].size.height 1712 + rects[TileCM].size.height 1713 + rects[TileBM].size.height; 1714 1715 return NSMakeSize(width, height); 1716} 1717 1718@end 1719 1720