1 // This file is part of VSTGUI. It is subject to the license terms 2 // in the LICENSE file found in the top-level directory of this 3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE 4 5 #include "uiundomanager.h" 6 7 #if VSTGUI_LIVE_EDITING 8 9 #include "iaction.h" 10 #include <string> 11 12 namespace VSTGUI { 13 14 //----------------------------------------------------------------------------- 15 class UndoStackTop : public IAction 16 { 17 public: 18 UTF8StringPtr getName () override { return nullptr; } 19 void perform () override {} 20 void undo () override {} 21 }; 22 23 //---------------------------------------------------------------------------------------------------- 24 class UIGroupAction : public IAction, public std::list<IAction*> 25 { 26 public: 27 static void doPerform (IAction* action) { action->perform (); } 28 static void doUndo (IAction* action) { action->undo (); } 29 static void doDelete (IAction* action) { delete action; } 30 31 UIGroupAction (UTF8StringPtr name) : name (name) {} 32 ~UIGroupAction () override 33 { 34 std::for_each (begin (), end (), doDelete); 35 } 36 37 UTF8StringPtr getName () override { return name.c_str (); } 38 39 void perform () override 40 { 41 std::for_each (begin (), end (), doPerform); 42 } 43 44 void undo () override 45 { 46 std::for_each (rbegin (), rend (), doUndo); 47 } 48 49 protected: 50 std::string name; 51 }; 52 53 //---------------------------------------------------------------------------------------------------- 54 UIUndoManager::UIUndoManager () 55 { 56 emplace_back (new UndoStackTop); 57 position = begin (); 58 savePosition = begin (); 59 } 60 61 //---------------------------------------------------------------------------------------------------- 62 UIUndoManager::~UIUndoManager () 63 { 64 std::for_each (begin (), end (), [] (IAction* action) { delete action; }); 65 } 66 67 //---------------------------------------------------------------------------------------------------- 68 void UIUndoManager::pushAndPerform (IAction* action) 69 { 70 if (groupQueue.empty () == false) 71 { 72 groupQueue.back ()->emplace_back (action); 73 return; 74 } 75 if (position != end ()) 76 { 77 position++; 78 iterator oldStack = position; 79 while (position != end ()) 80 { 81 if (position == savePosition) 82 savePosition = end (); 83 delete (*position); 84 position++; 85 } 86 erase (oldStack, end ()); 87 } 88 emplace_back (action); 89 position = end (); 90 position--; 91 action->perform (); 92 forEachListener ([] (IUIUndoManagerListener* l) { l->onUndoManagerChange (); }); 93 } 94 95 //---------------------------------------------------------------------------------------------------- 96 void UIUndoManager::performUndo () 97 { 98 if (position != end () && position != begin ()) 99 { 100 (*position)->undo (); 101 position--; 102 forEachListener ([] (IUIUndoManagerListener* l) { l->onUndoManagerChange (); }); 103 } 104 } 105 106 //---------------------------------------------------------------------------------------------------- 107 void UIUndoManager::performRedo () 108 { 109 if (position != end ()) 110 { 111 position++; 112 if (position != end ()) 113 { 114 (*position)->perform (); 115 forEachListener ([] (IUIUndoManagerListener* l) { l->onUndoManagerChange (); }); 116 } 117 } 118 } 119 120 //---------------------------------------------------------------------------------------------------- 121 bool UIUndoManager::canUndo () 122 { 123 return (position != end () && position != begin ()); 124 } 125 126 //---------------------------------------------------------------------------------------------------- 127 bool UIUndoManager::canRedo () 128 { 129 if (position == end () && position != begin ()) 130 return false; 131 position++; 132 bool result = (position != end ()); 133 position--; 134 return result; 135 } 136 137 //---------------------------------------------------------------------------------------------------- 138 UTF8StringPtr UIUndoManager::getUndoName () 139 { 140 if (position != end () && position != begin ()) 141 return (*position)->getName (); 142 return nullptr; 143 } 144 145 //---------------------------------------------------------------------------------------------------- 146 UTF8StringPtr UIUndoManager::getRedoName () 147 { 148 UTF8StringPtr redoName = nullptr; 149 if (position != end ()) 150 { 151 position++; 152 if (position != end ()) 153 redoName = (*position)->getName (); 154 position--; 155 } 156 return redoName; 157 } 158 159 //---------------------------------------------------------------------------------------------------- 160 void UIUndoManager::clear () 161 { 162 std::for_each (begin (), end (), [] (IAction* action) { delete action; }); 163 std::list<IAction*>::clear (); 164 emplace_back (new UndoStackTop); 165 position = end (); 166 savePosition = begin (); 167 forEachListener ([] (IUIUndoManagerListener* l) { l->onUndoManagerChange (); }); 168 } 169 170 //---------------------------------------------------------------------------------------------------- 171 void UIUndoManager::startGroupAction (UTF8StringPtr name) 172 { 173 UIGroupAction* action = new UIGroupAction (name); 174 groupQueue.emplace_back (action); 175 } 176 177 //---------------------------------------------------------------------------------------------------- 178 void UIUndoManager::endGroupAction () 179 { 180 UIGroupAction* action = groupQueue.back (); 181 if (action) 182 { 183 groupQueue.pop_back (); 184 if (action->empty ()) 185 { 186 delete action; 187 } 188 else 189 { 190 pushAndPerform (action); 191 } 192 } 193 } 194 195 //---------------------------------------------------------------------------------------------------- 196 void UIUndoManager::cancelGroupAction () 197 { 198 UIGroupAction* action = groupQueue.back (); 199 if (action) 200 { 201 groupQueue.pop_back (); 202 delete action; 203 } 204 } 205 206 //---------------------------------------------------------------------------------------------------- 207 void UIUndoManager::markSavePosition () 208 { 209 savePosition = position; 210 } 211 212 //---------------------------------------------------------------------------------------------------- 213 bool UIUndoManager::isSavePosition () const 214 { 215 return savePosition == position; 216 } 217 218 219 } // VSTGUI 220 221 #endif // VSTGUI_LIVE_EDITING 222