8#include "absl/strings/str_format.h"
32 constexpr const char* categories[] = {
"All items",
"Used here"};
35 std::vector<std::pair<int, std::string>> entries;
38 std::none_of(room.GetPotItems().begin(), room.GetPotItems().end(),
39 [
id](
const auto& item) { return item.item == id; }))
43 entries.emplace_back(
id, name);
46 std::stable_sort(entries.begin(), entries.end(),
47 [](
const auto& a,
const auto& b) {
48 return workbench::DungeonBrowserFold(a.second) <
49 workbench::DungeonBrowserFold(b.second);
54 if (ImGui::BeginChild(
"##ItemLibrary", ImVec2(0, 0),
false)) {
55 ImGui::BeginDisabled(!can_place);
56 for (
const auto& [
id, name] : entries) {
60 [&,
id =
id](ImVec2 pos, ImVec2 size) {
64 ImGui::GetWindowDrawList(), preview.pixels, preview.bounds, pos,
65 ImVec2(pos.x + size.x, pos.y + size.y), colors);
68 absl::StrFormat(
"place_item_%02X",
id));
69 if (picked && can_place) {
72 true,
static_cast<uint8_t
>(
id));
78 ImGui::TextDisabled(
"No matches");
86 ImGui::TextDisabled(tr(
"No room data available"));
92 ImGui::TextDisabled(tr(
"No room selected"));
100 if (show_room_items) {
136 const char* item_name =
138 ImGui::TextColored(theme.status_warning,
148 ImGui::TextColored(theme.text_secondary_gray,
168 auto [inserted_it, _] =
170 return inserted_it->second;
183 float available_height = ImGui::GetContentRegionAvail().y;
184 float reserved_height = 120.0f;
185 const float grid_height =
188 std::min(400.0f, available_height - reserved_height))
189 : std::max(1.0f, available_height);
192 float panel_width = ImGui::GetContentRegionAvail().x;
194 std::max(36.0f, std::min(48.0f, (panel_width - 32.0f) / 6.0f));
195 float spacing = 4.0f;
196 int items_per_row = std::max(
197 1,
static_cast<int>((panel_width + spacing) / (item_size + spacing)));
199 ImGui::BeginChild(
"##ItemGrid", ImVec2(0, grid_height),
true,
200 ImGuiWindowFlags_HorizontalScrollbar);
201 ImDrawList* draw_list = ImGui::GetWindowDrawList();
202 ImGui::BeginDisabled(!can_edit);
208 ImGui::PushID(
static_cast<int>(i));
210 const ImVec2 p0 = ImGui::GetCursorScreenPos();
212 ImGui::PushStyleColor(ImGuiCol_Button, theme.dungeon_selection_primary);
215 ImGui::Button(
"##item_btn", ImVec2(item_size, item_size));
218 ImGui::PopStyleColor();
220 if (picked && can_edit) {
225 true,
static_cast<uint8_t
>(i));
230 const ImVec2 preview_min(p0.x + 3.0f, p0.y + 2.0f);
231 const ImVec2 preview_max(p0.x + item_size - 3.0f, p0.y + item_size - 12.0f);
232 bool drew_preview =
false;
233 if (preview.bounds.w > 0 && preview.bounds.h > 0 &&
234 !preview.pixels.empty()) {
236 draw_list, preview.pixels, preview.bounds, preview_min, preview_max,
241 const ImVec2 icon_size = ImGui::CalcTextSize(icon);
243 ImVec2(preview_min.x +
244 (preview_max.x - preview_min.x - icon_size.x) * 0.5f,
246 (preview_max.y - preview_min.y - icon_size.y) * 0.5f),
247 ImGui::GetColorU32(theme.text_secondary_gray), icon);
250 const std::string id_text = absl::StrFormat(
"%02X", i);
251 const ImVec2 id_size = ImGui::CalcTextSize(id_text.c_str());
253 ImVec2(p0.x + (item_size - id_size.x) * 0.5f,
254 p0.y + item_size - id_size.y - 1.0f),
255 ImGui::GetColorU32(is_selected ? theme.text_primary
256 : theme.text_secondary_gray),
259 ImGui::LogText(
"%s (0x%02X)\n",
261 static_cast<int>(i));
263 if (ImGui::IsItemHovered()) {
264 ImGui::SetTooltip(tr(
"%s (0x%02X)\nClick to select for placement"),
266 static_cast<int>(i));
271 ImVec2 max = ImVec2(p0.x + item_size, p0.y + item_size);
273 ImGui::ColorConvertFloat4ToU32(theme.dungeon_selection_primary);
274 draw_list->AddRect(min, max, sel_color, 2.0f, 0, 2.0f);
280 if (col < items_per_row) {
281 ImGui::SameLine(0, spacing);
287 ImGui::EndDisabled();
294 const auto& items = room.GetPotItems();
295 int selected_item_index = -1;
298 const auto selected_entity =
300 if (selected_entity.type == EntityType::Item) {
301 selected_item_index =
static_cast<int>(selected_entity.index);
305 ImGui::Text(
ICON_MD_LIST " Room Items (%zu):", items.size());
314 ImGui::TextColored(theme.text_secondary_gray,
319 if (selected_item_index >= 0 &&
320 selected_item_index <
static_cast<int>(items.size()) &&
canvas_viewer_) {
322 ImGui::BeginDisabled(!can_edit);
323 uint8_t raw_item_type = items[selected_item_index].item;
324 ImGui::AlignTextToFramePadding();
325 ImGui::TextUnformatted(tr(
"Selected raw type"));
327 ImGui::SetNextItemWidth(72.0f);
329 "##SelectedItemRawType", ImGuiDataType_U8, &raw_item_type,
"%02X",
330 ImGuiInputTextFlags_CharsHexadecimal,
331 {
reinterpret_cast<uintptr_t
>(
rooms_),
333 static_cast<uint64_t
>(selected_item_index)});
335 "Selected pot item raw type byte");
336 ImGui::EndDisabled();
337 if (type_changed && can_edit) {
345 float list_height = std::max(100.0f, ImGui::GetContentRegionAvail().y);
348 ImGui::BeginChild(
"##ItemList", ImVec2(0, list_height),
true);
349 ImDrawList* draw_list = ImGui::GetWindowDrawList();
350 for (
size_t i = 0; i < items.size(); ++i) {
351 const auto& item = items[i];
353 ImGui::PushID(
static_cast<int>(i));
355 const float row_height = 24.0f;
356 const ImVec2 p0 = ImGui::GetCursorScreenPos();
357 const bool is_selected = (selected_item_index ==
static_cast<int>(i));
358 const bool row_selected =
359 ImGui::Selectable(
"##row", is_selected, 0, ImVec2(0, row_height));
361 "Select a pot item in the current dungeon room");
367 const ImVec2 preview_min(p0.x + 2.0f, p0.y + 1.0f);
368 const ImVec2 preview_max(p0.x + 24.0f, p0.y + 23.0f);
369 bool drew_preview =
false;
370 if (preview.bounds.w > 0 && preview.bounds.h > 0 &&
371 !preview.pixels.empty()) {
373 draw_list, preview.pixels, preview.bounds, preview_min, preview_max,
378 draw_list->AddText(ImVec2(preview_min.x + 4.0f, preview_min.y + 3.0f),
379 ImGui::GetColorU32(theme.text_secondary_gray), icon);
383 const std::string row_label =
384 absl::StrFormat(
"[%zu] %s (0x%02X)", i, item_name, item.item);
386 ImVec2(p0.x + 28.0f, p0.y + 4.0f),
387 ImGui::GetColorU32(is_selected ? theme.text_primary
388 : theme.text_secondary_gray),
391 const std::string coords_label =
392 absl::StrFormat(
"@ (%d,%d)", item.GetTileX(), item.GetTileY());
393 const ImVec2 coords_size = ImGui::CalcTextSize(coords_label.c_str());
395 ImVec2(ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x -
396 coords_size.x - 4.0f,
398 ImGui::GetColorU32(theme.text_secondary_gray), coords_label.c_str());
407 if (item_id == 0 || item_id == 22) {
409 }
else if (item_id >= 1 && item_id <= 7) {
411 }
else if (item_id == 8) {
413 }
else if (item_id >= 15 && item_id <= 17) {
415 }
else if (item_id >= 23 && item_id <= 27) {
422 if (item_id == 0 || item_id == 22) {
424 }
else if (item_id == 1 || item_id == 7) {
426 }
else if (item_id == 4 || item_id == 6 || item_id == 11 || item_id == 19 ||
429 }
else if (item_id == 8) {
431 }
else if (item_id == 5 || item_id == 10) {
433 }
else if (item_id == 9) {
435 }
else if (item_id == 12 || item_id == 13) {
437 }
else if (item_id == 14) {
439 }
else if (item_id >= 15 && item_id <= 17) {
441 }
else if (item_id == 18) {
443 }
else if (item_id == 20) {
445 }
else if (item_id == 23) {
447 }
else if (item_id == 24) {
449 }
else if (item_id == 25) {
451 }
else if (item_id == 26) {
453 }
else if (item_id == 27) {
455 }
else if (item_id == 2) {
457 }
else if (item_id == 3) {
InteractionContext * context() const
Get the interaction context.
DungeonRoomStore * rooms() const
int current_room_id() const
zelda3::GameData * game_data() const
DungeonObjectInteraction & object_interaction()
bool IsObjectInteractionEnabled() const
bool header_read_only() const
void SetItemPlacementMode(bool enabled, uint8_t item_id=0)
SelectedEntity GetSelectedEntity() const
bool IsItemPlacementActive() const
InteractionCoordinator & entity_coordinator()
Get the interaction coordinator for entity handling.
bool HasEntitySelection() const
void SelectEntity(EntityType type, size_t index)
static bool BuildPotItemPreview(uint8_t item_id, const zelda3::Room &room, std::vector< uint8_t > &out_pixels, SDL_Rect &out_bounds)
static bool DrawSpritePreview(ImDrawList *draw_list, const std::vector< uint8_t > &preview, const SDL_Rect &bounds, const ImVec2 &box_min, const ImVec2 &box_max, const std::array< SDL_Color, 256 > &color_table, uint8_t transparent_index=kSpritePreviewTransparentIndex)
ItemInteractionHandler & item_handler()
TileObjectHandler & tile_handler()
uint64_t cached_item_graphics_revision_
void DrawContent(bool show_room_items)
std::unordered_map< uint8_t, CachedItemPreview > item_preview_cache_
bool HasMatchingViewer() const
void DrawPlacementControls()
void DrawItemSelector(bool show_room_items)
DungeonCanvasViewer * canvas_viewer_
const char * GetItemTypeIcon(int item_id) const
ImVec4 GetItemTypeColor(int item_id, const AgentUITheme &theme) const
workbench::DungeonBrowserState browser_state_
const CachedItemPreview & GetOrCreateItemPreview(uint8_t item_id, const zelda3::Room &room)
std::function< void()> open_selection_inspector_callback_
void Draw(bool *p_open) override
Draw the panel content.
DungeonRoomStore * rooms_
uint8_t GetItemId() const
Get current item ID for placement.
bool MutateItemType(size_t index, uint8_t new_type)
Change one pot item's raw type byte in place.
uint64_t graphics_revision() const
#define ICON_MD_FLUTTER_DASH
#define ICON_MD_LANDSCAPE
#define ICON_MD_SWAP_HORIZ
#define ICON_MD_AUTO_AWESOME
#define ICON_MD_BUG_REPORT
#define ICON_MD_TOGGLE_ON
#define ICON_MD_BROKEN_IMAGE
#define ICON_MD_INVENTORY
#define ICON_MD_ARROW_UPWARD
#define ICON_MD_OPEN_IN_NEW
#define ICON_MD_MONETIZATION_ON
const AgentUITheme & GetTheme()
bool DungeonBrowserMatches(std::string_view query, int id, std::string_view name)
void DrawDungeonBrowserControls(DungeonBrowserState &state, std::span< const char *const > categories)
bool DrawDungeonBrowserRow(int id, const std::string &name, bool selected, DrawPreview preview, std::string_view badge={})
const char * GetDungeonPotItemName(uint8_t item_id)
constexpr size_t kDungeonPotItemCount
void DrawDungeonPotItemSaveNotice()
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
bool InputScalarDeferred(const char *label, ImGuiDataType data_type, void *data, const char *format, ImGuiInputTextFlags flags, InputScalarTargetIdentity target_identity)
std::array< SDL_Color, 256 > BuildDungeonSpriteRenderPalette(const Room &room, const GameData *game_data)
Centralized theme colors for Agent UI components.
ImVec4 dungeon_sprite_layer0
ImVec4 dungeon_object_chest
ImVec4 dungeon_object_pot
ImVec4 dungeon_object_stairs
ImVec4 dungeon_object_default
std::vector< uint8_t > pixels