summaryrefslogtreecommitdiff
path: root/Other/NodeEditorExamples/Assets/UNEB/Editor/Actions/ActionManager.cs
blob: b0450b46be2a7f6e0361818176206eab8f3fcd3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

using System;
using System.Collections.Generic;
using UnityEngine;
using UNEB.Utility;

namespace UNEB
{
    /// <summary>
    /// Handles execution of actions, undo, and redo.
    /// </summary>
    public class ActionManager
    {
        private NodeEditorWindow _window;

        private FiniteStack<UndoableAction> _undoStack;
        private Stack<UndoableAction> _redoStack;

        // Caches the current multi-stage action that is currently executing.
        private MultiStageAction _activeMultiAction = null;

        public event Action OnUndo;
        public event Action OnRedo;

        public ActionManager(NodeEditorWindow w)
        {
            _undoStack = new FiniteStack<UndoableAction>(100);
            _redoStack = new Stack<UndoableAction>();

            _window = w;

            // Makes sure that the action cleans up after itself
            // when it is removed from the undo buffer.
            _undoStack.OnRemoveBottomItem += (action) =>
            {
                action.OnDestroy();
            };
        }

        public void Update()
        {
            if (IsRunningAction) {
                _activeMultiAction.Do();
            }
        }

        public bool IsRunningAction
        {
            get { return _activeMultiAction != null; }
        }

        /// <summary>
        /// Runs an action and stores it in the undo stack.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void RunUndoableAction<T>() where T : UndoableAction, new()
        {
            T action = new T();
            action.manager = this;

            if (action.Init()) {

                clearRedoStack();
                _undoStack.Push(action);
                action.Do();
            }
        }

        /// <summary>
        /// Starts a multi stage action but does not record it in the undo stack.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void StartMultiStageAction<T>() where T : MultiStageAction, new()
        {
            // Only run 1 multi-action at a time.
            if (_activeMultiAction != null) {
                return;
            }

            T action = new T();
            action.manager = this;

            if (action.Init()) {
                _activeMultiAction = action;
                _activeMultiAction.OnActionStart();
            }
        }

        /// <summary>
        /// Records the multi-stage action in the undo stack.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action"></param>
        public void FinishMultiStageAction()
        {
            if (_activeMultiAction == null) {
                return;
            }

            // We check if the action ended properly so it can be stored in undo.
            if (_activeMultiAction.OnActionEnd()) {

                clearRedoStack();
                _undoStack.Push(_activeMultiAction);
            }

            // There is no longer an active multi-stage action.
            _activeMultiAction = null;
        }

        public void UndoAction()
        {
            if (_undoStack.Count != 0) {

                var action = _undoStack.Pop();
                _redoStack.Push(action);

                action.Undo();

                if (OnUndo != null)
                    OnUndo();
            }
        }

        public void RedoAction()
        {
            if (_redoStack.Count != 0) {

                var action = _redoStack.Pop();
                _undoStack.Push(action);

                action.Redo();

                if (OnRedo != null)
                    OnRedo();
            }
        }

        public void Reset()
        {
            _activeMultiAction = null;
            clearUndoStack();
            clearRedoStack();
        }

        private void clearRedoStack()
        {
            foreach (var action in _redoStack) {
                action.OnDestroy();
            }

            _redoStack.Clear();
        }

        private void clearUndoStack()
        {
            foreach (var action in _undoStack) {
                action.OnDestroy();
            }

            _undoStack.Clear();
        }

        public NodeEditorWindow window
        {
            get { return _window; }
        }
    }
}