yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
chest_editor_panel.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_DUNGEON_PANELS_CHEST_EDITOR_PANEL_H_
2#define YAZE_APP_EDITOR_DUNGEON_PANELS_CHEST_EDITOR_PANEL_H_
3
4#include <array>
5#include <cctype>
6#include <cstdint>
7#include <functional>
8#include <string>
9
10#include "absl/strings/str_format.h"
15#include "app/gui/core/icons.h"
17#include "imgui/imgui.h"
18#include "zelda3/dungeon/room.h"
20
21namespace yaze {
22namespace editor {
23
36 public:
37 ChestEditorPanel(int* current_room_id, DungeonRoomStore* rooms,
38 DungeonCanvasViewer* canvas_viewer = nullptr)
39 : current_room_id_(current_room_id),
40 rooms_(rooms),
41 canvas_viewer_(canvas_viewer) {}
42
43 // ==========================================================================
44 // WindowContent Identity
45 // ==========================================================================
46
47 std::string GetId() const override { return "dungeon.chest_editor"; }
48 std::string GetDisplayName() const override { return "Chest Editor"; }
49 std::string GetIcon() const override { return ICON_MD_INVENTORY_2; }
50 std::string GetEditorCategory() const override { return "Dungeon"; }
51 int GetPriority() const override { return 70; } // After sprite editor
52
53 // ==========================================================================
54 // WindowContent Drawing
55 // ==========================================================================
56
57 void Draw(bool* p_open) override {
58 if (!current_room_id_ || !rooms_) {
59 ImGui::TextDisabled("No room data available");
60 return;
61 }
62
63 if (*current_room_id_ < 0 ||
64 *current_room_id_ >= static_cast<int>(rooms_->size())) {
65 ImGui::TextDisabled("No room selected");
66 return;
67 }
68
70 ImGui::Separator();
72 }
73
74 // ==========================================================================
75 // Panel-Specific Methods
76 // ==========================================================================
77
79
80 void SetChestModifiedCallback(std::function<void(int, int)> callback) {
81 chest_modified_callback_ = std::move(callback);
82 }
83
84 private:
86 const auto& theme = AgentUI::GetTheme();
87 auto& room = (*rooms_)[*current_room_id_];
88 auto& chests = room.GetChests();
89
90 // Header with count and limit warning
91 int chest_count = static_cast<int>(chests.size());
92 ImVec4 count_color =
93 chest_count > 6 ? theme.text_error_red : theme.text_primary;
94 ImGui::TextColored(count_color, ICON_MD_INVENTORY_2 " Chests: %d/6",
95 chest_count);
96
97 if (chest_count > 6) {
98 ImGui::SameLine();
99 ImGui::TextColored(theme.text_warning_yellow, ICON_MD_WARNING);
100 if (ImGui::IsItemHovered()) {
101 ImGui::SetTooltip(
102 "Room exceeds chest limit (6 max)!\n"
103 "This may cause game crashes.");
104 }
105 }
106
107 // Add chest button
108 ImGui::SameLine();
109 if (ImGui::SmallButton(ICON_MD_ADD " Add")) {
110 // Add new chest with default values
111 zelda3::chest_data new_chest;
112 new_chest.id = 0; // Default item: nothing
113 new_chest.size = false; // Small chest
114 chests.push_back(new_chest);
115 selected_chest_index_ = static_cast<int>(chests.size()) - 1;
118 }
119 }
120 if (ImGui::IsItemHovered()) {
121 ImGui::SetTooltip("Add new chest to room");
122 }
123
124 // Chest list
125 if (chests.empty()) {
126 ImGui::TextColored(theme.text_secondary_gray,
127 ICON_MD_INFO " No chests in this room");
128 return;
129 }
130
131 const auto& item_names = zelda3::Zelda3Labels::GetItemNames();
132 float list_height =
133 std::min(200.0f, ImGui::GetContentRegionAvail().y * 0.5f);
134 ImGui::BeginChild("##ChestList", ImVec2(0, list_height), true);
135
136 for (size_t i = 0; i < chests.size(); ++i) {
137 const auto& chest = chests[i];
138 bool is_selected = (selected_chest_index_ == static_cast<int>(i));
139
140 ImGui::PushID(static_cast<int>(i));
141
142 // Chest icon based on size
143 const char* size_icon =
145 const char* size_label = chest.size ? "Big" : "Small";
146
147 // Get item name
148 std::string item_name =
149 (chest.id < item_names.size())
150 ? item_names[chest.id]
151 : absl::StrFormat("Unknown (0x%02X)", chest.id);
152
153 // Selectable list item
154 std::string label = absl::StrFormat("%s [%zu] %s: %s", size_icon, i + 1,
155 size_label, item_name.c_str());
156
157 if (ImGui::Selectable(label.c_str(), is_selected)) {
158 selected_chest_index_ = static_cast<int>(i);
159 }
160
161 // Highlight with theme color
162 if (is_selected) {
163 ImVec2 min = ImGui::GetItemRectMin();
164 ImVec2 max = ImGui::GetItemRectMax();
165 ImU32 sel_color =
166 ImGui::ColorConvertFloat4ToU32(theme.dungeon_selection_primary);
167 ImGui::GetWindowDrawList()->AddRect(min, max, sel_color, 0.0f, 0, 2.0f);
168 }
169
170 ImGui::PopID();
171 }
172
173 ImGui::EndChild();
174 }
175
177 const auto& theme = AgentUI::GetTheme();
178 auto& room = (*rooms_)[*current_room_id_];
179 auto& chests = room.GetChests();
180
181 if (selected_chest_index_ < 0 ||
182 selected_chest_index_ >= static_cast<int>(chests.size())) {
183 ImGui::TextColored(theme.text_secondary_gray,
184 ICON_MD_INFO " Select a chest to edit");
185 return;
186 }
187
188 auto& chest = chests[selected_chest_index_];
189 const auto& item_names = zelda3::Zelda3Labels::GetItemNames();
190
191 ImGui::Text(ICON_MD_EDIT " Editing Chest #%d", selected_chest_index_ + 1);
192
193 // Chest type (size)
194 ImGui::Text("Type:");
195 ImGui::SameLine();
196 bool is_big = chest.size;
197 if (ImGui::RadioButton("Small", !is_big)) {
198 chest.size = false;
201 }
202 }
203 ImGui::SameLine();
204 if (ImGui::RadioButton("Big", is_big)) {
205 chest.size = true;
208 }
209 }
210
211 // Item selector dropdown
212 ImGui::Text("Item:");
213 ImGui::SameLine();
214
215 std::string current_item =
216 (chest.id < item_names.size())
217 ? absl::StrFormat("[%02X] %s", chest.id,
218 item_names[chest.id].c_str())
219 : absl::StrFormat("[%02X] Unknown", chest.id);
220
221 ImGui::SetNextItemWidth(-1);
222 if (ImGui::BeginCombo("##ItemSelect", current_item.c_str())) {
223 // Search filter
224 static char search_buf[64] = "";
225 ImGui::InputTextWithHint("##Search", "Search items...", search_buf,
226 sizeof(search_buf));
227 ImGui::Separator();
228
229 for (size_t i = 0; i < item_names.size(); ++i) {
230 // Apply search filter
231 if (search_buf[0] != '\0') {
232 std::string name_lower = item_names[i];
233 std::string filter_lower = search_buf;
234 for (auto& c : name_lower) {
235 c = static_cast<char>(tolower(static_cast<unsigned char>(c)));
236 }
237 for (auto& c : filter_lower) {
238 c = static_cast<char>(tolower(static_cast<unsigned char>(c)));
239 }
240 if (name_lower.find(filter_lower) == std::string::npos) {
241 continue;
242 }
243 }
244
245 std::string item_label = absl::StrFormat(
246 "[%02X] %s", static_cast<int>(i), item_names[i].c_str());
247 bool is_selected = (chest.id == static_cast<uint8_t>(i));
248
249 if (ImGui::Selectable(item_label.c_str(), is_selected)) {
250 chest.id = static_cast<uint8_t>(i);
253 }
254 }
255
256 if (is_selected) {
257 ImGui::SetItemDefaultFocus();
258 }
259 }
260
261 ImGui::EndCombo();
262 }
263
264 // Delete button
265 ImGui::Spacing();
266 {
267 gui::StyleColorGuard del_guard(ImGuiCol_Button, theme.status_error);
268 if (ImGui::Button(ICON_MD_DELETE " Delete Chest")) {
269 chests.erase(chests.begin() + selected_chest_index_);
273 }
274 }
275 }
276 }
277
278 int* current_room_id_ = nullptr;
281
282 // Selection state
284
285 std::function<void(int, int)> chest_modified_callback_;
286};
287
288} // namespace editor
289} // namespace yaze
290
291#endif // YAZE_APP_EDITOR_DUNGEON_PANELS_CHEST_EDITOR_PANEL_H_
WindowContent for managing chest contents in dungeon rooms.
void Draw(bool *p_open) override
Draw the panel content.
void SetCanvasViewer(DungeonCanvasViewer *viewer)
DungeonCanvasViewer * canvas_viewer_
std::function< void(int, int)> chest_modified_callback_
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
void SetChestModifiedCallback(std::function< void(int, int)> callback)
std::string GetIcon() const override
Material Design icon for this panel.
std::string GetId() const override
Unique identifier for this panel.
int GetPriority() const override
Get display priority for menu ordering.
ChestEditorPanel(int *current_room_id, DungeonRoomStore *rooms, DungeonCanvasViewer *canvas_viewer=nullptr)
std::string GetEditorCategory() const override
Editor category this panel belongs to.
Base interface for all logical window content components.
RAII guard for ImGui style colors.
Definition style_guard.h:27
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_WARNING
Definition icons.h:2123
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_ADD
Definition icons.h:86
#define ICON_MD_INVENTORY
Definition icons.h:1011
#define ICON_MD_DELETE
Definition icons.h:530
#define ICON_MD_INVENTORY_2
Definition icons.h:1012
const AgentUITheme & GetTheme()
Treasure chest.
Definition zelda.h:425
static const std::vector< std::string > & GetItemNames()