yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
ui_helpers.cc
Go to the documentation of this file.
2
3#include "absl/strings/str_format.h"
7#include "imgui/imgui.h"
8#include "imgui/imgui_internal.h"
9
10namespace yaze {
11namespace gui {
12
13// ============================================================================
14// Theme and Semantic Colors
15// ============================================================================
16
17ImVec4 GetThemeColor(ImGuiCol idx) {
18 return ImGui::GetStyle().Colors[idx];
19}
20
22 const auto& theme = ThemeManager::Get().GetCurrentTheme();
23 return ConvertColorToImVec4(theme.success);
24}
25
27 const auto& theme = ThemeManager::Get().GetCurrentTheme();
28 return ConvertColorToImVec4(theme.warning);
29}
30
31ImVec4 GetErrorColor() {
32 const auto& theme = ThemeManager::Get().GetCurrentTheme();
33 return ConvertColorToImVec4(theme.error);
34}
35
36ImVec4 GetInfoColor() {
37 const auto& theme = ThemeManager::Get().GetCurrentTheme();
38 return ConvertColorToImVec4(theme.info);
39}
40
42 const auto& theme = ThemeManager::Get().GetCurrentTheme();
43 return ConvertColorToImVec4(theme.accent);
44}
45
46// Entity/Map marker colors (vibrant with good visibility)
48 // Bright yellow with strong visibility
49 return ImVec4(1.0f, 0.9f, 0.0f, 0.85f); // Yellow-gold, high visibility
50}
51
52ImVec4 GetExitColor() {
53 // Bright cyan-white for contrast
54 return ImVec4(0.9f, 1.0f, 1.0f, 0.85f); // Cyan-white, high visibility
55}
56
57ImVec4 GetItemColor() {
58 // Vibrant red for items
59 return ImVec4(1.0f, 0.2f, 0.2f, 0.85f); // Bright red, high visibility
60}
61
63 // Bright magenta for sprites
64 return ImVec4(1.0f, 0.3f, 1.0f, 0.85f); // Bright magenta, high visibility
65}
66
68 const auto& theme = ThemeManager::Get().GetCurrentTheme();
69 return ConvertColorToImVec4(theme.accent);
70}
71
73 return ImVec4(1.0f, 0.5f, 0.0f, 1.0f); // Orange for locked items
74}
75
76// Status colors
78 return GetWarningColor(); // Yellow from theme
79}
80
82 return GetSuccessColor(); // Green from theme
83}
84
86 const auto& theme = ThemeManager::Get().GetCurrentTheme();
87 return ConvertColorToImVec4(theme.accent);
88}
89
90// ============================================================================
91// Layout Helpers
92// ============================================================================
93
94void BeginField(const char* label, float label_width) {
95 ImGui::BeginGroup();
96 if (label_width > 0.0f) {
97 ImGui::Text("%s:", label);
98 ImGui::SameLine(label_width);
99 } else {
100 ImGui::TextUnformatted(label);
101 ImGui::SameLine();
102 }
103 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.6f);
104}
105
106void EndField() {
107 ImGui::PopItemWidth();
108 ImGui::EndGroup();
109}
110
111bool BeginPropertyTable(const char* id, int columns,
112 ImGuiTableFlags extra_flags) {
113 ImGuiTableFlags flags =
114 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | extra_flags;
115 if (ImGui::BeginTable(id, columns, flags)) {
116 ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 150);
117 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
118 return true;
119 }
120 return false;
121}
122
124 ImGui::EndTable();
125}
126
127void PropertyRow(const char* label, const char* value) {
128 ImGui::TableNextColumn();
129 ImGui::Text("%s", label);
130 ImGui::TableNextColumn();
131 ImGui::TextWrapped("%s", value);
132}
133
134void PropertyRow(const char* label, int value) {
135 ImGui::TableNextColumn();
136 ImGui::Text("%s", label);
137 ImGui::TableNextColumn();
138 ImGui::Text("%d", value);
139}
140
141void PropertyRowHex(const char* label, uint8_t value) {
142 ImGui::TableNextColumn();
143 ImGui::Text("%s", label);
144 ImGui::TableNextColumn();
145 ImGui::Text("0x%02X", value);
146}
147
148void PropertyRowHex(const char* label, uint16_t value) {
149 ImGui::TableNextColumn();
150 ImGui::Text("%s", label);
151 ImGui::TableNextColumn();
152 ImGui::Text("0x%04X", value);
153}
154
155void SectionHeader(const char* icon, const char* label, const ImVec4& color) {
156 ImGui::TextColored(color, "%s %s", icon, label);
157 ImGui::Separator();
158}
159
160// ============================================================================
161// Common Widget Patterns
162// ============================================================================
163
164bool IconButton(const char* icon, const char* label, const ImVec2& size) {
165 std::string button_text = std::string(icon) + " " + std::string(label);
166 return ImGui::Button(button_text.c_str(), size);
167}
168
169bool ColoredButton(const char* label, ButtonType type, const ImVec2& size) {
170 ImVec4 color;
171 switch (type) {
173 color = GetSuccessColor();
174 break;
176 color = GetWarningColor();
177 break;
179 color = GetErrorColor();
180 break;
181 case ButtonType::Info:
182 color = GetInfoColor();
183 break;
184 default:
185 color = GetThemeColor(ImGuiCol_Button);
186 break;
187 }
188
189 ImGui::PushStyleColor(ImGuiCol_Button, color);
190 ImGui::PushStyleColor(
191 ImGuiCol_ButtonHovered,
192 ImVec4(color.x * 1.2f, color.y * 1.2f, color.z * 1.2f, color.w));
193 ImGui::PushStyleColor(
194 ImGuiCol_ButtonActive,
195 ImVec4(color.x * 0.8f, color.y * 0.8f, color.z * 0.8f, color.w));
196
197 bool result = ImGui::Button(label, size);
198
199 ImGui::PopStyleColor(3);
200 return result;
201}
202
203bool ToggleIconButton(const char* icon_on, const char* icon_off, bool* state,
204 const char* tooltip) {
205 const char* icon = *state ? icon_on : icon_off;
206 ImVec4 color = *state ? GetSuccessColor() : GetThemeColor(ImGuiCol_Button);
207
208 ImGui::PushStyleColor(ImGuiCol_Button, color);
209 bool result = ImGui::SmallButton(icon);
210 ImGui::PopStyleColor();
211
212 if (result)
213 *state = !*state;
214
215 if (tooltip && ImGui::IsItemHovered()) {
216 ImGui::SetTooltip("%s", tooltip);
217 }
218
219 return result;
220}
221
222bool ToggleButton(const char* label, bool active, const ImVec2& size) {
223 if (active) {
224 ImGui::PushStyleColor(ImGuiCol_Button, GetAccentColor());
225 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, GetAccentColor());
226 ImGui::PushStyleColor(ImGuiCol_ButtonActive, GetAccentColor());
227 }
228
229 bool result = ImGui::Button(label, size);
230
231 if (active) {
232 ImGui::PopStyleColor(3);
233 }
234
235 return result;
236}
237
238void HelpMarker(const char* desc) {
239 ImGui::TextDisabled(ICON_MD_HELP_OUTLINE);
240 if (ImGui::IsItemHovered()) {
241 ImGui::BeginTooltip();
242 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
243 ImGui::TextUnformatted(desc);
244 ImGui::PopTextWrapPos();
245 ImGui::EndTooltip();
246 }
247}
248
249void SeparatorText(const char* label) {
250 ImGui::SeparatorText(label);
251}
252
253void StatusBadge(const char* text, ButtonType type) {
254 ImVec4 color;
255 switch (type) {
257 color = GetSuccessColor();
258 break;
260 color = GetWarningColor();
261 break;
263 color = GetErrorColor();
264 break;
265 case ButtonType::Info:
266 color = GetInfoColor();
267 break;
268 default:
269 color = GetThemeColor(ImGuiCol_Text);
270 break;
271 }
272
273 ImGui::PushStyleColor(ImGuiCol_Button, color);
274 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 10.0f);
275 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 3));
276 ImGui::SmallButton(text);
277 ImGui::PopStyleVar(2);
278 ImGui::PopStyleColor();
279}
280
281// ============================================================================
282// Editor-Specific Patterns
283// ============================================================================
284
285void BeginToolset(const char* id) {
286 ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(2, 2));
287 ImGui::BeginTable(id, 32, ImGuiTableFlags_SizingFixedFit);
288}
289
291 ImGui::EndTable();
292 ImGui::PopStyleVar();
293}
294
295void ToolsetButton(const char* icon, bool selected, const char* tooltip,
296 std::function<void()> on_click) {
297 ImGui::TableNextColumn();
298
299 if (selected) {
300 ImGui::PushStyleColor(ImGuiCol_Button, GetAccentColor());
301 }
302
303 if (ImGui::Button(icon)) {
304 if (on_click)
305 on_click();
306 }
307
308 if (selected) {
309 ImGui::PopStyleColor();
310 }
311
312 if (tooltip && ImGui::IsItemHovered()) {
313 ImGui::SetTooltip("%s", tooltip);
314 }
315}
316
317void BeginCanvasContainer(const char* id, bool scrollable) {
318 ImGuiWindowFlags flags = scrollable ? ImGuiWindowFlags_AlwaysVerticalScrollbar
319 : ImGuiWindowFlags_None;
320 ImGui::BeginChild(id, ImVec2(0, 0), true, flags);
321}
322
324 ImGui::EndChild();
325}
326
327bool EditorTabItem(const char* icon, const char* label, bool* p_open) {
328 char tab_label[256];
329 snprintf(tab_label, sizeof(tab_label), "%s %s", icon, label);
330 return ImGui::BeginTabItem(tab_label, p_open);
331}
332
333bool ConfirmationDialog(const char* id, const char* title, const char* message,
334 const char* confirm_text, const char* cancel_text) {
335 bool confirmed = false;
336
337 if (ImGui::BeginPopupModal(id, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
338 ImGui::Text("%s", title);
339 ImGui::Separator();
340 ImGui::TextWrapped("%s", message);
341 ImGui::Separator();
342
343 if (ColoredButton(confirm_text, ButtonType::Warning, ImVec2(120, 0))) {
344 confirmed = true;
345 ImGui::CloseCurrentPopup();
346 }
347
348 ImGui::SameLine();
349 if (ImGui::Button(cancel_text, ImVec2(120, 0))) {
350 ImGui::CloseCurrentPopup();
351 }
352
353 ImGui::EndPopup();
354 }
355
356 return confirmed;
357}
358
359// ============================================================================
360// Visual Indicators
361// ============================================================================
362
363void StatusIndicator(const char* label, bool active, const char* tooltip) {
364 ImVec4 color =
365 active ? GetSuccessColor() : GetThemeColor(ImGuiCol_TextDisabled);
366
367 ImDrawList* draw_list = ImGui::GetWindowDrawList();
368 ImVec2 pos = ImGui::GetCursorScreenPos();
369 float radius = 5.0f;
370
371 pos.x += radius + 3;
372 pos.y += ImGui::GetTextLineHeight() * 0.5f;
373
374 draw_list->AddCircleFilled(pos, radius, ImGui::GetColorU32(color));
375
376 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + radius * 2 + 8);
377 ImGui::Text("%s", label);
378
379 if (tooltip && ImGui::IsItemHovered()) {
380 ImGui::SetTooltip("%s", tooltip);
381 }
382}
383
384void RomVersionBadge(const char* version, bool is_vanilla) {
385 ImVec4 color = is_vanilla ? GetWarningColor() : GetSuccessColor();
386 const char* icon = is_vanilla ? ICON_MD_INFO : ICON_MD_CHECK_CIRCLE;
387
388 ImGui::PushStyleColor(ImGuiCol_Text, color);
389 ImGui::Text("%s %s", icon, version);
390 ImGui::PopStyleColor();
391}
392
393void LockIndicator(bool locked, const char* label) {
394 if (locked) {
395 ImGui::TextColored(GetLockedColor(), ICON_MD_LOCK " %s (Locked)", label);
396 } else {
397 ImGui::Text(ICON_MD_LOCK_OPEN " %s", label);
398 }
399}
400
401// ============================================================================
402// Spacing and Alignment
403// ============================================================================
404
405void VerticalSpacing(float pixels) {
406 ImGui::Dummy(ImVec2(0, pixels));
407}
408
409void HorizontalSpacing(float pixels) {
410 ImGui::Dummy(ImVec2(pixels, 0));
411 ImGui::SameLine();
412}
413
414void CenterText(const char* text) {
415 float text_width = ImGui::CalcTextSize(text).x;
416 ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - text_width) * 0.5f);
417 ImGui::Text("%s", text);
418}
419
420void RightAlign(float width) {
421 ImGui::SetCursorPosX(ImGui::GetCursorPosX() +
422 ImGui::GetContentRegionAvail().x - width);
423}
424
425// ============================================================================
426// Animation Helpers
427// ============================================================================
428
429float GetPulseAlpha(float speed) {
430 return 0.5f +
431 0.5f * sinf(static_cast<float>(ImGui::GetTime()) * speed * 2.0f);
432}
433
434float GetFadeIn(float duration) {
435 static double start_time = 0.0;
436 double current_time = ImGui::GetTime();
437
438 if (start_time == 0.0) {
439 start_time = current_time;
440 }
441
442 float elapsed = static_cast<float>(current_time - start_time);
443 float alpha = ImClamp(elapsed / duration, 0.0f, 1.0f);
444
445 // Reset after complete
446 if (alpha >= 1.0f) {
447 start_time = 0.0;
448 }
449
450 return alpha;
451}
452
453void PushPulseEffect(float speed) {
454 ImGui::PushStyleVar(ImGuiStyleVar_Alpha,
455 ImGui::GetStyle().Alpha * GetPulseAlpha(speed));
456}
457
459 ImGui::PopStyleVar();
460}
461
462void LoadingSpinner(const char* label, float radius) {
463 ImDrawList* draw_list = ImGui::GetWindowDrawList();
464 ImVec2 pos = ImGui::GetCursorScreenPos();
465 pos.x += radius + 4;
466 pos.y += radius + 4;
467
468 const float rotation = static_cast<float>(ImGui::GetTime()) * 3.0f;
469 const int segments = 16;
470 const float thickness = 3.0f;
471
472 const float start_angle = rotation;
473 const float end_angle = rotation + IM_PI * 1.5f;
474
475 draw_list->PathArcTo(pos, radius, start_angle, end_angle, segments);
476 draw_list->PathStroke(ImGui::GetColorU32(GetAccentColor()), 0, thickness);
477
478 if (label) {
479 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + radius * 2 + 8);
480 ImGui::Text("%s", label);
481 } else {
482 ImGui::Dummy(ImVec2(radius * 2 + 8, radius * 2 + 8));
483 }
484}
485
486// ============================================================================
487// Responsive Layout Helpers
488// ============================================================================
489
490float GetResponsiveWidth(float min_width, float max_width, float ratio) {
491 float available = ImGui::GetContentRegionAvail().x;
492 float target = available * ratio;
493
494 if (target < min_width)
495 return min_width;
496 if (target > max_width)
497 return max_width;
498 return target;
499}
500
501void SetupResponsiveColumns(int count, float min_col_width) {
502 float available = ImGui::GetContentRegionAvail().x;
503 float col_width = available / count;
504
505 if (col_width < min_col_width) {
506 col_width = min_col_width;
507 }
508
509 for (int i = 0; i < count; ++i) {
510 ImGui::TableSetupColumn("##col", ImGuiTableColumnFlags_WidthFixed,
511 col_width);
512 }
513}
514
515static int g_two_col_table_active = 0;
516
517void BeginTwoColumns(const char* id, float split_ratio) {
518 ImGuiTableFlags flags = ImGuiTableFlags_Resizable |
519 ImGuiTableFlags_BordersInnerV |
520 ImGuiTableFlags_SizingStretchProp;
521
522 if (ImGui::BeginTable(id, 2, flags)) {
523 float available = ImGui::GetContentRegionAvail().x;
524 ImGui::TableSetupColumn("##left", ImGuiTableColumnFlags_None,
525 available * split_ratio);
526 ImGui::TableSetupColumn("##right", ImGuiTableColumnFlags_None,
527 available * (1.0f - split_ratio));
528 ImGui::TableNextRow();
529 ImGui::TableNextColumn();
530 g_two_col_table_active++;
531 }
532}
533
535 ImGui::TableNextColumn();
536}
537
539 ImGui::EndTable();
540 g_two_col_table_active--;
541}
542
543// ============================================================================
544// Input Helpers
545// ============================================================================
546
547bool LabeledInputHex(const char* label, uint8_t* value) {
548 BeginField(label);
549 ImGui::PushItemWidth(60);
550 bool changed =
551 ImGui::InputScalar("##hex", ImGuiDataType_U8, value, nullptr, nullptr,
552 "%02X", ImGuiInputTextFlags_CharsHexadecimal);
553 ImGui::PopItemWidth();
554 EndField();
555 return changed;
556}
557
558bool LabeledInputHex(const char* label, uint16_t* value) {
559 BeginField(label);
560 ImGui::PushItemWidth(80);
561 bool changed =
562 ImGui::InputScalar("##hex", ImGuiDataType_U16, value, nullptr, nullptr,
563 "%04X", ImGuiInputTextFlags_CharsHexadecimal);
564 ImGui::PopItemWidth();
565 EndField();
566 return changed;
567}
568
569bool IconCombo(const char* icon, const char* label, int* current,
570 const char* const items[], int count) {
571 ImGui::Text("%s", icon);
572 ImGui::SameLine();
573 return ImGui::Combo(label, current, items, count);
574}
575
576std::string MakePanelTitle(const std::string& title) {
577 return title;
578}
579
580} // namespace gui
581} // namespace yaze
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_LOCK_OPEN
Definition icons.h:1142
#define ICON_MD_LOCK
Definition icons.h:1140
#define ICON_MD_CHECK_CIRCLE
Definition icons.h:400
#define ICON_MD_HELP_OUTLINE
Definition icons.h:935
void RightAlign(float width)
void VerticalSpacing(float pixels)
void EndCanvasContainer()
void BeginToolset(const char *id)
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:23
std::string MakePanelTitle(const std::string &title)
ImVec4 GetVanillaRomColor()
Definition ui_helpers.cc:77
void EndPropertyTable()
void PropertyRow(const char *label, const char *value)
bool ToggleIconButton(const char *icon_on, const char *icon_off, bool *state, const char *tooltip)
ImVec4 GetSuccessColor()
Definition ui_helpers.cc:21
void BeginField(const char *label, float label_width)
Definition ui_helpers.cc:94
void SeparatorText(const char *label)
void EndField()
ImVec4 GetLockedColor()
Definition ui_helpers.cc:72
void StatusIndicator(const char *label, bool active, const char *tooltip)
ImVec4 GetSelectedColor()
Definition ui_helpers.cc:67
void BeginTwoColumns(const char *id, float split_ratio)
void RomVersionBadge(const char *version, bool is_vanilla)
bool EditorTabItem(const char *icon, const char *label, bool *p_open)
ImVec4 GetEntranceColor()
Definition ui_helpers.cc:47
void CenterText(const char *text)
bool LabeledInputHex(const char *label, uint8_t *value)
void SectionHeader(const char *icon, const char *label, const ImVec4 &color)
void LockIndicator(bool locked, const char *label)
bool IconButton(const char *icon, const char *label, const ImVec2 &size)
void EndToolset()
ImVec4 GetSpriteColor()
Definition ui_helpers.cc:62
void PropertyRowHex(const char *label, uint8_t value)
bool ToggleButton(const char *label, bool active, const ImVec2 &size)
float GetResponsiveWidth(float min_width, float max_width, float ratio)
void SwitchColumn()
void SetupResponsiveColumns(int count, float min_col_width)
bool ColoredButton(const char *label, ButtonType type, const ImVec2 &size)
bool BeginPropertyTable(const char *id, int columns, ImGuiTableFlags extra_flags)
void BeginCanvasContainer(const char *id, bool scrollable)
ImVec4 GetItemColor()
Definition ui_helpers.cc:57
bool IconCombo(const char *icon, const char *label, int *current, const char *const items[], int count)
void LoadingSpinner(const char *label, float radius)
ImVec4 GetErrorColor()
Definition ui_helpers.cc:31
void ToolsetButton(const char *icon, bool selected, const char *tooltip, std::function< void()> on_click)
ImVec4 GetWarningColor()
Definition ui_helpers.cc:26
bool ConfirmationDialog(const char *id, const char *title, const char *message, const char *confirm_text, const char *cancel_text)
void EndTwoColumns()
ImVec4 GetModifiedColor()
Definition ui_helpers.cc:85
void PopPulseEffect()
ImVec4 GetInfoColor()
Definition ui_helpers.cc:36
float GetFadeIn(float duration)
float GetPulseAlpha(float speed)
void PushPulseEffect(float speed)
ImVec4 GetExitColor()
Definition ui_helpers.cc:52
void HelpMarker(const char *desc)
Color GetThemeColor(const std::string &color_name)
void StatusBadge(const char *text, ButtonType type)
void HorizontalSpacing(float pixels)
ImVec4 GetAccentColor()
Definition ui_helpers.cc:41
ImVec4 GetCustomRomColor()
Definition ui_helpers.cc:81
#define IM_PI