yaze 0.2.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
input.cc
Go to the documentation of this file.
1#include "input.h"
2
3#include <functional>
4#include <string>
5
6#include "absl/strings/string_view.h"
7#include "app/gfx/snes_tile.h"
8#include "imgui/imgui.h"
9#include "imgui/imgui_internal.h"
10
11namespace ImGui {
12
13static inline ImGuiInputTextFlags InputScalar_DefaultCharsFilter(
14 ImGuiDataType data_type, const char* format) {
15 if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)
16 return ImGuiInputTextFlags_CharsScientific;
17 const char format_last_char = format[0] ? format[strlen(format) - 1] : 0;
18 return (format_last_char == 'x' || format_last_char == 'X')
19 ? ImGuiInputTextFlags_CharsHexadecimal
20 : ImGuiInputTextFlags_CharsDecimal;
21}
22bool InputScalarLeft(const char* label, ImGuiDataType data_type, void* p_data,
23 const void* p_step, const void* p_step_fast,
24 const char* format, float input_width,
25 ImGuiInputTextFlags flags, bool no_step = false) {
26 ImGuiWindow* window = ImGui::GetCurrentWindow();
27 if (window->SkipItems) return false;
28
29 ImGuiContext& g = *GImGui;
30 ImGuiStyle& style = g.Style;
31
32 if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt;
33
34 char buf[64];
35 DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);
36
37 if (g.ActiveId == 0 && (flags & (ImGuiInputTextFlags_CharsDecimal |
38 ImGuiInputTextFlags_CharsHexadecimal |
39 ImGuiInputTextFlags_CharsScientific)) == 0)
40 flags |= InputScalar_DefaultCharsFilter(data_type, format);
41 flags |= ImGuiInputTextFlags_AutoSelectAll;
42
43 bool value_changed = false;
44 // if (p_step == NULL) {
45 // ImGui::SetNextItemWidth(input_width);
46 // if (InputText("", buf, IM_ARRAYSIZE(buf), flags))
47 // value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
48 // } else {
49 const float button_size = GetFrameHeight();
50 AlignTextToFramePadding();
51 Text("%s", label);
52 SameLine();
53 BeginGroup(); // The only purpose of the group here is to allow the caller
54 // to query item data e.g. IsItemActive()
55 PushID(label);
56 SetNextItemWidth(ImMax(
57 1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
58
59 // Place the label on the left of the input field
60 PushStyleVar(ImGuiStyleVar_ItemSpacing,
61 ImVec2{style.ItemSpacing.x, style.ItemSpacing.y});
62 PushStyleVar(ImGuiStyleVar_FramePadding,
63 ImVec2{style.FramePadding.x, style.FramePadding.y});
64
65 SetNextItemWidth(input_width);
66 if (InputText("", buf, IM_ARRAYSIZE(buf),
67 flags)) // PushId(label) + "" gives us the expected ID
68 // from outside point of view
69 value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
70 IMGUI_TEST_ENGINE_ITEM_INFO(
71 g.LastItemData.ID, label,
72 g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable);
73
74 // Mouse wheel support
75 if (IsItemHovered() && g.IO.MouseWheel != 0.0f) {
76 float scroll_amount = g.IO.MouseWheel;
77 float scroll_speed = 0.25f; // Adjust the scroll speed as needed
78
79 if (g.IO.KeyCtrl && p_step_fast)
80 scroll_amount *= *(const float*)p_step_fast;
81 else
82 scroll_amount *= *(const float*)p_step;
83
84 if (scroll_amount > 0.0f) {
85 scroll_amount *= scroll_speed; // Adjust the scroll speed as needed
86 DataTypeApplyOp(data_type, '+', p_data, p_data, &scroll_amount);
87 value_changed = true;
88 } else if (scroll_amount < 0.0f) {
89 scroll_amount *= -scroll_speed; // Adjust the scroll speed as needed
90 DataTypeApplyOp(data_type, '-', p_data, p_data, &scroll_amount);
91 value_changed = true;
92 }
93 }
94
95 // Step buttons
96 if (!no_step) {
97 const ImVec2 backup_frame_padding = style.FramePadding;
98 style.FramePadding.x = style.FramePadding.y;
99 ImGuiButtonFlags button_flags = ImGuiButtonFlags_PressedOnClick;
100 if (flags & ImGuiInputTextFlags_ReadOnly) BeginDisabled();
101 SameLine(0, style.ItemInnerSpacing.x);
102 if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) {
103 DataTypeApplyOp(data_type, '-', p_data, p_data,
104 g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
105 value_changed = true;
106 }
107 SameLine(0, style.ItemInnerSpacing.x);
108 if (ButtonEx("+", ImVec2(button_size, button_size), button_flags)) {
109 DataTypeApplyOp(data_type, '+', p_data, p_data,
110 g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
111 value_changed = true;
112 }
113
114 if (flags & ImGuiInputTextFlags_ReadOnly) EndDisabled();
115
116 style.FramePadding = backup_frame_padding;
117 }
118 PopID();
119 EndGroup();
120 ImGui::PopStyleVar(2);
121
122 if (value_changed) MarkItemEdited(g.LastItemData.ID);
123
124 return value_changed;
125}
126} // namespace ImGui
127
128namespace yaze {
129namespace gui {
130
131const int kStepOneHex = 0x01;
132const int kStepFastHex = 0x0F;
133
134bool InputHex(const char* label, uint64_t* data) {
135 return ImGui::InputScalar(label, ImGuiDataType_U64, data, &kStepOneHex,
136 &kStepFastHex, "%06X",
137 ImGuiInputTextFlags_CharsHexadecimal);
138}
139
140bool InputHex(const char* label, int* data, int num_digits, float input_width) {
141 const std::string format = "%0" + std::to_string(num_digits) + "X";
142 return ImGui::InputScalarLeft(label, ImGuiDataType_S32, data, &kStepOneHex,
143 &kStepFastHex, format.c_str(), input_width,
144 ImGuiInputTextFlags_CharsHexadecimal);
145}
146
147bool InputHexShort(const char* label, uint32_t* data) {
148 return ImGui::InputScalar(label, ImGuiDataType_U32, data, &kStepOneHex,
149 &kStepFastHex, "%06X",
150 ImGuiInputTextFlags_CharsHexadecimal);
151}
152
153bool InputHexWord(const char* label, uint16_t* data, float input_width,
154 bool no_step) {
155 return ImGui::InputScalarLeft(label, ImGuiDataType_U16, data, &kStepOneHex,
156 &kStepFastHex, "%04X", input_width,
157 ImGuiInputTextFlags_CharsHexadecimal, no_step);
158}
159
160bool InputHexWord(const char* label, int16_t* data, float input_width,
161 bool no_step) {
162 return ImGui::InputScalarLeft(label, ImGuiDataType_S16, data, &kStepOneHex,
163 &kStepFastHex, "%04X", input_width,
164 ImGuiInputTextFlags_CharsHexadecimal, no_step);
165}
166
167bool InputHexByte(const char* label, uint8_t* data, float input_width,
168 bool no_step) {
169 return ImGui::InputScalarLeft(label, ImGuiDataType_U8, data, &kStepOneHex,
170 &kStepFastHex, "%02X", input_width,
171 ImGuiInputTextFlags_CharsHexadecimal, no_step);
172}
173
174bool InputHexByte(const char* label, uint8_t* data, uint8_t max_value,
175 float input_width, bool no_step) {
176 if (ImGui::InputScalarLeft(label, ImGuiDataType_U8, data, &kStepOneHex,
177 &kStepFastHex, "%02X", input_width,
178 ImGuiInputTextFlags_CharsHexadecimal, no_step)) {
179 if (*data > max_value) {
180 *data = max_value;
181 }
182 return true;
183 }
184 return false;
185}
186
187void Paragraph(const std::string& text) {
188 ImGui::TextWrapped("%s", text.c_str());
189}
190
191// TODO: Setup themes and text/clickable colors
192bool ClickableText(const std::string& text) {
193 static auto color = ImGui::GetStyleColorVec4(ImGuiCol_Tab);
194 ImGui::TextColored(color, "%s", text.c_str());
195 if (ImGui::IsItemHovered()) {
196 color = ImGui::GetStyleColorVec4(ImGuiCol_TabHovered);
197 } else {
198 color = ImGui::GetStyleColorVec4(ImGuiCol_Tab);
199 }
200 return ImGui::IsItemClicked();
201}
202
203void ItemLabel(absl::string_view title, ItemLabelFlags flags) {
204 ImGuiWindow* window = ImGui::GetCurrentWindow();
205 const ImVec2 lineStart = ImGui::GetCursorScreenPos();
206 const ImGuiStyle& style = ImGui::GetStyle();
207 float fullWidth = ImGui::GetContentRegionAvail().x;
208 float itemWidth = ImGui::CalcItemWidth() + style.ItemSpacing.x;
209 ImVec2 textSize = ImGui::CalcTextSize(title.begin(), title.end());
210 ImRect textRect;
211 textRect.Min = ImGui::GetCursorScreenPos();
212 if (flags & ItemLabelFlag::Right) textRect.Min.x = textRect.Min.x + itemWidth;
213 textRect.Max = textRect.Min;
214 textRect.Max.x += fullWidth - itemWidth;
215 textRect.Max.y += textSize.y;
216
217 ImGui::SetCursorScreenPos(textRect.Min);
218
219 ImGui::AlignTextToFramePadding();
220 // Adjust text rect manually because we render it directly into a drawlist
221 // instead of using public functions.
222 textRect.Min.y += window->DC.CurrLineTextBaseOffset;
223 textRect.Max.y += window->DC.CurrLineTextBaseOffset;
224
225 ImGui::ItemSize(textRect);
226 if (ImGui::ItemAdd(
227 textRect, window->GetID(title.data(), title.data() + title.size()))) {
228 ImGui::RenderTextEllipsis(
229 ImGui::GetWindowDrawList(), textRect.Min, textRect.Max, textRect.Max.x,
230 textRect.Max.x, title.data(), title.data() + title.size(), &textSize);
231
232 if (textRect.GetWidth() < textSize.x && ImGui::IsItemHovered())
233 ImGui::SetTooltip("%.*s", (int)title.size(), title.data());
234 }
235 if (flags & ItemLabelFlag::Left) {
236 ImVec2 result;
237 auto other = ImVec2{0, textSize.y + window->DC.CurrLineTextBaseOffset};
238 result.x = textRect.Max.x - other.x;
239 result.y = textRect.Max.y - other.y;
240 ImGui::SetCursorScreenPos(result);
241 ImGui::SameLine();
242 } else if (flags & ItemLabelFlag::Right)
243 ImGui::SetCursorScreenPos(lineStart);
244}
245
246bool ListBox(const char* label, int* current_item,
247 const std::vector<std::string>& items, int height_in_items) {
248 std::vector<const char*> items_ptr;
249 items_ptr.reserve(items.size());
250 for (const auto& item : items) {
251 items_ptr.push_back(item.c_str());
252 }
253 int items_count = static_cast<int>(items.size());
254 return ImGui::ListBox(label, current_item, items_ptr.data(), items_count,
255 height_in_items);
256}
257
258bool InputTileInfo(const char* label, gfx::TileInfo* tile_info) {
259 ImGui::PushID(label);
260 ImGui::BeginGroup();
261 bool changed = false;
262 changed |= InputHexWord(label, &tile_info->id_);
263 changed |= InputHexByte("Palette", &tile_info->palette_);
264 changed |= ImGui::Checkbox("Priority", &tile_info->over_);
265 changed |= ImGui::Checkbox("Vertical Flip", &tile_info->vertical_mirror_);
266 changed |= ImGui::Checkbox("Horizontal Flip", &tile_info->horizontal_mirror_);
267 ImGui::EndGroup();
268 ImGui::PopID();
269 return changed;
270}
271
272ImGuiID GetID(const std::string& id) { return ImGui::GetID(id.c_str()); }
273
274ImGuiKey MapKeyToImGuiKey(char key) {
275 switch (key) {
276 case 'A':
277 return ImGuiKey_A;
278 case 'B':
279 return ImGuiKey_B;
280 case 'C':
281 return ImGuiKey_C;
282 case 'D':
283 return ImGuiKey_D;
284 case 'E':
285 return ImGuiKey_E;
286 case 'F':
287 return ImGuiKey_F;
288 case 'G':
289 return ImGuiKey_G;
290 case 'H':
291 return ImGuiKey_H;
292 case 'I':
293 return ImGuiKey_I;
294 case 'J':
295 return ImGuiKey_J;
296 case 'K':
297 return ImGuiKey_K;
298 case 'L':
299 return ImGuiKey_L;
300 case 'M':
301 return ImGuiKey_M;
302 case 'N':
303 return ImGuiKey_N;
304 case 'O':
305 return ImGuiKey_O;
306 case 'P':
307 return ImGuiKey_P;
308 case 'Q':
309 return ImGuiKey_Q;
310 case 'R':
311 return ImGuiKey_R;
312 case 'S':
313 return ImGuiKey_S;
314 case 'T':
315 return ImGuiKey_T;
316 case 'U':
317 return ImGuiKey_U;
318 case 'V':
319 return ImGuiKey_V;
320 case 'W':
321 return ImGuiKey_W;
322 case 'X':
323 return ImGuiKey_X;
324 case 'Y':
325 return ImGuiKey_Y;
326 case 'Z':
327 return ImGuiKey_Z;
328 case '/':
329 return ImGuiKey_Slash;
330 case '-':
331 return ImGuiKey_Minus;
332 default:
333 return ImGuiKey_COUNT;
334 }
335}
336
337void AddTableColumn(Table& table, const std::string& label,
338 GuiElement element) {
339 table.column_labels.push_back(label);
340 table.column_contents.push_back(element);
341}
342
343void DrawTable(Table& params) {
344 if (ImGui::BeginTable(params.id, params.num_columns, params.flags,
345 params.size)) {
346 for (int i = 0; i < params.num_columns; ++i)
347 ImGui::TableSetupColumn(params.column_labels[i].c_str());
348
349 for (int i = 0; i < params.num_columns; ++i) {
350 ImGui::TableNextColumn();
351 switch (params.column_contents[i].index()) {
352 case 0:
353 std::get<0>(params.column_contents[i])();
354 break;
355 case 1:
356 ImGui::Text("%s", std::get<1>(params.column_contents[i]).c_str());
357 break;
358 }
359 }
360 ImGui::EndTable();
361 }
362}
363
364void DrawMenu(Menu& menu) {
365 for (const auto& each_menu : menu) {
366 if (ImGui::BeginMenu(each_menu.name.c_str())) {
367 for (const auto& each_item : each_menu.subitems) {
368 if (!each_item.subitems.empty()) {
369 if (ImGui::BeginMenu(each_item.name.c_str())) {
370 for (const auto& each_subitem : each_item.subitems) {
371 if (ImGui::MenuItem(each_subitem.name.c_str(),
372 each_subitem.shortcut.c_str())) {
373 if (each_subitem.callback) each_subitem.callback();
374 }
375 }
376 ImGui::EndMenu();
377 }
378 } else if (each_item.name == kSeparator) {
379 ImGui::Separator();
380 } else {
381 if (ImGui::MenuItem(each_item.name.c_str(),
382 each_item.shortcut.c_str(),
383 each_item.enabled_condition())) {
384 if (each_item.callback) each_item.callback();
385 }
386 }
387 }
388 ImGui::EndMenu();
389 }
390 }
391}
392
393} // namespace gui
394} // namespace yaze
SNES 16-bit tile metadata container.
Definition snes_tile.h:49
Definition input.cc:11
bool InputScalarLeft(const char *label, ImGuiDataType data_type, void *p_data, const void *p_step, const void *p_step_fast, const char *format, float input_width, ImGuiInputTextFlags flags, bool no_step=false)
Definition input.cc:22
Graphical User Interface (GUI) components for the application.
Definition canvas.cc:15
constexpr std::string kSeparator
Definition input.h:92
bool ClickableText(const std::string &text)
Definition input.cc:192
void Paragraph(const std::string &text)
Definition input.cc:187
void ItemLabel(absl::string_view title, ItemLabelFlags flags)
Definition input.cc:203
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
Definition input.cc:153
bool ListBox(const char *label, int *current_item, const std::vector< std::string > &items, int height_in_items)
Definition input.cc:246
bool InputHexShort(const char *label, uint32_t *data)
Definition input.cc:147
void AddTableColumn(Table &table, const std::string &label, GuiElement element)
Definition input.cc:337
enum ItemLabelFlag { Left=1u<< 0u, Right=1u<< 1u, Default=Left, } ItemLabelFlags
Definition input.h:50
const int kStepOneHex
Definition input.cc:131
void DrawMenu(Menu &menu)
Definition input.cc:364
void DrawTable(Table &params)
Definition input.cc:343
std::vector< MenuItem > Menu
Definition input.h:86
bool InputHex(const char *label, uint64_t *data)
Definition input.cc:134
bool InputTileInfo(const char *label, gfx::TileInfo *tile_info)
Definition input.cc:258
std::variant< std::function< void()>, std::string > GuiElement
Definition input.h:62
const int kStepFastHex
Definition input.cc:132
ImGuiID GetID(const std::string &id)
Definition input.cc:272
ImGuiKey MapKeyToImGuiKey(char key)
Definition input.cc:274
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
Definition input.cc:167
Main namespace for the application.
Definition controller.cc:18
std::vector< std::string > column_labels
Definition input.h:69
std::vector< GuiElement > column_contents
Definition input.h:70
ImVec2 size
Definition input.h:68
int num_columns
Definition input.h:66
const char * id
Definition input.h:65
ImGuiTableFlags flags
Definition input.h:67