Unravel Engine C++ Reference
Loading...
Searching...
No Matches
composite_action.cpp
Go to the documentation of this file.
1#include "composite_action.h"
2
3namespace unravel
4{
5
6void composite_action_t::add_sub_action(std::shared_ptr<editing_action_t> action)
7{
8 if (action)
9 {
10
11 if(!name.empty())
12 {
13 name += "/";
14 }
15
16 name += action->get_name();
17
18 sub_actions.push_back(std::move(action));
19 }
20}
21
23{
24 for (auto& action : sub_actions)
25 {
26 if (action)
27 {
28 action->do_action();
29 }
30 }
31}
32
34{
35 // Undo in reverse order
36 for (auto it = sub_actions.rbegin(); it != sub_actions.rend(); ++it)
37 {
38 if (*it)
39 {
40 (*it)->undo_action();
41 }
42 }
43}
44
45auto composite_action_t::is_valid() const -> bool
46{
47 for (auto& action : sub_actions)
48 {
49 if (!action->is_valid())
50 {
51 return false;
52 }
53 }
54 return true;
55}
56
57auto composite_action_t::is_mergeable(const editing_action_t& previous) const -> bool
58{
59 // Default: composite actions with same type can try to merge their sub-actions
60 const auto& prev_composite_action = static_cast<const composite_action_t&>(previous);
61
62 if(sub_actions.size() != prev_composite_action.sub_actions.size())
63 {
64 return false;
65 }
66
67 bool all_sub_actions_can_merge = true;
68 for (size_t i = 0; i < sub_actions.size() && i < prev_composite_action.sub_actions.size(); ++i)
69 {
70 if (sub_actions[i] && prev_composite_action.sub_actions[i] &&
71 sub_actions[i]->get_meta_type() == prev_composite_action.sub_actions[i]->get_meta_type())
72 {
73 if(!sub_actions[i]->is_mergeable(*prev_composite_action.sub_actions[i]))
74 {
75 all_sub_actions_can_merge = false;
76 break;
77 }
78 }
79 }
80
81 return all_sub_actions_can_merge;
82}
83
85{
86 // Default: no merging for composite actions (derived classes should implement)
87
88 const auto& prev_composite_action = static_cast<const composite_action_t&>(previous);
89
90 // Merge corresponding sub-actions
91 for (size_t i = 0; i < sub_actions.size() && i < prev_composite_action.sub_actions.size(); ++i)
92 {
93 if (sub_actions[i] && prev_composite_action.sub_actions[i] &&
94 sub_actions[i]->get_meta_type() == prev_composite_action.sub_actions[i]->get_meta_type())
95 {
96 sub_actions[i]->merge_with(*prev_composite_action.sub_actions[i]);
97 }
98 }
99}
100
102{
103 for (auto& action : sub_actions)
104 {
105 action->draw_in_inspector(ctx);
106 }
107}
108
109void sequence_action_t::add_step(std::function<std::shared_ptr<editing_action_t>()> factory)
110{
111 if(factory)
112 {
113 step_factories.push_back(std::move(factory));
114 }
115}
116
118{
119 if(!first_run_done)
120 {
121 // First execution: invoke factories in order. Each factory runs AFTER the preceding
122 // sub-action has executed, so it can reference handles/values produced upstream.
123 for(auto& factory : step_factories)
124 {
125 if(!factory)
126 {
127 continue;
128 }
129 auto action = factory();
130 if(!action)
131 {
132 continue;
133 }
134 action->do_action();
135 sub_actions.push_back(std::move(action));
136 }
137 step_factories.clear();
138 first_run_done = true;
139 return;
140 }
141
142 // Redo path: replay captured sub-actions in order. Each sub-action owns its own
143 // first-vs-subsequent logic (e.g. create_entities_action_t restores from snapshot).
144 for(auto& action : sub_actions)
145 {
146 if(action)
147 {
148 action->do_action();
149 }
150 }
151}
152
154{
155 // Undo in reverse order so later steps are unwound before earlier ones.
156 for(auto it = sub_actions.rbegin(); it != sub_actions.rend(); ++it)
157 {
158 if(*it)
159 {
160 (*it)->undo_action();
161 }
162 }
163}
164
165auto sequence_action_t::is_valid() const -> bool
166{
167 if(!first_run_done)
168 {
169 return !step_factories.empty();
170 }
171 if(sub_actions.empty())
172 {
173 return false;
174 }
175 for(const auto& action : sub_actions)
176 {
177 if(!action || !action->is_valid())
178 {
179 return false;
180 }
181 }
182 return true;
183}
184
185auto sequence_action_t::is_mergeable(const editing_action_t& /*previous*/) const -> bool
186{
187 return false;
188}
189
191{
192 for(auto& action : sub_actions)
193 {
194 if(action)
195 {
196 action->draw_in_inspector(ctx);
197 }
198 }
199}
200
201} // namespace unravel
std::string name
Definition hub.cpp:33
void add_sub_action(std::shared_ptr< editing_action_t > action)
void draw_in_inspector(rtti::context &ctx) override
void merge_with(const editing_action_t &previous) override
auto is_valid() const -> bool override
auto is_mergeable(const editing_action_t &previous) const -> bool override
std::vector< std::shared_ptr< editing_action_t > > sub_actions
void draw_in_inspector(rtti::context &ctx) override
auto is_mergeable(const editing_action_t &previous) const -> bool override
std::vector< std::shared_ptr< editing_action_t > > sub_actions
Captured sub-actions after first execution, replayed on redo and reversed on undo.
auto is_valid() const -> bool override
std::vector< std::function< std::shared_ptr< editing_action_t >()> > step_factories
Factories evaluated lazily on the first execution. Cleared once consumed.
void add_step(std::function< std::shared_ptr< editing_action_t >()> factory)
Append a step to the sequence. Factory is invoked only on the first execution.