Implement issue #129 - Return to frame/layer where action is undone.

This commit is contained in:
David Capello 2012-07-10 18:26:08 -03:00
parent 1b9048f17a
commit 5d26b90276
13 changed files with 168 additions and 71 deletions

View File

@ -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&#10;the current frame &amp; layer will be modified&#10;to focus the undid/redid change." />
</box>
</box>
<separator vertical="true" />
<box vertical="true">

View File

@ -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();

View 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

View 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 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

View File

@ -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();

View File

@ -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");
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -147,6 +147,8 @@ private:
bool m_enabledFlag;
const char* m_label;
undo::Modification m_modification;
Layer* m_startLayer;
FrameNumber m_startFrame;
};
#endif

View File

@ -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);
}

View File

@ -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

View File

@ -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));
}

View File

@ -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