114 static const char* kCategories[] = {
"All",
"Enemies",
"NPCs",
"Bosses",
116 ImGui::SetNextItemWidth(100);
118 IM_ARRAYSIZE(kCategories));
122 ImGui::SetNextItemWidth(120);
127 float available_height = ImGui::GetContentRegionAvail().y;
129 float reserved_height = 120.0f;
132 std::max(150.0f, std::min(400.0f, available_height - reserved_height));
135 float panel_width = ImGui::GetContentRegionAvail().x;
137 std::max(28.0f, std::min(40.0f, (panel_width - 40.0f) / 8.0f));
139 std::max(1,
static_cast<int>(panel_width / (sprite_size + 6)));
141 ImGui::BeginChild(
"##SpriteGrid", ImVec2(0, grid_height),
true,
142 ImGuiWindowFlags_HorizontalScrollbar);
145 for (
int i = 0; i < 256; ++i) {
157 button_color.x = std::min(1.0f, button_color.x + 0.2f);
158 button_color.y = std::min(1.0f, button_color.y + 0.2f);
159 button_color.z = std::min(1.0f, button_color.z + 0.2f);
164 {{ImGuiCol_Button, button_color},
165 {ImGuiCol_ButtonHovered,
166 ImVec4(std::min(1.0f, button_color.x + 0.1f),
167 std::min(1.0f, button_color.y + 0.1f),
168 std::min(1.0f, button_color.z + 0.1f), 1.0f)},
169 {ImGuiCol_ButtonActive,
170 ImVec4(std::min(1.0f, button_color.x + 0.2f),
171 std::min(1.0f, button_color.y + 0.2f),
172 std::min(1.0f, button_color.z + 0.2f), 1.0f)}});
176 std::string label = absl::StrFormat(
"%s\n%02X", icon, i);
177 if (ImGui::Button(label.c_str(), ImVec2(sprite_size, sprite_size))) {
187 if (ImGui::IsItemHovered()) {
190 tr(
"%s (0x%02X)\n[%s]\nClick to select for placement"),
196 ImVec2 min = ImGui::GetItemRectMin();
197 ImVec2 max = ImGui::GetItemRectMax();
199 ImGui::ColorConvertFloat4ToU32(theme.dungeon_selection_primary);
200 ImGui::GetWindowDrawList()->AddRect(min, max, sel_color, 0.0f, 0, 2.0f);
206 if (col < items_per_row) {
219 auto& sprites = room.GetSprites();
220 int selected_sprite_list_index = -1;
223 const auto selected_entity =
226 selected_sprite_list_index =
static_cast<int>(selected_entity.index);
231 int sprite_count =
static_cast<int>(sprites.size());
233 sprite_count > 16 ? theme.text_error_red : theme.text_primary;
234 ImGui::TextColored(count_color,
ICON_MD_LIST " Room Sprites: %d/16",
243 if (sprite_count > 16) {
246 if (ImGui::IsItemHovered()) {
248 tr(
"Room exceeds sprite limit (16 max)!\n"
249 "This may cause game crashes."));
253 if (sprites.empty()) {
254 ImGui::TextColored(theme.text_secondary_gray,
260 float available = ImGui::GetContentRegionAvail().y;
261 float list_height = std::max(100.0f, available * 0.4f);
263 ImGui::BeginChild(
"##SpriteList", ImVec2(0, list_height),
true);
264 for (
size_t i = 0; i < sprites.size(); ++i) {
265 const auto& sprite = sprites[i];
266 bool is_selected = (selected_sprite_list_index ==
static_cast<int>(i));
268 ImGui::PushID(
static_cast<int>(i));
271 std::string label = absl::StrFormat(
275 if (sprite.key_drop() == 1) {
277 }
else if (sprite.key_drop() == 2) {
282 if (sprite.IsOverlord()) {
286 if (ImGui::Selectable(label.c_str(), is_selected)) {
294 ImGui::SameLine(ImGui::GetContentRegionAvail().x - 80);
295 ImGui::TextColored(theme.text_secondary_gray, tr(
"(%d,%d) L%d"),
296 sprite.x(), sprite.y(), sprite.layer());
307 bool is_enemy = (sprite_id >= 0x09 && sprite_id <= 0x7F);
308 bool is_npc = (sprite_id >= 0x80 && sprite_id <= 0xBF);
309 bool is_boss = (sprite_id >= 0xC0 && sprite_id <= 0xD8);
310 bool is_item = (sprite_id >= 0xD9 && sprite_id <= 0xFF);
326 std::string name_lower = name;
328 for (
auto& c : name_lower)
329 c =
static_cast<char>(tolower(c));
330 for (
auto& c : filter_lower)
331 c =
static_cast<char>(tolower(c));
332 if (name_lower.find(filter_lower) == std::string::npos) {