yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
menu_inspector_panel.cc
Go to the documentation of this file.
2
3#include <filesystem>
4
5#include "absl/strings/ascii.h"
6#include "absl/strings/str_format.h"
10#include "core/project.h"
11
12namespace yaze::editor {
13
14namespace {
15
17 if (auto* project = ContentRegistry::Context::current_project()) {
18 if (!project->code_folder.empty()) {
19 return project->GetAbsolutePath(project->code_folder);
20 }
21 if (!project->filepath.empty()) {
22 return std::filesystem::path(project->filepath).parent_path().string();
23 }
24 }
25 return std::filesystem::current_path().string();
26}
27
28} // namespace
29
31 if (project_path_.empty()) {
32 project_path_ = DetermineInitialProjectPath();
33 }
34
35 if (!attempted_initial_load_ && !project_path_.empty()) {
38 }
39}
40
43 if (!registry_or.ok()) {
44 has_registry_ = false;
45 last_error_ = std::string(registry_or.status().message());
46 status_message_.clear();
49 return;
50 }
51
52 registry_ = std::move(registry_or.value());
53 has_registry_ = true;
54 last_error_.clear();
55 status_message_ = absl::StrFormat(
56 "Loaded %zu asm files, %zu bins, %zu draw routines, %zu components.",
57 registry_.asm_files.size(), registry_.bins.size(),
59
62}
63
64bool OracleMenuInspectorPanel::MatchesFilter(const std::string& value,
65 const std::string& filter) const {
66 if (filter.empty()) {
67 return true;
68 }
69 const std::string value_lower = absl::AsciiStrToLower(value);
70 const std::string filter_lower = absl::AsciiStrToLower(filter);
71 return value_lower.find(filter_lower) != std::string::npos;
72}
73
75 ImGui::InputText("Project Root", &project_path_);
76 ImGui::SameLine();
77 if (ImGui::Button("Auto Detect")) {
78 project_path_ = DetermineInitialProjectPath();
79 }
80 ImGui::SameLine();
81 if (ImGui::Button("Refresh")) {
83 }
84}
85
87 if (!has_registry_) {
88 return;
89 }
90 ImGui::TextDisabled(
91 "ASM: %zu Bins: %zu Draw: %zu Components: %zu Warnings: %zu",
92 registry_.asm_files.size(), registry_.bins.size(),
94 registry_.warnings.size());
95}
96
98 const auto& theme = AgentUI::GetTheme();
99 ImGui::Checkbox("Missing bins only", &bins_missing_only_);
100
101 if (ImGui::BeginTable("oracle_menu_bins_table", 6,
102 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
103 ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY,
104 ImVec2(0, 320))) {
105 ImGui::TableSetupColumn("Label");
106 ImGui::TableSetupColumn("Bin Path");
107 ImGui::TableSetupColumn("Bytes", ImGuiTableColumnFlags_WidthFixed, 70.0f);
108 ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 70.0f);
109 ImGui::TableSetupColumn("ASM");
110 ImGui::TableSetupColumn("Line", ImGuiTableColumnFlags_WidthFixed, 55.0f);
111 ImGui::TableHeadersRow();
112
113 for (const auto& entry : registry_.bins) {
114 if (bins_missing_only_ && entry.exists) {
115 continue;
116 }
117
118 ImGui::TableNextRow();
119 ImGui::TableSetColumnIndex(0);
120 ImGui::TextUnformatted(entry.label.empty() ? "(unlabeled)"
121 : entry.label.c_str());
122 ImGui::TableSetColumnIndex(1);
123 ImGui::TextUnformatted(entry.resolved_bin_path.c_str());
124 ImGui::TableSetColumnIndex(2);
125 ImGui::Text("%llu", static_cast<unsigned long long>(entry.size_bytes));
126 ImGui::TableSetColumnIndex(3);
127 ImGui::TextColored(
128 entry.exists ? theme.status_success : theme.status_error, "%s",
129 entry.exists ? "OK" : "MISSING");
130 ImGui::TableSetColumnIndex(4);
131 ImGui::TextUnformatted(entry.asm_path.c_str());
132 ImGui::TableSetColumnIndex(5);
133 ImGui::Text("%d", entry.line);
134 }
135
136 ImGui::EndTable();
137 }
138}
139
141 ImGui::InputText("Filter", &draw_filter_);
142
143 if (ImGui::BeginTable("oracle_menu_draw_table", 5,
144 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
145 ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY,
146 ImVec2(0, 320))) {
147 ImGui::TableSetupColumn("Routine");
148 ImGui::TableSetupColumn("ASM");
149 ImGui::TableSetupColumn("Line", ImGuiTableColumnFlags_WidthFixed, 55.0f);
150 ImGui::TableSetupColumn("Refs", ImGuiTableColumnFlags_WidthFixed, 50.0f);
151 ImGui::TableSetupColumn("Kind", ImGuiTableColumnFlags_WidthFixed, 60.0f);
152 ImGui::TableHeadersRow();
153
154 for (const auto& routine : registry_.draw_routines) {
155 if (!MatchesFilter(routine.label, draw_filter_)) {
156 continue;
157 }
158
159 ImGui::TableNextRow();
160 ImGui::TableSetColumnIndex(0);
161 ImGui::TextUnformatted(routine.label.c_str());
162 ImGui::TableSetColumnIndex(1);
163 ImGui::TextUnformatted(routine.asm_path.c_str());
164 ImGui::TableSetColumnIndex(2);
165 ImGui::Text("%d", routine.line);
166 ImGui::TableSetColumnIndex(3);
167 ImGui::Text("%d", routine.references);
168 ImGui::TableSetColumnIndex(4);
169 ImGui::TextUnformatted(routine.local ? "local" : "global");
170 }
171
172 ImGui::EndTable();
173 }
174}
175
177 ImGui::InputText("Table Filter", &component_table_filter_);
178
179 filtered_components_.clear();
181 for (const auto& component : registry_.components) {
182 if (!MatchesFilter(component.table_label, component_table_filter_)) {
183 continue;
184 }
185 filtered_components_.push_back(&component);
186 }
187
189 static_cast<int>(filtered_components_.size())) {
191 }
192
193 const float left_width = ImGui::GetContentRegionAvail().x * 0.58f;
194 ImGui::BeginChild("oracle_menu_components_list", ImVec2(left_width, 340.0f),
195 ImGuiChildFlags_Borders);
196 if (ImGui::BeginTable("oracle_menu_components_table", 5,
197 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
198 ImGuiTableFlags_Resizable |
199 ImGuiTableFlags_ScrollY)) {
200 ImGui::TableSetupColumn("Table");
201 ImGui::TableSetupColumn("Index", ImGuiTableColumnFlags_WidthFixed, 55.0f);
202 ImGui::TableSetupColumn("Row", ImGuiTableColumnFlags_WidthFixed, 50.0f);
203 ImGui::TableSetupColumn("Col", ImGuiTableColumnFlags_WidthFixed, 50.0f);
204 ImGui::TableSetupColumn("Ref");
205 ImGui::TableHeadersRow();
206
207 for (int i = 0; i < static_cast<int>(filtered_components_.size()); ++i) {
208 const auto* component = filtered_components_[i];
209 ImGui::TableNextRow();
210
211 ImGui::TableSetColumnIndex(0);
212 const bool selected = (selected_component_list_index_ == i);
213 std::string row_label =
214 absl::StrFormat("%s##oracle_component_%d", component->table_label, i);
215 if (ImGui::Selectable(row_label.c_str(), selected,
216 ImGuiSelectableFlags_SpanAllColumns)) {
218 edit_row_ = component->row;
219 edit_col_ = component->col;
220 }
221
222 ImGui::TableSetColumnIndex(1);
223 ImGui::Text("%d", component->index);
224 ImGui::TableSetColumnIndex(2);
225 ImGui::Text("%d", component->row);
226 ImGui::TableSetColumnIndex(3);
227 ImGui::Text("%d", component->col);
228 ImGui::TableSetColumnIndex(4);
229 ImGui::Text("%s:%d", component->asm_path.c_str(), component->line);
230 }
231
232 ImGui::EndTable();
233 }
234 ImGui::EndChild();
235
236 ImGui::SameLine();
237 ImGui::BeginChild("oracle_menu_component_editor", ImVec2(0, 340.0f),
238 ImGuiChildFlags_Borders);
241 static_cast<int>(filtered_components_.size())) {
242 ImGui::TextDisabled("Select a component row to preview/apply edits.");
243 ImGui::EndChild();
244 return;
245 }
246
248 ImGui::Text("Table: %s", component->table_label.c_str());
249 ImGui::Text("Index: %d", component->index);
250 ImGui::Text("ASM: %s:%d", component->asm_path.c_str(), component->line);
251 if (!component->note.empty()) {
252 ImGui::TextDisabled("Note: %s", component->note.c_str());
253 }
254 ImGui::Separator();
255
256 ImGui::InputInt("Row", &edit_row_);
257 ImGui::InputInt("Col", &edit_col_);
258 if (edit_row_ < 0) {
259 edit_row_ = 0;
260 }
261 if (edit_col_ < 0) {
262 edit_col_ = 0;
263 }
264
265 if (ImGui::Button("Preview")) {
267 registry_.project_root, component->asm_path, component->table_label,
268 component->index, edit_row_, edit_col_, false);
269 if (!edit_or.ok()) {
271 absl::StrFormat("Preview failed: %s", edit_or.status().message());
272 } else {
273 const auto& edit = edit_or.value();
274 status_message_ = absl::StrFormat(
275 "Preview %s[%d] (%d,%d) -> (%d,%d)", edit.table_label, edit.index,
276 edit.old_row, edit.old_col, edit.new_row, edit.new_col);
277 }
278 }
279 ImGui::SameLine();
280 if (ImGui::Button("Apply")) {
282 registry_.project_root, component->asm_path, component->table_label,
283 component->index, edit_row_, edit_col_, true);
284 if (!edit_or.ok()) {
286 absl::StrFormat("Apply failed: %s", edit_or.status().message());
287 } else {
288 const auto& edit = edit_or.value();
289 status_message_ = absl::StrFormat(
290 "Applied %s[%d] (%d,%d) -> (%d,%d)", edit.table_label, edit.index,
291 edit.old_row, edit.old_col, edit.new_row, edit.new_col);
293 }
294 }
295
296 ImGui::EndChild();
297}
298
299void OracleMenuInspectorPanel::Draw(bool* /*p_open*/) {
300 const auto& theme = AgentUI::GetTheme();
302 DrawToolbar();
303
304 if (!last_error_.empty()) {
305 ImGui::TextColored(theme.status_error, "%s", last_error_.c_str());
306 return;
307 }
308
309 if (!status_message_.empty()) {
310 ImGui::TextDisabled("%s", status_message_.c_str());
311 }
312 DrawSummary();
313
314 if (!has_registry_) {
315 ImGui::TextDisabled("No menu registry data loaded.");
316 return;
317 }
318
319 if (gui::BeginThemedTabBar("oracle_menu_tabs")) {
320 if (ImGui::BeginTabItem("Bins")) {
321 DrawBinsTab();
322 ImGui::EndTabItem();
323 }
324 if (ImGui::BeginTabItem("Draw Routines")) {
326 ImGui::EndTabItem();
327 }
328 if (ImGui::BeginTabItem("Components")) {
330 ImGui::EndTabItem();
331 }
332 if (ImGui::BeginTabItem("Warnings")) {
333 if (registry_.warnings.empty()) {
334 ImGui::TextDisabled("No warnings.");
335 } else {
336 for (const auto& warning : registry_.warnings) {
337 ImGui::BulletText("%s", warning.c_str());
338 }
339 }
340 ImGui::EndTabItem();
341 }
343 }
344}
345
347
348} // namespace yaze::editor
void Draw(bool *p_open) override
Draw the panel content.
std::vector< const core::OracleMenuComponent * > filtered_components_
bool MatchesFilter(const std::string &value, const std::string &filter) const
absl::StatusOr< OracleMenuRegistry > BuildOracleMenuRegistry(const std::filesystem::path &project_root)
absl::StatusOr< OracleMenuComponentEditResult > SetOracleMenuComponentOffset(const std::filesystem::path &project_root, const std::string &asm_relative_path, const std::string &table_label, int index, int row, int col, bool write_changes)
const AgentUITheme & GetTheme()
::yaze::project::YazeProject * current_project()
Get the current project instance.
Editors are the view controllers for the application.
bool BeginThemedTabBar(const char *id, ImGuiTabBarFlags flags)
A stylized tab bar with "Mission Control" branding.
void EndThemedTabBar()
#define REGISTER_PANEL(PanelClass)
Auto-registration macro for panels with default constructors.
std::vector< OracleMenuComponent > components
std::vector< OracleMenuDrawRoutine > draw_routines
std::vector< std::string > warnings
std::vector< std::string > asm_files
std::vector< OracleMenuBinEntry > bins