implement action redo
This commit is contained in:
@@ -709,6 +709,7 @@
|
||||
</button-custom>
|
||||
</node>
|
||||
<button id="btn-undo" width="50" height="100%" margin="0 5 0 0" text="Undo"/>
|
||||
<button id="btn-redo" width="50" height="100%" margin="0 5 0 0" text="Redo"/>
|
||||
<!--
|
||||
<button-custom id="btn-layer" width="50" height="100%" margin="0 5 0 0" thickness="1" border-color="0 0 0 1" pad="6" align="center" justify="center">
|
||||
<icon width="100%" height="100%" icon="disk"/>
|
||||
|
||||
@@ -7,6 +7,7 @@ ActionManager ActionManager::I;
|
||||
|
||||
void ActionManager::add(Action *action)
|
||||
{
|
||||
I.m_redos = std::stack<std::unique_ptr<Action>>();
|
||||
I.m_actions.emplace(action);
|
||||
I.m_memory += action->memory();
|
||||
//LOG("History: %.2f KB", I.m_memory / 1024.f);
|
||||
@@ -15,6 +16,11 @@ void ActionManager::add(Action *action)
|
||||
|
||||
void ActionManager::undo()
|
||||
{
|
||||
if (I.m_actions.empty())
|
||||
return;
|
||||
|
||||
I.m_redos.emplace(I.m_actions.top()->get_redo());
|
||||
|
||||
I.m_actions.top()->undo();
|
||||
I.m_memory -= I.m_actions.top()->memory();
|
||||
I.m_actions.pop();
|
||||
@@ -22,6 +28,20 @@ void ActionManager::undo()
|
||||
App::I.update_memory_usage(I.m_memory);
|
||||
}
|
||||
|
||||
void ActionManager::redo()
|
||||
{
|
||||
if (I.m_redos.empty())
|
||||
return;
|
||||
|
||||
I.m_actions.emplace(I.m_redos.top()->get_redo());
|
||||
I.m_memory += I.m_actions.top()->memory();
|
||||
|
||||
I.m_redos.top()->undo();
|
||||
I.m_redos.pop();
|
||||
//LOG("History: %.2f KB", I.m_memory / 1024.f);
|
||||
App::I.update_memory_usage(I.m_memory);
|
||||
}
|
||||
|
||||
void ActionManager::clear()
|
||||
{
|
||||
while (!I.m_actions.empty())
|
||||
|
||||
@@ -5,6 +5,7 @@ class Action
|
||||
public:
|
||||
virtual void run() = 0;
|
||||
virtual void undo() = 0;
|
||||
virtual Action* get_redo() = 0;
|
||||
virtual size_t memory() = 0;
|
||||
virtual ~Action(){};
|
||||
};
|
||||
@@ -14,9 +15,11 @@ class ActionManager
|
||||
public:
|
||||
static ActionManager I;
|
||||
std::stack<std::unique_ptr<Action>> m_actions;
|
||||
std::stack<std::unique_ptr<Action>> m_redos;
|
||||
size_t m_memory = 0;
|
||||
static void add(Action* action);
|
||||
static void undo();
|
||||
static void redo();
|
||||
static void clear();
|
||||
static bool empty()
|
||||
{
|
||||
|
||||
@@ -55,8 +55,13 @@ void App::init_toolbar_main()
|
||||
if (auto* button = layout[main_id]->find<NodeButton>("btn-undo"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
if (!ActionManager::empty())
|
||||
ActionManager::undo();
|
||||
ActionManager::undo();
|
||||
};
|
||||
}
|
||||
if (auto* button = layout[main_id]->find<NodeButton>("btn-redo"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
ActionManager::redo();
|
||||
};
|
||||
}
|
||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-clean-memory"))
|
||||
|
||||
@@ -160,6 +160,35 @@ void ui::Canvas::snap_history(const std::vector<int>& planes)
|
||||
action->clear_layer = true;
|
||||
ActionManager::add(action);
|
||||
}
|
||||
ui::ActionStroke* ui::Canvas::create_action(int layer)
|
||||
{
|
||||
auto action = new ActionStroke;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (!m_layers[layer].m_dirty_face[i])
|
||||
continue; // no stroke on this face, skip it
|
||||
|
||||
m_layers[layer].m_rtt[i].bindFramebuffer();
|
||||
|
||||
// save image before commit
|
||||
glm::vec2 box_or = xy(m_layers[layer].m_dirty_box[i]);
|
||||
glm::vec2 box_sz = zw(m_layers[layer].m_dirty_box[i]) - xy(m_layers[layer].m_dirty_box[i]);
|
||||
action->m_image[i] = std::make_unique<uint8_t[]>(box_sz.x * box_sz.y * 4);
|
||||
glReadPixels(box_or.x, box_or.y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get());
|
||||
|
||||
action->m_box[i] = m_layers[layer].m_dirty_box[i];
|
||||
action->m_old_box[i] = m_layers[layer].m_dirty_box[i];
|
||||
action->m_old_dirty[i] = m_layers[layer].m_dirty_face[i];
|
||||
|
||||
m_layers[layer].m_rtt[i].unbindFramebuffer();
|
||||
}
|
||||
// save history
|
||||
action->m_layer_idx = layer;
|
||||
action->m_canvas = this;
|
||||
action->m_stroke = std::move(m_current_stroke);
|
||||
action->clear_layer = true;
|
||||
return action;
|
||||
}
|
||||
void ui::Canvas::stroke_end()
|
||||
{
|
||||
if (!m_current_stroke)
|
||||
|
||||
@@ -131,6 +131,7 @@ public:
|
||||
void snapshot_save(std::string data_path);
|
||||
void snapshot_restore();
|
||||
void snap_history(const std::vector<int>& planes);
|
||||
class ActionStroke* create_action(int layer);
|
||||
void clear_context();
|
||||
void import_equirectangular(std::string file_path);
|
||||
void import_equirectangular_thread(std::string file_path);
|
||||
@@ -174,6 +175,11 @@ public:
|
||||
virtual void run() override
|
||||
{
|
||||
|
||||
}
|
||||
virtual Action* get_redo()
|
||||
{
|
||||
auto redo = m_canvas->create_action(m_layer_idx);
|
||||
return redo;
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user