mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-29 09:23:32 +00:00
Implement issue #129 - Return to frame/layer where action is undone.
This commit is contained in:
parent
1b9048f17a
commit
5d26b90276
@ -32,6 +32,10 @@
|
||||
<label text="MB" />
|
||||
</box>
|
||||
|
||||
<box horizontal="true">
|
||||
<check id="undo_goto_modified" text="Go to modified frame/layer" tooltip="When it's enabled each time you undo/redo the current frame & layer will be modified to focus the undid/redid change." />
|
||||
</box>
|
||||
|
||||
</box>
|
||||
<separator vertical="true" />
|
||||
<box vertical="true">
|
||||
|
@ -80,6 +80,7 @@ void OptionsCommand::onExecute(Context* context)
|
||||
Widget* checked_bg_color2_box = app::find_widget<Widget>(window, "checked_bg_color2_box");
|
||||
Button* checked_bg_reset = app::find_widget<Button>(window, "checked_bg_reset");
|
||||
Widget* undo_size_limit = app::find_widget<Widget>(window, "undo_size_limit");
|
||||
Widget* undo_goto_modified = app::find_widget<Widget>(window, "undo_goto_modified");
|
||||
Widget* button_ok = app::find_widget<Widget>(window, "button_ok");
|
||||
|
||||
// Cursor color
|
||||
@ -131,6 +132,10 @@ void OptionsCommand::onExecute(Context* context)
|
||||
// Undo limit
|
||||
undo_size_limit->setTextf("%d", get_config_int("Options", "UndoSizeLimit", 8));
|
||||
|
||||
// Goto modified frame/layer on undo/redo
|
||||
if (get_config_bool("Options", "UndoGotoModified", true))
|
||||
undo_goto_modified->setSelected(true);
|
||||
|
||||
// Show the window and wait the user to close it
|
||||
window->openWindowInForeground();
|
||||
|
||||
@ -153,6 +158,7 @@ void OptionsCommand::onExecute(Context* context)
|
||||
undo_size_limit_value = undo_size_limit->getTextInt();
|
||||
undo_size_limit_value = MID(1, undo_size_limit_value, 9999);
|
||||
set_config_int("Options", "UndoSizeLimit", undo_size_limit_value);
|
||||
set_config_bool("Options", "UndoGotoModified", undo_goto_modified->isSelected());
|
||||
|
||||
// Save configuration
|
||||
flush_config_file();
|
||||
|
@ -19,11 +19,15 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "base/thread.h"
|
||||
#include "commands/command.h"
|
||||
#include "document_undo.h"
|
||||
#include "document_wrappers.h"
|
||||
#include "ini_file.h"
|
||||
#include "modules/editors.h"
|
||||
#include "modules/gui.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "widgets/editor/editor.h"
|
||||
#include "widgets/status_bar.h"
|
||||
|
||||
class RedoCommand : public Command
|
||||
@ -55,12 +59,28 @@ bool RedoCommand::onEnabled(Context* context)
|
||||
void RedoCommand::onExecute(Context* context)
|
||||
{
|
||||
ActiveDocumentWriter document(context);
|
||||
DocumentUndo* undo = document->getUndo();
|
||||
Sprite* sprite = document->getSprite();
|
||||
|
||||
if (get_config_bool("Options", "UndoGotoModified", true)) {
|
||||
if (undo->getNextRedoFrame() != sprite->getCurrentFrame() ||
|
||||
undo->getNextRedoLayer() != sprite->getCurrentLayer()) {
|
||||
sprite->setCurrentFrame(undo->getNextRedoFrame());
|
||||
sprite->setCurrentLayer(undo->getNextRedoLayer());
|
||||
|
||||
current_editor->drawSpriteSafe(0, 0, sprite->getWidth(), sprite->getHeight());
|
||||
update_screen_for_document(document);
|
||||
gui_feedback();
|
||||
|
||||
base::this_thread::sleep_for(0.01);
|
||||
}
|
||||
}
|
||||
|
||||
StatusBar::instance()
|
||||
->showTip(1000, "Redid %s",
|
||||
document->getUndo()->getNextRedoLabel());
|
||||
undo->getNextRedoLabel());
|
||||
|
||||
document->getUndo()->doRedo();
|
||||
undo->doRedo();
|
||||
document->generateMaskBoundaries();
|
||||
document->destroyExtraCel(); // Regenerate extras
|
||||
|
||||
|
@ -19,11 +19,15 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "base/thread.h"
|
||||
#include "commands/command.h"
|
||||
#include "document_undo.h"
|
||||
#include "document_wrappers.h"
|
||||
#include "ini_file.h"
|
||||
#include "modules/editors.h"
|
||||
#include "modules/gui.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "widgets/editor/editor.h"
|
||||
#include "widgets/status_bar.h"
|
||||
|
||||
class UndoCommand : public Command
|
||||
@ -55,12 +59,28 @@ bool UndoCommand::onEnabled(Context* context)
|
||||
void UndoCommand::onExecute(Context* context)
|
||||
{
|
||||
ActiveDocumentWriter document(context);
|
||||
DocumentUndo* undo = document->getUndo();
|
||||
Sprite* sprite = document->getSprite();
|
||||
|
||||
if (get_config_bool("Options", "UndoGotoModified", true)) {
|
||||
if (undo->getNextUndoFrame() != sprite->getCurrentFrame() ||
|
||||
undo->getNextUndoLayer() != sprite->getCurrentLayer()) {
|
||||
sprite->setCurrentFrame(undo->getNextUndoFrame());
|
||||
sprite->setCurrentLayer(undo->getNextUndoLayer());
|
||||
|
||||
current_editor->drawSpriteSafe(0, 0, sprite->getWidth(), sprite->getHeight());
|
||||
update_screen_for_document(document);
|
||||
gui_feedback();
|
||||
|
||||
base::this_thread::sleep_for(0.01);
|
||||
}
|
||||
}
|
||||
|
||||
StatusBar::instance()
|
||||
->showTip(1000, "Undid %s",
|
||||
document->getUndo()->getNextUndoLabel());
|
||||
undo->getNextUndoLabel());
|
||||
|
||||
document->getUndo()->doUndo();
|
||||
undo->doUndo();
|
||||
document->generateMaskBoundaries();
|
||||
document->destroyExtraCel(); // Regenerate extras
|
||||
|
||||
|
@ -708,35 +708,11 @@ bool AnimationEditor::onProcessMessage(Message* msg)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Undo.
|
||||
if (command && strcmp(command->short_name(), CommandId::Undo) == 0) {
|
||||
const DocumentReader document(const_cast<Document*>(m_document));
|
||||
const DocumentUndo* undo = document->getUndo();
|
||||
|
||||
if (undo->canUndo()) {
|
||||
DocumentWriter document_writer(document);
|
||||
DocumentUndo* undo_writer = document_writer->getUndo();
|
||||
|
||||
undo_writer->doUndo();
|
||||
|
||||
destroy_thumbnails();
|
||||
regenerateLayers();
|
||||
showCurrentCel();
|
||||
invalidate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Redo.
|
||||
if (command && strcmp(command->short_name(), CommandId::Redo) == 0) {
|
||||
const DocumentReader document(const_cast<Document*>(m_document));
|
||||
const DocumentUndo* undo = document->getUndo();
|
||||
|
||||
if (undo->canRedo()) {
|
||||
DocumentWriter document_writer(document);
|
||||
DocumentUndo* undo_writer = document_writer->getUndo();
|
||||
|
||||
undo_writer->doRedo();
|
||||
// Undo or redo.
|
||||
if (command && (strcmp(command->short_name(), CommandId::Undo) == 0 ||
|
||||
strcmp(command->short_name(), CommandId::Redo) == 0)) {
|
||||
if (command->isEnabled(UIContext::instance())) {
|
||||
UIContext::instance()->executeCommand(command, params);
|
||||
|
||||
destroy_thumbnails();
|
||||
regenerateLayers();
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include <allegro/config.h> // TODO remove this when get_config_int() is removed from here
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
DocumentUndo::DocumentUndo()
|
||||
: m_objects(new ObjectsContainerImpl)
|
||||
@ -92,36 +93,54 @@ size_t DocumentUndo::getUndoSizeLimit()
|
||||
|
||||
const char* DocumentUndo::getNextUndoLabel() const
|
||||
{
|
||||
undo::Undoer* undoer = m_undoHistory->getNextUndoer();
|
||||
if (undoer) {
|
||||
if (undoers::CloseGroup* closeGroup = dynamic_cast<undoers::CloseGroup*>(undoer)) {
|
||||
return closeGroup->getLabel();
|
||||
}
|
||||
else {
|
||||
assert(false && "There are some action without a CloseGroup");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(false && "There are some action without label");
|
||||
return "";
|
||||
}
|
||||
return getNextUndoGroup()->getLabel();
|
||||
}
|
||||
|
||||
const char* DocumentUndo::getNextRedoLabel() const
|
||||
{
|
||||
undo::Undoer* undoer = m_undoHistory->getNextRedoer();
|
||||
if (undoer) {
|
||||
if (undoers::CloseGroup* closeGroup = dynamic_cast<undoers::CloseGroup*>(undoer)) {
|
||||
return closeGroup->getLabel();
|
||||
}
|
||||
else {
|
||||
assert(false && "There are some action without a CloseGroup");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(false && "There are some action without label");
|
||||
return "";
|
||||
}
|
||||
return getNextRedoGroup()->getLabel();
|
||||
}
|
||||
|
||||
Layer* DocumentUndo::getNextUndoLayer() const
|
||||
{
|
||||
return getNextUndoGroup()->getLayer(m_objects);
|
||||
}
|
||||
|
||||
Layer* DocumentUndo::getNextRedoLayer() const
|
||||
{
|
||||
return getNextRedoGroup()->getLayer(m_objects);
|
||||
}
|
||||
|
||||
FrameNumber DocumentUndo::getNextUndoFrame() const
|
||||
{
|
||||
return getNextUndoGroup()->getFrame();
|
||||
}
|
||||
|
||||
FrameNumber DocumentUndo::getNextRedoFrame() const
|
||||
{
|
||||
return getNextRedoGroup()->getFrame();
|
||||
}
|
||||
|
||||
undoers::CloseGroup* DocumentUndo::getNextUndoGroup() const
|
||||
{
|
||||
undo::Undoer* undoer = m_undoHistory->getNextUndoer();
|
||||
if (!undoer)
|
||||
throw std::logic_error("There are some action without label");
|
||||
|
||||
if (undoers::CloseGroup* closeGroup = dynamic_cast<undoers::CloseGroup*>(undoer))
|
||||
return closeGroup;
|
||||
else
|
||||
throw std::logic_error("There are some action without a CloseGroup");
|
||||
}
|
||||
|
||||
undoers::CloseGroup* DocumentUndo::getNextRedoGroup() const
|
||||
{
|
||||
undo::Undoer* undoer = m_undoHistory->getNextRedoer();
|
||||
if (!undoer)
|
||||
throw std::logic_error("There are some action without label");
|
||||
|
||||
if (undoers::CloseGroup* closeGroup = dynamic_cast<undoers::CloseGroup*>(undoer))
|
||||
return closeGroup;
|
||||
else
|
||||
throw std::logic_error("There are some action without a CloseGroup");
|
||||
}
|
||||
|
@ -22,14 +22,21 @@
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/disable_copying.h"
|
||||
#include "base/unique_ptr.h"
|
||||
#include "raster/frame_number.h"
|
||||
#include "undo/undo_config_provider.h"
|
||||
#include "undo/undo_history.h"
|
||||
|
||||
class Layer;
|
||||
|
||||
namespace undo {
|
||||
class ObjectsContainer;
|
||||
class Undoer;
|
||||
}
|
||||
|
||||
namespace undoers {
|
||||
class CloseGroup;
|
||||
}
|
||||
|
||||
class DocumentUndo : public undo::UndoConfigProvider
|
||||
{
|
||||
public:
|
||||
@ -58,9 +65,18 @@ public:
|
||||
const char* getNextUndoLabel() const;
|
||||
const char* getNextRedoLabel() const;
|
||||
|
||||
Layer* getNextUndoLayer() const;
|
||||
Layer* getNextRedoLayer() const;
|
||||
|
||||
FrameNumber getNextUndoFrame() const;
|
||||
FrameNumber getNextRedoFrame() const;
|
||||
|
||||
private:
|
||||
size_t getUndoSizeLimit() OVERRIDE;
|
||||
|
||||
undoers::CloseGroup* getNextUndoGroup() const;
|
||||
undoers::CloseGroup* getNextRedoGroup() const;
|
||||
|
||||
// Collection of objects used by UndoHistory to reference deleted
|
||||
// objects that are re-created by an Undoer. The container keeps an
|
||||
// ID that is saved in the serialization process, and loaded in the
|
||||
|
@ -78,7 +78,11 @@ UndoTransaction::UndoTransaction(Document* document, const char* label, undo::Mo
|
||||
m_enabledFlag = m_undo->isEnabled();
|
||||
|
||||
if (isEnabled())
|
||||
m_undo->pushUndoer(new undoers::OpenGroup(m_label, m_modification));
|
||||
m_undo->pushUndoer(new undoers::OpenGroup(getObjects(),
|
||||
m_label,
|
||||
m_modification,
|
||||
m_startLayer = m_sprite->getCurrentLayer(),
|
||||
m_startFrame = m_sprite->getCurrentFrame()));
|
||||
}
|
||||
|
||||
UndoTransaction::~UndoTransaction()
|
||||
@ -106,7 +110,11 @@ void UndoTransaction::closeUndoGroup()
|
||||
|
||||
if (isEnabled()) {
|
||||
// Close the undo information.
|
||||
m_undo->pushUndoer(new undoers::CloseGroup(m_label, m_modification));
|
||||
m_undo->pushUndoer(new undoers::CloseGroup(getObjects(),
|
||||
m_label,
|
||||
m_modification,
|
||||
m_startLayer,
|
||||
m_startFrame));
|
||||
m_closed = true;
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +147,8 @@ private:
|
||||
bool m_enabledFlag;
|
||||
const char* m_label;
|
||||
undo::Modification m_modification;
|
||||
Layer* m_startLayer;
|
||||
FrameNumber m_startFrame;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -20,15 +20,18 @@
|
||||
|
||||
#include "undoers/close_group.h"
|
||||
|
||||
#include "undo/objects_container.h"
|
||||
#include "undo/undoers_collector.h"
|
||||
#include "undoers/open_group.h"
|
||||
|
||||
using namespace undo;
|
||||
using namespace undoers;
|
||||
|
||||
CloseGroup::CloseGroup(const char* label, undo::Modification modification)
|
||||
CloseGroup::CloseGroup(undo::ObjectsContainer* objects, const char* label, undo::Modification modification, Layer* layer, FrameNumber frame)
|
||||
: m_label(label)
|
||||
, m_modification(modification)
|
||||
, m_activeLayerId(objects->addObject(layer))
|
||||
, m_activeFrame(frame)
|
||||
{
|
||||
}
|
||||
|
||||
@ -39,5 +42,11 @@ void CloseGroup::dispose()
|
||||
|
||||
void CloseGroup::revert(ObjectsContainer* objects, UndoersCollector* redoers)
|
||||
{
|
||||
redoers->pushUndoer(new OpenGroup(m_label, m_modification));
|
||||
redoers->pushUndoer(new OpenGroup(objects, m_label, m_modification,
|
||||
getLayer(objects), m_activeFrame));
|
||||
}
|
||||
|
||||
Layer* CloseGroup::getLayer(undo::ObjectsContainer* objects)
|
||||
{
|
||||
return objects->getObjectT<Layer>(m_activeLayerId);
|
||||
}
|
||||
|
@ -20,14 +20,18 @@
|
||||
#define UNDOERS_CLOSE_GROUP_H_INCLUDED
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "raster/frame_number.h"
|
||||
#include "undo/object_id.h"
|
||||
#include "undo/undoer.h"
|
||||
|
||||
class Layer;
|
||||
|
||||
namespace undoers {
|
||||
|
||||
class CloseGroup : public undo::Undoer
|
||||
{
|
||||
public:
|
||||
CloseGroup(const char* label, undo::Modification modification);
|
||||
CloseGroup(undo::ObjectsContainer* objects, const char* label, undo::Modification modification, Layer* layer, FrameNumber frame);
|
||||
void dispose() OVERRIDE;
|
||||
size_t getMemSize() const OVERRIDE { return sizeof(*this); }
|
||||
undo::Modification getModification() const { return m_modification; }
|
||||
@ -36,10 +40,14 @@ public:
|
||||
void revert(undo::ObjectsContainer* objects, undo::UndoersCollector* redoers) OVERRIDE;
|
||||
|
||||
const char* getLabel() { return m_label; }
|
||||
FrameNumber getFrame() { return m_activeFrame; }
|
||||
Layer* getLayer(undo::ObjectsContainer* objects);
|
||||
|
||||
private:
|
||||
const char* m_label;
|
||||
undo::Modification m_modification;
|
||||
undo::ObjectId m_activeLayerId;
|
||||
FrameNumber m_activeFrame;
|
||||
};
|
||||
|
||||
} // namespace undoers
|
||||
|
@ -20,15 +20,18 @@
|
||||
|
||||
#include "undoers/open_group.h"
|
||||
|
||||
#include "undo/objects_container.h"
|
||||
#include "undo/undoers_collector.h"
|
||||
#include "undoers/close_group.h"
|
||||
|
||||
using namespace undo;
|
||||
using namespace undoers;
|
||||
|
||||
OpenGroup::OpenGroup(const char* label, undo::Modification modification)
|
||||
OpenGroup::OpenGroup(undo::ObjectsContainer* objects, const char* label, undo::Modification modification, Layer* layer, FrameNumber frame)
|
||||
: m_label(label)
|
||||
, m_modification(modification)
|
||||
, m_activeLayerId(objects->addObject(layer))
|
||||
, m_activeFrame(frame)
|
||||
{
|
||||
}
|
||||
|
||||
@ -39,5 +42,7 @@ void OpenGroup::dispose()
|
||||
|
||||
void OpenGroup::revert(ObjectsContainer* objects, UndoersCollector* redoers)
|
||||
{
|
||||
redoers->pushUndoer(new CloseGroup(m_label, m_modification));
|
||||
Layer* layer = objects->getObjectT<Layer>(m_activeLayerId);
|
||||
|
||||
redoers->pushUndoer(new CloseGroup(objects, m_label, m_modification, layer, m_activeFrame));
|
||||
}
|
||||
|
@ -20,14 +20,18 @@
|
||||
#define UNDOERS_OPEN_GROUP_H_INCLUDED
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "raster/frame_number.h"
|
||||
#include "undo/object_id.h"
|
||||
#include "undo/undoer.h"
|
||||
|
||||
class Layer;
|
||||
|
||||
namespace undoers {
|
||||
|
||||
class OpenGroup : public undo::Undoer
|
||||
{
|
||||
public:
|
||||
OpenGroup(const char* label, undo::Modification modification);
|
||||
OpenGroup(undo::ObjectsContainer* objects, const char* label, undo::Modification modification, Layer* layer, FrameNumber frame);
|
||||
void dispose() OVERRIDE;
|
||||
size_t getMemSize() const OVERRIDE { return sizeof(*this); }
|
||||
undo::Modification getModification() const { return m_modification; }
|
||||
@ -35,11 +39,11 @@ public:
|
||||
bool isCloseGroup() const OVERRIDE { return false; }
|
||||
void revert(undo::ObjectsContainer* objects, undo::UndoersCollector* redoers) OVERRIDE;
|
||||
|
||||
const char* getLabel() { return m_label; }
|
||||
|
||||
private:
|
||||
const char* m_label;
|
||||
undo::Modification m_modification;
|
||||
undo::ObjectId m_activeLayerId;
|
||||
FrameNumber m_activeFrame;
|
||||
};
|
||||
|
||||
} // namespace undoers
|
||||
|
Loading…
Reference in New Issue
Block a user