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"
14#include "app/gui/core/icons.h"
16#include "imgui/imgui.h"
17#include "zelda3/dungeon/room.h"
18
19namespace yaze {
20namespace editor {
21
34 public:
35 ItemEditorPanel(int* current_room_id, DungeonRoomStore* rooms,
36 DungeonCanvasViewer* canvas_viewer = nullptr)
37 : current_room_id_(current_room_id),
38 rooms_(rooms),
39 canvas_viewer_(canvas_viewer) {}
40
41 // ==========================================================================
42 // WindowContent 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 // WindowContent 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
81 std::function<void(const zelda3::PotItem&)> callback) {
82 item_placed_callback_ = std::move(callback);
83 }
84
85 private:
86 // Pot item names from ZELDA3_DUNGEON_SPEC.md Section 7.2
87 static constexpr const char* kPotItemNames[] = {
88 "Nothing", // 0
89 "Green Rupee", // 1
90 "Rock", // 2
91 "Bee", // 3
92 "Health", // 4
93 "Bomb", // 5
94 "Heart", // 6
95 "Blue Rupee", // 7
96 "Key", // 8
97 "Arrow", // 9
98 "Bomb", // 10
99 "Heart", // 11
100 "Magic", // 12
101 "Full Magic", // 13
102 "Cucco", // 14
103 "Green Soldier", // 15
104 "Bush Stal", // 16
105 "Blue Soldier", // 17
106 "Landmine", // 18
107 "Heart", // 19
108 "Fairy", // 20
109 "Heart", // 21
110 "Nothing", // 22
111 "Hole", // 23
112 "Warp", // 24
113 "Staircase", // 25
114 "Bombable", // 26
115 "Switch" // 27
116 };
117 static constexpr size_t kPotItemCount =
118 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,
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 =
152 std::max(150.0f, std::min(400.0f, available_height - reserved_height));
153
154 // Responsive item size based on panel width
155 float panel_width = ImGui::GetContentRegionAvail().x;
156 float item_size =
157 std::max(36.0f, std::min(48.0f, (panel_width - 40.0f) / 6.0f));
158 int items_per_row =
159 std::max(1, static_cast<int>(panel_width / (item_size + 8)));
160
161 ImGui::BeginChild("##ItemGrid", ImVec2(0, grid_height), true,
162 ImGuiWindowFlags_HorizontalScrollbar);
163
164 int col = 0;
165 for (size_t i = 0; i < kPotItemCount; ++i) {
166 bool is_selected = (selected_item_id_ == static_cast<int>(i));
167
168 ImGui::PushID(static_cast<int>(i));
169
170 // Color-coded button based on item type using theme colors
171 ImVec4 button_color = GetItemTypeColor(static_cast<int>(i), theme);
172 if (is_selected) {
173 button_color.x = std::min(1.0f, button_color.x + 0.2f);
174 button_color.y = std::min(1.0f, button_color.y + 0.2f);
175 button_color.z = std::min(1.0f, button_color.z + 0.2f);
176 }
177
178 {
179 gui::StyleColorGuard btn_colors({
180 {ImGuiCol_Button, button_color},
181 {ImGuiCol_ButtonHovered,
182 ImVec4(std::min(1.0f, button_color.x + 0.1f),
183 std::min(1.0f, button_color.y + 0.1f),
184 std::min(1.0f, button_color.z + 0.1f), 1.0f)},
185 {ImGuiCol_ButtonActive,
186 ImVec4(std::min(1.0f, button_color.x + 0.2f),
187 std::min(1.0f, button_color.y + 0.2f),
188 std::min(1.0f, button_color.z + 0.2f), 1.0f)},
189 });
190
191 // Get icon and short name for item
192 const char* icon = GetItemTypeIcon(static_cast<int>(i));
193 std::string label =
194 absl::StrFormat("%s\n%02X", icon, static_cast<int>(i));
195 if (ImGui::Button(label.c_str(), ImVec2(item_size, item_size))) {
196 selected_item_id_ = static_cast<int>(i);
197 placement_mode_ = true;
198 if (canvas_viewer_) {
200 true, static_cast<uint8_t>(i));
201 }
202 }
203 }
204
205 if (ImGui::IsItemHovered()) {
206 ImGui::SetTooltip("%s (0x%02X)\nClick to select for placement",
207 kPotItemNames[i], static_cast<int>(i));
208 }
209
210 // Selection highlight using theme color
211 if (is_selected) {
212 ImVec2 min = ImGui::GetItemRectMin();
213 ImVec2 max = ImGui::GetItemRectMax();
214 ImU32 sel_color =
215 ImGui::ColorConvertFloat4ToU32(theme.dungeon_selection_primary);
216 ImGui::GetWindowDrawList()->AddRect(min, max, sel_color, 0.0f, 0, 2.0f);
217 }
218
219 ImGui::PopID();
220
221 col++;
222 if (col < items_per_row) {
223 ImGui::SameLine();
224 } else {
225 col = 0;
226 }
227 }
228
229 ImGui::EndChild();
230 }
231
233 const auto& theme = AgentUI::GetTheme();
234 auto& room = (*rooms_)[*current_room_id_];
235 const auto& items = room.GetPotItems();
236
237 ImGui::Text(ICON_MD_LIST " Room Items (%zu):", items.size());
238
239 if (items.empty()) {
240 ImGui::TextColored(theme.text_secondary_gray,
241 ICON_MD_INFO " No items in this room");
242 return;
243 }
244
245 // Responsive list height - use remaining available space
246 float list_height =
247 std::max(120.0f, ImGui::GetContentRegionAvail().y - 10.0f);
248 ImGui::BeginChild("##ItemList", ImVec2(0, list_height), true);
249 for (size_t i = 0; i < items.size(); ++i) {
250 const auto& item = items[i];
251
252 ImGui::PushID(static_cast<int>(i));
253
254 const char* item_name =
255 (item.item < kPotItemCount) ? kPotItemNames[item.item] : "Unknown";
256
257 ImGui::Text("[%zu] %s (0x%02X)", i, item_name, item.item);
258 ImGui::SameLine();
259 ImGui::TextColored(theme.text_secondary_gray, "@ (%d,%d)",
260 item.GetTileX(), item.GetTileY());
261
262 ImGui::SameLine();
263 if (ImGui::SmallButton(ICON_MD_DELETE "##Del")) {
264 auto& mutable_room = (*rooms_)[*current_room_id_];
265 mutable_room.GetPotItems().erase(mutable_room.GetPotItems().begin() +
266 static_cast<long>(i));
267 }
268
269 ImGui::PopID();
270 }
271 ImGui::EndChild();
272 }
273
274 ImVec4 GetItemTypeColor(int item_id, const AgentUITheme& theme) {
275 // Color-code based on item type using theme colors
276 if (item_id == 0 || item_id == 22) {
277 return theme.dungeon_object_default; // Gray for "Nothing"
278 } else if (item_id >= 1 && item_id <= 7) {
279 return theme.dungeon_sprite_layer0; // Green for rupees/items
280 } else if (item_id == 8) {
281 return theme.dungeon_object_chest; // Gold for key
282 } else if (item_id >= 15 && item_id <= 17) {
283 return theme.status_error; // Red for enemies
284 } else if (item_id >= 23 && item_id <= 27) {
285 return theme.dungeon_object_stairs; // Yellow for special
286 }
287 return theme.dungeon_object_pot; // Pot color for default
288 }
289
290 const char* GetItemTypeIcon(int item_id) {
291 // Return item-type-appropriate icons
292 if (item_id == 0 || item_id == 22) {
293 return ICON_MD_BLOCK; // Nothing
294 } else if (item_id == 1 || item_id == 7) {
295 return ICON_MD_MONETIZATION_ON; // Rupees (green/blue)
296 } else if (item_id == 4 || item_id == 6 || item_id == 11 || item_id == 19 ||
297 item_id == 21) {
298 return ICON_MD_FAVORITE; // Hearts
299 } else if (item_id == 8) {
300 return ICON_MD_KEY; // Key
301 } else if (item_id == 5 || item_id == 10) {
302 return ICON_MD_CIRCLE; // Bombs
303 } else if (item_id == 9) {
304 return ICON_MD_ARROW_UPWARD; // Arrows
305 } else if (item_id == 12 || item_id == 13) {
306 return ICON_MD_AUTO_AWESOME; // Magic
307 } else if (item_id == 14) {
308 return ICON_MD_EGG; // Cucco
309 } else if (item_id >= 15 && item_id <= 17) {
310 return ICON_MD_PERSON; // Soldiers
311 } else if (item_id == 18) {
312 return ICON_MD_WARNING; // Landmine
313 } else if (item_id == 20) {
314 return ICON_MD_FLUTTER_DASH; // Fairy
315 } else if (item_id == 23) {
316 return ICON_MD_TERRAIN; // Hole
317 } else if (item_id == 24) {
318 return ICON_MD_SWAP_HORIZ; // Warp
319 } else if (item_id == 25) {
320 return ICON_MD_STAIRS; // Staircase
321 } else if (item_id == 26) {
322 return ICON_MD_BROKEN_IMAGE; // Bombable
323 } else if (item_id == 27) {
324 return ICON_MD_TOGGLE_ON; // Switch
325 } else if (item_id == 2) {
326 return ICON_MD_LANDSCAPE; // Rock
327 } else if (item_id == 3) {
328 return ICON_MD_BUG_REPORT; // Bee
329 }
330 return ICON_MD_HELP; // Unknown
331 }
332
333 int* current_room_id_ = nullptr;
336
337 // Selection state
339 bool placement_mode_ = false;
340
341 std::function<void(const zelda3::PotItem&)> item_placed_callback_;
342};
343
344} // namespace editor
345} // namespace yaze
346
347#endif // YAZE_APP_EDITOR_DUNGEON_PANELS_ITEM_EDITOR_PANEL_H_
DungeonObjectInteraction & object_interaction()
void SetItemPlacementMode(bool enabled, uint8_t item_id=0)
WindowContent 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_
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)
ItemEditorPanel(int *current_room_id, DungeonRoomStore *rooms, DungeonCanvasViewer *canvas_viewer=nullptr)
void Draw(bool *p_open) override
Draw the panel content.
Base interface for all logical window content components.
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