yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
right_panel_manager.cc
Go to the documentation of this file.
2
3#include <chrono>
4
5#include "absl/strings/str_format.h"
12#include "app/gui/core/icons.h"
14#include "app/gui/core/style.h"
16#include "imgui/imgui.h"
17
18namespace yaze {
19namespace editor {
20
22 switch (type) {
24 return "None";
26 return "AI Agent";
28 return "Proposals";
30 return "Settings";
32 return "Help";
34 return "Notifications";
36 return "Properties";
38 return "Project";
39 default:
40 return "Unknown";
41 }
42}
43
66
68 if (active_panel_ == type) {
69 ClosePanel();
70 } else {
71 OpenPanel(type);
72 }
73}
74
76 active_panel_ = type;
77 animating_ = true;
78 panel_animation_ = 0.0f;
79}
80
86
89 return 0.0f;
90 }
91
92 switch (active_panel_) {
94 return agent_chat_width_;
96 return proposals_width_;
98 return settings_width_;
100 return help_width_;
104 return properties_width_;
106 return project_width_;
107 default:
108 return 0.0f;
109 }
110}
111
113 switch (type) {
115 agent_chat_width_ = width;
116 break;
118 proposals_width_ = width;
119 break;
121 settings_width_ = width;
122 break;
123 case PanelType::kHelp:
124 help_width_ = width;
125 break;
127 notifications_width_ = width;
128 break;
130 properties_width_ = width;
131 break;
133 project_width_ = width;
134 break;
135 default:
136 break;
137 }
138}
139
142 return;
143 }
144
145 // Handle Escape key to close panel
146 if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
147 ClosePanel();
148 return;
149 }
150
151 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
152 const ImGuiViewport* viewport = ImGui::GetMainViewport();
153 const float viewport_height = viewport->WorkSize.y;
154 const float viewport_width = viewport->WorkSize.x;
155 const float panel_width = GetPanelWidth();
156
157 // Use SurfaceContainer for slightly elevated panel background
158 ImVec4 panel_bg = gui::GetSurfaceContainerVec4();
159 ImVec4 panel_border = gui::GetOutlineVec4();
160
161 ImGuiWindowFlags panel_flags =
162 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove |
163 ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking |
164 ImGuiWindowFlags_NoNavFocus;
165
166 // Position panel on right edge, full height
167 ImGui::SetNextWindowPos(
168 ImVec2(viewport->WorkPos.x + viewport_width - panel_width,
169 viewport->WorkPos.y));
170 ImGui::SetNextWindowSize(ImVec2(panel_width, viewport_height));
171
172 ImGui::PushStyleColor(ImGuiCol_WindowBg, panel_bg);
173 ImGui::PushStyleColor(ImGuiCol_Border, panel_border);
174 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
175 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
176
177 if (ImGui::Begin("##RightPanel", nullptr, panel_flags)) {
178 // Draw enhanced panel header
181
182 // Content area with padding
183 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12.0f, 8.0f));
184 ImGui::BeginChild("##PanelContent", ImVec2(0, 0), false,
185 ImGuiWindowFlags_AlwaysUseWindowPadding);
186
187 // Draw panel content based on type
188 switch (active_panel_) {
191 break;
194 break;
197 break;
198 case PanelType::kHelp:
200 break;
203 break;
206 break;
209 break;
210 default:
211 break;
212 }
213
214 ImGui::EndChild();
215 ImGui::PopStyleVar(); // WindowPadding for content
216 }
217 ImGui::End();
218
219 ImGui::PopStyleVar(2);
220 ImGui::PopStyleColor(2);
221}
222
223
224
225void RightPanelManager::DrawPanelHeader(const char* title, const char* icon) {
226 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
227 const float header_height = 44.0f;
228 const float padding = 12.0f;
229
230 // Header background - slightly elevated surface
231 ImVec2 header_min = ImGui::GetCursorScreenPos();
232 ImVec2 header_max = ImVec2(header_min.x + ImGui::GetWindowWidth(),
233 header_min.y + header_height);
234
235 ImDrawList* draw_list = ImGui::GetWindowDrawList();
236 draw_list->AddRectFilled(header_min, header_max,
237 ImGui::GetColorU32(gui::GetSurfaceContainerHighVec4()));
238
239 // Draw subtle bottom border
240 draw_list->AddLine(ImVec2(header_min.x, header_max.y),
241 ImVec2(header_max.x, header_max.y),
242 ImGui::GetColorU32(gui::GetOutlineVec4()), 1.0f);
243
244 // Position content within header
245 ImGui::SetCursorPosX(padding);
246 ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (header_height - ImGui::GetTextLineHeight()) * 0.5f);
247
248 // Panel icon with primary color
249 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
250 ImGui::Text("%s", icon);
251 ImGui::PopStyleColor();
252
253 ImGui::SameLine();
254
255 // Panel title (use current style text color)
256 ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
257 ImGui::Text("%s", title);
258 ImGui::PopStyleColor();
259
260 // Right-aligned buttons
261 const float button_size = 28.0f;
262 float current_x = ImGui::GetWindowWidth() - button_size - padding;
263
264 // Close button
265 ImGui::SameLine(current_x);
266 ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 4.0f); // Center vertically
267
268 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
269 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
271 ImGui::PushStyleColor(ImGuiCol_ButtonActive,
272 ImVec4(gui::GetPrimaryVec4().x * 0.3f,
273 gui::GetPrimaryVec4().y * 0.3f,
274 gui::GetPrimaryVec4().z * 0.3f, 0.4f));
275 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
276 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
277
278 if (ImGui::Button(ICON_MD_CLOSE, ImVec2(button_size, button_size))) {
279 ClosePanel();
280 }
281 if (ImGui::IsItemHovered()) {
282 ImGui::SetTooltip("Close Panel (Esc)");
283 }
284
285 // Lock Toggle (Only for Properties Panel)
287 current_x -= (button_size + 4.0f);
288 ImGui::SameLine(current_x);
289
290 // TODO: Hook up to actual lock state in SelectionPropertiesPanel
291 static bool is_locked = false;
292 ImVec4 lock_color = is_locked ? gui::GetPrimaryVec4() : gui::GetTextSecondaryVec4();
293 ImGui::PushStyleColor(ImGuiCol_Text, lock_color);
294
295 if (ImGui::Button(is_locked ? ICON_MD_LOCK : ICON_MD_LOCK_OPEN, ImVec2(button_size, button_size))) {
296 is_locked = !is_locked;
297 }
298 ImGui::PopStyleColor();
299
300 if (ImGui::IsItemHovered()) {
301 ImGui::SetTooltip(is_locked ? "Unlock Selection" : "Lock Selection");
302 }
303 }
304
305 ImGui::PopStyleVar();
306 ImGui::PopStyleColor(4);
307
308 // Move cursor past the header
309 ImGui::SetCursorPosY(header_height + 8.0f);
310}
311
312// =============================================================================
313// Panel Styling Helpers
314// =============================================================================
315
316bool RightPanelManager::BeginPanelSection(const char* label, const char* icon,
317 bool default_open) {
318 ImGui::PushStyleColor(ImGuiCol_Header, gui::GetSurfaceContainerHighVec4());
319 ImGui::PushStyleColor(ImGuiCol_HeaderHovered,
321 ImGui::PushStyleColor(ImGuiCol_HeaderActive,
323 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8.0f, 6.0f));
324 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
325
326 // Build header text with icon if provided
327 std::string header_text;
328 if (icon) {
329 header_text = std::string(icon) + " " + label;
330 } else {
331 header_text = label;
332 }
333
334 ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Framed |
335 ImGuiTreeNodeFlags_SpanAvailWidth |
336 ImGuiTreeNodeFlags_AllowOverlap |
337 ImGuiTreeNodeFlags_FramePadding;
338 if (default_open) {
339 flags |= ImGuiTreeNodeFlags_DefaultOpen;
340 }
341
342 bool is_open = ImGui::TreeNodeEx(header_text.c_str(), flags);
343
344 ImGui::PopStyleVar(2);
345 ImGui::PopStyleColor(3);
346
347 if (is_open) {
348 ImGui::Spacing();
349 ImGui::Indent(4.0f);
350 }
351
352 return is_open;
353}
354
356 ImGui::Unindent(4.0f);
357 ImGui::TreePop();
358 ImGui::Spacing();
359}
360
362 ImGui::Spacing();
363 ImGui::PushStyleColor(ImGuiCol_Separator, gui::GetOutlineVec4());
364 ImGui::Separator();
365 ImGui::PopStyleColor();
366 ImGui::Spacing();
367}
368
369void RightPanelManager::DrawPanelLabel(const char* label) {
370 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
371 ImGui::TextUnformatted(label);
372 ImGui::PopStyleColor();
373}
374
375void RightPanelManager::DrawPanelValue(const char* label, const char* value) {
376 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
377 ImGui::Text("%s:", label);
378 ImGui::PopStyleColor();
379 ImGui::SameLine();
380 ImGui::TextUnformatted(value);
381}
382
384 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextDisabledVec4());
385 ImGui::PushTextWrapPos(ImGui::GetContentRegionAvail().x);
386 ImGui::TextWrapped("%s", text);
387 ImGui::PopTextWrapPos();
388 ImGui::PopStyleColor();
389}
390
391// =============================================================================
392// Panel Content Drawing
393// =============================================================================
394
396#ifdef YAZE_BUILD_AGENT_UI
397 const ImVec4 header_bg = gui::GetSurfaceContainerHighVec4();
398 const ImVec4 hero_text = gui::GetOnSurfaceVec4();
399 const ImVec4 accent = gui::GetPrimaryVec4();
400
401 if (!agent_chat_) {
402 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
403 ImGui::Text(ICON_MD_SMART_TOY " AI Agent Not Available");
404 ImGui::PopStyleColor();
405 ImGui::Spacing();
407 "The AI Agent is not initialized. "
408 "Open the AI Agent from View menu or use Ctrl+Shift+A.");
409 return;
410 }
411
412 bool chat_active = *agent_chat_->active();
413
414 ImGui::PushStyleColor(ImGuiCol_ChildBg, header_bg);
415 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 8.0f);
416 if (ImGui::BeginChild("AgentHero", ImVec2(0, 110), true)) {
417 ImGui::PushStyleColor(ImGuiCol_Text, hero_text);
418 ImGui::TextColored(accent, "%s AI Agent", ICON_MD_SMART_TOY);
419 ImGui::PopStyleColor();
420 ImGui::SameLine();
421 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
422 ImGui::Text("Right Sidebar");
423 ImGui::PopStyleColor();
424
425 ImGui::Spacing();
426 DrawPanelValue("Status", chat_active ? "Active" : "Inactive");
427 DrawPanelValue("Provider", "Configured via Agent Editor");
428 }
429 ImGui::EndChild();
430 ImGui::PopStyleVar();
431 ImGui::PopStyleColor();
432
433 ImGui::Spacing();
434 agent_chat_->set_active(true);
435
436 const float footer_height = ImGui::GetFrameHeightWithSpacing() * 3.5f;
437 float content_height =
438 std::max(120.0f, ImGui::GetContentRegionAvail().y - footer_height);
439
440 static int active_tab = 0; // 0 = Chat, 1 = Quick Config
441 if (ImGui::BeginTabBar("AgentSidebarTabs")) {
442 if (ImGui::BeginTabItem(ICON_MD_CHAT " Chat")) {
443 active_tab = 0;
444 ImGui::EndTabItem();
445 }
446 if (ImGui::BeginTabItem(ICON_MD_SETTINGS " Quick Config")) {
447 active_tab = 1;
448 ImGui::EndTabItem();
449 }
450 ImGui::EndTabBar();
451 }
452
453 if (active_tab == 0) {
454 if (ImGui::BeginChild("AgentChatBody", ImVec2(0, content_height), true)) {
455 agent_chat_->Draw(content_height);
456 }
457 ImGui::EndChild();
458 } else {
459 if (ImGui::BeginChild("AgentQuickConfig", ImVec2(0, content_height), true)) {
460 bool auto_scroll = agent_chat_->auto_scroll();
461 bool show_ts = agent_chat_->show_timestamps();
462 bool show_reasoning = agent_chat_->show_reasoning();
463
464 ImGui::TextColored(accent, "%s Display", ICON_MD_TUNE);
465 if (ImGui::Checkbox("Auto-scroll", &auto_scroll)) {
466 agent_chat_->set_auto_scroll(auto_scroll);
467 }
468 if (ImGui::Checkbox("Show timestamps", &show_ts)) {
470 }
471 if (ImGui::Checkbox("Show reasoning traces", &show_reasoning)) {
472 agent_chat_->set_show_reasoning(show_reasoning);
473 }
474
475 ImGui::Separator();
476 ImGui::TextColored(accent, "%s Provider", ICON_MD_SMART_TOY);
478 "Change provider/model in the main Agent Editor. This sidebar shows "
479 "active chat controls.");
480 }
481 ImGui::EndChild();
482 }
483
484 // Footer actions (always visible, not clipped)
485 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6, 6));
486 ImGui::PushStyleColor(ImGuiCol_Button, gui::GetPrimaryVec4());
487 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, gui::GetPrimaryHoverVec4());
488 ImGui::PushStyleColor(ImGuiCol_ButtonActive, gui::GetPrimaryActiveVec4());
489 if (ImGui::Button(ICON_MD_OPEN_IN_NEW " Focus Agent Chat", ImVec2(-1, 0))) {
490 agent_chat_->set_active(true);
492 }
493 ImGui::PopStyleColor(3);
494
495 ImVec2 half_width(ImGui::GetContentRegionAvail().x / 2 - 4, 0);
496 ImGui::PushStyleColor(ImGuiCol_Button, gui::GetSurfaceContainerVec4());
497 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
499 ImGui::PushStyleColor(ImGuiCol_ButtonActive,
501 if (ImGui::Button(ICON_MD_DELETE_FOREVER " Clear", half_width)) {
503 }
504 ImGui::SameLine();
505 if (ImGui::Button(ICON_MD_FILE_DOWNLOAD " Save", half_width)) {
506 agent_chat_->SaveHistory(".yaze/agent_chat_history.json");
507 }
508 ImGui::PopStyleColor(3);
509 ImGui::PopStyleVar();
510#else
511 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
512 ImGui::Text(ICON_MD_SMART_TOY " AI Agent Not Available");
513 ImGui::PopStyleColor();
514
515 ImGui::Spacing();
517 "The AI Agent requires agent UI support. "
518 "Build with YAZE_BUILD_AGENT_UI=ON to enable.");
519#endif
520}
521
523 if (proposal_drawer_) {
524 // Set ROM and draw content inside the panel (not a separate window)
525 if (rom_) {
527 }
529 } else {
530 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
531 ImGui::Text(ICON_MD_DESCRIPTION " Proposals Not Available");
532 ImGui::PopStyleColor();
533
534 ImGui::Spacing();
536 "The proposal system is not initialized. "
537 "Proposals will appear here when the AI Agent creates them.");
538 }
539}
540
542 if (settings_panel_) {
543 // Draw settings inline (no card windows)
545 } else {
546 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
547 ImGui::Text(ICON_MD_SETTINGS " Settings Not Available");
548 ImGui::PopStyleColor();
549
550 ImGui::Spacing();
552 "Settings will be available once initialized. "
553 "This panel provides quick access to application settings.");
554 }
555}
556
558 // Context-aware editor header
560
561 // Keyboard Shortcuts section (default open)
562 if (BeginPanelSection("Keyboard Shortcuts", ICON_MD_KEYBOARD, true)) {
566 }
567
568 // Editor-specific help (default open)
569 if (BeginPanelSection("Editor Guide", ICON_MD_HELP, true)) {
572 }
573
574 // Quick Actions (collapsed by default)
575 if (BeginPanelSection("Quick Actions", ICON_MD_BOLT, false)) {
578 }
579
580 // About section (collapsed by default)
581 if (BeginPanelSection("About", ICON_MD_INFO, false)) {
584 }
585}
586
588 const char* editor_name = "No Editor Selected";
589 const char* editor_icon = ICON_MD_HELP;
590
591 switch (active_editor_type_) {
593 editor_name = "Overworld Editor";
594 editor_icon = ICON_MD_LANDSCAPE;
595 break;
597 editor_name = "Dungeon Editor";
598 editor_icon = ICON_MD_CASTLE;
599 break;
601 editor_name = "Graphics Editor";
602 editor_icon = ICON_MD_IMAGE;
603 break;
605 editor_name = "Palette Editor";
606 editor_icon = ICON_MD_PALETTE;
607 break;
609 editor_name = "Music Editor";
610 editor_icon = ICON_MD_MUSIC_NOTE;
611 break;
613 editor_name = "Screen Editor";
614 editor_icon = ICON_MD_TV;
615 break;
617 editor_name = "Sprite Editor";
618 editor_icon = ICON_MD_SMART_TOY;
619 break;
621 editor_name = "Message Editor";
622 editor_icon = ICON_MD_CHAT;
623 break;
625 editor_name = "Emulator";
626 editor_icon = ICON_MD_VIDEOGAME_ASSET;
627 break;
628 default:
629 break;
630 }
631
632 // Draw context header with editor info
633 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
634 ImGui::Text("%s %s Help", editor_icon, editor_name);
635 ImGui::PopStyleColor();
636
638}
639
641 const char* ctrl = gui::GetCtrlDisplayName();
642 DrawPanelLabel("Global");
643 ImGui::Indent(8.0f);
644 DrawPanelValue(absl::StrFormat("%s+O", ctrl).c_str(), "Open ROM");
645 DrawPanelValue(absl::StrFormat("%s+S", ctrl).c_str(), "Save ROM");
646 DrawPanelValue(absl::StrFormat("%s+Z", ctrl).c_str(), "Undo");
647 DrawPanelValue(absl::StrFormat("%s+Y", ctrl).c_str(), "Redo");
648 DrawPanelValue(absl::StrFormat("%s+B", ctrl).c_str(), "Toggle Sidebar");
649 DrawPanelValue("F1", "Help Panel");
650 DrawPanelValue("Esc", "Close Panel");
651 ImGui::Unindent(8.0f);
652 ImGui::Spacing();
653}
654
656 const char* ctrl = gui::GetCtrlDisplayName();
657 switch (active_editor_type_) {
659 DrawPanelLabel("Overworld");
660 ImGui::Indent(8.0f);
661 DrawPanelValue("1-3", "Switch World (LW/DW/SP)");
662 DrawPanelValue("Arrow Keys", "Navigate Maps");
663 DrawPanelValue("E", "Entity Mode");
664 DrawPanelValue("T", "Tile Mode");
665 DrawPanelValue("Right Click", "Pick Tile");
666 ImGui::Unindent(8.0f);
667 break;
668
670 DrawPanelLabel("Dungeon");
671 ImGui::Indent(8.0f);
672 DrawPanelValue("Delete", "Remove Object");
673 DrawPanelValue(absl::StrFormat("%s+D", ctrl).c_str(), "Duplicate");
674 DrawPanelValue("Arrow Keys", "Move Object");
675 DrawPanelValue("G", "Toggle Grid");
676 DrawPanelValue("L", "Cycle Layers");
677 ImGui::Unindent(8.0f);
678 break;
679
681 DrawPanelLabel("Graphics");
682 ImGui::Indent(8.0f);
683 DrawPanelValue("[ ]", "Previous/Next Sheet");
684 DrawPanelValue("P", "Pencil Tool");
685 DrawPanelValue("F", "Fill Tool");
686 DrawPanelValue("+ -", "Zoom In/Out");
687 ImGui::Unindent(8.0f);
688 break;
689
691 DrawPanelLabel("Palette");
692 ImGui::Indent(8.0f);
693 DrawPanelValue("Click", "Select Color");
694 DrawPanelValue("Double Click", "Edit Color");
695 DrawPanelValue("Drag", "Copy Color");
696 ImGui::Unindent(8.0f);
697 break;
698
700 DrawPanelLabel("Music");
701 ImGui::Indent(8.0f);
702 DrawPanelValue("Space", "Play/Pause");
703 DrawPanelValue("Enter", "Stop");
704 DrawPanelValue("Left/Right", "Seek");
705 ImGui::Unindent(8.0f);
706 break;
707
709 DrawPanelLabel("Message");
710 ImGui::Indent(8.0f);
711 DrawPanelValue(absl::StrFormat("%s+Enter", ctrl).c_str(), "Insert Line Break");
712 DrawPanelValue("Up/Down", "Navigate Messages");
713 ImGui::Unindent(8.0f);
714 break;
715
716 default:
717 DrawPanelLabel("Editor Shortcuts");
718 ImGui::Indent(8.0f);
719 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
720 ImGui::TextWrapped("Select an editor to see specific shortcuts.");
721 ImGui::PopStyleColor();
722 ImGui::Unindent(8.0f);
723 break;
724 }
725}
726
728 switch (active_editor_type_) {
730 ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
731 ImGui::Bullet(); ImGui::TextWrapped("Paint tiles by selecting from Tile16 Selector");
732 ImGui::Bullet(); ImGui::TextWrapped("Switch between Light World, Dark World, and Special Areas");
733 ImGui::Bullet(); ImGui::TextWrapped("Use Entity Mode to place entrances, exits, items, and sprites");
734 ImGui::Bullet(); ImGui::TextWrapped("Right-click on the map to pick a tile for painting");
735 ImGui::PopStyleColor();
736 break;
737
739 ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
740 ImGui::Bullet(); ImGui::TextWrapped("Select rooms from the Room Selector or Room Matrix");
741 ImGui::Bullet(); ImGui::TextWrapped("Place objects using the Object Editor panel");
742 ImGui::Bullet(); ImGui::TextWrapped("Edit room headers for palette, GFX, and floor settings");
743 ImGui::Bullet(); ImGui::TextWrapped("Multiple rooms can be opened in separate tabs");
744 ImGui::PopStyleColor();
745 break;
746
748 ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
749 ImGui::Bullet(); ImGui::TextWrapped("Browse graphics sheets using the Sheet Browser");
750 ImGui::Bullet(); ImGui::TextWrapped("Edit pixels directly with the Pixel Editor");
751 ImGui::Bullet(); ImGui::TextWrapped("Choose palettes from Palette Controls");
752 ImGui::Bullet(); ImGui::TextWrapped("View 3D objects like rupees and crystals");
753 ImGui::PopStyleColor();
754 break;
755
757 ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
758 ImGui::Bullet(); ImGui::TextWrapped("Edit overworld, dungeon, and sprite palettes");
759 ImGui::Bullet(); ImGui::TextWrapped("Use Quick Access for color harmony tools");
760 ImGui::Bullet(); ImGui::TextWrapped("Changes update in real-time across all editors");
761 ImGui::PopStyleColor();
762 break;
763
765 ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
766 ImGui::Bullet(); ImGui::TextWrapped("Browse songs in the Song Browser");
767 ImGui::Bullet(); ImGui::TextWrapped("Use the tracker for playback control");
768 ImGui::Bullet(); ImGui::TextWrapped("Edit instruments and BRR samples");
769 ImGui::PopStyleColor();
770 break;
771
773 ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
774 ImGui::Bullet(); ImGui::TextWrapped("Edit all in-game dialog messages");
775 ImGui::Bullet(); ImGui::TextWrapped("Preview text rendering with the font atlas");
776 ImGui::Bullet(); ImGui::TextWrapped("Manage the compression dictionary");
777 ImGui::PopStyleColor();
778 break;
779
780 default:
781 ImGui::Bullet(); ImGui::TextWrapped("Open a ROM file via File > Open ROM");
782 ImGui::Bullet(); ImGui::TextWrapped("Select an editor from the sidebar");
783 ImGui::Bullet(); ImGui::TextWrapped("Use panels to access tools and settings");
784 ImGui::Bullet(); ImGui::TextWrapped("Save your work via File > Save ROM");
785 break;
786 }
787}
788
790 const float button_width = ImGui::GetContentRegionAvail().x;
791
792 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8.0f, 6.0f));
793 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
794
795 // Documentation button
796 ImGui::PushStyleColor(ImGuiCol_Button, gui::GetSurfaceContainerHighVec4());
797 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, gui::GetSurfaceContainerHighestVec4());
798 if (ImGui::Button(ICON_MD_DESCRIPTION " Open Documentation", ImVec2(button_width, 0))) {
799 // TODO: Open documentation URL
800 }
801 ImGui::PopStyleColor(2);
802
803 ImGui::Spacing();
804
805 // GitHub Issues button
806 ImGui::PushStyleColor(ImGuiCol_Button, gui::GetSurfaceContainerHighVec4());
807 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, gui::GetSurfaceContainerHighestVec4());
808 if (ImGui::Button(ICON_MD_BUG_REPORT " Report Issue", ImVec2(button_width, 0))) {
809 // TODO: Open GitHub issues URL
810 }
811 ImGui::PopStyleColor(2);
812
813 ImGui::Spacing();
814
815 // Discord button
816 ImGui::PushStyleColor(ImGuiCol_Button, gui::GetSurfaceContainerHighVec4());
817 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, gui::GetSurfaceContainerHighestVec4());
818 if (ImGui::Button(ICON_MD_FORUM " Join Discord", ImVec2(button_width, 0))) {
819 // TODO: Open Discord invite URL
820 }
821 ImGui::PopStyleColor(2);
822
823 ImGui::PopStyleVar(2);
824}
825
827 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
828 ImGui::Text("YAZE - Yet Another Zelda3 Editor");
829 ImGui::PopStyleColor();
830
831 ImGui::Spacing();
833 "A comprehensive editor for The Legend of Zelda: "
834 "A Link to the Past ROM files.");
835
837
838 DrawPanelLabel("Credits");
839 ImGui::Spacing();
840 ImGui::Text("Written by: scawful");
841 ImGui::Text("Special Thanks: Zarby89, JaredBrian");
842
844
845 DrawPanelLabel("Links");
846 ImGui::Spacing();
847 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
848 ImGui::Text(ICON_MD_LINK " github.com/scawful/yaze");
849 ImGui::PopStyleColor();
850}
851
853 if (!toast_manager_) {
854 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
855 ImGui::Text(ICON_MD_NOTIFICATIONS_OFF " Notifications Unavailable");
856 ImGui::PopStyleColor();
857 return;
858 }
859
860 // Header actions
861 float button_width = 100.0f;
862 float avail = ImGui::GetContentRegionAvail().x;
863
864 // Mark all read button
865 ImGui::PushStyleColor(ImGuiCol_Button, gui::GetSurfaceContainerHighVec4());
866 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, gui::GetSurfaceContainerHighestVec4());
867
868 if (ImGui::Button(ICON_MD_DONE_ALL " Mark All Read", ImVec2(avail * 0.5f - 4.0f, 0))) {
870 }
871 ImGui::SameLine();
872 if (ImGui::Button(ICON_MD_DELETE_SWEEP " Clear All", ImVec2(avail * 0.5f - 4.0f, 0))) {
874 }
875
876 ImGui::PopStyleColor(2);
877
879
880 // Notification history
881 const auto& history = toast_manager_->GetHistory();
882
883 if (history.empty()) {
884 ImGui::Spacing();
885 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
886 ImGui::Text(ICON_MD_INBOX " No notifications");
887 ImGui::PopStyleColor();
888 ImGui::Spacing();
889 DrawPanelDescription("Notifications will appear here when actions complete.");
890 return;
891 }
892
893 // Stats
894 size_t unread_count = toast_manager_->GetUnreadCount();
895 if (unread_count > 0) {
896 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
897 ImGui::Text("%zu unread", unread_count);
898 ImGui::PopStyleColor();
899 } else {
900 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
901 ImGui::Text("All caught up");
902 ImGui::PopStyleColor();
903 }
904
905 ImGui::Spacing();
906
907 // Scrollable notification list
908 ImGui::BeginChild("##NotificationList", ImVec2(0, 0), false,
909 ImGuiWindowFlags_AlwaysVerticalScrollbar);
910
911 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
912 auto now = std::chrono::system_clock::now();
913
914 // Group by time (Today, Yesterday, Older)
915 bool shown_today = false;
916 bool shown_yesterday = false;
917 bool shown_older = false;
918
919 for (const auto& entry : history) {
920 auto diff = std::chrono::duration_cast<std::chrono::hours>(
921 now - entry.timestamp).count();
922
923 // Time grouping headers
924 if (diff < 24 && !shown_today) {
925 DrawPanelLabel("Today");
926 shown_today = true;
927 } else if (diff >= 24 && diff < 48 && !shown_yesterday) {
928 ImGui::Spacing();
929 DrawPanelLabel("Yesterday");
930 shown_yesterday = true;
931 } else if (diff >= 48 && !shown_older) {
932 ImGui::Spacing();
933 DrawPanelLabel("Older");
934 shown_older = true;
935 }
936
937 // Notification item
938 ImGui::PushID(&entry);
939
940 // Icon and color based on type
941 const char* icon;
942 ImVec4 color;
943 switch (entry.type) {
946 color = gui::ConvertColorToImVec4(theme.success);
947 break;
949 icon = ICON_MD_WARNING;
950 color = gui::ConvertColorToImVec4(theme.warning);
951 break;
953 icon = ICON_MD_ERROR;
954 color = gui::ConvertColorToImVec4(theme.error);
955 break;
956 default:
957 icon = ICON_MD_INFO;
958 color = gui::ConvertColorToImVec4(theme.info);
959 break;
960 }
961
962 // Unread indicator
963 if (!entry.read) {
964 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
965 ImGui::Text(ICON_MD_FIBER_MANUAL_RECORD);
966 ImGui::PopStyleColor();
967 ImGui::SameLine();
968 }
969
970 // Icon
971 ImGui::PushStyleColor(ImGuiCol_Text, color);
972 ImGui::Text("%s", icon);
973 ImGui::PopStyleColor();
974 ImGui::SameLine();
975
976 // Message
977 ImGui::TextWrapped("%s", entry.message.c_str());
978
979 // Timestamp
980 auto diff_sec = std::chrono::duration_cast<std::chrono::seconds>(
981 now - entry.timestamp).count();
982 std::string time_str;
983 if (diff_sec < 60) {
984 time_str = "just now";
985 } else if (diff_sec < 3600) {
986 time_str = absl::StrFormat("%dm ago", diff_sec / 60);
987 } else if (diff_sec < 86400) {
988 time_str = absl::StrFormat("%dh ago", diff_sec / 3600);
989 } else {
990 time_str = absl::StrFormat("%dd ago", diff_sec / 86400);
991 }
992
993 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextDisabledVec4());
994 ImGui::Text(" %s", time_str.c_str());
995 ImGui::PopStyleColor();
996
997 ImGui::PopID();
998 ImGui::Spacing();
999 }
1000
1001 ImGui::EndChild();
1002}
1003
1005 if (properties_panel_) {
1007 } else {
1008 // Placeholder when no properties panel is set
1009 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
1010 ImGui::Text(ICON_MD_SELECT_ALL " No Selection");
1011 ImGui::PopStyleColor();
1012
1013 ImGui::Spacing();
1015 "Select an item in the editor to view and edit its properties here.");
1016
1018
1019 // Show placeholder sections for what properties would look like
1020 if (BeginPanelSection("Position & Size", ICON_MD_STRAIGHTEN, true)) {
1021 DrawPanelValue("X", "--");
1022 DrawPanelValue("Y", "--");
1023 DrawPanelValue("Width", "--");
1024 DrawPanelValue("Height", "--");
1026 }
1027
1028 if (BeginPanelSection("Appearance", ICON_MD_PALETTE, false)) {
1029 DrawPanelValue("Tile ID", "--");
1030 DrawPanelValue("Palette", "--");
1031 DrawPanelValue("Layer", "--");
1033 }
1034
1035 if (BeginPanelSection("Behavior", ICON_MD_SETTINGS, false)) {
1036 DrawPanelValue("Type", "--");
1037 DrawPanelValue("Subtype", "--");
1038 DrawPanelValue("Properties", "--");
1040 }
1041 }
1042}
1043
1045 if (project_panel_) {
1047 } else {
1048 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
1049 ImGui::Text(ICON_MD_FOLDER_SPECIAL " No Project Loaded");
1050 ImGui::PopStyleColor();
1051
1052 ImGui::Spacing();
1054 "Open a .yaze project file to access project management features "
1055 "including ROM versioning, snapshots, and configuration.");
1056
1058
1059 // Placeholder for project features
1060 if (BeginPanelSection("Quick Start", ICON_MD_ROCKET_LAUNCH, true)) {
1061 ImGui::Bullet();
1062 ImGui::TextWrapped("Create a new project via File > New Project");
1063 ImGui::Bullet();
1064 ImGui::TextWrapped("Open existing .yaze project files");
1065 ImGui::Bullet();
1066 ImGui::TextWrapped("Projects track ROM versions and settings");
1068 }
1069
1070 if (BeginPanelSection("Features", ICON_MD_CHECKLIST, false)) {
1071 ImGui::Bullet();
1072 ImGui::TextWrapped("Version snapshots with Git integration");
1073 ImGui::Bullet();
1074 ImGui::TextWrapped("ROM backup and restore");
1075 ImGui::Bullet();
1076 ImGui::TextWrapped("Project-specific settings");
1077 ImGui::Bullet();
1078 ImGui::TextWrapped("Assembly code folder integration");
1080 }
1081 }
1082}
1083
1085 bool clicked = false;
1086
1087 // Helper lambda for drawing panel toggle buttons with consistent styling
1088 auto DrawPanelButton = [&](const char* icon, const char* tooltip,
1089 PanelType type) {
1090 bool is_active = IsPanelActive(type);
1091
1092 // Consistent button styling - transparent background with hover states
1093 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
1094 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
1096 ImGui::PushStyleColor(ImGuiCol_ButtonActive,
1098 // Active = primary color, inactive = secondary text color
1099 ImGui::PushStyleColor(
1100 ImGuiCol_Text,
1102
1103 if (ImGui::SmallButton(icon)) {
1104 TogglePanel(type);
1105 clicked = true;
1106 }
1107
1108 ImGui::PopStyleColor(4);
1109
1110 if (ImGui::IsItemHovered()) {
1111 ImGui::SetTooltip("%s", tooltip);
1112 }
1113 };
1114
1115 // Project button
1116 DrawPanelButton(ICON_MD_FOLDER_SPECIAL, "Project Panel", PanelType::kProject);
1117 ImGui::SameLine();
1118
1119 // Agent Chat button
1120 DrawPanelButton(ICON_MD_SMART_TOY, "AI Agent Panel", PanelType::kAgentChat);
1121 ImGui::SameLine();
1122
1123 // Help button
1124 DrawPanelButton(ICON_MD_HELP_OUTLINE, "Help Panel (F1)", PanelType::kHelp);
1125 ImGui::SameLine();
1126
1127 // Settings button
1128 DrawPanelButton(ICON_MD_SETTINGS, "Settings Panel", PanelType::kSettings);
1129 ImGui::SameLine();
1130
1131 // Properties button (last button - no SameLine after)
1132 DrawPanelButton(ICON_MD_LIST_ALT, "Properties Panel", PanelType::kProperties);
1133
1134 return clicked;
1135}
1136
1137} // namespace editor
1138} // namespace yaze
bool show_reasoning() const
Definition agent_chat.h:62
void set_auto_scroll(bool v)
Definition agent_chat.h:59
void set_show_timestamps(bool v)
Definition agent_chat.h:61
bool auto_scroll() const
Definition agent_chat.h:58
void set_show_reasoning(bool v)
Definition agent_chat.h:63
void Draw(float available_height=0.0f)
Definition agent_chat.cc:81
void set_active(bool active)
Definition agent_chat.h:67
bool show_timestamps() const
Definition agent_chat.h:60
absl::Status SaveHistory(const std::string &filepath)
void Draw()
Draw the panel and its contents.
float GetPanelWidth() const
Get the width of the panel when expanded.
void ClosePanel()
Close the currently active panel.
void DrawPanelValue(const char *label, const char *value)
void SetPanelWidth(PanelType type, float width)
Set panel width for a specific panel type.
void TogglePanel(PanelType type)
Toggle a specific panel on/off.
bool BeginPanelSection(const char *label, const char *icon=nullptr, bool default_open=true)
bool DrawPanelToggleButtons()
Draw toggle buttons for the status cluster.
bool IsPanelActive(PanelType type) const
Check if a specific panel is active.
void OpenPanel(PanelType type)
Open a specific panel.
void DrawPanelLabel(const char *label)
SelectionPropertiesPanel * properties_panel_
void DrawPanelDescription(const char *text)
void DrawPanelHeader(const char *title, const char *icon)
ProjectManagementPanel * project_panel_
void Draw()
Draw the properties panel content.
const std::deque< NotificationEntry > & GetHistory() const
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_ROCKET_LAUNCH
Definition icons.h:1612
#define ICON_MD_NOTIFICATIONS
Definition icons.h:1335
#define ICON_MD_SETTINGS
Definition icons.h:1699
#define ICON_MD_LINK
Definition icons.h:1090
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_CHAT
Definition icons.h:394
#define ICON_MD_LANDSCAPE
Definition icons.h:1059
#define ICON_MD_WARNING
Definition icons.h:2123
#define ICON_MD_LOCK_OPEN
Definition icons.h:1142
#define ICON_MD_DONE_ALL
Definition icons.h:608
#define ICON_MD_FOLDER_SPECIAL
Definition icons.h:815
#define ICON_MD_LOCK
Definition icons.h:1140
#define ICON_MD_CHECKLIST
Definition icons.h:402
#define ICON_MD_FORUM
Definition icons.h:851
#define ICON_MD_FILE_DOWNLOAD
Definition icons.h:744
#define ICON_MD_TUNE
Definition icons.h:2022
#define ICON_MD_LIST_ALT
Definition icons.h:1095
#define ICON_MD_VIDEOGAME_ASSET
Definition icons.h:2076
#define ICON_MD_BUG_REPORT
Definition icons.h:327
#define ICON_MD_CASTLE
Definition icons.h:380
#define ICON_MD_ERROR
Definition icons.h:686
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1264
#define ICON_MD_INBOX
Definition icons.h:990
#define ICON_MD_KEYBOARD
Definition icons.h:1028
#define ICON_MD_BOLT
Definition icons.h:282
#define ICON_MD_IMAGE
Definition icons.h:982
#define ICON_MD_CHECK_CIRCLE
Definition icons.h:400
#define ICON_MD_DESCRIPTION
Definition icons.h:539
#define ICON_MD_HELP_OUTLINE
Definition icons.h:935
#define ICON_MD_STRAIGHTEN
Definition icons.h:1871
#define ICON_MD_NOTIFICATIONS_OFF
Definition icons.h:1338
#define ICON_MD_SELECT_ALL
Definition icons.h:1680
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_OPEN_IN_NEW
Definition icons.h:1354
#define ICON_MD_TV
Definition icons.h:2032
#define ICON_MD_DELETE_FOREVER
Definition icons.h:531
#define ICON_MD_CLOSE
Definition icons.h:418
#define ICON_MD_HELP
Definition icons.h:933
#define ICON_MD_FIBER_MANUAL_RECORD
Definition icons.h:739
#define ICON_MD_SMART_TOY
Definition icons.h:1781
#define ICON_MD_DELETE_SWEEP
Definition icons.h:533
const char * GetPanelTypeName(RightPanelManager::PanelType type)
Get the name of a panel type.
const char * GetPanelTypeIcon(RightPanelManager::PanelType type)
Get the icon for a panel type.
const char * GetCtrlDisplayName()
Get the display name for the primary modifier key.
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:23
ImVec4 GetSurfaceContainerHighestVec4()
ImVec4 GetPrimaryActiveVec4()
ImVec4 GetPrimaryVec4()
ImVec4 GetTextDisabledVec4()
ImVec4 GetTextSecondaryVec4()
ImVec4 GetSurfaceContainerHighVec4()
ImVec4 GetPrimaryHoverVec4()
ImVec4 GetOutlineVec4()
ImVec4 GetOnSurfaceVec4()
ImVec4 GetSurfaceContainerVec4()