From c48a6da8a642ec179d2135fc31d8622d957a5b39 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Fri, 14 Jun 2019 18:46:11 +0200 Subject: [PATCH] improving actions history --- PanoPainter.vcxproj | 4 ++ PanoPainter.vcxproj.filters | 12 ++++ src/app.cpp | 2 +- src/app_cloud.cpp | 2 +- src/app_dialogs.cpp | 3 +- src/app_layout.cpp | 9 ++- src/canvas.cpp | 111 +++++------------------------------- src/canvas.h | 102 +-------------------------------- src/canvas_actions.cpp | 98 +++++++++++++++++++++++++++++++ src/canvas_actions.h | 20 +++++++ src/canvas_layer.cpp | 45 +++++++++++++++ src/canvas_layer.h | 45 +++++++++++++++ src/node_panel_layer.cpp | 105 ++++++++++++++++++++++++++++++++-- src/node_panel_layer.h | 44 +++++++++++++- 14 files changed, 388 insertions(+), 214 deletions(-) create mode 100644 src/canvas_actions.cpp create mode 100644 src/canvas_actions.h create mode 100644 src/canvas_layer.cpp create mode 100644 src/canvas_layer.h diff --git a/PanoPainter.vcxproj b/PanoPainter.vcxproj index 52b7b19..e881a3e 100644 --- a/PanoPainter.vcxproj +++ b/PanoPainter.vcxproj @@ -314,6 +314,8 @@ + + @@ -437,6 +439,8 @@ + + diff --git a/PanoPainter.vcxproj.filters b/PanoPainter.vcxproj.filters index 0ec929c..7a4e8a2 100644 --- a/PanoPainter.vcxproj.filters +++ b/PanoPainter.vcxproj.filters @@ -348,6 +348,12 @@ Source Files + + Source Files + + + Source Files + @@ -581,6 +587,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/src/app.cpp b/src/app.cpp index a3fd76d..d95c53e 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -57,7 +57,7 @@ void App::open_document(std::string path) title_update(); for (auto& i : canvas->m_canvas->m_order) { - auto l = layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str()); + auto l = layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str(), false); l->m_visibility->set_value(canvas->m_canvas->m_layers[i]->m_visible); } async_end(); diff --git a/src/app_cloud.cpp b/src/app_cloud.cpp index 2f0a5b0..f6660e7 100644 --- a/src/app_cloud.cpp +++ b/src/app_cloud.cpp @@ -170,7 +170,7 @@ void App::cloud_browse() doc_name = dialog->selected_name; title_update(); for (auto& i : canvas->m_canvas->m_order) - layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str()); + layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str(), false); ActionManager::clear(); m->destroy(); async_redraw(); diff --git a/src/app_dialogs.cpp b/src/app_dialogs.cpp index 365d350..5626677 100644 --- a/src/app_dialogs.cpp +++ b/src/app_dialogs.cpp @@ -119,8 +119,7 @@ void App::dialog_newdoc() canvas->reset_camera(); ActionManager::clear(); - canvas->m_canvas->layer_add("Default"); - layers->add_layer("Default"); + layers->add_layer("Default", false); canvas->m_canvas->m_unsaved = true; canvas->m_canvas->m_newdoc = false; diff --git a/src/app_layout.cpp b/src/app_layout.cpp index 646db13..ad37f86 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -166,8 +166,8 @@ void App::init_sidebar() brush_update(); }; - layers->on_layer_add = [this](Node*) { - canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str()); + layers->on_layer_add = [this](Node*, std::unique_ptr layer, int index) { + canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str(), std::move(layer), index); canvas->m_canvas->m_unsaved = true; title_update(); }; @@ -1162,7 +1162,7 @@ void App::init_menu_layer() canvas->m_canvas->layer_remove(current_idx_order); layers->clear(); for (auto& i : canvas->m_canvas->m_order) - layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str()); + layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str(), false); layers->m_current_layer->m_selected = false; layers->m_current_layer = layers->m_layers[current_idx_order - 1]; layers->m_current_layer->m_selected = true; @@ -1219,8 +1219,7 @@ void App::initLayout() init_sidebar(); - canvas->m_canvas->layer_add("Default"); - layers->add_layer("Default"); + layers->add_layer("Default", false); init_toolbar_draw(); init_toolbar_main(); diff --git a/src/canvas.cpp b/src/canvas.cpp index 7ecf87b..ca43d03 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1223,21 +1223,30 @@ void Canvas::stroke_start(glm::vec3 point, float pressure) } m_show_tmp = true; } -void Canvas::layer_add(std::string name) +void Canvas::layer_add(std::string name, std::unique_ptr layer /*= nullptr*/, int index /*= 0*/) { + LOG("canvas layer_add %s", name.c_str()); int idx = (int)m_layers.size(); - m_layers.push_back(std::make_unique()); - m_layers.back()->create(m_width, m_height, name); + if (layer) + { + m_layers.push_back(std::move(layer)); + } + else + { + m_layers.push_back(std::make_unique()); + m_layers.back()->create(m_width, m_height, name); + } m_order.push_back(idx); m_current_layer_idx = idx; } void Canvas::layer_remove(int idx) // m_order index { + LOG("canvas layer_remove %d", idx); int n = m_order[idx]; for (auto& i : m_order) if (i > n) i--; - m_layers[n]->destroy(); + //m_layers[n]->destroy(); m_layers.erase(m_layers.begin() + n); m_order.erase(m_order.begin() + idx); m_current_layer_idx = m_order[std::min((int)m_layers.size() - 1, idx)]; @@ -3158,97 +3167,3 @@ void Layer::resize(int width, int height) //m_dirty_face[i] = true; } } - -/////////////////////////////////////////////////////////////////////////////// - -void ActionStroke::undo() -{ - if (clear_layer) - m_canvas->m_layers[m_layer_idx]->clear({ 0, 0, 0, 0 }); - for (int i = 0; i < 6; i++) - { - // empty data - if (!m_image[i]) - continue; - - LOG("undo box %d dirty=%s [%d,%d,%d,%d] to dirty=%s [%d,%d,%d,%d]", - i, - m_canvas->m_layers[m_layer_idx]->m_dirty_face[i] ? "true" : "false", - (int)m_canvas->m_layers[m_layer_idx]->m_dirty_box[i].x, - (int)m_canvas->m_layers[m_layer_idx]->m_dirty_box[i].y, - (int)m_canvas->m_layers[m_layer_idx]->m_dirty_box[i].z, - (int)m_canvas->m_layers[m_layer_idx]->m_dirty_box[i].w, - m_old_dirty[i] ? "true" : "false", - (int)m_old_box[i].x, - (int)m_old_box[i].y, - (int)m_old_box[i].z, - (int)m_old_box[i].w); - m_canvas->m_layers[m_layer_idx]->m_dirty_box[i] = m_old_box[i]; - m_canvas->m_layers[m_layer_idx]->m_dirty_face[i] = m_old_dirty[i]; - - - glm::vec2 box_sz = zw(m_box[i]) - xy(m_box[i]); - if (box_sz.x > 0 && box_sz.y > 0 && box_sz.x <= m_canvas->m_layers[m_layer_idx]->w && box_sz.y <= m_canvas->m_layers[m_layer_idx]->h) - { - m_canvas->m_layers[m_layer_idx]->m_rtt[i].bindTexture(); - glTexSubImage2D(GL_TEXTURE_2D, 0, (int)m_box[i].x, (int)m_box[i].y, (int)box_sz.x, (int)box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image[i].get()); - m_canvas->m_layers[m_layer_idx]->m_rtt[i].unbindTexture(); - } - else - { - LOG("undo invalid box size (%d, %d)", (int)box_sz.x, (int)box_sz.y); - } - } - m_canvas->draw_merge(); -} - -size_t ActionStroke::memory() -{ - size_t mem = 0; - for (int i = 0; i < 6; i++) - { - glm::ivec2 sz = zw(m_box[i]) - xy(m_box[i]); - mem += sz.x * sz.y * 4 + sizeof(*this); - } - return mem; -} - -Action* ActionStroke::get_redo() -{ - auto action = new ActionStroke; - auto& layer = m_canvas->m_layers[m_layer_idx]; - for (int i = 0; i < 6; i++) - { - if (!layer->m_dirty_face[i] && !m_image[i]) - continue; // no stroke on this face, skip it - - layer->m_rtt[i].bindFramebuffer(); - - auto box = clear_layer ? glm::ivec4(layer->m_dirty_box[i]) : m_box[i]; - - // save image before commit - glm::vec2 box_or = xy(box); - glm::vec2 box_sz = zw(box) - xy(box); - if (box_sz.x > 0 && box_sz.y > 0 && box_sz.x <= layer->w && box_sz.y <= layer->h) - { - action->m_image[i] = std::make_unique(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()); - } - else - { - LOG("create_action invalid box size (%d, %d)", (int)box_sz.x, (int)box_sz.y); - } - - action->m_box[i] = box; - action->m_old_box[i] = layer->m_dirty_box[i]; - action->m_old_dirty[i] = layer->m_dirty_face[i]; - - layer->m_rtt[i].unbindFramebuffer(); - } - // save history - action->m_layer_idx = m_layer_idx; - action->m_canvas = m_canvas; - //action->m_stroke = std::move(m_stroke); - action->clear_layer = false; - return action; -} diff --git a/src/canvas.h b/src/canvas.h index 6a335c8..bc72282 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -4,90 +4,13 @@ #include "shader.h" #include "shape.h" #include "brush.h" -#include "action.h" +#include "canvas_layer.h" +#include "canvas_actions.h" #include "canvas_modes.h" #include #define CANVAS_RES 1536 -class LayerFrame -{ - -}; - -class Layer -{ -public: - Layer() = default; - Layer(const Layer&) = delete; - RTT m_rtt[6]; - glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0)); - bool m_dirty_face[6] = SIXPLETTE(false); - bool m_visible = true; - bool m_alpha_locked = false; - float m_opacity = 1.f; - bool m_hightlight = false; - int m_blend_mode = 0; - std::string m_name; - int w = 0; - int h = 0; - struct Snapshot - { - std::unique_ptr image[6] = SIXPLETTE(0); - glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0)); - bool m_dirty_face[6] = SIXPLETTE(false); - int width = 0; - int height = 0; - void create(int w, int h) - { - for (int i = 0; i < 6; i++) - { - image[i] = std::make_unique(w*h*4); - std::fill_n(image[i].get(), w*h*4, 0); - } - } - void clear() - { - for (int i = 0; i < 6; i++) - { - m_dirty_face[i] = false; - m_dirty_box[i] = glm::vec4(0); - std::fill_n(image[i].get(), width*height*4, 0); - } - } - void optimize() - { - for (int i = 0; i < 6; i++) - { - if (!m_dirty_face[i] || !image[i]) - continue; - auto data = reinterpret_cast(image[i].get()); - glm::ivec2 bbmin(width, height); - glm::ivec2 bbmax(0); - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - if (data[x + y * width].a > 0) - { - bbmin = glm::min(bbmin, { x, y }); - bbmax = glm::max(bbmax, { x + 1, y + 1 }); - } - } - } - //glm::vec2 bbsz = bbmax - bbmin; - } - } - }; - void resize(int width, int height); - bool create(int width, int height, std::string name); - void clear(const glm::vec4& c); - Snapshot snapshot(); - void restore(const Snapshot& snap); - void destroy(); - void optimize(); -}; - struct PPIThumb { int width = 128; @@ -241,7 +164,7 @@ public: bool create(int width, int height); void resize(int width, int height); void layer_remove(int idx); - void layer_add(std::string name); + void layer_add(std::string name, std::unique_ptr layer = nullptr, int index = 0); void layer_order(int idx, int pos); void layer_merge(int source_idx, int dest_idx); void stroke_start(glm::vec3 point, float pressure); @@ -302,22 +225,3 @@ public: CameraData get_camera(); void set_camera(const CameraData& c); }; - -class ActionStroke : public Action -{ -public: - //std::unique_ptr m_stroke; - std::unique_ptr m_image[6] = SIXPLETTE(nullptr); - glm::ivec4 m_old_box[6] = SIXPLETTE(glm::ivec4(0)); - bool m_old_dirty[6] = SIXPLETTE(false); - glm::ivec4 m_box[6] = SIXPLETTE(glm::ivec4(0)); - bool clear_layer = false; - int m_layer_idx = 0; - Canvas* m_canvas; - ActionStroke() = default; - virtual ~ActionStroke() = default; - virtual void run() override { } - virtual Action* get_redo() override; - virtual void undo() override; - virtual size_t memory() override; -}; diff --git a/src/canvas_actions.cpp b/src/canvas_actions.cpp new file mode 100644 index 0000000..a86fa03 --- /dev/null +++ b/src/canvas_actions.cpp @@ -0,0 +1,98 @@ +#include "pch.h" +#include "log.h" +#include "app.h" +#include "canvas.h" +#include "canvas_actions.h" +#include "node_panel_layer.h" + +void ActionStroke::undo() +{ + if (clear_layer) + m_canvas->m_layers[m_layer_idx]->clear({ 0, 0, 0, 0 }); + for (int i = 0; i < 6; i++) + { + // empty data + if (!m_image[i]) + continue; + + LOG("undo box %d dirty=%s [%d,%d,%d,%d] to dirty=%s [%d,%d,%d,%d]", + i, + m_canvas->m_layers[m_layer_idx]->m_dirty_face[i] ? "true" : "false", + (int)m_canvas->m_layers[m_layer_idx]->m_dirty_box[i].x, + (int)m_canvas->m_layers[m_layer_idx]->m_dirty_box[i].y, + (int)m_canvas->m_layers[m_layer_idx]->m_dirty_box[i].z, + (int)m_canvas->m_layers[m_layer_idx]->m_dirty_box[i].w, + m_old_dirty[i] ? "true" : "false", + (int)m_old_box[i].x, + (int)m_old_box[i].y, + (int)m_old_box[i].z, + (int)m_old_box[i].w); + m_canvas->m_layers[m_layer_idx]->m_dirty_box[i] = m_old_box[i]; + m_canvas->m_layers[m_layer_idx]->m_dirty_face[i] = m_old_dirty[i]; + + + glm::vec2 box_sz = zw(m_box[i]) - xy(m_box[i]); + if (box_sz.x > 0 && box_sz.y > 0 && box_sz.x <= m_canvas->m_layers[m_layer_idx]->w && box_sz.y <= m_canvas->m_layers[m_layer_idx]->h) + { + m_canvas->m_layers[m_layer_idx]->m_rtt[i].bindTexture(); + glTexSubImage2D(GL_TEXTURE_2D, 0, (int)m_box[i].x, (int)m_box[i].y, (int)box_sz.x, (int)box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image[i].get()); + m_canvas->m_layers[m_layer_idx]->m_rtt[i].unbindTexture(); + } + else + { + LOG("undo invalid box size (%d, %d)", (int)box_sz.x, (int)box_sz.y); + } + } + m_canvas->draw_merge(); +} + +size_t ActionStroke::memory() +{ + size_t mem = 0; + for (int i = 0; i < 6; i++) + { + glm::ivec2 sz = zw(m_box[i]) - xy(m_box[i]); + mem += sz.x * sz.y * 4 + sizeof(*this); + } + return mem; +} + +Action* ActionStroke::get_redo() +{ + auto action = new ActionStroke; + auto& layer = m_canvas->m_layers[m_layer_idx]; + for (int i = 0; i < 6; i++) + { + if (!layer->m_dirty_face[i] && !m_image[i]) + continue; // no stroke on this face, skip it + + layer->m_rtt[i].bindFramebuffer(); + + auto box = clear_layer ? glm::ivec4(layer->m_dirty_box[i]) : m_box[i]; + + // save image before commit + glm::vec2 box_or = xy(box); + glm::vec2 box_sz = zw(box) - xy(box); + if (box_sz.x > 0 && box_sz.y > 0 && box_sz.x <= layer->w && box_sz.y <= layer->h) + { + action->m_image[i] = std::make_unique(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()); + } + else + { + LOG("create_action invalid box size (%d, %d)", (int)box_sz.x, (int)box_sz.y); + } + + action->m_box[i] = box; + action->m_old_box[i] = layer->m_dirty_box[i]; + action->m_old_dirty[i] = layer->m_dirty_face[i]; + + layer->m_rtt[i].unbindFramebuffer(); + } + // save history + action->m_layer_idx = m_layer_idx; + action->m_canvas = m_canvas; + //action->m_stroke = std::move(m_stroke); + action->clear_layer = false; + return action; +} diff --git a/src/canvas_actions.h b/src/canvas_actions.h new file mode 100644 index 0000000..ef0eef1 --- /dev/null +++ b/src/canvas_actions.h @@ -0,0 +1,20 @@ +#pragma once +#include "action.h" + +class ActionStroke : public Action +{ +public: + //std::unique_ptr m_stroke; + std::unique_ptr m_image[6] = SIXPLETTE(nullptr); + glm::ivec4 m_old_box[6] = SIXPLETTE(glm::ivec4(0)); + bool m_old_dirty[6] = SIXPLETTE(false); + glm::ivec4 m_box[6] = SIXPLETTE(glm::ivec4(0)); + bool clear_layer = false; + int m_layer_idx = 0; + class Canvas* m_canvas; + virtual ~ActionStroke() = default; + virtual void run() override { } + virtual Action* get_redo() override; + virtual void undo() override; + virtual size_t memory() override; +}; diff --git a/src/canvas_layer.cpp b/src/canvas_layer.cpp new file mode 100644 index 0000000..62fad2f --- /dev/null +++ b/src/canvas_layer.cpp @@ -0,0 +1,45 @@ +#include "pch.h" +#include "canvas_layer.h" + +void Layer::Snapshot::create(int w, int h) +{ + for (int i = 0; i < 6; i++) + { + image[i] = std::make_unique(w * h * 4); + std::fill_n(image[i].get(), w * h * 4, 0); + } +} + +void Layer::Snapshot::clear() +{ + for (int i = 0; i < 6; i++) + { + m_dirty_face[i] = false; + m_dirty_box[i] = glm::vec4(0); + std::fill_n(image[i].get(), width * height * 4, 0); + } +} + +void Layer::Snapshot::optimize() +{ + for (int i = 0; i < 6; i++) + { + if (!m_dirty_face[i] || !image[i]) + continue; + auto data = reinterpret_cast(image[i].get()); + glm::ivec2 bbmin(width, height); + glm::ivec2 bbmax(0); + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + if (data[x + y * width].a > 0) + { + bbmin = glm::min(bbmin, { x, y }); + bbmax = glm::max(bbmax, { x + 1, y + 1 }); + } + } + } + //glm::vec2 bbsz = bbmax - bbmin; + } +} diff --git a/src/canvas_layer.h b/src/canvas_layer.h new file mode 100644 index 0000000..433e98d --- /dev/null +++ b/src/canvas_layer.h @@ -0,0 +1,45 @@ +#pragma once +#include "rtt.h" +#include "log.h" + +class LayerFrame +{ + +}; + +class Layer +{ +public: + Layer() = default; + Layer(const Layer&) = delete; + ~Layer() { LOG("LAYER AUTO DESTROY"); destroy(); } + RTT m_rtt[6]; + glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0)); + bool m_dirty_face[6] = SIXPLETTE(false); + bool m_visible = true; + bool m_alpha_locked = false; + float m_opacity = 1.f; + bool m_hightlight = false; + int m_blend_mode = 0; + std::string m_name; + int w = 0; + int h = 0; + struct Snapshot + { + std::unique_ptr image[6] = SIXPLETTE(0); + glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0)); + bool m_dirty_face[6] = SIXPLETTE(false); + int width = 0; + int height = 0; + void create(int w, int h); + void clear(); + void optimize(); + }; + void resize(int width, int height); + bool create(int width, int height, std::string name); + void clear(const glm::vec4& c); + Snapshot snapshot(); + void restore(const Snapshot& snap); + void destroy(); + void optimize(); +}; diff --git a/src/node_panel_layer.cpp b/src/node_panel_layer.cpp index fcfc44c..7d034a7 100644 --- a/src/node_panel_layer.cpp +++ b/src/node_panel_layer.cpp @@ -3,6 +3,7 @@ #include "node_panel_layer.h" #include "canvas.h" #include "node_combobox.h" +#include "app.h" Node* NodeLayer::clone_instantiate() const { @@ -140,7 +141,7 @@ void NodePanelLayer::init() btn_add->on_click = [this](Node*) { add_layer(); if (on_layer_add) - on_layer_add(this); + on_layer_add(this, nullptr, 0); if (on_layer_change) on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer)); update_attributes(); @@ -182,10 +183,13 @@ void NodePanelLayer::init() }; } -NodeLayer* NodePanelLayer::add_layer(const char* name) +NodeLayer* NodePanelLayer::add_layer(const char* name, bool add_history /*= true*/, std::unique_ptr layer /*= nullptr*/, int index /*= 0*/) { NodeLayer* l = new NodeLayer; - m_layers_container->add_child(l); + if (layer) + m_layers_container->add_child(l, index); + else + m_layers_container->add_child(l); l->init(); l->create(); l->loaded(); @@ -199,7 +203,25 @@ NodeLayer* NodePanelLayer::add_layer(const char* name) m_current_layer = l; m_current_layer->m_selected = true; m_layers.push_back(l); - update_attributes(); + + if (add_history) + { + auto a = new ActionLayerAdd; + a->m_panel = this; + a->m_layer_node = l->shared_from_this(); + a->m_layer_order = m_layers_container->get_child_index(l); + ActionManager::add(a); + update_attributes(); + } + else + { + if (on_layer_add) + on_layer_add(this, std::move(layer), index); + if (on_layer_change) + on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer)); + update_attributes(); + } + return l; } @@ -215,16 +237,28 @@ NodeLayer* NodePanelLayer::get_layer_at(int index) return static_cast(m_layers_container->get_child_at(index)); } -void NodePanelLayer::remove_layer(NodeLayer* layer) +void NodePanelLayer::remove_layer(NodeLayer* layer, bool add_history /*= true*/) { auto it = std::find(m_layers.begin(), m_layers.end(), m_current_layer); auto i = m_layers_container->get_child_index(m_current_layer); int old_idx = i;// (int)std::distance(m_layers.begin(), it); + auto copy = (*it)->shared_from_this(); m_layers_container->remove_child(m_current_layer); m_layers.erase(it); i = std::min(i, (int)m_layers.size() - 1); m_current_layer = (NodeLayer*)m_layers_container->get_child_at(i); m_current_layer->m_selected = true; + + if (add_history) + { + auto a = new ActionLayerRemove; + a->m_panel = this; + a->m_layer_node = copy; + a->m_layer = std::move(Canvas::I->m_layers[Canvas::I->m_order[old_idx]]); + a->m_layer_order = old_idx; + ActionManager::add(a); + } + if (on_layer_delete) on_layer_delete(this, old_idx); if (on_layer_change) @@ -307,3 +341,64 @@ kEventResult NodePanelLayer::handle_event(Event* e) } return kEventResult::Available; } + +/////////////////////////////////////////////////////////////////////////////// + +Action* ActionLayerAdd::get_redo() +{ + auto a = new ActionLayerRemove; + a->m_panel = m_panel; + a->m_layer_node = m_layer_node; + a->m_layer = std::move(Canvas::I->m_layers[Canvas::I->m_order[m_layer_order]]); + a->m_layer_order = m_layer_order; + return a; +} + +void ActionLayerAdd::undo() +{ + m_panel->remove_layer((NodeLayer*)m_layer_node.get(), false); +} + +size_t ActionLayerAdd::memory() +{ + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +Action* ActionLayerRemove::get_redo() +{ + auto a = new ActionLayerAdd; + a->m_panel = m_panel; + a->m_layer_node = m_layer_node; + a->m_layer_order = m_layer_order; + return a; +} + +void ActionLayerRemove::undo() +{ + std::string name = m_layer->m_name; + m_panel->add_layer(name.c_str(), false, std::move(m_layer), m_layer_order); +} + +size_t ActionLayerRemove::memory() +{ + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +Action* ActionLayerMove::get_redo() +{ + return nullptr; +} + +void ActionLayerMove::undo() +{ + +} + +size_t ActionLayerMove::memory() +{ + return 0; +} diff --git a/src/node_panel_layer.h b/src/node_panel_layer.h index 652ee34..eb4b299 100644 --- a/src/node_panel_layer.h +++ b/src/node_panel_layer.h @@ -6,6 +6,7 @@ #include "node_button_custom.h" #include "node_combobox.h" #include "node_scroll.h" +#include "action.h" class NodeLayer : public NodeBorder { @@ -49,7 +50,7 @@ public: std::function on_layer_blend_mode_changed; std::function on_layer_delete; std::function on_layer_duplicate; - std::function on_layer_add; + std::function layer, int index)> on_layer_add; std::function on_layer_order; NodeLayer* m_current_layer = nullptr; std::vector m_layers; @@ -61,9 +62,9 @@ public: virtual void init() override; virtual kEventResult handle_event(Event* e) override; void add_layer(); - NodeLayer* add_layer(const char* name); + NodeLayer* add_layer(const char* name, bool add_history = true, std::unique_ptr layer = nullptr, int index = 0); NodeLayer* get_layer_at(int index); - void remove_layer(NodeLayer* layer); + void remove_layer(NodeLayer* layer, bool add_history = true); void handle_layer_opacity(NodeLayer* target, float value); void handle_layer_visibility(NodeLayer* target, bool visible); void handle_layer_alpha_lock(NodeLayer* target, bool locked); @@ -73,3 +74,40 @@ public: void clear(); void update_attributes(); }; + +class ActionLayerAdd : public Action +{ +public: + NodePanelLayer* m_panel; + std::shared_ptr m_layer_node; + int m_layer_order; + virtual void run() override { } + virtual Action* get_redo() override; + virtual void undo() override; + virtual size_t memory() override; +}; + +class ActionLayerRemove : public Action +{ +public: + NodePanelLayer* m_panel; + std::shared_ptr m_layer_node; + std::unique_ptr m_layer; + int m_layer_order; + virtual void run() override { } + virtual Action* get_redo() override; + virtual void undo() override; + virtual size_t memory() override; +}; + +class ActionLayerMove : public Action +{ +public: + int m_index_old; + int m_index_new; + virtual void run() override { } + virtual Action* get_redo() override; + virtual void undo() override; + virtual size_t memory() override; +}; +