Generate selection boundaries automatically after transactions

Now Transaction::commit() will regenerate mask boundaries
automatically if in the middle of the transaction the document
selection was modified. This is the first step to finally remove
update_screen_for_document() and any kind of manual screen
refresh.

This will be useful for scripting functions that modify the selection
too, because we wouldn't need to regenerate the selection boundaries
automatically from the script or from app.refresh() Lua function.

Related to #378
This commit is contained in:
David Capello 2019-02-15 17:14:44 -03:00
parent 668b29193a
commit 7594ebf25b
28 changed files with 101 additions and 55 deletions

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -27,6 +28,7 @@ void DeselectMask::onExecute()
Doc* doc = document(); Doc* doc = document();
m_oldMask.reset(doc->isMaskVisible() ? new Mask(*doc->mask()): nullptr); m_oldMask.reset(doc->isMaskVisible() ? new Mask(*doc->mask()): nullptr);
doc->setMaskVisible(false); doc->setMaskVisible(false);
doc->notifySelectionChanged();
} }
void DeselectMask::onUndo() void DeselectMask::onUndo()
@ -35,6 +37,7 @@ void DeselectMask::onUndo()
doc->setMask(m_oldMask.get()); doc->setMask(m_oldMask.get());
doc->setMaskVisible(true); doc->setMaskVisible(true);
doc->notifySelectionChanged();
m_oldMask.reset(); m_oldMask.reset();
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2015 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -37,8 +38,8 @@ void FlipMask::onUndo()
void FlipMask::swap() void FlipMask::swap()
{ {
Doc* document = this->document(); Doc* doc = this->document();
Mask* mask = document->mask(); Mask* mask = doc->mask();
ASSERT(mask->bitmap()); ASSERT(mask->bitmap());
if (!mask->bitmap()) if (!mask->bitmap())
@ -48,6 +49,8 @@ void FlipMask::swap()
doc::algorithm::flip_image(mask->bitmap(), doc::algorithm::flip_image(mask->bitmap(),
mask->bitmap()->bounds(), m_flipType); mask->bitmap()->bounds(), m_flipType);
mask->unfreeze(); mask->unfreeze();
doc->notifySelectionChanged();
} }
} // namespace cmd } // namespace cmd

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -32,6 +33,7 @@ void ReselectMask::onExecute()
} }
doc->setMaskVisible(true); doc->setMaskVisible(true);
doc->notifySelectionChanged();
} }
void ReselectMask::onUndo() void ReselectMask::onUndo()
@ -41,6 +43,7 @@ void ReselectMask::onUndo()
m_oldMask.reset(doc->isMaskVisible() ? new Mask(*doc->mask()): nullptr); m_oldMask.reset(doc->isMaskVisible() ? new Mask(*doc->mask()): nullptr);
doc->setMaskVisible(false); doc->setMaskVisible(false);
doc->notifySelectionChanged();
} }
size_t ReselectMask::onMemSize() const size_t ReselectMask::onMemSize() const

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -16,14 +17,14 @@
namespace app { namespace app {
namespace cmd { namespace cmd {
SetMask::SetMask(Doc* doc, Mask* newMask) SetMask::SetMask(Doc* doc, const Mask* newMask)
: WithDocument(doc) : WithDocument(doc)
, m_oldMask(doc->isMaskVisible() ? new Mask(*doc->mask()): nullptr) , m_oldMask(doc->isMaskVisible() ? new Mask(*doc->mask()): nullptr)
, m_newMask(newMask && !newMask->isEmpty() ? new Mask(*newMask): nullptr) , m_newMask(newMask && !newMask->isEmpty() ? new Mask(*newMask): nullptr)
{ {
} }
void SetMask::setNewMask(Mask* newMask) void SetMask::setNewMask(const Mask* newMask)
{ {
m_newMask.reset(newMask ? new Mask(*newMask): nullptr); m_newMask.reset(newMask ? new Mask(*newMask): nullptr);
setMask(m_newMask.get()); setMask(m_newMask.get());
@ -46,7 +47,7 @@ size_t SetMask::onMemSize() const
(m_newMask ? m_newMask->getMemSize(): 0); (m_newMask ? m_newMask->getMemSize(): 0);
} }
void SetMask::setMask(Mask* mask) void SetMask::setMask(const Mask* mask)
{ {
Doc* doc = document(); Doc* doc = document();
@ -59,6 +60,8 @@ void SetMask::setMask(Mask* mask)
doc->setMask(&empty); doc->setMask(&empty);
doc->setMaskVisible(false); doc->setMaskVisible(false);
} }
doc->notifySelectionChanged();
} }
} // namespace cmd } // namespace cmd

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -25,10 +26,10 @@ namespace cmd {
class SetMask : public Cmd class SetMask : public Cmd
, public WithDocument { , public WithDocument {
public: public:
SetMask(Doc* doc, Mask* newMask); SetMask(Doc* doc, const Mask* newMask);
// Used to change the new mask used in the onRedo() // Used to change the new mask used in the onRedo()
void setNewMask(Mask* newMask); void setNewMask(const Mask* newMask);
protected: protected:
void onExecute() override; void onExecute() override;
@ -36,7 +37,7 @@ namespace cmd {
size_t onMemSize() const override; size_t onMemSize() const override;
private: private:
void setMask(Mask* mask); void setMask(const Mask* mask);
std::unique_ptr<Mask> m_oldMask; std::unique_ptr<Mask> m_oldMask;
std::unique_ptr<Mask> m_newMask; std::unique_ptr<Mask> m_newMask;

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2015 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -38,6 +39,8 @@ void SetMaskPosition::setMaskPosition(const gfx::Point& pos)
Doc* doc = document(); Doc* doc = document();
doc->mask()->setOrigin(pos.x, pos.y); doc->mask()->setOrigin(pos.x, pos.y);
doc->resetTransformation(); doc->resetTransformation();
doc->notifySelectionChanged();
} }
} // namespace cmd } // namespace cmd

View File

@ -352,8 +352,6 @@ void CanvasSizeCommand::onExecute(Context* context)
MID(1, y2-y1, DOC_SPRITE_MAX_HEIGHT))); MID(1, y2-y1, DOC_SPRITE_MAX_HEIGHT)));
tx.commit(); tx.commit();
doc->generateMaskBoundaries();
#ifdef ENABLE_UI #ifdef ENABLE_UI
if (context->isUIAvailable()) if (context->isUIAvailable())
update_screen_for_document(doc); update_screen_for_document(doc);

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -74,7 +75,6 @@ void CropSpriteCommand::onExecute(Context* context)
document->getApi(tx).cropSprite(sprite, bounds); document->getApi(tx).cropSprite(sprite, bounds);
tx.commit(); tx.commit();
} }
document->generateMaskBoundaries();
#ifdef ENABLE_UI #ifdef ENABLE_UI
if (context->isUIAvailable()) if (context->isUIAvailable())
@ -112,7 +112,6 @@ void AutocropSpriteCommand::onExecute(Context* context)
document->getApi(tx).trimSprite(sprite); document->getApi(tx).trimSprite(sprite);
tx.commit(); tx.commit();
} }
document->generateMaskBoundaries();
#ifdef ENABLE_UI #ifdef ENABLE_UI
if (context->isUIAvailable()) if (context->isUIAvailable())

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -47,7 +48,6 @@ void DeselectMaskCommand::onExecute(Context* context)
tx(new cmd::DeselectMask(document)); tx(new cmd::DeselectMask(document));
tx.commit(); tx.commit();
} }
document->generateMaskBoundaries();
update_screen_for_document(document); update_screen_for_document(document);
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -222,8 +223,6 @@ void FlipCommand::onExecute(Context* context)
(m_flipType == doc::algorithm::FlipVertical ? (m_flipType == doc::algorithm::FlipVertical ?
sprite->height() - mask->bounds().y2(): sprite->height() - mask->bounds().y2():
mask->bounds().y)))); mask->bounds().y))));
document->generateMaskBoundaries();
} }
tx.commit(); tx.commit();

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -96,7 +97,6 @@ void InvertMaskCommand::onExecute(Context* context)
tx(new cmd::SetMask(document, mask.get())); tx(new cmd::SetMask(document, mask.get()));
tx.commit(); tx.commit();
document->generateMaskBoundaries();
update_screen_for_document(document); update_screen_for_document(document);
} }
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -80,7 +81,6 @@ void LoadMaskCommand::onExecute(Context* context)
tx(new cmd::SetMask(document, mask.get())); tx(new cmd::SetMask(document, mask.get()));
tx.commit(); tx.commit();
document->generateMaskBoundaries();
update_screen_for_document(document); update_screen_for_document(document);
} }
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -50,10 +51,8 @@ void MaskAllCommand::onExecute(Context* context)
Tx tx(writer.context(), "Select All", DoesntModifyDocument); Tx tx(writer.context(), "Select All", DoesntModifyDocument);
tx(new cmd::SetMask(document, &newMask)); tx(new cmd::SetMask(document, &newMask));
tx.commit();
document->resetTransformation(); document->resetTransformation();
document->generateMaskBoundaries(); tx.commit();
if (Preferences::instance().selection.autoShowSelectionEdges()) { if (Preferences::instance().selection.autoShowSelectionEdges()) {
DocumentPreferences& docPref = Preferences::instance().document(document); DocumentPreferences& docPref = Preferences::instance().document(document);

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -189,9 +189,11 @@ void MaskByColorCommand::onExecute(Context* context)
set_config_int("MaskColor", "Tolerance", m_sliderTolerance->getValue()); set_config_int("MaskColor", "Tolerance", m_sliderTolerance->getValue());
set_config_bool("MaskColor", "Preview", m_checkPreview->isSelected()); set_config_bool("MaskColor", "Preview", m_checkPreview->isSelected());
} }
else {
document->generateMaskBoundaries();
}
// Update boundaries and editors. // Update boundaries and editors.
document->generateMaskBoundaries();
update_screen_for_document(document); update_screen_for_document(document);
// Save window configuration. // Save window configuration.

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -83,10 +84,8 @@ void MaskContentCommand::onExecute(Context* context)
Tx tx(writer.context(), "Select Content", DoesntModifyDocument); Tx tx(writer.context(), "Select Content", DoesntModifyDocument);
tx(new cmd::SetMask(document, &newMask)); tx(new cmd::SetMask(document, &newMask));
tx.commit();
document->resetTransformation(); document->resetTransformation();
document->generateMaskBoundaries(); tx.commit();
} }
// Select marquee tool // Select marquee tool

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2015-2018 David Capello // Copyright (C) 2015-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -143,7 +144,6 @@ void ModifySelectionCommand::onExecute(Context* context)
tx(new cmd::SetMask(document, mask.get())); tx(new cmd::SetMask(document, mask.get()));
tx.commit(); tx.commit();
document->generateMaskBoundaries();
update_screen_for_document(document); update_screen_for_document(document);
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -88,7 +89,6 @@ void MoveMaskCommand::onExecute(Context* context)
tx.commit(); tx.commit();
} }
document->generateMaskBoundaries();
update_screen_for_document(document); update_screen_for_document(document);
break; break;
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -53,7 +54,6 @@ void ReselectMaskCommand::onExecute(Context* context)
tx.commit(); tx.commit();
} }
document->generateMaskBoundaries();
update_screen_for_document(document); update_screen_for_document(document);
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -243,7 +244,6 @@ void RotateCommand::onExecute(Context* context)
job.startJob(); job.startJob();
job.waitJob(); job.waitJob();
} }
reader.document()->generateMaskBoundaries();
update_screen_for_document(reader.document()); update_screen_for_document(reader.document());
} }
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2015-2018 David Capello // Copyright (C) 2015-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -109,7 +109,6 @@ void SelectTileCommand::onExecute(Context* ctx)
tx(new cmd::SetMask(doc, mask.get())); tx(new cmd::SetMask(doc, mask.get()));
tx.commit(); tx.commit();
doc->generateMaskBoundaries();
update_screen_for_document(doc); update_screen_for_document(doc);
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -180,6 +180,12 @@ void Doc::notifySelectionChanged()
notify_observers<DocEvent&>(&DocObserver::onSelectionChanged, ev); notify_observers<DocEvent&>(&DocObserver::onSelectionChanged, ev);
} }
void Doc::notifySelectionBoundariesChanged()
{
DocEvent ev(this);
notify_observers<DocEvent&>(&DocObserver::onSelectionBoundariesChanged, ev);
}
bool Doc::isModified() const bool Doc::isModified() const
{ {
return !m_undo->isSavedState(); return !m_undo->isSavedState();
@ -252,8 +258,7 @@ void Doc::generateMaskBoundaries(const Mask* mask)
mask->bounds().y); mask->bounds().y);
} }
// TODO move this to the exact place where selection is modified. notifySelectionBoundariesChanged();
notifySelectionChanged();
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -261,7 +266,9 @@ void Doc::generateMaskBoundaries(const Mask* mask)
void Doc::setMask(const Mask* mask) void Doc::setMask(const Mask* mask)
{ {
m_mask.reset(new Mask(*mask)); ASSERT(mask);
m_mask->copyFrom(mask);
m_flags |= kMaskVisible; m_flags |= kMaskVisible;
resetTransformation(); resetTransformation();
@ -271,7 +278,6 @@ bool Doc::isMaskVisible() const
{ {
return return
(m_flags & kMaskVisible) && // The mask was not hidden by the user explicitly (m_flags & kMaskVisible) && // The mask was not hidden by the user explicitly
m_mask && // The mask does exist
!m_mask->isEmpty(); // The mask is not empty !m_mask->isEmpty(); // The mask is not empty
} }
@ -298,10 +304,7 @@ void Doc::setTransformation(const Transformation& transform)
void Doc::resetTransformation() void Doc::resetTransformation()
{ {
if (m_mask) m_transformation = Transformation(gfx::RectF(m_mask->bounds()));
m_transformation = Transformation(gfx::RectF(m_mask->bounds()));
else
m_transformation = Transformation();
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -96,6 +96,7 @@ namespace app {
void notifyCelMoved(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame); void notifyCelMoved(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame);
void notifyCelCopied(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame); void notifyCelCopied(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame);
void notifySelectionChanged(); void notifySelectionChanged();
void notifySelectionBoundariesChanged();
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// File related properties // File related properties
@ -211,7 +212,7 @@ namespace app {
ExtraCelRef m_extraCel; ExtraCelRef m_extraCel;
// Current mask. // Current mask.
std::unique_ptr<Mask> m_mask; std::unique_ptr<doc::Mask> m_mask;
// Current transformation. // Current transformation.
Transformation m_transformation; Transformation m_transformation;

View File

@ -68,6 +68,7 @@ namespace app {
// The selection has changed. // The selection has changed.
virtual void onSelectionChanged(DocEvent& ev) { } virtual void onSelectionChanged(DocEvent& ev) { }
virtual void onSelectionBoundariesChanged(DocEvent& ev) { }
// Called to destroy the observable. (Here you could call "delete this".) // Called to destroy the observable. (Here you could call "delete this".)
virtual void dispose() { } virtual void dispose() { }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -16,6 +16,7 @@
#include "app/doc.h" #include "app/doc.h"
#include "app/doc_undo.h" #include "app/doc_undo.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "ui/system.h"
#define TX_TRACE(...) #define TX_TRACE(...)
@ -25,17 +26,22 @@ using namespace doc;
Transaction::Transaction(Context* ctx, const std::string& label, Modification modification) Transaction::Transaction(Context* ctx, const std::string& label, Modification modification)
: m_ctx(ctx) : m_ctx(ctx)
, m_cmds(NULL) , m_doc(nullptr)
, m_undo(nullptr)
, m_cmds(nullptr)
, m_changes(Changes::kNone)
{ {
TX_TRACE("TX: Start <%s> (%s)\n", TX_TRACE("TX: Start <%s> (%s)\n",
label.c_str(), label.c_str(),
modification == ModifyDocument ? "modifies document": modification == ModifyDocument ? "modifies document":
"doesn't modify document"); "doesn't modify document");
Doc* doc = m_ctx->activeDocument(); m_doc = m_ctx->activeDocument();
if (!doc) if (!m_doc)
throw std::runtime_error("No active document to execute a transaction"); throw std::runtime_error("No active document to execute a transaction");
m_undo = doc->undoHistory();
m_doc->add_observer(this);
m_undo = m_doc->undoHistory();
m_cmds = new CmdTransaction(label, m_cmds = new CmdTransaction(label,
modification == Modification::ModifyDocument, modification == Modification::ModifyDocument,
@ -60,6 +66,8 @@ Transaction::~Transaction()
// TODO logging error // TODO logging error
} }
m_doc->remove_observer(this);
} }
// Used to set the document range after all the transaction is // Used to set the document range after all the transaction is
@ -73,12 +81,17 @@ void Transaction::setNewDocRange(const DocRange& range)
void Transaction::commit() void Transaction::commit()
{ {
ui::assert_ui_thread();
ASSERT(m_cmds); ASSERT(m_cmds);
TX_TRACE("TX: Commit <%s>\n", m_cmds->label().c_str()); TX_TRACE("TX: Commit <%s>\n", m_cmds->label().c_str());
m_cmds->commit(); m_cmds->commit();
m_undo->add(m_cmds); m_undo->add(m_cmds);
m_cmds = NULL; m_cmds = nullptr;
// Process changes
if (int(m_changes) & int(Changes::kSelection))
m_doc->generateMaskBoundaries();
} }
void Transaction::rollback() void Transaction::rollback()
@ -89,7 +102,7 @@ void Transaction::rollback()
m_cmds->undo(); m_cmds->undo();
delete m_cmds; delete m_cmds;
m_cmds = NULL; m_cmds = nullptr;
} }
void Transaction::execute(Cmd* cmd) void Transaction::execute(Cmd* cmd)
@ -112,4 +125,9 @@ void Transaction::execute(Cmd* cmd)
} }
} }
void Transaction::onSelectionChanged(DocEvent& ev)
{
m_changes = Changes(int(m_changes) | int(Changes::kSelection));
}
} // namespace app } // namespace app

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -8,6 +9,8 @@
#define APP_TRANSACTION_H_INCLUDED #define APP_TRANSACTION_H_INCLUDED
#pragma once #pragma once
#include "app/doc_observer.h"
#include <string> #include <string>
namespace app { namespace app {
@ -38,7 +41,7 @@ namespace app {
// transaction.commit(); // transaction.commit();
// } // }
// //
class Transaction { class Transaction : public DocObserver {
public: public:
// Starts a undoable sequence of operations in a transaction that // Starts a undoable sequence of operations in a transaction that
// can be committed or rollbacked. All the operations will be // can be committed or rollbacked. All the operations will be
@ -67,11 +70,20 @@ namespace app {
void execute(Cmd* cmd); void execute(Cmd* cmd);
private: private:
// List of changes during the execution of this transaction
enum class Changes { kNone = 0,
kSelection = 1 };
void rollback(); void rollback();
// DocObserver impl
void onSelectionChanged(DocEvent& ev) override;
Context* m_ctx; Context* m_ctx;
Doc* m_doc;
DocUndo* m_undo; DocUndo* m_undo;
CmdTransaction* m_cmds; CmdTransaction* m_cmds;
Changes m_changes;
}; };
} // namespace app } // namespace app

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -463,7 +464,6 @@ public:
} }
// Selection ink // Selection ink
else if (getInk()->isSelection()) { else if (getInk()->isSelection()) {
m_document->generateMaskBoundaries();
redraw = true; redraw = true;
// Show selection edges // Show selection edges

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -1784,7 +1784,7 @@ void Timeline::onRemoveFrame(DocEvent& ev)
invalidate(); invalidate();
} }
void Timeline::onSelectionChanged(DocEvent& ev) void Timeline::onSelectionBoundariesChanged(DocEvent& ev)
{ {
if (m_rangeLocks == 0) if (m_rangeLocks == 0)
clearAndInvalidateRange(); clearAndInvalidateRange();

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -144,7 +144,7 @@ namespace app {
void onAfterRemoveLayer(DocEvent& ev) override; void onAfterRemoveLayer(DocEvent& ev) override;
void onAddFrame(DocEvent& ev) override; void onAddFrame(DocEvent& ev) override;
void onRemoveFrame(DocEvent& ev) override; void onRemoveFrame(DocEvent& ev) override;
void onSelectionChanged(DocEvent& ev) override; void onSelectionBoundariesChanged(DocEvent& ev) override;
void onLayerNameChange(DocEvent& ev) override; void onLayerNameChange(DocEvent& ev) override;
void onAddFrameTag(DocEvent& ev) override; void onAddFrameTag(DocEvent& ev) override;
void onRemoveFrameTag(DocEvent& ev) override; void onRemoveFrameTag(DocEvent& ev) override;