1/*
2    PPDocument_CanvasSettings.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 "PPBackgroundPattern.h"
29#import "PPGridPattern.h"
30#import "NSColor_PPUtilities.h"
31#import "PPUserDefaults.h"
32#import "PPGeometry.h"
33
34
35@implementation PPDocument (CanvasSettings)
36
37- (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern
38            backgroundImage: (NSImage *) backgroundImage
39            shouldDisplayBackgroundImage: (bool) shouldDisplayBackgroundImage
40            shouldSmoothenBackgroundImage: (bool) shouldSmoothenBackgroundImage
41{
42    bool didUpdateBackgroundSettings, oldShouldDisplayBackgroundImage,
43            oldShouldSmoothenBackgroundImage;
44    PPBackgroundPattern *oldBackgroundPattern;
45    NSImage *oldBackgroundImage;
46    NSUndoManager *undoManager;
47
48    shouldDisplayBackgroundImage = (shouldDisplayBackgroundImage) ? YES : NO;
49    shouldSmoothenBackgroundImage = (shouldSmoothenBackgroundImage) ? YES : NO;
50
51    didUpdateBackgroundSettings = NO;
52
53    oldBackgroundPattern = [[_backgroundPattern retain] autorelease];
54    oldBackgroundImage = [[_backgroundImage retain] autorelease];
55    oldShouldDisplayBackgroundImage = _shouldDisplayBackgroundImage;
56    oldShouldSmoothenBackgroundImage = _shouldSmoothenBackgroundImage;
57
58    if (backgroundPattern
59        && ![_backgroundPattern isEqualToBackgroundPattern: backgroundPattern])
60    {
61        [_backgroundPattern release];
62        _backgroundPattern = [backgroundPattern retain];
63
64        didUpdateBackgroundSettings = YES;
65    }
66
67    if (backgroundImage != _backgroundImage)
68    {
69        [_backgroundImage release];
70        _backgroundImage = [backgroundImage retain];
71
72        [self destroyCompressedBackgroundImageData];
73
74        didUpdateBackgroundSettings = YES;
75    }
76
77    if (_shouldDisplayBackgroundImage != shouldDisplayBackgroundImage)
78    {
79        _shouldDisplayBackgroundImage = shouldDisplayBackgroundImage;
80
81        didUpdateBackgroundSettings = YES;
82    }
83
84    if (_shouldSmoothenBackgroundImage != shouldSmoothenBackgroundImage)
85    {
86        _shouldSmoothenBackgroundImage = shouldSmoothenBackgroundImage;
87
88        didUpdateBackgroundSettings = YES;
89    }
90
91    if (!didUpdateBackgroundSettings)
92        return;
93
94    undoManager = [self undoManager];
95
96    if (oldBackgroundImage
97        && (oldBackgroundImage != _backgroundImage))
98    {
99        [[undoManager prepareWithInvocationTarget: self] setupCompressedBackgroundImageData];
100    }
101
102    [[undoManager prepareWithInvocationTarget: self]
103                                                setBackgroundPattern: oldBackgroundPattern
104                                                backgroundImage: oldBackgroundImage
105                                                shouldDisplayBackgroundImage:
106                                                            oldShouldDisplayBackgroundImage
107                                                shouldSmoothenBackgroundImage:
108                                                            oldShouldSmoothenBackgroundImage];
109
110    if (![undoManager isUndoing] && ![undoManager isRedoing])
111    {
112        [undoManager setActionName: @"Change Canvas Background Settings"];
113    }
114
115    [self postNotification_UpdatedBackgroundSettings];
116}
117
118- (PPBackgroundPattern *) backgroundPattern
119{
120    return _backgroundPattern;
121}
122
123- (NSColor *) backgroundPatternAsColor
124{
125    return [_backgroundPattern patternFillColor];
126}
127
128- (NSImage *) backgroundImage
129{
130    return _backgroundImage;
131}
132
133- (bool) shouldDisplayBackgroundImage
134{
135    return _shouldDisplayBackgroundImage;
136}
137
138- (bool) shouldSmoothenBackgroundImage
139{
140    return _shouldSmoothenBackgroundImage;
141}
142
143- (void) toggleBackgroundImageVisibility
144{
145    [self setBackgroundPattern: _backgroundPattern
146            backgroundImage: _backgroundImage
147            shouldDisplayBackgroundImage: (_shouldDisplayBackgroundImage) ? NO : YES
148            shouldSmoothenBackgroundImage: _shouldSmoothenBackgroundImage];
149
150    [[self undoManager]
151            setActionName: (_shouldDisplayBackgroundImage) ? @"Show Canvas Background Image"
152                                                            : @"Hide Canvas Background Image"];
153}
154
155- (void) toggleBackgroundImageSmoothing
156{
157    [self setBackgroundPattern: _backgroundPattern
158            backgroundImage: _backgroundImage
159            shouldDisplayBackgroundImage: _shouldDisplayBackgroundImage
160            shouldSmoothenBackgroundImage: (_shouldSmoothenBackgroundImage) ? NO : YES];
161
162    [[self undoManager]
163            setActionName: (_shouldSmoothenBackgroundImage) ?
164                                @"Enable Background Image Smoothing" :
165                                @"Disable Background Image Smoothing"];
166}
167
168- (void) setGridPattern: (PPGridPattern *) gridPattern
169            shouldDisplayGrid: (bool) shouldDisplayGrid
170{
171    bool didUpdateGridSettings, oldShouldDisplayGrid;
172    PPGridPattern *oldGridPattern;
173    NSUndoManager *undoManager;
174
175    if (!gridPattern)
176    {
177        gridPattern = [PPUserDefaults gridPattern];
178    }
179
180    shouldDisplayGrid = (shouldDisplayGrid) ? YES : NO;
181
182    didUpdateGridSettings = NO;
183
184    oldGridPattern = [[_gridPattern retain] autorelease];
185    oldShouldDisplayGrid = _shouldDisplayGrid;
186
187    if (![_gridPattern isEqualToGridPattern: gridPattern])
188    {
189        [_gridPattern release];
190        _gridPattern = [gridPattern retain];
191
192        didUpdateGridSettings = YES;
193    }
194
195    if (_shouldDisplayGrid != shouldDisplayGrid)
196    {
197        _shouldDisplayGrid = shouldDisplayGrid;
198
199        didUpdateGridSettings = YES;
200    }
201
202    if (!didUpdateGridSettings)
203        return;
204
205    undoManager = [self undoManager];
206    [[undoManager prepareWithInvocationTarget: self] setGridPattern: oldGridPattern
207                                                        shouldDisplayGrid: oldShouldDisplayGrid];
208
209    if (![undoManager isUndoing] && ![undoManager isRedoing])
210    {
211        [undoManager setActionName: @"Change Canvas Grid Settings"];
212    }
213
214    [self postNotification_UpdatedGridSettings];
215}
216
217- (PPGridPattern *) gridPattern
218{
219    return _gridPattern;
220}
221
222- (bool) shouldDisplayGrid
223{
224    return _shouldDisplayGrid;
225}
226
227- (void) toggleGridVisibility
228{
229    [self setGridPattern: _gridPattern
230            shouldDisplayGrid: (_shouldDisplayGrid) ? NO : YES];
231
232    [[self undoManager]
233            setActionName: (_shouldDisplayGrid) ? @"Show Canvas Grid" : @"Hide Canvas Grid"];
234}
235
236- (PPGridType) pixelGridPatternType
237{
238    return [_gridPattern pixelGridType];
239}
240
241- (void) togglePixelGridPatternType
242{
243    PPGridPattern *toggledGridPattern;
244
245    if (!_shouldDisplayGrid)
246        return;
247
248    toggledGridPattern = [_gridPattern gridPatternByTogglingPixelGridType];
249
250    if (!toggledGridPattern)
251        goto ERROR;
252
253    [self setGridPattern: toggledGridPattern
254            shouldDisplayGrid: _shouldDisplayGrid];
255
256    [[self undoManager] setActionName: @"Switch Canvas Grid Type"];
257
258    return;
259
260ERROR:
261    return;
262}
263
264- (bool) gridPatternShouldDisplayGuidelines
265{
266    return [_gridPattern shouldDisplayGuidelines];
267}
268
269- (void) toggleGridGuidelinesVisibility
270{
271    PPGridPattern *toggledGridPattern;
272
273    if (!_shouldDisplayGrid)
274        return;
275
276    toggledGridPattern = [_gridPattern gridPatternByTogglingGuidelinesVisibility];
277
278    if (!toggledGridPattern)
279        goto ERROR;
280
281    [self setGridPattern: toggledGridPattern
282            shouldDisplayGrid: _shouldDisplayGrid];
283
284    [[self undoManager]
285            setActionName: ([self gridPatternShouldDisplayGuidelines]) ?
286                                @"Show Canvas Grid Guidelines" : @"Hide Canvas Grid Guidelines"];
287
288    return;
289
290ERROR:
291    return;
292}
293
294- (bool) shouldDisplayGridAndGridGuidelines
295{
296    return (_shouldDisplayGrid && [_gridPattern shouldDisplayGuidelines]) ? YES : NO;
297}
298
299- (NSRect) gridGuidelineBoundsCoveredByRect: (NSRect) rect
300{
301    return PPGeometry_GridBoundsCoveredByRectOnCanvasOfSizeWithGridOfSpacingSize(
302                                                            rect,
303                                                            _canvasFrame.size,
304                                                            [_gridPattern guidelineSpacingSize]);
305}
306
307- (bool) hasCustomCanvasSettings
308{
309    return (_backgroundImage
310            || ![_backgroundPattern isEqualToBackgroundPattern:
311                                                        [PPUserDefaults backgroundPattern]]
312            || ![_gridPattern isEqualToGridPattern: [PPUserDefaults gridPattern]]) ? YES : NO;
313}
314
315@end
316