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