2015-02-12 23:16:25 +08:00
|
|
|
// Aseprite
|
2018-10-19 02:29:16 +08:00
|
|
|
// Copyright (C) 2018 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.
|
2011-03-23 08:11:25 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2011-03-23 08:11:25 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
#include "app/doc.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2015-05-19 03:53:25 +08:00
|
|
|
#include "app/app.h"
|
2015-01-19 09:05:33 +08:00
|
|
|
#include "app/color_target.h"
|
|
|
|
#include "app/color_utils.h"
|
|
|
|
#include "app/context.h"
|
2018-07-07 13:47:42 +08:00
|
|
|
#include "app/context.h"
|
2018-07-07 22:54:44 +08:00
|
|
|
#include "app/doc_api.h"
|
2018-07-07 13:47:42 +08:00
|
|
|
#include "app/doc_event.h"
|
|
|
|
#include "app/doc_observer.h"
|
2018-07-07 13:55:27 +08:00
|
|
|
#include "app/doc_undo.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/file/format_options.h"
|
|
|
|
#include "app/flatten.h"
|
2015-05-19 03:53:25 +08:00
|
|
|
#include "app/pref/preferences.h"
|
2015-07-28 00:08:25 +08:00
|
|
|
#include "app/util/create_cel_copy.h"
|
2011-03-23 08:11:25 +08:00
|
|
|
#include "base/memory.h"
|
2014-11-13 10:20:27 +08:00
|
|
|
#include "doc/cel.h"
|
2015-03-17 05:21:08 +08:00
|
|
|
#include "doc/frame_tag.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/layer.h"
|
|
|
|
#include "doc/mask.h"
|
2015-06-12 04:44:27 +08:00
|
|
|
#include "doc/mask_boundaries.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/palette.h"
|
|
|
|
#include "doc/sprite.h"
|
2018-10-19 02:29:16 +08:00
|
|
|
#include "os/display.h"
|
|
|
|
#include "os/system.h"
|
2018-10-26 04:29:32 +08:00
|
|
|
#include "ui/system.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2017-06-16 23:18:22 +08:00
|
|
|
#include <limits>
|
2015-01-22 20:49:01 +08:00
|
|
|
#include <map>
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
namespace app {
|
|
|
|
|
|
|
|
using namespace base;
|
2014-10-21 09:21:31 +08:00
|
|
|
using namespace doc;
|
2011-03-23 08:11:25 +08:00
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
Doc::Doc(Sprite* sprite)
|
2018-07-07 13:47:42 +08:00
|
|
|
: m_ctx(nullptr)
|
|
|
|
, m_flags(kMaskVisible)
|
2018-07-07 13:55:27 +08:00
|
|
|
, m_undo(new DocUndo)
|
2018-06-14 03:00:37 +08:00
|
|
|
// Information about the file format used to load/save this document
|
|
|
|
, m_format_options(nullptr)
|
2011-03-25 05:03:38 +08:00
|
|
|
// Mask
|
|
|
|
, m_mask(new Mask())
|
2018-07-07 22:54:44 +08:00
|
|
|
, m_lastDrawingPoint(Doc::NoLastDrawingPoint())
|
2011-03-23 08:11:25 +08:00
|
|
|
{
|
2014-07-29 11:53:24 +08:00
|
|
|
setFilename("Sprite");
|
2014-03-13 06:25:09 +08:00
|
|
|
|
2014-07-29 11:53:24 +08:00
|
|
|
if (sprite)
|
|
|
|
sprites().add(sprite);
|
2018-10-19 02:29:16 +08:00
|
|
|
|
|
|
|
updateOSColorSpace(false);
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
Doc::~Doc()
|
2011-03-23 08:11:25 +08:00
|
|
|
{
|
2018-07-07 13:47:42 +08:00
|
|
|
removeFromContext();
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::setContext(Context* ctx)
|
2018-07-07 13:47:42 +08:00
|
|
|
{
|
|
|
|
if (ctx == m_ctx)
|
|
|
|
return;
|
|
|
|
|
|
|
|
removeFromContext();
|
|
|
|
|
|
|
|
m_ctx = ctx;
|
|
|
|
if (ctx)
|
|
|
|
ctx->documents().add(this);
|
|
|
|
|
|
|
|
onContextChanged();
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
DocApi Doc::getApi(Transaction& transaction)
|
2013-03-12 07:29:45 +08:00
|
|
|
{
|
2018-07-07 14:07:16 +08:00
|
|
|
return DocApi(this, transaction);
|
2013-03-12 07:29:45 +08:00
|
|
|
}
|
|
|
|
|
2015-01-19 09:05:33 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Main properties
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
color_t Doc::bgColor() const
|
2015-01-19 09:05:33 +08:00
|
|
|
{
|
|
|
|
return color_utils::color_for_target(
|
2015-05-19 03:53:25 +08:00
|
|
|
Preferences::instance().colorBar.bgColor(),
|
2015-01-19 09:05:33 +08:00
|
|
|
ColorTarget(ColorTarget::BackgroundLayer,
|
2015-05-19 03:53:25 +08:00
|
|
|
sprite()->pixelFormat(),
|
|
|
|
sprite()->transparentColor()));
|
2015-01-19 09:05:33 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
color_t Doc::bgColor(Layer* layer) const
|
2015-01-19 09:05:33 +08:00
|
|
|
{
|
|
|
|
if (layer->isBackground())
|
|
|
|
return color_utils::color_for_layer(
|
2015-05-19 03:53:25 +08:00
|
|
|
Preferences::instance().colorBar.bgColor(),
|
2015-01-19 09:05:33 +08:00
|
|
|
layer);
|
|
|
|
else
|
|
|
|
return layer->sprite()->transparentColor();
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Notifications
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::notifyGeneralUpdate()
|
2013-01-21 05:40:37 +08:00
|
|
|
{
|
2018-07-07 13:47:42 +08:00
|
|
|
DocEvent ev(this);
|
|
|
|
notify_observers<DocEvent&>(&DocObserver::onGeneralUpdate, ev);
|
2013-01-21 05:40:37 +08:00
|
|
|
}
|
|
|
|
|
2018-10-19 02:29:16 +08:00
|
|
|
void Doc::notifyColorSpaceChanged()
|
|
|
|
{
|
|
|
|
updateOSColorSpace(true);
|
|
|
|
|
|
|
|
DocEvent ev(this);
|
|
|
|
ev.sprite(sprite());
|
|
|
|
notify_observers<DocEvent&>(&DocObserver::onColorSpaceChanged, ev);
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::notifySpritePixelsModified(Sprite* sprite, const gfx::Region& region, frame_t frame)
|
2013-01-21 05:40:37 +08:00
|
|
|
{
|
2018-07-07 13:47:42 +08:00
|
|
|
DocEvent ev(this);
|
2013-03-12 07:29:45 +08:00
|
|
|
ev.sprite(sprite);
|
|
|
|
ev.region(region);
|
2015-08-13 04:32:17 +08:00
|
|
|
ev.frame(frame);
|
2018-07-07 13:47:42 +08:00
|
|
|
notify_observers<DocEvent&>(&DocObserver::onSpritePixelsModified, ev);
|
2013-01-21 05:40:37 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::notifyExposeSpritePixels(Sprite* sprite, const gfx::Region& region)
|
2014-12-09 01:57:56 +08:00
|
|
|
{
|
2018-07-07 13:47:42 +08:00
|
|
|
DocEvent ev(this);
|
2014-12-09 01:57:56 +08:00
|
|
|
ev.sprite(sprite);
|
|
|
|
ev.region(region);
|
2018-07-07 13:47:42 +08:00
|
|
|
notify_observers<DocEvent&>(&DocObserver::onExposeSpritePixels, ev);
|
2014-12-09 01:57:56 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::notifyLayerMergedDown(Layer* srcLayer, Layer* targetLayer)
|
2013-03-12 07:29:45 +08:00
|
|
|
{
|
2018-07-07 13:47:42 +08:00
|
|
|
DocEvent ev(this);
|
2014-07-30 12:28:15 +08:00
|
|
|
ev.sprite(srcLayer->sprite());
|
2013-03-12 07:29:45 +08:00
|
|
|
ev.layer(srcLayer);
|
|
|
|
ev.targetLayer(targetLayer);
|
2018-07-07 13:47:42 +08:00
|
|
|
notify_observers<DocEvent&>(&DocObserver::onLayerMergedDown, ev);
|
2013-03-12 07:29:45 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::notifyCelMoved(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame)
|
2013-03-12 07:29:45 +08:00
|
|
|
{
|
2018-07-07 13:47:42 +08:00
|
|
|
DocEvent ev(this);
|
2014-07-30 12:28:15 +08:00
|
|
|
ev.sprite(fromLayer->sprite());
|
2013-03-12 07:29:45 +08:00
|
|
|
ev.layer(fromLayer);
|
|
|
|
ev.frame(fromFrame);
|
|
|
|
ev.targetLayer(toLayer);
|
|
|
|
ev.targetFrame(toFrame);
|
2018-07-07 13:47:42 +08:00
|
|
|
notify_observers<DocEvent&>(&DocObserver::onCelMoved, ev);
|
2013-03-12 07:29:45 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::notifyCelCopied(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame)
|
2013-03-12 07:29:45 +08:00
|
|
|
{
|
2018-07-07 13:47:42 +08:00
|
|
|
DocEvent ev(this);
|
2014-07-30 12:28:15 +08:00
|
|
|
ev.sprite(fromLayer->sprite());
|
2013-03-12 07:29:45 +08:00
|
|
|
ev.layer(fromLayer);
|
|
|
|
ev.frame(fromFrame);
|
|
|
|
ev.targetLayer(toLayer);
|
|
|
|
ev.targetFrame(toFrame);
|
2018-07-07 13:47:42 +08:00
|
|
|
notify_observers<DocEvent&>(&DocObserver::onCelCopied, ev);
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::notifySelectionChanged()
|
2014-11-12 22:24:26 +08:00
|
|
|
{
|
2018-07-07 13:47:42 +08:00
|
|
|
DocEvent ev(this);
|
|
|
|
notify_observers<DocEvent&>(&DocObserver::onSelectionChanged, ev);
|
2014-11-12 22:24:26 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
bool Doc::isModified() const
|
2011-03-23 08:11:25 +08:00
|
|
|
{
|
2012-07-08 12:25:26 +08:00
|
|
|
return !m_undo->isSavedState();
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
bool Doc::isAssociatedToFile() const
|
2011-03-23 08:11:25 +08:00
|
|
|
{
|
2018-06-14 03:00:37 +08:00
|
|
|
return (m_flags & kAssociatedToFile) == kAssociatedToFile;
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::markAsSaved()
|
2011-03-23 08:11:25 +08:00
|
|
|
{
|
2012-07-08 12:25:26 +08:00
|
|
|
m_undo->markSavedState();
|
2018-06-14 03:00:37 +08:00
|
|
|
m_flags |= kAssociatedToFile;
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::impossibleToBackToSavedState()
|
2014-05-03 04:04:55 +08:00
|
|
|
{
|
|
|
|
m_undo->impossibleToBackToSavedState();
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
bool Doc::needsBackup() const
|
2015-04-09 20:02:23 +08:00
|
|
|
{
|
|
|
|
// If the undo history isn't empty, the user has modified the
|
2016-08-01 07:36:18 +08:00
|
|
|
// document, so we need to backup those changes.
|
2015-04-09 20:02:23 +08:00
|
|
|
return m_undo->canUndo() || m_undo->canRedo();
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
bool Doc::inhibitBackup() const
|
2018-06-14 03:00:37 +08:00
|
|
|
{
|
|
|
|
return (m_flags & kInhibitBackup) == kInhibitBackup;
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::setInhibitBackup(const bool inhibitBackup)
|
2018-06-14 03:00:37 +08:00
|
|
|
{
|
|
|
|
if (inhibitBackup)
|
|
|
|
m_flags |= kInhibitBackup;
|
|
|
|
else
|
|
|
|
m_flags &= ~kInhibitBackup;
|
|
|
|
}
|
|
|
|
|
2011-03-23 08:11:25 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Loaded options from file
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::setFormatOptions(const base::SharedPtr<FormatOptions>& format_options)
|
2011-03-23 08:11:25 +08:00
|
|
|
{
|
|
|
|
m_format_options = format_options;
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Boundaries
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::generateMaskBoundaries(const Mask* mask)
|
2011-03-23 08:11:25 +08:00
|
|
|
{
|
2015-06-12 04:44:27 +08:00
|
|
|
m_maskBoundaries.reset();
|
2011-03-23 08:11:25 +08:00
|
|
|
|
2011-03-23 11:06:43 +08:00
|
|
|
// No mask specified? Use the current one in the document
|
|
|
|
if (!mask) {
|
2012-01-06 06:45:03 +08:00
|
|
|
if (!isMaskVisible()) // The mask is hidden
|
|
|
|
return; // Done, without boundaries
|
2011-03-23 11:06:43 +08:00
|
|
|
else
|
2014-07-30 12:28:15 +08:00
|
|
|
mask = this->mask(); // Use the document mask
|
2011-03-23 11:06:43 +08:00
|
|
|
}
|
|
|
|
|
2015-06-12 04:44:27 +08:00
|
|
|
ASSERT(mask);
|
2011-03-23 08:11:25 +08:00
|
|
|
|
2012-01-09 09:34:36 +08:00
|
|
|
if (!mask->isEmpty()) {
|
2015-06-12 04:44:27 +08:00
|
|
|
m_maskBoundaries.reset(new MaskBoundaries(mask->bitmap()));
|
|
|
|
m_maskBoundaries->offset(mask->bounds().x,
|
|
|
|
mask->bounds().y);
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
2014-11-12 22:24:26 +08:00
|
|
|
|
|
|
|
// TODO move this to the exact place where selection is modified.
|
|
|
|
notifySelectionChanged();
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
|
2011-03-23 11:06:43 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Mask
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::setMask(const Mask* mask)
|
2011-03-23 11:06:43 +08:00
|
|
|
{
|
2012-01-09 09:34:36 +08:00
|
|
|
m_mask.reset(new Mask(*mask));
|
2018-06-14 03:00:37 +08:00
|
|
|
m_flags |= kMaskVisible;
|
2012-01-02 10:08:25 +08:00
|
|
|
|
|
|
|
resetTransformation();
|
2011-03-23 11:06:43 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
bool Doc::isMaskVisible() const
|
2011-03-23 11:06:43 +08:00
|
|
|
{
|
|
|
|
return
|
2018-06-14 03:00:37 +08:00
|
|
|
(m_flags & kMaskVisible) && // The mask was not hidden by the user explicitly
|
2012-01-06 06:45:03 +08:00
|
|
|
m_mask && // The mask does exist
|
2012-01-09 09:34:36 +08:00
|
|
|
!m_mask->isEmpty(); // The mask is not empty
|
2011-03-23 11:06:43 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::setMaskVisible(bool visible)
|
2011-03-23 11:06:43 +08:00
|
|
|
{
|
2018-06-14 03:00:37 +08:00
|
|
|
if (visible)
|
|
|
|
m_flags |= kMaskVisible;
|
|
|
|
else
|
|
|
|
m_flags &= ~kMaskVisible;
|
2011-03-23 11:06:43 +08:00
|
|
|
}
|
|
|
|
|
2011-03-23 08:11:25 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2012-01-02 10:08:25 +08:00
|
|
|
// Transformation
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
Transformation Doc::getTransformation() const
|
2012-01-02 10:08:25 +08:00
|
|
|
{
|
|
|
|
return m_transformation;
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::setTransformation(const Transformation& transform)
|
2012-01-02 10:08:25 +08:00
|
|
|
{
|
|
|
|
m_transformation = transform;
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::resetTransformation()
|
2012-01-02 10:08:25 +08:00
|
|
|
{
|
|
|
|
if (m_mask)
|
2016-07-12 01:16:01 +08:00
|
|
|
m_transformation = Transformation(gfx::RectF(m_mask->bounds()));
|
2012-01-02 10:08:25 +08:00
|
|
|
else
|
2016-07-12 01:16:01 +08:00
|
|
|
m_transformation = Transformation();
|
2012-01-02 10:08:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
2011-03-28 09:08:19 +08:00
|
|
|
// Copying
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::copyLayerContent(const Layer* sourceLayer0, Doc* destDoc, Layer* destLayer0) const
|
2011-03-28 09:08:19 +08:00
|
|
|
{
|
2015-03-17 05:05:19 +08:00
|
|
|
LayerFlags dstFlags = sourceLayer0->flags();
|
|
|
|
|
|
|
|
// Remove the "background" flag if the destDoc already has a background layer.
|
|
|
|
if (((int)dstFlags & (int)LayerFlags::Background) == (int)LayerFlags::Background &&
|
|
|
|
(destDoc->sprite()->backgroundLayer())) {
|
2015-03-17 21:07:12 +08:00
|
|
|
dstFlags = (LayerFlags)((int)dstFlags & ~(int)(LayerFlags::BackgroundLayerFlags));
|
2015-03-17 05:05:19 +08:00
|
|
|
}
|
|
|
|
|
2015-12-12 02:11:34 +08:00
|
|
|
// Copy the layer name/flags/user data
|
2014-07-30 12:28:15 +08:00
|
|
|
destLayer0->setName(sourceLayer0->name());
|
2015-03-17 05:05:19 +08:00
|
|
|
destLayer0->setFlags(dstFlags);
|
2015-12-12 02:11:34 +08:00
|
|
|
destLayer0->setUserData(sourceLayer0->userData());
|
2011-03-28 09:08:19 +08:00
|
|
|
|
2013-01-11 23:43:25 +08:00
|
|
|
if (sourceLayer0->isImage() && destLayer0->isImage()) {
|
2011-03-29 10:31:16 +08:00
|
|
|
const LayerImage* sourceLayer = static_cast<const LayerImage*>(sourceLayer0);
|
|
|
|
LayerImage* destLayer = static_cast<LayerImage*>(destLayer0);
|
2011-03-28 09:08:19 +08:00
|
|
|
|
2015-06-15 09:59:23 +08:00
|
|
|
// Copy blend mode and opacity
|
|
|
|
destLayer->setBlendMode(sourceLayer->blendMode());
|
|
|
|
destLayer->setOpacity(sourceLayer->opacity());
|
|
|
|
|
|
|
|
// Copy cels
|
2011-03-29 10:31:16 +08:00
|
|
|
CelConstIterator it = sourceLayer->getCelBegin();
|
|
|
|
CelConstIterator end = sourceLayer->getCelEnd();
|
2011-03-28 09:08:19 +08:00
|
|
|
|
2015-02-09 22:40:43 +08:00
|
|
|
std::map<ObjectId, Cel*> linked;
|
2015-01-22 20:49:01 +08:00
|
|
|
|
2011-03-29 10:31:16 +08:00
|
|
|
for (; it != end; ++it) {
|
|
|
|
const Cel* sourceCel = *it;
|
2014-08-08 21:33:45 +08:00
|
|
|
if (sourceCel->frame() > destLayer->sprite()->lastFrame())
|
|
|
|
break;
|
|
|
|
|
2018-08-09 04:27:26 +08:00
|
|
|
std::unique_ptr<Cel> newCel(nullptr);
|
2011-03-29 10:31:16 +08:00
|
|
|
|
2015-02-09 22:40:43 +08:00
|
|
|
auto it = linked.find(sourceCel->data()->id());
|
|
|
|
if (it != linked.end()) {
|
|
|
|
newCel.reset(Cel::createLink(it->second));
|
|
|
|
newCel->setFrame(sourceCel->frame());
|
2015-01-22 20:49:01 +08:00
|
|
|
}
|
|
|
|
else {
|
2015-07-28 00:08:25 +08:00
|
|
|
newCel.reset(create_cel_copy(sourceCel,
|
|
|
|
destLayer->sprite(),
|
2016-11-08 02:09:52 +08:00
|
|
|
destLayer,
|
2015-07-28 00:08:25 +08:00
|
|
|
sourceCel->frame()));
|
2015-02-09 22:40:43 +08:00
|
|
|
linked.insert(std::make_pair(sourceCel->data()->id(), newCel.get()));
|
2015-01-22 20:49:01 +08:00
|
|
|
}
|
2011-03-28 09:08:19 +08:00
|
|
|
|
2018-08-09 04:27:26 +08:00
|
|
|
destLayer->addCel(newCel.get());
|
2011-03-29 10:31:16 +08:00
|
|
|
newCel.release();
|
|
|
|
}
|
|
|
|
}
|
2016-06-08 06:38:56 +08:00
|
|
|
else if (sourceLayer0->isGroup() && destLayer0->isGroup()) {
|
|
|
|
const LayerGroup* sourceLayer = static_cast<const LayerGroup*>(sourceLayer0);
|
|
|
|
LayerGroup* destLayer = static_cast<LayerGroup*>(destLayer0);
|
2011-03-29 10:31:16 +08:00
|
|
|
|
2016-06-09 03:46:15 +08:00
|
|
|
for (Layer* sourceChild : sourceLayer->layers()) {
|
2018-08-09 04:27:26 +08:00
|
|
|
std::unique_ptr<Layer> destChild(nullptr);
|
2011-03-29 10:31:16 +08:00
|
|
|
|
2013-01-11 23:43:25 +08:00
|
|
|
if (sourceChild->isImage()) {
|
2014-07-30 12:28:15 +08:00
|
|
|
destChild.reset(new LayerImage(destLayer->sprite()));
|
2018-08-09 04:27:26 +08:00
|
|
|
copyLayerContent(sourceChild, destDoc, destChild.get());
|
2011-03-29 10:31:16 +08:00
|
|
|
}
|
2016-06-08 06:38:56 +08:00
|
|
|
else if (sourceChild->isGroup()) {
|
|
|
|
destChild.reset(new LayerGroup(destLayer->sprite()));
|
2018-08-09 04:27:26 +08:00
|
|
|
copyLayerContent(sourceChild, destDoc, destChild.get());
|
2011-03-29 10:31:16 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-01-06 06:45:03 +08:00
|
|
|
ASSERT(false);
|
2011-03-29 10:31:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(destChild != NULL);
|
|
|
|
|
|
|
|
// Add the new layer in the sprite.
|
2014-04-10 08:56:06 +08:00
|
|
|
|
|
|
|
Layer* newLayer = destChild.release();
|
2016-06-08 06:38:56 +08:00
|
|
|
Layer* afterThis = destLayer->lastLayer();
|
2014-04-10 08:56:06 +08:00
|
|
|
|
|
|
|
destLayer->addLayer(newLayer);
|
|
|
|
destChild.release();
|
|
|
|
|
|
|
|
destLayer->stackLayer(newLayer, afterThis);
|
2011-03-29 10:31:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ASSERT(false && "Trying to copy two incompatible layers");
|
2011-03-28 09:08:19 +08:00
|
|
|
}
|
|
|
|
}
|
2011-03-23 08:11:25 +08:00
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
Doc* Doc::duplicate(DuplicateType type) const
|
2011-03-23 08:11:25 +08:00
|
|
|
{
|
2014-07-29 11:53:24 +08:00
|
|
|
const Sprite* sourceSprite = sprite();
|
2018-08-09 04:27:26 +08:00
|
|
|
std::unique_ptr<Sprite> spriteCopyPtr(new Sprite(
|
2018-10-26 02:23:01 +08:00
|
|
|
sourceSprite->spec(),
|
2014-12-29 07:39:11 +08:00
|
|
|
sourceSprite->palette(frame_t(0))->size()));
|
2014-07-29 11:53:24 +08:00
|
|
|
|
2018-08-09 04:27:26 +08:00
|
|
|
std::unique_ptr<Doc> documentCopy(new Doc(spriteCopyPtr.get()));
|
2011-03-29 10:31:16 +08:00
|
|
|
Sprite* spriteCopy = spriteCopyPtr.release();
|
2011-03-23 08:11:25 +08:00
|
|
|
|
2014-07-30 12:28:15 +08:00
|
|
|
spriteCopy->setTotalFrames(sourceSprite->totalFrames());
|
2011-03-23 08:11:25 +08:00
|
|
|
|
2011-03-28 10:21:22 +08:00
|
|
|
// Copy frames duration
|
2014-12-29 07:39:11 +08:00
|
|
|
for (frame_t i(0); i < sourceSprite->totalFrames(); ++i)
|
|
|
|
spriteCopy->setFrameDuration(i, sourceSprite->frameDuration(i));
|
2011-03-23 08:11:25 +08:00
|
|
|
|
2015-03-17 05:21:08 +08:00
|
|
|
// Copy frame tags
|
|
|
|
for (const FrameTag* tag : sourceSprite->frameTags())
|
|
|
|
spriteCopy->frameTags().add(new FrameTag(*tag));
|
|
|
|
|
2011-03-23 08:11:25 +08:00
|
|
|
// Copy color palettes
|
|
|
|
{
|
2011-03-28 10:21:22 +08:00
|
|
|
PalettesList::const_iterator it = sourceSprite->getPalettes().begin();
|
|
|
|
PalettesList::const_iterator end = sourceSprite->getPalettes().end();
|
2011-03-23 08:11:25 +08:00
|
|
|
for (; it != end; ++it) {
|
2011-03-28 10:21:22 +08:00
|
|
|
const Palette* pal = *it;
|
|
|
|
spriteCopy->setPalette(pal, true);
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-28 10:21:22 +08:00
|
|
|
switch (type) {
|
|
|
|
|
|
|
|
case DuplicateExactCopy:
|
2016-06-08 06:38:56 +08:00
|
|
|
// Copy the layer group
|
2018-08-09 04:27:26 +08:00
|
|
|
copyLayerContent(sourceSprite->root(),
|
|
|
|
documentCopy.get(),
|
|
|
|
spriteCopy->root());
|
2014-08-09 23:45:04 +08:00
|
|
|
|
2015-03-17 05:05:19 +08:00
|
|
|
ASSERT((spriteCopy->backgroundLayer() && sourceSprite->backgroundLayer()) ||
|
|
|
|
(!spriteCopy->backgroundLayer() && !sourceSprite->backgroundLayer()));
|
2011-03-28 10:21:22 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DuplicateWithFlattenLayers:
|
|
|
|
{
|
2012-01-06 06:45:03 +08:00
|
|
|
// Flatten layers
|
2016-06-08 06:38:56 +08:00
|
|
|
ASSERT(sourceSprite->root() != NULL);
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2012-06-09 08:34:53 +08:00
|
|
|
LayerImage* flatLayer = create_flatten_layer_copy
|
2012-01-06 06:45:03 +08:00
|
|
|
(spriteCopy,
|
2016-06-08 06:38:56 +08:00
|
|
|
sourceSprite->root(),
|
2014-07-30 12:28:15 +08:00
|
|
|
gfx::Rect(0, 0, sourceSprite->width(), sourceSprite->height()),
|
2014-12-29 07:39:11 +08:00
|
|
|
frame_t(0), sourceSprite->lastFrame());
|
2012-01-06 06:45:03 +08:00
|
|
|
|
|
|
|
// Add and select the new flat layer
|
2016-06-08 06:38:56 +08:00
|
|
|
spriteCopy->root()->addLayer(flatLayer);
|
2012-01-06 06:45:03 +08:00
|
|
|
|
|
|
|
// Configure the layer as background only if the original
|
|
|
|
// sprite has a background layer.
|
2014-07-30 12:28:15 +08:00
|
|
|
if (sourceSprite->backgroundLayer() != NULL)
|
2012-01-06 06:45:03 +08:00
|
|
|
flatLayer->configureAsBackground();
|
2011-03-28 10:21:22 +08:00
|
|
|
}
|
|
|
|
break;
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
|
2018-06-14 03:00:37 +08:00
|
|
|
// Copy only some flags
|
|
|
|
documentCopy->m_flags = (m_flags & kMaskVisible);
|
2018-07-04 23:35:15 +08:00
|
|
|
documentCopy->setFilename(filename());
|
2014-07-30 12:28:15 +08:00
|
|
|
documentCopy->setMask(mask());
|
2011-03-28 10:21:22 +08:00
|
|
|
documentCopy->generateMaskBoundaries();
|
2011-03-23 08:11:25 +08:00
|
|
|
|
2011-03-28 10:21:22 +08:00
|
|
|
return documentCopy.release();
|
2011-03-23 08:11:25 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::close()
|
2018-07-07 13:47:42 +08:00
|
|
|
{
|
|
|
|
removeFromContext();
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::onFileNameChange()
|
2018-07-07 13:47:42 +08:00
|
|
|
{
|
|
|
|
notify_observers(&DocObserver::onFileNameChanged, this);
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::onContextChanged()
|
2014-07-31 11:19:58 +08:00
|
|
|
{
|
|
|
|
m_undo->setContext(context());
|
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void Doc::removeFromContext()
|
2018-07-07 13:47:42 +08:00
|
|
|
{
|
|
|
|
if (m_ctx) {
|
|
|
|
m_ctx->documents().remove(this);
|
|
|
|
m_ctx = nullptr;
|
|
|
|
|
|
|
|
onContextChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-19 02:29:16 +08:00
|
|
|
void Doc::updateOSColorSpace(bool appWideSignal)
|
|
|
|
{
|
|
|
|
auto system = os::instance();
|
|
|
|
if (system) {
|
|
|
|
m_osColorSpace = system->createColorSpace(sprite()->colorSpace());
|
|
|
|
if (!m_osColorSpace && system->defaultDisplay())
|
|
|
|
m_osColorSpace = system->defaultDisplay()->colorSpace();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (appWideSignal &&
|
|
|
|
context() &&
|
|
|
|
context()->activeDocument() == this) {
|
|
|
|
App::instance()->ColorSpaceChange();
|
|
|
|
}
|
2018-10-26 04:29:32 +08:00
|
|
|
|
|
|
|
if (ui::is_ui_thread()) {
|
|
|
|
// As the color space has changed, we might need to upate the
|
|
|
|
// current palette (because the color space conversion might be
|
|
|
|
// came from a cmd::ConvertColorProfile, so the palette might be
|
|
|
|
// changed). This might generate a PaletteChange() signal.
|
|
|
|
app_update_current_palette();
|
|
|
|
}
|
2018-10-19 02:29:16 +08:00
|
|
|
}
|
|
|
|
|
2017-06-16 23:18:22 +08:00
|
|
|
// static
|
2018-07-07 22:54:44 +08:00
|
|
|
gfx::Point Doc::NoLastDrawingPoint()
|
2017-06-16 23:18:22 +08:00
|
|
|
{
|
|
|
|
return gfx::Point(std::numeric_limits<int>::min(),
|
|
|
|
std::numeric_limits<int>::min());
|
|
|
|
}
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
} // namespace app
|