10#include "absl/strings/str_format.h"
11#include "imgui/imgui.h"
23 const size_t current_sprite_count = room ? room->GetSprites().size() : 0;
46 if (sprite_index.has_value()) {
50 ImVec2(
static_cast<float>(canvas_x),
static_cast<float>(canvas_y));
78 auto [tile_x, tile_y] =
86 auto& sprites = room->GetSprites();
105 if (!pointer_screen_pos.has_value())
109 const auto [canvas_x, canvas_y] =
119 const size_t current_sprite_count = room ? room->GetSprites().size() : 0;
124 ImVec2(
static_cast<float>(snapped_x),
static_cast<float>(snapped_y)));
127 const ImVec2 rect_max(rect_min.x + rect_size.x, rect_min.y + rect_size.y);
130 const ImVec4 base_color =
132 ImVec4 fill_color = base_color;
133 fill_color.w = 0.40f;
134 ImVec4 outline_color = base_color;
135 outline_color.w = 0.85f;
137 canvas->draw_list()->AddRectFilled(rect_min, rect_max,
138 ImGui::GetColorU32(fill_color));
139 canvas->draw_list()->AddRect(
140 rect_min, rect_max, ImGui::GetColorU32(outline_color), 0.0f, 0, 2.0f);
144 canvas->draw_list()->AddText(rect_min, ImGui::GetColorU32(theme.text_primary),
148 if (capacity_state != GhostCapacityState::kNormal &&
149 ImGui::IsMouseHoveringRect(rect_min, rect_max)) {
150 ImGui::SetTooltip(tr(
"Sprites: %zu/%zu\n%s"), current_sprite_count,
155 const std::string badge_text = absl::StrFormat(
158 ImVec2(rect_min.x, rect_max.y + 6.0f), theme,
159 capacity_state, badge_text);
170 const auto& sprites = room->GetSprites();
182 auto [tile_x, tile_y] =
191 ImDrawList* draw_list = ImGui::GetWindowDrawList();
193 const float scale = transform.
scale();
195 ImVec2(
static_cast<float>(pixel_x),
static_cast<float>(pixel_y)));
200 static float pulse = 0.0f;
201 pulse += ImGui::GetIO().DeltaTime * 3.0f;
202 float alpha = 0.5f + 0.3f * sinf(pulse);
204 ImU32 color = IM_COL32(0, 255, 0, 180);
206 (color & 0x00FFFFFF) | (
static_cast<ImU32
>(alpha * 100) << 24);
208 draw_list->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y),
210 draw_list->AddRect(pos, ImVec2(pos.x + size.x, pos.y + size.y), color, 0.0f,
214 ImVec2 text_pos(pos.x, pos.y - 14 * scale);
215 draw_list->AddText(text_pos, IM_COL32(255, 255, 255, 220),
"Sprite");
219 int canvas_x,
int canvas_y)
const {
229 for (
size_t i = 0; i < sprites.size(); ++i) {
230 const auto& sprite = sprites[i];
237 if (canvas_x >= sprite_x &&
239 canvas_y >= sprite_y &&
266 auto& sprites = room->GetSprites();
271 sprites.erase(sprites.begin() +
273 room->MarkSpritesDirty();
285 if (!room || room->GetSprites().empty()) {
290 room->GetSprites().clear();
291 room->MarkSpritesDirty();
307 auto& sprites = room->GetSprites();
313 const int64_t requested_x =
static_cast<int64_t
>(sprite.x()) + delta_x;
314 const int64_t requested_y =
static_cast<int64_t
>(sprite.y()) + delta_y;
315 const int next_x =
static_cast<int>(
317 const int next_y =
static_cast<int>(
319 if (next_x == sprite.x() && next_y == sprite.y()) {
324 sprite.set_x(next_x);
325 sprite.set_y(next_y);
326 room->MarkSpritesDirty();
363 static_cast<uint8_t
>(sprite_y), 0, 0);
366 room->GetSprites().push_back(new_sprite);
367 room->MarkSpritesDirty();
374 int canvas_x,
int canvas_y)
const {
std::optional< ImVec2 > GetPointerScreenPosition() const
DungeonCanvasTransform GetCanvasTransform() const
void TriggerSuccessToast()
InteractionContext * ctx_
bool IsWithinBounds(int canvas_x, int canvas_y) const
Check if coordinates are within room bounds.
zelda3::Room * GetCurrentRoom() const
Get current room (convenience method)
bool HasValidContext() const
Check if context is valid.
GhostCapacityState GetPlacementGhostCapacityState() const
bool NudgeSelected(int delta_x, int delta_y)
void PlaceSpriteAtPosition(int canvas_x, int canvas_y)
Place sprite at position.
void ClearSelection()
Clear sprite selection.
PlacementCapacityState GhostCapacityState
void HandleRelease() override
Handle mouse release.
void SelectSprite(size_t index)
Select sprite at index.
std::optional< size_t > selected_sprite_index_
std::optional< size_t > GetEntityAtPosition(int canvas_x, int canvas_y) const override
Get entity at canvas position.
void DrawGhostPreview() override
Draw ghost preview during placement.
uint8_t preview_sprite_id_
bool sprite_placement_mode_
void DrawSelectionHighlight() override
Draw selection highlight for selected entities.
void HandleDrag(ImVec2 current_pos, ImVec2 delta) override
Handle mouse drag.
bool HandleClick(int canvas_x, int canvas_y) override
Handle mouse click at canvas position.
std::pair< int, int > CanvasToSpriteCoords(int canvas_x, int canvas_y) const
Convert canvas to sprite coordinates (16-pixel grid)
void BeginPlacement() override
Begin placement mode.
PlacementBlockReason placement_block_reason_
void DeleteSelected()
Delete selected sprite.
const std::vector< zelda3::Sprite > & GetSprites() const
A class for managing sprites in the overworld and underworld.
const AgentUITheme & GetTheme()
constexpr int kSpriteGridMax
constexpr int kSpriteTileSize
Editors are the view controllers for the application.
void DrawPlacementCapacityBadge(ImDrawList *draw_list, const ImVec2 &badge_min, const AgentUITheme &theme, PlacementCapacityState state, std::string_view primary_text)
ImVec4 GetPlacementAccentColor(const AgentUITheme &theme, PlacementCapacityState state, const ImVec4 &normal_color)
std::string_view GetPlacementCapacityTooltipSuffix(PlacementCapacityState state)
PlacementCapacityState GetPlacementCapacityState(size_t current_count, size_t max_count)
constexpr size_t kMaxTotalSprites
const zelda3::Room * GetCurrentRoomConst() const
Get const pointer to current room.
void NotifyEntityChanged() const
Notify that entity has changed.
void NotifyInvalidateCache(MutationDomain domain=MutationDomain::kUnknown) const
Notify that cache invalidation is needed.
void NotifyMutation(MutationDomain domain=MutationDomain::kUnknown) const
Notify that a mutation is about to happen.