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