1 /*
2     PPDocument.h
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 <Cocoa/Cocoa.h>
26 #import "PPDocumentTypes.h"
27 #import "PPDefines.h"
28 #import "PPToolType.h"
29 #import "PPGridType.h"
30 #import "PPDirectionType.h"
31 #import "PPLayerDisplayMode.h"
32 #import "PPSamplerImagePanelType.h"
33 #import "NSDocument_PPUtilities.h"
34 #import "PPBitmapPixelTypes.h"
35 
36 
37 @class PPDocumentLayer, PPTool, PPBackgroundPattern, PPGridPattern, PPDocumentSamplerImage,
38         PPExportPanelAccessoryViewController, PPDocumentWindowController;
39 
40 @interface PPDocument : NSDocument <NSCoding>
41 {
42     NSRect _canvasFrame;
43 
44     NSMutableArray *_layers;
45     int _numLayers;
46 
47     PPDocumentLayer *_drawingLayer;
48     NSBitmapImageRep *_drawingLayerBitmap;
49     NSImage *_drawingLayerImage;
50     int _indexOfDrawingLayer;
51 
52     NSBitmapImageRep *_dissolvedDrawingLayerBitmap;
53     NSImage *_dissolvedDrawingLayerThumbnailImage;
54 
55     NSBitmapImageRep *_mergedVisibleLayersBitmap;
56     NSImage *_mergedVisibleLayersThumbnailImage;
57 
58     NSBitmapImageRep *_mergedVisibleLayersLinearBitmap;
59 
60     NSObject *_cachedOverlayersImageObjects[kMaxLayersPerDocument];
61     NSObject *_cachedUnderlayersImageObjects[kMaxLayersPerDocument];
62 
63     NSBitmapImageRep *_drawingMask;
64 
65     NSBitmapImageRep *_drawingUndoBitmap;
66     NSRect _drawingUndoBounds;
67 
68     NSBitmapImageRep *_selectionMask;
69     NSRect _selectionBounds;
70 
71     NSBitmapImageRep *_interactiveEraseMask;
72     NSRect _interactiveEraseBounds;
73 
74     PPToolType _selectedToolType;
75     PPToolType _lastSelectedToolType;
76     PPToolType _activeToolType;
77     PPTool *_activeTool;
78 
79     PPPenMode _penMode;
80 
81     NSColor *_fillColor;        // original colorspace preserved, returned by -fillColor method
82     NSColor *_fillColor_sRGB;   // _fillColor in sRGB colorspace, used when drawing & saving
83 
84     PPImageBitmapPixel _fillColorPixelValue_sRGB;   // _fillColor_sRGB as bitmapData pixel-value
85 
86     PPLayerOperationTarget _layerOperationTarget;
87     int _targetLayerIndexes[kMaxLayersPerDocument];
88     int _numTargetLayerIndexes;
89 
90     PPLayerBlendingMode _layerBlendingMode;
91 
92     PPBackgroundPattern *_backgroundPattern;
93     NSImage *_backgroundImage;
94     NSData *_compressedBackgroundImageData;
95 
96     PPGridPattern *_gridPattern;
97 
98     NSMutableArray *_samplerImages;
99     int _numSamplerImages;
100     int _activeSamplerImageIndexes[kNumPPSamplerImagePanelTypes];
101     int _samplerImageMinIndexValues[kNumPPSamplerImagePanelTypes];
102 
103     PPLayerOperationTarget _interactiveMoveOperationTarget;
104     PPLayerDisplayMode _interactiveMoveDisplayMode;
105     NSBitmapImageRep *_interactiveMoveTargetBitmap;
106     NSBitmapImageRep *_interactiveMoveFloatingBitmap;
107     NSBitmapImageRep *_interactiveMoveFloatingMask;
108     NSBitmapImageRep *_interactiveMoveUnderlyingBitmap;
109     NSBitmapImageRep *_interactiveMoveInitialSelectionMask;
110     NSRect _interactiveMoveInitialSelectionBounds;
111     PPMoveOperationType _lastInteractiveMoveType;
112     NSPoint _lastInteractiveMoveOffset;
113     NSRect _lastInteractiveMoveBounds;
114 
115     PPExportPanelAccessoryViewController *_exportPanelViewController;
116 
117     PPDocumentSaveFormat _saveFormat;
118 
119     bool _hasSelection;
120     bool _isDrawing;
121     bool _shouldUndoCurrentDrawing;
122     bool _isPerformingInteractiveMove;
123     bool _shouldDisplayBackgroundImage;
124     bool _shouldSmoothenBackgroundImage;
125     bool _shouldDisplayGrid;
126     bool _shouldEnableSamplerImagePanel;
127     bool _mergedVisibleBitmapHasEnabledLayer;
128     bool _disallowUpdatesToMergedBitmap;
129     bool _disallowThumbnailImageUpdateNotifications;
130     bool _disallowAutosaving;
131     bool _shouldAutosaveWhenAllowed;
132     bool _savePanelShouldAttachExportAccessoryView;
133     bool _saveToOperationShouldUseExportSettings;
134     bool _sourceBitmapHasAnimationFrames;
135 }
136 
137 - (bool) setupNewPPDocumentWithCanvasSize: (NSSize) canvasSize;
138 
139 - (bool) loadFromPPDocument: (PPDocument *) ppDocument;
140 
141 - (bool) loadFromImageBitmap: (NSBitmapImageRep *) bitmap
142             withFileType: (NSString *) fileType;
143 
144 - (bool) needToSetCanvasSize;
145 - (NSSize) canvasSize;
146 
147 - (bool) resizeCanvasForCurrentLayers;
148 
149 - (NSBitmapImageRep *) mergedVisibleLayersBitmap;
150 - (NSImage *) mergedVisibleLayersThumbnailImage;
151 
152 - (NSBitmapImageRep *) drawingLayerBitmap;
153 - (NSImage *) drawingLayerThumbnailImage;
154 
155 - (NSBitmapImageRep *) dissolvedDrawingLayerBitmap;
156 - (NSImage *) dissolvedDrawingLayerThumbnailImage;
157 
158 - (NSBitmapImageRep *) mergedVisibleLayersBitmapUsingExportPanelSettings;
159 
160 - (PPDocumentWindowController *) ppDocumentWindowController;
161 
162 - (void) setupCompressedBackgroundImageData;
163 - (void) destroyCompressedBackgroundImageData;
164 
165 - (bool) sourceBitmapHasAnimationFrames;
166 
167 @end
168 
169 @interface PPDocument (Saving)
170 
171 - (void) disableAutosaving: (bool) disallowAutosaving;
172 
173 - (void) exportImage;
174 
175 @end
176 
177 @interface PPDocument (LayerOperationTarget)
178 
179 - (void) setLayerOperationTarget: (PPLayerOperationTarget) operationTarget;
180 - (PPLayerOperationTarget) layerOperationTarget;
181 
182 - (bool) layerOperationTargetHasEnabledLayer;
183 
184 - (NSBitmapImageRep *) sourceBitmapForLayerOperationTarget:
185                                                     (PPLayerOperationTarget) operationTarget;
186 
187 - (void) setupTargetLayerIndexesForOperationTarget: (PPLayerOperationTarget) operationTarget;
188 
189 - (NSString *) nameOfLayerOperationTarget: (PPLayerOperationTarget) operationTarget;
190 - (NSString *) nameWithSelectionStateForLayerOperationTarget:
191                                                     (PPLayerOperationTarget) operationTarget;
192 
193 @end
194 
195 @interface PPDocument (Layers)
196 
197 - (int) numLayers;
198 - (PPDocumentLayer *) layerAtIndex: (int) index;
199 
200 - (void) createNewLayer;
201 - (void) insertLayer: (PPDocumentLayer *) layer
202             atIndex: (int) index
203             andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer;
204 - (void) removeLayerAtIndex: (int) index;
205 - (void) moveLayerAtIndex: (int) oldIndex
206             toIndex: (int) newIndex;
207 - (void) duplicateLayerAtIndex: (int) index;
208 
209 - (void) removeAllLayers;
210 - (void) removeNontargetLayers;
211 
212 - (bool) setLayers: (NSArray *) newLayers;
213 
214 - (void) selectDrawingLayerAtIndex: (int) newDrawingLayerIndex;
215 - (int) indexOfDrawingLayer;
216 - (PPDocumentLayer *) drawingLayer;
217 
218 - (void) beginMultilayerOperation;
219 - (void) finishMultilayerOperation;
220 
221 - (void) moveDrawingLayerUp;
222 - (void) moveDrawingLayerDown;
223 
224 - (void) mergeDrawingLayerUp;
225 - (void) mergeDrawingLayerDown;
226 
227 - (void) mergeAllLayers;
228 
229 - (void) setEnabledFlagForAllLayers: (bool) isEnabled;
230 
231 - (PPLayerBlendingMode) layerBlendingMode;
232 - (void) setLayerBlendingMode: (PPLayerBlendingMode) layerBlendingMode;
233 - (void) toggleLayerBlendingMode;
234 
235 - (bool) setupLayerBlendingBitmapOfSize: (NSSize) bitmapSize;
236 
237 - (void) copyImageBitmap: (NSBitmapImageRep *) bitmap
238             toLayerAtIndex: (int) index
239             atPoint: (NSPoint) origin;
240 
241 - (void) handleUpdateToLayerAtIndex: (int) index
242             inRect: (NSRect) updateRect;
243 
244 @end
245 
246 @interface PPDocument (ActiveTool)
247 
248 // The Selected tool is the tool selected by the user in the tool palette; The Active tool is
249 // the tool used on the canvas - it can be different from the Selected tool if a modifier key's
250 // pressed.
251 
252 - (void) setSelectedToolType: (PPToolType) toolType;
253 - (void) setSelectedToolTypeToLastSelectedType;
254 - (PPToolType) selectedToolType;
255 
256 - (void) setActiveToolType: (PPToolType) toolType;
257 - (PPToolType) activeToolType;
258 - (PPTool *) activeTool;
259 
260 @end
261 
262 @interface PPDocument (Drawing)
263 
264 - (NSColor *) fillColor;
265 - (void) setFillColor: (NSColor *) fillColor;
266 - (void) setFillColorWithoutUndoRegistration: (NSColor *) fillColor;
267 
268 - (void) beginDrawingWithPenMode: (PPPenMode) penMode;
269 - (void) finishDrawing;
270 
271 - (void) undoCurrentDrawingAtNextDraw;
272 
273 - (void) drawPixelAtPoint: (NSPoint) point;
274 - (void) drawLineFromPoint: (NSPoint) startPoint toPoint: (NSPoint) endPoint;
275 - (void) drawRect: (NSRect) rect andFill: (bool) shouldFill;
276 - (void) drawOvalInRect: (NSRect) rect andFill: (bool) shouldFill;
277 - (void) drawBezierPath: (NSBezierPath *) path andFill: (bool) shouldFill;
278 
279 - (void) drawColorRampWithStartingColor: (NSColor *) startColor
280             fromPoint: (NSPoint) startPoint
281             toPoint: (NSPoint) endPoint
282             returnedRampBounds: (NSRect *) returnedRampBounds
283             returnedDrawMask: (NSBitmapImageRep **) returnedDrawMask;
284 
285 - (NSColor *) colorAtPoint: (NSPoint) point
286                 inTarget: (PPLayerOperationTarget) target;
287 
288 - (void) fillPixelsMatchingColorAtPoint: (NSPoint) point
289             colorMatchTolerance: (unsigned) colorMatchTolerance
290             pixelMatchingMode: (PPPixelMatchingMode) pixelMatchingMode
291             returnedMatchMask: (NSBitmapImageRep **) returnedMatchMask
292             returnedMatchMaskBounds: (NSRect *) returnedMatchMaskBounds;
293 
294 - (void) noninteractiveFillSelectedDrawingArea;
295 
296 - (void) noninteractiveEraseSelectedAreaInTarget: (PPLayerOperationTarget) operationTarget
297             andClearSelectionMask: (bool) shouldClearSelectionMask;
298 
299 - (bool) getInteractiveEraseMask: (NSBitmapImageRep **) returnedEraseMask
300             andBounds: (NSRect *) returnedEraseBounds;
301 
302 - (void) copyImageBitmapToDrawingLayer: (NSBitmapImageRep *) bitmap atPoint: (NSPoint) origin;
303 
304 @end
305 
306 @interface PPDocument (Selection)
307 
308 - (bool) setupSelectionMaskBitmapOfSize: (NSSize) maskSize;
309 
310 - (bool) hasSelection;
311 - (NSRect) selectionBounds;
312 
313 - (NSBitmapImageRep *) selectionMask;
314 - (void) setSelectionMask: (NSBitmapImageRep *) selectionMask;
315 
316 - (void) setSelectionMaskAreaWithBitmap: (NSBitmapImageRep *) selectionMask
317                                 atPoint: (NSPoint) origin;
318 
319 - (void) selectRect: (NSRect) rect
320             selectionMode: (PPSelectionMode) selectionMode;
321 
322 - (void) selectPath: (NSBezierPath *) path
323             selectionMode: (PPSelectionMode) selectionMode;
324 
325 - (void) selectPixelsMatchingColorAtPoint: (NSPoint) point
326             colorMatchTolerance: (unsigned) colorMatchTolerance
327             pixelMatchingMode: (PPPixelMatchingMode) pixelMatchingMode
328             selectionMode: (PPSelectionMode) selectionMode;
329 
330 - (void) selectAll;
331 - (void) selectVisibleTargetPixels;
332 - (void) deselectAll;
333 - (void) deselectInvisibleTargetPixels;
334 
335 - (void) invertSelection;
336 - (void) closeHolesInSelection;
337 
338 - (PPDocument *) ppDocumentFromSelection;
339 
340 @end
341 
342 @interface PPDocument (PixelMatching)
343 
344 // maskForPixelsMatchingColorAtPoint::: can be called repeatedly (when dragging the fill or
345 // wand tools), so rather than construct a new bitmap each time, it just returns a pointer to
346 // the _drawingMask member (the returned bitmap should only be used temporarily)
347 
348 - (NSBitmapImageRep *) maskForPixelsMatchingColorAtPoint: (NSPoint) point
349                         colorMatchTolerance: (unsigned) colorMatchTolerance
350                         pixelMatchingMode: (PPPixelMatchingMode) pixelMatchingMode
351                         shouldIntersectSelectionMask: (bool) shouldIntersectSelectionMask;
352 
353 @end
354 
355 @interface PPDocument (Moving)
356 
357 - (void) nudgeInDirection: (PPDirectionType) directionType
358             moveType: (PPMoveOperationType) moveType
359             target: (PPLayerOperationTarget) operationTarget;
360 
361 - (void) beginInteractiveMoveWithTarget: (PPLayerOperationTarget) operationTarget
362             canvasDisplayMode: (PPLayerDisplayMode) canvasDisplayMode
363             moveType: (PPMoveOperationType) moveType;
364 
365 - (void) setInteractiveMoveOffset: (NSPoint) offset
366             andMoveType: (PPMoveOperationType) moveType;
367 
368 - (void) finishInteractiveMove;
369 
370 @end
371 
372 @interface PPDocument (MirroringRotating)
373 
374 - (void) mirrorHorizontallyWithTarget: (PPLayerOperationTarget) operationTarget;
375 - (void) mirrorVerticallyWithTarget: (PPLayerOperationTarget) operationTarget;
376 
377 - (void) rotate180WithTarget: (PPLayerOperationTarget) operationTarget;
378 - (void) rotate90ClockwiseWithTarget: (PPLayerOperationTarget) operationTarget;
379 - (void) rotate90CounterclockwiseWithTarget: (PPLayerOperationTarget) operationTarget;
380 
381 @end
382 
383 @interface PPDocument (Pasteboard)
384 
385 - (bool) canReadFromPasteboard;
386 - (bool) canWriteToPasteboard;
387 
388 - (void) copySelectionToPasteboardFromTarget: (PPLayerOperationTarget) operationTarget;
389 
390 - (void) cutSelectionToPasteboardFromTarget: (PPLayerOperationTarget) operationTarget;
391 
392 - (void) pasteNewLayerFromPasteboard;
393 - (void) pasteIntoDrawingLayerFromPasteboard;
394 
395 + (PPDocument *) ppDocumentFromPasteboard;
396 
397 @end
398 
399 @interface PPDocument (CanvasSettings)
400 
401 - (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern
402             backgroundImage: (NSImage *) backgroundImage
403             shouldDisplayBackgroundImage: (bool) shouldDisplayBackgroundImage
404             shouldSmoothenBackgroundImage: (bool) shouldSmoothenBackgroundImage;
405 
406 - (PPBackgroundPattern *) backgroundPattern;
407 - (NSColor *) backgroundPatternAsColor;
408 - (NSImage *) backgroundImage;
409 - (bool) shouldDisplayBackgroundImage;
410 - (bool) shouldSmoothenBackgroundImage;
411 
412 - (void) toggleBackgroundImageVisibility;
413 - (void) toggleBackgroundImageSmoothing;
414 
415 - (void) setGridPattern: (PPGridPattern *) gridPattern
416             shouldDisplayGrid: (bool) shouldDisplayGrid;
417 
418 - (PPGridPattern *) gridPattern;
419 
420 - (bool) shouldDisplayGrid;
421 - (void) toggleGridVisibility;
422 
423 - (PPGridType) pixelGridPatternType;
424 - (void) togglePixelGridPatternType;
425 
426 - (bool) gridPatternShouldDisplayGuidelines;
427 - (void) toggleGridGuidelinesVisibility;
428 
429 - (bool) shouldDisplayGridAndGridGuidelines;
430 
431 - (NSRect) gridGuidelineBoundsCoveredByRect: (NSRect) rect;
432 
433 - (bool) hasCustomCanvasSettings;
434 
435 @end
436 
437 @interface PPDocument (Resizing)
438 
439 - (void) resizeToSize: (NSSize) newSize shouldScale: (bool) shouldScale;
440 
441 - (void) cropToSelectionBounds;
442 
443 @end
444 
445 @interface PPDocument (Tiling)
446 
447 - (void) tileSelection;
448 
449 - (void) tileSelectionAsNewLayer;
450 
451 @end
452 
453 @interface PPDocument (SamplerImages)
454 
455 - (void) setupSamplerImageIndexes;
456 
457 - (int) numSamplerImages;
458 
459 - (NSArray *) samplerImages;
460 - (void) setSamplerImages: (NSArray *) newSamplerImages;
461 
462 - (PPDocumentSamplerImage *) activeSamplerImageForPanelType:
463                                                     (PPSamplerImagePanelType) samplerPanelType;
464 
465 - (void) activateNextSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType;
466 - (void) activatePreviousSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType;
467 
468 - (bool) hasActiveSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType;
469 
470 - (bool) shouldEnableSamplerImagePanel;
471 - (void) setShouldEnableSamplerImagePanel: (bool) shouldEnableSamplerImagePanel;
472 
473 @end
474 
475 @interface PPDocument (NotificationOverrides)
476 
477 // for better performance, operations that perform multiple quick updates to the document
478 // bitmaps (interactive drawing, interactive moving, opacity sliders) should disable thumbnail
479 // image update notifications to prevent the various thumbnail views from redrawing (each
480 // different size forces a resample of the entire image: SLOW) until the end of the operation
481 - (void) disableThumbnailImageUpdateNotifications:
482                                         (bool) shouldDisableThumbnailImageUpdateNotifications;
483 
484 - (void) sendThumbnailImageUpdateNotifications;
485 
486 @end
487 
488 extern NSString *PPDocumentNotification_UpdatedMergedVisibleArea;
489 extern NSString *PPDocumentNotification_UpdatedDrawingLayerArea;
490 extern NSString *PPDocumentNotification_UpdatedMergedVisibleThumbnailImage;
491 extern NSString *PPDocumentNotification_UpdatedDrawingLayerThumbnailImage;
492 extern NSString *PPDocumentNotification_UpdatedSelection;
493 extern NSString *PPDocumentNotification_SwitchedDrawingLayer;
494 extern NSString *PPDocumentNotification_ReorderedLayers;
495 extern NSString *PPDocumentNotification_PerformedMultilayerOperation;
496 extern NSString *PPDocumentNotification_ChangedLayerAttribute;
497 extern NSString *PPDocumentNotification_SwitchedLayerOperationTarget;
498 extern NSString *PPDocumentNotification_SwitchedLayerBlendingMode;
499 extern NSString *PPDocumentNotification_SwitchedSelectedTool;
500 extern NSString *PPDocumentNotification_SwitchedActiveTool;
501 extern NSString *PPDocumentNotification_ChangedFillColor;
502 extern NSString *PPDocumentNotification_UpdatedBackgroundSettings;
503 extern NSString *PPDocumentNotification_UpdatedGridSettings;
504 extern NSString *PPDocumentNotification_ReloadedDocument;
505 extern NSString *PPDocumentNotification_UpdatedSamplerImages;
506 extern NSString *PPDocumentNotification_SwitchedActiveSamplerImage;
507 
508 extern NSString *PPDocumentNotification_UserInfoKey_UpdateAreaRect;
509 extern NSString *PPDocumentNotification_UserInfoKey_IndexOfChangedLayer;
510 extern NSString *PPDocumentNotification_UserInfoKey_SamplerImagePanelType;
511