yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
widget_id_registry.h
Go to the documentation of this file.
1#ifndef YAZE_APP_GUI_WIDGETS_WIDGET_ID_REGISTRY_H_
2#define YAZE_APP_GUI_WIDGETS_WIDGET_ID_REGISTRY_H_
3
4#include <cstdint>
5#include <optional>
6#include <string>
7#include <unordered_map>
8#include <vector>
9
10#include "absl/strings/string_view.h"
11#include "absl/time/time.h"
12#include "imgui/imgui.h"
13
14namespace yaze {
15namespace gui {
16
37 public:
38 explicit WidgetIdScope(const std::string& name);
40
41 // Get the full hierarchical path at this scope level
42 std::string GetFullPath() const;
43
44 // Get the full path with a widget suffix
45 std::string GetWidgetPath(const std::string& widget_type,
46 const std::string& widget_name) const;
47
48 private:
49 std::string name_;
50 static thread_local std::vector<std::string> id_stack_;
51};
52
68 public:
69 struct WidgetBounds {
70 float min_x = 0.0f;
71 float min_y = 0.0f;
72 float max_x = 0.0f;
73 float max_y = 0.0f;
74 bool valid = false;
75 };
76
78 std::optional<std::string> label;
79 std::optional<std::string> window_name;
80 std::optional<bool> visible;
81 std::optional<bool> enabled;
82 std::optional<WidgetBounds> bounds;
83 };
84
85 struct WidgetInfo {
86 std::string full_path; // e.g. "Overworld/Canvas/canvas:Map"
87 std::string type; // e.g. "button", "input", "canvas", "table"
88 ImGuiID imgui_id; // ImGui's internal ID
89 std::string description; // Optional human-readable description
90 std::string label; // Sanitized display label (without IDs/icons)
91 std::string window_name; // Window this widget was last seen in
92 bool visible = true; // Visibility in the most recent frame
93 bool enabled = true; // Enabled state in the most recent frame
94 WidgetBounds bounds; // Bounding box in screen space
96 absl::Time last_seen_time;
99 };
100
101 static WidgetIdRegistry& Instance();
102
103 // Frame lifecycle - call once per ImGui frame
104 void BeginFrame();
105 void EndFrame();
106
107 // Register a widget for discovery
108 // Should be called after widget is created (when ImGui::GetItemID() is valid)
109 void RegisterWidget(const std::string& full_path, const std::string& type,
110 ImGuiID imgui_id,
111 const std::string& description = "",
112 const WidgetMetadata& metadata = WidgetMetadata());
113
114 // Query widgets for test automation
115 std::vector<std::string> FindWidgets(const std::string& pattern) const;
116 ImGuiID GetWidgetId(const std::string& full_path) const;
117 const WidgetInfo* GetWidgetInfo(const std::string& full_path) const;
118
119 // Get all registered widgets
120 const std::unordered_map<std::string, WidgetInfo>& GetAllWidgets() const {
121 return widgets_;
122 }
123
124 // Clear all registered widgets (useful between frames for dynamic UIs)
125 void Clear();
126
127 // Export catalog for z3ed agent describe
128 // Format: "yaml" or "json"
129 std::string ExportCatalog(const std::string& format = "yaml") const;
130 void ExportCatalogToFile(const std::string& output_file,
131 const std::string& format = "yaml") const;
132
133 // Helper utilities for consistent naming
134 static std::string NormalizeLabel(absl::string_view label);
135 static std::string NormalizePathSegment(absl::string_view segment);
136
137 private:
138 WidgetIdRegistry() = default;
139 void TrimStaleEntries();
140 bool ShouldPrune(const WidgetInfo& info) const;
141
142 std::unordered_map<std::string, WidgetInfo> widgets_;
144 absl::Time frame_time_;
145 int stale_frame_limit_ = 600; // frames before pruning a widget
146};
147
148// RAII helper macros for convenient scoping
149#define YAZE_WIDGET_SCOPE(name) yaze::gui::WidgetIdScope _yaze_scope_##__LINE__(name)
150
151// Register a widget after creation (when GetItemID() is valid)
152#define YAZE_REGISTER_WIDGET(widget_type, widget_name) \
153 do { \
154 if (ImGui::GetItemID() != 0) { \
155 yaze::gui::WidgetIdRegistry::Instance().RegisterWidget( \
156 _yaze_scope_##__LINE__.GetWidgetPath(#widget_type, widget_name), \
157 #widget_type, ImGui::GetItemID()); \
158 } \
159 } while (0)
160
161// Convenience macro for registering with automatic name extraction
162// Usage: YAZE_REGISTER_CURRENT_WIDGET("button")
163#define YAZE_REGISTER_CURRENT_WIDGET(widget_type) \
164 do { \
165 if (ImGui::GetItemID() != 0) { \
166 yaze::gui::WidgetIdRegistry::Instance().RegisterWidget( \
167 _yaze_scope_##__LINE__.GetWidgetPath(widget_type, \
168 ImGui::GetLastItemLabel()), \
169 widget_type, ImGui::GetItemID()); \
170 } \
171 } while (0)
172
173} // namespace gui
174} // namespace yaze
175
176#endif // YAZE_APP_GUI_WIDGETS_WIDGET_ID_REGISTRY_H_
Centralized registry for discoverable GUI widgets.
std::unordered_map< std::string, WidgetInfo > widgets_
void ExportCatalogToFile(const std::string &output_file, const std::string &format="yaml") const
static std::string NormalizePathSegment(absl::string_view segment)
std::string ExportCatalog(const std::string &format="yaml") const
bool ShouldPrune(const WidgetInfo &info) const
const WidgetInfo * GetWidgetInfo(const std::string &full_path) const
ImGuiID GetWidgetId(const std::string &full_path) const
static std::string NormalizeLabel(absl::string_view label)
const std::unordered_map< std::string, WidgetInfo > & GetAllWidgets() const
void RegisterWidget(const std::string &full_path, const std::string &type, ImGuiID imgui_id, const std::string &description="", const WidgetMetadata &metadata=WidgetMetadata())
static WidgetIdRegistry & Instance()
std::vector< std::string > FindWidgets(const std::string &pattern) const
RAII helper for managing hierarchical ImGui ID scopes.
std::string GetFullPath() const
static thread_local std::vector< std::string > id_stack_
std::string GetWidgetPath(const std::string &widget_type, const std::string &widget_name) const
Main namespace for the application.