yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
door_editor_content.cc
Go to the documentation of this file.
2#include "util/i18n/tr.h"
3
4#include <algorithm>
5#include <array>
6#include <string>
7
8#include "absl/strings/str_format.h"
11#include "app/gui/core/input.h"
14#include "imgui/imgui.h"
15
16namespace yaze::editor {
17
18namespace {
19
20ImVec4 DoorTypeAccent(const AgentUITheme& theme, zelda3::DoorType type) {
21 const int type_val = static_cast<int>(type);
22 if (type_val <= 0x12) {
23 return theme.dungeon_object_door;
24 }
25 if (type_val <= 0x1E) {
26 return theme.status_warning;
27 }
28 return theme.status_success;
29}
30
31// Semantic icon prefix used by both the 20-type placement picker and the
32// "Selected Door" swap combo. Keeps the 20 core types scannable by category.
70
72 switch (type) {
74 return "Normal";
76 return "Lower";
78 return "Cave";
80 return "2-Side";
82 return "Eye";
84 return "S-Key";
86 return "B-Key";
88 return "Up";
90 return "Down";
92 return "Dash";
94 return "Bomb";
96 return "Blast";
98 return "Curtain";
100 return "Bottom";
102 return "Top";
104 return "Exit";
106 return "Water";
108 return "Marker";
110 return "Layer";
112 return "Swap";
113 }
114 return "Door";
115}
116
117} // namespace
118
125
133
137
138void DoorEditorContent::Draw(bool* p_open) {
139 (void)p_open;
141 gui::AutoWidgetScope automation_scope("Dungeon/DoorEditor");
142
143 const auto& theme = AgentUI::GetTheme();
144 static constexpr std::array<zelda3::DoorType, 20> kDoorTypes = {{
165 }};
166
167 if (ResolveCanvasViewer() &&
171 gui::SectionHeader(ICON_MD_SELECT_ALL, "Selected Door", theme.text_info);
173 ImGui::Button(ICON_MD_OPEN_IN_NEW " Inspect Selected", ImVec2(-1, 0))) {
175 }
176 ImGui::Spacing();
177 }
178
179 gui::SectionHeader(ICON_MD_DOOR_FRONT, "Door Styles", theme.text_info);
180 ImGui::TextColored(theme.text_secondary_gray,
181 tr("Select a door style, then click a wall in the room "
182 "canvas to place it."));
183
185 ImGui::TextColored(
186 theme.status_warning, ICON_MD_PLACE " Active: %s",
187 std::string(zelda3::GetDoorTypeName(selected_door_type_)).c_str());
188 ImGui::SameLine();
189 if (ImGui::SmallButton(ICON_MD_CANCEL " Cancel")) {
191 }
192 }
193
194 constexpr float kDoorCardHeight = 48.0f;
195 constexpr float kDoorCardSpacing = 6.0f;
196 constexpr float kMinDoorCardWidth = 92.0f;
197 const float panel_width = ImGui::GetContentRegionAvail().x;
198 const int items_per_row =
199 std::max(2, static_cast<int>((panel_width + kDoorCardSpacing) /
200 (kMinDoorCardWidth + kDoorCardSpacing)));
201 const float card_width = std::max(
202 kMinDoorCardWidth,
203 (panel_width - (items_per_row - 1) * kDoorCardSpacing) / items_per_row);
204
205 ImGui::BeginChild("##DoorTypeGrid", ImVec2(0, 150), true,
206 ImGuiWindowFlags_AlwaysVerticalScrollbar);
207
208 int col = 0;
209 for (size_t i = 0; i < kDoorTypes.size(); ++i) {
210 const auto door_type = kDoorTypes[i];
211 const bool is_selected = selected_door_type_ == door_type;
212 const int type_val = static_cast<int>(door_type);
213 ImGui::PushID(static_cast<int>(i));
214
215 ImVec4 button_color = DoorTypeAccent(theme, door_type);
216 if (is_selected) {
217 button_color.x = std::min(1.0f, button_color.x + 0.2f);
218 button_color.y = std::min(1.0f, button_color.y + 0.2f);
219 button_color.z = std::min(1.0f, button_color.z + 0.2f);
220 }
221
222 gui::StyleColorGuard btn_colors({
223 {ImGuiCol_Button, button_color},
224 {ImGuiCol_ButtonHovered,
225 ImVec4(button_color.x + 0.1f, button_color.y + 0.1f,
226 button_color.z + 0.1f, 1.0f)},
227 {ImGuiCol_ButtonActive,
228 ImVec4(button_color.x + 0.2f, button_color.y + 0.2f,
229 button_color.z + 0.2f, 1.0f)},
230 });
231
232 const std::string label =
233 absl::StrFormat("%s %02X\n%s", DoorTypeIcon(door_type), type_val,
234 ShortDoorTypeLabel(door_type).c_str());
235 if (ImGui::Button(label.c_str(), ImVec2(card_width, kDoorCardHeight))) {
236 selected_door_type_ = door_type;
238 if (ResolveCanvasViewer()) {
240 true, selected_door_type_);
241 }
242 }
243
244 if (ImGui::IsItemHovered()) {
245 ImGui::SetTooltip(tr("%s (0x%02X)\nClick to select for placement"),
246 std::string(zelda3::GetDoorTypeName(door_type)).c_str(),
247 type_val);
248 }
249
250 if (is_selected) {
251 ImVec2 min = ImGui::GetItemRectMin();
252 ImVec2 max = ImGui::GetItemRectMax();
253 ImGui::GetWindowDrawList()->AddRect(min, max, IM_COL32(255, 255, 0, 255),
254 0.0f, 0, 2.0f);
255 }
256
257 ImGui::PopID();
258 col++;
259 if (col < items_per_row && i < kDoorTypes.size() - 1) {
260 ImGui::SameLine();
261 } else {
262 col = 0;
263 }
264 }
265
266 ImGui::EndChild();
267
268 if (!rooms_ || current_room_id_ < 0 || current_room_id_ >= 296) {
269 return;
270 }
271
272 const auto& room = (*rooms_)[current_room_id_];
273 const auto& doors = room.GetDoors();
274
275 ImGui::Spacing();
276 gui::SectionHeader(ICON_MD_LIST, "Doors In Room", theme.text_info);
277 if (doors.empty()) {
278 ImGui::TextColored(theme.text_secondary_gray,
279 ICON_MD_INFO " No doors in this room");
280 return;
281 }
282
283 int selected_door_index = -1;
284 if (ResolveCanvasViewer() &&
286 const auto selected_entity =
288 if (selected_entity.type == EntityType::Door) {
289 selected_door_index = static_cast<int>(selected_entity.index);
290 }
291 }
292
293 if (selected_door_index >= 0 &&
294 selected_door_index < static_cast<int>(doors.size())) {
295 uint8_t raw_type = static_cast<uint8_t>(doors[selected_door_index].type);
296 ImGui::AlignTextToFramePadding();
297 ImGui::TextUnformatted(tr("Selected raw type"));
298 ImGui::SameLine();
299 ImGui::SetNextItemWidth(72.0f);
300 const bool type_changed = gui::InputScalarDeferred(
301 "##SelectedDoorRawType", ImGuiDataType_U8, &raw_type, "%02X",
302 ImGuiInputTextFlags_CharsHexadecimal,
303 {reinterpret_cast<uintptr_t>(rooms_),
304 static_cast<uint64_t>(current_room_id_),
305 static_cast<uint64_t>(selected_door_index)});
306 gui::AutoRegisterLastItem("input_scalar", "selected_door_raw_type",
307 "Selected door raw type byte");
308 if (type_changed && canvas_viewer_) {
311 .door_handler()
312 .MutateDoorType(selected_door_index,
313 static_cast<zelda3::DoorType>(raw_type));
314 }
315 }
316
317 ImGui::BeginChild("##DoorList", ImVec2(0, 0), true);
318 for (size_t i = 0; i < doors.size(); ++i) {
319 const auto& door = doors[i];
320 const auto [tile_x, tile_y] = door.GetTileCoords();
321 const std::string type_name(zelda3::GetDoorTypeName(door.type));
322 const std::string dir_name(zelda3::GetDoorDirectionName(door.direction));
323
324 ImGui::PushID(static_cast<int>(i));
325 const std::string row_label = absl::StrFormat("[%zu] %s", i, type_name);
326 const bool row_selected = ImGui::Selectable(
327 row_label.c_str(), selected_door_index == static_cast<int>(i));
328 gui::AutoRegisterLastItem("selectable", absl::StrFormat("door_row_%zu", i),
329 "Select a door in the current dungeon room");
330 if (row_selected) {
331 if (canvas_viewer_) {
333 }
334 }
335 ImGui::SameLine();
336 ImGui::TextColored(theme.text_secondary_gray, "(%s @ %d,%d)",
337 dir_name.c_str(), tile_x, tile_y);
338 ImGui::PopID();
339 }
340 ImGui::EndChild();
341}
342
343} // namespace yaze::editor
DungeonCanvasViewer * ResolveCanvasViewer()
std::function< DungeonCanvasViewer *()> canvas_viewer_provider_
void OnClose() override
Called when panel is hidden.
void Draw(bool *p_open) override
Draw the panel content.
std::function< void()> open_selection_inspector_callback_
bool MutateDoorType(size_t index, zelda3::DoorType new_type)
Change the type of a door in place, re-encoding ROM bytes.
DungeonObjectInteraction & object_interaction()
InteractionCoordinator & entity_coordinator()
Get the interaction coordinator for entity handling.
void SelectEntity(EntityType type, size_t index)
void SetDoorPlacementMode(bool enabled, zelda3::DoorType type=zelda3::DoorType::NormalDoor)
RAII scope that enables automatic widget registration.
RAII guard for ImGui style colors.
Definition style_guard.h:27
#define ICON_MD_VIEW_DAY
Definition icons.h:2088
#define ICON_MD_EXIT_TO_APP
Definition icons.h:699
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_CANCEL
Definition icons.h:364
#define ICON_MD_DOOR_SLIDING
Definition icons.h:614
#define ICON_MD_PLACE
Definition icons.h:1477
#define ICON_MD_SWAP_HORIZ
Definition icons.h:1896
#define ICON_MD_STAIRS
Definition icons.h:1847
#define ICON_MD_VISIBILITY
Definition icons.h:2101
#define ICON_MD_WHATSHOT
Definition icons.h:2153
#define ICON_MD_LIST
Definition icons.h:1094
#define ICON_MD_DOOR_FRONT
Definition icons.h:613
#define ICON_MD_BOLT
Definition icons.h:282
#define ICON_MD_FLAG
Definition icons.h:784
#define ICON_MD_SELECT_ALL
Definition icons.h:1680
#define ICON_MD_KEY
Definition icons.h:1026
#define ICON_MD_OPEN_IN_NEW
Definition icons.h:1354
#define ICON_MD_WATER_DROP
Definition icons.h:2131
const AgentUITheme & GetTheme()
ImVec4 DoorTypeAccent(const AgentUITheme &theme, zelda3::DoorType type)
Editors are the view controllers for the application.
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
void SectionHeader(const char *icon, const char *label, const ImVec4 &color)
bool InputScalarDeferred(const char *label, ImGuiDataType data_type, void *data, const char *format, ImGuiInputTextFlags flags, InputScalarTargetIdentity target_identity)
Definition input.cc:388
DoorType
Door types from ALTTP.
Definition door_types.h:33
@ FancyDungeonExit
Fancy dungeon exit.
@ SmallKeyDoor
Small key door.
@ SmallKeyStairsDown
Small key stairs (downwards)
@ SmallKeyStairsUp
Small key stairs (upwards)
@ DungeonSwapMarker
Dungeon swap marker.
@ NormalDoor
Normal door (upper layer)
@ BombableDoor
Bombable door.
@ LayerSwapMarker
Layer swap marker.
@ ExplodingWall
Exploding wall.
@ TopSidedShutter
Top-sided shutter door.
@ NormalDoorLower
Normal door (lower layer)
@ BottomSidedShutter
Bottom-sided shutter door.
@ CurtainDoor
Curtain door.
@ WaterfallDoor
Waterfall door.
@ BigKeyDoor
Big key door.
@ EyeWatchDoor
Eye watch door.
@ ExitMarker
Exit marker.
@ DoubleSidedShutter
Double sided shutter door.
constexpr std::string_view GetDoorDirectionName(DoorDirection dir)
Get human-readable name for door direction.
Definition door_types.h:204
constexpr std::string_view GetDoorTypeName(DoorType type)
Get human-readable name for door type.
Definition door_types.h:110
Centralized theme colors for Agent UI components.
Definition agent_theme.h:19
Automatic widget registration helpers for ImGui Test Engine integration.