Initial revision
[blender-staging.git] / intern / action / intern / ACT_ActionStack.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 /**
33
34  * $Id$
35  * Copyright (C) 2001 NaN Technologies B.V.
36  * @author      Maarten Gribnau
37  * @date        March 31, 2001
38  */
39
40 #include "ACT_ActionStack.h"
41
42
43 ACT_ActionStack::ACT_ActionStack(unsigned int maxStackDepth)
44         : m_maxStackDepth(maxStackDepth),
45           m_undoIndex(0), m_undoIndexValid(false),
46           m_redoIndex(0), m_redoIndexValid(false)
47 {
48 }
49
50
51 ACT_ActionStack::~ACT_ActionStack()
52 {
53         flush();
54 }
55
56
57 unsigned int ACT_ActionStack::getStackDepth() const
58 {
59         return m_stack.size();
60 }
61
62
63 unsigned int ACT_ActionStack::getMaxStackDepth() const
64 {
65         return m_maxStackDepth;
66 }
67
68
69 void ACT_ActionStack::setMaxStackDepth(unsigned int maxStackDepth)
70 {
71         if (maxStackDepth != m_maxStackDepth) {
72                 if (maxStackDepth) {
73                         unsigned int size = m_stack.size();
74                         if (maxStackDepth < size) {
75                                 // New max stack size is smaller than current stack size, need to shrink stack
76                                 unsigned int numRemove = size - maxStackDepth;
77                                 if (m_undoIndex >= maxStackDepth) {
78                                         // Pop items from the front (throw away undo steps)
79                                         popFront(numRemove);
80                                         m_undoIndex -= numRemove;
81                                         m_redoIndex = m_undoIndex + 1;
82                                         m_redoIndexValid = m_redoIndexValid && (maxStackDepth > 1);
83                                 }
84                                 else {
85                                         // Pop items from the back (throw away redo steps)
86                                         popBack(numRemove);
87                                         m_redoIndexValid = m_redoIndexValid && (m_redoIndex < maxStackDepth);
88                                 }
89                         }
90                 }
91                 else {
92                         // New stack size is zero
93                         flush();
94                 }
95                 m_maxStackDepth = maxStackDepth;
96         }
97 }
98
99
100 void ACT_ActionStack::push(ACT_Action& action)
101 {
102         if (m_maxStackDepth) {
103                 unsigned int size = m_stack.size();
104                 if (m_redoIndexValid) {
105                         // Remove items after the current action (throw away redo steps)
106                         popBack(size - m_redoIndex);
107                 }
108                 else if (size >= m_maxStackDepth) {
109                         // Remove items from the front (throw away undo steps)
110                         popFront(m_maxStackDepth - size + 1);
111                 }
112
113                 // Store the action
114                 if (!action.getIsApplied()) {
115                         action.apply();
116                 }
117                 action.incRef();
118                 m_stack.push_back(&action);
119
120                 // Update action indices
121                 m_redoIndex = m_stack.size();
122                 m_redoIndexValid = false;
123                 m_undoIndex = m_redoIndex - 1;
124                 m_undoIndexValid = true;
125         }
126 }
127
128
129 ACT_Action* ACT_ActionStack::peekUndo()
130 {
131         unsigned int i;
132         return getUndoIndex(i) ? m_stack[i] : 0;
133 }
134
135
136 ACT_Action* ACT_ActionStack::peekRedo()
137 {
138         unsigned int i;
139         return getRedoIndex(i) ? m_stack[i] : 0;
140 }
141
142
143 void ACT_ActionStack::flush()
144 {
145         popBack(m_stack.size());
146         m_undoIndex = 0;
147         m_undoIndexValid = false;
148         m_redoIndex = 0;
149         m_redoIndexValid = false;
150 }
151
152
153 bool ACT_ActionStack::canUndo() const
154 {
155         unsigned int i;
156         return getUndoIndex(i);
157 }
158
159
160 void ACT_ActionStack::undo()
161 {
162         ACT_Action* action = peekUndo();
163         if (action) {
164                 action->undo();
165
166                 // Update action indices
167                 m_redoIndex = m_undoIndex;
168                 m_redoIndexValid = true;
169                 if (m_undoIndex) {
170                         m_undoIndex--;
171                 }
172                 else {
173                         m_undoIndexValid = false;
174                 }
175         }
176 }
177
178
179 bool ACT_ActionStack::canRedo() const
180 {
181         unsigned int i;
182         return getRedoIndex(i);
183 }
184
185
186 void ACT_ActionStack::redo()
187 {
188         ACT_Action* action = peekRedo();
189         if (action) {
190                 action->apply();
191
192                 // Update action indices
193                 m_undoIndex = m_redoIndex;
194                 m_undoIndexValid = true;
195                 m_redoIndex++;
196                 m_redoIndexValid = m_redoIndex < m_stack.size();
197         }
198 }
199
200
201 unsigned int ACT_ActionStack::popFront(unsigned int numActions)
202 {
203         unsigned int numRemoved = 0;
204
205         while (numActions-- && m_stack.size()) {
206                 ACT_Action* action = m_stack[0];
207                 action->decRef();
208                 m_stack.pop_front();
209                 numRemoved++;
210         }
211         return numRemoved;      
212 }
213
214
215 unsigned int ACT_ActionStack::popBack(unsigned int numActions)
216 {
217         unsigned int numRemoved = 0;
218         unsigned int size;
219
220         while (numActions-- && (size = m_stack.size())) {
221                 ACT_Action* action = m_stack[size-1];
222                 action->decRef();
223                 m_stack.pop_back();
224                 numRemoved++;
225         }
226         return numRemoved;      
227 }
228
229
230 bool ACT_ActionStack::getUndoIndex(unsigned int& i) const
231 {
232         i = m_undoIndex;
233         return m_undoIndexValid;
234 }
235
236
237 bool ACT_ActionStack::getRedoIndex(unsigned int& i) const
238 {
239         i = m_redoIndex;
240         return m_redoIndexValid;
241 }