9#include "imgui/imgui.h"
18 ImGui::TextWrapped(
"%s · room %03X", label, room_id);
19 if (ImGui::BeginTable(
21 ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_NoPadOuterX)) {
22 constexpr float kSize = 52.0f;
23 ImGui::TableSetupColumn(
"Slot preview", ImGuiTableColumnFlags_WidthFixed,
25 ImGui::TableSetupColumn(
"Endpoint", ImGuiTableColumnFlags_WidthStretch);
26 ImGui::TableNextRow();
27 ImGui::TableNextColumn();
28 const ImVec2 origin = ImGui::GetCursorScreenPos();
29 auto* draw = ImGui::GetWindowDrawList();
30 const ImVec2 corner(origin.x + kSize, origin.y + kSize);
31 draw->AddRectFilled(origin, corner, ImGui::GetColorU32(ImGuiCol_FrameBg),
33 draw->AddRect(origin, corner, ImGui::GetColorU32(ImGuiCol_Border), 3.0f);
35 constexpr float kScale = kSize / 512.0f;
36 const ImVec2 slot_min(origin.x + std::clamp(x *
kScale, 0.0f, kSize - 3),
37 origin.y + std::clamp(y *
kScale, 0.0f, kSize - 3));
38 const ImVec2 slot_max(
39 std::min(corner.x, slot_min.x + std::max(3.0f, width *
kScale)),
40 std::min(corner.y, slot_min.y + std::max(3.0f, height *
kScale)));
41 draw->AddRectFilled(slot_min, slot_max,
42 ImGui::GetColorU32(ImGuiCol_PlotHistogram));
43 ImGui::Dummy(ImVec2(kSize, kSize));
44 if (ImGui::IsItemHovered()) {
45 ImGui::SetTooltip(
"Door slot preview in the room's 64 by 64 tile grid");
47 ImGui::TableNextColumn();
52 if (existing && existing->
type != proposed.
type) {
59 "%s%s", existing ?
"" :
"New: ",
68 const std::function<
void(
int,
size_t)>& jump_to_reciprocal) {
83 const auto [x, y, width, height] = door.GetEditorBounds();
88 viewer.
ScrollToTile((x + width / 2) / 8, (y + height / 2) / 8);
96 const std::function<
void(
int,
size_t)>& jump_to_reciprocal) {
97 const auto* room = viewer.
rooms()
100 if (!room || door_index >= room->GetDoors().size()) {
103 const auto source = room->
GetDoors()[door_index];
104 const std::array<uint8_t, 3> source_identity{
105 source.position,
static_cast<uint8_t
>(source.type),
106 static_cast<uint8_t
>(source.direction)};
109 state.door_index != door_index || state.rom != viewer.
rom() ||
110 state.source != source_identity) {
113 state.door_index = door_index;
114 state.rom = viewer.
rom();
115 state.source = source_identity;
122 ImGui::PushID(
"DungeonConnectionEditor");
123 ImGui::PushID(state.room_id);
124 ImGui::PushID(
static_cast<int>(door_index));
127 ImGui::TextUnformatted(
"Room connection");
128 ImGui::TextWrapped(
"Preview both endpoints before applying the pair.");
134 ImGui::TextUnformatted(
"Pair layer");
135 ImGui::SetNextItemWidth(-1);
138 ImGui::BeginCombo(
"##ConnectionLayer", lower ?
"Lower" :
"Upper");
141 if (ImGui::Selectable(
"Upper", !lower)) {
146 if (ImGui::Selectable(
"Lower", lower)) {
153 ImGui::EndDisabled();
159 DrawEndpoint(
"Source", state.room_id, source, &source);
160 ImGui::TextWrapped(
"Connection unavailable: %s",
161 std::string(preview.status().message()).c_str());
163 const auto& plan = *preview;
164 const auto* target_before =
165 plan.creates_return ? nullptr
166 : &plan.target_before[plan.target_door_index];
167 DrawEndpoint(
"Source", state.room_id, plan.source_after[door_index],
168 &plan.source_before[door_index]);
169 DrawEndpoint(
"Return", plan.target_room_id,
170 plan.target_after[plan.target_door_index], target_before);
172 "%s", plan.creates_return
173 ?
"Missing return door. Apply creates the shown endpoint."
175 ?
"Return door found. Apply updates the shown pair."
176 :
"Both doors already match.");
178 ImGui::TextWrapped(
"This view is read-only.");
183 const bool apply = ImGui::Button(
184 plan.creates_return ?
"Create Return Door" :
"Update Pair",
187 ImGui::EndDisabled();
190 state.error = status.ok() ?
"" : std::string(status.message());
192 const bool can_open =
194 (!plan.creates_return &&
196 ImGui::BeginDisabled(!can_open);
197 const bool open_target = ImGui::Button(
"Open Target Room", ImVec2(-1, 0));
199 ImGui::EndDisabled();
201 OpenTarget(viewer, plan, jump_to_reciprocal);
204 if (!state.error.empty()) {
205 ImGui::TextWrapped(
"Edit not applied: %s", state.error.c_str());
bool CanNavigateDoorConnectionTarget() const
DungeonRoomStore * rooms() const
absl::Status ApplyDoorConnection(const DungeonConnectionPlan &plan)
int current_room_id() const
DungeonConnectionEditorState & connection_editor_state()
absl::StatusOr< DungeonConnectionPlan > PreviewDoorConnection(const DungeonConnectionRequest &request)
DungeonObjectInteraction & object_interaction()
void TriggerCanvasPingRect(int pixel_x, int pixel_y, int pixel_w, int pixel_h)
bool NavigateToDoorConnectionTarget(int room_id, size_t door_index)
bool IsObjectInteractionEnabled() const
bool header_read_only() const
bool CanNavigateRooms() const
void ScrollToTile(int tile_x, int tile_y)
void NavigateToRoom(int target_room)
void SelectEntity(EntityType type, size_t index)
zelda3::Room * GetIfLoaded(int room_id)
const std::vector< Door > & GetDoors() const
void OpenTarget(DungeonCanvasViewer &viewer, const DungeonConnectionPlan &plan, const std::function< void(int, size_t)> &jump_to_reciprocal)
void DrawEndpoint(const char *label, int room_id, const zelda3::Room::Door &proposed, const zelda3::Room::Door *existing)
Editors are the view controllers for the application.
void DrawDungeonConnectionEditor(DungeonCanvasViewer &viewer, size_t door_index, const std::function< void(int, size_t)> &jump_to_reciprocal)
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
@ NormalDoor
Normal door (upper layer)
@ NormalDoorLower
Normal door (lower layer)
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.
std::vector< zelda3::Room::Door > target_after
DungeonConnectionLayer layer
Represents a door in a dungeon room.
std::tuple< int, int, int, int > GetEditorBounds() const
Get editor interaction bounds (x, y, width, height in pixels)
DoorType type
Door type (determines appearance/behavior)
DoorDirection direction
Which wall the door is on.
uint8_t position
Encoded position (5-bit, 0-31)