5#include "imgui/imgui.h"
33 if (door_index.has_value()) {
37 static_cast<float>(canvas_y));
72 drag_x, drag_y, direction);
77 auto& doors = room->GetDoors();
87 room->MarkObjectsDirty();
100 if (!canvas->IsMouseHovering())
return;
102 const ImGuiIO& io = ImGui::GetIO();
103 ImVec2 canvas_pos = canvas->zero_point();
104 int canvas_x =
static_cast<int>(io.MousePos.x - canvas_pos.x);
105 int canvas_y =
static_cast<int>(io.MousePos.y - canvas_pos.y);
118 int door_width_px = dims.width_tiles * 8;
119 int door_height_px = dims.height_tiles * 8;
122 auto [snap_canvas_x, snap_canvas_y] =
RoomToCanvas(tile_x, tile_y);
125 ImDrawList* draw_list = ImGui::GetWindowDrawList();
128 ImVec2 preview_start(canvas_pos.x + snap_canvas_x * scale,
129 canvas_pos.y + snap_canvas_y * scale);
130 ImVec2 preview_end(preview_start.x + door_width_px * scale,
131 preview_start.y + door_height_px * scale);
137 IM_COL32(theme.dungeon_selection_primary.x * 255,
138 theme.dungeon_selection_primary.y * 255,
139 theme.dungeon_selection_primary.z * 255, 80);
140 draw_list->AddRectFilled(preview_start, preview_end, fill_color);
143 ImVec4 outline_color = ImVec4(theme.dungeon_selection_primary.x,
144 theme.dungeon_selection_primary.y,
145 theme.dungeon_selection_primary.z, 0.9f);
146 draw_list->AddRect(preview_start, preview_end,
147 ImGui::GetColorU32(outline_color), 0.0f, 0, 2.0f);
152 std::string label = type_name +
" (" + dir_name +
")";
154 ImVec2 text_pos(preview_start.x, preview_start.y - 16 * scale);
155 draw_list->AddText(text_pos, IM_COL32(255, 255, 255, 200), label.c_str());
164 const auto& doors = room->GetDoors();
168 auto [tile_x, tile_y] = door.GetTileCoords();
177 bool is_inner =
false;
182 auto [snap_x, snap_y] =
190 ImDrawList* draw_list = ImGui::GetWindowDrawList();
194 ImVec2 pos(canvas_pos.x + tile_x * 8 * scale,
195 canvas_pos.y + tile_y * 8 * scale);
196 ImVec2 size(dims.width_tiles * 8 * scale, dims.height_tiles * 8 * scale);
199 static float pulse = 0.0f;
200 pulse += ImGui::GetIO().DeltaTime * 3.0f;
201 float alpha = 0.5f + 0.3f * sinf(pulse);
203 ImU32 color = IM_COL32(255, 165, 0, 180);
204 ImU32 fill_color = (color & 0x00FFFFFF) | (
static_cast<ImU32
>(alpha * 100) << 24);
206 draw_list->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y),
208 draw_list->AddRect(pos, ImVec2(pos.x + size.x, pos.y + size.y), color, 0.0f,
212 ImVec2 text_pos(pos.x, pos.y - 14 * scale);
213 draw_list->AddText(text_pos, IM_COL32(255, 255, 255, 220),
"Door");
222 int canvas_x,
int canvas_y)
const {
226 if (!room)
return std::nullopt;
230 int room_x =
static_cast<int>(canvas_x / scale);
231 int room_y =
static_cast<int>(canvas_y / scale);
233 const auto& doors = room->GetDoors();
234 for (
size_t i = 0; i < doors.size(); ++i) {
235 const auto& door = doors[i];
237 auto [tile_x, tile_y] = door.GetTileCoords();
240 int door_x = tile_x * 8;
241 int door_y = tile_y * 8;
242 int door_w = dims.width_tiles * 8;
243 int door_h = dims.height_tiles * 8;
245 if (room_x >= door_x && room_x < door_x + door_w && room_y >= door_y &&
246 room_y < door_y + door_h) {
270 auto& doors = room->GetDoors();
275 room->MarkObjectsDirty();
313 new_door.
byte1 = byte1;
314 new_door.
byte2 = byte2;
317 room->AddDoor(new_door);
342 bool is_inner =
false;
350 uint8_t nearest_snap =
353 ImDrawList* draw_list = ImGui::GetWindowDrawList();
360 for (uint8_t i = 0; i < 6; ++i) {
361 uint8_t pos = start_pos + i;
362 auto [tile_x, tile_y] =
364 float pixel_x = tile_x * 8.0f;
365 float pixel_y = tile_y * 8.0f;
367 ImVec2 snap_start(canvas_pos.x + pixel_x * scale,
368 canvas_pos.y + pixel_y * scale);
369 ImVec2 snap_end(snap_start.x + dims.width_pixels() * scale,
370 snap_start.y + dims.height_pixels() * scale);
372 if (pos == nearest_snap) {
374 ImVec4 highlight = ImVec4(theme.dungeon_selection_primary.x,
375 theme.dungeon_selection_primary.y,
376 theme.dungeon_selection_primary.z, 0.75f);
377 draw_list->AddRect(snap_start, snap_end, ImGui::GetColorU32(highlight),
381 ImVec4 ghost = ImVec4(1.0f, 1.0f, 1.0f, 0.25f);
382 draw_list->AddRect(snap_start, snap_end, ImGui::GetColorU32(ghost), 0.0f,
InteractionContext * ctx_
float GetCanvasScale() const
Get canvas global scale.
zelda3::Room * GetCurrentRoom() const
Get current room (convenience method)
bool HasValidContext() const
Check if context is valid.
std::pair< int, int > RoomToCanvas(int room_x, int room_y) const
Convert room tile coordinates to canvas pixel coordinates.
ImVec2 GetCanvasZeroPoint() const
Get canvas zero point (for screen coordinate conversion)
bool door_placement_mode_
void DrawSelectionHighlight() override
Draw selection highlight for selected entities.
void DrawSnapIndicators()
Draw snap position indicators during door drag.
void SelectDoor(size_t index)
Select door at index.
std::optional< size_t > selected_door_index_
zelda3::DoorType preview_door_type_
void DrawGhostPreview() override
Draw ghost preview during placement.
void ClearSelection()
Clear door selection.
void HandleDrag(ImVec2 current_pos, ImVec2 delta) override
Handle mouse drag.
void DeleteSelected()
Delete selected door.
uint8_t snapped_door_position_
void CancelPlacement() override
Cancel current placement.
zelda3::DoorDirection detected_door_direction_
void BeginPlacement() override
Begin placement mode.
void HandleRelease() override
Handle mouse release.
bool HandleClick(int canvas_x, int canvas_y) override
Handle mouse click at canvas position.
bool UpdateSnappedPosition(int canvas_x, int canvas_y)
Update snapped position based on cursor.
void PlaceDoorAtSnappedPosition(int canvas_x, int canvas_y)
Place door at snapped position.
std::optional< size_t > GetEntityAtPosition(int canvas_x, int canvas_y) const override
Get entity at canvas position.
static uint8_t GetSectionStartPosition(DoorDirection direction, bool is_inner)
Get the starting position index for outer/inner section.
static bool DetectWallFromPosition(int canvas_x, int canvas_y, DoorDirection &out_direction)
Detect which wall the cursor is near.
static bool IsValidPosition(uint8_t position, DoorDirection direction)
Check if a position is valid for door placement.
static std::pair< int, int > PositionToTileCoords(uint8_t position, DoorDirection direction)
Convert encoded position to tile coordinates.
static bool DetectWallSection(int canvas_x, int canvas_y, DoorDirection &out_direction, bool &out_is_inner)
Detect wall with inner/outer section information.
static uint8_t SnapToNearestPosition(int canvas_x, int canvas_y, DoorDirection direction)
Convert canvas coordinates to nearest valid door position.
const AgentUITheme & GetTheme()
Editors are the view controllers for the application.
constexpr DoorDimensions GetDoorDimensions(DoorDirection dir)
Get door dimensions based on direction.
constexpr std::string_view GetDoorDirectionName(DoorDirection dir)
Get human-readable name for door direction.
constexpr std::string_view GetDoorTypeName(DoorType type)
Get human-readable name for door type.
DoorDirection
Door direction on room walls.
@ North
Top wall (horizontal door, 4x3 tiles)
const zelda3::Room * GetCurrentRoomConst() const
Get const pointer to current room.
void NotifyEntityChanged() const
Notify that entity has changed.
void NotifyInvalidateCache() const
Notify that cache invalidation is needed.
void NotifyMutation() const
Notify that a mutation is about to happen.
Represents a door in a dungeon room.
uint8_t byte1
Original ROM byte 1 (position data)
DoorType type
Door type (determines appearance/behavior)
std::pair< uint8_t, uint8_t > EncodeBytes() const
Encode door data for ROM storage.
DoorDirection direction
Which wall the door is on.
uint8_t position
Encoded position (5-bit, 0-31)
uint8_t byte2
Original ROM byte 2 (type + direction)