yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
editor_card_manager.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cstdio>
5
6#include "absl/strings/str_format.h"
7#include "app/gui/icons.h"
8#include "imgui/imgui.h"
9#include "util/file_util.h"
10
11namespace yaze {
12namespace gui {
13
15 static EditorCardManager instance;
16 return instance;
17}
18
20 if (info.card_id.empty()) {
21 printf("[EditorCardManager] Warning: Attempted to register card with empty ID\n");
22 return;
23 }
24
25 // Check if already registered to avoid duplicates
26 if (cards_.find(info.card_id) != cards_.end()) {
27 printf("[EditorCardManager] WARNING: Card '%s' already registered, skipping duplicate\n",
28 info.card_id.c_str());
29 return;
30 }
31
32 cards_[info.card_id] = info;
33 printf("[EditorCardManager] Registered card: %s (%s)\n",
34 info.card_id.c_str(), info.display_name.c_str());
35}
36
37void EditorCardManager::UnregisterCard(const std::string& card_id) {
38 auto it = cards_.find(card_id);
39 if (it != cards_.end()) {
40 printf("[EditorCardManager] Unregistered card: %s\n", card_id.c_str());
41 cards_.erase(it);
42 }
43}
44
46 printf("[EditorCardManager] Clearing all %zu registered cards\n", cards_.size());
47 cards_.clear();
48}
49
50bool EditorCardManager::ShowCard(const std::string& card_id) {
51 auto it = cards_.find(card_id);
52 if (it == cards_.end()) {
53 return false;
54 }
55
56 if (it->second.visibility_flag) {
57 *it->second.visibility_flag = true;
58
59 if (it->second.on_show) {
60 it->second.on_show();
61 }
62
63 return true;
64 }
65
66 return false;
67}
68
69bool EditorCardManager::HideCard(const std::string& card_id) {
70 auto it = cards_.find(card_id);
71 if (it == cards_.end()) {
72 return false;
73 }
74
75 if (it->second.visibility_flag) {
76 *it->second.visibility_flag = false;
77
78 if (it->second.on_hide) {
79 it->second.on_hide();
80 }
81
82 return true;
83 }
84
85 return false;
86}
87
88bool EditorCardManager::ToggleCard(const std::string& card_id) {
89 auto it = cards_.find(card_id);
90 if (it == cards_.end()) {
91 return false;
92 }
93
94 if (it->second.visibility_flag) {
95 bool new_state = !(*it->second.visibility_flag);
96 *it->second.visibility_flag = new_state;
97
98 if (new_state && it->second.on_show) {
99 it->second.on_show();
100 } else if (!new_state && it->second.on_hide) {
101 it->second.on_hide();
102 }
103
104 return true;
105 }
106
107 return false;
108}
109
110bool EditorCardManager::IsCardVisible(const std::string& card_id) const {
111 auto it = cards_.find(card_id);
112 if (it != cards_.end() && it->second.visibility_flag) {
113 return *it->second.visibility_flag;
114 }
115 return false;
116}
117
118void EditorCardManager::ShowAllCardsInCategory(const std::string& category) {
119 for (auto& [id, info] : cards_) {
120 if (info.category == category && info.visibility_flag) {
121 *info.visibility_flag = true;
122 if (info.on_show) info.on_show();
123 }
124 }
125}
126
127void EditorCardManager::HideAllCardsInCategory(const std::string& category) {
128 for (auto& [id, info] : cards_) {
129 if (info.category == category && info.visibility_flag) {
130 *info.visibility_flag = false;
131 if (info.on_hide) info.on_hide();
132 }
133 }
134}
135
136void EditorCardManager::ShowOnlyCard(const std::string& card_id) {
137 auto target = cards_.find(card_id);
138 if (target == cards_.end()) {
139 return;
140 }
141
142 std::string category = target->second.category;
143
144 // Hide all cards in the same category
145 for (auto& [id, info] : cards_) {
146 if (info.category == category && info.visibility_flag) {
147 *info.visibility_flag = (id == card_id);
148
149 if (id == card_id && info.on_show) {
150 info.on_show();
151 } else if (id != card_id && info.on_hide) {
152 info.on_hide();
153 }
154 }
155 }
156}
157
158std::vector<CardInfo> EditorCardManager::GetCardsInCategory(const std::string& category) const {
159 std::vector<CardInfo> result;
160
161 for (const auto& [id, info] : cards_) {
162 if (info.category == category) {
163 result.push_back(info);
164 }
165 }
166
167 // Sort by priority
168 std::sort(result.begin(), result.end(),
169 [](const CardInfo& a, const CardInfo& b) {
170 return a.priority < b.priority;
171 });
172
173 return result;
174}
175
176std::vector<std::string> EditorCardManager::GetAllCategories() const {
177 std::vector<std::string> categories;
178
179 for (const auto& [id, info] : cards_) {
180 if (std::find(categories.begin(), categories.end(), info.category) == categories.end()) {
181 categories.push_back(info.category);
182 }
183 }
184
185 std::sort(categories.begin(), categories.end());
186 return categories;
187}
188
189const CardInfo* EditorCardManager::GetCardInfo(const std::string& card_id) const {
190 auto it = cards_.find(card_id);
191 return (it != cards_.end()) ? &it->second : nullptr;
192}
193
194void EditorCardManager::DrawViewMenuSection(const std::string& category) {
195 auto cards_in_category = GetCardsInCategory(category);
196
197 if (cards_in_category.empty()) {
198 ImGui::MenuItem("(No cards registered)", nullptr, false, false);
199 return;
200 }
201
202 for (const auto& info : cards_in_category) {
203 if (!info.visibility_flag) continue;
204
205 std::string label = info.icon.empty()
206 ? info.display_name
207 : info.icon + " " + info.display_name;
208
209 bool visible = *info.visibility_flag;
210
211 if (ImGui::MenuItem(label.c_str(),
212 info.shortcut_hint.empty() ? nullptr : info.shortcut_hint.c_str(),
213 visible)) {
214 ToggleCard(info.card_id);
215 }
216 }
217}
218
220 auto categories = GetAllCategories();
221
222 if (categories.empty()) {
223 ImGui::TextDisabled("No cards registered");
224 return;
225 }
226
227 for (const auto& category : categories) {
228 if (ImGui::BeginMenu(category.c_str())) {
229 DrawViewMenuSection(category);
230 ImGui::Separator();
231
232 // Category-level actions
233 if (ImGui::MenuItem(absl::StrFormat("%s Show All", ICON_MD_VISIBILITY).c_str())) {
234 ShowAllCardsInCategory(category);
235 }
236
237 if (ImGui::MenuItem(absl::StrFormat("%s Hide All", ICON_MD_VISIBILITY_OFF).c_str())) {
238 HideAllCardsInCategory(category);
239 }
240
241 ImGui::EndMenu();
242 }
243 }
244
245 ImGui::Separator();
246
247 // Global actions
248 if (ImGui::MenuItem(absl::StrFormat("%s Show All Cards", ICON_MD_VISIBILITY).c_str())) {
249 ShowAll();
250 }
251
252 if (ImGui::MenuItem(absl::StrFormat("%s Hide All Cards", ICON_MD_VISIBILITY_OFF).c_str())) {
253 HideAll();
254 }
255
256 ImGui::Separator();
257
258 if (ImGui::MenuItem(absl::StrFormat("%s Card Browser", ICON_MD_DASHBOARD).c_str(),
259 "Ctrl+Shift+B")) {
260 // This will be shown by EditorManager
261 }
262}
263
264void EditorCardManager::DrawCompactCardControl(const std::string& category) {
265 auto cards_in_category = GetCardsInCategory(category);
266
267 if (cards_in_category.empty()) {
268 return; // Nothing to show
269 }
270
271 // Use theme colors for button
272 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4(ImGuiCol_Button));
273 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered));
274 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive));
275
276 if (ImGui::SmallButton(ICON_MD_VIEW_MODULE)) {
277 ImGui::OpenPopup("CardControlPopup");
278 }
279
280 ImGui::PopStyleColor(3);
281
282 if (ImGui::IsItemHovered()) {
283 ImGui::SetTooltip("%s Card Controls", category.c_str());
284 }
285
286 // Compact popup with checkboxes
287 if (ImGui::BeginPopup("CardControlPopup")) {
288 ImGui::TextColored(ImVec4(0.7f, 0.9f, 1.0f, 1.0f), "%s %s Cards",
289 ICON_MD_DASHBOARD, category.c_str());
290 ImGui::Separator();
291
292 for (const auto& info : cards_in_category) {
293 if (!info.visibility_flag) continue;
294
295 std::string label = info.icon.empty()
296 ? info.display_name
297 : info.icon + " " + info.display_name;
298
299 bool visible = *info.visibility_flag;
300 if (ImGui::Checkbox(label.c_str(), &visible)) {
301 *info.visibility_flag = visible;
302 if (visible && info.on_show) {
303 info.on_show();
304 } else if (!visible && info.on_hide) {
305 info.on_hide();
306 }
307 }
308
309 // Show shortcut hint
310 if (!info.shortcut_hint.empty()) {
311 ImGui::SameLine();
312 ImGui::TextDisabled("(%s)", info.shortcut_hint.c_str());
313 }
314 }
315
316 ImGui::Separator();
317
318 if (ImGui::MenuItem(absl::StrFormat("%s Show All", ICON_MD_VISIBILITY).c_str())) {
319 ShowAllCardsInCategory(category);
320 }
321
322 if (ImGui::MenuItem(absl::StrFormat("%s Hide All", ICON_MD_VISIBILITY_OFF).c_str())) {
323 HideAllCardsInCategory(category);
324 }
325
326 ImGui::EndPopup();
327 }
328}
329
330void EditorCardManager::DrawInlineCardToggles(const std::string& category) {
331 auto cards_in_category = GetCardsInCategory(category);
332
333 if (cards_in_category.empty()) {
334 return;
335 }
336
337 // Show visible count as indicator
338 size_t visible_count = 0;
339 for (const auto& info : cards_in_category) {
340 if (info.visibility_flag && *info.visibility_flag) {
341 visible_count++;
342 }
343 }
344
345 ImGui::TextDisabled("%s %zu/%zu", ICON_MD_DASHBOARD, visible_count, cards_in_category.size());
346
347 if (ImGui::IsItemHovered()) {
348 ImGui::SetTooltip("%s cards: %zu visible, %zu hidden",
349 category.c_str(), visible_count,
350 cards_in_category.size() - visible_count);
351 }
352}
353
355 if (!p_open || !*p_open) return;
356
357 ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
358 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
359 ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
360
361 if (!ImGui::Begin(absl::StrFormat("%s Card Browser", ICON_MD_DASHBOARD).c_str(),
362 p_open)) {
363 ImGui::End();
364 return;
365 }
366
367 // Search filter
368 static char search_filter[256] = "";
369 ImGui::SetNextItemWidth(-100);
370 ImGui::InputTextWithHint("##CardSearch",
371 absl::StrFormat("%s Search cards...", ICON_MD_SEARCH).c_str(),
372 search_filter, sizeof(search_filter));
373
374 ImGui::SameLine();
375 if (ImGui::Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) {
376 search_filter[0] = '\0';
377 }
378
379 ImGui::Separator();
380
381 // Statistics
382 ImGui::Text("%s Total Cards: %zu | Visible: %zu",
384
385 ImGui::Separator();
386
387 // Category tabs
388 if (ImGui::BeginTabBar("CardBrowserTabs")) {
389
390 // All Cards tab
391 if (ImGui::BeginTabItem(absl::StrFormat("%s All", ICON_MD_APPS).c_str())) {
392 DrawCardBrowserTable(search_filter, "");
393 ImGui::EndTabItem();
394 }
395
396 // Category tabs
397 for (const auto& category : GetAllCategories()) {
398 std::string tab_label = category;
399 if (ImGui::BeginTabItem(tab_label.c_str())) {
400 DrawCardBrowserTable(search_filter, category);
401 ImGui::EndTabItem();
402 }
403 }
404
405 // Presets tab
406 if (ImGui::BeginTabItem(absl::StrFormat("%s Presets", ICON_MD_BOOKMARK).c_str())) {
408 ImGui::EndTabItem();
409 }
410
411 ImGui::EndTabBar();
412 }
413
414 ImGui::End();
415}
416
417void EditorCardManager::DrawCardBrowserTable(const char* search_filter,
418 const std::string& category_filter) {
419 if (ImGui::BeginTable("CardBrowserTable", 4,
420 ImGuiTableFlags_Borders |
421 ImGuiTableFlags_RowBg |
422 ImGuiTableFlags_Resizable |
423 ImGuiTableFlags_ScrollY)) {
424
425 ImGui::TableSetupColumn("Card", ImGuiTableColumnFlags_WidthStretch, 0.4f);
426 ImGui::TableSetupColumn("Category", ImGuiTableColumnFlags_WidthStretch, 0.2f);
427 ImGui::TableSetupColumn("Shortcut", ImGuiTableColumnFlags_WidthStretch, 0.2f);
428 ImGui::TableSetupColumn("Visible", ImGuiTableColumnFlags_WidthFixed, 80.0f);
429 ImGui::TableHeadersRow();
430
431 // Collect and sort cards
432 std::vector<CardInfo> display_cards;
433 for (const auto& [id, info] : cards_) {
434 // Apply filters
435 if (!category_filter.empty() && info.category != category_filter) {
436 continue;
437 }
438
439 if (search_filter && search_filter[0] != '\0') {
440 std::string search_lower = search_filter;
441 std::transform(search_lower.begin(), search_lower.end(),
442 search_lower.begin(), ::tolower);
443
444 std::string name_lower = info.display_name;
445 std::transform(name_lower.begin(), name_lower.end(),
446 name_lower.begin(), ::tolower);
447
448 if (name_lower.find(search_lower) == std::string::npos) {
449 continue;
450 }
451 }
452
453 display_cards.push_back(info);
454 }
455
456 // Sort by category then priority
457 std::sort(display_cards.begin(), display_cards.end(),
458 [](const CardInfo& a, const CardInfo& b) {
459 if (a.category != b.category) return a.category < b.category;
460 return a.priority < b.priority;
461 });
462
463 // Draw rows
464 for (const auto& info : display_cards) {
465 ImGui::PushID(info.card_id.c_str());
466
467 ImGui::TableNextRow();
468 ImGui::TableNextColumn();
469
470 // Card name with icon
471 std::string label = info.icon.empty()
472 ? info.display_name
473 : info.icon + " " + info.display_name;
474 ImGui::Text("%s", label.c_str());
475
476 ImGui::TableNextColumn();
477 ImGui::TextDisabled("%s", info.category.c_str());
478
479 ImGui::TableNextColumn();
480 if (!info.shortcut_hint.empty()) {
481 ImGui::TextDisabled("%s", info.shortcut_hint.c_str());
482 }
483
484 ImGui::TableNextColumn();
485 if (info.visibility_flag) {
486 bool visible = *info.visibility_flag;
487 if (ImGui::Checkbox("##Visible", &visible)) {
488 *info.visibility_flag = visible;
489 if (visible && info.on_show) {
490 info.on_show();
491 } else if (!visible && info.on_hide) {
492 info.on_hide();
493 }
494 }
495 }
496
497 ImGui::PopID();
498 }
499
500 ImGui::EndTable();
501 }
502}
503
505 ImGui::Text("%s Workspace Presets", ICON_MD_BOOKMARK);
506 ImGui::Separator();
507
508 // Save current as preset
509 static char preset_name[256] = "";
510 static char preset_desc[512] = "";
511
512 ImGui::Text("Save Current Layout:");
513 ImGui::InputText("Name", preset_name, sizeof(preset_name));
514 ImGui::InputText("Description", preset_desc, sizeof(preset_desc));
515
516 if (ImGui::Button(absl::StrFormat("%s Save Preset", ICON_MD_SAVE).c_str())) {
517 if (preset_name[0] != '\0') {
518 SavePreset(preset_name, preset_desc);
519 preset_name[0] = '\0';
520 preset_desc[0] = '\0';
521 }
522 }
523
524 ImGui::Separator();
525 ImGui::Text("Saved Presets:");
526
527 // List presets
528 auto presets = GetPresets();
529 if (presets.empty()) {
530 ImGui::TextDisabled("No presets saved");
531 } else {
532 for (const auto& preset : presets) {
533 ImGui::PushID(preset.name.c_str());
534
535 if (ImGui::Button(absl::StrFormat("%s Load", ICON_MD_FOLDER_OPEN).c_str())) {
536 LoadPreset(preset.name);
537 }
538
539 ImGui::SameLine();
540 if (ImGui::Button(absl::StrFormat("%s Delete", ICON_MD_DELETE).c_str())) {
541 DeletePreset(preset.name);
542 }
543
544 ImGui::SameLine();
545 ImGui::Text("%s %s", ICON_MD_BOOKMARK, preset.name.c_str());
546
547 if (!preset.description.empty()) {
548 ImGui::SameLine();
549 ImGui::TextDisabled("- %s", preset.description.c_str());
550 }
551
552 ImGui::SameLine();
553 ImGui::TextDisabled("(%zu cards)", preset.visible_cards.size());
554
555 ImGui::PopID();
556 }
557 }
558}
559
560void EditorCardManager::SavePreset(const std::string& name, const std::string& description) {
561 WorkspacePreset preset;
562 preset.name = name;
563 preset.description = description;
564
565 // Save currently visible cards
566 for (const auto& [id, info] : cards_) {
567 if (info.visibility_flag && *info.visibility_flag) {
568 preset.visible_cards.push_back(id);
569 }
570 }
571
572 presets_[name] = preset;
574
575 printf("[EditorCardManager] Saved preset '%s' with %zu cards\n",
576 name.c_str(), preset.visible_cards.size());
577}
578
579bool EditorCardManager::LoadPreset(const std::string& name) {
580 auto it = presets_.find(name);
581 if (it == presets_.end()) {
582 return false;
583 }
584
585 // Hide all cards first
586 HideAll();
587
588 // Show cards in preset
589 for (const auto& card_id : it->second.visible_cards) {
590 ShowCard(card_id);
591 }
592
593 printf("[EditorCardManager] Loaded preset '%s' with %zu cards\n",
594 name.c_str(), it->second.visible_cards.size());
595
596 return true;
597}
598
599void EditorCardManager::DeletePreset(const std::string& name) {
600 auto it = presets_.find(name);
601 if (it != presets_.end()) {
602 presets_.erase(it);
604 printf("[EditorCardManager] Deleted preset '%s'\n", name.c_str());
605 }
606}
607
608std::vector<EditorCardManager::WorkspacePreset> EditorCardManager::GetPresets() const {
609 std::vector<WorkspacePreset> result;
610 for (const auto& [name, preset] : presets_) {
611 result.push_back(preset);
612 }
613 return result;
614}
615
617 for (auto& [id, info] : cards_) {
618 if (info.visibility_flag) {
619 *info.visibility_flag = true;
620 if (info.on_show) info.on_show();
621 }
622 }
623}
624
626 for (auto& [id, info] : cards_) {
627 if (info.visibility_flag) {
628 *info.visibility_flag = false;
629 if (info.on_hide) info.on_hide();
630 }
631 }
632}
633
635 // Default visibility based on priority
636 for (auto& [id, info] : cards_) {
637 if (info.visibility_flag) {
638 // Show high-priority cards (priority < 50)
639 *info.visibility_flag = (info.priority < 50);
640
641 if (*info.visibility_flag && info.on_show) {
642 info.on_show();
643 } else if (!*info.visibility_flag && info.on_hide) {
644 info.on_hide();
645 }
646 }
647 }
648}
649
651 size_t count = 0;
652 for (const auto& [id, info] : cards_) {
653 if (info.visibility_flag && *info.visibility_flag) {
654 count++;
655 }
656 }
657 return count;
658}
659
661 // Save presets to JSON or simple format
662 // TODO: Implement file I/O
663 printf("[EditorCardManager] Saving %zu presets to file\n", presets_.size());
664}
665
667 // Load presets from file
668 // TODO: Implement file I/O
669 printf("[EditorCardManager] Loading presets from file\n");
670}
671
672} // namespace gui
673} // namespace yaze
674
Central registry and manager for all editor cards.
void DrawInlineCardToggles(const std::string &category)
bool ShowCard(const std::string &card_id)
void ShowAllCardsInCategory(const std::string &category)
void DrawViewMenuSection(const std::string &category)
bool LoadPreset(const std::string &name)
void HideAllCardsInCategory(const std::string &category)
std::vector< CardInfo > GetCardsInCategory(const std::string &category) const
void UnregisterCard(const std::string &card_id)
bool ToggleCard(const std::string &card_id)
bool IsCardVisible(const std::string &card_id) const
void RegisterCard(const CardInfo &info)
std::vector< WorkspacePreset > GetPresets() const
bool HideCard(const std::string &card_id)
std::unordered_map< std::string, WorkspacePreset > presets_
std::vector< std::string > GetAllCategories() const
void DrawCompactCardControl(const std::string &category)
static EditorCardManager & Get()
void ShowOnlyCard(const std::string &card_id)
std::unordered_map< std::string, CardInfo > cards_
const CardInfo * GetCardInfo(const std::string &card_id) const
void SavePreset(const std::string &name, const std::string &description="")
void DrawCardBrowserTable(const char *search_filter, const std::string &category_filter)
void DeletePreset(const std::string &name)
#define ICON_MD_FOLDER_OPEN
Definition icons.h:811
#define ICON_MD_APPS
Definition icons.h:166
#define ICON_MD_INFO
Definition icons.h:991
#define ICON_MD_VIEW_MODULE
Definition icons.h:2091
#define ICON_MD_SEARCH
Definition icons.h:1671
#define ICON_MD_VISIBILITY
Definition icons.h:2099
#define ICON_MD_VISIBILITY_OFF
Definition icons.h:2100
#define ICON_MD_CLEAR
Definition icons.h:414
#define ICON_MD_DASHBOARD
Definition icons.h:515
#define ICON_MD_SAVE
Definition icons.h:1642
#define ICON_MD_BOOKMARK
Definition icons.h:283
#define ICON_MD_DELETE
Definition icons.h:528
Main namespace for the application.
Metadata for an editor card.