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_AUTOMATION_WIDGET_ID_REGISTRY_H_
2#define YAZE_APP_GUI_AUTOMATION_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, const std::string& description = "",
111 const WidgetMetadata& metadata = WidgetMetadata());
112
113 // Query widgets for test automation
114 std::vector<std::string> FindWidgets(const std::string& pattern) const;
115 ImGuiID GetWidgetId(const std::string& full_path) const;
116 const WidgetInfo* GetWidgetInfo(const std::string& full_path) const;
117
118 // Get all registered widgets
119 const std::unordered_map<std::string, WidgetInfo>& GetAllWidgets() const {
120 return widgets_;
121 }
122
123 // Clear all registered widgets (useful between frames for dynamic UIs)
124 void Clear();
125
126 // Export catalog for z3ed agent describe
127 // Format: "yaml" or "json"
128 std::string ExportCatalog(const std::string& format = "yaml") const;
129 void ExportCatalogToFile(const std::string& output_file,
130 const std::string& format = "yaml") const;
131
132 // Helper utilities for consistent naming
133 static std::string NormalizeLabel(absl::string_view label);
134 static std::string NormalizePathSegment(absl::string_view segment);
135
136 private:
137 WidgetIdRegistry() = default;
138 void TrimStaleEntries();
139 bool ShouldPrune(const WidgetInfo& info) const;
140
141 std::unordered_map<std::string, WidgetInfo> widgets_;
143 absl::Time frame_time_;
144 int stale_frame_limit_ = 600; // frames before pruning a widget
145};
146
147// RAII helper macros for convenient scoping
148#define YAZE_WIDGET_SCOPE(name) \
149 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_AUTOMATION_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.
WidgetIdScope(const std::string &name)
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