1 /* 2 Copyright © 2020, Inochi2D Project 3 Distributed under the 2-Clause BSD License, see LICENSE file. 4 5 Authors: Luna Nielsen 6 */ 7 module creator.core.actionstack; 8 import creator.core.settings; 9 import creator.actions; 10 import inochi2d; 11 12 private { 13 Action[] actions; 14 size_t actionPointer; 15 size_t actionIndex; 16 size_t maxUndoHistory; 17 } 18 19 /** 20 Initialize actions system 21 */ 22 void incActionInit() { 23 maxUndoHistory = incSettingsGet!size_t("MaxUndoHistory", 100); 24 } 25 26 /** 27 Pushes a new action to the stack 28 */ 29 void incActionPush(Action action) { 30 31 // Chop away entries outside undo history 32 if (actions.length > incActionGetUndoHistoryLength()) { 33 size_t toChop = actions.length-incActionGetUndoHistoryLength(); 34 actions = actions[toChop..$]; 35 } 36 37 if (incActionTop() !is null && incActionTop().canMerge(action)) { 38 incActionTop().merge(action); 39 incActionNotifyTopChanged(); 40 } else { 41 // Add to the history 42 actions = actions[0..actionPointer]~action; 43 actionPointer++; 44 } 45 } 46 47 /** 48 Steps back in the action stack 49 */ 50 void incActionUndo() { 51 actionPointer--; 52 if (cast(ptrdiff_t)actionPointer < 0) { 53 actionPointer = 0; 54 return; 55 } 56 actions[actionPointer].rollback(); 57 } 58 59 /** 60 Steps forward in the action stack 61 */ 62 void incActionRedo() { 63 if (actionPointer >= actions.length) { 64 actionPointer = actions.length-1; 65 return; 66 } 67 actions[actionPointer].redo(); 68 actionPointer++; 69 } 70 71 /** 72 Gets whether undo is possible 73 */ 74 bool incActionCanUndo() { 75 return actionPointer > 0; 76 } 77 78 /** 79 Gets whether redo is possible 80 */ 81 bool incActionCanRedo() { 82 return actionPointer < actions.length; 83 } 84 85 /** 86 Gets the action history 87 */ 88 Action[] incActionHistory() { 89 return actions; 90 } 91 92 /** 93 Index of the current action 94 */ 95 size_t incActionIndex() { 96 return actionPointer; 97 } 98 99 /** 100 Gets the "top" action 101 */ 102 Action incActionTop() { 103 return actionPointer > 0 && actionPointer <= actions.length ? actions[actionPointer-1] : null; 104 } 105 106 /** 107 Notify that the top action has changed 108 */ 109 void incActionNotifyTopChanged() { 110 actions.length = actionPointer; 111 } 112 113 /** 114 Sets max undo history length 115 */ 116 void incActionSetUndoHistoryLength(size_t length) { 117 length = clamp(length, 0, 1000); 118 maxUndoHistory = length; 119 incSettingsSet("MaxUndoHistory", maxUndoHistory); 120 } 121 122 /** 123 Gets max undo history 124 */ 125 size_t incActionGetUndoHistoryLength() { 126 return maxUndoHistory; 127 } 128 129 /** 130 Sets the action index 131 Indexes start at 1, 0 is reserved for the INTIAL index 132 */ 133 void incActionSetIndex(size_t index) { 134 if (index > actions.length) { 135 index = actions.length; 136 } 137 138 if (index == 0) { 139 140 // Undo till we can't anymore 141 while (incActionCanUndo()) incActionUndo(); 142 } 143 144 if (index < actionPointer) { 145 while (index < actionPointer) incActionUndo(); 146 } else if (cast(ptrdiff_t)index > cast(ptrdiff_t)actionPointer) { 147 while (cast(ptrdiff_t)index > cast(ptrdiff_t)actionPointer) incActionRedo(); 148 } 149 } 150 151 /** 152 Clears action history 153 */ 154 void incActionClearHistory() { 155 actions.length = 0; 156 actionPointer = 0; 157 }