yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
annotation_overlay_panel.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_HACK_ORACLE_UI_ANNOTATION_OVERLAY_PANEL_H
2#define YAZE_APP_EDITOR_HACK_ORACLE_UI_ANNOTATION_OVERLAY_PANEL_H
3
4#include <algorithm>
5#include <cstdio>
6#include <filesystem>
7#include <fstream>
8#include <string>
9#include <vector>
10
13#include "app/gui/core/icons.h"
14#include "core/project.h"
15#include "imgui/imgui.h"
16#include "nlohmann/json.hpp"
17
18namespace yaze::editor {
19
23enum class AnnotationPriority : int {
24 kNote = 0,
25 kBug = 1,
26 kBlocker = 2,
27};
28
33 int room_id = 0;
34 std::string text;
36 std::string category; // "design", "test", "bug", etc.
37 std::string created_at;
38};
39
54 public:
55 std::string GetId() const override { return "oracle.annotations"; }
56 std::string GetDisplayName() const override { return "Annotations"; }
57 std::string GetIcon() const override { return ICON_MD_NOTES; }
58 std::string GetEditorCategory() const override { return "Agent"; }
59 std::string GetWorkflowGroup() const override { return "Planning"; }
60 std::string GetWorkflowDescription() const override {
61 return "Review and edit room-level project annotations";
62 }
66
67 void SetAnnotationsPath(const std::string& path) {
68 annotations_path_ = path;
70 }
71
72 void Draw(bool* /*p_open*/) override {
73 // Lazily discover annotations path from project context
74 if (annotations_path_.empty()) {
75 if (auto* project = ContentRegistry::Context::current_project()) {
76 if (!project->code_folder.empty()) {
77 namespace fs = std::filesystem;
78 fs::path candidate =
79 fs::path(project->GetAbsolutePath(project->code_folder)) /
80 "Docs" / "Dev" / "Planning" / "annotations.json";
81 SetAnnotationsPath(candidate.string());
82 }
83 }
84 }
85
86 // Filter controls
87 ImGui::Text("Room filter:");
88 ImGui::SameLine();
89 ImGui::InputInt("##room_filter", &filter_room_id_);
90 ImGui::SameLine();
91 if (ImGui::Button("All"))
92 filter_room_id_ = -1;
93
94 ImGui::SameLine();
95 const char* priorities[] = {"All", "Note", "Bug", "Blocker"};
96 ImGui::Combo("Priority", &filter_priority_, priorities, 4);
97
98 ImGui::Separator();
99
100 // Annotation list
101 ImGui::BeginChild("annotation_list", ImVec2(0, -120),
102 ImGuiChildFlags_Borders);
103
104 for (size_t i = 0; i < annotations_.size(); ++i) {
105 const auto& ann = annotations_[i];
106
107 // Apply filters
108 if (filter_room_id_ >= 0 && ann.room_id != filter_room_id_)
109 continue;
110 if (filter_priority_ > 0 &&
111 static_cast<int>(ann.priority) != (filter_priority_ - 1))
112 continue;
113
114 ImU32 dot_color = GetPriorityColor(ann.priority);
115 ImVec2 cursor = ImGui::GetCursorScreenPos();
116 ImGui::GetWindowDrawList()->AddCircleFilled(
117 ImVec2(cursor.x + 6, cursor.y + 10), 5.0f, dot_color);
118 ImGui::Dummy(ImVec2(16, 0));
119 ImGui::SameLine();
120
121 char label[128];
122 snprintf(label, sizeof(label), "Room 0x%02X: %s##ann_%zu", ann.room_id,
123 ann.text.c_str(), i);
124
125 if (ImGui::Selectable(label, selected_index_ == static_cast<int>(i))) {
126 selected_index_ = static_cast<int>(i);
127 // Copy to edit buffer
128 edit_room_ = ann.room_id;
129 snprintf(edit_text_, sizeof(edit_text_), "%s", ann.text.c_str());
130 edit_priority_ = static_cast<int>(ann.priority);
131 snprintf(edit_category_, sizeof(edit_category_), "%s",
132 ann.category.c_str());
133 }
134 }
135
136 ImGui::EndChild();
137
138 ImGui::Separator();
139
140 // Edit / Add form
141 ImGui::Text("Room:");
142 ImGui::SameLine();
143 ImGui::SetNextItemWidth(80);
144 ImGui::InputInt("##edit_room", &edit_room_);
145
146 ImGui::SameLine();
147 ImGui::Text("Priority:");
148 ImGui::SameLine();
149 ImGui::SetNextItemWidth(80);
150 const char* pri_names[] = {"Note", "Bug", "Blocker"};
151 ImGui::Combo("##edit_priority", &edit_priority_, pri_names, 3);
152
153 ImGui::InputText("Text", edit_text_, sizeof(edit_text_));
154 ImGui::InputText("Category", edit_category_, sizeof(edit_category_));
155
156 if (ImGui::Button("Add")) {
157 AnnotationEntry entry;
158 entry.room_id = edit_room_;
159 entry.text = edit_text_;
160 entry.priority = static_cast<AnnotationPriority>(edit_priority_);
161 entry.category = edit_category_;
162 annotations_.push_back(entry);
164 }
165
166 ImGui::SameLine();
167 if (selected_index_ >= 0 &&
168 selected_index_ < static_cast<int>(annotations_.size())) {
169 if (ImGui::Button("Update")) {
170 auto& ann = annotations_[selected_index_];
171 ann.room_id = edit_room_;
172 ann.text = edit_text_;
173 ann.priority = static_cast<AnnotationPriority>(edit_priority_);
174 ann.category = edit_category_;
176 }
177 ImGui::SameLine();
178 if (ImGui::Button("Delete")) {
180 selected_index_ = -1;
182 }
183 }
184 }
185
186 // ─── Public API for DungeonMapPanel integration ───────────────
187
191 std::vector<const AnnotationEntry*> GetAnnotationsForRoom(int room_id) const {
192 std::vector<const AnnotationEntry*> result;
193 for (const auto& ann : annotations_) {
194 if (ann.room_id == room_id) {
195 result.push_back(&ann);
196 }
197 }
198 return result;
199 }
200
205 int GetMaxPriorityForRoom(int room_id) const {
206 int max_pri = -1;
207 for (const auto& ann : annotations_) {
208 if (ann.room_id == room_id) {
209 max_pri = std::max(max_pri, static_cast<int>(ann.priority));
210 }
211 }
212 return max_pri;
213 }
214
215 static ImU32 GetPriorityColor(AnnotationPriority priority) {
216 switch (priority) {
218 return IM_COL32(220, 50, 50, 255); // Red
220 return IM_COL32(220, 150, 30, 255); // Orange
222 default:
223 return IM_COL32(60, 120, 220, 255); // Blue
224 }
225 }
226
227 private:
229 annotations_.clear();
230 if (annotations_path_.empty())
231 return;
232
233 std::ifstream file(annotations_path_);
234 if (!file.is_open())
235 return;
236
237 try {
238 nlohmann::json root;
239 file >> root;
240
241 if (root.contains("annotations") && root["annotations"].is_array()) {
242 for (const auto& item : root["annotations"]) {
243 AnnotationEntry entry;
244 entry.room_id = item.value("room_id", 0);
245 entry.text = item.value("text", "");
246 entry.priority =
247 static_cast<AnnotationPriority>(item.value("priority", 0));
248 entry.category = item.value("category", "");
249 entry.created_at = item.value("created_at", "");
250 annotations_.push_back(std::move(entry));
251 }
252 }
253 } catch (...) {
254 // Silently ignore parse errors
255 }
256 }
257
259 if (annotations_path_.empty())
260 return;
261
262 nlohmann::json root;
263 nlohmann::json arr = nlohmann::json::array();
264
265 for (const auto& ann : annotations_) {
266 nlohmann::json item;
267 item["room_id"] = ann.room_id;
268 item["text"] = ann.text;
269 item["priority"] = static_cast<int>(ann.priority);
270 item["category"] = ann.category;
271 item["created_at"] = ann.created_at;
272 arr.push_back(item);
273 }
274
275 root["annotations"] = arr;
276
277 std::ofstream file(annotations_path_);
278 if (file.is_open()) {
279 file << root.dump(2) << std::endl;
280 }
281 }
282
283 std::string annotations_path_;
284 std::vector<AnnotationEntry> annotations_;
285
286 // Filter state
289
290 // Edit state
292 int edit_room_ = 0;
293 char edit_text_[256] = {0};
295 char edit_category_[64] = {0};
296};
297
298} // namespace yaze::editor
299
300#endif // YAZE_APP_EDITOR_HACK_ORACLE_UI_ANNOTATION_OVERLAY_PANEL_H
Room-level annotation management for Oracle projects.
void SetAnnotationsPath(const std::string &path)
void Draw(bool *) override
Draw the panel content.
WindowLifecycle GetWindowLifecycle() const override
Get the lifecycle category for this window.
std::string GetWorkflowGroup() const override
Optional workflow group for hack-centric actions.
std::vector< const AnnotationEntry * > GetAnnotationsForRoom(int room_id) const
Get annotations for a specific room.
int GetMaxPriorityForRoom(int room_id) const
Get the highest priority for a room (for dot color). Returns -1 if no annotations.
std::string GetWorkflowDescription() const override
Optional workflow description for menus/command palette.
std::string GetEditorCategory() const override
Editor category this panel belongs to.
std::vector< AnnotationEntry > annotations_
static ImU32 GetPriorityColor(AnnotationPriority priority)
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
std::string GetId() const override
Unique identifier for this panel.
std::string GetIcon() const override
Material Design icon for this panel.
Base interface for all logical window content components.
#define ICON_MD_NOTES
Definition icons.h:1332
::yaze::project::YazeProject * current_project()
Get the current project instance.
Editors are the view controllers for the application.
AnnotationPriority
Annotation priority levels.
WindowLifecycle
Defines lifecycle behavior for editor windows.
@ CrossEditor
User can pin to persist across editors.
A room-level annotation entry.