1/* 2 PPLayerControlsPopupPanelController.m 3 4 Copyright 2013-2018,2020 Josh Freeman 5 http://www.twilightedge.com 6 7 This file is part of PikoPixel for Mac OS X and GNUstep. 8 PikoPixel is a graphical application for drawing & editing pixel-art images. 9 10 PikoPixel is free software: you can redistribute it and/or modify it under 11 the terms of the GNU Affero General Public License as published by the 12 Free Software Foundation, either version 3 of the License, or (at your 13 option) any later version approved for PikoPixel by its copyright holder (or 14 an authorized proxy). 15 16 PikoPixel is distributed in the hope that it will be useful, but WITHOUT ANY 17 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more 19 details. 20 21 You should have received a copy of the GNU Affero General Public License 22 along with this program. If not, see <http://www.gnu.org/licenses/>. 23*/ 24 25#import "PPLayerControlsPopupPanelController.h" 26 27#import "PPDocument.h" 28#import "PPDocumentLayer.h" 29#import "PPDocumentWindowController.h" 30#import "PPThumbnailImageView.h" 31#import "NSObject_PPUtilities.h" 32#import "PPUIColors_Panels.h" 33#import "PPLayerControlButtonImagesManager.h" 34#import "PPTitleablePopUpButton.h" 35#import "PPGeometry.h" 36#import "PPBackgroundPattern.h" 37#import "PPTextAttributesDicts.h" 38#import "NSBitmapImageRep_PPUtilities.h" 39#import "NSImage_PPUtilities.h" 40#import "PPThumbnailUtilities.h" 41 42 43#define kLayerControlsPopupPanelNibName @"LayerControlsPopupPanel" 44 45#define kPopupMenuThumbnailSize NSMakeSize(21.0f, 21.0f) 46 47#define kDrawingLayerOpacityFormatString @"%.1f%%" 48 49 50@interface PPLayerControlsPopupPanelController (PrivateMethods) 51 52- (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: 53 (NSNotification *) notification; 54- (void) handlePPDocumentNotification_SwitchedDrawingLayer: (NSNotification *) notification; 55- (void) handlePPDocumentNotification_ReorderedLayers: (NSNotification *) notification; 56- (void) handlePPDocumentNotification_ChangedLayerAttribute: (NSNotification *) notification; 57- (void) handlePPDocumentNotification_SwitchedLayerOperationTarget: 58 (NSNotification *) notification; 59- (void) handlePPDocumentNotification_UpdatedBackgroundSettings: 60 (NSNotification *) notification; 61- (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification; 62 63 64- (void) addAsObserverForPPDocumentWindowControllerNotifications; 65- (void) removeAsObserverForPPDocumentWindowControllerNotifications; 66- (void) handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode: 67 (NSNotification *) notification; 68 69- (void) addAsObserverForPPLayerControlButtonImagesManagerNotifications; 70- (void) removeAsObserverForPPLayerControlButtonImagesManagerNotifications; 71- (void) handlePPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages: 72 (NSNotification *) notification; 73- (void) handlePPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages: 74 (NSNotification *) notification; 75 76- (void) handleOpacitySliderDidBeginTracking; 77- (void) handleOpacitySliderDidFinishTracking; 78 79- (void) setupWithPPDocumentWindowController: 80 (PPDocumentWindowController *) ppDocumentWindowController; 81 82- (void) setupDrawingLayerThumbnailImage; 83- (void) setupDrawingLayerThumbnailImageBackground; 84 85- (void) setupPopupMenuThumbnailDrawMembers; 86- (void) setupPopupMenuThumbnailBackgroundBitmap; 87- (void) destroyPopupMenuThumbnailBackgroundBitmap; 88 89- (NSImage *) popupMenuThumbnailImageForLayerImage: (NSImage *) layerImage; 90 91- (void) updateCanvasDisplayMode; 92- (void) updateLayerOperationTarget; 93 94- (void) updateLayerControlButtonImages; 95- (void) updateCanvasDisplayModeButtonImage; 96- (void) updateLayerOperationTargetButtonImage; 97 98- (void) updateDrawingLayerControls; 99- (void) updateDrawingLayerControlsIfPanelIsVisible; 100- (void) updateDrawingLayerAttributeControls; 101- (void) updateDrawingLayerOpacityTextField; 102 103- (void) updateDrawingLayerPopUpButtonMenu; 104 105- (int) layerIndexForPopUpButtonMenuItemAtIndex: (int) itemIndex; 106- (int) popUpButtonMenuItemIndexForLayerAtIndex: (int) layerIndex; 107 108- (float) drawingLayerOpacitySliderQuantizedValue; 109 110@end 111 112@implementation PPLayerControlsPopupPanelController 113 114- (void) dealloc 115{ 116 [self removeAsObserverForPPLayerControlButtonImagesManagerNotifications]; 117 118 [self setupWithPPDocumentWindowController: nil]; 119 120 [self destroyPopupMenuThumbnailBackgroundBitmap]; 121 122 [super dealloc]; 123} 124 125#pragma mark Actions 126 127- (IBAction) canvasDisplayModeButtonPressed: (id) sender 128{ 129 [_ppDocumentWindowController toggleCanvasDisplayMode: self]; 130} 131 132- (IBAction) layerOperationTargetButtonPressed: (id) sender 133{ 134 [_ppDocumentWindowController toggleLayerOperationTarget: self]; 135} 136 137- (IBAction) drawingLayerEnabledCheckboxClicked: (id) sender 138{ 139 [[_ppDocument drawingLayer] setEnabled: [_drawingLayerEnabledCheckbox intValue]]; 140} 141 142- (IBAction) drawingLayerPopupMenuItemSelected: (id) sender 143{ 144 int indexOfSelectedDrawingLayer = 145 [self layerIndexForPopUpButtonMenuItemAtIndex: 146 [_drawingLayerTitleablePopUpButton indexOfSelectedItem]]; 147 148 [_ppDocument selectDrawingLayerAtIndex: indexOfSelectedDrawingLayer]; 149} 150 151- (IBAction) drawingLayerOpacitySliderMoved: (id) sender 152{ 153 if (!_isTrackingOpacitySlider) 154 { 155 [self handleOpacitySliderDidBeginTracking]; 156 } 157 158 _ignoreNotificationForChangedLayerAttribute = YES; 159 160 [[_ppDocument drawingLayer] setOpacityWithoutRegisteringUndo: 161 [self drawingLayerOpacitySliderQuantizedValue]]; 162 163 _ignoreNotificationForChangedLayerAttribute = NO; 164 165 [self updateDrawingLayerOpacityTextField]; 166} 167 168#pragma mark NSWindowController overrrides 169 170- (void) windowDidLoad 171{ 172 _needToUpdateLayerControlButtonImages = YES; 173 _needToUpdateDrawingLayerControls = YES; 174 _needToUpdateDrawingLayerPopupButtonMenu = YES; 175 176 // [super windowDidLoad] calls [self setupPanelForCurrentPPDocument], so any preliminary 177 // setup required before calling setupPanelForCurrentPPDocument should go before this call 178 [super windowDidLoad]; 179 180 [_backgroundFillTextField setBackgroundColor: [NSColor windowBackgroundColor]]; 181 182 [_drawingLayerTitleablePopUpButton setDelegate: self]; 183 184 [self addAsObserverForPPLayerControlButtonImagesManagerNotifications]; 185} 186 187#pragma mark PPPopupPanelController overrides 188 189+ (NSString *) panelNibName 190{ 191 return kLayerControlsPopupPanelNibName; 192} 193 194- (void) setPPDocument: (PPDocument *) ppDocument 195{ 196 [super setPPDocument: ppDocument]; 197 198 if (!_ppDocument) 199 { 200 [self setupWithPPDocumentWindowController: nil]; 201 } 202} 203 204- (void) addAsObserverForPPDocumentNotifications 205{ 206 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 207 208 if (!_ppDocument) 209 return; 210 211 [notificationCenter addObserver: self 212 selector: 213 @selector( 214 handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage:) 215 name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage 216 object: _ppDocument]; 217 218 [notificationCenter addObserver: self 219 selector: @selector(handlePPDocumentNotification_SwitchedDrawingLayer:) 220 name: PPDocumentNotification_SwitchedDrawingLayer 221 object: _ppDocument]; 222 223 [notificationCenter addObserver: self 224 selector: @selector(handlePPDocumentNotification_ReorderedLayers:) 225 name: PPDocumentNotification_ReorderedLayers 226 object: _ppDocument]; 227 228 [notificationCenter addObserver: self 229 selector: @selector(handlePPDocumentNotification_ChangedLayerAttribute:) 230 name: PPDocumentNotification_ChangedLayerAttribute 231 object: _ppDocument]; 232 233 [notificationCenter addObserver: self 234 selector: 235 @selector(handlePPDocumentNotification_SwitchedLayerOperationTarget:) 236 name: PPDocumentNotification_SwitchedLayerOperationTarget 237 object: _ppDocument]; 238 239 [notificationCenter addObserver: self 240 selector: 241 @selector(handlePPDocumentNotification_UpdatedBackgroundSettings:) 242 name: PPDocumentNotification_UpdatedBackgroundSettings 243 object: _ppDocument]; 244 245 [notificationCenter addObserver: self 246 selector: @selector(handlePPDocumentNotification_ReloadedDocument:) 247 name: PPDocumentNotification_ReloadedDocument 248 object: _ppDocument]; 249} 250 251- (void) removeAsObserverForPPDocumentNotifications 252{ 253 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 254 255 [notificationCenter removeObserver: self 256 name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage 257 object: _ppDocument]; 258 259 [notificationCenter removeObserver: self 260 name: PPDocumentNotification_SwitchedDrawingLayer 261 object: _ppDocument]; 262 263 [notificationCenter removeObserver: self 264 name: PPDocumentNotification_ReorderedLayers 265 object: _ppDocument]; 266 267 [notificationCenter removeObserver: self 268 name: PPDocumentNotification_ChangedLayerAttribute 269 object: _ppDocument]; 270 271 [notificationCenter removeObserver: self 272 name: PPDocumentNotification_SwitchedLayerOperationTarget 273 object: _ppDocument]; 274 275 [notificationCenter removeObserver: self 276 name: PPDocumentNotification_UpdatedBackgroundSettings 277 object: _ppDocument]; 278 279 [notificationCenter removeObserver: self 280 name: PPDocumentNotification_ReloadedDocument 281 object: _ppDocument]; 282} 283 284- (void) setupPanelForCurrentPPDocument 285{ 286 [super setupPanelForCurrentPPDocument]; 287 288 [self setupWithPPDocumentWindowController: [_ppDocument ppDocumentWindowController]]; 289 290 [self setupDrawingLayerThumbnailImage]; 291 [self setupDrawingLayerThumbnailImageBackground]; 292 293 [self setupPopupMenuThumbnailDrawMembers]; 294 [self setupPopupMenuThumbnailBackgroundBitmap]; 295 296 [self updateCanvasDisplayMode]; 297 [self updateLayerOperationTarget]; 298 299 [[PPLayerControlButtonImagesManager sharedManager] setPPDocument: _ppDocument]; 300 301 [self updateDrawingLayerControlsIfPanelIsVisible]; 302 303 _needToUpdateDrawingLayerPopupButtonMenu = YES; 304} 305 306- (void) setupPanelBeforeMakingVisible 307{ 308 [super setupPanelBeforeMakingVisible]; 309 310 if (_needToUpdateLayerControlButtonImages) 311 { 312 [self updateLayerControlButtonImages]; 313 } 314 315 if (_needToUpdateDrawingLayerControls) 316 { 317 [self updateDrawingLayerControls]; 318 } 319} 320 321- (NSColor *) backgroundColorForPopupPanel 322{ 323 return kUIColor_LayerControlsPopupPanel_Background; 324} 325 326- (void) handleDirectionCommand: (PPDirectionType) directionType 327{ 328 switch (directionType) 329 { 330 case kPPDirectionType_Left: 331 { 332 [_ppDocumentWindowController toggleCanvasDisplayMode: self]; 333 } 334 break; 335 336 case kPPDirectionType_Right: 337 { 338 [_ppDocumentWindowController toggleLayerOperationTarget: self]; 339 } 340 break; 341 342 case kPPDirectionType_Up: 343 { 344 [_ppDocumentWindowController makePreviousLayerActive: self]; 345 } 346 break; 347 348 case kPPDirectionType_Down: 349 { 350 [_ppDocumentWindowController makeNextLayerActive: self]; 351 } 352 break; 353 354 default: 355 break; 356 } 357} 358 359#pragma mark PPTitleablePopUpButton delegate methods 360 361- (NSDictionary *) titleTextAttributesForMenuItemAtIndex: (int) itemIndex 362 onTitleablePopUpButton: (PPTitleablePopUpButton *) button 363{ 364 int layerIndex; 365 bool layerIsEnabled; 366 367 layerIndex = [self layerIndexForPopUpButtonMenuItemAtIndex: itemIndex]; 368 369 layerIsEnabled = [[_ppDocument layerAtIndex: layerIndex] isEnabled]; 370 371 return (layerIsEnabled) ? nil : PPTextAttributesDict_DisabledTitle_PopupButton(); 372} 373 374- (void) titleablePopUpButtonWillDisplayPopupMenu: (PPTitleablePopUpButton *) button 375{ 376 if (_needToUpdateDrawingLayerPopupButtonMenu) 377 { 378 [self updateDrawingLayerPopUpButtonMenu]; 379 } 380} 381 382#pragma mark PPDocument notifications 383 384- (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: 385 (NSNotification *) notification 386{ 387 [_drawingLayerThumbnailView handleUpdateToImage]; 388 389 _needToUpdateDrawingLayerPopupButtonMenu = YES; 390} 391 392- (void) handlePPDocumentNotification_SwitchedDrawingLayer: (NSNotification *) notification 393{ 394 [self setupDrawingLayerThumbnailImage]; 395 [self updateDrawingLayerControlsIfPanelIsVisible]; 396} 397 398- (void) handlePPDocumentNotification_ReorderedLayers: (NSNotification *) notification 399{ 400 [self setupDrawingLayerThumbnailImage]; 401 [self updateDrawingLayerControlsIfPanelIsVisible]; 402 403 _needToUpdateDrawingLayerPopupButtonMenu = YES; 404} 405 406- (void) handlePPDocumentNotification_ChangedLayerAttribute: (NSNotification *) notification 407{ 408 NSDictionary *userInfo; 409 NSNumber *layerIndexNumber; 410 int layerIndex = -1; 411 412 if (_ignoreNotificationForChangedLayerAttribute) 413 return; 414 415 userInfo = [notification userInfo]; 416 417 layerIndexNumber = 418 [userInfo objectForKey: PPDocumentNotification_UserInfoKey_IndexOfChangedLayer]; 419 420 if (layerIndexNumber) 421 { 422 layerIndex = [layerIndexNumber intValue]; 423 } 424 425 if (layerIndex == [_ppDocument indexOfDrawingLayer]) 426 { 427 if ([self panelIsVisible]) 428 { 429 [self updateDrawingLayerAttributeControls]; 430 } 431 else 432 { 433 _needToUpdateDrawingLayerControls = YES; 434 } 435 } 436 437 _needToUpdateDrawingLayerPopupButtonMenu = YES; 438} 439 440- (void) handlePPDocumentNotification_SwitchedLayerOperationTarget: 441 (NSNotification *) notification 442{ 443 [self updateLayerOperationTarget]; 444 445 if ([self panelIsVisible]) 446 { 447 [self updateLayerOperationTargetButtonImage]; 448 } 449 else 450 { 451 _needToUpdateLayerControlButtonImages = YES; 452 } 453} 454 455- (void) handlePPDocumentNotification_UpdatedBackgroundSettings: 456 (NSNotification *) notification 457{ 458 [self setupDrawingLayerThumbnailImageBackground]; 459 460 [self setupPopupMenuThumbnailBackgroundBitmap]; 461 462 _needToUpdateDrawingLayerPopupButtonMenu = YES; 463} 464 465- (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification 466{ 467 [self setupPanelForCurrentPPDocument]; 468} 469 470#pragma mark PPDocumentWindowController notifications 471 472- (void) addAsObserverForPPDocumentWindowControllerNotifications 473{ 474 if (!_ppDocumentWindowController) 475 return; 476 477 [[NSNotificationCenter defaultCenter] 478 addObserver: self 479 selector: 480 @selector(handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode:) 481 name: PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode 482 object: _ppDocumentWindowController]; 483} 484 485- (void) removeAsObserverForPPDocumentWindowControllerNotifications 486{ 487 [[NSNotificationCenter defaultCenter] 488 removeObserver: self 489 name: PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode 490 object: _ppDocumentWindowController]; 491} 492 493- (void) handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode: 494 (NSNotification *) notification 495{ 496 [self updateCanvasDisplayMode]; 497 498 if ([self panelIsVisible]) 499 { 500 [self updateCanvasDisplayModeButtonImage]; 501 } 502 else 503 { 504 _needToUpdateLayerControlButtonImages = YES; 505 } 506} 507 508#pragma mark PPLayerControlButtonImagesManager notifications 509 510- (void) addAsObserverForPPLayerControlButtonImagesManagerNotifications 511{ 512 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 513 514 [notificationCenter 515 addObserver: self 516 selector: 517 @selector( 518 handlePPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages:) 519 name: PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages 520 object: nil]; 521 522 [notificationCenter 523 addObserver: self 524 selector: 525 @selector( 526 handlePPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages:) 527 name: PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages 528 object: nil]; 529} 530 531- (void) removeAsObserverForPPLayerControlButtonImagesManagerNotifications 532{ 533 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 534 535 [notificationCenter 536 removeObserver: self 537 name: PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages 538 object: nil]; 539 540 [notificationCenter 541 removeObserver: self 542 name: PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages 543 object: nil]; 544} 545 546- (void) handlePPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages: 547 (NSNotification *) notification 548{ 549 if (![self panelIsVisible]) 550 { 551 _needToUpdateLayerControlButtonImages = YES; 552 553 return; 554 } 555 556 if (_canvasDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) 557 { 558 [self updateCanvasDisplayModeButtonImage]; 559 } 560 561 if (_layerOperationTarget == kPPLayerOperationTarget_DrawingLayerOnly) 562 { 563 [self updateLayerOperationTargetButtonImage]; 564 } 565} 566 567- (void) handlePPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages: 568 (NSNotification *) notification 569{ 570 if (![self panelIsVisible]) 571 { 572 _needToUpdateLayerControlButtonImages = YES; 573 574 return; 575 } 576 577 if (_canvasDisplayMode != kPPLayerDisplayMode_DrawingLayerOnly) 578 { 579 [self updateCanvasDisplayModeButtonImage]; 580 } 581 582 if (_layerOperationTarget != kPPLayerOperationTarget_DrawingLayerOnly) 583 { 584 [self updateLayerOperationTargetButtonImage]; 585 } 586} 587 588#pragma mark Opacity slider tracking 589 590- (void) handleOpacitySliderDidBeginTracking 591{ 592 if (_isTrackingOpacitySlider) 593 return; 594 595 _isTrackingOpacitySlider = YES; 596 597 _drawingLayerInitialOpacity = [[_ppDocument drawingLayer] opacity]; 598 599 [_ppDocument disableThumbnailImageUpdateNotifications: YES]; 600 601 // won't return to the main run loop until the slider's done tracking, so post a message 602 // in the next stack frame to serve as notification that tracking's finished 603 [self ppPerformSelectorFromNewStackFrame: @selector(handleOpacitySliderDidFinishTracking)]; 604} 605 606- (void) handleOpacitySliderDidFinishTracking 607{ 608 float newOpacity = [self drawingLayerOpacitySliderQuantizedValue]; 609 610 _isTrackingOpacitySlider = NO; 611 612 [_ppDocument disableThumbnailImageUpdateNotifications: NO]; 613 614 if (newOpacity != _drawingLayerInitialOpacity) 615 { 616 [[_ppDocument drawingLayer] setOpacity: newOpacity]; 617 } 618} 619 620#pragma mark Private methods 621 622- (void) setupWithPPDocumentWindowController: 623 (PPDocumentWindowController *) ppDocumentWindowController 624{ 625 if (_ppDocumentWindowController == ppDocumentWindowController) 626 { 627 return; 628 } 629 630 if (_ppDocumentWindowController) 631 { 632 [self removeAsObserverForPPDocumentWindowControllerNotifications]; 633 } 634 635 [_ppDocumentWindowController release]; 636 _ppDocumentWindowController = [ppDocumentWindowController retain]; 637 638 if (_ppDocumentWindowController) 639 { 640 [self addAsObserverForPPDocumentWindowControllerNotifications]; 641 } 642} 643 644- (void) setupDrawingLayerThumbnailImage 645{ 646 [_drawingLayerThumbnailView setImage: [_ppDocument drawingLayerThumbnailImage]]; 647} 648 649- (void) setupDrawingLayerThumbnailImageBackground 650{ 651 [_drawingLayerThumbnailView setBackgroundPattern: [_ppDocument backgroundPattern]]; 652} 653 654- (void) setupPopupMenuThumbnailDrawMembers 655{ 656 _popupMenuThumbnailDrawSourceRect.size = [_ppDocument canvasSize]; 657 _popupMenuThumbnailDrawDestinationRect = 658 PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize( 659 _popupMenuThumbnailDrawSourceRect.size, 660 kPopupMenuThumbnailSize); 661 662 _popupMenuThumbnailInterpolation = 663 PPThumbUtils_ImageInterpolationForSourceRectToDestinationRect( 664 _popupMenuThumbnailDrawSourceRect, 665 _popupMenuThumbnailDrawDestinationRect); 666} 667 668- (void) setupPopupMenuThumbnailBackgroundBitmap 669{ 670 PPBackgroundPattern *documentBackgroundPattern, *thumbnailBackgroundPattern; 671 float patternScalingFactor; 672 NSColor *thumbnailBackgroundPatternColor; 673 NSBitmapImageRep *backgroundBitmap; 674 675 [self destroyPopupMenuThumbnailBackgroundBitmap]; 676 677 if (!_ppDocument || NSIsEmptyRect(_popupMenuThumbnailDrawSourceRect)) 678 { 679 goto ERROR; 680 } 681 682 documentBackgroundPattern = [_ppDocument backgroundPattern]; 683 684 patternScalingFactor = kScalingFactorForThumbnailBackgroundPatternSize 685 * _popupMenuThumbnailDrawDestinationRect.size.width 686 / _popupMenuThumbnailDrawSourceRect.size.width; 687 688 if (patternScalingFactor > 1.0f) 689 { 690 patternScalingFactor = 1.0f; 691 } 692 693 thumbnailBackgroundPattern = 694 [documentBackgroundPattern backgroundPatternScaledByFactor: patternScalingFactor]; 695 696 thumbnailBackgroundPatternColor = [thumbnailBackgroundPattern patternFillColor]; 697 698 if (!thumbnailBackgroundPatternColor) 699 goto ERROR; 700 701 backgroundBitmap = [NSBitmapImageRep ppImageBitmapOfSize: kPopupMenuThumbnailSize]; 702 703 if (!backgroundBitmap) 704 goto ERROR; 705 706 [backgroundBitmap ppSetAsCurrentGraphicsContext]; 707 708 [thumbnailBackgroundPatternColor set]; 709 NSRectFill(_popupMenuThumbnailDrawDestinationRect); 710 711 [backgroundBitmap ppRestoreGraphicsContext]; 712 713 _popupMenuThumbnailBackgroundBitmap = [backgroundBitmap retain]; 714 715 return; 716 717ERROR: 718 return; 719} 720 721- (NSImage *) popupMenuThumbnailImageForLayerImage: (NSImage *) layerImage 722{ 723 NSBitmapImageRep *thumbnailBitmap; 724 725 if (!layerImage) 726 goto ERROR; 727 728 thumbnailBitmap = [[_popupMenuThumbnailBackgroundBitmap copy] autorelease]; 729 730 if (!thumbnailBitmap) 731 goto ERROR; 732 733 [thumbnailBitmap ppSetAsCurrentGraphicsContext]; 734 735 [[NSGraphicsContext currentContext] setImageInterpolation: _popupMenuThumbnailInterpolation]; 736 737 [layerImage drawInRect: _popupMenuThumbnailDrawDestinationRect 738 fromRect: _popupMenuThumbnailDrawSourceRect 739 operation: NSCompositeSourceOver 740 fraction: 1.0f]; 741 742 [thumbnailBitmap ppRestoreGraphicsContext]; 743 744 return [NSImage ppImageWithBitmap: thumbnailBitmap]; 745 746ERROR: 747 return nil; 748} 749 750- (void) destroyPopupMenuThumbnailBackgroundBitmap 751{ 752 [_popupMenuThumbnailBackgroundBitmap release]; 753 _popupMenuThumbnailBackgroundBitmap = nil; 754} 755 756- (void) updateCanvasDisplayMode 757{ 758 _canvasDisplayMode = [_ppDocumentWindowController canvasDisplayMode]; 759 760 if (_canvasDisplayMode != kPPLayerDisplayMode_DrawingLayerOnly) 761 { 762 _canvasDisplayMode = kPPLayerDisplayMode_VisibleLayers; 763 } 764} 765 766- (void) updateLayerOperationTarget 767{ 768 _layerOperationTarget = [_ppDocument layerOperationTarget]; 769 770 if (_layerOperationTarget != kPPLayerOperationTarget_DrawingLayerOnly) 771 { 772 _layerOperationTarget = kPPLayerOperationTarget_VisibleLayers; 773 } 774} 775 776- (void) updateLayerControlButtonImages 777{ 778 [self updateCanvasDisplayModeButtonImage]; 779 [self updateLayerOperationTargetButtonImage]; 780 781 _needToUpdateLayerControlButtonImages = NO; 782} 783 784- (void) updateCanvasDisplayModeButtonImage 785{ 786 NSImage *buttonImage = 787 [[PPLayerControlButtonImagesManager sharedManager] 788 buttonImageForDisplayMode: _canvasDisplayMode]; 789 790 // button's current image may already be buttonImage, so force redraw by clearing the image 791 // first 792 [_canvasDisplayModeButton setImage: nil]; 793 [_canvasDisplayModeButton setImage: buttonImage]; 794} 795 796- (void) updateLayerOperationTargetButtonImage 797{ 798 NSImage *buttonImage = 799 [[PPLayerControlButtonImagesManager sharedManager] 800 buttonImageForOperationTarget: _layerOperationTarget]; 801 802 // button's current image may already be buttonImage, so force redraw by clearing the image 803 // first 804 [_layerOperationTargetButton setImage: nil]; 805 [_layerOperationTargetButton setImage: buttonImage]; 806} 807 808- (void) updateDrawingLayerControls 809{ 810 [_drawingLayerThumbnailView handleUpdateToImage]; 811 812 [self updateDrawingLayerAttributeControls]; 813 814 _needToUpdateDrawingLayerControls = NO; 815} 816 817- (void) updateDrawingLayerControlsIfPanelIsVisible 818{ 819 if ([self panelIsVisible]) 820 { 821 [self updateDrawingLayerControls]; 822 } 823 else 824 { 825 _needToUpdateDrawingLayerControls = YES; 826 } 827} 828 829- (void) updateDrawingLayerAttributeControls 830{ 831 PPDocumentLayer *drawingLayer; 832 bool drawingLayerIsEnabled; 833 NSDictionary *drawingLayerTitleAttributes; 834 835 drawingLayer = [_ppDocument drawingLayer]; 836 drawingLayerIsEnabled = [drawingLayer isEnabled]; 837 838 [_drawingLayerEnabledCheckbox setIntValue: drawingLayerIsEnabled]; 839 840 drawingLayerTitleAttributes = 841 (drawingLayerIsEnabled) ? nil : PPTextAttributesDict_DisabledTitle_PopupButton(); 842 843 [_drawingLayerTitleablePopUpButton setTitle: [drawingLayer name] 844 withTextAttributes: drawingLayerTitleAttributes]; 845 846 [self updateDrawingLayerOpacityTextField]; 847 848 [_drawingLayerOpacitySlider setFloatValue: [drawingLayer opacity]]; 849} 850 851- (void) updateDrawingLayerOpacityTextField 852{ 853 float opacity = [[_ppDocument drawingLayer] opacity] * 100.0f; 854 NSString *opacityString = 855 [NSString stringWithFormat: kDrawingLayerOpacityFormatString, opacity]; 856 857 [_drawingLayerOpacityTextField setStringValue: opacityString]; 858} 859 860- (void) updateDrawingLayerPopUpButtonMenu 861{ 862 NSMenu *layersMenu; 863 int layerCounter; 864 PPDocumentLayer *layer; 865 NSString *layerName; 866 // use PPSDKNativeType_NSMenuItemPtr for menuItem, as -[NSMenu addItemWithTitle:...] 867 // could return either (NSMenuItem *) or (id <NSMenuItem>), depending on the SDK 868 PPSDKNativeType_NSMenuItemPtr menuItem; 869 870 layersMenu = [[[NSMenu alloc] init] autorelease]; 871 872 layerCounter = [_ppDocument numLayers]; 873 874 while (layerCounter--) 875 { 876 layer = [_ppDocument layerAtIndex: layerCounter]; 877 878 layerName = [layer name]; 879 880 if (!layerName) 881 { 882 layerName = @""; 883 } 884 885 menuItem = [layersMenu addItemWithTitle: layerName 886 action: NULL 887 keyEquivalent: @""]; 888 889 [menuItem setImage: [self popupMenuThumbnailImageForLayerImage: [layer image]]]; 890 891 if (![layer isEnabled]) 892 { 893 NSAttributedString *attributedTitle; 894 895 attributedTitle = 896 [[[NSAttributedString alloc] 897 initWithString: layerName 898 attributes: 899 PPTextAttributesDict_DisabledTitle_PopupMenuItem()] 900 autorelease]; 901 902 [menuItem setAttributedTitle: attributedTitle]; 903 } 904 } 905 906 [_drawingLayerTitleablePopUpButton setMenu: layersMenu]; 907 908 [_drawingLayerTitleablePopUpButton 909 selectItemAtIndex: 910 [self popUpButtonMenuItemIndexForLayerAtIndex: [_ppDocument indexOfDrawingLayer]]]; 911 912 _needToUpdateDrawingLayerPopupButtonMenu = NO; 913} 914 915- (int) layerIndexForPopUpButtonMenuItemAtIndex: (int) itemIndex 916{ 917 return [_ppDocument numLayers] - itemIndex - 1; 918} 919 920- (int) popUpButtonMenuItemIndexForLayerAtIndex: (int) layerIndex 921{ 922 return [_ppDocument numLayers] - layerIndex - 1; 923} 924 925- (float) drawingLayerOpacitySliderQuantizedValue 926{ 927 // roundoff slider value to nearest .5% (1/200) 928 return roundf(200.0f * [_drawingLayerOpacitySlider floatValue]) / 200.0f; 929} 930 931@end 932