Unravel Engine C++ Reference
Loading...
Searching...
No Matches
editing_manager.h
Go to the documentation of this file.
1#pragma once
2#include "editor_actions.h"
3#include "uuid/uuid.h"
4
5#include <base/basetypes.hpp>
6#include <context/context.hpp>
9#include <math/math.h>
10#include <uuid/uuid.h>
11
15#include "actions/actions.h"
16
17namespace unravel
18{
19
21{
23 std::vector<std::shared_ptr<editing_action_t>> pending_actions; // Actions waiting to be executed
24 std::stack<bool> undo_stack_enabled;
25
26 struct selection
27 {
28 std::vector<entt::meta_any> objects{entt::meta_any{}};
29 };
30
31 struct focused
32 {
33 entt::meta_any object;
34 int frames{};
35
36 fs::path focus_path{};
37 };
38
39 struct snap
40 {
42 math::vec3 translation_snap = {1.0f, 1.0f, 1.0f};
44 float rotation_degree_snap = 15.0f;
46 float scale_snap = 0.1f;
47 };
48
49 struct grid
50 {
51 float opacity = 1.0f;
52 bool depth_aware {true};
53 };
54
56 {
57 float opacity = 0.75f;
58 float size = 0.5f;
59 bool depth_aware {false};
60 };
61
63 {
64 int num_nodes = 2;
65 };
66
73
74 enum class editing_mode
75 {
76 scene,
77 prefab
78 };
79
80 enum class save_option
81 {
82 yes, // Save changes
83 no, // Don't save changes
84 prompt // Prompt the user whether to save changes
85 };
86
87 auto init(rtti::context& ctx) -> bool;
88 auto deinit(rtti::context& ctx) -> bool;
89
93 void on_script_recompile(rtti::context& ctx, const std::string& protocol, uint64_t version);
95
96 void sync_prefab_entity(rtti::context& ctx, entt::handle entity, const asset_handle<prefab>& pfb);
98 auto get_select_mode() const -> select_mode;
99
100 //-----------------------------------------------------------------------------
101 // Name : select ()
105 //-----------------------------------------------------------------------------
106 void focus(entt::meta_any object);
107 void focus_path(const fs::path& object);
108
109 //-----------------------------------------------------------------------------
110 // Name : unselect ()
114 //-----------------------------------------------------------------------------
115 void unselect(bool clear_selection_tools = true);
116 void unfocus();
117
118 //-----------------------------------------------------------------------------
119 // Name : try_unselect ()
123 //-----------------------------------------------------------------------------
124 template<typename T>
126 {
128 {
129 unselect();
130 }
131 }
132
133 template<typename T>
135 {
136 if(focused_data.object.type() == entt::resolve<T>())
137 {
138 unfocus();
139 }
140 }
141
142 template<typename T>
143 auto is_selected(const T& entry) -> bool
144 {
145 for(const auto& object : selection_data.objects)
146 {
147 if(is_selected_impl(entry, object))
148 {
149 return true;
150 }
151 }
152 return false;
153 }
154
155 template<typename T>
156 auto is_selected_type() -> bool
157 {
158 const auto& selected = get_active_selection();
159
160 return selected && selected.type() == entt::resolve<T>();
161 }
162
163 auto get_active_selection() const -> const entt::meta_any&
164 {
165 return selection_data.objects.back();
166 }
167
168 auto get_active_selection() -> entt::meta_any&
169 {
170 return selection_data.objects.back();
171 }
172
173 auto get_selections() const -> hpp::span<const entt::meta_any>
174 {
175 return selection_data.objects;
176 }
177
178 auto get_selections() -> hpp::span<entt::meta_any>
179 {
180 return selection_data.objects;
181 }
182
183 template<typename T>
184 auto get_active_selection_as() const -> const T&
185 {
186 return get_active_selection().cast<const T&>();
187 }
188
189 template<typename T>
191 {
192 auto& active = get_active_selection();
193 if(active.type() == entt::resolve<T>())
194 {
195 return &active.cast<T&>();
196 }
197
198 return nullptr;
199 }
200
201 template<typename T>
202 auto try_get_active_selection_as() const -> const T*
203 {
204 const auto& active = get_active_selection();
205 if(active.type() == entt::resolve<T>())
206 {
207 return &active.cast<T&>();
208 }
209
210 return nullptr;
211 }
212
213 template<typename T>
214 auto try_get_selections_as() const -> std::vector<const T*>
215 {
216 std::vector<T*> result;
217
218 for(const auto& obj : selection_data.objects)
219 {
220 if(obj.type() == entt::resolve<T>())
221 {
222 result.emplace_back(&obj.cast<T&>());
223 }
224 }
225
226 return result;
227 }
228
229 template<typename T>
230 auto try_get_selections_as() -> std::vector<T*>
231 {
232 std::vector<T*> result;
233
234 for(auto& obj : selection_data.objects)
235 {
236 if(obj.type() == entt::resolve<T>())
237 {
238 result.emplace_back(&obj.cast<T&>());
239 }
240 }
241
242 return result;
243 }
244
245 template<typename T>
246 auto try_get_selections_as_copy() const -> std::vector<T>
247 {
248 std::vector<T> result;
249
250 for(const auto& obj : selection_data.objects)
251 {
252 if(obj.type() == entt::resolve<T>())
253 {
254 result.emplace_back(obj.cast<T>());
255 }
256 }
257
258 return result;
259 }
260
261 template<typename T>
262 auto is_focused(const T& entry) -> bool
263 {
264 const auto& focused = focused_data.object;
265
266 if(focused.type() != entt::resolve<T>())
267 {
268 return false;
269 }
270
271 return focused.cast<T>() == entry;
272 }
273
274 template<typename T>
275 auto is_focused(const asset_handle<T>& entry) -> bool
276 {
277 const auto& focused = focused_data.object;
278
279 if(focused.type() == entt::resolve<asset_handle<T>>())
280 {
281 return focused.cast<asset_handle<T>>() == entry;
282 }
283
284 if(focused.type() != entt::resolve<fs::path>())
285 {
286 return false;
287 }
288
289 return focused.cast<fs::path>() == fs::resolve_protocol(entry.id());
290 }
291
292 template<typename T>
293 auto try_get_active_focus_as() const -> const T*
294 {
295 const auto& focused = focused_data.object;
296 if(focused.type() == entt::resolve<T>())
297 {
298 return focused.try_cast<T>();
299 }
300
301 return nullptr;
302 }
303
304 template<typename T>
305 void unselect(const T& entry)
306 {
307 std::erase_if(selection_data.objects,
308 [&](const auto& el)
309 {
310 return is_selected_impl(entry, el);
311 });
312 sanity_check_selection_data();
313
314 }
315
316 template<typename T>
318 {
319 focus(entry);
320 switch(mode)
321 {
323 {
324 selection_data.objects.clear();
325 selection_data.objects.emplace_back(entry);
326 break;
327 }
329 {
330 if(!selection_data.objects.empty())
331 {
332 if(!selection_data.objects.back())
333 {
334 selection_data.objects.clear();
335 }
336 }
337
338 if(!is_selected(entry))
339 {
340 selection_data.objects.emplace_back(entry);
341 }
342 else
343 {
345 }
346 break;
347 }
349 {
350 if(!selection_data.objects.empty())
351 {
352 if(!selection_data.objects.back())
353 {
354 selection_data.objects.clear();
355 }
356 }
357
358 if(!is_selected(entry))
359 {
360 selection_data.objects.emplace_back(entry);
361 }
362 else
363 {
364 // make it active
366
367 if(!selection_data.objects.back())
368 {
369 selection_data.objects.clear();
370 }
371 selection_data.objects.emplace_back(entry);
372 }
373 break;
374 }
375 default:
376 break;
377 }
378
379 sanity_check_selection_data();
380
381 // auto& ctx = engine::context();
382 // auto& ui_ev = ctx.get_cached<ui_events>();
383 // ui_ev.on_selection_changed();
384 }
385
386 // Unified action system - all actions go through this interface
387 // Whether an action is undoable depends on the action's is_undoable() method
388 //
389 // Usage examples:
390 // 1. Non-undoable action: do_action("Quick Fix", []() { /* do something */ });
391 // 2. Undoable action: do_action("Move", []() { move(); }, []() { restore(); });
392 // 3. Custom action: do_action<transform_move_action_t>("Move Entity", entity, old_pos, new_pos);
393 // 4. Manual undo/redo: undo(), redo(), can_undo(), can_redo()
394
395 // Add an action with a lambda/function (non-undoable)
396 void do_action(const std::string& name, const std::function<void()>& action);
397
398 // Add an action with both do and undo lambdas (undoable)
399 void do_action(const std::string& name, const std::function<void()>& do_action, const std::function<void()>& undo_action);
400
401 // Add any action object (undoable or non-undoable determined by action itself)
402 void do_action(const std::string& name, std::shared_ptr<editing_action_t> action);
403
404 template<typename ActionType, typename... Args>
405 void do_action(const std::string& name, Args&&... args)
406 {
407 auto action = std::make_shared<ActionType>(std::forward<Args>(args)...);
408 do_action(name, std::move(action));
409 }
410
411 void queue_action(const std::string& name, const std::function<void()>& action);
412
413 // Add an action with both do and undo lambdas (undoable)
414 void queue_action(const std::string& name, const std::function<void()>& do_action, const std::function<void()>& undo_action);
415
416 // Add any action object (undoable or non-undoable determined by action itself)
417 void queue_action(const std::string& name, std::shared_ptr<editing_action_t> action);
418
419 template<typename ActionType, typename... Args>
420 void queue_action(const std::string& name, Args&&... args)
421 {
422 auto action = std::make_shared<ActionType>(std::forward<Args>(args)...);
423 queue_action(name, std::move(action));
424 }
425
426 void add_action(const std::string& name, std::shared_ptr<editing_action_t> action, bool immediate = true);
427
428
429 void push_undo_stack_enabled(bool enabled);
431
432 // Execute all pending actions (called automatically each frame)
433 void execute_actions();
434
435 // Undo/Redo operations
436 void undo();
437 void redo();
438 auto can_undo() const -> bool { return undo_stack.can_undo(); }
439 auto can_redo() const -> bool { return undo_stack.can_redo(); }
440
441
442 // Pending actions management
443 auto has_pending_actions() const -> bool { return !pending_actions.empty(); }
444 auto get_pending_actions_count() const -> size_t { return pending_actions.size(); }
445
446 auto has_unsaved_changes() const -> bool { return has_unsaved_changes_; }
447 void clear_unsaved_changes() { has_unsaved_changes_ = false; }
448
449 void clear();
450
451 // Prefab editing mode methods
452 void enter_prefab_mode(rtti::context& ctx, const asset_handle<prefab>& prefab, bool auto_save = false);
454 auto is_prefab_mode() const -> bool { return current_mode == editing_mode::prefab; }
456
457 // Returns the active scene based on the current edit mode
458 auto get_active_scene(rtti::context& ctx) -> scene*;
459
461 bool show_grid = true;
463 bool show_icon_gizmos = true;
467 ImGuizmo::OPERATION operation = ImGuizmo::TRANSLATE;
469 ImGuizmo::MODE mode = ImGuizmo::LOCAL;
472
474
479
481
482 // Current editing mode
484
485 // Currently edited prefab
487
488 // The entity created from the prefab that we're editing
489 entt::handle prefab_entity;
490
491 // Separate scene for prefab editing
492 scene prefab_scene{"prefab_scene"};
493
494
495 private:
496 template<typename T>
497 auto is_selected_impl(const T& entry, const entt::meta_any& selected) -> bool
498 {
499 if(selected.type() != entt::resolve<T>())
500 {
501 return false;
502 }
503
504 return selected.cast<const T&>() == entry;
505 }
506
507 void sanity_check_selection_data()
508 {
509 if(selection_data.objects.empty())
510 {
511 selection_data = {};
512 }
513 }
514 struct scene_cache
515 {
516 scene* scn = nullptr;
517 std::stringstream cache;
518 asset_handle<scene_prefab> cache_source;
519 };
520
521 struct selection_cache
522 {
523 std::vector<hpp::uuid> uids;
524 };
525
526 std::map<std::string, scene_cache> caches_;
527 selection_cache selection_cache_;
528 void save_selection(rtti::context& ctx);
529 void save_checkpoint(rtti::context& ctx, scene_cache& cache);
530 void load_checkpoint(rtti::context& ctx, scene_cache& cache, bool recover_selection = false);
531
532 std::shared_ptr<int> sentinel_ = std::make_shared<int>(0);
533
534 bool waiting_for_compilation_before_play_{};
535 bool has_unsaved_changes_;
536
537
538 // Prompts the user to save changes and returns true if changes should be saved
539 auto prompt_save_changes(rtti::context& ctx, const std::function<void()>& on_save, const std::function<void()>& on_continue) -> bool;
540};
541} // namespace unravel
542
std::chrono::duration< float > delta_t
std::string name
Definition hub.cpp:27
Definition cache.hpp:11
path resolve_protocol(const path &_path)
Given the specified path/filename, resolve the final full filename. This will be based on either the ...
entt::entity entity
Represents a handle to an asset, providing access and management functions.
std::vector< entt::meta_any > objects
auto has_pending_actions() const -> bool
auto is_prefab_mode() const -> bool
auto get_active_scene(rtti::context &ctx) -> scene *
auto get_selections() const -> hpp::span< const entt::meta_any >
auto try_get_active_selection_as() -> T *
bool show_grid
enable editor grid
void on_play_after_end(rtti::context &ctx)
auto is_focused(const T &entry) -> bool
auto try_get_selections_as() const -> std::vector< const T * >
auto get_select_mode() const -> select_mode
bool wireframe_selection
enable wireframe selection
ImGuizmo::OPERATION operation
current manipulation gizmo operation.
void push_undo_stack_enabled(bool enabled)
void unselect(const T &entry)
ImGuizmo::MODE mode
current manipulation gizmo space.
void queue_action(const std::string &name, Args &&... args)
void focus_path(const fs::path &object)
auto get_selections() -> hpp::span< entt::meta_any >
auto init(rtti::context &ctx) -> bool
billboard_gizmos billboard_data
void on_play_before_begin(rtti::context &ctx)
auto can_undo() const -> bool
void on_frame_update(rtti::context &ctx, delta_t)
void on_script_recompile(rtti::context &ctx, const std::string &protocol, uint64_t version)
auto is_selected_type() -> bool
auto has_unsaved_changes() const -> bool
auto is_selected(const T &entry) -> bool
auto get_active_selection() const -> const entt::meta_any &
std::vector< std::shared_ptr< editing_action_t > > pending_actions
auto get_active_selection_as() const -> const T &
auto can_redo() const -> bool
void try_unselect()
Clears the selection data if it maches the type.
bool show_icon_gizmos
enable editor icon gizmos
auto try_get_active_focus_as() const -> const T *
void sync_prefab_entity(rtti::context &ctx, entt::handle entity, const asset_handle< prefab > &pfb)
selection selection_data
selection data containing selected object
void queue_action(const std::string &name, const std::function< void()> &action)
auto try_get_active_selection_as() const -> const T *
void do_action(const std::string &name, const std::function< void()> &action)
auto get_active_selection() -> entt::meta_any &
auto try_get_selections_as_copy() const -> std::vector< T >
void sync_prefab_instances(rtti::context &ctx, scene *scn)
void on_prefab_updated(const asset_handle< prefab > &pfb)
auto try_get_selections_as() -> std::vector< T * >
void enter_prefab_mode(rtti::context &ctx, const asset_handle< prefab > &prefab, bool auto_save=false)
std::stack< bool > undo_stack_enabled
void do_action(const std::string &name, Args &&... args)
void select(const T &entry, select_mode mode=select_mode::normal)
auto deinit(rtti::context &ctx) -> bool
void add_action(const std::string &name, std::shared_ptr< editing_action_t > action, bool immediate=true)
void focus(entt::meta_any object)
Selects an object. Can be anything.
auto get_pending_actions_count() const -> size_t
auto is_focused(const asset_handle< T > &entry) -> bool
void exit_prefab_mode(rtti::context &ctx, save_option save_changes=save_option::prompt)
inverse_kinematics ik_data
void save_prefab_changes(rtti::context &ctx)
asset_handle< prefab > edited_prefab
snap snap_data
snap data containging various snap options
void unselect(bool clear_selection_tools=true)
Clears the selection data.
Represents a generic prefab with a buffer for serialized data.
Definition prefab.h:18
Represents a scene in the ACE framework, managing entities and their relationships.
Definition scene.h:21
auto can_undo() const -> bool
auto can_redo() const -> bool
cache_t cache
Definition uniform.cpp:15