ASAPCabinetFE
 
Loading...
Searching...
No Matches
isection_renderer.h
Go to the documentation of this file.
1
10#ifndef ISECTION_RENDERER_H
11#define ISECTION_RENDERER_H
12
13#include <nlohmann/json.hpp>
14#include <string>
15#include <vector>
16#include <unordered_map>
17#include <imgui.h>
18#include <filesystem>
19#include "ImGuiFileDialog.h"
20#include "log/logging.h"
21
23public:
24 virtual ~ISectionRenderer() = default;
25
26 virtual void render(const std::string& sectionName, nlohmann::json& sectionData, bool& isCapturing,
27 std::string& capturingKeyName, ImGuiFileDialog* fileDialog, bool defaultOpen = false,
28 bool& isDialogOpen = *(new bool(false)), std::string& dialogKey = *(new std::string())) = 0;
29};
30
32protected:
33 void renderBool(const std::string& key, nlohmann::json& value, const std::string& sectionName) {
34 bool val = value.get<bool>();
35 if (ImGui::Checkbox(key.c_str(), &val)) {
36 value = val;
37 LOG_DEBUG("Updated " + sectionName + "." + key + " to " + std::to_string(val));
38 }
39 }
40
41 void renderFloat(const std::string& key, nlohmann::json& value, const std::string& sectionName,
42 float minVal = 0.0f, float maxVal = 1.0f, const char* format = "%.2f") {
43 float val = value.get<float>();
44 if (key == "Title weight") {
45 ImGui::Text("Metadata matchmaking settings:");
46 minVal = 0.2f; maxVal = 0.8f;
47 } else if (key == "Year weight") {
48 minVal = 0.0f; maxVal = 0.4f;
49 } else if (key == "Manufacturer weight") {
50 minVal = 0.0f; maxVal = 0.3f;
51 } else if (key == "ROM weight") {
52 minVal = 0.0f; maxVal = 0.5f;
53 } else if (key == "Title similarity") {
54 minVal = 0.3f; maxVal = 0.8f;
55 } else if (key == "Overall confidence") {
56 minVal = 0.4f; maxVal = 0.9f;
57 } else if (key == "DPI Scale") {
58 minVal = 0.5f; maxVal = 3.0f;
59 } else if (key.find("Alpha") != std::string::npos || key == "scrollbarLength" ||
60 key == "metadataPanelWidth" || key == "metadataPanelHeight") {
61 minVal = 0.0f; maxVal = 1.0f;
62 } else if (key == "arrowHintWidth" || key == "arrowHintHeight") {
63 minVal = 0.0f; maxVal = 200.0f;
64 } else if (key == "arrowThickness" || key == "arrowGlow") {
65 minVal = 0.0f; maxVal = 10.0f;
66 } else if (key == "scrollbarWidth" || key == "thumbWidth") {
67 minVal = 0.0f; maxVal = 50.0f;
68 } else if (key == "masterVol" || key == "mediaAudioVol" || key == "tableMusicVol" ||
69 key == "interfaceAudioVol" || key == "interfaceAmbienceVol") {
70 minVal = 0.0f; maxVal = 100.0f;
71 } else if (key == "configUIWidth" || key == "configUIHeight") {
72 minVal = 0.1f; maxVal = 1.0f;
73 }
74 if (ImGui::SliderFloat(key.c_str(), &val, minVal, maxVal, format)) {
75 value = val;
76 LOG_DEBUG("Updated " + sectionName + "." + key + " to " + std::to_string(val));
77 }
78 }
79
80 void renderInt(const std::string& key, nlohmann::json& value, const std::string& sectionName,
81 int minVal = 0, int maxVal = 10000) {
82 int val = value.get<int>();
83 if (key.find("WindowWidth") != std::string::npos || key.find("WindowHeight") != std::string::npos ||
84 key.find("MediaWidth") != std::string::npos || key.find("MediaHeight") != std::string::npos) {
85 minVal = 0; maxVal = 3840;
86 } else if (key == "fontSize") {
87 minVal = 10; maxVal = 60;
88 } else if (key == "screenshotWait") {
89 minVal = 0; maxVal = 60;
90 }
91 if (ImGui::InputInt(key.c_str(), &val)) {
92 val = std::clamp(val, minVal, maxVal);
93 value = val;
94 LOG_DEBUG("Updated " + sectionName + "." + key + " to " + std::to_string(val));
95 }
96 }
97
98 void renderString(const std::string& key, nlohmann::json& value, const std::string& sectionName) {
99 std::string val = value.get<std::string>();
100 char buffer[256];
101 strncpy(buffer, val.c_str(), sizeof(buffer) - 1);
102 buffer[sizeof(buffer) - 1] = '\0';
103 if (ImGui::InputText(key.c_str(), buffer, sizeof(buffer))) {
104 value = std::string(buffer);
105 LOG_DEBUG("Updated " + sectionName + "." + key + " to " + buffer);
106 }
107 }
108
109 void renderColor(const std::string& key, nlohmann::json& value, const std::string& sectionName) {
110 float color[4] = {
111 value[0].get<float>() / 255.0f,
112 value[1].get<float>() / 255.0f,
113 value[2].get<float>() / 255.0f,
114 value[3].get<float>() / 255.0f
115 };
116 if (ImGui::ColorEdit4(key.c_str(), color)) {
117 value = nlohmann::json{
118 static_cast<int>(color[0] * 255.0f),
119 static_cast<int>(color[1] * 255.0f),
120 static_cast<int>(color[2] * 255.0f),
121 static_cast<int>(color[3] * 255.0f)
122 };
123 LOG_DEBUG("Updated " + sectionName + "." + key + " to [" +
124 std::to_string(value[0].get<int>()) + "," +
125 std::to_string(value[1].get<int>()) + "," +
126 std::to_string(value[2].get<int>()) + "," +
127 std::to_string(value[3].get<int>()) + "]");
128 }
129 }
130
131 void renderRotation(const std::string& key, nlohmann::json& value, const std::string& sectionName) {
132 int val = value.get<int>();
133 static std::unordered_map<std::string, int> lastLoggedValues;
134 int currentValue = snapToStep(val);
135 if (ImGui::SliderInt(key.c_str(), &currentValue, 0, 360, "%d°")) {
136 int snappedValue = snapToStep(currentValue);
137 if (snappedValue != lastLoggedValues[key]) {
138 value = snappedValue;
139 lastLoggedValues[key] = snappedValue;
140 LOG_DEBUG("Updated " + sectionName + "." + key + " to " + std::to_string(snappedValue) + "°");
141 }
142 }
143 }
144
145 void renderKeybind(const std::string& key, nlohmann::json& value, const std::string& sectionName,
146 bool& isCapturing, std::string& capturingKeyName) {
147 if (!value.is_string()) {
148 LOG_DEBUG("Invalid type for keybind " + key + ", expected string, got " + value.type_name());
149 return;
150 }
151 std::string currentBind = value.get<std::string>();
152 std::string buttonLabel = "[" + key + ": " + (currentBind.empty() ? "Unbound" : currentBind) + "]";
153 if (ImGui::Button(buttonLabel.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
154 if (!isCapturing) {
155 isCapturing = true;
156 capturingKeyName = key;
157 LOG_DEBUG("Started capturing key for " + sectionName + "." + key);
158 }
159 }
160 if (isCapturing && capturingKeyName == key) {
161 // ImGui::Text("Press a key or joystick input to bind... (Esc to cancel)"); //shows under key
162 ImGui::Text("Press a key or joystick input to bind to %s...", capturingKeyName.c_str());
163 }
164 }
165
166 void renderPathOrExecutable(const std::string& key, nlohmann::json& value, const std::string& sectionName,
167 ImGuiFileDialog* fileDialog, bool& isDialogOpen, std::string& dialogKey) {
168 std::string val = value.get<std::string>();
169 char buffer[1024];
170 strncpy(buffer, val.c_str(), sizeof(buffer) - 1);
171 buffer[sizeof(buffer) - 1] = '\0';
172 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - 60);
173 if (ImGui::InputText("##value", buffer, sizeof(buffer))) {
174 value = std::string(buffer);
175 LOG_DEBUG("Updated " + sectionName + "." + key + " to " + buffer);
176 }
177 ImGui::PopItemWidth();
178 ImGui::SameLine();
179 if (ImGui::Button("Browse", ImVec2(50, 0))) {
180 LOG_DEBUG("Browse button clicked for " + key);
181 IGFD::FileDialogConfig config;
182 config.path = (!val.empty() && std::filesystem::exists(val)) ? std::filesystem::path(val).parent_path().string() : std::string(getenv("HOME"));
183 config.flags = ImGuiFileDialogFlags_Modal;
184 fileDialog->SetFileStyle(IGFD_FileStyleByTypeDir, nullptr, ImVec4(0.5f, 1.0f, 0.9f, 0.9f));
185
186 if (key == "VPXTablesPath") {
187 fileDialog->OpenDialog("FolderDlg_VPXTablesPath", "Select VPX Tables Folder", nullptr, config);
188 } else if (key == "VPinballXPath") {
189 fileDialog->SetFileStyle(IGFD_FileStyleByFullName, "((VPinballX.*))", ImVec4(0.0f, 1.0f, 0.0f, 0.9f));
190 fileDialog->OpenDialog("FileDlg_VPinballXPath", "Select VPinballX Executable", "((VPinballX.*))", config);
191 } else if (key == "vpxIniPath") {
192 fileDialog->SetFileStyle(IGFD_FileStyleByExtention, ".ini", ImVec4(1.0f, 1.0f, 0.0f, 0.9f));
193 fileDialog->OpenDialog("FileDlg_vpxIniPath", "Select VPinballX Config File", ".ini", config);
194 }
195 isDialogOpen = true;
196 dialogKey = key;
197 LOG_DEBUG("Dialog opened with key: " + dialogKey + ", isDialogOpen: " + std::to_string(isDialogOpen));
198 }
199 }
200
201 int snapToStep(int value) {
202 const int steps[] = {0, 90, 180, 270, 360};
203 int nearestStep = 0;
204 int minDiff = abs(value - steps[0]);
205 for (int i = 1; i < 5; ++i) {
206 int diff = abs(value - steps[i]);
207 if (diff < minDiff) {
208 minDiff = diff;
209 nearestStep = steps[i];
210 }
211 }
212 return nearestStep;
213 }
214};
215
216#endif // ISECTION_RENDERER_H
Definition isection_renderer.h:31
Definition isection_renderer.h:22