yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
activity_bar.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cctype>
5#include <cstddef>
6#include <functional>
7#include <string>
8#include <unordered_set>
9#include <vector>
10
11#include "absl/strings/str_format.h"
13#include "app/gui/core/icons.h"
16#include "core/color.h"
17#include "imgui/imgui.h"
18
19namespace yaze {
20namespace editor {
21
23 : panel_manager_(panel_manager) {}
24
26 size_t session_id, const std::string& active_category,
27 const std::vector<std::string>& all_categories,
28 const std::unordered_set<std::string>& active_editor_categories,
29 std::function<bool()> has_rom) {
31 return;
32
33 DrawActivityBarStrip(session_id, active_category, all_categories,
34 active_editor_categories, has_rom);
35
37 DrawSidePanel(session_id, active_category, has_rom);
38 }
39}
40
42 size_t session_id, const std::string& active_category,
43 const std::vector<std::string>& all_categories,
44 const std::unordered_set<std::string>& active_editor_categories,
45 std::function<bool()> has_rom) {
46
47 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
48 const ImGuiViewport* viewport = ImGui::GetMainViewport();
49 const float viewport_height = viewport->WorkSize.y;
50 const float bar_width = 48.0f; // Fixed width for Activity Bar
51
52 // Position on left edge, full height
53 ImGui::SetNextWindowPos(ImVec2(viewport->WorkPos.x, viewport->WorkPos.y));
54 ImGui::SetNextWindowSize(ImVec2(bar_width, viewport_height));
55
56 ImVec4 bar_bg = gui::ConvertColorToImVec4(theme.surface);
57 ImVec4 bar_border = gui::ConvertColorToImVec4(theme.text_disabled);
58
59 ImGuiWindowFlags flags =
60 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
61 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
62 ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoScrollbar |
63 ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNavFocus |
64 ImGuiWindowFlags_NoBringToFrontOnFocus;
65
66 ImGui::PushStyleColor(ImGuiCol_WindowBg, bar_bg);
67 ImGui::PushStyleColor(ImGuiCol_Border, bar_border);
68 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 8.0f));
69 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 8.0f)); // Increased spacing
70 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
71
72 if (ImGui::Begin("##ActivityBar", nullptr, flags)) {
73
74 // Global Search / Command Palette at top
75 if (gui::TransparentIconButton(ICON_MD_SEARCH, ImVec2(48.0f, 40.0f),
76 "Global Search (Ctrl+Shift+F)", false)) {
78 }
79
80 // Separator
81 ImGui::Spacing();
82 ImVec2 sep_p1 = ImGui::GetCursorScreenPos();
83 ImVec2 sep_p2 = ImVec2(sep_p1.x + 48.0f, sep_p1.y);
84 ImGui::GetWindowDrawList()->AddLine(
85 sep_p1, sep_p2,
86 ImGui::ColorConvertFloat4ToU32(gui::ConvertColorToImVec4(theme.border)),
87 1.0f);
88 ImGui::Spacing();
89
90 bool rom_loaded = has_rom ? has_rom() : false;
91
92 // Draw ALL editor categories (not just active ones)
93 for (const auto& cat : all_categories) {
94 bool is_selected =
95 (cat == active_category) && panel_manager_.IsPanelExpanded();
96 bool has_active_editor = active_editor_categories.count(cat) > 0;
97
98 // Emulator is always available, others require ROM
99 bool category_enabled = rom_loaded || (cat == "Emulator");
100
101 // Get category-specific theme colors for expressive appearance
102 auto cat_theme = PanelManager::GetCategoryTheme(cat);
103 ImVec4 cat_color(cat_theme.r, cat_theme.g, cat_theme.b, cat_theme.a);
104 ImVec4 glow_color(cat_theme.glow_r, cat_theme.glow_g, cat_theme.glow_b, 1.0f);
105
106 // Active Indicator with category-specific colors
107 if (is_selected && category_enabled) {
108 ImVec2 pos = ImGui::GetCursorScreenPos();
109
110 // Outer glow shadow (subtle, category color at 15% opacity)
111 ImVec4 outer_glow = glow_color;
112 outer_glow.w = 0.15f;
113 ImGui::GetWindowDrawList()->AddRectFilled(
114 ImVec2(pos.x - 1.0f, pos.y - 1.0f),
115 ImVec2(pos.x + 49.0f, pos.y + 41.0f),
116 ImGui::ColorConvertFloat4ToU32(outer_glow), 4.0f);
117
118 // Background highlight (category glow at 30% opacity)
119 ImVec4 highlight = glow_color;
120 highlight.w = 0.30f;
121 ImGui::GetWindowDrawList()->AddRectFilled(
122 pos,
123 ImVec2(pos.x + 48.0f, pos.y + 40.0f),
124 ImGui::ColorConvertFloat4ToU32(highlight), 2.0f);
125
126 // Left accent border (4px wide, category-specific color)
127 ImGui::GetWindowDrawList()->AddRectFilled(
128 pos,
129 ImVec2(pos.x + 4.0f, pos.y + 40.0f),
130 ImGui::ColorConvertFloat4ToU32(cat_color));
131 }
132
133 std::string icon = PanelManager::GetCategoryIcon(cat);
134
135 // Use ThemedWidgets with category-specific color when active
136 ImVec4 icon_color = is_selected ? cat_color : ImVec4(0, 0, 0, 0); // 0 = use default
137 if (gui::TransparentIconButton(icon.c_str(), ImVec2(48.0f, 40.0f),
138 nullptr, is_selected, icon_color)) {
139 if (category_enabled) {
140 if (cat == active_category && panel_manager_.IsPanelExpanded()) {
142 } else {
145 // Notify that a category was selected (dismisses dashboard)
147 }
148 }
149 }
150
151 // Tooltip with status information
152 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
153 ImGui::BeginTooltip();
154 ImGui::Text("%s %s", icon.c_str(), cat.c_str());
155 if (!category_enabled) {
156 ImGui::TextColored(gui::ConvertColorToImVec4(theme.warning),
157 "Open ROM required");
158 } else if (has_active_editor) {
159 ImGui::PushStyleColor(ImGuiCol_Text,
160 gui::ConvertColorToImVec4(theme.success));
161 ImGui::TextUnformatted("Editor open");
162 ImGui::PopStyleColor();
163 } else {
164 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
165 ImGui::TextUnformatted("Click to view panels");
166 ImGui::PopStyleColor();
167 }
168 ImGui::EndTooltip();
169 }
170 }
171 }
172
173 // Draw "More Actions" button at the bottom
174 ImGui::SetCursorPosY(viewport_height - 48.0f);
175
176 if (gui::TransparentIconButton(ICON_MD_MORE_HORIZ, ImVec2(48.0f, 48.0f))) {
177 ImGui::OpenPopup("ActivityBarMoreMenu");
178 }
179
180 if (ImGui::BeginPopup("ActivityBarMoreMenu")) {
181 if (ImGui::MenuItem(ICON_MD_TERMINAL " Command Palette")) {
183 }
184 if (ImGui::MenuItem(ICON_MD_KEYBOARD " Keyboard Shortcuts")) {
186 }
187 ImGui::Separator();
188 if (ImGui::MenuItem(ICON_MD_FOLDER_OPEN " Open ROM")) {
190 }
191 if (ImGui::MenuItem(ICON_MD_SETTINGS " Settings")) {
193 }
194 ImGui::Separator();
195 if (ImGui::MenuItem("Reset Layout")) {
196 // TODO: Implement layout reset
197 }
198 ImGui::EndPopup();
199 }
200
201 ImGui::End();
202
203 ImGui::PopStyleVar(3);
204 ImGui::PopStyleColor(2);
205}
206
207void ActivityBar::DrawSidePanel(size_t session_id, const std::string& category,
208 std::function<bool()> has_rom) {
209
210 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
211 const ImGuiViewport* viewport = ImGui::GetMainViewport();
212 const float bar_width = PanelManager::GetSidebarWidth();
213 const float panel_width = PanelManager::GetSidePanelWidth();
214
215 ImGui::SetNextWindowPos(
216 ImVec2(viewport->WorkPos.x + bar_width, viewport->WorkPos.y));
217 ImGui::SetNextWindowSize(ImVec2(panel_width, viewport->WorkSize.y));
218
219 ImVec4 panel_bg = gui::ConvertColorToImVec4(theme.surface);
220
221 ImGuiWindowFlags flags =
222 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
223 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
224 ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoFocusOnAppearing;
225
226 ImGui::PushStyleColor(ImGuiCol_WindowBg, panel_bg);
227 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
228 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f); // Right border
229 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,
230 ImVec2(12.0f, 12.0f)); // Consistent padding
231
232 if (ImGui::Begin("##SidePanel", nullptr, flags)) {
233 // Header
234 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]); // Use default font
235 ImGui::Text("%s", category.c_str());
236 ImGui::PopFont();
237
238 // Header Buttons (Right Aligned)
239 float avail_width = ImGui::GetContentRegionAvail().x;
240 float button_size = 28.0f;
241 float spacing = 4.0f;
242 float current_x = ImGui::GetCursorPosX() + avail_width - button_size;
243
244 // Collapse Button (rightmost)
245 ImGui::SameLine(current_x);
246 ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 4.0f);
247 if (ImGui::Button(ICON_MD_KEYBOARD_DOUBLE_ARROW_LEFT,
248 ImVec2(button_size, button_size))) {
250 }
251 if (ImGui::IsItemHovered()) {
252 ImGui::SetTooltip("Collapse Panel");
253 }
254
255 // Close All Panels Button
256 current_x -= (button_size + spacing);
257 ImGui::SameLine(current_x);
258 if (ImGui::Button(ICON_MD_CLOSE_FULLSCREEN,
259 ImVec2(button_size, button_size))) {
260 panel_manager_.HideAllPanelsInCategory(session_id, category);
261 }
262 if (ImGui::IsItemHovered()) {
263 ImGui::SetTooltip("Close All Panels");
264 }
265
266 // Expand All Panels Button
267 current_x -= (button_size + spacing);
268 ImGui::SameLine(current_x);
269 if (ImGui::Button(ICON_MD_OPEN_IN_FULL, ImVec2(button_size, button_size))) {
270 panel_manager_.ShowAllPanelsInCategory(session_id, category);
271 }
272 if (ImGui::IsItemHovered()) {
273 ImGui::SetTooltip("Show All Panels");
274 }
275
276 ImGui::Spacing();
277 ImGui::Separator();
278 ImGui::Spacing();
279
280 // Search Bar
281 static char sidebar_search[256] = "";
282 ImGui::SetNextItemWidth(-1);
283 ImGui::InputTextWithHint("##SidebarSearch", ICON_MD_SEARCH " Filter...",
284 sidebar_search, sizeof(sidebar_search));
285 ImGui::Spacing();
286
287 // Disable non-emulator categories when no ROM is loaded
288 const bool rom_loaded = has_rom ? has_rom() : true;
289 const bool disable_cards = !rom_loaded && category != "Emulator";
290 if (disable_cards) {
291 ImGui::TextUnformatted(ICON_MD_FOLDER_OPEN
292 " Open a ROM to enable this category");
293 ImGui::Spacing();
294 }
295
296 if (disable_cards) {
297 ImGui::BeginDisabled();
298 }
299
300 // Get pinned and recent panels
301 const auto pinned_cards = panel_manager_.GetPinnedPanels();
302 const auto& recent_cards = panel_manager_.GetRecentPanels();
303
304 // --- Pinned Section (panels that persist across editors) ---
305 if (sidebar_search[0] == '\0' && !pinned_cards.empty()) {
306 bool has_pinned_in_category = false;
307 for (const auto& card_id : pinned_cards) {
308 const auto* card =
309 panel_manager_.GetPanelDescriptor(session_id, card_id);
310 if (card && card->category == category) {
311 has_pinned_in_category = true;
312 break;
313 }
314 }
315
316 if (has_pinned_in_category) {
317 if (ImGui::CollapsingHeader(ICON_MD_PUSH_PIN " Pinned",
318 ImGuiTreeNodeFlags_DefaultOpen)) {
319 for (const auto& card_id : pinned_cards) {
320 const auto* card =
321 panel_manager_.GetPanelDescriptor(session_id, card_id);
322 if (!card || card->category != category)
323 continue;
324
325 bool visible =
326 card->visibility_flag ? *card->visibility_flag : false;
327
328 // Unpin button
329 ImGui::PushStyleColor(ImGuiCol_Text,
330 gui::ConvertColorToImVec4(theme.primary));
331 if (ImGui::SmallButton(
332 (std::string(ICON_MD_PUSH_PIN "##pin_") + card->card_id)
333 .c_str())) {
334 panel_manager_.SetPanelPinned(card->card_id, false);
335 }
336 ImGui::PopStyleColor();
337 if (ImGui::IsItemHovered()) {
338 ImGui::SetTooltip("Unpin panel");
339 }
340
341 ImGui::SameLine();
342
343 // Panel Item
344 std::string label = absl::StrFormat("%s %s", card->icon.c_str(),
345 card->display_name.c_str());
346 if (ImGui::Selectable(label.c_str(), visible)) {
347 panel_manager_.TogglePanel(session_id, card->card_id);
348
349 bool new_visible =
350 card->visibility_flag ? *card->visibility_flag : false;
351 if (new_visible) {
352 panel_manager_.TriggerPanelClicked(card->category);
353 ImGui::SetWindowFocus(card->GetWindowTitle().c_str());
354 }
355 }
356 }
357 ImGui::Spacing();
358 ImGui::Separator();
359 ImGui::Spacing();
360 }
361 }
362 }
363
364 // --- Recent Section ---
365 if (sidebar_search[0] == '\0' && !recent_cards.empty()) {
366 bool has_recents_in_category = false;
367 for (const auto& card_id : recent_cards) {
368 const auto* card =
369 panel_manager_.GetPanelDescriptor(session_id, card_id);
370 if (card && card->category == category) {
371 has_recents_in_category = true;
372 break;
373 }
374 }
375
376 if (has_recents_in_category) {
377 if (ImGui::CollapsingHeader(ICON_MD_HISTORY " Recent",
378 ImGuiTreeNodeFlags_DefaultOpen)) {
379 for (const auto& card_id : recent_cards) {
380 const auto* card =
381 panel_manager_.GetPanelDescriptor(session_id, card_id);
382 if (!card || card->category != category)
383 continue;
384
385 bool visible =
386 card->visibility_flag ? *card->visibility_flag : false;
387
388 // Pin Toggle Button
389 bool is_pinned = panel_manager_.IsPanelPinned(card->card_id);
390 ImGui::PushID((std::string("recent_") + card->card_id).c_str());
391 if (is_pinned) {
392 ImGui::PushStyleColor(ImGuiCol_Text,
393 gui::ConvertColorToImVec4(theme.primary));
394 if (ImGui::SmallButton(ICON_MD_PUSH_PIN)) {
395 panel_manager_.SetPanelPinned(card->card_id, false);
396 }
397 ImGui::PopStyleColor();
398 } else {
399 ImGui::PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(
400 theme.text_disabled));
401 if (ImGui::SmallButton(ICON_MD_PUSH_PIN)) {
402 panel_manager_.SetPanelPinned(card->card_id, true);
403 }
404 ImGui::PopStyleColor();
405 }
406 ImGui::PopID();
407 ImGui::SameLine();
408
409 // Panel Item
410 std::string label = absl::StrFormat("%s %s", card->icon.c_str(),
411 card->display_name.c_str());
412 if (ImGui::Selectable(label.c_str(), visible)) {
413 panel_manager_.TogglePanel(session_id, card->card_id);
414
415 bool new_visible =
416 card->visibility_flag ? *card->visibility_flag : false;
417 if (new_visible) {
418 panel_manager_.AddToRecent(card->card_id); // Move to top
419 panel_manager_.TriggerPanelClicked(card->category);
420 ImGui::SetWindowFocus(card->GetWindowTitle().c_str());
421 }
422 }
423 }
424 ImGui::Spacing();
425 ImGui::Separator();
426 ImGui::Spacing();
427 }
428 }
429 }
430
431 // Content - Reusing GetPanelsInCategory logic
432 auto cards = panel_manager_.GetPanelsInCategory(session_id, category);
433
434 // Calculate available height for cards vs file browser
435 float available_height = ImGui::GetContentRegionAvail().y;
436 bool has_file_browser = panel_manager_.HasFileBrowser(category);
437 float cards_height =
438 has_file_browser ? available_height * 0.4f : available_height;
439 float file_browser_height = available_height - cards_height - 30.0f;
440
441 // Panels section
442 ImGui::BeginChild("##PanelContent", ImVec2(0, cards_height), false,
443 ImGuiWindowFlags_None);
444 for (const auto& card : cards) {
445 // Apply search filter
446 if (sidebar_search[0] != '\0') {
447 std::string search_str = sidebar_search;
448 std::string card_name = card.display_name;
449 std::transform(search_str.begin(), search_str.end(), search_str.begin(),
450 ::tolower);
451 std::transform(card_name.begin(), card_name.end(), card_name.begin(),
452 ::tolower);
453 if (card_name.find(search_str) == std::string::npos) {
454 continue;
455 }
456 }
457
458 bool visible = card.visibility_flag ? *card.visibility_flag : false;
459
460 // Pin Toggle Button (replaces favorites - more useful for panel management)
461 // Use active session to avoid potential session ID issues
462 bool is_pinned = panel_manager_.IsPanelPinned(card.card_id);
463 ImGui::PushID(card.card_id.c_str());
464 if (is_pinned) {
465 ImGui::PushStyleColor(ImGuiCol_Text,
466 gui::ConvertColorToImVec4(theme.primary));
467 if (ImGui::SmallButton(ICON_MD_PUSH_PIN)) {
468 panel_manager_.SetPanelPinned(card.card_id, false);
469 }
470 ImGui::PopStyleColor();
471 if (ImGui::IsItemHovered()) {
472 ImGui::SetTooltip("Unpin - panel will hide when switching editors");
473 }
474 } else {
475 ImGui::PushStyleColor(ImGuiCol_Text,
476 gui::ConvertColorToImVec4(theme.text_disabled));
477 if (ImGui::SmallButton(ICON_MD_PUSH_PIN)) {
478 panel_manager_.SetPanelPinned(card.card_id, true);
479 }
480 ImGui::PopStyleColor();
481 if (ImGui::IsItemHovered()) {
482 ImGui::SetTooltip("Pin - keep visible across all editors");
483 }
484 }
485 ImGui::PopID();
486 ImGui::SameLine();
487
488 // Panel Item with Icon
489 std::string label = absl::StrFormat("%s %s", card.icon.c_str(),
490 card.display_name.c_str());
491 if (ImGui::Selectable(label.c_str(), visible)) {
492 // Toggle visibility
493 panel_manager_.TogglePanel(session_id, card.card_id);
494
495 // Get the new visibility state after toggle
496 bool new_visible = card.visibility_flag ? *card.visibility_flag : false;
497
498 if (new_visible) {
499 panel_manager_.AddToRecent(card.card_id); // Track recent
500
501 // Panel was just shown - activate the associated editor
502 panel_manager_.TriggerPanelClicked(card.category);
503
504 // Focus the card window so it comes to front
505 std::string window_title = card.GetWindowTitle();
506 ImGui::SetWindowFocus(window_title.c_str());
507 }
508 }
509
510 // Shortcut hint on hover
511 if (ImGui::IsItemHovered() && !card.shortcut_hint.empty()) {
512 ImGui::SetTooltip("%s", card.shortcut_hint.c_str());
513 }
514 }
515 ImGui::EndChild();
516
517 // File browser section (if enabled for this category)
518 if (has_file_browser) {
519 ImGui::Spacing();
520 ImGui::Separator();
521
522 // Collapsible header for file browser
523 ImGui::PushStyleColor(ImGuiCol_Header,
525 ImGui::PushStyleColor(ImGuiCol_HeaderHovered,
527 bool files_expanded = ImGui::CollapsingHeader(
528 ICON_MD_FOLDER " Files", ImGuiTreeNodeFlags_DefaultOpen);
529 ImGui::PopStyleColor(2);
530
531 if (files_expanded) {
532 ImGui::BeginChild("##FileBrowser", ImVec2(0, file_browser_height),
533 false, ImGuiWindowFlags_None);
534 auto* browser = panel_manager_.GetFileBrowser(category);
535 if (browser) {
536 browser->DrawCompact();
537 }
538 ImGui::EndChild();
539 }
540 }
541
542 if (disable_cards) {
543 ImGui::EndDisabled();
544 }
545 }
546 ImGui::End();
547
548 ImGui::PopStyleVar(3);
549 ImGui::PopStyleColor(1);
550}
551
552void ActivityBar::DrawPanelBrowser(size_t session_id, bool* p_open) {
553 ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
554
555 if (ImGui::Begin(
556 absl::StrFormat("%s Panel Browser", ICON_MD_DASHBOARD).c_str(),
557 p_open)) {
558 static char search_filter[256] = "";
559 static std::string category_filter = "All";
560
561 // Search bar
562 ImGui::SetNextItemWidth(300);
563 ImGui::InputTextWithHint(
564 "##Search",
565 absl::StrFormat("%s Search panels...", ICON_MD_SEARCH).c_str(),
566 search_filter, sizeof(search_filter));
567
568 ImGui::SameLine();
569
570 // Category filter
571 if (ImGui::BeginCombo("##CategoryFilter", category_filter.c_str())) {
572 if (ImGui::Selectable("All", category_filter == "All")) {
573 category_filter = "All";
574 }
575
576 auto categories = panel_manager_.GetAllCategories(session_id);
577 for (const auto& cat : categories) {
578 if (ImGui::Selectable(cat.c_str(), category_filter == cat)) {
579 category_filter = cat;
580 }
581 }
582 ImGui::EndCombo();
583 }
584
585 ImGui::Separator();
586
587 // Panel table
588 if (ImGui::BeginTable("##PanelTable", 4,
589 ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg |
590 ImGuiTableFlags_Borders)) {
591 ImGui::TableSetupColumn("Visible", ImGuiTableColumnFlags_WidthFixed, 60);
592 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
593 ImGui::TableSetupColumn("Category", ImGuiTableColumnFlags_WidthFixed,
594 120);
595 ImGui::TableSetupColumn("Shortcut", ImGuiTableColumnFlags_WidthFixed,
596 100);
597 ImGui::TableHeadersRow();
598
599 auto cards = (category_filter == "All")
601 : std::vector<std::string>{};
602
603 if (category_filter != "All") {
604 auto cat_cards =
605 panel_manager_.GetPanelsInCategory(session_id, category_filter);
606 for (const auto& card : cat_cards) {
607 cards.push_back(card.card_id);
608 }
609 }
610
611 for (const auto& card_id : cards) {
612 const auto* card =
613 panel_manager_.GetPanelDescriptor(session_id, card_id);
614 if (!card)
615 continue;
616
617 // Apply search filter
618 std::string search_str = search_filter;
619 if (!search_str.empty()) {
620 std::string card_lower = card->display_name;
621 std::transform(card_lower.begin(), card_lower.end(),
622 card_lower.begin(), ::tolower);
623 std::transform(search_str.begin(), search_str.end(),
624 search_str.begin(), ::tolower);
625 if (card_lower.find(search_str) == std::string::npos) {
626 continue;
627 }
628 }
629
630 ImGui::TableNextRow();
631
632 // Visibility toggle
633 ImGui::TableNextColumn();
634 if (card->visibility_flag) {
635 bool visible = *card->visibility_flag;
636 if (ImGui::Checkbox(
637 absl::StrFormat("##vis_%s", card->card_id.c_str()).c_str(),
638 &visible)) {
639 panel_manager_.TogglePanel(session_id, card->card_id);
640 // Note: TogglePanel handles callbacks
641 }
642 }
643
644 // Name with icon
645 ImGui::TableNextColumn();
646 ImGui::Text("%s %s", card->icon.c_str(), card->display_name.c_str());
647
648 // Category
649 ImGui::TableNextColumn();
650 ImGui::Text("%s", card->category.c_str());
651
652 // Shortcut
653 ImGui::TableNextColumn();
654 ImGui::TextDisabled("%s", card->shortcut_hint.c_str());
655 }
656
657 ImGui::EndTable();
658 }
659 }
660 ImGui::End();
661}
662
663} // namespace editor
664} // namespace yaze
void DrawPanelBrowser(size_t session_id, bool *p_open)
void DrawSidePanel(size_t session_id, const std::string &category, std::function< bool()> has_rom)
void Render(size_t session_id, const std::string &active_category, const std::vector< std::string > &all_categories, const std::unordered_set< std::string > &active_editor_categories, std::function< bool()> has_rom)
void DrawActivityBarStrip(size_t session_id, const std::string &active_category, const std::vector< std::string > &all_categories, const std::unordered_set< std::string > &active_editor_categories, std::function< bool()> has_rom)
PanelManager & panel_manager_
ActivityBar(PanelManager &panel_manager)
void DrawCompact()
Draw a compact version for narrow sidebars.
Central registry for all editor cards with session awareness and dependency injection.
std::vector< std::string > GetAllCategories(size_t session_id) const
void AddToRecent(const std::string &card_id)
void TriggerCategorySelected(const std::string &category)
std::vector< std::string > GetPinnedPanels(size_t session_id) const
bool TogglePanel(size_t session_id, const std::string &base_card_id)
const PanelDescriptor * GetPanelDescriptor(size_t session_id, const std::string &base_card_id) const
void TriggerPanelClicked(const std::string &category)
std::vector< std::string > GetPanelsInSession(size_t session_id) const
bool HasFileBrowser(const std::string &category) const
std::vector< PanelDescriptor > GetPanelsInCategory(size_t session_id, const std::string &category) const
static CategoryTheme GetCategoryTheme(const std::string &category)
void SetPanelExpanded(bool expanded)
static constexpr float GetSidebarWidth()
const std::vector< std::string > & GetRecentPanels() const
void ShowAllPanelsInCategory(size_t session_id, const std::string &category)
static std::string GetCategoryIcon(const std::string &category)
static constexpr float GetSidePanelWidth()
bool IsPanelPinned(size_t session_id, const std::string &base_card_id) const
FileBrowser * GetFileBrowser(const std::string &category)
void SetActiveCategory(const std::string &category)
void SetPanelPinned(size_t session_id, const std::string &base_card_id, bool pinned)
void HideAllPanelsInCategory(size_t session_id, const std::string &category)
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_FOLDER_OPEN
Definition icons.h:813
#define ICON_MD_SETTINGS
Definition icons.h:1699
#define ICON_MD_SEARCH
Definition icons.h:1673
#define ICON_MD_OPEN_IN_FULL
Definition icons.h:1353
#define ICON_MD_MORE_HORIZ
Definition icons.h:1241
#define ICON_MD_KEYBOARD_DOUBLE_ARROW_LEFT
Definition icons.h:1041
#define ICON_MD_CLOSE_FULLSCREEN
Definition icons.h:419
#define ICON_MD_KEYBOARD
Definition icons.h:1028
#define ICON_MD_TERMINAL
Definition icons.h:1951
#define ICON_MD_DASHBOARD
Definition icons.h:517
#define ICON_MD_FOLDER
Definition icons.h:809
#define ICON_MD_PUSH_PIN
Definition icons.h:1529
#define ICON_MD_HISTORY
Definition icons.h:946
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:23
bool TransparentIconButton(const char *icon, const ImVec2 &size, const char *tooltip, bool is_active, const ImVec4 &active_color)
Draw a transparent icon button (hover effect only).
ImVec4 GetSurfaceContainerHighestVec4()
ImVec4 GetTextSecondaryVec4()
ImVec4 GetSurfaceContainerHighVec4()