yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dashboard_panel.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cfloat>
5#include <fstream>
6#include <sstream>
7
8#include "absl/strings/str_cat.h"
9#include "absl/strings/str_format.h"
11#include "rom/rom.h"
12#include "app/gui/core/color.h"
13#include "app/gui/core/icons.h"
15#include "app/gui/core/style.h"
19#include "imgui/imgui.h"
20#include "imgui/imgui_internal.h"
21#include "util/file_util.h"
22
23namespace yaze {
24namespace editor {
25
26namespace {
27
28constexpr float kDashboardCardBaseWidth = 180.0f;
29constexpr float kDashboardCardBaseHeight = 120.0f;
30constexpr float kDashboardCardWidthMaxFactor = 1.35f;
31constexpr float kDashboardCardHeightMaxFactor = 1.35f;
32constexpr float kDashboardCardMinWidthFactor = 0.9f;
33constexpr float kDashboardCardMinHeightFactor = 0.9f;
34constexpr int kDashboardMaxColumns = 5;
35constexpr float kDashboardRecentBaseWidth = 150.0f;
36constexpr float kDashboardRecentBaseHeight = 35.0f;
37constexpr float kDashboardRecentWidthMaxFactor = 1.3f;
39
40struct FlowLayout {
41 int columns = 1;
42 float item_width = 0.0f;
43 float item_height = 0.0f;
44 float spacing = 0.0f;
45};
46
47FlowLayout ComputeFlowLayout(float avail_width, float min_width,
48 float max_width, float min_height,
49 float max_height, float aspect_ratio,
50 float spacing, int max_columns, int item_count) {
51 FlowLayout layout;
52 layout.spacing = spacing;
53 if (avail_width <= 0.0f) {
54 layout.columns = 1;
55 layout.item_width = min_width;
56 layout.item_height = min_height;
57 return layout;
58 }
59
60 const int clamped_max =
61 std::max(1, max_columns > 0 ? max_columns : item_count);
62 const auto width_for_columns = [avail_width, spacing](int columns) {
63 return (avail_width - spacing * static_cast<float>(columns - 1)) /
64 static_cast<float>(columns);
65 };
66
67 int columns = std::max(
68 1, static_cast<int>((avail_width + spacing) / (min_width + spacing)));
69 columns = std::min(columns, clamped_max);
70 if (item_count > 0) {
71 columns = std::min(columns, item_count);
72 }
73 columns = std::max(columns, 1);
74
75 float width = width_for_columns(columns);
76 while (columns < clamped_max && width > max_width) {
77 columns += 1;
78 width = width_for_columns(columns);
79 }
80
81 const float clamped_max_width = std::min(max_width, avail_width);
82 const float clamped_min_width = std::min(min_width, clamped_max_width);
83 layout.item_width = std::clamp(width, clamped_min_width, clamped_max_width);
84 layout.item_height =
85 std::clamp(layout.item_width * aspect_ratio, min_height, max_height);
86
87 layout.columns = columns;
88
89 return layout;
90}
91
92ImVec4 ScaleColor(const ImVec4& color, float scale, float alpha) {
93 return ImVec4(color.x * scale, color.y * scale, color.z * scale, alpha);
94}
95
96ImVec4 ScaleColor(const ImVec4& color, float scale) {
97 return ScaleColor(color, scale, color.w);
98}
99
100ImVec4 WithAlpha(ImVec4 color, float alpha) {
101 color.w = alpha;
102 return color;
103}
104
105ImVec4 GetEditorAccentColor(EditorType type, const gui::Theme& theme) {
106 switch (type) {
114 return gui::ConvertColorToImVec4(theme.info);
118 return gui::ConvertColorToImVec4(theme.accent);
120 return gui::ConvertColorToImVec4(theme.error);
122 return gui::ConvertColorToImVec4(theme.info);
125 case EditorType::kHex:
128 return gui::ConvertColorToImVec4(theme.info);
130 return gui::ConvertColorToImVec4(theme.accent);
133 default:
135 }
136}
137
138} // namespace
139
141 : editor_switcher_(editor_switcher), window_("Dashboard", ICON_MD_DASHBOARD) {
143 window_.SetDefaultSize(950, 650);
145
146 // Use platform-aware shortcut strings (Cmd on macOS, Ctrl elsewhere)
147 const char* ctrl = gui::GetCtrlDisplayName();
148 editors_ = {
149 {"Overworld", ICON_MD_MAP,
150 "Edit overworld maps, entrances, and properties",
151 absl::StrFormat("%s+1", ctrl), EditorType::kOverworld},
152 {"Dungeon", ICON_MD_CASTLE,
153 "Design dungeon rooms, layouts, and mechanics",
154 absl::StrFormat("%s+2", ctrl), EditorType::kDungeon},
155 {"Graphics", ICON_MD_PALETTE, "Modify tiles, palettes, and graphics sets",
156 absl::StrFormat("%s+3", ctrl), EditorType::kGraphics},
157 {"Sprites", ICON_MD_EMOJI_EMOTIONS, "Edit sprite graphics and properties",
158 absl::StrFormat("%s+4", ctrl), EditorType::kSprite},
159 {"Messages", ICON_MD_CHAT_BUBBLE, "Edit dialogue, signs, and text",
160 absl::StrFormat("%s+5", ctrl), EditorType::kMessage},
161 {"Music", ICON_MD_MUSIC_NOTE, "Configure music and sound effects",
162 absl::StrFormat("%s+6", ctrl), EditorType::kMusic},
163 {"Palettes", ICON_MD_COLOR_LENS, "Edit color palettes and animations",
164 absl::StrFormat("%s+7", ctrl), EditorType::kPalette},
165 {"Screens", ICON_MD_TV, "Edit title screen and ending screens",
166 absl::StrFormat("%s+8", ctrl), EditorType::kScreen},
167 {"Assembly", ICON_MD_CODE, "Write and edit assembly code",
168 absl::StrFormat("%s+9", ctrl), EditorType::kAssembly},
169 {"Hex Editor", ICON_MD_DATA_ARRAY,
170 "Direct ROM memory editing and comparison",
171 absl::StrFormat("%s+0", ctrl), EditorType::kHex},
172 {"Emulator", ICON_MD_VIDEOGAME_ASSET,
173 "Test and debug your ROM in real-time",
174 absl::StrFormat("%s+Shift+E", ctrl), EditorType::kEmulator},
175 {"AI Agent", ICON_MD_SMART_TOY,
176 "Configure AI agent, collaboration, and automation",
177 absl::StrFormat("%s+Shift+A", ctrl), EditorType::kAgent, false, false},
178 };
179
181}
182
184 if (!show_)
185 return;
186
187 // Set window properties immediately before Begin
188 ImGuiViewport* viewport = ImGui::GetMainViewport();
189 ImVec2 center = viewport->GetCenter();
190 ImVec2 view_size = viewport->WorkSize;
191 float target_width = std::clamp(view_size.x * 0.9f, 520.0f, 1000.0f);
192 float target_height = std::clamp(view_size.y * 0.88f, 420.0f, 780.0f);
193 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
194 ImGui::SetNextWindowSize(ImVec2(target_width, target_height),
195 ImGuiCond_Appearing);
196 ImGui::SetNextWindowSizeConstraints(
197 ImVec2(420.0f, 360.0f),
198 ImVec2(view_size.x * 0.98f, view_size.y * 0.95f));
199
202
203 if (window_.Begin(&show_)) {
205 ImGui::Separator();
206 ImGui::Spacing();
207
208 if (!has_rom_) {
209 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
210 ImVec4 info_color = gui::ConvertColorToImVec4(theme.text_secondary);
211 ImGui::TextColored(info_color,
212 ICON_MD_INFO " Load a ROM to enable editors.");
213 ImGui::Spacing();
214 }
215
217 if (!recent_editors_.empty()) {
218 ImGui::Separator();
219 ImGui::Spacing();
220 }
222 }
223 window_.End();
224}
225
227 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
228 const ImVec4 accent = gui::ConvertColorToImVec4(theme.accent);
229 const ImVec4 text_secondary = gui::ConvertColorToImVec4(theme.text_secondary);
230
231 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[2]); // Large font
232 ImGui::TextColored(accent, ICON_MD_EDIT " Select an Editor");
233 ImGui::PopFont();
234
235 ImGui::TextColored(text_secondary,
236 "Choose an editor to begin working on your ROM. "
237 "You can open multiple editors simultaneously.");
238}
239
241 if (recent_editors_.empty())
242 return;
243
244 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
245 const ImVec4 accent = gui::ConvertColorToImVec4(theme.accent);
246 ImGui::TextColored(accent, ICON_MD_HISTORY " Recently Used");
247 ImGui::Spacing();
248
249 const ImGuiStyle& style = ImGui::GetStyle();
250 const float avail_width = ImGui::GetContentRegionAvail().x;
251 const float min_width = kDashboardRecentBaseWidth;
252 const float max_width =
253 kDashboardRecentBaseWidth * kDashboardRecentWidthMaxFactor;
254 const float height =
255 std::max(kDashboardRecentBaseHeight, ImGui::GetFrameHeight());
256 const float spacing = style.ItemSpacing.x;
257 const bool stack_items = avail_width < min_width * 1.6f;
258 FlowLayout row_layout{};
259 if (stack_items) {
260 row_layout.columns = 1;
261 row_layout.item_width = avail_width;
262 row_layout.item_height = height;
263 row_layout.spacing = spacing;
264 } else {
265 row_layout = ComputeFlowLayout(avail_width, min_width, max_width, height,
266 height, height / std::max(min_width, 1.0f),
267 spacing, kDashboardMaxRecentColumns,
268 static_cast<int>(recent_editors_.size()));
269 }
270
271 ImGuiTableFlags table_flags =
272 ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoPadOuterX;
273 const ImVec2 cell_padding(row_layout.spacing * 0.5f,
274 style.ItemSpacing.y * 0.4f);
275 gui::StyleVarGuard cell_var_guard(ImGuiStyleVar_CellPadding, cell_padding);
276 if (ImGui::BeginTable("DashboardRecentGrid", row_layout.columns,
277 table_flags)) {
278 for (EditorType type : recent_editors_) {
279 // Find editor info
280 auto it = std::find_if(
281 editors_.begin(), editors_.end(),
282 [type](const EditorInfo& info) { return info.type == type; });
283
284 if (it == editors_.end()) {
285 continue;
286 }
287
288 ImGui::TableNextColumn();
289
290 const bool enabled = has_rom_ || !it->requires_rom;
291 const float alpha = enabled ? 1.0f : 0.35f;
292 const ImVec4 base_color = GetEditorAccentColor(it->type, theme);
293 gui::StyleColorGuard btn_guard(
294 {{ImGuiCol_Button, ScaleColor(base_color, 0.5f, 0.7f * alpha)},
295 {ImGuiCol_ButtonHovered,
296 ScaleColor(base_color, 0.7f, 0.9f * alpha)},
297 {ImGuiCol_ButtonActive, WithAlpha(base_color, 1.0f * alpha)}});
298
299 ImVec2 button_size(
300 stack_items ? avail_width : row_layout.item_width,
301 row_layout.item_height > 0.0f ? row_layout.item_height : height);
302 if (!enabled) {
303 ImGui::BeginDisabled();
304 }
305 if (ImGui::Button(absl::StrCat(it->icon, " ", it->name).c_str(),
306 button_size)) {
307 if (enabled && editor_switcher_) {
308 MarkRecentlyUsed(type);
311 show_ = false;
312 }
313 }
314 if (!enabled) {
315 ImGui::EndDisabled();
316 }
317
318 if (ImGui::IsItemHovered()) {
319 if (!enabled) {
320 ImGui::SetTooltip("Load a ROM to open %s", it->name.c_str());
321 } else {
322 ImGui::SetTooltip("%s", it->description.c_str());
323 }
324 }
325 }
326 ImGui::EndTable();
327 }
328}
329
331 ImGui::Text(ICON_MD_APPS " All Editors");
332 ImGui::Spacing();
333
334 const ImGuiStyle& style = ImGui::GetStyle();
335 const float avail_width = ImGui::GetContentRegionAvail().x;
336 const float scale = ImGui::GetFontSize() / 16.0f;
337 const float compact_scale = avail_width < 620.0f ? 0.85f : 1.0f;
338 const float min_width =
339 kDashboardCardBaseWidth * kDashboardCardMinWidthFactor * scale *
340 compact_scale;
341 const float max_width =
342 kDashboardCardBaseWidth * kDashboardCardWidthMaxFactor * scale *
343 compact_scale;
344 const float min_height =
345 std::max(kDashboardCardBaseHeight * kDashboardCardMinHeightFactor * scale *
346 compact_scale,
347 ImGui::GetFrameHeight() * 3.2f);
348 const float max_height =
349 kDashboardCardBaseHeight * kDashboardCardHeightMaxFactor * scale *
350 compact_scale;
351 const float aspect_ratio =
352 kDashboardCardBaseHeight / std::max(kDashboardCardBaseWidth, 1.0f);
353 const float spacing = style.ItemSpacing.x;
354
355 FlowLayout layout = ComputeFlowLayout(
356 avail_width, min_width, max_width, min_height, max_height, aspect_ratio,
357 spacing, kDashboardMaxColumns, static_cast<int>(editors_.size()));
358
359 ImGuiTableFlags table_flags =
360 ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoPadOuterX;
361 const ImVec2 cell_padding(layout.spacing * 0.5f, style.ItemSpacing.y * 0.5f);
362 gui::StyleVarGuard grid_var_guard(ImGuiStyleVar_CellPadding, cell_padding);
363 if (ImGui::BeginTable("DashboardEditorGrid", layout.columns, table_flags)) {
364 for (size_t i = 0; i < editors_.size(); ++i) {
365 ImGui::TableNextColumn();
366 const bool enabled = has_rom_ || !editors_[i].requires_rom;
367 DrawEditorPanel(editors_[i], static_cast<int>(i),
368 ImVec2(layout.item_width, layout.item_height), enabled);
369 }
370 ImGui::EndTable();
371 }
372}
373
374void DashboardPanel::DrawEditorPanel(const EditorInfo& info, int index,
375 const ImVec2& card_size, bool enabled) {
376 ImGui::PushID(index);
377
378 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
379 const float disabled_alpha = enabled ? 1.0f : 0.35f;
380 const ImVec4 base_color = GetEditorAccentColor(info.type, theme);
381 ImVec4 text_primary = gui::ConvertColorToImVec4(theme.text_primary);
382 ImVec4 text_secondary = gui::ConvertColorToImVec4(theme.text_secondary);
383 const ImVec4 accent = gui::ConvertColorToImVec4(theme.accent);
384 text_primary.w *= enabled ? 1.0f : 0.5f;
385 text_secondary.w *= enabled ? 1.0f : 0.5f;
386 ImFont* text_font = ImGui::GetFont();
387 const float text_font_size = ImGui::GetFontSize();
388
389 const ImGuiStyle& style = ImGui::GetStyle();
390 const float line_height = ImGui::GetTextLineHeight();
391 const float padding_x = std::max(style.FramePadding.x, card_size.x * 0.06f);
392 const float padding_y = std::max(style.FramePadding.y, card_size.y * 0.08f);
393
394 const float footer_height = info.shortcut.empty() ? 0.0f : line_height;
395 const float footer_spacing =
396 info.shortcut.empty() ? 0.0f : style.ItemSpacing.y;
397 const float available_icon_height = card_size.y - padding_y * 2.0f -
398 line_height - footer_height -
399 footer_spacing;
400 const float min_icon_radius = line_height * 0.9f;
401 float max_icon_radius = card_size.y * 0.24f;
402 max_icon_radius = std::max(max_icon_radius, min_icon_radius);
403 const float icon_radius = std::clamp(available_icon_height * 0.5f,
404 min_icon_radius, max_icon_radius);
405
406 const ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
407 ImDrawList* draw_list = ImGui::GetWindowDrawList();
408 const ImVec2 icon_center(cursor_pos.x + card_size.x * 0.5f,
409 cursor_pos.y + padding_y + icon_radius);
410 float title_y = icon_center.y + icon_radius + style.ItemSpacing.y;
411 const float footer_y = cursor_pos.y + card_size.y - padding_y - footer_height;
412 if (title_y + line_height > footer_y - style.ItemSpacing.y) {
413 title_y = footer_y - line_height - style.ItemSpacing.y;
414 }
415
416 bool is_recent = std::find(recent_editors_.begin(), recent_editors_.end(),
417 info.type) != recent_editors_.end();
418
419 // Create gradient background
420 ImU32 color_top =
421 ImGui::GetColorU32(ScaleColor(base_color, 0.4f, 0.85f * disabled_alpha));
422 ImU32 color_bottom =
423 ImGui::GetColorU32(ScaleColor(base_color, 0.2f, 0.9f * disabled_alpha));
424
425 // Draw gradient card background
426 draw_list->AddRectFilledMultiColor(
427 cursor_pos,
428 ImVec2(cursor_pos.x + card_size.x, cursor_pos.y + card_size.y), color_top,
429 color_top, color_bottom, color_bottom);
430
431 // Colored border
432 ImU32 border_color = is_recent
433 ? ImGui::GetColorU32(
434 WithAlpha(base_color, 1.0f * disabled_alpha))
435 : ImGui::GetColorU32(
436 ScaleColor(base_color, 0.6f,
437 0.7f * disabled_alpha));
438 const float rounding = std::max(style.FrameRounding, card_size.y * 0.05f);
439 const float border_thickness =
440 is_recent ? std::max(2.0f, style.FrameBorderSize + 1.0f)
441 : std::max(1.0f, style.FrameBorderSize);
442 draw_list->AddRect(
443 cursor_pos,
444 ImVec2(cursor_pos.x + card_size.x, cursor_pos.y + card_size.y),
445 border_color, rounding, 0, border_thickness);
446
447 // Recent indicator badge
448 if (is_recent) {
449 const float badge_radius =
450 std::clamp(line_height * 0.6f, line_height * 0.4f, line_height);
451 ImVec2 badge_pos(cursor_pos.x + card_size.x - padding_x - badge_radius,
452 cursor_pos.y + padding_y + badge_radius);
453 draw_list->AddCircleFilled(badge_pos, badge_radius,
454 ImGui::GetColorU32(base_color), 16);
455 const ImU32 star_color = ImGui::GetColorU32(text_primary);
456 const ImVec2 star_size =
457 text_font->CalcTextSizeA(text_font_size, FLT_MAX, 0.0f, ICON_MD_STAR);
458 const ImVec2 star_pos(badge_pos.x - star_size.x * 0.5f,
459 badge_pos.y - star_size.y * 0.5f);
460 draw_list->AddText(text_font, text_font_size, star_pos, star_color,
462 }
463
464 // Make button transparent (we draw our own background)
465 ImVec4 button_bg = ImGui::GetStyleColorVec4(ImGuiCol_Button);
466 button_bg.w = 0.0f;
467 gui::StyleColorGuard card_btn_guard(
468 {{ImGuiCol_Button, button_bg},
469 {ImGuiCol_ButtonHovered,
470 ScaleColor(base_color, 0.3f, enabled ? 0.5f : 0.2f)},
471 {ImGuiCol_ButtonActive,
472 ScaleColor(base_color, 0.5f, enabled ? 0.7f : 0.2f)}});
473
474 if (!enabled) {
475 ImGui::BeginDisabled();
476 }
477 bool clicked =
478 ImGui::Button(absl::StrCat("##", info.name).c_str(), card_size);
479 if (!enabled) {
480 ImGui::EndDisabled();
481 }
482 bool is_hovered = ImGui::IsItemHovered();
483
484 // Draw icon with colored background circle
485 ImU32 icon_bg =
486 ImGui::GetColorU32(WithAlpha(base_color, 1.0f * disabled_alpha));
487 draw_list->AddCircleFilled(icon_center, icon_radius, icon_bg, 32);
488
489 // Draw icon
490 ImFont* icon_font = ImGui::GetFont();
491 if (ImGui::GetIO().Fonts->Fonts.size() > 2 &&
492 card_size.y >= kDashboardCardBaseHeight) {
493 icon_font = ImGui::GetIO().Fonts->Fonts[2];
494 } else if (ImGui::GetIO().Fonts->Fonts.size() > 1) {
495 icon_font = ImGui::GetIO().Fonts->Fonts[1];
496 }
497 ImGui::PushFont(icon_font);
498 const float icon_font_size = ImGui::GetFontSize();
499 const ImVec2 icon_size = icon_font->CalcTextSizeA(icon_font_size, FLT_MAX,
500 0.0f, info.icon.c_str());
501 ImGui::PopFont();
502 const ImVec2 icon_text_pos(icon_center.x - icon_size.x * 0.5f,
503 icon_center.y - icon_size.y * 0.5f);
504 draw_list->AddText(icon_font, icon_font_size, icon_text_pos,
505 ImGui::GetColorU32(text_primary), info.icon.c_str());
506
507 // Draw name
508 const ImVec2 name_size = text_font->CalcTextSizeA(text_font_size, FLT_MAX,
509 0.0f, info.name.c_str());
510 float name_x = cursor_pos.x + (card_size.x - name_size.x) * 0.5f;
511 const float name_min_x = cursor_pos.x + padding_x;
512 const float name_max_x = cursor_pos.x + card_size.x - padding_x;
513 name_x = std::clamp(name_x, name_min_x, name_max_x);
514 const ImVec2 name_pos(name_x, title_y);
515 const ImVec4 name_clip(name_min_x, cursor_pos.y + padding_y, name_max_x,
516 footer_y);
517 draw_list->AddText(
518 text_font, text_font_size, name_pos,
519 ImGui::GetColorU32(WithAlpha(base_color, disabled_alpha)),
520 info.name.c_str(), nullptr, 0.0f, &name_clip);
521
522 // Draw shortcut hint if available
523 if (!info.shortcut.empty()) {
524 const ImVec2 shortcut_pos(cursor_pos.x + padding_x, footer_y);
525 const ImVec4 shortcut_clip(cursor_pos.x + padding_x, footer_y,
526 cursor_pos.x + card_size.x - padding_x,
527 cursor_pos.y + card_size.y - padding_y);
528 draw_list->AddText(text_font, text_font_size, shortcut_pos,
529 ImGui::GetColorU32(text_secondary),
530 info.shortcut.c_str(), nullptr, 0.0f, &shortcut_clip);
531 }
532
533 // Hover glow effect
534 if (is_hovered) {
535 ImU32 glow_color =
536 ImGui::GetColorU32(ScaleColor(base_color, 1.0f,
537 enabled ? 0.18f : 0.08f));
538 draw_list->AddRectFilled(
539 cursor_pos,
540 ImVec2(cursor_pos.x + card_size.x, cursor_pos.y + card_size.y),
541 glow_color, rounding);
542 }
543
544 // Enhanced tooltip
545 if (is_hovered) {
546 const float tooltip_width = std::clamp(card_size.x * 1.4f, 240.0f, 340.0f);
547 ImGui::SetNextWindowSize(ImVec2(tooltip_width, 0), ImGuiCond_Always);
548 ImGui::BeginTooltip();
549 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); // Medium font
550 ImGui::TextColored(WithAlpha(base_color, disabled_alpha), "%s %s",
551 info.icon.c_str(), info.name.c_str());
552 ImGui::PopFont();
553 ImGui::Separator();
554 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + tooltip_width - 20.0f);
555 if (!enabled) {
556 ImGui::TextWrapped("Load a ROM to open this editor.");
557 } else {
558 ImGui::TextWrapped("%s", info.description.c_str());
559 }
560 ImGui::PopTextWrapPos();
561 if (enabled && !info.shortcut.empty()) {
562 ImGui::Spacing();
563 ImGui::TextColored(WithAlpha(base_color, disabled_alpha),
564 ICON_MD_KEYBOARD " %s", info.shortcut.c_str());
565 }
566 if (is_recent) {
567 ImGui::Spacing();
568 ImGui::TextColored(accent, ICON_MD_STAR " Recently used");
569 }
570 ImGui::EndTooltip();
571 }
572
573 if (clicked && enabled) {
574 if (editor_switcher_) {
578 show_ = false;
579 }
580 }
581
582 ImGui::PopID();
583}
584
586 // Remove if already in list
587 auto it = std::find(recent_editors_.begin(), recent_editors_.end(), type);
588 if (it != recent_editors_.end()) {
589 recent_editors_.erase(it);
590 }
591
592 // Add to front
593 recent_editors_.insert(recent_editors_.begin(), type);
594
595 // Limit size
596 if (recent_editors_.size() > kMaxRecentEditors) {
598 }
599
601}
602
604 try {
605 auto data = util::LoadFileFromConfigDir("recent_editors.txt");
606 if (!data.empty()) {
607 std::istringstream ss(data);
608 std::string line;
609 while (std::getline(ss, line) &&
611 int type_int = std::stoi(line);
612 if (type_int >= 0 &&
613 type_int < static_cast<int>(EditorType::kSettings)) {
614 recent_editors_.push_back(static_cast<EditorType>(type_int));
615 }
616 }
617 }
618 } catch (...) {
619 // Ignore errors
620 }
621}
622
624 try {
625 std::ostringstream ss;
626 for (EditorType type : recent_editors_) {
627 ss << static_cast<int>(type) << "\n";
628 }
629 util::SaveFile("recent_editors.txt", ss.str());
630 } catch (...) {
631 // Ignore save errors
632 }
633}
634
639
640} // namespace editor
641} // namespace yaze
bool is_loaded() const
Definition rom.h:132
std::vector< EditorInfo > editors_
static constexpr size_t kMaxRecentEditors
std::vector< EditorType > recent_editors_
void MarkRecentlyUsed(EditorType type)
void DrawEditorPanel(const EditorInfo &info, int index, const ImVec2 &card_size, bool enabled)
DashboardPanel(IEditorSwitcher *editor_switcher)
IEditorSwitcher * editor_switcher_
Interface for editor selection and navigation.
virtual void SwitchToEditor(EditorType type, bool force_visible=false, bool from_dialog=false)=0
virtual void DismissEditorSelection()=0
virtual Rom * GetCurrentRom() const =0
void SetSaveSettings(bool save)
void SetPosition(Position pos)
bool Begin(bool *p_open=nullptr)
void SetDefaultSize(float width, float height)
RAII guard for ImGui style colors.
Definition style_guard.h:27
RAII guard for ImGui style vars.
Definition style_guard.h:68
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_APPS
Definition icons.h:168
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_EMOJI_EMOTIONS
Definition icons.h:672
#define ICON_MD_DATA_ARRAY
Definition icons.h:519
#define ICON_MD_STAR
Definition icons.h:1848
#define ICON_MD_MAP
Definition icons.h:1173
#define ICON_MD_CODE
Definition icons.h:434
#define ICON_MD_VIDEOGAME_ASSET
Definition icons.h:2076
#define ICON_MD_CHAT_BUBBLE
Definition icons.h:395
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_CASTLE
Definition icons.h:380
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1264
#define ICON_MD_KEYBOARD
Definition icons.h:1028
#define ICON_MD_DASHBOARD
Definition icons.h:517
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_TV
Definition icons.h:2032
#define ICON_MD_COLOR_LENS
Definition icons.h:440
#define ICON_MD_SMART_TOY
Definition icons.h:1781
#define ICON_MD_HISTORY
Definition icons.h:946
ImVec4 GetEditorAccentColor(EditorType type, const gui::Theme &theme)
ImVec4 ScaleColor(const ImVec4 &color, float scale, float alpha)
FlowLayout ComputeFlowLayout(float avail_width, float min_width, float max_width, float min_height, float max_height, float aspect_ratio, float spacing, int max_columns, int item_count)
const char * GetCtrlDisplayName()
Get the display name for the primary modifier key.
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:134
void SaveFile(const std::string &filename, const std::string &contents)
Definition file_util.cc:56
std::string LoadFileFromConfigDir(const std::string &filename)
Loads a file from the user's config directory.
Definition file_util.cc:38
Comprehensive theme structure for YAZE.