1 /*
2     Copyright © 2020, Luna Nielsen
3     Distributed under the 2-Clause BSD License, see LICENSE file.
4     
5     Authors: Luna Nielsen
6 */
7 module engine.core.astack;
8 import std.exception;
9 
10 /**
11     A stack of actions performed in the game
12 
13     Actions can be undone and redone.
14     Pushing a new action to the stack will overwrite actions past the current top cursor.
15 */
16 class ActionStack(ActionT) {
17 private:
18     ActionT[] stack;
19     size_t top;
20 
21 public:
22 
23     /**
24         Push an action to the stack
25 
26         Returns the resulting top of the stack
27     */
28     ActionT push(ActionT item) {
29 
30         // First remove any elements in the undo/redo chain after our top
31         stack.length = top+1;
32 
33         // Move the top up one element
34         top++;
35 
36         // Add new item
37         stack ~= item;
38         return stack[$-1];
39     }
40 
41     /**
42         Get the current top of the stack
43     */
44     ActionT get() {
45         enforce(stack.length > 0, "ActionStack is empty.");
46         return stack[top];
47     }
48 
49     /**
50         Undo an action
51 
52         Returns the resulting top of the stack
53     */
54     ActionT undo() {
55         enforce(stack.length > 0, "ActionStack is empty.");
56         if (top > 0) top--;
57         return stack[top];
58     }
59 
60     /**
61         Redo an action
62 
63         Returns the resulting top of the stack
64     */
65     ActionT redo() {
66         enforce(stack.length > 0, "ActionStack is empty.");
67         if (top < stack.length) top++;
68         return stack[top];
69     }
70 
71     /**
72         Clear the action stack
73     */
74     void clear() {
75         top = 0;
76         stack.length = 0;
77     }
78 
79     /**
80         Gets whether the action stack is empty.
81     */
82     bool empty() {
83         return stack.length == 0;
84     }
85 
86     /**
87         Returns true if there's any actions left to undo
88     */
89     bool canUndo() {
90         return top > 0;
91     }
92 
93     /**
94         Returns true if there's any actions left to redo
95     */
96     bool canRedo() {
97         return top < stack.length;
98     }
99 }