2015-02-12 23:16:25 +08:00
|
|
|
// Aseprite
|
2024-02-27 00:11:26 +08:00
|
|
|
// Copyright (C) 2018-2024 Igara Studio S.A.
|
2018-06-14 03:00:37 +08:00
|
|
|
// Copyright (C) 2001-2018 David Capello
|
2015-02-12 23:16:25 +08:00
|
|
|
//
|
2016-08-27 04:02:58 +08:00
|
|
|
// This program is distributed under the terms of
|
|
|
|
// the End-User License Agreement for Aseprite.
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
#ifndef APP_DOC_H_INCLUDED
|
|
|
|
#define APP_DOC_H_INCLUDED
|
2014-03-30 06:40:17 +08:00
|
|
|
#pragma once
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2018-07-07 13:47:42 +08:00
|
|
|
#include "app/doc_observer.h"
|
2015-08-19 21:03:29 +08:00
|
|
|
#include "app/extra_cel.h"
|
2014-08-22 10:39:20 +08:00
|
|
|
#include "app/file/format_options.h"
|
2016-07-12 01:16:01 +08:00
|
|
|
#include "app/transformation.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "base/disable_copying.h"
|
2018-07-07 07:55:10 +08:00
|
|
|
#include "base/rw_lock.h"
|
2015-06-14 08:29:16 +08:00
|
|
|
#include "doc/blend_mode.h"
|
2015-01-19 09:05:33 +08:00
|
|
|
#include "doc/color.h"
|
2014-03-13 06:25:09 +08:00
|
|
|
#include "doc/document.h"
|
2014-12-29 07:39:11 +08:00
|
|
|
#include "doc/frame.h"
|
2020-05-19 04:58:22 +08:00
|
|
|
#include "doc/mask_boundaries.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/pixel_format.h"
|
2014-11-24 11:09:22 +08:00
|
|
|
#include "gfx/rect.h"
|
2018-07-07 13:47:42 +08:00
|
|
|
#include "obs/observable.h"
|
2018-10-19 02:29:16 +08:00
|
|
|
#include "os/color_space.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2020-06-18 05:10:26 +08:00
|
|
|
#include <atomic>
|
2019-08-02 06:14:46 +08:00
|
|
|
#include <memory>
|
2014-04-21 06:53:27 +08:00
|
|
|
#include <string>
|
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
namespace doc {
|
2013-08-06 08:20:19 +08:00
|
|
|
class Cel;
|
|
|
|
class Layer;
|
2023-07-08 05:40:06 +08:00
|
|
|
class LayerTilemap;
|
2013-08-06 08:20:19 +08:00
|
|
|
class Mask;
|
|
|
|
class Sprite;
|
2019-03-30 02:57:10 +08:00
|
|
|
class Tileset;
|
2013-08-06 08:20:19 +08:00
|
|
|
} // namespace doc
|
|
|
|
|
|
|
|
namespace gfx {
|
|
|
|
class Region;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace app {
|
2018-07-07 13:47:42 +08:00
|
|
|
|
|
|
|
class Context;
|
2018-07-07 14:07:16 +08:00
|
|
|
class DocApi;
|
2018-07-07 13:55:27 +08:00
|
|
|
class DocUndo;
|
2015-01-19 09:05:33 +08:00
|
|
|
class Transaction;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
using namespace doc;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
enum DuplicateType {
|
|
|
|
DuplicateExactCopy,
|
|
|
|
DuplicateWithFlattenLayers,
|
2024-12-16 21:10:34 +08:00
|
|
|
};
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// An application document. It is the class used to contain one file
|
|
|
|
// opened and being edited by the user (a sprite).
|
2018-07-07 22:54:44 +08:00
|
|
|
class Doc : public doc::Document,
|
|
|
|
public obs::observable<DocObserver> {
|
2018-06-14 03:00:37 +08:00
|
|
|
enum Flags {
|
|
|
|
kAssociatedToFile = 1, // This sprite is associated to a file in the file-system
|
|
|
|
kMaskVisible = 2, // The mask wasn't hidden by the user
|
|
|
|
kInhibitBackup = 4, // Inhibit the backup process
|
2019-06-08 00:17:21 +08:00
|
|
|
kFullyBackedUp = 8, // Full backup was done
|
2023-04-26 00:26:35 +08:00
|
|
|
kReadOnly = 16, // This document is read-only
|
2024-12-16 21:10:34 +08:00
|
|
|
};
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2024-12-16 21:10:34 +08:00
|
|
|
public:
|
2014-10-21 09:21:31 +08:00
|
|
|
using LockResult = base::RWLock::LockResult;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
Doc(Sprite* sprite);
|
2024-12-16 21:10:34 +08:00
|
|
|
~Doc();
|
|
|
|
|
2018-07-07 13:47:42 +08:00
|
|
|
Context* context() const { return m_ctx; }
|
|
|
|
void setContext(Context* ctx);
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2020-06-09 03:16:45 +08:00
|
|
|
// Lock/unlock API (RWLock wrapper)
|
|
|
|
bool canWriteLockFromRead() const;
|
2014-10-21 09:21:31 +08:00
|
|
|
LockResult readLock(int timeout);
|
2023-12-27 09:29:18 +08:00
|
|
|
LockResult writeLock(int timeout);
|
|
|
|
LockResult upgradeToWrite(int timeout);
|
|
|
|
void downgradeToRead(LockResult lockResult);
|
|
|
|
void unlock(LockResult lockResult);
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2020-06-18 05:10:26 +08:00
|
|
|
bool weakLock(std::atomic<base::RWLock::WeakLock>* weak_lock_flag);
|
2020-06-09 03:16:45 +08:00
|
|
|
void weakUnlock();
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
// Sets active/running transaction.
|
2019-09-12 06:12:11 +08:00
|
|
|
void setTransaction(Transaction* transaction);
|
|
|
|
Transaction* transaction() { return m_transaction; }
|
2013-08-06 08:20:19 +08:00
|
|
|
|
|
|
|
// Returns a high-level API: observable and undoable methods.
|
|
|
|
DocApi getApi(Transaction& transaction);
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Main properties
|
2023-04-26 00:26:35 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
const DocUndo* undoHistory() const { return m_undo.get(); }
|
2018-08-09 04:27:26 +08:00
|
|
|
DocUndo* undoHistory() { return m_undo.get(); }
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2019-08-02 07:20:02 +08:00
|
|
|
bool isUndoing() const;
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2015-01-19 09:05:33 +08:00
|
|
|
color_t bgColor() const;
|
2013-08-06 08:20:19 +08:00
|
|
|
color_t bgColor(Layer* layer) const;
|
|
|
|
|
2015-06-12 04:44:27 +08:00
|
|
|
os::ColorSpaceRef osColorSpace() const { return m_osColorSpace; }
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2024-02-27 00:11:26 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2020-05-19 04:58:22 +08:00
|
|
|
// Modifications with notifications
|
|
|
|
|
|
|
|
// Use this function to change the layer visibility and notify all
|
|
|
|
// DocObservers about this change (e.g. so the Editor can be
|
|
|
|
// invalidated/redrawn, MovingPixelsState can drop pixels, etc.)
|
|
|
|
void setLayerVisibilityWithNotifications(Layer* layer, const bool visible);
|
|
|
|
|
2024-12-12 01:42:14 +08:00
|
|
|
// Use this function to change the layer editable flag and
|
|
|
|
// notify all DocObservers about this change (e.g. so the Editor
|
|
|
|
// can be invalidated/redrawn, MovingPixelsState can drop pixels,
|
|
|
|
// etc.)
|
|
|
|
void setLayerEditableWithNotifications(Layer* layer, const bool editable);
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2020-05-19 04:58:22 +08:00
|
|
|
// Notifications
|
2013-08-06 08:20:19 +08:00
|
|
|
|
|
|
|
void notifyGeneralUpdate();
|
|
|
|
void notifyColorSpaceChanged();
|
|
|
|
void notifyPaletteChanged();
|
|
|
|
void notifySpritePixelsModified(Sprite* sprite, const gfx::Region& region, frame_t frame);
|
|
|
|
void notifyExposeSpritePixels(Sprite* sprite, const gfx::Region& region);
|
|
|
|
void notifyLayerMergedDown(Layer* srcLayer, Layer* targetLayer);
|
|
|
|
void notifyBeforeLayerVisibilityChange(Layer* layer, bool newState);
|
2024-02-27 00:11:26 +08:00
|
|
|
void notifyAfterLayerVisibilityChange(Layer* layer);
|
2024-12-12 01:42:14 +08:00
|
|
|
void notifyBeforeLayerEditableChange(Layer* layer, bool newState);
|
2013-08-06 08:20:19 +08:00
|
|
|
void notifyCelMoved(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame);
|
2014-12-29 07:39:11 +08:00
|
|
|
void notifyCelCopied(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame);
|
2014-11-12 22:24:26 +08:00
|
|
|
void notifySelectionChanged();
|
2019-02-16 04:14:44 +08:00
|
|
|
void notifySelectionBoundariesChanged();
|
2013-08-06 08:20:19 +08:00
|
|
|
void notifyTilesetChanged(Tileset* tileset);
|
2022-10-25 04:17:06 +08:00
|
|
|
void notifyLayerGroupCollapseChange(Layer* layer);
|
2013-08-06 08:20:19 +08:00
|
|
|
void notifyAfterAddTile(LayerTilemap* layer, frame_t frame, tile_index ti);
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
2015-08-19 21:03:29 +08:00
|
|
|
// File related properties
|
2014-08-27 20:43:42 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
bool isModified() const;
|
|
|
|
bool isAssociatedToFile() const;
|
|
|
|
void markAsSaved();
|
|
|
|
|
|
|
|
// You can use this to indicate that we've destroyed (or we cannot
|
|
|
|
// trust) the file associated with the document (e.g. when we
|
|
|
|
// cancel a Save operation in the middle). So it's impossible to
|
|
|
|
// back to the saved state using the UndoHistory.
|
2018-08-09 04:27:26 +08:00
|
|
|
void impossibleToBackToSavedState();
|
2013-08-06 08:20:19 +08:00
|
|
|
|
|
|
|
// Returns true if it does make sense to create a backup in this
|
|
|
|
// document. For example, it doesn't make sense to create a backup
|
|
|
|
// for an unmodified document.
|
|
|
|
bool needsBackup() const;
|
|
|
|
|
|
|
|
// Can be used to avoid creating a backup when the file is in a
|
|
|
|
// unusual temporary state (e.g. when the file is resized to be
|
|
|
|
// exported with other size)
|
|
|
|
bool inhibitBackup() const;
|
2018-06-14 03:00:37 +08:00
|
|
|
void setInhibitBackup(const bool inhibitBackup);
|
2013-08-06 08:20:19 +08:00
|
|
|
|
|
|
|
void markAsBackedUp();
|
|
|
|
bool isFullyBackedUp() const;
|
|
|
|
|
|
|
|
// TODO This read-only flag might be confusing because it
|
|
|
|
// indicates that the file was loaded from an incompatible
|
|
|
|
// version (future unknown feature) and it's preferable to
|
|
|
|
// mark the sprite as read-only to avoid overwriting unknown
|
2023-05-11 23:18:31 +08:00
|
|
|
// data. If in the future we want to add the possibility to
|
|
|
|
// mark a regular file as read-only, this flag'll need a new
|
2024-12-16 21:10:34 +08:00
|
|
|
// name.
|
2023-04-26 00:26:35 +08:00
|
|
|
void markAsReadOnly();
|
2013-08-06 08:20:19 +08:00
|
|
|
bool isReadOnly() const;
|
2023-04-26 00:26:35 +08:00
|
|
|
void removeReadOnlyMark();
|
2013-08-06 08:20:19 +08:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Loaded options from file
|
|
|
|
|
2017-06-16 23:18:22 +08:00
|
|
|
void setFormatOptions(const FormatOptionsPtr& format_options);
|
|
|
|
FormatOptionsPtr formatOptions() const { return m_format_options; }
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Boundaries
|
2017-06-16 23:18:22 +08:00
|
|
|
|
2019-09-06 07:03:16 +08:00
|
|
|
void destroyMaskBoundaries();
|
2013-08-06 08:20:19 +08:00
|
|
|
void generateMaskBoundaries(const Mask* mask = nullptr);
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
const MaskBoundaries& maskBoundaries() const { return m_maskBoundaries; }
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2018-07-07 13:47:42 +08:00
|
|
|
MaskBoundaries& maskBoundaries() { return m_maskBoundaries; }
|
|
|
|
|
|
|
|
bool hasMaskBoundaries() const { return !m_maskBoundaries.isEmpty(); }
|
2014-07-31 11:19:58 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2018-07-07 13:47:42 +08:00
|
|
|
// Extra Cel (it is used to draw pen preview, pixels in movement, etc.)
|
|
|
|
|
2020-06-09 03:16:45 +08:00
|
|
|
ExtraCelRef extraCel() const { return m_extraCel; }
|
2018-07-07 13:47:42 +08:00
|
|
|
void setExtraCel(const ExtraCelRef& extraCel) { m_extraCel = extraCel; }
|
2020-06-09 03:16:45 +08:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
2018-06-14 03:00:37 +08:00
|
|
|
// Mask
|
|
|
|
|
2020-06-09 03:16:45 +08:00
|
|
|
// Returns the current mask, it can be empty. The mask could be not
|
2018-06-14 03:00:37 +08:00
|
|
|
// empty but hidden to the user if the setMaskVisible(false) was
|
2020-06-09 03:16:45 +08:00
|
|
|
// used called before.
|
|
|
|
Mask* mask() const { return m_mask.get(); }
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// Sets the current mask. The new mask will be visible by default,
|
|
|
|
// so you don't need to call setMaskVisible(true).
|
2018-08-09 04:27:26 +08:00
|
|
|
void setMask(const Mask* mask);
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2019-09-12 06:12:11 +08:00
|
|
|
// Returns true only when the mask is not empty, and was not yet
|
|
|
|
// hidden using setMaskVisible (e.g. when the user "deselect the
|
|
|
|
// mask").
|
|
|
|
bool isMaskVisible() const;
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// Changes the visibility state of the mask (it is useful only if
|
2020-05-19 04:58:22 +08:00
|
|
|
// the getMask() is not empty and the user can see that the mask is
|
|
|
|
// being hidden and shown to him).
|
|
|
|
void setMaskVisible(bool visible);
|
2013-08-06 08:20:19 +08:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
2019-08-02 07:20:02 +08:00
|
|
|
// Transformation
|
2013-08-06 08:20:19 +08:00
|
|
|
|
|
|
|
Transformation getTransformation() const;
|
|
|
|
void setTransformation(const Transformation& transform);
|
2015-08-19 21:03:29 +08:00
|
|
|
void resetTransformation();
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2017-06-16 23:18:22 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2013-08-06 08:20:19 +08:00
|
|
|
// Last point used to draw straight lines using freehand tools + Shift key
|
2019-02-16 04:14:44 +08:00
|
|
|
// (EditorCustomizationDelegate::isStraightLineFromLastPoint() modifier)
|
2013-08-06 08:20:19 +08:00
|
|
|
|
|
|
|
static gfx::Point NoLastDrawingPoint();
|
|
|
|
gfx::Point lastDrawingPoint() const { return m_lastDrawingPoint; }
|
2016-07-12 01:16:01 +08:00
|
|
|
void setLastDrawingPoint(const gfx::Point& pos) { m_lastDrawingPoint = pos; }
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2017-06-16 23:18:22 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Copying
|
|
|
|
|
2018-10-19 02:29:16 +08:00
|
|
|
void copyLayerContent(const Layer* sourceLayer, Doc* destDoc, Layer* destLayer) const;
|
2020-07-08 06:06:48 +08:00
|
|
|
Doc* duplicate(DuplicateType type) const;
|
2018-10-19 02:29:16 +08:00
|
|
|
|
2018-07-07 13:47:42 +08:00
|
|
|
void close();
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2014-07-31 11:19:58 +08:00
|
|
|
protected:
|
2018-07-07 13:47:42 +08:00
|
|
|
void onFileNameChange() override;
|
|
|
|
virtual void onContextChanged();
|
2024-12-16 21:10:34 +08:00
|
|
|
|
|
|
|
private:
|
2018-07-07 13:47:42 +08:00
|
|
|
void removeFromContext();
|
2018-10-19 02:29:16 +08:00
|
|
|
void updateOSColorSpace(bool appWideSignal);
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2020-06-09 03:16:45 +08:00
|
|
|
// The document is in the collection of documents of this context.
|
2018-07-07 13:47:42 +08:00
|
|
|
Context* m_ctx;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2020-06-09 03:16:45 +08:00
|
|
|
// Internal states of the document.
|
2018-06-14 03:00:37 +08:00
|
|
|
int m_flags;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2020-06-09 03:16:45 +08:00
|
|
|
// Read-Write locks.
|
|
|
|
base::RWLock m_rwLock;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// Undo and redo information about the document.
|
2018-08-09 04:27:26 +08:00
|
|
|
std::unique_ptr<DocUndo> m_undo;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2020-06-09 03:16:45 +08:00
|
|
|
// Current transaction for this document (when this is commit(), a
|
2019-09-12 06:12:11 +08:00
|
|
|
// new undo command is added to m_undo).
|
|
|
|
Transaction* m_transaction;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// Selected mask region boundaries
|
2020-05-19 04:58:22 +08:00
|
|
|
doc::MaskBoundaries m_maskBoundaries;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// Data to save the file in the same format that it was loaded
|
2019-08-02 07:20:02 +08:00
|
|
|
FormatOptionsPtr m_format_options;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// Extra cel used to draw extra stuff (e.g. editor's pen preview, pixels in movement, etc.)
|
2015-08-19 21:03:29 +08:00
|
|
|
ExtraCelRef m_extraCel;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// Current mask.
|
2019-02-16 04:14:44 +08:00
|
|
|
std::unique_ptr<doc::Mask> m_mask;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// Current transformation.
|
2016-07-12 01:16:01 +08:00
|
|
|
Transformation m_transformation;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2017-06-16 23:18:22 +08:00
|
|
|
gfx::Point m_lastDrawingPoint;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2018-10-19 02:29:16 +08:00
|
|
|
// Last used color space to render a sprite.
|
2020-07-08 06:06:48 +08:00
|
|
|
os::ColorSpaceRef m_osColorSpace;
|
2024-12-16 21:10:34 +08:00
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
DISABLE_COPYING(Doc);
|
2013-08-06 08:20:19 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace app
|
|
|
|
|
|
|
|
#endif
|