1// Aseprite
2// Copyright (C) 2018-2020 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifndef APP_DOC_H_INCLUDED
9#define APP_DOC_H_INCLUDED
10#pragma once
11
12#include "app/doc_observer.h"
13#include "app/extra_cel.h"
14#include "app/file/format_options.h"
15#include "app/transformation.h"
16#include "base/disable_copying.h"
17#include "base/rw_lock.h"
18#include "doc/blend_mode.h"
19#include "doc/color.h"
20#include "doc/document.h"
21#include "doc/frame.h"
22#include "doc/mask_boundaries.h"
23#include "doc/pixel_format.h"
24#include "gfx/rect.h"
25#include "obs/observable.h"
26#include "os/color_space.h"
27
28#include <atomic>
29#include <memory>
30#include <string>
31
32namespace doc {
33 class Cel;
34 class Layer;
35 class Mask;
36 class Sprite;
37 class Tileset;
38}
39
40namespace gfx {
41 class Region;
42}
43
44namespace app {
45
46 class Context;
47 class DocApi;
48 class DocUndo;
49 class Transaction;
50
51 using namespace doc;
52
53 enum DuplicateType {
54 DuplicateExactCopy,
55 DuplicateWithFlattenLayers,
56 };
57
58 // An application document. It is the class used to contain one file
59 // opened and being edited by the user (a sprite).
60 class Doc : public doc::Document,
61 public obs::observable<DocObserver> {
62 enum Flags {
63 kAssociatedToFile = 1, // This sprite is associated to a file in the file-system
64 kMaskVisible = 2, // The mask wasn't hidden by the user
65 kInhibitBackup = 4, // Inhibit the backup process
66 kFullyBackedUp = 8, // Full backup was done
67 };
68 public:
69 Doc(Sprite* sprite);
70 ~Doc();
71
72 Context* context() const { return m_ctx; }
73 void setContext(Context* ctx);
74
75 // Lock/unlock API (RWLock wrapper)
76 bool canWriteLockFromRead() const;
77 bool readLock(int timeout);
78 bool writeLock(int timeout);
79 bool upgradeToWrite(int timeout);
80 void downgradeToRead();
81 void unlock();
82
83 bool weakLock(std::atomic<base::RWLock::WeakLock>* weak_lock_flag);
84 void weakUnlock();
85
86 // Sets active/running transaction.
87 void setTransaction(Transaction* transaction);
88 Transaction* transaction() { return m_transaction; }
89
90 // Returns a high-level API: observable and undoable methods.
91 DocApi getApi(Transaction& transaction);
92
93 //////////////////////////////////////////////////////////////////////
94 // Main properties
95
96 const DocUndo* undoHistory() const { return m_undo.get(); }
97 DocUndo* undoHistory() { return m_undo.get(); }
98
99 color_t bgColor() const;
100 color_t bgColor(Layer* layer) const;
101
102 os::ColorSpaceRef osColorSpace() const { return m_osColorSpace; }
103
104 //////////////////////////////////////////////////////////////////////
105 // Notifications
106
107 void notifyGeneralUpdate();
108 void notifyColorSpaceChanged();
109 void notifyPaletteChanged();
110 void notifySpritePixelsModified(Sprite* sprite, const gfx::Region& region, frame_t frame);
111 void notifyExposeSpritePixels(Sprite* sprite, const gfx::Region& region);
112 void notifyLayerMergedDown(Layer* srcLayer, Layer* targetLayer);
113 void notifyCelMoved(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame);
114 void notifyCelCopied(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame);
115 void notifySelectionChanged();
116 void notifySelectionBoundariesChanged();
117 void notifyTilesetChanged(Tileset* tileset);
118
119 //////////////////////////////////////////////////////////////////////
120 // File related properties
121
122 bool isModified() const;
123 bool isAssociatedToFile() const;
124 void markAsSaved();
125
126 // You can use this to indicate that we've destroyed (or we cannot
127 // trust) the file associated with the document (e.g. when we
128 // cancel a Save operation in the middle). So it's impossible to
129 // back to the saved state using the UndoHistory.
130 void impossibleToBackToSavedState();
131
132 // Returns true if it does make sense to create a backup in this
133 // document. For example, it doesn't make sense to create a backup
134 // for an unmodified document.
135 bool needsBackup() const;
136
137 // Can be used to avoid creating a backup when the file is in a
138 // unusual temporary state (e.g. when the file is resized to be
139 // exported with other size)
140 bool inhibitBackup() const;
141 void setInhibitBackup(const bool inhibitBackup);
142
143 void markAsBackedUp();
144 bool isFullyBackedUp() const;
145
146 //////////////////////////////////////////////////////////////////////
147 // Loaded options from file
148
149 void setFormatOptions(const FormatOptionsPtr& format_options);
150 FormatOptionsPtr formatOptions() const { return m_format_options; }
151
152 //////////////////////////////////////////////////////////////////////
153 // Boundaries
154
155 void destroyMaskBoundaries();
156 void generateMaskBoundaries(const Mask* mask = nullptr);
157
158 const MaskBoundaries& maskBoundaries() const {
159 return m_maskBoundaries;
160 }
161
162 MaskBoundaries& maskBoundaries() {
163 return m_maskBoundaries;
164 }
165
166 bool hasMaskBoundaries() const {
167 return !m_maskBoundaries.isEmpty();
168 }
169
170 //////////////////////////////////////////////////////////////////////
171 // Extra Cel (it is used to draw pen preview, pixels in movement, etc.)
172
173 ExtraCelRef extraCel() const { return m_extraCel; }
174 void setExtraCel(const ExtraCelRef& extraCel) { m_extraCel = extraCel; }
175
176 //////////////////////////////////////////////////////////////////////
177 // Mask
178
179 // Returns the current mask, it can be empty. The mask could be not
180 // empty but hidden to the user if the setMaskVisible(false) was
181 // used called before.
182 Mask* mask() const { return m_mask.get(); }
183
184 // Sets the current mask. The new mask will be visible by default,
185 // so you don't need to call setMaskVisible(true).
186 void setMask(const Mask* mask);
187
188 // Returns true only when the mask is not empty, and was not yet
189 // hidden using setMaskVisible (e.g. when the user "deselect the
190 // mask").
191 bool isMaskVisible() const;
192
193 // Changes the visibility state of the mask (it is useful only if
194 // the getMask() is not empty and the user can see that the mask is
195 // being hidden and shown to him).
196 void setMaskVisible(bool visible);
197
198 //////////////////////////////////////////////////////////////////////
199 // Transformation
200
201 Transformation getTransformation() const;
202 void setTransformation(const Transformation& transform);
203 void resetTransformation();
204
205 //////////////////////////////////////////////////////////////////////
206 // Last point used to draw straight lines using freehand tools + Shift key
207 // (EditorCustomizationDelegate::isStraightLineFromLastPoint() modifier)
208
209 static gfx::Point NoLastDrawingPoint();
210 gfx::Point lastDrawingPoint() const { return m_lastDrawingPoint; }
211 void setLastDrawingPoint(const gfx::Point& pos) { m_lastDrawingPoint = pos; }
212
213 //////////////////////////////////////////////////////////////////////
214 // Copying
215
216 void copyLayerContent(const Layer* sourceLayer, Doc* destDoc, Layer* destLayer) const;
217 Doc* duplicate(DuplicateType type) const;
218
219 void close();
220
221 protected:
222 void onFileNameChange() override;
223 virtual void onContextChanged();
224
225 private:
226 void removeFromContext();
227 void updateOSColorSpace(bool appWideSignal);
228
229 // The document is in the collection of documents of this context.
230 Context* m_ctx;
231
232 // Internal states of the document.
233 int m_flags;
234
235 // Read-Write locks.
236 base::RWLock m_rwLock;
237
238 // Undo and redo information about the document.
239 std::unique_ptr<DocUndo> m_undo;
240
241 // Current transaction for this document (when this is commit(), a
242 // new undo command is added to m_undo).
243 Transaction* m_transaction;
244
245 // Selected mask region boundaries
246 doc::MaskBoundaries m_maskBoundaries;
247
248 // Data to save the file in the same format that it was loaded
249 FormatOptionsPtr m_format_options;
250
251 // Extra cel used to draw extra stuff (e.g. editor's pen preview, pixels in movement, etc.)
252 ExtraCelRef m_extraCel;
253
254 // Current mask.
255 std::unique_ptr<doc::Mask> m_mask;
256
257 // Current transformation.
258 Transformation m_transformation;
259
260 gfx::Point m_lastDrawingPoint;
261
262 // Last used color space to render a sprite.
263 os::ColorSpaceRef m_osColorSpace;
264
265 DISABLE_COPYING(Doc);
266 };
267
268} // namespace app
269
270#endif
271