9#include <filedialog/filedialog.h>
10#include <imgui/imgui.h>
11#include <imgui/imgui_internal.h>
21 return static_cast<os::key::code
>(code);
24auto to_os_key(int32_t code) -> os::key::code
26 return static_cast<os::key::code
>(code);
39template<
typename EnumT,
typename ToStringFn>
40auto ImGuiEnumCombo(
const char* label,
42 const EnumT* all_values,
44 ToStringFn stringify) ->
bool
47 std::string preview_text = stringify(current_value);
50 if(ImGui::BeginCombo(label, preview_text.c_str()))
52 for(
size_t i = 0;
i <
count; ++
i)
54 EnumT candidate = all_values[
i];
55 bool is_selected = (candidate == current_value);
56 if(ImGui::Selectable(stringify(candidate).c_str(), is_selected))
59 if(candidate != current_value)
61 current_value = candidate;
69 ImGui::SetItemDefaultFocus();
78template<
typename EnumT,
typename ToStringFn,
typename FromIntFn,
typename GetDescriptionFn>
79auto ImGuiEnumSelector(
const char* label,
80 EnumT& selected_value,
84 GetDescriptionFn get_description,
85 const char* popup_id =
"Enum Selector") ->
bool
87 std::vector<std::string> names;
88 std::vector<const char*> names_cstr;
90 static ImGuiTextFilter filter;
95 names.reserve(enum_count);
96 for(
int i = 0;
i < enum_count; ++
i)
99 names.push_back(stringify(e));
103 names_cstr.reserve(names.size());
104 for(
const auto&
name : names)
106 names_cstr.push_back(
name.c_str());
111 std::string current_name = stringify(selected_value);
112 if(current_name.empty())
114 current_name =
"None";
118 bool selection_changed =
false;
119 if(ImGui::Button(current_name.c_str(), ImVec2(150.0f, ImGui::GetFrameHeight())))
123 ImGui::OpenPopup(popup_id);
128 ImGui::SetItemTooltipEx(
"%s", desc.c_str());
132 ImGui::TextUnformatted(label);
135 if(ImGui::BeginPopup(popup_id))
137 if(ImGui::IsWindowAppearing())
139 ImGui::SetKeyboardFocusHere();
144 ImGui::DrawItemActivityOutline();
149 if(ImGui::BeginChild(
"Enum Selector Context", ImVec2(0, 200.0f),
true))
151 for(
int i = 0;
i < enum_count; ++
i)
159 if(!filter.PassFilter(names[i].c_str()))
165 bool is_selected = (
static_cast<int>(selected_value) ==
i);
166 if(ImGui::Selectable(names[i].c_str(), is_selected))
169 selected_value = from_int(i);
170 selection_changed =
true;
171 ImGui::CloseCurrentPopup();
177 ImGui::SetItemTooltipEx(
"%s", desc.c_str());
179 ImGui::TextDisabled(
"%s",
"(?)");
191 return selection_changed;
197 auto& settings = pm.get_settings();
199 ImGui::PushItemWidth(150.0f);
201 if(
inspect(ctx, settings.app).edit_finished)
203 pm.save_project_settings(ctx);
206 ImGui::PopItemWidth();
212 auto& settings = pm.get_settings();
214 ImGui::PushItemWidth(150.0f);
216 if(
inspect(ctx, settings.resolution).edit_finished)
218 pm.save_project_settings(ctx);
221 ImGui::PopItemWidth();
227 auto& settings = pm.get_settings();
229 ImGui::PushItemWidth(150.0f);
231 if(
inspect(ctx, settings.graphics).edit_finished)
233 pm.save_project_settings(ctx);
236 ImGui::PopItemWidth();
242 auto& settings = pm.get_settings();
244 ImGui::PushItemWidth(150.0f);
246 if(
inspect(ctx, settings.standalone).edit_finished)
248 pm.save_project_settings(ctx);
251 ImGui::PopItemWidth();
257 auto& settings = pm.get_settings();
259 ImGui::PushItemWidth(150.0f);
261 if(
inspect(ctx, settings.layer).edit_finished)
263 pm.save_project_settings(ctx);
266 ImGui::PopItemWidth();
272 auto& settings = pm.get_settings();
274 ImGui::PushItemWidth(150.0f);
276 if(
inspect(ctx, settings.assets.texture).edit_finished)
278 pm.save_project_settings(ctx);
281 if(ImGui::Button(
"Recompile Textures"))
286 ImGui::PopItemWidth();
292 auto& settings = pm.get_settings();
294 int total_inputs = 0;
296 inspect_result result;
297 ImGui::PushItemWidth(150.0f);
299 if(ImGui::TreeNode(
"Keyboard"))
301 auto& entries = settings.input.actions.keyboard_map.entries_by_action_id_;
303 if(ImGui::Button(
"Add Action"))
305 auto& mapping = entries[
"New Action"];
306 mapping.emplace_back();
308 result.changed =
true;
309 result.edit_finished =
true;
312 std::string rename_from;
313 std::string rename_to;
314 std::string to_delete;
316 for(
auto& kvp : entries)
318 ImGui::PushID(total_inputs++);
319 auto& action = kvp.first;
320 auto& mappings = kvp.second;
329 if(ImGui::TreeNode(action.c_str()))
334 if(ImGui::InputTextWidget(
"Name",
name,
false, ImGuiInputTextFlags_EnterReturnsTrue))
336 rename_from = action;
340 if(ImGui::Button(
"Add Mapping"))
342 mappings.emplace_back();
344 result.changed =
true;
345 result.edit_finished =
true;
348 int index_to_remove = -1;
349 for(
auto& mapping : mappings)
351 if(&mapping != &mappings.front())
356 ImGui::PushID(int32_t(i));
358 ImGui::PushID(int32_t(mapping.key));
368 auto oskey = to_os_key(mapping.key);
370 if(ImGuiEnumSelector(
373 os::key::code::count,
374 [](os::key::code code)
376 return os::key::to_string(code);
380 return to_os_key(code);
382 [](os::key::code code)
388 mapping.key = from_os_key(oskey);
389 result.changed =
true;
390 result.edit_finished =
true;
394 int mod_index_to_remove = -1;
395 for(
auto& modifier : mapping.modifiers)
397 ImGui::PushID(mod_i);
398 auto osmodifier = to_os_key(modifier);
401 mod_index_to_remove = mod_i;
405 if(ImGuiEnumSelector(
408 os::key::code::count,
409 [](os::key::code code)
411 return os::key::to_string(code);
415 return to_os_key(code);
417 [](os::key::code code)
421 "Modifier Selector"))
423 modifier = from_os_key(osmodifier);
424 result.changed =
true;
425 result.edit_finished =
true;
432 if(mod_index_to_remove != -1)
434 if(mod_index_to_remove < mapping.modifiers.size())
436 mapping.modifiers.erase(mapping.modifiers.begin() + mod_index_to_remove);
440 ImGui::Dummy(ImVec2(150.0f, ImGui::GetFrameHeight()));
442 if(ImGui::Button(
"Add Modifier"))
444 mapping.modifiers.emplace_back();
445 result.changed =
true;
446 result.edit_finished =
true;
449 if(ImGui::DragFloat(
"Analog Value", &mapping.analog_value, 0.05))
451 result.changed =
true;
453 result.edit_finished |= ImGui::IsItemDeactivatedAfterEdit();
462 if(index_to_remove != -1)
464 if(index_to_remove < mappings.size())
466 mappings.erase(mappings.begin() + index_to_remove);
468 result.changed =
true;
469 result.edit_finished =
true;
478 if(!rename_to.empty())
480 entries[rename_to] = entries[rename_from];
481 entries.erase(rename_from);
484 if(!to_delete.empty())
486 entries.erase(to_delete);
492 if(ImGui::TreeNode(
"Gamepad"))
494 auto& entries = settings.input.actions.gamepad_map.entries_by_action_id_;
496 if(ImGui::Button(
"Add Action"))
498 auto& mapping = entries[
"New Action"];
499 mapping.emplace_back();
501 result.changed =
true;
502 result.edit_finished =
true;
505 std::string rename_from;
506 std::string rename_to;
507 std::string to_delete;
509 for(
auto& kvp : settings.input.actions.gamepad_map.entries_by_action_id_)
511 auto& action = kvp.first;
512 auto& mappings = kvp.second;
514 ImGui::PushID(total_inputs++);
523 if(ImGui::TreeNode(action.c_str()))
528 if(ImGui::InputTextWidget(
"Name",
name,
false, ImGuiInputTextFlags_EnterReturnsTrue))
530 rename_from = action;
534 if(ImGui::Button(
"Add Mapping"))
536 mappings.emplace_back();
538 result.changed =
true;
539 result.edit_finished =
true;
542 int index_to_remove = -1;
543 for(
auto& mapping : mappings)
545 if(&mapping != &mappings.front())
550 ImGui::PushID(int32_t(i));
552 ImGui::PushID(int32_t(mapping.type));
564 if(ImGuiEnumCombo(
"Type",
573 result.changed =
true;
574 result.edit_finished =
true;
582 if(ImGuiEnumCombo(
"Range",
585 IM_ARRAYSIZE(ranges),
591 result.changed =
true;
592 result.edit_finished =
true;
597 if(ImGuiEnumSelector(
613 "Gamepad Axis Selector"))
615 mapping.value =
static_cast<uint32_t
>(
axis);
617 result.changed =
true;
618 result.edit_finished =
true;
621 ImGui::DragFloat(
"Min Analog Value", &mapping.min_analog_value, 0.05);
622 result.edit_finished |= ImGui::IsItemDeactivatedAfterEdit();
624 ImGui::DragFloat(
"Max Analog Value", &mapping.max_analog_value, 0.05);
625 result.edit_finished |= ImGui::IsItemDeactivatedAfterEdit();
631 if(ImGuiEnumSelector(
647 "Gamepad Button Selector"))
649 mapping.value =
static_cast<uint32_t
>(
button);
651 result.changed =
true;
652 result.edit_finished =
true;
663 if(index_to_remove != -1)
665 if(index_to_remove < mappings.size())
667 mappings.erase(mappings.begin() + index_to_remove);
669 result.changed =
true;
670 result.edit_finished =
true;
678 if(!rename_to.empty())
680 entries[rename_to] = entries[rename_from];
681 entries.erase(rename_from);
684 if(!to_delete.empty())
686 entries.erase(to_delete);
692 if(ImGui::TreeNode(
"Mouse"))
694 auto& entries = settings.input.actions.mouse_map.entries_by_action_id_;
696 if(ImGui::Button(
"Add Action"))
698 auto& mapping = entries[
"New Action"];
699 mapping.emplace_back();
701 result.changed =
true;
702 result.edit_finished =
true;
705 std::string rename_from;
706 std::string rename_to;
707 std::string to_delete;
709 for(
auto& kvp : entries)
711 const auto& action = kvp.first;
712 auto& mappings = kvp.second;
714 ImGui::PushID(total_inputs++);
723 if(ImGui::TreeNode(action.c_str()))
728 if(ImGui::InputTextWidget(
"Name",
name,
false, ImGuiInputTextFlags_EnterReturnsTrue))
730 rename_from = action;
734 if(ImGui::Button(
"Add Mapping"))
736 mappings.emplace_back();
738 result.changed =
true;
739 result.edit_finished =
true;
742 int index_to_remove = -1;
743 for(
auto& mapping : mappings)
745 if(&mapping != &mappings.front())
762 if(ImGuiEnumCombo(
"Type",
771 result.changed =
true;
772 result.edit_finished =
true;
780 if(ImGuiEnumCombo(
"Range",
783 IM_ARRAYSIZE(ranges),
789 result.changed =
true;
790 result.edit_finished =
true;
797 if(ImGuiEnumCombo(
"Axis",
806 mapping.value =
static_cast<uint32_t
>(
axis);
808 result.changed =
true;
809 result.edit_finished =
true;
816 if(ImGuiEnumSelector(
834 mapping.value =
static_cast<uint32_t
>(
button);
836 result.changed =
true;
837 result.edit_finished =
true;
849 if(index_to_remove != -1)
851 if(index_to_remove < mappings.size())
853 mappings.erase(mappings.begin() + index_to_remove);
855 result.changed =
true;
856 result.edit_finished =
true;
863 if(!rename_to.empty())
865 entries[rename_to] = entries[rename_from];
866 entries.erase(rename_from);
869 if(!to_delete.empty())
871 entries.erase(to_delete);
877 if(result.edit_finished)
879 pm.save_project_settings(ctx);
886 auto& settings = pm.get_settings();
888 ImGui::PushItemWidth(150.0f);
890 if(
inspect(ctx, settings.time).edit_finished)
892 pm.save_project_settings(ctx);
895 ImGui::PopItemWidth();
914 ImGui::OpenPopup(
name);
915 show_request_ =
false;
918 ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size * 0.5f);
920 if(ImGui::BeginPopupModal(
name, &
show))
936 auto avail = ImGui::GetContentRegionAvail();
937 if(avail.x < 1.0f || avail.y < 1.0f)
942 static std::vector<setting_entry> categories{{
"Application", &draw_application_settings},
943 {
"Resolution", &draw_resolution_settings},
944 {
"Assets", &draw_asset_settings},
945 {
"Graphics", &draw_graphics_settings},
946 {
"Standalone", &draw_standalone_settings},
947 {
"Layers", &draw_layers_settings},
948 {
"Input", &draw_input_settings},
949 {
"Time", &draw_time_settings}};
952 ImGui::BeginChild(
"##LeftSidebar", avail * ImVec2(0.15f, 1.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
955 for(
const auto& category : categories)
957 if(hint_ == category.id)
959 selected_entry_ = category;
964 if(ImGui::Selectable(category.id.c_str(), (selected_entry_.id == category.id)))
966 selected_entry_ = category;
976 ImGui::BeginChild(
"##RightContent");
978 if(selected_entry_.callback)
980 selected_entry_.callback(ctx);
void on_frame_ui_render(rtti::context &ctx, const char *name)
void show(bool s, const std::string &hint)
project_settings_panel(imgui_panels *parent)
#define ICON_MDI_DELETE_VARIANT
#define ICON_MDI_SELECT_SEARCH
#define ICON_MDI_DELETE_ALERT
auto inspect(rtti::context &ctx, T &obj) -> inspect_result
Convenience template function for inspecting objects of known type.
static void recompile_textures()