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