9#include <filedialog/filedialog.h>
10#include <imgui/imgui.h>
11#include <imgui/imgui_internal.h>
13#include <imgui_widgets/keyboard/imgui_keyboard.h>
14#include <imgui_widgets/keyboard/imgui_mouse.h>
15#include <imgui_widgets/keyboard/imgui_gamepad.h>
27 return static_cast<os::key::code
>(code);
30auto to_os_key(int32_t code) -> os::key::code
32 return static_cast<os::key::code
>(code);
45template<
typename EnumT,
typename ToStringFn>
46auto ImGuiEnumCombo(
const char* label,
48 const EnumT* all_values,
50 ToStringFn stringify) ->
bool
53 std::string preview_text = stringify(current_value);
56 if(ImGui::BeginCombo(label, preview_text.c_str()))
58 for(
size_t i = 0;
i <
count; ++
i)
60 EnumT candidate = all_values[
i];
61 bool is_selected = (candidate == current_value);
62 if(ImGui::Selectable(stringify(candidate).c_str(), is_selected))
65 if(candidate != current_value)
67 current_value = candidate;
75 ImGui::SetItemDefaultFocus();
85auto ImGuiKeySelector(
const char* label,
86 os::key::code& selected_value,
87 const char* popup_id =
"Key Selector") ->
bool
89 std::vector<std::string> names;
90 std::vector<const char*> names_cstr;
96 std::string current_name = os::key::to_string(selected_value);
97 if(current_name.empty())
99 current_name =
"None";
103 bool selection_changed =
false;
104 if(ImGui::Button(current_name.c_str(), ImVec2(150.0f, ImGui::GetFrameHeight())))
106 ImGui::OpenPopup(popup_id);
108 std::string
desc = {};
111 ImGui::SetItemTooltipEx(
"%s",
desc.c_str());
115 ImGui::TextUnformatted(label);
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))
123 ImKeyboard::Keyboard(ImKeyboard::ImGuiKeyboardLayout_Qwerty, ImKeyboard::ImGuiKeyboardFlags_Recordable);
125 auto recorded_keys = ImKeyboard::GetRecordedKeys();
126 for(
auto& key : recorded_keys)
130 selection_changed =
true;
132 ImKeyboard::ClearHighlights();
133 ImKeyboard::ClearRecorded();
140 return selection_changed;
144template<
typename EnumT,
typename ToStringFn,
typename FromIntFn,
typename GetDescriptionFn>
145auto ImGuiEnumSelector(
const char* label,
146 EnumT& selected_value,
148 ToStringFn stringify,
150 GetDescriptionFn get_description,
151 const char* popup_id =
"Enum Selector") ->
bool
153 std::vector<std::string> names;
154 std::vector<const char*> names_cstr;
156 static ImGuiTextFilter filter;
158 ImGui::PushID(label);
161 names.reserve(enum_count);
162 for(
int i = 0;
i < enum_count; ++
i)
164 auto e = from_int(i);
165 names.push_back(stringify(e));
169 names_cstr.reserve(names.size());
170 for(
const auto&
name : names)
172 names_cstr.push_back(
name.c_str());
177 std::string current_name = stringify(selected_value);
178 if(current_name.empty())
180 current_name =
"None";
184 bool selection_changed =
false;
185 if(ImGui::Button(current_name.c_str(), ImVec2(150.0f, ImGui::GetFrameHeight())))
189 ImGui::OpenPopup(popup_id);
194 ImGui::SetItemTooltipEx(
"%s",
desc.c_str());
198 ImGui::TextUnformatted(label);
201 if(ImGui::BeginPopup(popup_id))
203 if(ImGui::IsWindowAppearing())
205 ImGui::SetKeyboardFocusHere();
210 ImGui::DrawItemActivityOutline();
215 if(ImGui::BeginChild(
"Enum Selector Context", ImVec2(0, 200.0f),
true))
217 for(
int i = 0;
i < enum_count; ++
i)
225 if(!filter.PassFilter(names[i].c_str()))
231 bool is_selected = (
static_cast<int>(selected_value) ==
i);
232 if(ImGui::Selectable(names[i].c_str(), is_selected))
235 selected_value = from_int(i);
236 selection_changed =
true;
237 ImGui::CloseCurrentPopup();
243 ImGui::SetItemTooltipEx(
"%s",
desc.c_str());
245 ImGui::TextDisabled(
"%s",
"(?)");
257 return selection_changed;
263 auto& settings = pm.get_settings();
265 ImGui::PushItemWidth(150.0f);
267 if(
inspect(ctx, settings.app).edit_finished)
269 pm.save_project_settings(ctx);
272 ImGui::PopItemWidth();
278 auto& settings = pm.get_settings();
280 ImGui::PushItemWidth(150.0f);
282 if(
inspect(ctx, settings.resolution).edit_finished)
284 pm.save_project_settings(ctx);
287 ImGui::PopItemWidth();
293 auto& settings = pm.get_settings();
295 ImGui::PushItemWidth(150.0f);
297 if(
inspect(ctx, settings.graphics).edit_finished)
299 pm.save_project_settings(ctx);
302 ImGui::PopItemWidth();
308 auto& settings = pm.get_settings();
309 ImGui::PushItemWidth(150.0f);
310 if(
inspect(ctx, settings.splash).edit_finished)
312 pm.save_project_settings(ctx);
314 ImGui::PopItemWidth();
320 auto& settings = pm.get_settings();
322 ImGui::PushItemWidth(150.0f);
324 if(
inspect(ctx, settings.standalone).edit_finished)
326 pm.save_project_settings(ctx);
329 ImGui::PopItemWidth();
335 auto& settings = pm.get_settings();
337 ImGui::PushItemWidth(150.0f);
339 if(
inspect(ctx, settings.layer).edit_finished)
341 pm.save_project_settings(ctx);
344 ImGui::PopItemWidth();
350 auto& settings = pm.get_settings();
352 ImGui::PushItemWidth(150.0f);
354 if(
inspect(ctx, settings.assets.texture).edit_finished)
356 pm.save_project_settings(ctx);
359 if(ImGui::Button(
"Recompile Textures"))
364 ImGui::PopItemWidth();
370 auto& settings = pm.get_settings();
372 int total_inputs = 0;
374 inspect_result result;
375 ImGui::PushItemWidth(150.0f);
377 if(ImGui::TreeNode(
"Keyboard"))
380 auto&
entries = settings.input.actions.keyboard_map.entries_by_action_id_;
382 if(ImGui::Button(
"Add Action"))
384 auto& mapping =
entries[
"New Action"];
385 mapping.emplace_back();
387 result.changed =
true;
388 result.edit_finished =
true;
391 std::string rename_from;
392 std::string rename_to;
393 std::string to_delete;
397 ImGui::PushID(total_inputs++);
398 auto& action = kvp.first;
399 auto& mappings = kvp.second;
408 if(ImGui::TreeNode(action.c_str()))
413 if(ImGui::InputTextWidget(
"Name",
name,
false, ImGuiInputTextFlags_EnterReturnsTrue))
415 rename_from = action;
419 if(ImGui::Button(
"Add Mapping"))
421 mappings.emplace_back();
423 result.changed =
true;
424 result.edit_finished =
true;
427 int index_to_remove = -1;
428 for(
auto& mapping : mappings)
430 if(&mapping != &mappings.front())
435 ImGui::PushID(int32_t(i));
447 auto oskey = to_os_key(mapping.key);
449 if(ImGuiKeySelector(
"Key", oskey,
"Key Selector"))
451 mapping.key = from_os_key(oskey);
452 result.changed =
true;
453 result.edit_finished =
true;
483 int mod_index_to_remove = -1;
484 for(
auto& modifier : mapping.modifiers)
486 ImGui::PushID(mod_i);
487 auto osmodifier = to_os_key(modifier);
490 mod_index_to_remove = mod_i;
494 if(ImGuiKeySelector(
"Modifier", osmodifier,
"Modifier Selector"))
496 modifier = from_os_key(osmodifier);
497 result.changed =
true;
498 result.edit_finished =
true;
528 if(mod_index_to_remove != -1)
530 if(mod_index_to_remove < mapping.modifiers.size())
532 mapping.modifiers.erase(mapping.modifiers.begin() + mod_index_to_remove);
536 ImGui::Dummy(ImVec2(150.0f, ImGui::GetFrameHeight()));
538 if(ImGui::Button(
"Add Modifier"))
540 mapping.modifiers.emplace_back();
541 result.changed =
true;
542 result.edit_finished =
true;
545 if(ImGui::DragFloat(
"Analog Value", &mapping.analog_value, 0.05))
547 result.changed =
true;
549 result.edit_finished |= ImGui::IsItemDeactivatedAfterEdit();
558 if(index_to_remove != -1)
560 if(index_to_remove < mappings.size())
562 mappings.erase(mappings.begin() + index_to_remove);
564 result.changed =
true;
565 result.edit_finished =
true;
574 if(!rename_to.empty())
580 if(!to_delete.empty())
588 if(ImGui::TreeNode(
"Gamepad"))
590 auto&
entries = settings.input.actions.gamepad_map.entries_by_action_id_;
592 if(ImGui::Button(
"Add Action"))
594 auto& mapping =
entries[
"New Action"];
595 mapping.emplace_back();
597 result.changed =
true;
598 result.edit_finished =
true;
601 std::string rename_from;
602 std::string rename_to;
603 std::string to_delete;
605 for(
auto& kvp : settings.input.actions.gamepad_map.entries_by_action_id_)
607 auto& action = kvp.first;
608 auto& mappings = kvp.second;
610 ImGui::PushID(total_inputs++);
619 if(ImGui::TreeNode(action.c_str()))
624 if(ImGui::InputTextWidget(
"Name",
name,
false, ImGuiInputTextFlags_EnterReturnsTrue))
626 rename_from = action;
630 if(ImGui::Button(
"Add Mapping"))
632 mappings.emplace_back();
634 result.changed =
true;
635 result.edit_finished =
true;
638 int index_to_remove = -1;
639 for(
auto& mapping : mappings)
641 if(&mapping != &mappings.front())
646 ImGui::PushID(int32_t(i));
648 ImGui::PushID(int32_t(mapping.type));
660 if(ImGuiEnumCombo(
"Type",
669 result.changed =
true;
670 result.edit_finished =
true;
678 if(ImGuiEnumCombo(
"Range",
681 IM_ARRAYSIZE(ranges),
687 result.changed =
true;
688 result.edit_finished =
true;
693 if(ImGuiEnumSelector(
709 "Gamepad Axis Selector"))
711 mapping.value =
static_cast<uint32_t
>(
axis);
713 result.changed =
true;
714 result.edit_finished =
true;
717 ImGui::DragFloat(
"Min Analog Value", &mapping.min_analog_value, 0.05);
718 result.edit_finished |= ImGui::IsItemDeactivatedAfterEdit();
720 ImGui::DragFloat(
"Max Analog Value", &mapping.max_analog_value, 0.05);
721 result.edit_finished |= ImGui::IsItemDeactivatedAfterEdit();
727 if(ImGuiEnumSelector(
743 "Gamepad Button Selector"))
745 mapping.value =
static_cast<uint32_t
>(
button);
747 result.changed =
true;
748 result.edit_finished =
true;
759 if(index_to_remove != -1)
761 if(index_to_remove < mappings.size())
763 mappings.erase(mappings.begin() + index_to_remove);
765 result.changed =
true;
766 result.edit_finished =
true;
774 if(!rename_to.empty())
780 if(!to_delete.empty())
788 if(ImGui::TreeNode(
"Mouse"))
790 auto&
entries = settings.input.actions.mouse_map.entries_by_action_id_;
792 if(ImGui::Button(
"Add Action"))
794 auto& mapping =
entries[
"New Action"];
795 mapping.emplace_back();
797 result.changed =
true;
798 result.edit_finished =
true;
801 std::string rename_from;
802 std::string rename_to;
803 std::string to_delete;
807 const auto& action = kvp.first;
808 auto& mappings = kvp.second;
810 ImGui::PushID(total_inputs++);
819 if(ImGui::TreeNode(action.c_str()))
824 if(ImGui::InputTextWidget(
"Name",
name,
false, ImGuiInputTextFlags_EnterReturnsTrue))
826 rename_from = action;
830 if(ImGui::Button(
"Add Mapping"))
832 mappings.emplace_back();
834 result.changed =
true;
835 result.edit_finished =
true;
838 int index_to_remove = -1;
839 for(
auto& mapping : mappings)
841 if(&mapping != &mappings.front())
858 if(ImGuiEnumCombo(
"Type",
867 result.changed =
true;
868 result.edit_finished =
true;
876 if(ImGuiEnumCombo(
"Range",
879 IM_ARRAYSIZE(ranges),
885 result.changed =
true;
886 result.edit_finished =
true;
893 if(ImGuiEnumCombo(
"Axis",
902 mapping.value =
static_cast<uint32_t
>(
axis);
904 result.changed =
true;
905 result.edit_finished =
true;
912 if(ImGuiEnumSelector(
930 mapping.value =
static_cast<uint32_t
>(
button);
932 result.changed =
true;
933 result.edit_finished =
true;
945 if(index_to_remove != -1)
947 if(index_to_remove < mappings.size())
949 mappings.erase(mappings.begin() + index_to_remove);
951 result.changed =
true;
952 result.edit_finished =
true;
959 if(!rename_to.empty())
965 if(!to_delete.empty())
973 if(result.edit_finished)
975 pm.save_project_settings(ctx);
982 auto& settings = pm.get_settings();
984 ImGui::PushItemWidth(150.0f);
986 if(
inspect(ctx, settings.time).edit_finished)
988 pm.save_project_settings(ctx);
991 ImGui::PopItemWidth();
1010 ImGui::OpenPopup(
name);
1011 show_request_ =
false;
1014 ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size * 0.5f);
1016 if(ImGui::BeginPopupModal(
name, &
show))
1032 auto avail = ImGui::GetContentRegionAvail();
1033 if(avail.x < 1.0f || avail.y < 1.0f)
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}};
1049 ImGui::BeginChild(
"##LeftSidebar", avail * ImVec2(0.15f, 1.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
1052 for(
const auto& category : categories)
1054 if(hint_ == category.id)
1056 selected_entry_ = category;
1061 if(ImGui::Selectable(category.id.c_str(), (selected_entry_.id == category.id)))
1063 selected_entry_ = category;
1073 ImGui::BeginChild(
"##RightContent");
1075 if(selected_entry_.callback)
1077 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 ImGui_ImplOSPP_KeycodeToImGuiKey(os::key::code keycode) -> ImGuiKey
auto ImGui_ImplOSPP_ImGuiKeyToKeycode(ImGuiKey key) -> os::key::code
std::vector< size_t > parent_
auto inspect(rtti::context &ctx, T &obj, const std::string &name={}) -> inspect_result
Convenience template function for inspecting objects of known type.
static void recompile_textures(const std::string &group="")