Unravel Engine C++ Reference
Loading...
Searching...
No Matches
inspector.cpp
Go to the documentation of this file.
1#include "inspector.h"
2#include <imgui/imgui_internal.h>
3
4namespace unravel
5{
6
7namespace
8{
9std::vector<property_layout*> stack;
10void push_layout_to_stack(property_layout* l)
11{
12 stack.push_back(l);
13}
14
15void pop_layout_from_stack(property_layout* l)
16{
17 stack.pop_back();
18}
19} // namespace
21{
22 return stack.back();
23}
24
26{
27 push_layout_to_stack(this);
28}
29
30property_layout::property_layout(const entt::meta_data& prop, bool columns /*= true*/)
31{
32 push_layout_to_stack(this);
33
34 set_data(prop, columns);
35
37}
38
39property_layout::property_layout(const std::string& name, bool columns /*= true*/)
40{
41 push_layout_to_stack(this);
42
43 set_data(name, {}, columns);
44
46}
47
48property_layout::property_layout(const std::string& name, const std::string& tooltip, bool columns /*= true*/)
49{
50 push_layout_to_stack(this);
51
52 set_data(name, tooltip, columns);
53
55}
56
57property_layout::property_layout(const std::string& name, const std::function<void()>& callback, bool columns /*= true*/)
58{
59 push_layout_to_stack(this);
60
61 callback_ = callback;
62 set_data(name, {}, columns);
63
65}
66
67
69{
70 pop_layout();
71
72 pop_layout_from_stack(this);
73}
74
75void property_layout::set_data(const entt::meta_data& prop, bool columns)
76{
77 auto name = entt::get_pretty_name(prop);
78
79 auto tooltip = entt::get_attribute_as<std::string>(prop, "tooltip");
80
81 set_data(name, tooltip, columns);
82
83}
84
85void property_layout::set_data(const std::string& name, const std::string& tooltip, bool columns)
86{
87 name_ = name;
88 tooltip_ = tooltip;
89 columns_ = columns;
90}
91
92void property_layout::push_layout(bool auto_proceed_to_next_column)
93{
94 pushed_ = true;
95
96 if(columns_)
97 {
98 auto avail = ImGui::GetContentRegionAvail();
99
100 columns_open_ = ImGui::BeginTable(("properties##" + name_).c_str(), 2);
101
102 if(columns_open_)
103 {
104
105 auto first_column = 0.325f;
106 ImGui::TableSetupColumn("##prop_column1", ImGuiTableColumnFlags_WidthFixed, avail.x * first_column);
107 ImGui::TableSetupColumn("##prop_column2", ImGuiTableColumnFlags_WidthFixed, avail.x * (1.0f - first_column));
108
109 ImGui::TableNextRow();
110 ImGui::TableNextColumn();
111 }
112 }
113
114 ImGui::AlignTextToFramePadding();
115 if(callback_)
116 {
117 callback_();
118 }
119 else
120 {
121 ImGui::TextUnformatted(name_.c_str());
122 }
123
124
125
126 if(ImGui::BeginPopupContextItem("Property Context Menu"))
127 {
128 if(ImGui::MenuItem(fmt::format("Reset {} to default", name_).c_str()))
129 {
130
131 }
132
133 ImGui::EndPopup();
134 }
135
136 if(!tooltip_.empty())
137 {
138 ImGui::SetItemTooltipEx("%s", tooltip_.c_str());
139 ImGui::SameLine();
140 ImGui::HelpMarker(tooltip_.c_str());
141 }
142
143
144
145 if(auto_proceed_to_next_column)
146 {
148 }
149}
150
152{
153 if(columns_open_)
154 {
155 ImGui::TableNextColumn();
156 }
157
158 ImGui::PushID(name_.c_str());
159 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
160}
161
162auto property_layout::push_tree_layout(ImGuiTreeNodeFlags flags) -> bool
163{
164 pushed_ = true;
165
166 if(columns_)
167 {
168 auto avail = ImGui::GetContentRegionAvail();
169
170 columns_open_ = ImGui::BeginTable(("properties##" + name_).c_str(), 2);
171
172 if(columns_open_)
173 {
174 auto first_column = 0.325f;
175 ImGui::TableSetupColumn("##prop_column1", ImGuiTableColumnFlags_WidthFixed, avail.x * first_column);
176 ImGui::TableSetupColumn("##prop_column2", ImGuiTableColumnFlags_WidthFixed, avail.x * (1.0f - first_column));
177
178 ImGui::TableNextRow();
179 ImGui::TableNextColumn();
180 }
181 }
182
183 ImGui::SetNextItemOpen(true, ImGuiCond_Appearing);
184 ImGui::AlignTextToFramePadding();
185 open_ = ImGui::TreeNodeEx(name_.c_str(), flags | ImGuiTreeNodeFlags_AllowOverlap);
186
187
188
189 if(ImGui::BeginPopupContextItem("Property Context Menu"))
190 {
191 if(ImGui::MenuItem(fmt::format("Reset {} to default", name_).c_str()))
192 {
193
194 }
195
196 ImGui::EndPopup();
197 }
198
199 if(!tooltip_.empty())
200 {
201 ImGui::SetItemTooltipEx("%s", tooltip_.c_str());
202 ImGui::SameLine();
203 ImGui::HelpMarker(tooltip_.c_str());
204 }
205
206 prepare_for_item();
207
208 return open_;
209}
210
212{
213 if(!pushed_)
214 {
215 return;
216 }
217
218 ImGui::PopID();
219 ImGui::PopItemWidth();
220
221 if(open_)
222 {
223 open_ = false;
224 ImGui::TreePop();
225 }
226
227 if(columns_)
228 {
229 columns_ = false;
230 if(columns_open_ && ImGui::TableGetColumnCount() > 1)
231 {
232 ImGui::EndTable();
233 }
234 }
235
236 pushed_ = false;
237}
238
239void inspector::before_inspect(const entt::meta_data& prop)
240{
241 layout_ = std::make_unique<property_layout>(prop);
242}
243
244void inspector::after_inspect(const entt::meta_data& prop)
245{
246 layout_.reset();
247}
248
249
250auto make_proxy(entt::meta_any& var, const std::string& name) -> meta_any_proxy
251{
252 meta_any_proxy proxy;
253 proxy.impl->get_name = [name]()
254 {
255 return name;
256 };
257 proxy.impl->getter = [var](entt::meta_any& result)
258 {
259 result = var;
260 return true;
261 };
262 proxy.impl->setter = [var](meta_any_proxy& proxy, const entt::meta_any& value, uint64_t execution_count)
263 {
264 entt::meta_any var;
265 if(proxy.impl->getter(var) && var)
266 {
267 return var.assign(value);
268 }
269 return false;
270 };
271 return proxy;
272}
273
274auto make_property_proxy(const meta_any_proxy& var_proxy, const entt::meta_data& prop) -> meta_any_proxy
275{
276 meta_any_proxy prop_proxy;
277 prop_proxy.impl->get_name = [var_proxy, prop]()
278 {
279 auto name = var_proxy.impl->get_name();
280 if(name.empty())
281 {
282 return entt::get_pretty_name(prop);
283 }
284 return fmt::format("{}/{}", name, entt::get_pretty_name(prop));
285 };
286 prop_proxy.impl->getter = [parent_proxy = var_proxy, prop](entt::meta_any& result)
287 {
288 entt::meta_any var;
289 if(parent_proxy.impl->getter(var) && var)
290 {
291 result = prop.get(var);
292 return true;
293 }
294 return false;
295 };
296 prop_proxy.impl->setter = [parent_proxy = var_proxy, prop](meta_any_proxy& proxy, const entt::meta_any& value, uint64_t execution_count) mutable
297 {
298 entt::meta_any var;
299 if(parent_proxy.impl->getter(var) && var)
300 {
301 prop.set(var, value);
302 return parent_proxy.impl->setter(parent_proxy, var, execution_count);
303 }
304 return false;
305 };
306 return prop_proxy;
307}
308} // namespace unravel
Manages ImGui layout for property inspection in the editor.
Definition inspector.h:19
void set_data(const entt::meta_data &prop, bool columns=true)
Updates layout data from meta property.
Definition inspector.cpp:75
property_layout()
Default constructor that registers this layout in the global stack.
Definition inspector.cpp:25
void push_layout(bool auto_proceed_to_next_column=true)
Initializes ImGui layout with tables and property label.
Definition inspector.cpp:92
static auto get_current() -> property_layout *
Gets the currently active property layout from the global stack.
Definition inspector.cpp:20
void pop_layout()
Cleans up ImGui state (IDs, tables, tree nodes)
void prepare_for_item()
Prepares ImGui for rendering the property value widget.
auto push_tree_layout(ImGuiTreeNodeFlags flags=0) -> bool
Creates a collapsible tree node layout for nested properties.
~property_layout()
Destructor that cleans up ImGui state and removes from stack.
Definition inspector.cpp:68
std::string name
Definition hub.cpp:27
const char * tooltip
auto get_pretty_name(const meta_type &t) -> std::string
auto get_attribute_as< std::string >(const meta_custom &custom, const char *name) -> std::string
Definition reflection.h:35
auto make_property_proxy(const meta_any_proxy &var_proxy, const entt::meta_data &prop) -> meta_any_proxy
auto make_proxy(entt::meta_any &var, const std::string &name) -> meta_any_proxy
Creates a simple proxy for direct variable access.
float x
std::unique_ptr< property_layout > layout_
Layout manager for this inspector's UI.
Definition inspector.h:292
virtual void before_inspect(const entt::meta_data &prop)
Called before inspecting a property to set up layout.
virtual void after_inspect(const entt::meta_data &prop)
Called after inspecting a property to clean up layout.
Safe deferred property access proxy for arbitrary object properties.
Definition inspector.h:198
std::shared_ptr< meta_any_proxy_impl > impl
Definition inspector.h:221