yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
item_editor_panel.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_DUNGEON_PANELS_ITEM_EDITOR_PANEL_H_
2#define YAZE_APP_EDITOR_DUNGEON_PANELS_ITEM_EDITOR_PANEL_H_
3
4#include <array>
5#include <cstdint>
6#include <functional>
7#include <string>
8
9#include "absl/strings/str_format.h"
13#include "app/gui/core/icons.h"
15#include "imgui/imgui.h"
16#include "zelda3/dungeon/room.h"
17
18namespace yaze {
19namespace editor {
20
33 public:
34 ItemEditorPanel(int* current_room_id,
35 std::array<zelda3::Room, 0x128>* rooms,
36 DungeonCanvasViewer* canvas_viewer = nullptr)
37 : current_room_id_(current_room_id),
38 rooms_(rooms),
39 canvas_viewer_(canvas_viewer) {}
40
41 // ==========================================================================
42 // EditorPanel Identity
43 // ==========================================================================
44
45 std::string GetId() const override { return "dungeon.item_editor"; }
46 std::string GetDisplayName() const override { return "Item Editor"; }
47 std::string GetIcon() const override { return ICON_MD_INVENTORY; }
48 std::string GetEditorCategory() const override { return "Dungeon"; }
49 int GetPriority() const override { return 66; }
50
51 // ==========================================================================
52 // EditorPanel Drawing
53 // ==========================================================================
54
55 void Draw(bool* p_open) override {
56 if (!current_room_id_ || !rooms_) {
57 ImGui::TextDisabled("No room data available");
58 return;
59 }
60
61 if (*current_room_id_ < 0 ||
62 *current_room_id_ >= static_cast<int>(rooms_->size())) {
63 ImGui::TextDisabled("No room selected");
64 return;
65 }
66
68 ImGui::Separator();
70 ImGui::Separator();
72 }
73
74 // ==========================================================================
75 // Panel-Specific Methods
76 // ==========================================================================
77
79 canvas_viewer_ = viewer;
80 }
81
83 std::function<void(const zelda3::PotItem&)> callback) {
84 item_placed_callback_ = std::move(callback);
85 }
86
87 private:
88 // Pot item names from ZELDA3_DUNGEON_SPEC.md Section 7.2
89 static constexpr const char* kPotItemNames[] = {
90 "Nothing", // 0
91 "Green Rupee", // 1
92 "Rock", // 2
93 "Bee", // 3
94 "Health", // 4
95 "Bomb", // 5
96 "Heart", // 6
97 "Blue Rupee", // 7
98 "Key", // 8
99 "Arrow", // 9
100 "Bomb", // 10
101 "Heart", // 11
102 "Magic", // 12
103 "Full Magic", // 13
104 "Cucco", // 14
105 "Green Soldier", // 15
106 "Bush Stal", // 16
107 "Blue Soldier", // 17
108 "Landmine", // 18
109 "Heart", // 19
110 "Fairy", // 20
111 "Heart", // 21
112 "Nothing", // 22
113 "Hole", // 23
114 "Warp", // 24
115 "Staircase", // 25
116 "Bombable", // 26
117 "Switch" // 27
118 };
119 static constexpr size_t kPotItemCount = sizeof(kPotItemNames) / sizeof(kPotItemNames[0]);
120
122 const auto& theme = AgentUI::GetTheme();
123 // Placement mode indicator
124 if (placement_mode_) {
125 const char* item_name = (selected_item_id_ < kPotItemCount)
127 : "Unknown";
128 ImGui::TextColored(theme.status_warning,
129 ICON_MD_PLACE " Placing: %s (0x%02X)", item_name, selected_item_id_);
130 if (ImGui::SmallButton(ICON_MD_CANCEL " Cancel")) {
131 placement_mode_ = false;
132 if (canvas_viewer_) {
134 }
135 }
136 } else {
137 ImGui::TextColored(theme.text_secondary_gray,
138 ICON_MD_INFO " Select an item to place");
139 }
140 }
141
143 const auto& theme = AgentUI::GetTheme();
144 ImGui::Text(ICON_MD_INVENTORY " Select Item:");
145
146 // Item grid with responsive sizing
147 float available_height = ImGui::GetContentRegionAvail().y;
148 // Reserve space for room items section (header + list + some margin)
149 float reserved_height = 120.0f;
150 // Calculate grid height: at least 150px, but responsive to available space
151 float grid_height = std::max(150.0f, std::min(400.0f, available_height - reserved_height));
152
153 // Responsive item size based on panel width
154 float panel_width = ImGui::GetContentRegionAvail().x;
155 float item_size = std::max(36.0f, std::min(48.0f, (panel_width - 40.0f) / 6.0f));
156 int items_per_row = std::max(1, static_cast<int>(panel_width / (item_size + 8)));
157
158 ImGui::BeginChild("##ItemGrid", ImVec2(0, grid_height), true,
159 ImGuiWindowFlags_HorizontalScrollbar);
160
161 int col = 0;
162 for (size_t i = 0; i < kPotItemCount; ++i) {
163 bool is_selected = (selected_item_id_ == static_cast<int>(i));
164
165 ImGui::PushID(static_cast<int>(i));
166
167 // Color-coded button based on item type using theme colors
168 ImVec4 button_color = GetItemTypeColor(static_cast<int>(i), theme);
169 if (is_selected) {
170 button_color.x = std::min(1.0f, button_color.x + 0.2f);
171 button_color.y = std::min(1.0f, button_color.y + 0.2f);
172 button_color.z = std::min(1.0f, button_color.z + 0.2f);
173 }
174
175 {
176 gui::StyleColorGuard btn_colors({
177 {ImGuiCol_Button, button_color},
178 {ImGuiCol_ButtonHovered,
179 ImVec4(std::min(1.0f, button_color.x + 0.1f),
180 std::min(1.0f, button_color.y + 0.1f),
181 std::min(1.0f, button_color.z + 0.1f), 1.0f)},
182 {ImGuiCol_ButtonActive,
183 ImVec4(std::min(1.0f, button_color.x + 0.2f),
184 std::min(1.0f, button_color.y + 0.2f),
185 std::min(1.0f, button_color.z + 0.2f), 1.0f)},
186 });
187
188 // Get icon and short name for item
189 const char* icon = GetItemTypeIcon(static_cast<int>(i));
190 std::string label =
191 absl::StrFormat("%s\n%02X", icon, static_cast<int>(i));
192 if (ImGui::Button(label.c_str(), ImVec2(item_size, item_size))) {
193 selected_item_id_ = static_cast<int>(i);
194 placement_mode_ = true;
195 if (canvas_viewer_) {
197 true, static_cast<uint8_t>(i));
198 }
199 }
200 }
201
202 if (ImGui::IsItemHovered()) {
203 ImGui::SetTooltip("%s (0x%02X)\nClick to select for placement",
204 kPotItemNames[i], static_cast<int>(i));
205 }
206
207 // Selection highlight using theme color
208 if (is_selected) {
209 ImVec2 min = ImGui::GetItemRectMin();
210 ImVec2 max = ImGui::GetItemRectMax();
211 ImU32 sel_color = ImGui::ColorConvertFloat4ToU32(theme.dungeon_selection_primary);
212 ImGui::GetWindowDrawList()->AddRect(min, max, sel_color, 0.0f, 0, 2.0f);
213 }
214
215 ImGui::PopID();
216
217 col++;
218 if (col < items_per_row) {
219 ImGui::SameLine();
220 } else {
221 col = 0;
222 }
223 }
224
225 ImGui::EndChild();
226 }
227
229 const auto& theme = AgentUI::GetTheme();
230 auto& room = (*rooms_)[*current_room_id_];
231 const auto& items = room.GetPotItems();
232
233 ImGui::Text(ICON_MD_LIST " Room Items (%zu):", items.size());
234
235 if (items.empty()) {
236 ImGui::TextColored(theme.text_secondary_gray,
237 ICON_MD_INFO " No items in this room");
238 return;
239 }
240
241 // Responsive list height - use remaining available space
242 float list_height = std::max(120.0f, ImGui::GetContentRegionAvail().y - 10.0f);
243 ImGui::BeginChild("##ItemList", ImVec2(0, list_height), true);
244 for (size_t i = 0; i < items.size(); ++i) {
245 const auto& item = items[i];
246
247 ImGui::PushID(static_cast<int>(i));
248
249 const char* item_name = (item.item < kPotItemCount)
250 ? kPotItemNames[item.item]
251 : "Unknown";
252
253 ImGui::Text("[%zu] %s (0x%02X)", i, item_name, item.item);
254 ImGui::SameLine();
255 ImGui::TextColored(theme.text_secondary_gray,
256 "@ (%d,%d)", item.GetTileX(), item.GetTileY());
257
258 ImGui::SameLine();
259 if (ImGui::SmallButton(ICON_MD_DELETE "##Del")) {
260 auto& mutable_room = (*rooms_)[*current_room_id_];
261 mutable_room.GetPotItems().erase(
262 mutable_room.GetPotItems().begin() + static_cast<long>(i));
263 }
264
265 ImGui::PopID();
266 }
267 ImGui::EndChild();
268 }
269
270 ImVec4 GetItemTypeColor(int item_id, const AgentUITheme& theme) {
271 // Color-code based on item type using theme colors
272 if (item_id == 0 || item_id == 22) {
273 return theme.dungeon_object_default; // Gray for "Nothing"
274 } else if (item_id >= 1 && item_id <= 7) {
275 return theme.dungeon_sprite_layer0; // Green for rupees/items
276 } else if (item_id == 8) {
277 return theme.dungeon_object_chest; // Gold for key
278 } else if (item_id >= 15 && item_id <= 17) {
279 return theme.status_error; // Red for enemies
280 } else if (item_id >= 23 && item_id <= 27) {
281 return theme.dungeon_object_stairs; // Yellow for special
282 }
283 return theme.dungeon_object_pot; // Pot color for default
284 }
285
286 const char* GetItemTypeIcon(int item_id) {
287 // Return item-type-appropriate icons
288 if (item_id == 0 || item_id == 22) {
289 return ICON_MD_BLOCK; // Nothing
290 } else if (item_id == 1 || item_id == 7) {
291 return ICON_MD_MONETIZATION_ON; // Rupees (green/blue)
292 } else if (item_id == 4 || item_id == 6 || item_id == 11 || item_id == 19 || item_id == 21) {
293 return ICON_MD_FAVORITE; // Hearts
294 } else if (item_id == 8) {
295 return ICON_MD_KEY; // Key
296 } else if (item_id == 5 || item_id == 10) {
297 return ICON_MD_CIRCLE; // Bombs
298 } else if (item_id == 9) {
299 return ICON_MD_ARROW_UPWARD; // Arrows
300 } else if (item_id == 12 || item_id == 13) {
301 return ICON_MD_AUTO_AWESOME; // Magic
302 } else if (item_id == 14) {
303 return ICON_MD_EGG; // Cucco
304 } else if (item_id >= 15 && item_id <= 17) {
305 return ICON_MD_PERSON; // Soldiers
306 } else if (item_id == 18) {
307 return ICON_MD_WARNING; // Landmine
308 } else if (item_id == 20) {
309 return ICON_MD_FLUTTER_DASH; // Fairy
310 } else if (item_id == 23) {
311 return ICON_MD_TERRAIN; // Hole
312 } else if (item_id == 24) {
313 return ICON_MD_SWAP_HORIZ; // Warp
314 } else if (item_id == 25) {
315 return ICON_MD_STAIRS; // Staircase
316 } else if (item_id == 26) {
317 return ICON_MD_BROKEN_IMAGE; // Bombable
318 } else if (item_id == 27) {
319 return ICON_MD_TOGGLE_ON; // Switch
320 } else if (item_id == 2) {
321 return ICON_MD_LANDSCAPE; // Rock
322 } else if (item_id == 3) {
323 return ICON_MD_BUG_REPORT; // Bee
324 }
325 return ICON_MD_HELP; // Unknown
326 }
327
328 int* current_room_id_ = nullptr;
329 std::array<zelda3::Room, 0x128>* rooms_ = nullptr;
331
332 // Selection state
334 bool placement_mode_ = false;
335
336 std::function<void(const zelda3::PotItem&)> item_placed_callback_;
337};
338
339} // namespace editor
340} // namespace yaze
341
342#endif // YAZE_APP_EDITOR_DUNGEON_PANELS_ITEM_EDITOR_PANEL_H_
343
DungeonObjectInteraction & object_interaction()
void SetItemPlacementMode(bool enabled, uint8_t item_id=0)
Base interface for all logical panel components.
EditorPanel for placing and managing dungeon pot items.
std::string GetIcon() const override
Material Design icon for this panel.
static constexpr size_t kPotItemCount
static constexpr const char * kPotItemNames[]
int GetPriority() const override
Get display priority for menu ordering.
ImVec4 GetItemTypeColor(int item_id, const AgentUITheme &theme)
void SetCanvasViewer(DungeonCanvasViewer *viewer)
std::function< void(const zelda3::PotItem &) item_placed_callback_)
std::string GetEditorCategory() const override
Editor category this panel belongs to.
std::string GetId() const override
Unique identifier for this panel.
DungeonCanvasViewer * canvas_viewer_
ItemEditorPanel(int *current_room_id, std::array< zelda3::Room, 0x128 > *rooms, DungeonCanvasViewer *canvas_viewer=nullptr)
void SetItemPlacedCallback(std::function< void(const zelda3::PotItem &)> callback)
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
const char * GetItemTypeIcon(int item_id)
std::array< zelda3::Room, 0x128 > * rooms_
void Draw(bool *p_open) override
Draw the panel content.
RAII guard for ImGui style colors.
Definition style_guard.h:27
#define ICON_MD_BLOCK
Definition icons.h:269
#define ICON_MD_FLUTTER_DASH
Definition icons.h:805
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_CANCEL
Definition icons.h:364
#define ICON_MD_LANDSCAPE
Definition icons.h:1059
#define ICON_MD_WARNING
Definition icons.h:2123
#define ICON_MD_TERRAIN
Definition icons.h:1952
#define ICON_MD_PLACE
Definition icons.h:1477
#define ICON_MD_SWAP_HORIZ
Definition icons.h:1896
#define ICON_MD_CIRCLE
Definition icons.h:411
#define ICON_MD_STAIRS
Definition icons.h:1847
#define ICON_MD_AUTO_AWESOME
Definition icons.h:214
#define ICON_MD_BUG_REPORT
Definition icons.h:327
#define ICON_MD_TOGGLE_ON
Definition icons.h:1994
#define ICON_MD_LIST
Definition icons.h:1094
#define ICON_MD_BROKEN_IMAGE
Definition icons.h:320
#define ICON_MD_EGG
Definition icons.h:654
#define ICON_MD_INVENTORY
Definition icons.h:1011
#define ICON_MD_ARROW_UPWARD
Definition icons.h:189
#define ICON_MD_PERSON
Definition icons.h:1415
#define ICON_MD_FAVORITE
Definition icons.h:727
#define ICON_MD_DELETE
Definition icons.h:530
#define ICON_MD_KEY
Definition icons.h:1026
#define ICON_MD_HELP
Definition icons.h:933
#define ICON_MD_MONETIZATION_ON
Definition icons.h:1229
const AgentUITheme & GetTheme()
Centralized theme colors for Agent UI components.
Definition agent_theme.h:19