Unravel Engine C++ Reference
Loading...
Searching...
No Matches
project_settings_panel.cpp
Go to the documentation of this file.
2#include "../panel.h"
3#include "../panels_defs.h"
4
8
9#include <filedialog/filedialog.h>
10#include <imgui/imgui.h>
11#include <imgui/imgui_internal.h>
12
13#include <imgui_widgets/keyboard/imgui_keyboard.h>
14#include <imgui_widgets/keyboard/imgui_mouse.h>
15#include <imgui_widgets/keyboard/imgui_gamepad.h>
16
18
19namespace unravel
20{
21
22namespace
23{
24
25auto to_os_key(input::key_code code) -> os::key::code
26{
27 return static_cast<os::key::code>(code);
28}
29
30auto to_os_key(int32_t code) -> os::key::code
31{
32 return static_cast<os::key::code>(code);
33}
34
35auto from_os_key(os::key::code code) -> input::key_code
36{
37 return static_cast<input::key_code>(code);
38}
39
40auto from_os_key(int32_t code) -> input::key_code
41{
42 return static_cast<input::key_code>(code);
43}
44
45template<typename EnumT, typename ToStringFn>
46auto ImGuiEnumCombo(const char* label,
47 EnumT& current_value,
48 const EnumT* all_values,
49 size_t count,
50 ToStringFn stringify) -> bool
51{
52 // Convert current value to a display name
53 std::string preview_text = stringify(current_value);
54
55 bool changed = false;
56 if(ImGui::BeginCombo(label, preview_text.c_str()))
57 {
58 for(size_t i = 0; i < count; ++i)
59 {
60 EnumT candidate = all_values[i];
61 bool is_selected = (candidate == current_value);
62 if(ImGui::Selectable(stringify(candidate).c_str(), is_selected))
63 {
64 // If user selected a different value
65 if(candidate != current_value)
66 {
67 current_value = candidate;
68 changed = true;
69 }
70 }
71
72 // Set focus if this is the currently selected item
73 if(is_selected)
74 {
75 ImGui::SetItemDefaultFocus();
76 }
77 }
78 ImGui::EndCombo();
79 }
80
81 return changed;
82}
83
84
85auto ImGuiKeySelector(const char* label,
86 os::key::code& selected_value,
87 const char* popup_id = "Key Selector") -> bool
88{
89 std::vector<std::string> names;
90 std::vector<const char*> names_cstr;
91
92 ImGui::PushID(label);
93
94
95 // The button text: what is the current selection's name?
96 std::string current_name = os::key::to_string(selected_value);
97 if(current_name.empty())
98 {
99 current_name = "None";
100 }
101
102 // If user clicks, open the popup
103 bool selection_changed = false;
104 if(ImGui::Button(current_name.c_str(), ImVec2(150.0f, ImGui::GetFrameHeight())))
105 {
106 ImGui::OpenPopup(popup_id);
107 }
108 std::string desc = {};
109 if(!desc.empty())
110 {
111 ImGui::SetItemTooltipEx("%s", desc.c_str());
112 }
113
114 ImGui::SameLine();
115 ImGui::TextUnformatted(label);
116
117 ImGuiWindow* window = ImGui::GetCurrentWindow();
118 const ImGuiViewport* viewport = window->WasActive ? window->Viewport : ImGui::GetMainViewport();
119 ImGui::SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
120 if(ImGui::BeginPopup(popup_id, ImGuiWindowFlags_Popup))
121 {
122 ImKeyboard::Highlight(ImGui_ImplOSPP_KeycodeToImGuiKey(selected_value), true);
123 ImKeyboard::Keyboard(ImKeyboard::ImGuiKeyboardLayout_Qwerty, ImKeyboard::ImGuiKeyboardFlags_Recordable);
124
125 auto recorded_keys = ImKeyboard::GetRecordedKeys();
126 for(auto& key : recorded_keys)
127 {
128 selected_value = ImGui_ImplOSPP_ImGuiKeyToKeycode(key);
129
130 selection_changed = true;
131 }
132 ImKeyboard::ClearHighlights();
133 ImKeyboard::ClearRecorded();
134
135 ImGui::EndPopup();
136 }
137
138 ImGui::PopID();
139
140 return selection_changed;
141}
142
143
144template<typename EnumT, typename ToStringFn, typename FromIntFn, typename GetDescriptionFn>
145auto ImGuiEnumSelector(const char* label,
146 EnumT& selected_value,
147 int enum_count,
148 ToStringFn stringify,
149 FromIntFn from_int,
150 GetDescriptionFn get_description,
151 const char* popup_id = "Enum Selector") -> bool
152{
153 std::vector<std::string> names;
154 std::vector<const char*> names_cstr;
155
156 static ImGuiTextFilter filter;
157
158 ImGui::PushID(label);
159 // Lazy initialization
160 {
161 names.reserve(enum_count);
162 for(int i = 0; i < enum_count; ++i)
163 {
164 auto e = from_int(i);
165 names.push_back(stringify(e));
166 }
167
168 // Build the const char* array
169 names_cstr.reserve(names.size());
170 for(const auto& name : names)
171 {
172 names_cstr.push_back(name.c_str());
173 }
174 }
175
176 // The button text: what is the current selection's name?
177 std::string current_name = stringify(selected_value);
178 if(current_name.empty())
179 {
180 current_name = "None";
181 }
182
183 // If user clicks, open the popup
184 bool selection_changed = false;
185 if(ImGui::Button(current_name.c_str(), ImVec2(150.0f, ImGui::GetFrameHeight())))
186 {
187 // Clear the filter
188 filter.Clear();
189 ImGui::OpenPopup(popup_id);
190 }
191 std::string desc = get_description(selected_value);
192 if(!desc.empty())
193 {
194 ImGui::SetItemTooltipEx("%s", desc.c_str());
195 }
196
197 ImGui::SameLine();
198 ImGui::TextUnformatted(label);
199
200 // The actual popup with a filter input and a list of items
201 if(ImGui::BeginPopup(popup_id))
202 {
203 if(ImGui::IsWindowAppearing())
204 {
205 ImGui::SetKeyboardFocusHere();
206 }
207
208 // Draw filter input box
209 ImGui::DrawFilterWithHint(filter, ICON_MDI_SELECT_SEARCH " Search...", 150.0);
210 ImGui::DrawItemActivityOutline();
211
212 ImGui::Separator();
213
214 // We create a scrolling region for the items
215 if(ImGui::BeginChild("Enum Selector Context", ImVec2(0, 200.0f), true))
216 {
217 for(int i = 0; i < enum_count; ++i)
218 {
219 if(names[i].empty())
220 {
221 continue;
222 }
223
224 // If it doesn't pass the filter, skip
225 if(!filter.PassFilter(names[i].c_str()))
226 {
227 continue;
228 }
229
230 // Check if it's the currently selected
231 bool is_selected = (static_cast<int>(selected_value) == i);
232 if(ImGui::Selectable(names[i].c_str(), is_selected))
233 {
234 // The user picked something new
235 selected_value = from_int(i);
236 selection_changed = true;
237 ImGui::CloseCurrentPopup();
238 }
239
240 std::string desc = get_description(from_int(i));
241 if(!desc.empty())
242 {
243 ImGui::SetItemTooltipEx("%s", desc.c_str());
244 ImGui::SameLine();
245 ImGui::TextDisabled("%s", "(?)");
246 // ImGui::HelpMarker(desc.c_str());
247 }
248 }
249 ImGui::EndChild();
250 }
251
252 ImGui::EndPopup();
253 }
254
255 ImGui::PopID();
256
257 return selection_changed;
258}
259
260void draw_application_settings(rtti::context& ctx)
261{
262 auto& pm = ctx.get_cached<project_manager>();
263 auto& settings = pm.get_settings();
264
265 ImGui::PushItemWidth(150.0f);
266
267 if(inspect(ctx, settings.app).edit_finished)
268 {
269 pm.save_project_settings(ctx);
270 }
271
272 ImGui::PopItemWidth();
273}
274
275void draw_resolution_settings(rtti::context& ctx)
276{
277 auto& pm = ctx.get_cached<project_manager>();
278 auto& settings = pm.get_settings();
279
280 ImGui::PushItemWidth(150.0f);
281
282 if(inspect(ctx, settings.resolution).edit_finished)
283 {
284 pm.save_project_settings(ctx);
285 }
286
287 ImGui::PopItemWidth();
288}
289
290void draw_graphics_settings(rtti::context& ctx)
291{
292 auto& pm = ctx.get_cached<project_manager>();
293 auto& settings = pm.get_settings();
294
295 ImGui::PushItemWidth(150.0f);
296
297 if(inspect(ctx, settings.graphics).edit_finished)
298 {
299 pm.save_project_settings(ctx);
300 }
301
302 ImGui::PopItemWidth();
303}
304
305void draw_splash_settings(rtti::context& ctx)
306{
307 auto& pm = ctx.get_cached<project_manager>();
308 auto& settings = pm.get_settings();
309 ImGui::PushItemWidth(150.0f);
310 if(inspect(ctx, settings.splash).edit_finished)
311 {
312 pm.save_project_settings(ctx);
313 }
314 ImGui::PopItemWidth();
315}
316
317void draw_standalone_settings(rtti::context& ctx)
318{
319 auto& pm = ctx.get_cached<project_manager>();
320 auto& settings = pm.get_settings();
321
322 ImGui::PushItemWidth(150.0f);
323
324 if(inspect(ctx, settings.standalone).edit_finished)
325 {
326 pm.save_project_settings(ctx);
327 }
328
329 ImGui::PopItemWidth();
330}
331
332void draw_layers_settings(rtti::context& ctx)
333{
334 auto& pm = ctx.get_cached<project_manager>();
335 auto& settings = pm.get_settings();
336
337 ImGui::PushItemWidth(150.0f);
338
339 if(inspect(ctx, settings.layer).edit_finished)
340 {
341 pm.save_project_settings(ctx);
342 }
343
344 ImGui::PopItemWidth();
345}
346
347void draw_asset_settings(rtti::context& ctx)
348{
349 auto& pm = ctx.get_cached<project_manager>();
350 auto& settings = pm.get_settings();
351
352 ImGui::PushItemWidth(150.0f);
353
354 if(inspect(ctx, settings.assets.texture).edit_finished)
355 {
356 pm.save_project_settings(ctx);
357 }
358
359 if(ImGui::Button("Recompile Textures"))
360 {
362 }
363
364 ImGui::PopItemWidth();
365}
366
367void draw_input_settings(rtti::context& ctx)
368{
369 auto& pm = ctx.get_cached<project_manager>();
370 auto& settings = pm.get_settings();
371
372 int total_inputs = 0;
373
374 inspect_result result;
375 ImGui::PushItemWidth(150.0f);
376
377 if(ImGui::TreeNode("Keyboard"))
378 {
379
380 auto& entries = settings.input.actions.keyboard_map.entries_by_action_id_;
381
382 if(ImGui::Button("Add Action"))
383 {
384 auto& mapping = entries["New Action"];
385 mapping.emplace_back();
386
387 result.changed = true;
388 result.edit_finished = true;
389 }
390
391 std::string rename_from;
392 std::string rename_to;
393 std::string to_delete;
394
395 for(auto& kvp : entries)
396 {
397 ImGui::PushID(total_inputs++);
398 auto& action = kvp.first;
399 auto& mappings = kvp.second;
400
401 if(ImGui::Button(ICON_MDI_DELETE_ALERT))
402 {
403 to_delete = action;
404 }
405
406 ImGui::SameLine();
407
408 if(ImGui::TreeNode(action.c_str()))
409 {
410 int i = 0;
411
412 auto name = action;
413 if(ImGui::InputTextWidget("Name", name, false, ImGuiInputTextFlags_EnterReturnsTrue))
414 {
415 rename_from = action;
416 rename_to = name;
417 }
418
419 if(ImGui::Button("Add Mapping"))
420 {
421 mappings.emplace_back();
422
423 result.changed = true;
424 result.edit_finished = true;
425 }
426
427 int index_to_remove = -1;
428 for(auto& mapping : mappings)
429 {
430 if(&mapping != &mappings.front())
431 {
432 ImGui::Separator();
433 }
434
435 ImGui::PushID(int32_t(i));
436
437 // ImGui::PushID(int32_t(mapping.key));
438
439 if(ImGui::Button(ICON_MDI_DELETE))
440 {
441 index_to_remove = i;
442 }
443 ImGui::SameLine();
444
445 ImGui::BeginGroup();
446 {
447 auto oskey = to_os_key(mapping.key);
448
449 if(ImGuiKeySelector("Key", oskey, "Key Selector"))
450 {
451 mapping.key = from_os_key(oskey);
452 result.changed = true;
453 result.edit_finished = true;
454 }
455
456
457
458 // if(ImGuiEnumSelector(
459 // "Key",
460 // oskey,
461 // os::key::code::count,
462 // [](os::key::code code)
463 // {
464 // return os::key::to_string(code);
465 // },
466 // [](int code)
467 // {
468 // return to_os_key(code);
469 // },
470 // [](os::key::code code)
471 // {
472 // return "";
473 // },
474 // "Key Selector"))
475 // {
476 // mapping.key = from_os_key(oskey);
477 // result.changed = true;
478 // result.edit_finished = true;
479 // }
480
481
482 int mod_i = 0;
483 int mod_index_to_remove = -1;
484 for(auto& modifier : mapping.modifiers)
485 {
486 ImGui::PushID(mod_i);
487 auto osmodifier = to_os_key(modifier);
488 if(ImGui::Button(ICON_MDI_DELETE_VARIANT))
489 {
490 mod_index_to_remove = mod_i;
491 }
492 ImGui::SameLine();
493
494 if(ImGuiKeySelector("Modifier", osmodifier, "Modifier Selector"))
495 {
496 modifier = from_os_key(osmodifier);
497 result.changed = true;
498 result.edit_finished = true;
499 }
500
501 // if(ImGuiEnumSelector(
502 // "Modifier",
503 // osmodifier,
504 // os::key::code::count,
505 // [](os::key::code code)
506 // {
507 // return os::key::to_string(code);
508 // },
509 // [](int code)
510 // {
511 // return to_os_key(code);
512 // },
513 // [](os::key::code code)
514 // {
515 // return "";
516 // },
517 // "Modifier Selector"))
518 // {
519 // modifier = from_os_key(osmodifier);
520 // result.changed = true;
521 // result.edit_finished = true;
522 // }
523 ImGui::PopID();
524
525 mod_i++;
526 }
527
528 if(mod_index_to_remove != -1)
529 {
530 if(mod_index_to_remove < mapping.modifiers.size())
531 {
532 mapping.modifiers.erase(mapping.modifiers.begin() + mod_index_to_remove);
533 }
534 }
535
536 ImGui::Dummy(ImVec2(150.0f, ImGui::GetFrameHeight()));
537 ImGui::SameLine();
538 if(ImGui::Button("Add Modifier"))
539 {
540 mapping.modifiers.emplace_back();
541 result.changed = true;
542 result.edit_finished = true;
543 }
544
545 if(ImGui::DragFloat("Analog Value", &mapping.analog_value, 0.05))
546 {
547 result.changed = true;
548 }
549 result.edit_finished |= ImGui::IsItemDeactivatedAfterEdit();
550 }
551 ImGui::EndGroup();
552
553 i++;
554 ImGui::PopID();
555 // ImGui::PopID();
556 }
557
558 if(index_to_remove != -1)
559 {
560 if(index_to_remove < mappings.size())
561 {
562 mappings.erase(mappings.begin() + index_to_remove);
563 }
564 result.changed = true;
565 result.edit_finished = true;
566 }
567
568 ImGui::TreePop();
569 }
570
571 ImGui::PopID();
572 }
573
574 if(!rename_to.empty())
575 {
576 entries[rename_to] = entries[rename_from];
577 entries.erase(rename_from);
578 }
579
580 if(!to_delete.empty())
581 {
582 entries.erase(to_delete);
583 }
584
585 ImGui::TreePop();
586 }
587
588 if(ImGui::TreeNode("Gamepad"))
589 {
590 auto& entries = settings.input.actions.gamepad_map.entries_by_action_id_;
591
592 if(ImGui::Button("Add Action"))
593 {
594 auto& mapping = entries["New Action"];
595 mapping.emplace_back();
596
597 result.changed = true;
598 result.edit_finished = true;
599 }
600
601 std::string rename_from;
602 std::string rename_to;
603 std::string to_delete;
604
605 for(auto& kvp : settings.input.actions.gamepad_map.entries_by_action_id_)
606 {
607 auto& action = kvp.first;
608 auto& mappings = kvp.second;
609
610 ImGui::PushID(total_inputs++);
611
612 if(ImGui::Button(ICON_MDI_DELETE_ALERT))
613 {
614 to_delete = action;
615 }
616
617 ImGui::SameLine();
618
619 if(ImGui::TreeNode(action.c_str()))
620 {
621 int i = 0;
622
623 auto name = action;
624 if(ImGui::InputTextWidget("Name", name, false, ImGuiInputTextFlags_EnterReturnsTrue))
625 {
626 rename_from = action;
627 rename_to = name;
628 }
629
630 if(ImGui::Button("Add Mapping"))
631 {
632 mappings.emplace_back();
633
634 result.changed = true;
635 result.edit_finished = true;
636 }
637
638 int index_to_remove = -1;
639 for(auto& mapping : mappings)
640 {
641 if(&mapping != &mappings.front())
642 {
643 ImGui::Separator();
644 }
645
646 ImGui::PushID(int32_t(i));
647
648 ImGui::PushID(int32_t(mapping.type));
649
650 if(ImGui::Button(ICON_MDI_DELETE))
651 {
652 index_to_remove = i;
653 }
654
655 ImGui::SameLine();
656
657 ImGui::BeginGroup();
658 {
660 if(ImGuiEnumCombo("Type",
661 mapping.type,
662 types,
663 IM_ARRAYSIZE(types),
665 {
666 return input::to_string(type);
667 }))
668 {
669 result.changed = true;
670 result.edit_finished = true;
671 }
672
673 if(mapping.type == input::input_type::axis)
674 {
678 if(ImGuiEnumCombo("Range",
679 mapping.range,
680 ranges,
681 IM_ARRAYSIZE(ranges),
683 {
684 return input::to_string(range);
685 }))
686 {
687 result.changed = true;
688 result.edit_finished = true;
689 }
690
691 auto axis = static_cast<input::gamepad_axis>(mapping.value);
692
693 if(ImGuiEnumSelector(
694 "Axis",
695 axis,
697 [](input::gamepad_axis button)
698 {
699 return input::to_string(button);
700 },
701 [](int val)
702 {
703 return static_cast<input::gamepad_axis>(val);
704 },
706 {
707 return "";
708 },
709 "Gamepad Axis Selector"))
710 {
711 mapping.value = static_cast<uint32_t>(axis);
712
713 result.changed = true;
714 result.edit_finished = true;
715 }
716
717 ImGui::DragFloat("Min Analog Value", &mapping.min_analog_value, 0.05);
718 result.edit_finished |= ImGui::IsItemDeactivatedAfterEdit();
719
720 ImGui::DragFloat("Max Analog Value", &mapping.max_analog_value, 0.05);
721 result.edit_finished |= ImGui::IsItemDeactivatedAfterEdit();
722 }
723 else
724 {
725 auto button = static_cast<input::gamepad_button>(mapping.value);
726
727 if(ImGuiEnumSelector(
728 "Button",
729 button,
731 [](input::gamepad_button button)
732 {
733 return input::to_string(button);
734 },
735 [](int val)
736 {
737 return static_cast<input::gamepad_button>(val);
738 },
740 {
741 return input::get_description(button);
742 },
743 "Gamepad Button Selector"))
744 {
745 mapping.value = static_cast<uint32_t>(button);
746
747 result.changed = true;
748 result.edit_finished = true;
749 }
750 }
751 }
752 ImGui::EndGroup();
753
754 i++;
755 ImGui::PopID();
756 ImGui::PopID();
757 }
758
759 if(index_to_remove != -1)
760 {
761 if(index_to_remove < mappings.size())
762 {
763 mappings.erase(mappings.begin() + index_to_remove);
764 }
765 result.changed = true;
766 result.edit_finished = true;
767 }
768
769 ImGui::TreePop();
770 }
771 ImGui::PopID();
772 }
773
774 if(!rename_to.empty())
775 {
776 entries[rename_to] = entries[rename_from];
777 entries.erase(rename_from);
778 }
779
780 if(!to_delete.empty())
781 {
782 entries.erase(to_delete);
783 }
784
785 ImGui::TreePop();
786 }
787
788 if(ImGui::TreeNode("Mouse"))
789 {
790 auto& entries = settings.input.actions.mouse_map.entries_by_action_id_;
791
792 if(ImGui::Button("Add Action"))
793 {
794 auto& mapping = entries["New Action"];
795 mapping.emplace_back();
796
797 result.changed = true;
798 result.edit_finished = true;
799 }
800
801 std::string rename_from;
802 std::string rename_to;
803 std::string to_delete;
804
805 for(auto& kvp : entries)
806 {
807 const auto& action = kvp.first;
808 auto& mappings = kvp.second;
809
810 ImGui::PushID(total_inputs++);
811
812 if(ImGui::Button(ICON_MDI_DELETE_ALERT))
813 {
814 to_delete = action;
815 }
816
817 ImGui::SameLine();
818
819 if(ImGui::TreeNode(action.c_str()))
820 {
821 int i = 0;
822
823 auto name = action;
824 if(ImGui::InputTextWidget("Name", name, false, ImGuiInputTextFlags_EnterReturnsTrue))
825 {
826 rename_from = action;
827 rename_to = name;
828 }
829
830 if(ImGui::Button("Add Mapping"))
831 {
832 mappings.emplace_back();
833
834 result.changed = true;
835 result.edit_finished = true;
836 }
837
838 int index_to_remove = -1;
839 for(auto& mapping : mappings)
840 {
841 if(&mapping != &mappings.front())
842 {
843 ImGui::Separator();
844 }
845
846 ImGui::PushID(i);
847
848 if(ImGui::Button(ICON_MDI_DELETE))
849 {
850 index_to_remove = i;
851 }
852
853 ImGui::SameLine();
854
855 ImGui::BeginGroup();
856 {
858 if(ImGuiEnumCombo("Type",
859 mapping.type,
860 types,
861 IM_ARRAYSIZE(types),
863 {
864 return input::to_string(type);
865 }))
866 {
867 result.changed = true;
868 result.edit_finished = true;
869 }
870
871 if(mapping.type == input::input_type::axis)
872 {
876 if(ImGuiEnumCombo("Range",
877 mapping.range,
878 ranges,
879 IM_ARRAYSIZE(ranges),
881 {
882 return input::to_string(range);
883 }))
884 {
885 result.changed = true;
886 result.edit_finished = true;
887 }
888
889 auto axis = static_cast<input::mouse_axis>(mapping.value);
893 if(ImGuiEnumCombo("Axis",
894 axis,
895 axes,
896 IM_ARRAYSIZE(axes),
897 [](input::mouse_axis axis)
898 {
899 return input::to_string(axis);
900 }))
901 {
902 mapping.value = static_cast<uint32_t>(axis);
903
904 result.changed = true;
905 result.edit_finished = true;
906 }
907 }
908 else
909 {
910 auto button = static_cast<input::mouse_button>(mapping.value);
911
912 if(ImGuiEnumSelector(
913 "Button",
914 button,
916 [](input::mouse_button button)
917 {
918 return input::to_string(button);
919 },
920 [](int val)
921 {
922 return static_cast<input::mouse_button>(val);
923 },
925 {
926 return "";
927 },
928 "Button Selector"))
929 {
930 mapping.value = static_cast<uint32_t>(button);
931
932 result.changed = true;
933 result.edit_finished = true;
934 }
935 }
936 }
937 ImGui::EndGroup();
938
939 i++;
940
941 ImGui::PopID();
942 }
943 ImGui::TreePop();
944
945 if(index_to_remove != -1)
946 {
947 if(index_to_remove < mappings.size())
948 {
949 mappings.erase(mappings.begin() + index_to_remove);
950 }
951 result.changed = true;
952 result.edit_finished = true;
953 }
954 }
955
956 ImGui::PopID();
957 }
958
959 if(!rename_to.empty())
960 {
961 entries[rename_to] = entries[rename_from];
962 entries.erase(rename_from);
963 }
964
965 if(!to_delete.empty())
966 {
967 entries.erase(to_delete);
968 }
969
970 ImGui::TreePop();
971 }
972
973 if(result.edit_finished)
974 {
975 pm.save_project_settings(ctx);
976 }
977}
978
979void draw_time_settings(rtti::context& ctx)
980{
981 auto& pm = ctx.get_cached<project_manager>();
982 auto& settings = pm.get_settings();
983
984 ImGui::PushItemWidth(150.0f);
985
986 if(inspect(ctx, settings.time).edit_finished)
987 {
988 pm.save_project_settings(ctx);
989 }
990
991 ImGui::PopItemWidth();
992}
993
994} // namespace
995
999
1000void project_settings_panel::show(bool s, const std::string& hint)
1001{
1002 show_request_ = s;
1003 hint_ = hint;
1004}
1005
1007{
1008 if(show_request_)
1009 {
1010 ImGui::OpenPopup(name);
1011 show_request_ = false;
1012 }
1013
1014 ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size * 0.5f);
1015 bool show = true;
1016 if(ImGui::BeginPopupModal(name, &show))
1017 {
1018 // ImGui::WindowTimeBlock block(ImGui::GetFont(ImGui::Font::Mono));
1019
1020 draw_ui(ctx);
1021
1022 ImGui::EndPopup();
1023 }
1024}
1025
1026void project_settings_panel::draw_ui(rtti::context& ctx)
1027{
1028 // We'll create two child windows side by side:
1029 // 1) Left child: categories
1030 // 2) Right child: actual settings
1031
1032 auto avail = ImGui::GetContentRegionAvail();
1033 if(avail.x < 1.0f || avail.y < 1.0f)
1034 {
1035 return;
1036 }
1037
1038 static std::vector<setting_entry> categories{{"Application", &draw_application_settings},
1039 {"Resolution", &draw_resolution_settings},
1040 {"Assets", &draw_asset_settings},
1041 {"Graphics", &draw_graphics_settings},
1042 {"Splash Screen", &draw_splash_settings},
1043 {"Standalone", &draw_standalone_settings},
1044 {"Layers", &draw_layers_settings},
1045 {"Input", &draw_input_settings},
1046 {"Time", &draw_time_settings}};
1047 // Child A: the categories list
1048 // We fix the width of this child, so the right child uses the remaining space.
1049 ImGui::BeginChild("##LeftSidebar", avail * ImVec2(0.15f, 1.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
1050 {
1051 // Display categories
1052 for(const auto& category : categories)
1053 {
1054 if(hint_ == category.id)
1055 {
1056 selected_entry_ = category;
1057 hint_.clear();
1058 }
1059
1060 // 'Selectable' returns true if clicked
1061 if(ImGui::Selectable(category.id.c_str(), (selected_entry_.id == category.id)))
1062 {
1063 selected_entry_ = category;
1064 }
1065 }
1066 }
1067 ImGui::EndChild();
1068
1069 // On the same line:
1070 ImGui::SameLine();
1071
1072 // Child B: show settings for the selected category
1073 ImGui::BeginChild("##RightContent");
1074 {
1075 if(selected_entry_.callback)
1076 {
1077 selected_entry_.callback(ctx);
1078 }
1079 }
1080 ImGui::EndChild();
1081}
1082
1083} // namespace unravel
void on_frame_ui_render(rtti::context &ctx, const char *name)
void show(bool s, const std::string &hint)
std::vector< render_pass_entry > entries
std::string name
Definition hub.cpp:33
#define ICON_MDI_DELETE_VARIANT
#define ICON_MDI_SELECT_SEARCH
#define ICON_MDI_DELETE
#define ICON_MDI_DELETE_ALERT
auto ImGui_ImplOSPP_KeycodeToImGuiKey(os::key::code keycode) -> ImGuiKey
auto ImGui_ImplOSPP_ImGuiKeyToKeycode(ImGuiKey key) -> os::key::code
texture_job_type type
std::vector< size_t > parent_
imported_texture desc
auto get_description(gamepad_button button) -> std::string
key_code
Definition key.hpp:6
auto to_string(axis_range range) -> const std::string &
Definition to_string.hpp:15
auto inspect(rtti::context &ctx, T &obj, const std::string &name={}) -> inspect_result
Convenience template function for inspecting objects of known type.
Definition inspectors.h:402
auto get_cached() -> T &
Definition context.hpp:49
static void recompile_textures(const std::string &group="")