GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
15 / 16
93.8%
Branches:
15 / 22
68.2%
Functions:
1 / 1, 1 excl
100.0%

scene/edit_history.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file edit_history.h
3 /// @brief Undo and redo of scene edits, for the viewer.
4 ///
5 /// References:
6 /// - E. Gamma, R. Helm, R. Johnson and J. Vlissides, "Design Patterns", the Command pattern,
7 /// Addison-Wesley, 1994.
8 #pragma once
9
10 #include "ernie/scene/scene.h"
11
12 #include <cstddef>
13 #include <cstdint>
14 #include <map>
15 #include <optional>
16 #include <string>
17 #include <string_view>
18 #include <utility>
19 #include <vector>
20
21 namespace ernie {
22
23 /// @brief Undo and redo for the edits made through it: attributes set or cleared, prims defined,
24 /// removed with their descendants, or copied in. Each step records what it changes, so `Undo`
25 /// puts it back and `Redo` does it again.
26 ///
27 /// Continuous edits, as dragging a slider or a gizmo, merge into one step: an `open` edit of the
28 /// same attributes as the last step updates it until `Close`. Edits between `BeginGroup` and
29 /// `EndGroup` undo and redo together. Edits made to the scene directly are not recorded.
30 5 class EditHistory {
31 public:
32 /// @brief Sets attributes of a prim as one step, dropping the undone steps. With `open`, merges
33 /// into the last step if that is an open edit of the same attributes.
34 /// @throws std::invalid_argument as `Scene::Set`.
35 void Set(Scene& scene, const Path& path, std::vector<std::pair<std::string, Value>> edits,
36 bool open = false);
37 9 void Set(Scene& scene, const Path& path, std::string_view attribute, Value value,
38 bool open = false) {
39
6/6
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 8 times.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 1 time.
19 Set(scene, path, {{std::string(attribute), std::move(value)}}, open);
40
1/2
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
26 }
41 /// @brief Unauthors an attribute, back to its fallback.
42 void Clear(Scene& scene, const Path& path, std::string_view attribute);
43 /// @brief Defines a new prim; undoing removes it.
44 /// @throws std::invalid_argument as `Scene::Define`, or if a prim is there already.
45 void Define(Scene& scene, const Path& path, std::string_view type);
46 /// @brief Removes a prim and its descendants; undoing restores them, sharing their arrays.
47 /// @return Whether there was a prim.
48 bool Remove(Scene& scene, const Path& path);
49 /// @brief Copies a prim of `source` and its descendants to the same path of `scene`, as for
50 /// prims authored in a scratch scene first; undoing removes them.
51 /// @throws std::invalid_argument if `source` has no prim at `path` or `scene` has one.
52 void Add(Scene& scene, const Scene& source, const Path& path);
53
54 /// Groups the edits until `EndGroup` into one step. Groups nest; the outermost counts.
55 void BeginGroup();
56 void EndGroup();
57 /// Ends the open step, so the next edit starts a new one.
58 1 void Close() {
59
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 open_ = false;
60 }
61
62 14 bool CanUndo() const {
63
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
14 return next_ > 0;
64 }
65 6 bool CanRedo() const {
66
3/6
<unknown function 30>:
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
ernie::EditHistory::Set(ernie::Scene&, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::Value, bool):
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
6 return next_ < steps_.size();
67 }
68 /// @brief Undoes the last step or group; edits of prims removed since are skipped.
69 /// @return Whether there was one.
70 bool Undo(Scene& scene);
71 bool Redo(Scene& scene);
72 /// @return What `Undo` or `Redo` would do, as "/World/Cube xformOp:translate".
73 std::string UndoLabel() const;
74 std::string RedoLabel() const;
75 /// Forgets every step, as when the viewer switches scenes.
76 void Reset();
77 /// @return The steps recorded, a group's edits each counted.
78 1 std::size_t Size() const {
79
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 return steps_.size();
80 }
81
82 private:
83 /// One attribute's authored state: unset, a value, an array or time samples.
84 struct Cell {
85 std::optional<Value> value;
86 Tensor array;
87 std::vector<TimeSample> samples;
88 };
89 /// One prim of a subtree, enough to define it again.
90 5 struct PrimSnapshot {
91 Path path;
92 std::string type;
93 std::vector<std::string> apis;
94 std::map<std::string, Cell> attributes;
95 };
96 struct AttributeEdit {
97 std::string name;
98 Cell before;
99 Cell after;
100 };
101 ✗ struct Step {
102 Path path;
103 std::vector<AttributeEdit> attributes;
104 /// Structure steps: the subtree at `path` before and after, parents first; empty for none.
105 std::vector<PrimSnapshot> before;
106 std::vector<PrimSnapshot> after;
107 bool structural = false;
108 bool open = false;
109 /// Steps of one non-zero group undo together.
110 std::uint64_t group = 0;
111 };
112
113 static Cell Capture(const Scene& scene, PrimId prim, const std::string& attribute);
114 static void Apply(Scene& scene, PrimId prim, const std::string& attribute, const Cell& cell);
115 static std::vector<PrimSnapshot> Snapshot(const Scene& scene, const Path& path);
116 static void Restore(Scene& scene, const std::vector<PrimSnapshot>& prims);
117 static void Apply(Scene& scene, const Step& step, bool forward);
118 void Push(Step step);
119 bool Move(Scene& scene, bool forward);
120 static std::string Label(const Step& step);
121
122 std::vector<Step> steps_;
123 /// Steps before it are done; from it on, undone.
124 std::size_t next_ = 0;
125 bool open_ = false;
126 int groupDepth_ = 0;
127 std::uint64_t group_ = 0;
128 std::uint64_t nextGroup_ = 1;
129 };
130
131 } // namespace ernie
132