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
309 void OnEditorSwitch(const std::string& from_category,
310 const std::string& to_category);
311
312 // ============================================================================
313 // Panel Control (Programmatic)
314 // ============================================================================
315
316 bool OpenWindow(size_t session_id, const std::string& base_window_id) {
317 return OpenWindowImpl(session_id, base_window_id);
318 }
319 bool OpenWindowFloating(size_t session_id, const std::string& base_window_id);
320 bool CloseWindow(size_t session_id, const std::string& base_window_id) {
321 return CloseWindowImpl(session_id, base_window_id);
322 }
323 bool ToggleWindow(size_t session_id, const std::string& base_window_id) {
324 return ToggleWindowImpl(session_id, base_window_id);
325 }
326 bool IsWindowOpen(size_t session_id,
327 const std::string& base_window_id) const {
328 return IsWindowVisibleImpl(session_id, base_window_id);
329 }
330 bool* GetWindowVisibilityFlag(size_t session_id,
331 const std::string& base_window_id) {
332 return GetVisibilityFlag(session_id, base_window_id);
333 }
334
335 // ============================================================================
336 // Batch Operations
337 // ============================================================================
338
339 void ShowAllWindowsInSession(size_t session_id);
340 void HideAllWindowsInSession(size_t session_id);
341 void ShowAllWindowsInCategory(size_t session_id, const std::string& category);
342 void HideAllWindowsInCategory(size_t session_id, const std::string& category);
343 void ShowOnlyWindow(size_t session_id, const std::string& base_window_id);
344
345 // ============================================================================
346 // Query Methods
347 // ============================================================================
348
349 std::vector<std::string> GetWindowsInSession(size_t session_id) const {
350 return GetWindowsInSessionImpl(session_id);
351 }
352 std::vector<WindowDescriptor> GetWindowsInCategory(
353 size_t session_id, const std::string& category) const {
354 return GetWindowsInCategoryImpl(session_id, category);
355 }
356 std::vector<std::string> GetAllCategories(size_t session_id) const;
357 std::vector<std::string> GetAllWindowCategories(size_t session_id) const {
358 return GetAllCategories(session_id);
359 }
361 size_t session_id, const std::string& base_window_id) const {
362 return GetWindowDescriptorImpl(session_id, base_window_id);
363 }
364
369 const std::unordered_map<std::string, WindowDescriptor>&
373
374 std::vector<std::string> GetAllCategories() const;
375 std::vector<std::string> GetAllWindowCategories() const {
376 return GetAllCategories();
377 }
378
379 // ============================================================================
380 // State Persistence
381 // ============================================================================
382
388 std::vector<std::string> GetVisibleWindowIds(size_t session_id) const {
389 return GetVisibleWindowIdsImpl(session_id);
390 }
391
397 void SetVisibleWindows(size_t session_id,
398 const std::vector<std::string>& window_ids) {
399 SetVisibleWindowsImpl(session_id, window_ids);
400 }
401
407 std::unordered_map<std::string, bool> SerializeVisibilityState(
408 size_t session_id) const;
409
416 size_t session_id, const std::unordered_map<std::string, bool>& state,
417 bool publish_events = false);
418
423 std::unordered_map<std::string, bool> SerializePinnedState() const;
424
429 void RestorePinnedState(const std::unordered_map<std::string, bool>& state);
430
435 std::string GetWorkspaceWindowName(size_t session_id,
436 const std::string& base_window_id) const {
437 return GetWindowNameImpl(session_id, base_window_id);
438 }
439 std::string GetWorkspaceWindowName(const WindowDescriptor& descriptor) const {
440 return GetWindowNameImpl(descriptor);
441 }
442
443 static constexpr float GetSidebarWidth() { return 48.0f; }
444 static constexpr float GetSidePanelWidth() { return 300.0f; }
448 };
449 static SidePanelWidthBounds GetSidePanelWidthBounds(float viewport_width);
450 static float GetSidePanelWidthForViewport(float viewport_width) {
451 if (viewport_width <= 0.0f) {
452 return GetSidePanelWidth();
453 }
454
455 // Keep side panel useful on compact/touch widths while preserving
456 // desktop defaults on large displays.
457 if (viewport_width < 900.0f) {
458 const float preferred = viewport_width * 0.50f;
459 const float min_width = std::max(220.0f, viewport_width * 0.40f);
460 const float max_width =
461 std::max(min_width, std::min(380.0f, viewport_width * 0.58f));
462 return std::clamp(preferred, min_width, max_width);
463 }
464
465 if (viewport_width < 1200.0f) {
466 const float preferred = viewport_width * 0.34f;
467 const float min_width = 300.0f;
468 const float max_width = std::min(420.0f, viewport_width * 0.42f);
469 return std::clamp(preferred, min_width, max_width);
470 }
471
472 // iPad Pro landscape sits in this range; avoid falling back to a narrow
473 // desktop sidebar width that feels cramped for touch navigation.
474 if (viewport_width < 1400.0f) {
475 const float preferred = viewport_width * 0.25f;
476 const float min_width = 300.0f;
477 const float max_width = 380.0f;
478 return std::clamp(preferred, min_width, max_width);
479 }
480
481 float width = GetSidePanelWidth();
482 const float max_width = viewport_width * 0.30f;
483 if (max_width > 0.0f && width > max_width) {
484 width = max_width;
485 }
486 return width;
487 }
488 float GetActiveSidePanelWidth(float viewport_width) const;
489 void SetActiveSidePanelWidth(float width, float viewport_width = 0.0f,
490 bool notify = true);
491 void ResetSidePanelWidth(bool notify = true);
493 void SetStoredSidePanelWidth(float width, bool notify = false) {
494 SetActiveSidePanelWidth(width, 0.0f, notify);
495 }
496 void SetSidePanelWidthChangedCallback(std::function<void(float)> cb) {
498 }
499
503 YAZE_CARD_SHIM_DEPRECATED("Use SetWindowBrowserCategoryWidth() instead.")
504 void SetPanelBrowserCategoryWidth(float width, bool notify = true);
505 void SetWindowBrowserCategoryWidth(float width, bool notify = true) {
506 SetPanelBrowserCategoryWidth(width, notify);
507 }
509 std::function<void(float)> cb) {
511 }
513 std::function<void(float)> cb) {
515 }
517 "Use GetDefaultWindowBrowserCategoryWidth() instead.")
518 static constexpr float GetDefaultPanelBrowserCategoryWidth() {
519 return 260.0f;
520 }
521 static constexpr float GetDefaultWindowBrowserCategoryWidth() {
522 return 260.0f;
523 }
524
525 static constexpr float GetCollapsedSidebarWidth() { return 16.0f; }
526
527 static std::string GetCategoryIcon(const std::string& category);
528
535 float r, g, b, a; // Icon color when active
536 float glow_r, glow_g, glow_b; // Glow/accent color (same hue)
537 };
538 static CategoryTheme GetCategoryTheme(const std::string& category);
539
543 void HandleSidebarKeyboardNav(size_t session_id,
544 const std::vector<WindowDescriptor>& cards);
545
551
559
560 void SetSidebarVisible(bool visible, bool notify = true) {
561 if (browser_state_.sidebar_visible != visible) {
566 }
567 }
568 }
569
571
579
580 YAZE_CARD_SHIM_DEPRECATED("Use SetSidebarExpanded() instead.")
581 void SetPanelExpanded(bool expanded, bool notify = true) {
582 SetSidebarExpanded(expanded, notify);
583 }
584
585 void SetSidebarExpanded(bool expanded, bool notify = true) {
586 if (browser_state_.sidebar_expanded != expanded) {
591 }
592 }
593 }
594
595 YAZE_CARD_SHIM_DEPRECATED("Use IsSidebarExpanded() instead.")
596 bool IsPanelExpanded() const { return IsSidebarExpanded(); }
598
599 // ============================================================================
600 // EventBus Integration
601 // ============================================================================
602
603 void SetEventBus(EventBus* event_bus) { event_bus_ = event_bus; }
604
605 // ============================================================================
606 // Triggers (exposed for ActivityBar) - prefer EventBus, fallback to callbacks
607 // ============================================================================
608
619 YAZE_CARD_SHIM_DEPRECATED("Use TriggerShowWindowBrowser() instead.")
621
633 void TriggerUndo() {
634 if (event_bus_) {
636 }
637 }
638 void TriggerRedo() {
639 if (event_bus_) {
641 }
642 }
687 void TriggerWindowClicked(const std::string& category) {
690 }
691 void TriggerCategorySelected(const std::string& category) {
694 }
695 }
696 void TriggerWindowCategorySelected(const std::string& category) {
697 TriggerCategorySelected(category);
698 }
699
700 // ============================================================================
701 // Utility Icon Callbacks (DEPRECATED: subscribe to UIActionRequestEvent instead)
702 // ============================================================================
703
704 void SetSidebarStateChangedCallback(std::function<void(bool, bool)> cb) {
706 }
707
708 void SetCategoryChangedCallback(std::function<void(const std::string&)> cb) {
709 browser_state_.on_category_changed = std::move(cb);
710 }
711
712 // ============================================================================
713 // Workspace Presets
714 // ============================================================================
715
717 std::string name;
718 std::vector<std::string> visible_cards; // Panel IDs
719 std::string description;
720 };
721
722 void SavePreset(const std::string& name, const std::string& description = "");
723 bool LoadPreset(const std::string& name);
724 void DeletePreset(const std::string& name);
725 std::vector<WorkspacePreset> GetPresets() const;
726
727 // ============================================================================
728 // Panel Validation (for catching ImGui window-name mismatches)
729 // ============================================================================
730
732 std::string card_id;
733 std::string expected_title; // Exact ImGui window name for docking/focus
734 bool found_in_imgui; // Whether ImGui found a window with this title
735 std::string message; // Human-readable status
736 };
737
738 std::vector<WindowValidationResult> ValidateWindows() const;
739 WindowValidationResult ValidateWindow(const std::string& card_id) const;
740
741 // ============================================================================
742 // Quick Actions
743 // ============================================================================
744
745 void ShowAll(size_t session_id);
746 void HideAll(size_t session_id);
747 void ResetToDefaults(size_t session_id);
748 void ResetToDefaults(size_t session_id, EditorType editor_type);
749
750 // ============================================================================
751 // Statistics
752 // ============================================================================
753
754 size_t GetWindowCount() const { return registry_state_.descriptors.size(); }
755 size_t GetVisibleWindowCount(size_t session_id) const;
757
758 // ============================================================================
759 // Session Prefixing Utilities
760 // ============================================================================
761
762 std::string MakeWindowId(size_t session_id, const std::string& base_id) const;
763 std::string MakeWindowId(size_t session_id, const std::string& base_id,
764 WindowScope scope) const;
765 bool ShouldPrefixPanels() const { return session_count_ > 1; }
766
767 // ============================================================================
768 // Convenience Methods (for EditorManager direct usage without session_id)
769 // ============================================================================
770
771 void RegisterPanel(const WindowDescriptor& base_info) {
772 RegisterPanel(active_session_, base_info);
773 }
774 void RegisterWindow(const WindowDescriptor& descriptor) {
775 RegisterPanel(active_session_, descriptor);
776 }
777 void UnregisterPanel(const std::string& base_card_id) {
778 UnregisterPanel(active_session_, base_card_id);
779 }
780 void UnregisterWindow(const std::string& base_window_id) {
781 UnregisterPanel(active_session_, base_window_id);
782 }
783 bool OpenWindow(const std::string& base_window_id) {
784 return OpenWindowImpl(active_session_, base_window_id);
785 }
786 bool OpenWindowFloating(const std::string& base_window_id) {
787 return OpenWindowFloating(active_session_, base_window_id);
788 }
789 bool CloseWindow(const std::string& base_window_id) {
790 return CloseWindowImpl(active_session_, base_window_id);
791 }
792 bool IsWindowOpen(const std::string& base_window_id) const {
793 return IsWindowVisibleImpl(active_session_, base_window_id);
794 }
795 void HideAllWindowsInCategory(const std::string& category) {
797 }
798 std::string GetActiveCategory() const {
800 }
801 void SetActiveCategory(const std::string& category, bool notify = true) {
802 if (browser_state_.active_category != category) {
804 if (notify && browser_state_.on_category_changed) {
806 }
807 }
808 }
809 void ShowAllWindowsInCategory(const std::string& category) {
811 }
812 bool* GetWindowVisibilityFlag(const std::string& base_window_id) {
813 return GetVisibilityFlag(active_session_, base_window_id);
814 }
818 std::function<void(const std::string&)> callback) {
819 browser_state_.on_window_clicked = std::move(callback);
820 }
822 std::function<void(const std::string&)> callback) {
823 browser_state_.on_category_selected = std::move(callback);
824 }
825 void SetEditorResolver(std::function<Editor*(const std::string&)> resolver) {
826 editor_resolver_ = std::move(resolver);
827 }
828
829 size_t GetActiveSessionId() const { return active_session_; }
830
831 // ============================================================================
832 // File Browser Integration
833 // ============================================================================
834
835 FileBrowser* GetFileBrowser(const std::string& category);
836 void EnableFileBrowser(const std::string& category,
837 const std::string& root_path = "");
838 void DisableFileBrowser(const std::string& category);
839 bool HasFileBrowser(const std::string& category) const;
840 void SetFileBrowserPath(const std::string& category, const std::string& path);
842 std::function<void(const std::string& category, const std::string& path)>
843 callback) {
844 on_file_clicked_ = std::move(callback);
845 }
846
847 // ============================================================================
848 // Favorites (delegates to Pinned) and Recent
849 // ============================================================================
850
851 // Favorites are now aliases for pinned panels
852 void ToggleFavorite(const std::string& card_id) {
853 SetWindowPinned(card_id, !IsWindowPinned(card_id));
854 }
855 bool IsFavorite(const std::string& card_id) const {
856 return IsWindowPinned(card_id);
857 }
858
859 void MarkWindowRecentlyUsed(const std::string& window_id) {
861 }
862
863 std::vector<WindowDescriptor> GetWindowsSortedByMRU(
864 size_t session_id, const std::string& category) const {
865 return GetWindowsSortedByMRUImpl(session_id, category);
866 }
867
868 uint64_t GetWindowMRUTime(const std::string& window_id) const {
869 return GetWindowMRUTimeImpl(window_id);
870 }
871
872 // ============================================================================
873 // Pinning (Phase 3 scaffold)
874 // ============================================================================
875
876 void SetWindowPinned(size_t session_id, const std::string& base_window_id,
877 bool pinned) {
878 SetWindowPinnedImpl(session_id, base_window_id, pinned);
879 }
880 bool IsWindowPinned(size_t session_id,
881 const std::string& base_window_id) const {
882 return IsWindowPinnedImpl(session_id, base_window_id);
883 }
884 std::vector<std::string> GetPinnedWindows(size_t session_id) const {
885 return GetPinnedWindowsImpl(session_id);
886 }
887
888 void SetWindowPinned(const std::string& base_window_id, bool pinned) {
889 SetWindowPinnedImpl(base_window_id, pinned);
890 }
891 bool IsWindowPinned(const std::string& base_window_id) const {
892 return IsWindowPinnedImpl(base_window_id);
893 }
894 std::vector<std::string> GetPinnedWindows() const {
895 return GetPinnedWindowsImpl();
896 }
897
898 // ============================================================================
899 // Resource Management (Phase 6)
900 // ============================================================================
901
909 void EnforceResourceLimits(const std::string& resource_type);
910 void EnforceResourceWindowLimits(const std::string& resource_type) {
911 EnforceResourceLimits(resource_type);
912 }
913
918 void MarkPanelUsed(const std::string& panel_id);
919
920 WindowContent* FindPanelInstance(const std::string& prefixed_panel_id,
921 const std::string& base_panel_id);
923 const std::string& prefixed_panel_id,
924 const std::string& base_panel_id) const;
925
926 private:
928 size_t operator()(WindowContextScope scope) const noexcept {
929 return static_cast<size_t>(scope);
930 }
931 };
932
933 void ApplyContextPolicy(size_t session_id, WindowContextScope scope,
934 const std::string& old_key,
935 const std::string& new_key);
936 WindowDescriptor* FindDescriptorByPrefixedId(const std::string& prefixed_id);
938 const std::string& prefixed_id) const;
939 std::vector<std::string>* FindSessionWindowIds(size_t session_id);
940 const std::vector<std::string>* FindSessionWindowIds(size_t session_id) const;
941 std::unordered_map<std::string, std::string>* FindSessionWindowMapping(
942 size_t session_id);
943 const std::unordered_map<std::string, std::string>* FindSessionWindowMapping(
944 size_t session_id) const;
945 std::unordered_map<std::string, std::string>* FindSessionReverseWindowMapping(
946 size_t session_id);
947 const std::unordered_map<std::string, std::string>*
948 FindSessionReverseWindowMapping(size_t session_id) const;
949 void PublishWindowVisibilityChanged(size_t session_id,
950 const std::string& prefixed_window_id,
951 const std::string& base_window_id,
952 const std::string& category,
953 bool visible) const;
954 bool OpenWindowImpl(size_t session_id, const std::string& base_card_id);
955 bool CloseWindowImpl(size_t session_id, const std::string& base_card_id);
956 bool ToggleWindowImpl(size_t session_id, const std::string& base_card_id);
957 bool IsWindowVisibleImpl(size_t session_id,
958 const std::string& base_card_id) const;
959 bool* GetVisibilityFlag(size_t session_id, const std::string& base_card_id);
960 std::vector<std::string> GetWindowsInSessionImpl(size_t session_id) const;
961 std::vector<WindowDescriptor> GetWindowsInCategoryImpl(
962 size_t session_id, const std::string& category) const;
963 std::vector<std::string> GetVisibleWindowIdsImpl(size_t session_id) const;
964 void SetVisibleWindowsImpl(size_t session_id,
965 const std::vector<std::string>& panel_ids);
967 size_t session_id, const std::string& base_card_id) const;
968 std::string GetWindowNameImpl(size_t session_id,
969 const std::string& base_card_id) const;
970 std::string GetWindowNameImpl(const WindowDescriptor& descriptor) const;
971 void MarkWindowRecentlyUsedImpl(const std::string& card_id);
972 std::vector<WindowDescriptor> GetWindowsSortedByMRUImpl(
973 size_t session_id, const std::string& category) const;
974 uint64_t GetWindowMRUTimeImpl(const std::string& card_id) const {
975 auto iter = last_used_at_.find(card_id);
976 return (iter != last_used_at_.end()) ? iter->second : 0;
977 }
978 void SetWindowPinnedImpl(size_t session_id, const std::string& base_card_id,
979 bool pinned);
980 bool IsWindowPinnedImpl(size_t session_id,
981 const std::string& base_card_id) const;
982 std::vector<std::string> GetPinnedWindowsImpl(size_t session_id) const;
983 void RememberPinnedStateForRemovedWindow(size_t session_id,
984 const std::string& base_card_id,
985 const std::string& prefixed_id);
986 void SetWindowPinnedImpl(const std::string& base_card_id, bool pinned);
987 bool IsWindowPinnedImpl(const std::string& base_card_id) const;
988 std::vector<std::string> GetPinnedWindowsImpl() const;
989 size_t GetResourceWindowLimit(const std::string& resource_type) const;
990 void TrackResourceWindow(const std::string& panel_id,
991 ResourceWindowContent* resource_panel);
992 void UntrackResourceWindow(const std::string& panel_id);
994 const std::list<std::string>& panel_ids) const;
995 std::string ResolveBaseWindowId(const std::string& panel_id) const;
996 std::string GetBaseIdForPrefixedId(size_t session_id,
997 const std::string& prefixed_id) const;
998
999 // ... existing private members ...
1000
1002 std::unordered_map<std::string, std::list<std::string>> window_ids_by_type;
1003 std::unordered_map<std::string, std::string> window_type_by_id;
1004 };
1005
1007
1008 std::unordered_map<std::string, std::list<std::string>>& resource_panels_ =
1010 std::unordered_map<std::string, std::string>& panel_resource_types_ =
1012
1014 std::unordered_map<std::string, WindowDescriptor> descriptors;
1015 std::unordered_map<std::string, std::unique_ptr<WindowContent>> instances;
1016 std::unordered_set<std::string> registry_ids;
1017 std::unordered_set<std::string> global_ids;
1018 std::unordered_map<std::string, bool> centralized_visibility;
1019 std::unordered_map<std::string, std::string> aliases;
1020 };
1021
1023 std::unordered_map<std::string, uint64_t> last_used_at;
1024 uint64_t mru_counter = 0;
1025 std::unordered_map<std::string, bool> pinned_windows;
1026 // Base-id → pinned entries restored before the matching panel registered.
1027 // Consumed by TrackPanelForSession when late-registering panels arrive.
1028 // Also included in SerializePinnedState so pins survive a restart even
1029 // when the user never actually opened the panel in the prior session.
1030 std::unordered_map<std::string, bool> pending_pinned_base_ids;
1031 std::unordered_set<std::string> pending_float_window_ids;
1032 size_t session_count = 0;
1033 size_t active_session = 0;
1034 std::unordered_map<size_t, std::vector<std::string>> session_windows;
1035 std::unordered_map<size_t, std::unordered_map<std::string, std::string>>
1037 std::unordered_map<size_t, std::unordered_map<std::string, std::string>>
1039 std::unordered_map<size_t,
1040 std::unordered_map<WindowContextScope, std::string,
1043 };
1044
1047
1048 // Legacy field aliases kept during the panel->window migration while methods
1049 // are gradually moved over to the grouped state containers above.
1050 std::unordered_map<std::string, WindowDescriptor>& cards_ =
1052 std::unordered_map<std::string, std::unique_ptr<WindowContent>>&
1054 std::unordered_set<std::string>& registry_panel_ids_ =
1056 std::unordered_set<std::string>& global_panel_ids_ =
1058 std::unordered_map<std::string, bool>& centralized_visibility_ =
1060 std::unordered_map<std::string, std::string>& panel_id_aliases_ =
1062
1063 std::unordered_map<std::string, uint64_t>& last_used_at_ =
1066 std::unordered_map<std::string, bool>& pinned_panels_ =
1068 std::unordered_map<std::string, bool>& pending_pinned_base_ids_ =
1070 std::unordered_set<std::string>& pending_float_window_ids_ =
1074 std::unordered_map<size_t, std::vector<std::string>>& session_cards_ =
1076 std::unordered_map<size_t, std::unordered_map<std::string, std::string>>&
1078 std::unordered_map<size_t, std::unordered_map<std::string, std::string>>&
1081 std::unordered_map<size_t, std::unordered_map<WindowContextScope, std::string,
1084
1085 // Workspace presets
1086 std::unordered_map<std::string, WorkspacePreset> presets_;
1087
1089 static constexpr size_t kMaxRecentCategories = 5;
1090
1091 std::string active_category;
1092 std::vector<std::string> recent_categories;
1093 bool sidebar_visible = false;
1094 bool sidebar_expanded = false;
1095 float sidebar_width = 0.0f;
1096 float window_browser_category_width = GetDefaultPanelBrowserCategoryWidth();
1098 bool sidebar_has_focus = false;
1099 std::function<void(bool visible, bool expanded)> on_sidebar_state_changed;
1100 std::function<void(float width)> on_sidebar_width_changed;
1101 std::function<void(float width)> on_window_browser_width_changed;
1102 std::function<void(const std::string&)> on_category_changed;
1103 std::function<void(const std::string&)> on_window_clicked;
1104 std::function<void(const std::string&)> on_category_selected;
1105 std::unordered_map<std::string, std::unique_ptr<FileBrowser>>
1107 };
1108
1110
1111 // EventBus for action events (preferred over callbacks)
1113
1114 // State change callbacks
1115 std::function<void(const std::string&, const std::string&)> on_file_clicked_;
1116 std::function<Editor*(const std::string&)> editor_resolver_;
1117
1118 // Helper methods
1119 void UpdateSessionCount();
1120 std::string GetPrefixedWindowId(size_t session_id,
1121 const std::string& base_id) const;
1122 void RegisterPanelDescriptorForSession(size_t session_id,
1123 const WindowContent& panel);
1124 void TrackPanelForSession(size_t session_id, const std::string& base_id,
1125 const std::string& panel_id);
1126 void UnregisterSessionPanels(size_t session_id);
1127 void SavePresetsToFile();
1128 void LoadPresetsFromFile();
1129};
1130
1131} // namespace editor
1132} // namespace yaze
1133
1134#undef YAZE_CARD_SHIM_DEPRECATED
1135
1136#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:249
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)
Handle editor/category switching for panel visibility.
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)