From 01e1bd9130947af1a29ba95df28e1a9269dfa534 Mon Sep 17 00:00:00 2001 From: besh81 Date: Tue, 5 Jan 2021 16:47:46 +0100 Subject: [PATCH] added undo on add, cut and paste controls now cutted controls can be paste more times --- src/ctrls/notebook.cpp | 32 +++++- src/ctrls/notebook.h | 1 + src/guimanager.cpp | 218 ++++++++++++++++++++--------------------- src/guimanager.h | 27 ++--- 4 files changed, 148 insertions(+), 130 deletions(-) diff --git a/src/ctrls/notebook.cpp b/src/ctrls/notebook.cpp index 028214f..49784b0 100644 --- a/src/ctrls/notebook.cpp +++ b/src/ctrls/notebook.cpp @@ -104,7 +104,6 @@ namespace ctrls pages.push_back(child); - // tbb.push_back(child->properties.property("caption").as_string()); tbb.attach(tbb.length() - 1, *child->nanawdg); @@ -114,6 +113,37 @@ namespace ctrls } + bool notebook::insert(ctrl* child, ctrl* pos, bool after) + { + if(!child) + return false; + + int i = 0; + for(auto p = pages.begin(); p < pages.end(); ++p, ++i) + { + if(*p == pos) + { + if(after) + { + ++p; + ++i; + } + + pages.insert(p, child); + + tbb.insert(i, child->properties.property("caption").as_string()); + tbb.attach(i, *child->nanawdg); + + plc["pages"].fasten(*child->nanawdg); + plc.collocate(); + return true; + } + } + + return false; + } + + bool notebook::remove(ctrl* child) { if(!child) diff --git a/src/ctrls/notebook.h b/src/ctrls/notebook.h index 04be720..b01dbcf 100644 --- a/src/ctrls/notebook.h +++ b/src/ctrls/notebook.h @@ -26,6 +26,7 @@ namespace ctrls // relationship management bool append(ctrl* child) override; + bool insert(ctrl* child, ctrl* pos, bool after) override; bool remove(ctrl* child) override; // bool moveup(ctrl* child) override; diff --git a/src/guimanager.cpp b/src/guimanager.cpp index 558a95e..0c68578 100644 --- a/src/guimanager.cpp +++ b/src/guimanager.cpp @@ -166,7 +166,6 @@ void guimanager::clear() if(!_cut_copy_doc.empty()) _cut_copy_doc.reset(); - _copied = false; _modified = false; @@ -524,7 +523,7 @@ void guimanager::deleteselected(bool push_undo) return; if(push_undo) - _push_undo(ur_action::remove_control, _selected); + _push_undo(ur_action::remove, _selected); auto toremove = _selected; auto parent = toremove->owner; @@ -730,10 +729,8 @@ void guimanager::_moveinto(tree_node* ctrl, move_into into) } // deserialize ctrls to move - if(!_deserialize(new_node, &root, insert_mode::into, true)) - { + if(!_deserialize(new_node, &root, insert_mode::into)) _error_message("Unable to move the selected controls!"); - } // enable GUI _op->auto_draw(true); @@ -765,7 +762,6 @@ void guimanager::copyselected(bool cut) if(!_cut_copy_doc.empty()) _cut_copy_doc.reset(); - _copied = !cut; // append root node pugi::xml_node root = _cut_copy_doc.append_child(NODE_ROOT); @@ -778,14 +774,14 @@ void guimanager::copyselected(bool cut) void guimanager::pasteselected() { + if(!_selected) + return; + // read root node pugi::xml_node root = _cut_copy_doc.child(NODE_ROOT); if(root.empty()) return; // nothing to paste - if(!_selected) - return; - auto prev_selected = _selected; auto type = prev_selected->value->properties.property("type").as_string(); @@ -810,19 +806,14 @@ void guimanager::pasteselected() _op->emit_events(false); _op->auto_draw(false); - bool paste_ok = _deserialize(_selected, &root, insert_mode::into, true); - if(!paste_ok) - _error_message("Unable to move the selected controls!"); + if(!_deserialize(_selected, &root, insert_mode::into, true)) + _error_message("Unable to paste here!"); _op->auto_draw(true); _op->emit_events(true); _update_op(); enableGUI(true, true); - if(!_copied && paste_ok) // cut items can be paste only once - if(!_cut_copy_doc.empty()) - _cut_copy_doc.reset(); - // select previous ctrl left_click_ctrl(prev_selected->value); } @@ -900,7 +891,6 @@ bool guimanager::click_ctrl(control_obj ctrl, const nana::arg_mouse& arg) mode = insert_mode::before; } - // deselect previous ctrl _ap->deselect(); @@ -921,9 +911,9 @@ bool guimanager::click_ctrl(control_obj ctrl, const nana::arg_mouse& arg) // add ctrl if(!addcommonctrl(_ctrl_node, cursor().type, mode)) - { _error_message("Unable to add control!"); - } + else + _push_undo(ur_action::add, _selected); // reset mouse cursor cursor(cursor_state{ cursor_action::select }); @@ -1062,7 +1052,7 @@ bool guimanager::deserialize(pugi::xml_node* xml_parent) return true; } -bool guimanager::_deserialize(tree_node* node, pugi::xml_node* xml_parent, insert_mode mode, bool paste) +bool guimanager::_deserialize(tree_node* node, pugi::xml_node* xml_parent, insert_mode mode, bool push_undo) { tree_node* parent = (mode == insert_mode::into) ? node : node->owner; @@ -1116,6 +1106,13 @@ bool guimanager::_deserialize(tree_node* node, pugi::xml_node* xml_ } + if(!xml_node.attribute("mainclass").as_bool()) + { + // check parent and siblings + if(!_check_relationship(parent->value, xml_node.attribute("type").as_string())) + return false; + } + // add name to name manager (and check) bool ctrl_name_changed = false; if(!_name_mgr.add(ctrl_name)) @@ -1127,23 +1124,13 @@ bool guimanager::_deserialize(tree_node* node, pugi::xml_node* xml_ tree_node* new_node = 0; if(xml_node.attribute("mainclass").as_bool()) - { new_node = addmainctrl(node_name, ctrl_name); - } else - { - // check parent and siblings - if(_check_relationship(parent->value, xml_node.attribute("type").as_string())) - new_node = addcommonctrl(node, node_name, mode, ctrl_name); - } + new_node = addcommonctrl(node, node_name, mode, ctrl_name); if(new_node == 0) { - if(paste) - return false; //XXX //TODO non torna perchè + stato aggiunto il nome in _name_mgr ??? - - //TODO message box con errore - std::cout << "UNKNOWN NODE: " << xml_node.name() << std::endl; + std::cout << "ERROR ADDING CTRL: " << node_name.c_str() << std::endl; continue; } @@ -1155,6 +1142,9 @@ bool guimanager::_deserialize(tree_node* node, pugi::xml_node* xml_ if(ctrl_name_changed) new_node->value->properties.property("name") = ctrl_name; + if(push_undo) + _push_undo(ur_action::add, new_node); + // deserialize children if(!_deserialize(new_node, &xml_node, insert_mode::into)) return false; @@ -1347,75 +1337,28 @@ void guimanager::undo() rstate.name = ustate.name; // perform undo - switch(ustate.action) + if(ustate.action == ur_action::add) { - case ur_action::remove_control: - // add ctrl (and children) previously removed - { - auto removed_node = ustate.snapshot.find_node([&ustate](pugi::xml_node node) -> bool { - return node.attribute("name").as_string() == ustate.name; - }); - - insert_mode mode; - std::string node_name; - if(!removed_node.previous_sibling().empty()) - { - mode = insert_mode::after; - node_name = removed_node.previous_sibling().attribute("name").as_string(); - } - else if(!removed_node.next_sibling().empty()) - { - mode = insert_mode::before; - node_name = removed_node.next_sibling().attribute("name").as_string(); - } - else - { - mode = insert_mode::into; - node_name = removed_node.parent().attribute("name").as_string(); - } - - // get ctrl from node name - tree_node* ctrl = 0; - _ctrls.for_each([node_name, &ctrl](tree_node* node) -> bool - { - if(node->value->properties.property("name").as_string() == node_name) - { - ctrl = node; - return false; - } - - return true; - }); - - pugi::xml_document doc; - pugi::xml_node root = doc.append_child(NODE_ROOT); - root.append_copy(removed_node); - - lock_guard des_lock(&_deserializing, true); - _op->emit_events(false); - _op->auto_draw(false); - - _deserialize(ctrl, &root, mode); - - _op->auto_draw(true); - _op->emit_events(true); + // save UI state + auto root = rstate.snapshot.append_child(NODE_ROOT); + serialize(&root); - click_ctrlname(ustate.name); - // reorder objectspanel item - _update_op(); - } - break; - case ur_action::move_up: + click_ctrlname(rstate.name); + deleteselected(false); + } + else if(ustate.action == ur_action::remove) + { + _ur_restore_ctrls(ustate); + } + else if(ustate.action == ur_action::move_up) + { click_ctrlname(ustate.name); movedownselected(false); - break; - case ur_action::move_down: + } + else if(ustate.action == ur_action::move_down) + { click_ctrlname(ustate.name); moveupselected(false); - break; - default: - // error - break; } _undo.pop_back(); @@ -1438,30 +1381,29 @@ void guimanager::redo() ustate.action = rstate.action; ustate.name = rstate.name; - if(rstate.action == ur_action::remove_control) + // perform redo + if(rstate.action == ur_action::add) { + _ur_restore_ctrls(rstate); + } + else if(rstate.action == ur_action::remove) + { + // save UI state auto root = ustate.snapshot.append_child(NODE_ROOT); serialize(&root); - } - // perform redo - switch(rstate.action) - { - case ur_action::remove_control: click_ctrlname(rstate.name); deleteselected(false); - break; - case ur_action::move_up: + } + else if(rstate.action == ur_action::move_up) + { click_ctrlname(rstate.name); moveupselected(false); - break; - case ur_action::move_down: + } + else if(rstate.action == ur_action::move_down) + { click_ctrlname(rstate.name); movedownselected(false); - break; - default: - // error - break; } _redo.pop_back(); @@ -1470,6 +1412,61 @@ void guimanager::redo() } +void guimanager::_ur_restore_ctrls(const ur_state& state) +{ + auto removed_node = state.snapshot.find_node([&state](pugi::xml_node node) -> bool { + return node.attribute("name").as_string() == state.name; + }); + + insert_mode mode; + std::string node_name; + if(!removed_node.previous_sibling().empty()) + { + mode = insert_mode::after; + node_name = removed_node.previous_sibling().attribute("name").as_string(); + } + else if(!removed_node.next_sibling().empty()) + { + mode = insert_mode::before; + node_name = removed_node.next_sibling().attribute("name").as_string(); + } + else + { + mode = insert_mode::into; + node_name = removed_node.parent().attribute("name").as_string(); + } + + // get ctrl from node name + tree_node* ctrl = 0; + _ctrls.for_each([node_name, &ctrl](tree_node* node) -> bool + { + if(node->value->properties.property("name").as_string() == node_name) + { + ctrl = node; + return false; + } + return true; + }); + + pugi::xml_document doc; + pugi::xml_node root = doc.append_child(NODE_ROOT); + root.append_copy(removed_node); + + lock_guard des_lock(&_deserializing, true); + _op->emit_events(false); + _op->auto_draw(false); + + _deserialize(ctrl, &root, mode); + + _op->auto_draw(true); + _op->emit_events(true); + + click_ctrlname(state.name); + // reorder objectspanel item + _update_op(); +} + + void guimanager::_push_undo(ur_action action, tree_node* ctrl) { _modified = true; @@ -1478,8 +1475,9 @@ void guimanager::_push_undo(ur_action action, tree_node* ctrl) ustate.action = action; ustate.name = ctrl->value->properties.property("name").as_string(); - if(action == ur_action::remove_control) + if(action == ur_action::remove) { + // save UI state auto root = ustate.snapshot.append_child(NODE_ROOT); serialize(&root); } diff --git a/src/guimanager.h b/src/guimanager.h index fb703a7..cc80ff0 100644 --- a/src/guimanager.h +++ b/src/guimanager.h @@ -78,18 +78,9 @@ class guimanager void copyselected(bool cut = false); void pasteselected(); + tree_node* get_root() { return _ctrls.get_root(); } - tree_node* get_root() - { - return _ctrls.get_root(); - } - - - void updateselected() - { - _updatectrl(_selected); - } - + void updateselected() { _updatectrl(_selected); } bool click_ctrl(control_obj ctrl, const nana::arg_mouse& arg); void left_click_ctrl(control_obj ctrl); @@ -125,7 +116,7 @@ class guimanager tree_node* _registerobject(control_obj ctrl, tree_node* node, insert_mode mode); void _serialize(tree_node* node, pugi::xml_node* xml_parent, bool children_only = false); - bool _deserialize(tree_node* node, pugi::xml_node* xml_parent, insert_mode mode, bool paste = false); + bool _deserialize(tree_node* node, pugi::xml_node* xml_parent, insert_mode mode, bool push_undo = false); bool _updatectrlname(tree_node* node, const std::string& new_name); void _updatectrl(tree_node* node, bool update_owner = true, bool update_children = true); @@ -159,11 +150,8 @@ class guimanager namemanager _name_mgr; // manage the controls name used in the creator bool _deserializing{ false }; - - pugi::xml_document _cut_copy_doc; - bool _copied{ false }; - bool _modified{ false }; + pugi::xml_document _cut_copy_doc; /*---------------*/ @@ -171,11 +159,11 @@ class guimanager /*---------------*/ enum class ur_action { - add_control, - remove_control, + add, + remove, move_up, move_down, - modify_property, + modify, empty }; @@ -185,6 +173,7 @@ class guimanager pugi::xml_document snapshot; }; + void _ur_restore_ctrls(const ur_state& state); void _push_undo(ur_action action, tree_node* ctrl); std::deque _undo;