1/* 2 PPDocument_Layers.m 3 4 Copyright 2013-2018 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 "PPDocument.h" 26 27#import "PPDocument_Notifications.h" 28#import "PPDocumentLayer.h" 29#import "PPGeometry.h" 30#import "NSImage_PPUtilities.h" 31#import "NSBitmapImageRep_PPUtilities.h" 32#import "PPAppBootUtilities.h" 33 34 35static NSObject *gEmptyImageObject = nil; 36static NSBitmapImageRep *gEmptyBitmap = nil; 37 38 39@interface PPDocument (LayersPrivateMethods) 40 41- (bool) hasLayerAtIndex: (int) index; 42- (bool) isValidLayerInsertionIndex: (int) index; 43- (int) indexOfLayer: (PPDocumentLayer *) layer; 44 45- (bool) setupLayerForCurrentBlendingMode: (PPDocumentLayer *) layer; 46- (bool) setupAllLayersForCurrentBlendingMode; 47 48- (void) invalidateAllRelativeCachedLayerImagesForIndex: (int) index; 49- (void) invalidateCachedLayerImagesAtIndex: (int) index; 50- (void) invalidateImageObjectsInCache: (NSObject **) cachedImageObjectsArray 51 fromIndex: (int) startIndex 52 toIndex: (int) endIndex; 53- (void) removeAllCachedLayersImages; 54 55- (NSObject *) cachedOverlayersImageObjectForIndex: (int) index; 56- (NSObject *) cachedUnderlayersImageObjectForIndex: (int) index; 57 58- (NSObject *) mergedLayersImageObjectFromIndex: (int) firstIndex 59 toIndex: (int) lastIndex; 60 61- (NSBitmapImageRep *) mergedLayersBitmapFromIndex: (int) firstIndex 62 toIndex: (int) lastIndex; 63 64- (void) updateMergedVisibleLayersBitmapInRect: (NSRect) rect 65 indexOfUpdatedLayer: (int) indexOfUpdatedLayer; 66 67- (NSString *) uniqueLayerNameWithRoot: (NSString *) rootName; 68- (NSString *) duplicateNameForLayerName: (NSString *) layerName; 69 70- (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex 71 andPostNotification: (bool) shouldPostNotification; 72 73- (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex; 74 75- (void) setupDrawingLayerMembers; 76 77- (void) mergeDrawingLayerWithNextLayerInDirection: (PPDirectionType) directionType; 78 79- (bool) handleUpdateToLayer: (PPDocumentLayer *) layer; 80- (void) handleUpdateToDrawingLayerInRect: (NSRect) updateRect; 81 82- (void) updateDissolvedDrawingLayerBitmapInRect: (NSRect) updateRect; 83 84- (void) insertArchivedLayer: (NSData *) archivedLayer 85 atIndex: (int) index 86 andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer; 87 88- (bool) setLayersWithArchivedLayersData: (NSData *) archivedLayersData; 89 90- (void) setName: (NSString *) name forLayerAtIndex: (int) index; 91- (void) setEnabledFlag: (bool) isEnabled forLayerAtIndex: (int) index; 92- (void) setOpacity: (float) opacity forLayerAtIndex: (int) index; 93 94- (void) copyTIFFData: (NSData *) tiffData 95 toLayerAtIndex: (int) index 96 atPoint: (NSPoint) origin; 97 98- (void) recacheMergedVisibleLayersThumbnailImageInBounds: (NSRect) bounds; 99- (void) recacheDissolvedDrawingLayerThumbnailImageInBounds: (NSRect) bounds; 100 101@end 102 103@implementation NSObject (PPDocument_Layers) 104 105+ (void) ppDocument_Layers_SetupGlobals 106{ 107 gEmptyImageObject = [[NSNull null] retain]; 108 109 gEmptyBitmap = [[NSBitmapImageRep ppMaskBitmapOfSize: NSMakeSize(1,1)] retain]; 110} 111 112+ (void) load 113{ 114 macroPerformNSObjectSelectorAfterAppLoads(ppDocument_Layers_SetupGlobals); 115} 116 117@end 118 119@implementation PPDocument (Layers) 120 121- (int) numLayers 122{ 123 return _numLayers; 124} 125 126- (PPDocumentLayer *) layerAtIndex: (int) index 127{ 128 if (![self hasLayerAtIndex: index]) 129 { 130 return nil; 131 } 132 133 return (PPDocumentLayer *) [_layers objectAtIndex: index]; 134} 135 136- (void) createNewLayer 137{ 138 NSString *newLayerName; 139 PPDocumentLayer *newLayer; 140 int insertionIndex; 141 142 if (!_numLayers) 143 { 144 newLayerName = @"Main Layer"; 145 insertionIndex = 0; 146 } 147 else 148 { 149 newLayerName = [self uniqueLayerNameWithRoot: @"New Layer"]; 150 insertionIndex = _indexOfDrawingLayer + 1; 151 } 152 153 newLayer = [PPDocumentLayer layerWithSize: _canvasFrame.size andName: newLayerName]; 154 155 if (!newLayer) 156 goto ERROR; 157 158 [self insertLayer: newLayer atIndex: insertionIndex andSetAsDrawingLayer: YES]; 159 160 [[self undoManager] setActionName: @"Add Layer"]; 161 162 return; 163 164ERROR: 165 return; 166} 167 168- (void) insertLayer: (PPDocumentLayer *) layer 169 atIndex: (int) index 170 andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer 171{ 172 int oldDrawingLayerIndex; 173 NSUndoManager *undoManager; 174 175 if (!layer || ![self isValidLayerInsertionIndex: index]) 176 { 177 return; 178 } 179 180 // manually invalidate relevant cached images that won't be invalidated later by 181 // invalidateAllRelativeCachedLayerImagesForIndex: (called by handleUpdateToLayerAtIndex:) 182 183 [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects 184 fromIndex: index 185 toIndex: _numLayers - 1]; 186 187 [layer setDelegate: self]; 188 189 [self setupLayerForCurrentBlendingMode: layer]; 190 191 [_layers insertObject: layer atIndex: index]; 192 _numLayers = [_layers count]; 193 194 oldDrawingLayerIndex = _indexOfDrawingLayer; 195 196 if (shouldSetAsDrawingLayer) 197 { 198 [self setupDrawingLayerWithLayerAtIndex: index andPostNotification: NO]; 199 } 200 else if (_indexOfDrawingLayer >= index) 201 { 202 _indexOfDrawingLayer++; 203 } 204 205 [self handleUpdateToLayerAtIndex: index inRect: _canvasFrame]; 206 207 undoManager = [self undoManager]; 208 209 if (shouldSetAsDrawingLayer) 210 { 211 [[undoManager prepareWithInvocationTarget: self] 212 setupDrawingLayerWithLayerAtIndex: oldDrawingLayerIndex]; 213 } 214 215 [[undoManager prepareWithInvocationTarget: self] removeLayerAtIndex: index]; 216 217 if (![undoManager isUndoing] && ![undoManager isRedoing]) 218 { 219 [undoManager setActionName: @"Insert Layer"]; 220 } 221 222 [self postNotification_ReorderedLayers]; 223} 224 225- (void) removeLayerAtIndex: (int) index 226{ 227 int topLayerIndex; 228 PPDocumentLayer *layer; 229 NSData *archivedLayer = nil; 230 bool needToSetDrawingLayer = NO; 231 NSUndoManager *undoManager; 232 233 if (![self hasLayerAtIndex: index]) 234 { 235 return; 236 } 237 238 // manually invalidate relevant cached images that won't be invalidated later by 239 // invalidateAllRelativeCachedLayerImagesForIndex: (called by handleUpdateToLayerAtIndex:) 240 241 topLayerIndex = _numLayers - 1; 242 [self invalidateCachedLayerImagesAtIndex: topLayerIndex]; 243 [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects 244 fromIndex: index 245 toIndex: topLayerIndex]; 246 247 layer = [_layers objectAtIndex: index]; 248 [layer setDelegate: nil]; 249 250 archivedLayer = [NSKeyedArchiver archivedDataWithRootObject: layer]; 251 252 [_layers removeObjectAtIndex: index]; 253 _numLayers = [_layers count]; 254 255 if (index == _indexOfDrawingLayer) 256 { 257 needToSetDrawingLayer = YES; 258 } 259 260 undoManager = [self undoManager]; 261 262 // need to register insertArchivedLayer:... undo invocation before the call to 263 // createNewLayer, because createNewLayer registers an undo invocation for 264 // removeLayerAtIndex: (which might cause layer ordering & draw layer index issues on 265 // undo if the old removed layer is inserted before the newly-created layer is removed) 266 267 [[undoManager prepareWithInvocationTarget: self] 268 insertArchivedLayer: archivedLayer 269 atIndex: index 270 andSetAsDrawingLayer: needToSetDrawingLayer]; 271 272 if (!_numLayers) 273 { 274 if (![undoManager isUndoing] && ![undoManager isRedoing]) 275 { 276 [self createNewLayer]; 277 } 278 } 279 else if (needToSetDrawingLayer) 280 { 281 index = _indexOfDrawingLayer; 282 283 if (index > 0) 284 { 285 index--; 286 287 [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects 288 fromIndex: index 289 toIndex: index]; 290 } 291 292 [self setupDrawingLayerWithLayerAtIndex: index andPostNotification: NO]; 293 } 294 else if (_indexOfDrawingLayer > index) 295 { 296 _indexOfDrawingLayer--; 297 } 298 299 if (index >= _numLayers) 300 { 301 index--; 302 } 303 304 [self handleUpdateToLayerAtIndex: index inRect: _canvasFrame]; 305 306 if (![undoManager isUndoing] && ![undoManager isRedoing]) 307 { 308 [undoManager setActionName: @"Delete Layer"]; 309 } 310 311 [self postNotification_ReorderedLayers]; 312} 313 314- (void) moveLayerAtIndex: (int) oldIndex 315 toIndex: (int) newIndex 316{ 317 PPDocumentLayer *layer; 318 NSUndoManager *undoManager; 319 320 if (![self hasLayerAtIndex: oldIndex] 321 || ![self hasLayerAtIndex: newIndex] 322 || (oldIndex == newIndex)) 323 { 324 return; 325 } 326 327 // manually invalidate relevant cached images that won't be invalidated later by 328 // invalidateAllRelativeCachedLayerImagesForIndex: (called by 329 // handleUpdateToLayerAtIndex: newIndex) 330 331 if (oldIndex < newIndex) 332 { 333 [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects 334 fromIndex: oldIndex + 1 335 toIndex: newIndex]; 336 } 337 else 338 { 339 [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects 340 fromIndex: newIndex 341 toIndex: oldIndex - 1]; 342 } 343 344 layer = [[[_layers objectAtIndex: oldIndex] retain] autorelease]; 345 346 [_layers removeObjectAtIndex: oldIndex]; 347 [_layers insertObject: layer atIndex: newIndex]; 348 349 _indexOfDrawingLayer = [_layers indexOfObject: _drawingLayer]; 350 351 undoManager = [self undoManager]; 352 [[undoManager prepareWithInvocationTarget: self] moveLayerAtIndex: newIndex 353 toIndex: oldIndex]; 354 355 if (![undoManager isUndoing] && ![undoManager isRedoing]) 356 { 357 [undoManager setActionName: @"Reorder Layers"]; 358 } 359 360 [self handleUpdateToLayerAtIndex: newIndex inRect: _canvasFrame]; 361 362 [self postNotification_ReorderedLayers]; 363} 364 365- (void) duplicateLayerAtIndex: (int) index 366{ 367 PPDocumentLayer *dupeLayer; 368 NSString *dupeLayerName; 369 370 if (![self hasLayerAtIndex: index]) 371 { 372 return; 373 } 374 375 dupeLayer = [[[_layers objectAtIndex: index] copy] autorelease]; 376 377 if (!dupeLayer) 378 goto ERROR; 379 380 dupeLayerName = [self duplicateNameForLayerName: [dupeLayer name]]; 381 382 [dupeLayer setName: dupeLayerName]; 383 384 [self insertLayer: dupeLayer atIndex: index + 1 andSetAsDrawingLayer: YES]; 385 386 [[self undoManager] setActionName: @"Duplicate Layer"]; 387 388 return; 389 390ERROR: 391 return; 392} 393 394- (void) removeAllLayers 395{ 396 [self removeAllCachedLayersImages]; 397 398 [_layers makeObjectsPerformSelector: @selector(setDelegate:) withObject: nil]; 399 [_layers removeAllObjects]; 400 401 _numLayers = 0; 402 _indexOfDrawingLayer = -1; 403 404 [self setupDrawingLayerMembers]; 405} 406 407- (void) removeNontargetLayers 408{ 409 NSMutableArray *targetLayers; 410 int i; 411 NSBitmapImageRep *selectionMask = nil; 412 413 targetLayers = [NSMutableArray array]; 414 415 if (!targetLayers) 416 goto ERROR; 417 418 [self setupTargetLayerIndexesForOperationTarget: _layerOperationTarget]; 419 420 // don't allow all layers to be removed (must be at least one target layer remaining) 421 if (!_numTargetLayerIndexes) 422 goto ERROR; 423 424 for (i=0; i<_numTargetLayerIndexes; i++) 425 { 426 [targetLayers addObject: [_layers objectAtIndex: _targetLayerIndexes[i]]]; 427 } 428 429 if (_hasSelection) 430 { 431 selectionMask = [[_selectionMask copy] autorelease]; 432 } 433 434 [self setLayers: targetLayers]; 435 436 if (selectionMask) 437 { 438 [self setSelectionMask: selectionMask]; 439 } 440 441 [[self undoManager] setActionName: @"Remove Nontarget Layers"]; 442 443 return; 444 445ERROR: 446 return; 447} 448 449- (bool) setLayers: (NSArray *) newLayers 450{ 451 NSData *archivedOldLayers; 452 unsigned oldIndexOfDrawingLayer, newIndexOfDrawingLayer; 453 NSUndoManager *undoManager; 454 455 if (!newLayers || ![newLayers count]) 456 { 457 goto ERROR; 458 } 459 460 // use copies of the new layers, not the originals 461 newLayers = [[[NSArray alloc] initWithArray: newLayers copyItems: YES] autorelease]; 462 463 if (!newLayers) 464 goto ERROR; 465 466 archivedOldLayers = [NSKeyedArchiver archivedDataWithRootObject: _layers]; 467 oldIndexOfDrawingLayer = _indexOfDrawingLayer; 468 469 if (_hasSelection) 470 { 471 [self deselectAll]; // stores old selection in undo stack 472 } 473 474 [self removeAllLayers]; 475 476 [_layers setArray: newLayers]; 477 478 [_layers makeObjectsPerformSelector: @selector(setDelegate:) withObject: self]; 479 480 _numLayers = [_layers count]; 481 482 if (![self resizeCanvasForCurrentLayers]) 483 { 484 goto ERROR; 485 } 486 487 [self setupAllLayersForCurrentBlendingMode]; 488 489 newIndexOfDrawingLayer = oldIndexOfDrawingLayer; 490 491 if (![self hasLayerAtIndex: newIndexOfDrawingLayer]) 492 { 493 newIndexOfDrawingLayer = 0; 494 } 495 496 [self setupDrawingLayerWithLayerAtIndex: newIndexOfDrawingLayer andPostNotification: NO]; 497 498 [self handleUpdateToLayerAtIndex: _indexOfDrawingLayer inRect: _canvasFrame]; 499 500 undoManager = [self undoManager]; 501 502 [[undoManager prepareWithInvocationTarget: self] 503 setupDrawingLayerWithLayerAtIndex: oldIndexOfDrawingLayer]; 504 505 [[undoManager prepareWithInvocationTarget: self] 506 setLayersWithArchivedLayersData: archivedOldLayers]; 507 508 [self postNotification_ReloadedDocument]; 509 510 return YES; 511 512ERROR: 513 return NO; 514} 515 516- (void) selectDrawingLayerAtIndex: (int) newDrawingLayerIndex 517{ 518 int oldIndexOfDrawingLayer; 519 NSUndoManager *undoManager; 520 521 if (![self hasLayerAtIndex: newDrawingLayerIndex] 522 || (newDrawingLayerIndex == _indexOfDrawingLayer)) 523 { 524 return; 525 } 526 527 oldIndexOfDrawingLayer = _indexOfDrawingLayer; 528 529 [self setupDrawingLayerWithLayerAtIndex: newDrawingLayerIndex]; 530 531 undoManager = [self undoManager]; 532 [[undoManager prepareWithInvocationTarget: self] 533 selectDrawingLayerAtIndex: oldIndexOfDrawingLayer]; 534 535 if (![undoManager isUndoing] && ![undoManager isRedoing]) 536 { 537 [undoManager setActionName: @"Switch Drawing Layer"]; 538 } 539} 540 541- (int) indexOfDrawingLayer 542{ 543 return _indexOfDrawingLayer; 544} 545 546- (PPDocumentLayer *) drawingLayer 547{ 548 return _drawingLayer; 549} 550 551- (void) beginMultilayerOperation 552{ 553 _disallowUpdatesToMergedBitmap = YES; 554 555 [[[self undoManager] prepareWithInvocationTarget: self] finishMultilayerOperation]; 556} 557 558- (void) finishMultilayerOperation 559{ 560 _disallowUpdatesToMergedBitmap = NO; 561 562 [self removeAllCachedLayersImages]; 563 [self handleUpdateToLayerAtIndex: _indexOfDrawingLayer inRect: _canvasFrame]; 564 565 [[[self undoManager] prepareWithInvocationTarget: self] beginMultilayerOperation]; 566 567 [self postNotification_PerformedMultilayerOperation]; 568} 569 570- (void) moveDrawingLayerUp 571{ 572 if ((_indexOfDrawingLayer >= (_numLayers - 1)) || (_indexOfDrawingLayer < 0)) 573 { 574 return; 575 } 576 577 [self moveLayerAtIndex: _indexOfDrawingLayer toIndex: _indexOfDrawingLayer+1]; 578 579 [[self undoManager] setActionName: @"Move Layer Up"]; 580} 581 582- (void) moveDrawingLayerDown 583{ 584 if (_indexOfDrawingLayer < 1) 585 { 586 return; 587 } 588 589 [self moveLayerAtIndex: _indexOfDrawingLayer toIndex: _indexOfDrawingLayer-1]; 590 591 [[self undoManager] setActionName: @"Move Layer Down"]; 592} 593 594- (void) mergeDrawingLayerUp 595{ 596 [self mergeDrawingLayerWithNextLayerInDirection: kPPDirectionType_Up]; 597} 598 599- (void) mergeDrawingLayerDown 600{ 601 [self mergeDrawingLayerWithNextLayerInDirection: kPPDirectionType_Down]; 602} 603 604- (void) mergeAllLayers 605{ 606 PPDocumentLayer *mergedLayer; 607 NSBitmapImageRep *selectionMask = nil; 608 609 mergedLayer = [[_drawingLayer copy] autorelease]; 610 611 if (!mergedLayer) 612 goto ERROR; 613 614 [[mergedLayer bitmap] ppCopyFromBitmap: _mergedVisibleLayersBitmap 615 toPoint: NSZeroPoint]; 616 617 [mergedLayer handleUpdateToBitmapInRect: _canvasFrame]; 618 619 [mergedLayer setOpacity: 1.0f]; 620 [mergedLayer setEnabled: YES]; 621 622 if (_hasSelection) 623 { 624 selectionMask = [[_selectionMask copy] autorelease]; 625 } 626 627 [self setLayers: [NSArray arrayWithObject: mergedLayer]]; 628 629 if (selectionMask) 630 { 631 [self setSelectionMask: selectionMask]; 632 } 633 634 [[self undoManager] setActionName: @"Merge All Layers"]; 635 636 return; 637 638ERROR: 639 return; 640} 641 642- (void) setEnabledFlagForAllLayers: (bool) isEnabled 643{ 644 int i; 645 646 isEnabled = (isEnabled) ? YES : NO; 647 648 [self beginMultilayerOperation]; 649 650 for (i=0; i<_numLayers; i++) 651 { 652 [(PPDocumentLayer *) [_layers objectAtIndex: i] setEnabled: isEnabled]; 653 } 654 655 [self finishMultilayerOperation]; 656 657 [[self undoManager] 658 setActionName: (isEnabled) ? @"Enable All Layers" : @"Disable All Layers"]; 659} 660 661- (PPLayerBlendingMode) layerBlendingMode 662{ 663 return _layerBlendingMode; 664} 665 666- (void) setLayerBlendingMode: (PPLayerBlendingMode) layerBlendingMode 667{ 668 PPLayerBlendingMode oldLayerBlendingMode; 669 NSUndoManager *undoManager; 670 671 if (!PPLayerBlendingMode_IsValid(layerBlendingMode) 672 || (layerBlendingMode == _layerBlendingMode)) 673 { 674 return; 675 } 676 677 [self removeAllCachedLayersImages]; 678 679 oldLayerBlendingMode = _layerBlendingMode; 680 681 _layerBlendingMode = layerBlendingMode; 682 683 if (![self setupAllLayersForCurrentBlendingMode] 684 || ![self setupLayerBlendingBitmapOfSize: _canvasFrame.size]) 685 { 686 // if setup fails (can only fail in Linear mode), recover by forcing to Standard mode 687 688 _layerBlendingMode = kPPLayerBlendingMode_Standard; 689 690 [self setupAllLayersForCurrentBlendingMode]; 691 [self setupLayerBlendingBitmapOfSize: _canvasFrame.size]; 692 } 693 694 [self updateMergedVisibleLayersBitmapInRect: _canvasFrame 695 indexOfUpdatedLayer: _indexOfDrawingLayer]; 696 697 undoManager = [self undoManager]; 698 [[undoManager prepareWithInvocationTarget: self] setLayerBlendingMode: oldLayerBlendingMode]; 699 700 if (![undoManager isUndoing] && ![undoManager isRedoing]) 701 { 702 [undoManager setActionName: @"Switch Layer Blending Mode"]; 703 } 704 705 [self postNotification_SwitchedLayerBlendingMode]; 706 707 [self postNotification_UpdatedMergedVisibleAreaInRect: _canvasFrame]; 708 709 if (!_disallowThumbnailImageUpdateNotifications) 710 { 711 [self postNotification_UpdatedMergedVisibleThumbnailImage]; 712 } 713} 714 715- (void) toggleLayerBlendingMode 716{ 717 PPLayerBlendingMode newLayerBlendingMode = _layerBlendingMode + 1; 718 719 if (!PPLayerBlendingMode_IsValid(newLayerBlendingMode)) 720 { 721 newLayerBlendingMode = 0; 722 } 723 724 [self setLayerBlendingMode: newLayerBlendingMode]; 725} 726 727- (bool) setupLayerBlendingBitmapOfSize: (NSSize) bitmapSize 728{ 729 if (PPGeometry_IsZeroSize(bitmapSize)) 730 { 731 goto ERROR; 732 } 733 734 if (_layerBlendingMode == kPPLayerBlendingMode_Linear) 735 { 736 if (!_mergedVisibleLayersLinearBitmap 737 || !NSEqualSizes([_mergedVisibleLayersLinearBitmap ppSizeInPixels], bitmapSize)) 738 { 739 NSBitmapImageRep *mergedVisibleLayersLinearBitmap = 740 [NSBitmapImageRep ppLinearRGB16BitmapOfSize: bitmapSize]; 741 742 if (!mergedVisibleLayersLinearBitmap) 743 goto ERROR; 744 745 [_mergedVisibleLayersLinearBitmap release]; 746 _mergedVisibleLayersLinearBitmap = [mergedVisibleLayersLinearBitmap retain]; 747 } 748 else 749 { 750 [_mergedVisibleLayersLinearBitmap ppClearBitmap]; 751 } 752 } 753 else // kPPLayerBlendingMode_Standard: no linear bitmap needed 754 { 755 if (_mergedVisibleLayersLinearBitmap) 756 { 757 [_mergedVisibleLayersLinearBitmap release]; 758 _mergedVisibleLayersLinearBitmap = nil; 759 } 760 } 761 762 return YES; 763 764ERROR: 765 return NO; 766} 767 768- (void) copyImageBitmap: (NSBitmapImageRep *) bitmap 769 toLayerAtIndex: (int) index 770 atPoint: (NSPoint) origin 771{ 772 PPDocumentLayer *layer; 773 NSSize bitmapSize; 774 NSRect updateRect; 775 NSBitmapImageRep *layerBitmap; 776 NSData *undoBitmapTIFFData; 777 778 if (index == _indexOfDrawingLayer) 779 { 780 [self copyImageBitmapToDrawingLayer: bitmap atPoint: origin]; 781 return; 782 } 783 784 if (![bitmap ppIsImageBitmap]) 785 { 786 goto ERROR; 787 } 788 789 layer = [self layerAtIndex: index]; 790 791 if (!layer) 792 goto ERROR; 793 794 origin = PPGeometry_PointClippedToIntegerValues(origin); 795 bitmapSize = [bitmap ppSizeInPixels]; 796 797 updateRect.origin = origin; 798 updateRect.size = bitmapSize; 799 800 updateRect = NSIntersectionRect(updateRect, _canvasFrame); 801 802 if (NSIsEmptyRect(updateRect)) 803 { 804 goto ERROR; 805 } 806 807 if (!NSEqualSizes(updateRect.size, bitmapSize)) 808 { 809 NSRect croppingBounds; 810 811 croppingBounds.origin = NSMakePoint(updateRect.origin.x - origin.x, 812 updateRect.origin.y - origin.y); 813 814 croppingBounds.size = updateRect.size; 815 816 bitmap = [bitmap ppShallowDuplicateFromBounds: croppingBounds]; 817 818 if (!bitmap) 819 goto ERROR; 820 } 821 822 layerBitmap = [layer bitmap]; 823 824 undoBitmapTIFFData = [layerBitmap ppCompressedTIFFDataFromBounds: updateRect]; 825 826 if (!undoBitmapTIFFData) 827 goto ERROR; 828 829 [layerBitmap ppCopyFromBitmap: bitmap toPoint: updateRect.origin]; 830 [layer handleUpdateToBitmapInRect: updateRect]; 831 832 [self handleUpdateToLayerAtIndex: index inRect: updateRect]; 833 834 [[[self undoManager] prepareWithInvocationTarget: self] copyTIFFData: undoBitmapTIFFData 835 toLayerAtIndex: index 836 atPoint: updateRect.origin]; 837 838 return; 839 840ERROR: 841 return; 842} 843 844- (void) handleUpdateToLayerAtIndex: (int) index inRect: (NSRect) updateRect 845{ 846 if (![self hasLayerAtIndex: index] || _disallowUpdatesToMergedBitmap) 847 { 848 return; 849 } 850 851 updateRect = NSIntersectionRect(updateRect, _canvasFrame); 852 853 if (NSIsEmptyRect(updateRect)) 854 { 855 return; 856 } 857 858 [self invalidateAllRelativeCachedLayerImagesForIndex: index]; 859 860 [self updateMergedVisibleLayersBitmapInRect: updateRect 861 indexOfUpdatedLayer: index]; 862 863 if (index == _indexOfDrawingLayer) 864 { 865 [self handleUpdateToDrawingLayerInRect: updateRect]; 866 } 867 868 [self postNotification_UpdatedMergedVisibleAreaInRect: updateRect]; 869 870 if (!_disallowThumbnailImageUpdateNotifications) 871 { 872 [self postNotification_UpdatedMergedVisibleThumbnailImage]; 873 } 874} 875 876#pragma mark PPDocumentLayer delegate methods 877 878- (void) layer: (PPDocumentLayer *) layer 879 changedNameFromOldValue: (NSString *) oldName 880{ 881 int layerIndex; 882 NSUndoManager *undoManager; 883 884 layerIndex = [self indexOfLayer: layer]; 885 886 if (layerIndex < 0) 887 { 888 return; 889 } 890 891 undoManager = [self undoManager]; 892 [[undoManager prepareWithInvocationTarget: self] setName: oldName 893 forLayerAtIndex: layerIndex]; 894 895 if (![undoManager isUndoing] && ![undoManager isRedoing]) 896 { 897 [undoManager setActionName: @"Rename Layer"]; 898 } 899 900 [self postNotification_ChangedAttributeOfLayerAtIndex: layerIndex]; 901} 902 903- (void) layer: (PPDocumentLayer *) layer 904 changedEnabledFlagFromOldValue: (bool) oldEnabledFlag 905{ 906 int layerIndex; 907 NSUndoManager *undoManager; 908 909 if (![self handleUpdateToLayer: layer]) 910 { 911 return; 912 } 913 914 layerIndex = [self indexOfLayer: layer]; 915 916 undoManager = [self undoManager]; 917 [[undoManager prepareWithInvocationTarget: self] setEnabledFlag: oldEnabledFlag 918 forLayerAtIndex: layerIndex]; 919 920 if (![undoManager isUndoing] && ![undoManager isRedoing]) 921 { 922 [undoManager setActionName: [layer isEnabled] ? @"Enable Layer" : @"Disable Layer"]; 923 } 924 925 [self postNotification_ChangedAttributeOfLayerAtIndex: layerIndex]; 926} 927 928- (void) layer: (PPDocumentLayer *) layer 929 changedOpacityFromOldValue: (float) oldOpacity 930 shouldRegisterUndo: (bool) shouldRegisterUndo 931{ 932 int layerIndex; 933 934 if (![self handleUpdateToLayer: layer]) 935 { 936 return; 937 } 938 939 layerIndex = [self indexOfLayer: layer]; 940 941 if (shouldRegisterUndo) 942 { 943 NSUndoManager *undoManager = [self undoManager]; 944 945 [[undoManager prepareWithInvocationTarget: self] setOpacity: oldOpacity 946 forLayerAtIndex: layerIndex]; 947 948 if (![undoManager isUndoing] && ![undoManager isRedoing]) 949 { 950 NSString *actionName; 951 952 actionName = ([layer opacity] > oldOpacity) ? @"Increase" : @"Decrease"; 953 actionName = [actionName stringByAppendingString: @" Layer Opacity"]; 954 955 if (!actionName) 956 { 957 actionName = @"Change Layer Opacity"; 958 } 959 960 [[self undoManager] setActionName: actionName]; 961 } 962 } 963 964 [self postNotification_ChangedAttributeOfLayerAtIndex: layerIndex]; 965} 966 967#pragma mark Private methods 968 969- (bool) hasLayerAtIndex: (int) index 970{ 971 return ((index >= 0) && (index < _numLayers)) ? YES : NO; 972} 973 974- (bool) isValidLayerInsertionIndex: (int) index 975{ 976 return ((index >= 0) 977 && (index <= _numLayers) 978 && (_numLayers < kMaxLayersPerDocument)) ? YES : NO; 979} 980 981- (int) indexOfLayer: (PPDocumentLayer *) layer 982{ 983 NSUInteger indexOfLayer; 984 985 indexOfLayer = [_layers indexOfObject: layer]; 986 987 if (indexOfLayer == NSNotFound) 988 { 989 return -1; 990 } 991 992 return (int) indexOfLayer; 993} 994 995- (bool) setupLayerForCurrentBlendingMode: (PPDocumentLayer *) layer 996{ 997 bool shouldEnableLinearBitmap; 998 999 if (!layer) 1000 goto ERROR; 1001 1002 shouldEnableLinearBitmap = (_layerBlendingMode == kPPLayerBlendingMode_Linear) ? YES : NO; 1003 1004 if (![layer enableLinearBlendingBitmap: shouldEnableLinearBitmap]) 1005 { 1006 goto ERROR; 1007 } 1008 1009 return YES; 1010 1011ERROR: 1012 return NO; 1013} 1014 1015- (bool) setupAllLayersForCurrentBlendingMode 1016{ 1017 NSEnumerator *layerEnumerator; 1018 PPDocumentLayer *layer; 1019 1020 layerEnumerator = [_layers objectEnumerator]; 1021 1022 while (layer = [layerEnumerator nextObject]) 1023 { 1024 if (![self setupLayerForCurrentBlendingMode: layer]) 1025 { 1026 goto ERROR; 1027 } 1028 } 1029 1030 return YES; 1031 1032ERROR: 1033 return NO; 1034} 1035 1036- (void) invalidateAllRelativeCachedLayerImagesForIndex: (int) index 1037{ 1038 if (![self hasLayerAtIndex: index]) 1039 { 1040 return; 1041 } 1042 1043 [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects 1044 fromIndex: 0 1045 toIndex: index - 1]; 1046 1047 [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects 1048 fromIndex: index + 1 1049 toIndex: _numLayers - 1]; 1050} 1051 1052- (void) invalidateCachedLayerImagesAtIndex: (int) index 1053{ 1054 if (![self hasLayerAtIndex: index]) 1055 { 1056 return; 1057 } 1058 1059 [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects 1060 fromIndex: index 1061 toIndex: index]; 1062 1063 [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects 1064 fromIndex: index 1065 toIndex: index]; 1066} 1067 1068- (void) invalidateImageObjectsInCache: (NSObject **) cachedImageObjectsArray 1069 fromIndex: (int) startIndex 1070 toIndex: (int) endIndex 1071{ 1072 int i; 1073 1074 if (!cachedImageObjectsArray) 1075 goto ERROR; 1076 1077 if (startIndex < 0) 1078 { 1079 startIndex = 0; 1080 } 1081 1082 if (endIndex >= _numLayers) 1083 { 1084 endIndex = _numLayers - 1; 1085 } 1086 1087 if (startIndex > endIndex) 1088 { 1089 goto ERROR; 1090 } 1091 1092 for (i=startIndex; i<=endIndex; i++) 1093 { 1094 if (cachedImageObjectsArray[i]) 1095 { 1096 [cachedImageObjectsArray[i] release]; 1097 cachedImageObjectsArray[i] = nil; 1098 } 1099 } 1100 1101 return; 1102 1103ERROR: 1104 return; 1105} 1106 1107- (void) removeAllCachedLayersImages 1108{ 1109 [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects 1110 fromIndex: 0 1111 toIndex: _numLayers - 1]; 1112 1113 [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects 1114 fromIndex: 0 1115 toIndex: _numLayers - 1]; 1116} 1117 1118- (NSObject *) cachedOverlayersImageObjectForIndex: (int) index 1119{ 1120 if ((index >= (_numLayers - 1)) || ![self hasLayerAtIndex: index]) 1121 { 1122 return nil; 1123 } 1124 1125 if (!_cachedOverlayersImageObjects[index]) 1126 { 1127 _cachedOverlayersImageObjects[index] = 1128 [[self mergedLayersImageObjectFromIndex: index + 1 toIndex: _numLayers - 1] retain]; 1129 } 1130 1131 return _cachedOverlayersImageObjects[index]; 1132} 1133 1134- (NSObject *) cachedUnderlayersImageObjectForIndex: (int) index 1135{ 1136 if ((index < 1) || ![self hasLayerAtIndex: index]) 1137 { 1138 return nil; 1139 } 1140 1141 if (!_cachedUnderlayersImageObjects[index]) 1142 { 1143 _cachedUnderlayersImageObjects[index] = 1144 [[self mergedLayersImageObjectFromIndex: 0 toIndex: index - 1] retain]; 1145 } 1146 1147 return _cachedUnderlayersImageObjects[index]; 1148} 1149 1150- (NSObject *) mergedLayersImageObjectFromIndex: (int) firstIndex 1151 toIndex: (int) lastIndex 1152{ 1153 NSBitmapImageRep *mergedLayersBitmap; 1154 NSObject *imageObject = nil; 1155 1156 mergedLayersBitmap = [self mergedLayersBitmapFromIndex: firstIndex toIndex: lastIndex]; 1157 1158 if (!mergedLayersBitmap) 1159 goto ERROR; 1160 1161 if (mergedLayersBitmap == gEmptyBitmap) 1162 { 1163 // Empty bitmap: return empty image-object 1164 imageObject = gEmptyImageObject; 1165 } 1166 else if (_layerBlendingMode == kPPLayerBlendingMode_Linear) 1167 { 1168 // Linear blending: image-objects are NSBitmapImageReps (LinearRGB16) 1169 imageObject = mergedLayersBitmap; 1170 } 1171 else 1172 { 1173 // Standard blending: image-objects are NSImages 1174 imageObject = [NSImage ppImageWithBitmap: mergedLayersBitmap]; 1175 } 1176 1177 if (!imageObject) 1178 goto ERROR; 1179 1180 return imageObject; 1181 1182ERROR: 1183 return nil; 1184} 1185 1186- (NSBitmapImageRep *) mergedLayersBitmapFromIndex: (int) firstIndex 1187 toIndex: (int) lastIndex 1188{ 1189 NSBitmapImageRep *mergedLayersBitmap = nil; 1190 int index; 1191 PPDocumentLayer *layer; 1192 float layerOpacity; 1193 1194 if (firstIndex < 0) 1195 { 1196 firstIndex = 0; 1197 } 1198 1199 if (lastIndex >= [_layers count]) 1200 { 1201 lastIndex = [_layers count] - 1; 1202 } 1203 1204 if (firstIndex > lastIndex) 1205 { 1206 goto ERROR; 1207 } 1208 1209 if (_layerBlendingMode == kPPLayerBlendingMode_Linear) 1210 { 1211 // Linear blending - generate LinearRGB16 bitmap, merge using PikoPixel's LinearRGB16 1212 // methods 1213 1214 for (index=lastIndex; index>=firstIndex; index--) 1215 { 1216 layer = [self layerAtIndex: index]; 1217 layerOpacity = [layer opacity]; 1218 1219 if ([layer isEnabled] && (layerOpacity > 0.0f)) 1220 { 1221 if (!mergedLayersBitmap) 1222 { 1223 mergedLayersBitmap = 1224 [NSBitmapImageRep ppLinearRGB16BitmapOfSize: _canvasFrame.size]; 1225 1226 if (!mergedLayersBitmap) 1227 goto ERROR; 1228 1229 // merge the first layer using linear-copy (faster than linear-blend) 1230 1231 [mergedLayersBitmap ppLinearCopyFromLinearBitmap: 1232 [layer linearBlendingBitmap] 1233 opacity: layerOpacity 1234 inBounds: _canvasFrame]; 1235 } 1236 else 1237 { 1238 [mergedLayersBitmap ppLinearBlendFromLinearBitmapUnderneath: 1239 [layer linearBlendingBitmap] 1240 sourceOpacity: layerOpacity 1241 inBounds: _canvasFrame]; 1242 } 1243 } 1244 } 1245 } 1246 else 1247 { 1248 // Standard blending - generate standard Image bitmap (sRGB), merge using native Cocoa 1249 // methods 1250 1251 NSCompositingOperation compositingOperation; 1252 1253 for (index=firstIndex; index<=lastIndex; index++) 1254 { 1255 layer = [self layerAtIndex: index]; 1256 layerOpacity = [layer opacity]; 1257 1258 if ([layer isEnabled] && (layerOpacity > 0.0f)) 1259 { 1260 if (!mergedLayersBitmap) 1261 { 1262 mergedLayersBitmap = 1263 [NSBitmapImageRep ppImageBitmapOfSize: _canvasFrame.size]; 1264 1265 if (!mergedLayersBitmap) 1266 goto ERROR; 1267 1268 [mergedLayersBitmap ppSetAsCurrentGraphicsContext]; 1269 1270 // merge the first layer using NSCompositeCopy (faster than 1271 // NSCompositeSourceOver) 1272 1273 compositingOperation = NSCompositeCopy; 1274 } 1275 else 1276 { 1277 compositingOperation = NSCompositeSourceOver; 1278 } 1279 1280 [[layer image] drawInRect: _canvasFrame 1281 fromRect: _canvasFrame 1282 operation: compositingOperation 1283 fraction: layerOpacity]; 1284 } 1285 } 1286 1287 if (mergedLayersBitmap) 1288 { 1289 [mergedLayersBitmap ppRestoreGraphicsContext]; 1290 } 1291 } 1292 1293 if (!mergedLayersBitmap) 1294 { 1295 // No layers were merged - return empty bitmap (different from returning nil, which 1296 // signifies an error) 1297 return gEmptyBitmap; 1298 } 1299 1300 return mergedLayersBitmap; 1301 1302ERROR: 1303 return nil; 1304} 1305 1306- (void) updateMergedVisibleLayersBitmapInRect: (NSRect) rect 1307 indexOfUpdatedLayer: (int) indexOfUpdatedLayer 1308{ 1309 NSObject *imageObject, *imageObjectsToMerge[3]; 1310 int numImageObjectsToMerge = 0, imageIndexOfUpdatedLayer = -1, imageIndex; 1311 PPDocumentLayer *updatedLayer; 1312 float opacityOfUpdatedLayer, mergingOpacity; 1313 bool performedInitialMerge = NO; 1314 1315 if (NSIsEmptyRect(rect) 1316 || ![self hasLayerAtIndex: indexOfUpdatedLayer]) 1317 { 1318 return; 1319 } 1320 1321 // Collect image-objects for merge: 1322 1323 // 1) Underlayers image (merged layers below updated layer) 1324 1325 imageObject = [self cachedUnderlayersImageObjectForIndex: indexOfUpdatedLayer]; 1326 1327 if (imageObject && (imageObject != gEmptyImageObject)) 1328 { 1329 imageObjectsToMerge[numImageObjectsToMerge++] = imageObject; 1330 } 1331 1332 // 2) Updated-layer image 1333 1334 updatedLayer = [_layers objectAtIndex: indexOfUpdatedLayer]; 1335 opacityOfUpdatedLayer = [updatedLayer opacity]; 1336 1337 if ([updatedLayer isEnabled] && (opacityOfUpdatedLayer > 0.0f)) 1338 { 1339 // Linear blending: image-objects are NSBitmapImageReps (LinearRGB16) 1340 // Standard blending: image-objects are NSImages 1341 1342 imageObject = 1343 (_layerBlendingMode == kPPLayerBlendingMode_Linear) ? 1344 (NSObject *) [updatedLayer linearBlendingBitmap] : 1345 (NSObject *) [updatedLayer image]; 1346 1347 // Don't need to check that (imageObject != gEmptyImageObject), since gEmptyImageObject 1348 // is local & won't be returned by PPDocumentLayer methods 1349 1350 if (imageObject) 1351 { 1352 imageIndexOfUpdatedLayer = numImageObjectsToMerge; 1353 1354 imageObjectsToMerge[numImageObjectsToMerge++] = imageObject; 1355 } 1356 } 1357 1358 // 3) Overlayers image (merged layers above updated layer) 1359 1360 imageObject = [self cachedOverlayersImageObjectForIndex: indexOfUpdatedLayer]; 1361 1362 if (imageObject && (imageObject != gEmptyImageObject)) 1363 { 1364 imageObjectsToMerge[numImageObjectsToMerge++] = imageObject; 1365 } 1366 1367 // Merge collected image-objects: 1368 1369 if (_layerBlendingMode == kPPLayerBlendingMode_Linear) 1370 { 1371 // Linear blending - image-objects are NSBitmapImageReps (LinearRGB16); merge using 1372 // PikoPixel's LinearRGB16 bitmap methods 1373 1374 NSBitmapImageRep *mergingBitmap; 1375 1376 for (imageIndex=numImageObjectsToMerge-1; imageIndex>=0; imageIndex--) 1377 { 1378 mergingBitmap = (NSBitmapImageRep *) imageObjectsToMerge[imageIndex]; 1379 1380 mergingOpacity = 1381 (imageIndex == imageIndexOfUpdatedLayer) ? opacityOfUpdatedLayer : 1.0f; 1382 1383 if (!performedInitialMerge) 1384 { 1385 // merge the first bitmap using linear-copy (faster than linear-blend) 1386 1387 [_mergedVisibleLayersLinearBitmap ppLinearCopyFromLinearBitmap: mergingBitmap 1388 opacity: mergingOpacity 1389 inBounds: rect]; 1390 1391 performedInitialMerge = YES; 1392 } 1393 else 1394 { 1395 [_mergedVisibleLayersLinearBitmap ppLinearBlendFromLinearBitmapUnderneath: 1396 mergingBitmap 1397 sourceOpacity: mergingOpacity 1398 inBounds: rect]; 1399 } 1400 } 1401 1402 if (!performedInitialMerge) 1403 { 1404 // nothing was merged to the updated area, so clear it manually 1405 [_mergedVisibleLayersLinearBitmap ppClearBitmapInBounds: rect]; 1406 } 1407 1408 [_mergedVisibleLayersLinearBitmap ppLinearCopyToImageBitmap: _mergedVisibleLayersBitmap 1409 inBounds: rect]; 1410 } 1411 else 1412 { 1413 // Standard blending - image-objects are NSImages; merge using native Cocoa methods 1414 1415 NSImage *mergingImage; 1416 NSCompositingOperation compositingOperation; 1417 1418 for (imageIndex=0; imageIndex<numImageObjectsToMerge; imageIndex++) 1419 { 1420 mergingImage = (NSImage *) imageObjectsToMerge[imageIndex]; 1421 1422 mergingOpacity = 1423 (imageIndex == imageIndexOfUpdatedLayer) ? opacityOfUpdatedLayer : 1.0f; 1424 1425 if (!performedInitialMerge) 1426 { 1427 [_mergedVisibleLayersBitmap ppSetAsCurrentGraphicsContext]; 1428 1429 // merge the first image using NSCompositeCopy (faster than 1430 // NSCompositeSourceOver) 1431 1432 compositingOperation = NSCompositeCopy; 1433 performedInitialMerge = YES; 1434 } 1435 else 1436 { 1437 compositingOperation = NSCompositeSourceOver; 1438 } 1439 1440 [mergingImage drawInRect: rect 1441 fromRect: rect 1442 operation: compositingOperation 1443 fraction: mergingOpacity]; 1444 } 1445 1446 if (performedInitialMerge) 1447 { 1448 [_mergedVisibleLayersBitmap ppRestoreGraphicsContext]; 1449 } 1450 else 1451 { 1452 // nothing was merged to the updated area, so clear it manually 1453 [_mergedVisibleLayersBitmap ppClearBitmapInBounds: rect]; 1454 } 1455 } 1456 1457 _mergedVisibleBitmapHasEnabledLayer = (numImageObjectsToMerge > 0) ? YES : NO; 1458 1459 [self recacheMergedVisibleLayersThumbnailImageInBounds: rect]; 1460} 1461 1462- (NSString *) uniqueLayerNameWithRoot: (NSString *) rootName 1463{ 1464 int rootNameLength; 1465 NSMutableSet *prefixMatches; 1466 NSEnumerator *enumerator; 1467 PPDocumentLayer *layer; 1468 NSString *layerName, *testName; 1469 int suffixValue; 1470 1471 if (![rootName length]) 1472 { 1473 rootName = @""; 1474 } 1475 1476 rootNameLength = [rootName length]; 1477 1478 prefixMatches = [NSMutableSet set]; 1479 1480 enumerator = [_layers objectEnumerator]; 1481 1482 while (layer = [enumerator nextObject]) 1483 { 1484 layerName = [layer name]; 1485 1486 if (([layerName length] >= rootNameLength) 1487 && [layerName hasPrefix: rootName]) 1488 { 1489 [prefixMatches addObject: layerName]; 1490 } 1491 } 1492 1493 if (![prefixMatches count]) 1494 { 1495 return rootName; 1496 } 1497 1498 suffixValue = 1; 1499 testName = [NSString stringWithFormat: @"%@ %02d", rootName, suffixValue]; 1500 1501 while ([prefixMatches containsObject: testName]) 1502 { 1503 suffixValue++; 1504 testName = [NSString stringWithFormat: @"%@ %02d", rootName, suffixValue]; 1505 } 1506 1507 return testName; 1508} 1509 1510- (NSString *) duplicateNameForLayerName: (NSString *) layerName 1511{ 1512 if (![layerName hasSuffix: @" copy"]) 1513 { 1514 layerName = [layerName stringByAppendingString: @" copy"]; 1515 } 1516 1517 return [self uniqueLayerNameWithRoot: layerName]; 1518} 1519 1520- (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex 1521 andPostNotification: (bool) shouldPostNotification 1522{ 1523 if (![self hasLayerAtIndex: newDrawingLayerIndex]) 1524 { 1525 newDrawingLayerIndex = -1; 1526 } 1527 1528 _indexOfDrawingLayer = newDrawingLayerIndex; 1529 1530 [self setupDrawingLayerMembers]; 1531 1532 [self handleUpdateToDrawingLayerInRect: _canvasFrame]; 1533 1534 if (shouldPostNotification) 1535 { 1536 [self postNotification_SwitchedDrawingLayer]; 1537 } 1538} 1539 1540- (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex 1541{ 1542 [self setupDrawingLayerWithLayerAtIndex: newDrawingLayerIndex andPostNotification: YES]; 1543} 1544 1545- (void) setupDrawingLayerMembers 1546{ 1547 [_drawingLayerImage release]; 1548 _drawingLayerImage = nil; 1549 1550 [_drawingLayerBitmap release]; 1551 _drawingLayerBitmap = nil; 1552 1553 [_drawingLayer release]; 1554 _drawingLayer = nil; 1555 1556 if ([self hasLayerAtIndex: _indexOfDrawingLayer]) 1557 { 1558 _drawingLayer = [[_layers objectAtIndex: _indexOfDrawingLayer] retain]; 1559 _drawingLayerBitmap = [[_drawingLayer bitmap] retain]; 1560 _drawingLayerImage = [[_drawingLayer image] retain]; 1561 1562 [_drawingUndoBitmap ppCopyFromBitmap: _drawingLayerBitmap toPoint: NSZeroPoint]; 1563 } 1564 else 1565 { 1566 [_drawingUndoBitmap ppClearBitmap]; 1567 } 1568} 1569 1570- (void) mergeDrawingLayerWithNextLayerInDirection: (PPDirectionType) directionType 1571{ 1572 int indexOfMergingLayer; 1573 NSBitmapImageRep *mergedLayersBitmap; 1574 NSString *actionName; 1575 bool shouldEnableMergedDrawLayer = YES; 1576 1577 if (![self hasLayerAtIndex: _indexOfDrawingLayer]) 1578 { 1579 goto ERROR; 1580 } 1581 1582 if (directionType == kPPDirectionType_Up) 1583 { 1584 indexOfMergingLayer = _indexOfDrawingLayer + 1; 1585 1586 if (![self hasLayerAtIndex: indexOfMergingLayer]) 1587 { 1588 goto ERROR; 1589 } 1590 1591 mergedLayersBitmap = [self mergedLayersBitmapFromIndex: _indexOfDrawingLayer 1592 toIndex: indexOfMergingLayer]; 1593 1594 actionName = @"Merge with Layer Above"; 1595 } 1596 else if (directionType == kPPDirectionType_Down) 1597 { 1598 indexOfMergingLayer = _indexOfDrawingLayer - 1; 1599 1600 if (![self hasLayerAtIndex: indexOfMergingLayer]) 1601 { 1602 goto ERROR; 1603 } 1604 1605 mergedLayersBitmap = [self mergedLayersBitmapFromIndex: indexOfMergingLayer 1606 toIndex: _indexOfDrawingLayer]; 1607 1608 actionName = @"Merge with Layer Below"; 1609 } 1610 else 1611 { 1612 // only allow up or down directions 1613 goto ERROR; 1614 } 1615 1616 if (mergedLayersBitmap == gEmptyBitmap) 1617 { 1618 mergedLayersBitmap = [NSBitmapImageRep ppImageBitmapOfSize: _canvasFrame.size]; 1619 shouldEnableMergedDrawLayer = NO; 1620 } 1621 else if ([mergedLayersBitmap ppIsLinearRGB16Bitmap]) 1622 { 1623 mergedLayersBitmap = [mergedLayersBitmap ppImageBitmapFromLinearRGB16Bitmap]; 1624 } 1625 1626 if (!mergedLayersBitmap) 1627 goto ERROR; 1628 1629 [self copyImageBitmapToDrawingLayer: mergedLayersBitmap atPoint: NSZeroPoint]; 1630 1631 [_drawingLayer setOpacity: 1.0f]; 1632 [_drawingLayer setEnabled: shouldEnableMergedDrawLayer]; 1633 1634 [self removeLayerAtIndex: indexOfMergingLayer]; 1635 1636 [[self undoManager] setActionName: actionName]; 1637 1638 return; 1639 1640ERROR: 1641 return; 1642} 1643 1644- (bool) handleUpdateToLayer: (PPDocumentLayer *) layer 1645{ 1646 int indexOfChangedLayer; 1647 1648 indexOfChangedLayer = [_layers indexOfObject: layer]; 1649 1650 if (![self hasLayerAtIndex: indexOfChangedLayer]) 1651 { 1652 return NO; 1653 } 1654 1655 [self handleUpdateToLayerAtIndex: indexOfChangedLayer inRect: _canvasFrame]; 1656 1657 return YES; 1658} 1659 1660- (void) handleUpdateToDrawingLayerInRect: (NSRect) updateRect 1661{ 1662 [self updateDissolvedDrawingLayerBitmapInRect: updateRect]; 1663 1664 [self postNotification_UpdatedDrawingLayerAreaInRect: updateRect]; 1665 1666 if (!_disallowThumbnailImageUpdateNotifications) 1667 { 1668 [self postNotification_UpdatedDrawingLayerThumbnailImage]; 1669 } 1670} 1671 1672- (void) updateDissolvedDrawingLayerBitmapInRect: (NSRect) updateRect 1673{ 1674 float drawingLayerOpacity = [_drawingLayer opacity]; 1675 1676 if ([_drawingLayer isEnabled] && (drawingLayerOpacity > 0)) 1677 { 1678 [_dissolvedDrawingLayerBitmap ppSetAsCurrentGraphicsContext]; 1679 1680 [_drawingLayerImage drawInRect: updateRect 1681 fromRect: updateRect 1682 operation: NSCompositeCopy 1683 fraction: drawingLayerOpacity]; 1684 1685 [_dissolvedDrawingLayerBitmap ppRestoreGraphicsContext]; 1686 } 1687 else 1688 { 1689 [_dissolvedDrawingLayerBitmap ppClearBitmapInBounds: updateRect]; 1690 } 1691 1692 [self recacheDissolvedDrawingLayerThumbnailImageInBounds: updateRect]; 1693} 1694 1695- (void) insertArchivedLayer: (NSData *) archivedLayer 1696 atIndex: (int) index 1697 andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer 1698{ 1699 PPDocumentLayer *layer; 1700 1701 if (!archivedLayer) 1702 goto ERROR; 1703 1704 layer = [NSKeyedUnarchiver unarchiveObjectWithData: archivedLayer]; 1705 1706 if (!layer || ![layer isKindOfClass: [PPDocumentLayer class]]) 1707 { 1708 goto ERROR; 1709 } 1710 1711 [self insertLayer: layer atIndex: index andSetAsDrawingLayer: shouldSetAsDrawingLayer]; 1712 1713 return; 1714 1715ERROR: 1716 return; 1717} 1718 1719- (bool) setLayersWithArchivedLayersData: (NSData *) archivedLayersData 1720{ 1721 NSArray *layers; 1722 1723 if (!archivedLayersData) 1724 goto ERROR; 1725 1726 layers = [NSKeyedUnarchiver unarchiveObjectWithData: archivedLayersData]; 1727 1728 if (!layers || ![layers isKindOfClass: [NSArray class]]) 1729 { 1730 goto ERROR; 1731 } 1732 1733 return [self setLayers: layers]; 1734 1735ERROR: 1736 return NO; 1737} 1738 1739- (void) setName: (NSString *) name forLayerAtIndex: (int) index 1740{ 1741 [[self layerAtIndex: index] setName: name]; 1742} 1743 1744- (void) setEnabledFlag: (bool) isEnabled forLayerAtIndex: (int) index 1745{ 1746 [[self layerAtIndex: index] setEnabled: isEnabled]; 1747} 1748 1749- (void) setOpacity: (float) opacity forLayerAtIndex: (int) index 1750{ 1751 [[self layerAtIndex: index] setOpacity: opacity]; 1752} 1753 1754- (void) copyTIFFData: (NSData *) tiffData 1755 toLayerAtIndex: (int) index 1756 atPoint: (NSPoint) origin 1757{ 1758 [self copyImageBitmap: [NSBitmapImageRep imageRepWithData: tiffData] 1759 toLayerAtIndex: index 1760 atPoint: origin]; 1761} 1762 1763// recacheMergedVisibleLayersThumbnailImageInBounds: 1764// & recacheDissolvedDrawingLayerThumbnailImageInBounds: methods are patch targets on GNUstep 1765// (PPGNUstepGlue_ImageRecacheSpeedups) 1766 1767- (void) recacheMergedVisibleLayersThumbnailImageInBounds: (NSRect) bounds 1768{ 1769 [_mergedVisibleLayersThumbnailImage recache]; 1770} 1771 1772- (void) recacheDissolvedDrawingLayerThumbnailImageInBounds: (NSRect) bounds 1773{ 1774 [_dissolvedDrawingLayerThumbnailImage recache]; 1775} 1776 1777@end 1778