1 /* This file is part of Dilay
2  * Copyright © 2015-2018 Alexander Bau
3  * Use and redistribute under the terms of the GNU General Public License
4  */
5 #include <list>
6 #include <vector>
7 #include "config.hpp"
8 #include "dynamic/mesh.hpp"
9 #include "history.hpp"
10 #include "maybe.hpp"
11 #include "mesh.hpp"
12 #include "scene.hpp"
13 #include "sketch/mesh.hpp"
14 #include "sketch/path.hpp"
15 #include "state.hpp"
16 
17 namespace
18 {
19   struct SnapshotConfig
20   {
21     bool snapshotDynamicMeshes;
22     bool snapshotSketchMeshes;
23 
SnapshotConfig__anon82ebc8310111::SnapshotConfig24     SnapshotConfig (bool d, bool s)
25       : snapshotDynamicMeshes (d)
26       , snapshotSketchMeshes (s)
27     {
28       assert (this->snapshotDynamicMeshes || this->snapshotSketchMeshes);
29     }
30   };
31 
32   struct SceneSnapshot
33   {
34     const SnapshotConfig   config;
35     std::list<DynamicMesh> dynamicMeshes;
36     std::list<SketchMesh>  sketchMeshes;
37 
SceneSnapshot__anon82ebc8310111::SceneSnapshot38     SceneSnapshot (const SnapshotConfig& c)
39       : config (c)
40     {
41     }
42   };
43 
44   typedef std::list<SceneSnapshot> Timeline;
45 
sceneSnapshot(const Scene & scene,const SnapshotConfig & config)46   SceneSnapshot sceneSnapshot (const Scene& scene, const SnapshotConfig& config)
47   {
48     SceneSnapshot snapshot (config);
49 
50     if (config.snapshotDynamicMeshes)
51     {
52       scene.forEachConstMesh (
53         [&snapshot](const DynamicMesh& mesh) { snapshot.dynamicMeshes.emplace_back (mesh); });
54     }
55     if (config.snapshotSketchMeshes)
56     {
57       scene.forEachConstMesh (
58         [&snapshot](const SketchMesh& mesh) { snapshot.sketchMeshes.emplace_back (mesh); });
59     }
60     return snapshot;
61   }
62 
resetToSnapshot(const SceneSnapshot & snapshot,State & state)63   void resetToSnapshot (const SceneSnapshot& snapshot, State& state)
64   {
65     Scene& scene = state.scene ();
66 
67     if (snapshot.config.snapshotDynamicMeshes)
68     {
69       scene.deleteDynamicMeshes ();
70 
71       for (const DynamicMesh& mesh : snapshot.dynamicMeshes)
72       {
73         scene.newDynamicMesh (state.config (), mesh);
74       }
75     }
76     if (snapshot.config.snapshotSketchMeshes)
77     {
78       scene.deleteSketchMeshes ();
79 
80       for (const SketchMesh& mesh : snapshot.sketchMeshes)
81       {
82         scene.newSketchMesh (state.config (), mesh);
83       }
84     }
85   }
86 }
87 
88 struct History::Impl
89 {
90   unsigned int undoDepth;
91   Timeline     past;
92   Timeline     future;
93 
ImplHistory::Impl94   Impl (const Config& config) { this->runFromConfig (config); }
95 
snapshotAllHistory::Impl96   void snapshotAll (const Scene& scene) { this->snapshot (scene, SnapshotConfig (true, true)); }
97 
snapshotDynamicMeshesHistory::Impl98   void snapshotDynamicMeshes (const Scene& scene)
99   {
100     this->snapshot (scene, SnapshotConfig (true, false));
101   }
102 
snapshotSketchMeshesHistory::Impl103   void snapshotSketchMeshes (const Scene& scene)
104   {
105     this->snapshot (scene, SnapshotConfig (false, true));
106   }
107 
snapshotHistory::Impl108   void snapshot (const Scene& scene, const SnapshotConfig& config)
109   {
110     assert (undoDepth > 0);
111 
112     this->future.clear ();
113 
114     while (this->past.size () >= this->undoDepth)
115     {
116       this->past.pop_back ();
117     }
118     this->past.push_front (sceneSnapshot (scene, config));
119   }
120 
dropPastSnapshotHistory::Impl121   void dropPastSnapshot ()
122   {
123     if (this->past.empty () == false)
124     {
125       this->past.pop_front ();
126     }
127   }
128 
dropFutureSnapshotHistory::Impl129   void dropFutureSnapshot ()
130   {
131     if (this->future.empty () == false)
132     {
133       this->future.pop_front ();
134     }
135   }
136 
undoHistory::Impl137   void undo (State& state)
138   {
139     if (this->past.empty () == false)
140     {
141       const SnapshotConfig& config = this->past.front ().config;
142 
143       this->future.push_front (sceneSnapshot (state.scene (), config));
144       resetToSnapshot (this->past.front (), state);
145       this->past.pop_front ();
146     }
147   }
148 
redoHistory::Impl149   void redo (State& state)
150   {
151     if (this->future.empty () == false)
152     {
153       const SnapshotConfig& config = this->future.front ().config;
154 
155       this->past.push_front (sceneSnapshot (state.scene (), config));
156       resetToSnapshot (this->future.front (), state);
157       this->future.pop_front ();
158     }
159   }
160 
hasRecentDynamicMeshHistory::Impl161   bool hasRecentDynamicMesh () const
162   {
163     return this->past.empty () == false && this->past.front ().config.snapshotDynamicMeshes;
164   }
165 
forEachRecentDynamicMeshHistory::Impl166   void forEachRecentDynamicMesh (const std::function<void(const DynamicMesh&)>& f) const
167   {
168     assert (this->hasRecentDynamicMesh ());
169 
170     for (const DynamicMesh& m : this->past.front ().dynamicMeshes)
171     {
172       f (m);
173     }
174   }
175 
resetHistory::Impl176   void reset ()
177   {
178     this->past.clear ();
179     this->future.clear ();
180   }
181 
runFromConfigHistory::Impl182   void runFromConfig (const Config& config)
183   {
184     this->undoDepth = config.get<int> ("editor/undo-depth");
185   }
186 };
187 
188 DELEGATE1_BIG3 (History, const Config&)
189 DELEGATE1 (void, History, snapshotAll, const Scene&)
190 DELEGATE1 (void, History, snapshotDynamicMeshes, const Scene&)
191 DELEGATE1 (void, History, snapshotSketchMeshes, const Scene&)
192 DELEGATE (void, History, dropPastSnapshot)
193 DELEGATE (void, History, dropFutureSnapshot)
194 DELEGATE1 (void, History, undo, State&)
195 DELEGATE1 (void, History, redo, State&)
196 DELEGATE_CONST (bool, History, hasRecentDynamicMesh)
197 DELEGATE1_CONST (void, History, forEachRecentDynamicMesh,
198                  const std::function<void(const DynamicMesh&)>&)
199 DELEGATE (void, History, reset)
200 DELEGATE1 (void, History, runFromConfig, const Config&)
201