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