134 if (tile_handler.was_placement_blocked()) {
136 tile_handler.clear_placement_blocked();
140 "Object limit reached (%d max) - placement blocked",
153 auto& sprite_handler = coordinator.sprite_handler();
154 if (sprite_handler.was_placement_blocked()) {
155 const auto reason = sprite_handler.placement_block_reason();
156 sprite_handler.clear_placement_blocked();
160 "Sprite limit reached (%d max) - placement blocked",
173 auto& door_handler = coordinator.door_handler();
174 if (door_handler.was_placement_blocked()) {
175 const auto reason = door_handler.placement_block_reason();
176 door_handler.clear_placement_blocked();
180 "Door limit reached (%d max) - placement blocked", max_doors));
196 float available_height = ImGui::GetContentRegionAvail().y;
197 float browser_height = std::max(240.0f, available_height);
201 ImGui::BeginChild(
"ObjectBrowserRegion", ImVec2(0, browser_height),
false);
239 const auto snapshot = viewer !=
nullptr
241 viewer->object_interaction(), viewer->rooms(),
242 viewer->current_room_id())
245 ImGui::AlignTextToFramePadding();
268 ImGui::TextColored(theme.status_warning,
273 const float cancel_width = ImGui::CalcTextSize(cancel_label).x +
274 ImGui::GetStyle().FramePadding.x * 2.0f;
275 const float next_x = ImGui::GetItemRectMax().x +
276 ImGui::GetStyle().ItemSpacing.x + cancel_width;
277 const float line_right =
278 ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
279 if (next_x <= line_right) {
282 if (ImGui::SmallButton(cancel_label)) {
286 ImGui::TextColored(theme.status_success,
290 ImGui::TextColored(theme.status_success,
297 ImGui::TextColored(theme.status_success,
309 " Browse, filter, and click an object below to queue placement.");
316 size_t object_count = room.GetTileObjects().
size();
317 size_t sprite_count = room.GetSprites().size();
318 size_t door_count = room.GetDoors().size();
320 for (
const auto& obj : room.GetTileObjects()) {
332 auto usage_color = [&](
size_t count,
int max_val,
333 bool exact_capacity_warning) -> ImVec4 {
334 if (exact_capacity_warning) {
336 theme.text_secondary_gray);
338 float ratio =
static_cast<float>(count) /
static_cast<float>(max_val);
340 return theme.status_error;
342 if (ratio >= 0.75f) {
343 return theme.status_warning;
345 return theme.text_secondary_gray;
353 {{
ICON_MD_WIDGETS, absl::StrFormat(
"%zu/%d", object_count, kMaxObjects),
354 usage_color(object_count, kMaxObjects,
true)},
356 absl::StrFormat(
"%zu/%d", sprite_count, kMaxSprites),
357 usage_color(sprite_count, kMaxSprites,
true)},
359 usage_color(door_count, kMaxDoors,
true)},
361 absl::StrFormat(
"%d/%d", chest_count, kMaxChests),
362 usage_color(chest_count, kMaxChests,
false)}});
364 if (!result.errors.empty() || !result.warnings.empty()) {
366 result.errors.empty() ? theme.status_warning : theme.status_error,
367 tr(
"%s %zu issue%s"),
369 result.errors.size() + result.warnings.size(),
370 (result.errors.size() + result.warnings.size()) == 1 ?
"" :
"s");
371 if (ImGui::IsItemHovered()) {
372 ImGui::BeginTooltip();
373 for (
const auto& err : result.errors) {
377 for (
const auto& warn : result.warnings) {
386 ImGui::TextColored(theme.text_secondary_gray,
void SetPlacementError(const std::string &message)
static constexpr double kPlacementErrorDuration
std::function< DungeonCanvasViewer *()> canvas_viewer_provider_
zelda3::RoomObject preview_object_
DungeonCanvasViewer * ResolveCanvasViewer()
std::shared_ptr< zelda3::DungeonObjectEditor > object_editor_
std::function< void()> open_object_editor_callback_
ObjectSelectorContent(Rom *rom, DungeonCanvasViewer *canvas_viewer, std::shared_ptr< zelda3::DungeonObjectEditor > object_editor=nullptr, ToastManager *toast_manager=nullptr)
DungeonCanvasViewer * canvas_viewer_
DungeonObjectSelector object_selector_
void Draw(bool *p_open) override
Draw the panel content.
void SetAgentOptimizedLayout(bool enabled)
void DrawInlineInspectButton(const std::function< void()> &callback)
void DrawUsageChips(std::initializer_list< UsageChip > chips)