yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
workspace_window_manager.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_SYSTEM_WORKSPACE_WINDOW_MANAGER_H_
2#define YAZE_APP_EDITOR_SYSTEM_WORKSPACE_WINDOW_MANAGER_H_
3
4#include <algorithm>
5#include <cstdint>
6#include <functional>
7#include <list>
8#include <memory>
9#include <string>
10#include <unordered_map>
11#include <unordered_set>
12#include <vector>
13
18
19#ifndef YAZE_ENABLE_CARD_SHIM_DEPRECATION
20#define YAZE_ENABLE_CARD_SHIM_DEPRECATION 1
21#endif
22
23#if YAZE_ENABLE_CARD_SHIM_DEPRECATION && defined(__has_cpp_attribute)
24#if __has_cpp_attribute(deprecated)
25#define YAZE_CARD_SHIM_DEPRECATED(msg) [[deprecated(msg)]]
26#else
27#define YAZE_CARD_SHIM_DEPRECATED(msg)
28#endif
29#else
30#define YAZE_CARD_SHIM_DEPRECATED(msg)
31#endif
32
33namespace yaze {
34
35namespace gui {
36class PanelWindow;
37} // namespace gui
38
39namespace editor {
40
41// Forward declarations
42enum class EditorType;
43class Editor;
44class ResourceWindowContent;
45
51 std::string card_id; // Unique identifier (e.g., "dungeon.room_selector")
52 std::string display_name; // Human-readable name (e.g., "Room Selector")
53 std::string
54 window_title; // ImGui window title for DockBuilder (e.g., " Rooms List")
55 std::string icon; // Material icon
56 std::string category; // Category (e.g., "Dungeon", "Graphics", "Palette")
57 std::string workflow_group;
58 std::string workflow_label;
61
62 // Lifecycle behavior on editor switches (default: EditorBound).
64
65 // Optional context binding (default: none).
67
68 // Product admission/hosting policy. This does not affect registration or
69 // command-palette reachability. Undeclared (default) behaves as a listed
70 // optional pop-out and is reported by the admission audit.
72
74 enum class ShortcutScope {
75 kGlobal, // Available regardless of active editor
76 kEditor, // Only active within the owning editor
77 kPanel // Panel visibility/within-panel actions
78 };
79 std::string shortcut_hint; // Display hint (e.g., "Ctrl+Shift+R")
81 bool* visibility_flag; // Pointer to bool controlling visibility
82 std::function<void()> on_show; // Callback when card is shown
83 std::function<void()> on_hide; // Callback when card is hidden
84 int priority; // Display priority for menus (lower = higher)
85
86 // Disabled state support for IDE-like behavior
87 std::function<bool()>
88 enabled_condition; // Returns true if card is enabled (nullptr = always enabled)
89 std::string disabled_tooltip; // Tooltip shown when hovering disabled card
90
95 std::string GetWindowTitle() const {
96 if (!window_title.empty()) {
97 return window_title;
98 }
99 // Generate from icon + display_name if window_title not explicitly set
100 return icon + " " + display_name;
101 }
102
109 std::string GetImGuiWindowName() const {
110 const std::string label =
111 icon.empty() ? display_name : (icon + " " + display_name);
112 if (!card_id.empty()) {
113 return label + "##" + card_id;
114 }
115 return label;
116 }
117
118 bool IsAdmitted() const { return presentation.IsAdmitted(); }
122};
123
130 public:
133
134 // Non-copyable, non-movable
139
140 // Special category for dashboard/welcome screen - suppresses panel drawing
141 static constexpr const char* kDashboardCategory = "Dashboard";
142
143 // ============================================================================
144 // Session Lifecycle Management
145 // ============================================================================
146
147 void RegisterSession(size_t session_id);
148 void UnregisterSession(size_t session_id);
149 void SetActiveSession(size_t session_id);
150
151 // ============================================================================
152 // Context Keys (Optional Policy Engine)
153 // ============================================================================
154
162 void SetContextKey(size_t session_id, WindowContextScope scope,
163 std::string key);
164 std::string GetContextKey(size_t session_id, WindowContextScope scope) const;
165
166 // ============================================================================
167 // Panel Registration
168 // ============================================================================
169
170 void RegisterPanel(size_t session_id, const WindowDescriptor& base_info);
171 void RegisterWindow(size_t session_id, const WindowDescriptor& descriptor) {
172 RegisterPanel(session_id, descriptor);
173 }
174
181 void RegisterPanelAlias(const std::string& legacy_base_id,
182 const std::string& canonical_base_id);
183 void RegisterWindowAlias(const std::string& legacy_base_id,
184 const std::string& canonical_base_id) {
185 RegisterPanelAlias(legacy_base_id, canonical_base_id);
186 }
187
192 std::string ResolvePanelAlias(const std::string& panel_id) const;
193 std::string ResolveWindowAlias(const std::string& window_id) const {
194 return ResolvePanelAlias(window_id);
195 }
196
197 void RegisterPanel(size_t session_id, const std::string& card_id,
198 const std::string& display_name, const std::string& icon,
199 const std::string& category,
200 const std::string& shortcut_hint = "", int priority = 50,
201 std::function<void()> on_show = nullptr,
202 std::function<void()> on_hide = nullptr,
203 bool visible_by_default = false);
204
205 void RegisterWindow(size_t session_id, const std::string& window_id,
206 const std::string& display_name, const std::string& icon,
207 const std::string& category,
208 const std::string& shortcut_hint = "", int priority = 50,
209 std::function<void()> on_show = nullptr,
210 std::function<void()> on_hide = nullptr,
211 bool visible_by_default = false) {
212 RegisterPanel(session_id, window_id, display_name, icon, category,
213 shortcut_hint, priority, std::move(on_show),
214 std::move(on_hide), visible_by_default);
215 }
216
217 void UnregisterPanel(size_t session_id, const std::string& base_card_id);
218 void UnregisterWindow(size_t session_id, const std::string& base_window_id) {
219 UnregisterPanel(session_id, base_window_id);
220 }
221 void UnregisterPanelsWithPrefix(const std::string& prefix);
222 void ClearAllPanels();
224
225 // ============================================================================
226 // WindowContent Instance Management (Phase 4)
227 // ============================================================================
228
237 void RegisterRegistryWindowContent(std::unique_ptr<WindowContent> window);
238 void RegisterRegistryWindow(std::unique_ptr<WindowContent> window) {
239 RegisterRegistryWindowContent(std::move(window));
240 }
241
248 void RegisterRegistryWindowContentsForSession(size_t session_id);
249 void RegisterRegistryWindowsForSession(size_t session_id) {
251 }
252
255 return registry_state_.registry_ids.size();
256 }
257 size_t GetRegistryWindowCount() const {
259 }
260
270 void RegisterWindowContent(std::unique_ptr<WindowContent> window);
271 void RegisterWindowContent(std::unique_ptr<WindowContent> window,
272 WindowPresentationPolicy presentation);
273
278 void UnregisterWindowContent(const std::string& window_id);
279
285 WindowContent* GetWindowContent(const std::string& window_id);
286 WindowContent* GetWindowContent(size_t session_id,
287 const std::string& window_id);
288
298
307 void OnEditorSwitch(const std::string& from_category,
308 const std::string& to_category);
309
310 // ============================================================================
311 // Panel Control (Programmatic)
312 // ============================================================================
313
314 bool OpenWindow(size_t session_id, const std::string& base_window_id) {
315 return OpenWindowImpl(session_id, base_window_id);
316 }
317 bool OpenWindowFloating(size_t session_id, const std::string& base_window_id);
318 bool CloseWindow(size_t session_id, const std::string& base_window_id) {
319 return CloseWindowImpl(session_id, base_window_id);
320 }
321 bool ToggleWindow(size_t session_id, const std::string& base_window_id) {
322 return ToggleWindowImpl(session_id, base_window_id);
323 }
324 bool IsWindowOpen(size_t session_id,
325 const std::string& base_window_id) const {
326 return IsWindowVisibleImpl(session_id, base_window_id);
327 }
328 bool* GetWindowVisibilityFlag(size_t session_id,
329 const std::string& base_window_id) {
330 return GetVisibilityFlag(session_id, base_window_id);
331 }
332
333 // ============================================================================
334 // Batch Operations
335 // ============================================================================
336
337 void ShowAllWindowsInSession(size_t session_id);
338 void HideAllWindowsInSession(size_t session_id);
339 void ShowAllWindowsInCategory(size_t session_id, const std::string& category);
340 void HideAllWindowsInCategory(size_t session_id, const std::string& category);
341 void ShowOnlyWindow(size_t session_id, const std::string& base_window_id);
342
343 // ============================================================================
344 // Query Methods
345 // ============================================================================
346
347 std::vector<std::string> GetWindowsInSession(size_t session_id) const {
348 return GetWindowsInSessionImpl(session_id);
349 }
350 std::vector<WindowDescriptor> GetWindowsInCategory(
351 size_t session_id, const std::string& category) const {
352 return GetWindowsInCategoryImpl(session_id, category);
353 }
354 std::vector<std::string> GetAllCategories(size_t session_id) const;
355 std::vector<std::string> GetAllWindowCategories(size_t session_id) const {
356 return GetAllCategories(session_id);
357 }
359 size_t session_id, const std::string& base_window_id) const {
360 return GetWindowDescriptorImpl(session_id, base_window_id);
361 }
362
367 const std::unordered_map<std::string, WindowDescriptor>&
371
372 std::vector<std::string> GetAllCategories() const;
373 std::vector<std::string> GetAllWindowCategories() const {
374 return GetAllCategories();
375 }
376
377 // ============================================================================
378 // State Persistence
379 // ============================================================================
380
386 std::vector<std::string> GetVisibleWindowIds(size_t session_id) const {
387 return GetVisibleWindowIdsImpl(session_id);
388 }
389
395 void SetVisibleWindows(size_t session_id,
396 const std::vector<std::string>& window_ids) {
397 SetVisibleWindowsImpl(session_id, window_ids);
398 }
399
405 std::unordered_map<std::string, bool> SerializeVisibilityState(
406 size_t session_id) const;
407
414 size_t session_id, const std::unordered_map<std::string, bool>& state,
415 bool publish_events = false);
416
421 std::unordered_map<std::string, bool> SerializePinnedState() const;
422
427 void RestorePinnedState(const std::unordered_map<std::string, bool>& state);
428
433 std::string GetWorkspaceWindowName(size_t session_id,
434 const std::string& base_window_id) const {
435 return GetWindowNameImpl(session_id, base_window_id);
436 }
437 std::string GetWorkspaceWindowName(const WindowDescriptor& descriptor) const {
438 return GetWindowNameImpl(descriptor);
439 }
440
441 static constexpr float GetSidebarWidth() { return 48.0f; }
442 static constexpr float GetSidePanelWidth() { return 300.0f; }
446 };
447 static SidePanelWidthBounds GetSidePanelWidthBounds(float viewport_width);
448 static float GetSidePanelWidthForViewport(float viewport_width) {
449 if (viewport_width <= 0.0f) {
450 return GetSidePanelWidth();
451 }
452
453 // Keep side panel useful on compact/touch widths while preserving
454 // desktop defaults on large displays.
455 if (viewport_width < 900.0f) {
456 const float preferred = viewport_width * 0.50f;
457 const float min_width = std::max(220.0f, viewport_width * 0.40f);
458 const float max_width =
459 std::max(min_width, std::min(380.0f, viewport_width * 0.58f));
460 return std::clamp(preferred, min_width, max_width);
461 }
462
463 if (viewport_width < 1200.0f) {
464 const float preferred = viewport_width * 0.34f;
465 const float min_width = 300.0f;
466 const float max_width = std::min(420.0f, viewport_width * 0.42f);
467 return std::clamp(preferred, min_width, max_width);
468 }
469
470 // iPad Pro landscape sits in this range; avoid falling back to a narrow
471 // desktop sidebar width that feels cramped for touch navigation.
472 if (viewport_width < 1400.0f) {
473 const float preferred = viewport_width * 0.25f;
474 const float min_width = 300.0f;
475 const float max_width = 380.0f;
476 return std::clamp(preferred, min_width, max_width);
477 }
478
479 float width = GetSidePanelWidth();
480 const float max_width = viewport_width * 0.30f;
481 if (max_width > 0.0f && width > max_width) {
482 width = max_width;
483 }
484 return width;
485 }
486 float GetActiveSidePanelWidth(float viewport_width) const;
487 void SetActiveSidePanelWidth(float width, float viewport_width = 0.0f,
488 bool notify = true);
489 void ResetSidePanelWidth(bool notify = true);
491 void SetStoredSidePanelWidth(float width, bool notify = false) {
492 SetActiveSidePanelWidth(width, 0.0f, notify);
493 }
494 void SetSidePanelWidthChangedCallback(std::function<void(float)> cb) {
496 }
497
501 YAZE_CARD_SHIM_DEPRECATED("Use SetWindowBrowserCategoryWidth() instead.")
502 void SetPanelBrowserCategoryWidth(float width, bool notify = true);
503 void SetWindowBrowserCategoryWidth(float width, bool notify = true) {
504 SetPanelBrowserCategoryWidth(width, notify);
505 }
507 std::function<void(float)> cb) {
509 }
511 std::function<void(float)> cb) {
513 }
515 "Use GetDefaultWindowBrowserCategoryWidth() instead.")
516 static constexpr float GetDefaultPanelBrowserCategoryWidth() {
517 return 260.0f;
518 }
519 static constexpr float GetDefaultWindowBrowserCategoryWidth() {
520 return 260.0f;
521 }
522
523 static constexpr float GetCollapsedSidebarWidth() { return 16.0f; }
524
525 static std::string GetCategoryIcon(const std::string& category);
526
533 float r, g, b, a; // Icon color when active
534 float glow_r, glow_g, glow_b; // Glow/accent color (same hue)
535 };
536 static CategoryTheme GetCategoryTheme(const std::string& category);
537
541 void HandleSidebarKeyboardNav(size_t session_id,
542 const std::vector<WindowDescriptor>& cards);
543
549
557
558 void SetSidebarVisible(bool visible, bool notify = true) {
559 if (browser_state_.sidebar_visible != visible) {
564 }
565 }
566 }
567
569
577
578 YAZE_CARD_SHIM_DEPRECATED("Use SetSidebarExpanded() instead.")
579 void SetPanelExpanded(bool expanded, bool notify = true) {
580 SetSidebarExpanded(expanded, notify);
581 }
582
583 void SetSidebarExpanded(bool expanded, bool notify = true) {
584 if (browser_state_.sidebar_expanded != expanded) {
589 }
590 }
591 }
592
593 YAZE_CARD_SHIM_DEPRECATED("Use IsSidebarExpanded() instead.")
594 bool IsPanelExpanded() const { return IsSidebarExpanded(); }
596
597 // ============================================================================
598 // EventBus Integration
599 // ============================================================================
600
601 void SetEventBus(EventBus* event_bus) { event_bus_ = event_bus; }
602
603 // ============================================================================
604 // Triggers (exposed for ActivityBar) - prefer EventBus, fallback to callbacks
605 // ============================================================================
606
617 YAZE_CARD_SHIM_DEPRECATED("Use TriggerShowWindowBrowser() instead.")
619
631 void TriggerUndo() {
632 if (event_bus_) {
634 }
635 }
636 void TriggerRedo() {
637 if (event_bus_) {
639 }
640 }
685 void TriggerWindowClicked(const std::string& category) {
688 }
689 void TriggerCategorySelected(const std::string& category) {
692 }
693 }
694 void TriggerWindowCategorySelected(const std::string& category) {
695 TriggerCategorySelected(category);
696 }
697
698 // ============================================================================
699 // Utility Icon Callbacks (DEPRECATED: subscribe to UIActionRequestEvent instead)
700 // ============================================================================
701
702 void SetSidebarStateChangedCallback(std::function<void(bool, bool)> cb) {
704 }
705
706 void SetCategoryChangedCallback(std::function<void(const std::string&)> cb) {
707 browser_state_.on_category_changed = std::move(cb);
708 }
709
710 // ============================================================================
711 // Workspace Presets
712 // ============================================================================
713
715 std::string name;
716 std::vector<std::string> visible_cards; // Panel IDs
717 std::string description;
718 };
719
720 void SavePreset(const std::string& name, const std::string& description = "");
721 bool LoadPreset(const std::string& name);
722 void DeletePreset(const std::string& name);
723 std::vector<WorkspacePreset> GetPresets() const;
724
725 // ============================================================================
726 // Panel Validation (for catching ImGui window-name mismatches)
727 // ============================================================================
728
730 std::string card_id;
731 std::string expected_title; // Exact ImGui window name for docking/focus
732 bool found_in_imgui; // Whether ImGui found a window with this title
733 std::string message; // Human-readable status
734 };
735
736 std::vector<WindowValidationResult> ValidateWindows() const;
737 WindowValidationResult ValidateWindow(const std::string& card_id) const;
738
739 // ============================================================================
740 // Quick Actions
741 // ============================================================================
742
743 void ShowAll(size_t session_id);
744 void HideAll(size_t session_id);
745 void ResetToDefaults(size_t session_id);
746 void ResetToDefaults(size_t session_id, EditorType editor_type);
747
748 // ============================================================================
749 // Statistics
750 // ============================================================================
751
752 size_t GetWindowCount() const { return registry_state_.descriptors.size(); }
753 size_t GetVisibleWindowCount(size_t session_id) const;
755
756 // ============================================================================
757 // Session Prefixing Utilities
758 // ============================================================================
759
760 std::string MakeWindowId(size_t session_id, const std::string& base_id) const;
761 std::string MakeWindowId(size_t session_id, const std::string& base_id,
762 WindowScope scope) const;
763 bool ShouldPrefixPanels() const { return session_count_ > 1; }
764
765 // ============================================================================
766 // Convenience Methods (for EditorManager direct usage without session_id)
767 // ============================================================================
768
769 void RegisterPanel(const WindowDescriptor& base_info) {
770 RegisterPanel(active_session_, base_info);
771 }
772 void RegisterWindow(const WindowDescriptor& descriptor) {
773 RegisterPanel(active_session_, descriptor);
774 }
775 void UnregisterPanel(const std::string& base_card_id) {
776 UnregisterPanel(active_session_, base_card_id);
777 }
778 void UnregisterWindow(const std::string& base_window_id) {
779 UnregisterPanel(active_session_, base_window_id);
780 }
781 bool OpenWindow(const std::string& base_window_id) {
782 return OpenWindowImpl(active_session_, base_window_id);
783 }
784 bool OpenWindowFloating(const std::string& base_window_id) {
785 return OpenWindowFloating(active_session_, base_window_id);
786 }
787 bool CloseWindow(const std::string& base_window_id) {
788 return CloseWindowImpl(active_session_, base_window_id);
789 }
790 bool IsWindowOpen(const std::string& base_window_id) const {
791 return IsWindowVisibleImpl(active_session_, base_window_id);
792 }
793 void HideAllWindowsInCategory(const std::string& category) {
795 }
796 std::string GetActiveCategory() const {
798 }
799 void SetActiveCategory(const std::string& category, bool notify = true) {
800 if (browser_state_.active_category != category) {
802 if (notify && browser_state_.on_category_changed) {
804 }
805 }
806 }
807 void ShowAllWindowsInCategory(const std::string& category) {
809 }
810 bool* GetWindowVisibilityFlag(const std::string& base_window_id) {
811 return GetVisibilityFlag(active_session_, base_window_id);
812 }
816 std::function<void(const std::string&)> callback) {
817 browser_state_.on_window_clicked = std::move(callback);
818 }
820 std::function<void(const std::string&)> callback) {
821 browser_state_.on_category_selected = std::move(callback);
822 }
823 void SetEditorResolver(std::function<Editor*(const std::string&)> resolver) {
824 editor_resolver_ = std::move(resolver);
825 }
826
827 size_t GetActiveSessionId() const { return active_session_; }
828
829 // ============================================================================
830 // File Browser Integration
831 // ============================================================================
832
833 FileBrowser* GetFileBrowser(const std::string& category);
834 void EnableFileBrowser(const std::string& category,
835 const std::string& root_path = "");
836 void DisableFileBrowser(const std::string& category);
837 bool HasFileBrowser(const std::string& category) const;
838 void SetFileBrowserPath(const std::string& category, const std::string& path);
840 std::function<void(const std::string& category, const std::string& path)>
841 callback) {
842 on_file_clicked_ = std::move(callback);
843 }
844
845 // ============================================================================
846 // Favorites (delegates to Pinned) and Recent
847 // ============================================================================
848
849 // Favorites are now aliases for pinned panels
850 void ToggleFavorite(const std::string& card_id) {
851 SetWindowPinned(card_id, !IsWindowPinned(card_id));
852 }
853 bool IsFavorite(const std::string& card_id) const {
854 return IsWindowPinned(card_id);
855 }
856
857 void MarkWindowRecentlyUsed(const std::string& window_id) {
859 }
860
861 std::vector<WindowDescriptor> GetWindowsSortedByMRU(
862 size_t session_id, const std::string& category) const {
863 return GetWindowsSortedByMRUImpl(session_id, category);
864 }
865
866 uint64_t GetWindowMRUTime(const std::string& window_id) const {
867 return GetWindowMRUTimeImpl(window_id);
868 }
869
870 // ============================================================================
871 // Pinning (Phase 3 scaffold)
872 // ============================================================================
873
874 void SetWindowPinned(size_t session_id, const std::string& base_window_id,
875 bool pinned) {
876 SetWindowPinnedImpl(session_id, base_window_id, pinned);
877 }
878 bool IsWindowPinned(size_t session_id,
879 const std::string& base_window_id) const {
880 return IsWindowPinnedImpl(session_id, base_window_id);
881 }
882 std::vector<std::string> GetPinnedWindows(size_t session_id) const {
883 return GetPinnedWindowsImpl(session_id);
884 }
885
886 void SetWindowPinned(const std::string& base_window_id, bool pinned) {
887 SetWindowPinnedImpl(base_window_id, pinned);
888 }
889 bool IsWindowPinned(const std::string& base_window_id) const {
890 return IsWindowPinnedImpl(base_window_id);
891 }
892 std::vector<std::string> GetPinnedWindows() const {
893 return GetPinnedWindowsImpl();
894 }
895
896 // ============================================================================
897 // Resource Management (Phase 6)
898 // ============================================================================
899
907 void EnforceResourceLimits(const std::string& resource_type);
908 void EnforceResourceWindowLimits(const std::string& resource_type) {
909 EnforceResourceLimits(resource_type);
910 }
911
916 void MarkPanelUsed(const std::string& panel_id);
917
918 WindowContent* FindPanelInstance(const std::string& prefixed_panel_id,
919 const std::string& base_panel_id);
921 const std::string& prefixed_panel_id,
922 const std::string& base_panel_id) const;
923
924 private:
926 size_t operator()(WindowContextScope scope) const noexcept {
927 return static_cast<size_t>(scope);
928 }
929 };
930
931 void ApplyContextPolicy(size_t session_id, WindowContextScope scope,
932 const std::string& old_key,
933 const std::string& new_key);
934 WindowDescriptor* FindDescriptorByPrefixedId(const std::string& prefixed_id);
936 const std::string& prefixed_id) const;
937 std::vector<std::string>* FindSessionWindowIds(size_t session_id);
938 const std::vector<std::string>* FindSessionWindowIds(size_t session_id) const;
939 std::unordered_map<std::string, std::string>* FindSessionWindowMapping(
940 size_t session_id);
941 const std::unordered_map<std::string, std::string>* FindSessionWindowMapping(
942 size_t session_id) const;
943 std::unordered_map<std::string, std::string>* FindSessionReverseWindowMapping(
944 size_t session_id);
945 const std::unordered_map<std::string, std::string>*
946 FindSessionReverseWindowMapping(size_t session_id) const;
947 void PublishWindowVisibilityChanged(size_t session_id,
948 const std::string& prefixed_window_id,
949 const std::string& base_window_id,
950 const std::string& category,
951 bool visible) const;
952 bool OpenWindowImpl(size_t session_id, const std::string& base_card_id);
953 bool CloseWindowImpl(size_t session_id, const std::string& base_card_id);
954 bool ToggleWindowImpl(size_t session_id, const std::string& base_card_id);
955 bool IsWindowVisibleImpl(size_t session_id,
956 const std::string& base_card_id) const;
957 bool* GetVisibilityFlag(size_t session_id, const std::string& base_card_id);
958 std::vector<std::string> GetWindowsInSessionImpl(size_t session_id) const;
959 std::vector<WindowDescriptor> GetWindowsInCategoryImpl(
960 size_t session_id, const std::string& category) const;
961 std::vector<std::string> GetVisibleWindowIdsImpl(size_t session_id) const;
962 void SetVisibleWindowsImpl(size_t session_id,
963 const std::vector<std::string>& panel_ids);
965 size_t session_id, const std::string& base_card_id) const;
966 std::string GetWindowNameImpl(size_t session_id,
967 const std::string& base_card_id) const;
968 std::string GetWindowNameImpl(const WindowDescriptor& descriptor) const;
969 void MarkWindowRecentlyUsedImpl(const std::string& card_id);
970 std::vector<WindowDescriptor> GetWindowsSortedByMRUImpl(
971 size_t session_id, const std::string& category) const;
972 uint64_t GetWindowMRUTimeImpl(const std::string& card_id) const {
973 auto iter = last_used_at_.find(card_id);
974 return (iter != last_used_at_.end()) ? iter->second : 0;
975 }
976 void SetWindowPinnedImpl(size_t session_id, const std::string& base_card_id,
977 bool pinned);
978 bool IsWindowPinnedImpl(size_t session_id,
979 const std::string& base_card_id) const;
980 std::vector<std::string> GetPinnedWindowsImpl(size_t session_id) const;
981 void RememberPinnedStateForRemovedWindow(size_t session_id,
982 const std::string& base_card_id,
983 const std::string& prefixed_id);
984 void SetWindowPinnedImpl(const std::string& base_card_id, bool pinned);
985 bool IsWindowPinnedImpl(const std::string& base_card_id) const;
986 std::vector<std::string> GetPinnedWindowsImpl() const;
987 size_t GetResourceWindowLimit(const std::string& resource_type) const;
988 void TrackResourceWindow(const std::string& panel_id,
989 ResourceWindowContent* resource_panel);
990 void UntrackResourceWindow(const std::string& panel_id);
992 const std::list<std::string>& panel_ids) const;
993 std::string ResolveBaseWindowId(const std::string& panel_id) const;
994 std::string GetBaseIdForPrefixedId(size_t session_id,
995 const std::string& prefixed_id) const;
996
997 // ... existing private members ...
998
1000 std::unordered_map<std::string, std::list<std::string>> window_ids_by_type;
1001 std::unordered_map<std::string, std::string> window_type_by_id;
1002 };
1003
1005
1006 std::unordered_map<std::string, std::list<std::string>>& resource_panels_ =
1008 std::unordered_map<std::string, std::string>& panel_resource_types_ =
1010
1012 std::unordered_map<std::string, WindowDescriptor> descriptors;
1013 std::unordered_map<std::string, std::unique_ptr<WindowContent>> instances;
1014 std::unordered_set<std::string> registry_ids;
1015 std::unordered_set<std::string> global_ids;
1016 std::unordered_map<std::string, bool> centralized_visibility;
1017 std::unordered_map<std::string, std::string> aliases;
1018 };
1019
1021 std::unordered_map<std::string, uint64_t> last_used_at;
1022 uint64_t mru_counter = 0;
1023 std::unordered_map<std::string, bool> pinned_windows;
1024 // Base-id → pinned entries restored before the matching panel registered.
1025 // Consumed by TrackPanelForSession when late-registering panels arrive.
1026 // Also included in SerializePinnedState so pins survive a restart even
1027 // when the user never actually opened the panel in the prior session.
1028 std::unordered_map<std::string, bool> pending_pinned_base_ids;
1029 std::unordered_set<std::string> pending_float_window_ids;
1030 size_t session_count = 0;
1031 size_t active_session = 0;
1032 std::unordered_map<size_t, std::vector<std::string>> session_windows;
1033 std::unordered_map<size_t, std::unordered_map<std::string, std::string>>
1035 std::unordered_map<size_t, std::unordered_map<std::string, std::string>>
1037 std::unordered_map<size_t,
1038 std::unordered_map<WindowContextScope, std::string,
1041 };
1042
1045
1046 // Legacy field aliases kept during the panel->window migration while methods
1047 // are gradually moved over to the grouped state containers above.
1048 std::unordered_map<std::string, WindowDescriptor>& cards_ =
1050 std::unordered_map<std::string, std::unique_ptr<WindowContent>>&
1052 std::unordered_set<std::string>& registry_panel_ids_ =
1054 std::unordered_set<std::string>& global_panel_ids_ =
1056 std::unordered_map<std::string, bool>& centralized_visibility_ =
1058 std::unordered_map<std::string, std::string>& panel_id_aliases_ =
1060
1061 std::unordered_map<std::string, uint64_t>& last_used_at_ =
1064 std::unordered_map<std::string, bool>& pinned_panels_ =
1066 std::unordered_map<std::string, bool>& pending_pinned_base_ids_ =
1068 std::unordered_set<std::string>& pending_float_window_ids_ =
1072 std::unordered_map<size_t, std::vector<std::string>>& session_cards_ =
1074 std::unordered_map<size_t, std::unordered_map<std::string, std::string>>&
1076 std::unordered_map<size_t, std::unordered_map<std::string, std::string>>&
1079 std::unordered_map<size_t, std::unordered_map<WindowContextScope, std::string,
1082
1083 // Workspace presets
1084 std::unordered_map<std::string, WorkspacePreset> presets_;
1085
1087 static constexpr size_t kMaxRecentCategories = 5;
1088
1089 std::string active_category;
1090 std::vector<std::string> recent_categories;
1091 bool sidebar_visible = false;
1092 bool sidebar_expanded = false;
1093 float sidebar_width = 0.0f;
1094 float window_browser_category_width = GetDefaultPanelBrowserCategoryWidth();
1096 bool sidebar_has_focus = false;
1097 std::function<void(bool visible, bool expanded)> on_sidebar_state_changed;
1098 std::function<void(float width)> on_sidebar_width_changed;
1099 std::function<void(float width)> on_window_browser_width_changed;
1100 std::function<void(const std::string&)> on_category_changed;
1101 std::function<void(const std::string&)> on_window_clicked;
1102 std::function<void(const std::string&)> on_category_selected;
1103 std::unordered_map<std::string, std::unique_ptr<FileBrowser>>
1105 };
1106
1108
1109 // EventBus for action events (preferred over callbacks)
1111
1112 // State change callbacks
1113 std::function<void(const std::string&, const std::string&)> on_file_clicked_;
1114 std::function<Editor*(const std::string&)> editor_resolver_;
1115
1116 // Helper methods
1117 void UpdateSessionCount();
1118 std::string GetPrefixedWindowId(size_t session_id,
1119 const std::string& base_id) const;
1120 void RegisterPanelDescriptorForSession(size_t session_id,
1121 const WindowContent& panel);
1122 void TrackPanelForSession(size_t session_id, const std::string& base_id,
1123 const std::string& panel_id);
1124 void UnregisterSessionPanels(size_t session_id);
1125 void SavePresetsToFile();
1126 void LoadPresetsFromFile();
1127};
1128
1129} // namespace editor
1130} // namespace yaze
1131
1132#undef YAZE_CARD_SHIM_DEPRECATED
1133
1134#endif // YAZE_APP_EDITOR_SYSTEM_WORKSPACE_WINDOW_MANAGER_H_
void Publish(const T &event)
Definition event_bus.h:35
Interface for editor classes.
Definition editor.h:252
File system browser for the sidebar.
Base class for windows that edit specific ROM resources.
Base interface for all logical window content components.
Central registry for all editor cards with session awareness and dependency injection.
void EnableFileBrowser(const std::string &category, const std::string &root_path="")
std::unordered_set< std::string > & pending_float_window_ids_
void RegisterPanel(size_t session_id, const WindowDescriptor &base_info)
bool IsWindowPinnedImpl(size_t session_id, const std::string &base_card_id) const
void SavePreset(const std::string &name, const std::string &description="")
std::vector< std::string > GetWindowsInSessionImpl(size_t session_id) const
void SetVisibleWindows(size_t session_id, const std::vector< std::string > &window_ids)
Set which panels should be visible for a session.
bool IsWindowOpen(const std::string &base_window_id) const
void SetActiveSidePanelWidth(float width, float viewport_width=0.0f, bool notify=true)
void HideAllWindowsInCategory(size_t session_id, const std::string &category)
bool CloseWindowImpl(size_t session_id, const std::string &base_card_id)
std::string GetContextKey(size_t session_id, WindowContextScope scope) const
size_t GetResourceWindowLimit(const std::string &resource_type) const
std::unordered_map< size_t, std::unordered_map< std::string, std::string > > & session_reverse_card_mapping_
std::string GetWorkspaceWindowName(size_t session_id, const std::string &base_window_id) const
Resolve the exact ImGui window name for a panel by base ID.
static SidePanelWidthBounds GetSidePanelWidthBounds(float viewport_width)
void SetSidebarVisible(bool visible, bool notify=true)
std::vector< WindowDescriptor > GetWindowsInCategory(size_t session_id, const std::string &category) const
std::vector< WorkspacePreset > GetPresets() const
void UnregisterWindowContent(const std::string &window_id)
Unregister and destroy a WindowContent instance.
std::unordered_map< std::string, std::string > * FindSessionWindowMapping(size_t session_id)
std::string SelectResourceWindowForEviction(const std::list< std::string > &panel_ids) const
void RegisterRegistryWindowsForSession(size_t session_id)
bool * GetVisibilityFlag(size_t session_id, const std::string &base_card_id)
void UntrackResourceWindow(const std::string &panel_id)
std::string ResolveBaseWindowId(const std::string &panel_id) const
void RegisterWindow(const WindowDescriptor &descriptor)
void SetEditorResolver(std::function< Editor *(const std::string &)> resolver)
std::unordered_map< std::string, WindowDescriptor > & cards_
std::string GetPrefixedWindowId(size_t session_id, const std::string &base_id) const
std::string ResolveWindowAlias(const std::string &window_id) const
void RestoreVisibilityState(size_t session_id, const std::unordered_map< std::string, bool > &state, bool publish_events=false)
Restore panel visibility state from persistence.
bool OpenWindowFloating(size_t session_id, const std::string &base_window_id)
static float GetSidePanelWidthForViewport(float viewport_width)
void SetPanelBrowserCategoryWidthChangedCallback(std::function< void(float)> cb)
std::vector< std::string > * FindSessionWindowIds(size_t session_id)
const WindowDescriptor * GetWindowDescriptor(size_t session_id, const std::string &base_window_id) const
void ApplyContextPolicy(size_t session_id, WindowContextScope scope, const std::string &old_key, const std::string &new_key)
const WindowDescriptor * GetWindowDescriptorImpl(size_t session_id, const std::string &base_card_id) const
WorkspaceWindowManager(WorkspaceWindowManager &&)=delete
std::vector< std::string > GetWindowsInSession(size_t session_id) const
bool CloseWindow(const std::string &base_window_id)
void RememberPinnedStateForRemovedWindow(size_t session_id, const std::string &base_card_id, const std::string &prefixed_id)
std::string GetBaseIdForPrefixedId(size_t session_id, const std::string &prefixed_id) const
static CategoryTheme GetCategoryTheme(const std::string &category)
void RegisterWindowAlias(const std::string &legacy_base_id, const std::string &canonical_base_id)
WorkspaceWindowManager & operator=(const WorkspaceWindowManager &)=delete
FileBrowser * GetFileBrowser(const std::string &category)
std::unordered_map< std::string, std::string > & panel_resource_types_
std::vector< WindowDescriptor > GetWindowsInCategoryImpl(size_t session_id, const std::string &category) const
const std::unordered_map< std::string, WindowDescriptor > & GetAllWindowDescriptors() const
Get all panel descriptors (for layout designer, panel browser, etc.)
std::unordered_map< std::string, bool > & centralized_visibility_
std::unordered_map< size_t, std::unordered_map< std::string, std::string > > & session_card_mapping_
std::unordered_map< std::string, bool > & pending_pinned_base_ids_
void SetPanelExpanded(bool expanded, bool notify=true)
void MarkPanelUsed(const std::string &panel_id)
Mark a panel as recently used (for LRU)
bool IsWindowPinned(const std::string &base_window_id) const
std::function< void(const std::string &, const std::string &) on_file_clicked_)
void TrackPanelForSession(size_t session_id, const std::string &base_id, const std::string &panel_id)
void SetWindowPinned(size_t session_id, const std::string &base_window_id, bool pinned)
bool CloseWindow(size_t session_id, const std::string &base_window_id)
std::unordered_map< std::string, std::list< std::string > > & resource_panels_
std::vector< std::string > GetAllWindowCategories() const
void TrackResourceWindow(const std::string &panel_id, ResourceWindowContent *resource_panel)
std::vector< std::string > GetAllWindowCategories(size_t session_id) const
std::vector< std::string > GetAllCategories() const
void SetActiveCategory(const std::string &category, bool notify=true)
void SetSidebarStateChangedCallback(std::function< void(bool, bool)> cb)
std::string GetWorkspaceWindowName(const WindowDescriptor &descriptor) const
std::vector< std::string > GetPinnedWindowsImpl() const
void RegisterRegistryWindowContent(std::unique_ptr< WindowContent > window)
Register a ContentRegistry-managed WindowContent instance.
static std::string GetCategoryIcon(const std::string &category)
void UnregisterPanel(size_t session_id, const std::string &base_card_id)
void TriggerWindowClicked(const std::string &category)
void ShowOnlyWindow(size_t session_id, const std::string &base_window_id)
bool IsFavorite(const std::string &card_id) const
bool OpenWindowFloating(const std::string &base_window_id)
void RegisterWindowContent(std::unique_ptr< WindowContent > window)
Register a WindowContent instance for central drawing.
std::function< Editor *(const std::string &) editor_resolver_)
static constexpr const char * kDashboardCategory
std::unordered_map< std::string, WorkspacePreset > presets_
void EnforceResourceLimits(const std::string &resource_type)
Enforce limits on resource panels (LRU eviction)
bool HasFileBrowser(const std::string &category) const
YAZE_CARD_SHIM_DEPRECATED("Use GetDefaultWindowBrowserCategoryWidth() instead.") static const expr float GetDefaultPanelBrowserCategoryWidth()
WindowDescriptor * FindDescriptorByPrefixedId(const std::string &prefixed_id)
std::vector< std::string > GetVisibleWindowIds(size_t session_id) const
Get list of currently visible panel IDs for a session.
void SetPanelBrowserCategoryWidth(float width, bool notify=true)
void RegisterWindow(size_t session_id, const WindowDescriptor &descriptor)
bool IsWindowVisibleImpl(size_t session_id, const std::string &base_card_id) const
void SetStoredSidePanelWidth(float width, bool notify=false)
void DrawAllVisiblePanels()
Draw all visible WindowContent instances (central drawing)
std::unordered_map< std::string, std::unique_ptr< WindowContent > > & panel_instances_
void SetVisibleWindowsImpl(size_t session_id, const std::vector< std::string > &panel_ids)
void RegisterRegistryWindow(std::unique_ptr< WindowContent > window)
std::unordered_set< std::string > & registry_panel_ids_
std::vector< std::string > GetVisibleWindowIdsImpl(size_t session_id) const
void SetWindowPinnedImpl(size_t session_id, const std::string &base_card_id, bool pinned)
void MarkWindowRecentlyUsedImpl(const std::string &card_id)
bool ToggleWindowImpl(size_t session_id, const std::string &base_card_id)
std::unordered_map< size_t, std::vector< std::string > > & session_cards_
std::vector< std::string > GetPinnedWindows(size_t session_id) const
void HideAllWindowsInCategory(const std::string &category)
uint64_t GetWindowMRUTime(const std::string &window_id) const
size_t GetVisibleWindowCount(size_t session_id) const
bool IsWindowOpen(size_t session_id, const std::string &base_window_id) const
void EnforceResourceWindowLimits(const std::string &resource_type)
std::string ResolvePanelAlias(const std::string &panel_id) const
Resolve a panel ID through the alias table.
std::unordered_map< std::string, std::string > * FindSessionReverseWindowMapping(size_t session_id)
bool OpenWindow(const std::string &base_window_id)
std::string GetWindowNameImpl(size_t session_id, const std::string &base_card_id) const
void SetCategoryChangedCallback(std::function< void(const std::string &)> cb)
void SetFileBrowserPath(const std::string &category, const std::string &path)
std::unordered_map< std::string, uint64_t > & last_used_at_
void SetWindowBrowserCategoryWidthChangedCallback(std::function< void(float)> cb)
float GetActiveSidePanelWidth(float viewport_width) const
std::string MakeWindowId(size_t session_id, const std::string &base_id) const
std::vector< WindowDescriptor > GetWindowsSortedByMRUImpl(size_t session_id, const std::string &category) const
bool * GetWindowVisibilityFlag(const std::string &base_window_id)
void SetOnWindowCategorySelectedCallback(std::function< void(const std::string &)> callback)
void TriggerCategorySelected(const std::string &category)
std::unordered_map< std::string, bool > SerializeVisibilityState(size_t session_id) const
Serialize panel visibility state for persistence.
void SetOnWindowClickedCallback(std::function< void(const std::string &)> callback)
void HandleSidebarKeyboardNav(size_t session_id, const std::vector< WindowDescriptor > &cards)
Handle keyboard navigation in sidebar (click-to-focus modal)
void OnEditorSwitch(const std::string &from_category, const std::string &to_category)
Update the active category and start panel transitions.
bool OpenWindow(size_t session_id, const std::string &base_window_id)
uint64_t GetWindowMRUTimeImpl(const std::string &card_id) const
void ToggleFavorite(const std::string &card_id)
std::vector< WindowValidationResult > ValidateWindows() const
static constexpr float GetDefaultWindowBrowserCategoryWidth()
std::vector< std::string > GetPinnedWindows() const
std::vector< WindowDescriptor > GetWindowsSortedByMRU(size_t session_id, const std::string &category) const
void RegisterWindow(size_t session_id, const std::string &window_id, const std::string &display_name, const std::string &icon, const std::string &category, const std::string &shortcut_hint="", int priority=50, std::function< void()> on_show=nullptr, std::function< void()> on_hide=nullptr, bool visible_by_default=false)
void ShowAllWindowsInCategory(const std::string &category)
std::unordered_map< std::string, std::string > & panel_id_aliases_
std::unordered_map< std::string, bool > & pinned_panels_
bool IsWindowPinned(size_t session_id, const std::string &base_window_id) const
void SetSidePanelWidthChangedCallback(std::function< void(float)> cb)
WorkspaceWindowManager(const WorkspaceWindowManager &)=delete
void TriggerWindowCategorySelected(const std::string &category)
WindowContent * GetWindowContent(const std::string &window_id)
Get a WindowContent instance by ID.
bool ToggleWindow(size_t session_id, const std::string &base_window_id)
void SetWindowBrowserCategoryWidth(float width, bool notify=true)
void RegisterRegistryWindowContentsForSession(size_t session_id)
Register descriptors for all registry window contents in a session.
void SetFileClickedCallback(std::function< void(const std::string &category, const std::string &path)> callback)
size_t GetRegistryWindowContentCount() const
Returns the number of window contents registered via ContentRegistry.
void UnregisterPanel(const std::string &base_card_id)
std::unordered_map< std::string, bool > SerializePinnedState() const
Serialize pinned panel state for persistence.
void SetSidebarExpanded(bool expanded, bool notify=true)
WorkspaceWindowManager & operator=(WorkspaceWindowManager &&)=delete
std::unordered_map< size_t, std::unordered_map< WindowContextScope, std::string, WindowContextScopeHash > > & session_context_keys_
void UnregisterWindow(const std::string &base_window_id)
WindowContent * FindPanelInstance(const std::string &prefixed_panel_id, const std::string &base_panel_id)
void RegisterPanel(const WindowDescriptor &base_info)
void UnregisterPanelsWithPrefix(const std::string &prefix)
bool * GetWindowVisibilityFlag(size_t session_id, const std::string &base_window_id)
void SetContextKey(size_t session_id, WindowContextScope scope, std::string key)
Set a string key for a given context scope (room/selection/etc)
WindowValidationResult ValidateWindow(const std::string &card_id) const
void PublishWindowVisibilityChanged(size_t session_id, const std::string &prefixed_window_id, const std::string &base_window_id, const std::string &category, bool visible) const
void RegisterPanelDescriptorForSession(size_t session_id, const WindowContent &panel)
bool OpenWindowImpl(size_t session_id, const std::string &base_card_id)
void ShowAllWindowsInCategory(size_t session_id, const std::string &category)
void UnregisterWindow(size_t session_id, const std::string &base_window_id)
void RestorePinnedState(const std::unordered_map< std::string, bool > &state)
Restore pinned panel state from persistence.
void RegisterPanelAlias(const std::string &legacy_base_id, const std::string &canonical_base_id)
Register a legacy panel ID alias that resolves to a canonical ID.
void MarkWindowRecentlyUsed(const std::string &window_id)
void SetWindowPinned(const std::string &base_window_id, bool pinned)
std::unordered_set< std::string > & global_panel_ids_
WindowContextScope
Optional context binding for a window's behavior within an editor.
WindowLifecycle
Defines lifecycle behavior for editor windows.
@ EditorBound
Hidden when switching editors (default)
WindowScope
Defines whether a window is session-scoped or global.
static UIActionRequestEvent Redo(size_t session=0)
static UIActionRequestEvent ShowCommandPalette(size_t session=0)
static UIActionRequestEvent SaveRom(size_t session=0)
static UIActionRequestEvent Create(Action act, size_t session=0)
static UIActionRequestEvent Undo(size_t session=0)
static UIActionRequestEvent ShowSettings(size_t session=0)
static UIActionRequestEvent ShowAgentProposalsSidebar(size_t session=0)
static UIActionRequestEvent ShowAgentChatSidebar(size_t session=0)
static UIActionRequestEvent OpenRom(size_t session=0)
static UIActionRequestEvent ShowEmulator(size_t session=0)
Metadata for a dockable editor window (formerly PanelInfo)
std::string GetWindowTitle() const
Get the effective window title for DockBuilder.
std::string GetImGuiWindowName() const
Build the exact ImGui window name used by PanelWindow::Begin.
Get the expressive theme color for a category.
std::unordered_map< std::string, std::string > window_type_by_id
std::unordered_map< std::string, std::list< std::string > > window_ids_by_type
std::function< void(bool visible, bool expanded)> on_sidebar_state_changed
std::function< void(const std::string &) on_category_selected)
std::unordered_map< std::string, std::unique_ptr< FileBrowser > > category_file_browsers
std::function< void(const std::string &) on_category_changed)
size_t operator()(WindowContextScope scope) const noexcept
std::unordered_map< std::string, std::string > aliases
std::unordered_map< std::string, std::unique_ptr< WindowContent > > instances
std::unordered_map< std::string, WindowDescriptor > descriptors
std::unordered_map< size_t, std::unordered_map< WindowContextScope, std::string, WindowContextScopeHash > > session_context_keys
std::unordered_map< size_t, std::vector< std::string > > session_windows
std::unordered_map< size_t, std::unordered_map< std::string, std::string > > session_reverse_window_mapping
std::unordered_map< size_t, std::unordered_map< std::string, std::string > > session_window_mapping
#define YAZE_CARD_SHIM_DEPRECATED(msg)