aseprite/src/app/cmd_transaction.cpp
David Capello 38c0400927 Fix Doc::isModified() when we are in a similar UndoState to the saved one
If the current UndoState doesn't modify the "saved state" (e.g. there
is a sequence of undoes/redoes that doesn't modify the saved version
of the sprite compared to the current one), we can indicate that we
are in the saved state anyway (!Doc::isModified).
2022-11-02 09:58:18 -03:00

160 lines
3.5 KiB
C++

// Aseprite
// Copyright (C) 2019-2022 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/cmd_transaction.h"
#include "app/context.h"
#include "app/site.h"
#ifdef ENABLE_UI
#include "app/app.h"
#include "app/ui/timeline/timeline.h"
#endif
namespace app {
CmdTransaction::CmdTransaction(const std::string& label,
bool changeSavedState)
: m_ranges(nullptr)
, m_label(label)
, m_changeSavedState(changeSavedState)
{
}
CmdTransaction* CmdTransaction::moveToEmptyCopy()
{
CmdTransaction* copy = new CmdTransaction(m_label,
m_changeSavedState);
copy->m_spritePositionBefore = m_spritePositionBefore;
copy->m_spritePositionAfter = m_spritePositionAfter;
if (m_ranges) {
copy->m_ranges.reset(new Ranges);
copy->m_ranges->m_before = std::move(m_ranges->m_before);
copy->m_ranges->m_after = std::move(m_ranges->m_after);
}
return copy;
}
void CmdTransaction::setNewDocRange(const DocRange& range)
{
#ifdef ENABLE_UI
if (m_ranges)
range.write(m_ranges->m_after);
#endif
}
void CmdTransaction::updateSpritePositionAfter()
{
m_spritePositionAfter = calcSpritePosition();
// We cannot capture m_ranges->m_after from the Timeline here
// because the document range in the Timeline is updated after the
// commit/command (on Timeline::onAfterCommandExecution).
//
// So m_ranges->m_after is captured explicitly in
// setNewDocRange().
}
std::istream* CmdTransaction::documentRangeBeforeExecute() const
{
if (m_ranges && m_ranges->m_before.tellp() > 0) {
m_ranges->m_before.seekg(0);
return &m_ranges->m_before;
}
else
return nullptr;
}
std::istream* CmdTransaction::documentRangeAfterExecute() const
{
if (m_ranges && m_ranges->m_after.tellp() > 0) {
m_ranges->m_after.seekg(0);
return &m_ranges->m_after;
}
else
return nullptr;
}
void CmdTransaction::onExecute()
{
// Save the current site and doc range
m_spritePositionBefore = calcSpritePosition();
#ifdef ENABLE_UI
if (isDocRangeEnabled()) {
m_ranges.reset(new Ranges);
calcDocRange().write(m_ranges->m_before);
}
#endif
// Execute the sequence of "cmds"
CmdSequence::onExecute();
}
void CmdTransaction::onUndo()
{
CmdSequence::onUndo();
}
void CmdTransaction::onRedo()
{
CmdSequence::onRedo();
}
std::string CmdTransaction::onLabel() const
{
return m_label;
}
size_t CmdTransaction::onMemSize() const
{
size_t size = CmdSequence::onMemSize();
if (m_ranges) {
size += (m_ranges->m_before.tellp() +
m_ranges->m_after.tellp());
}
return size;
}
SpritePosition CmdTransaction::calcSpritePosition() const
{
Site site = context()->activeSite();
return SpritePosition(site.layer(), site.frame());
}
bool CmdTransaction::isDocRangeEnabled() const
{
#ifdef ENABLE_UI
if (App::instance()) {
Timeline* timeline = App::instance()->timeline();
if (timeline && timeline->range().enabled())
return true;
}
#endif
return false;
}
DocRange CmdTransaction::calcDocRange() const
{
#ifdef ENABLE_UI
// TODO We cannot use Context::activeSite() because it losts
// important information about the DocRange() (type and
// flags).
if (App::instance()) {
Timeline* timeline = App::instance()->timeline();
if (timeline)
return timeline->range();
}
#endif
return DocRange();
}
} // namespace app