yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_canvas_room_chrome.cc
Go to the documentation of this file.
3#include "util/i18n/tr.h"
4
5#include <algorithm>
6#include <cmath>
7#include <cstdint>
8#include <initializer_list>
9#include <optional>
10#include <string>
11
12#include "absl/status/status.h"
13#include "absl/strings/str_format.h"
22#include "app/gui/core/icons.h"
23#include "app/gui/core/input.h"
29#include "imgui/imgui.h"
30#include "util/log.h"
31#include "util/macro.h"
34
35namespace yaze::editor {
36
37namespace {
38
39const char* GetBg2ModeName(int value) {
40 static constexpr const char* kNames[] = {
41 "Off", "Parallax", "Dark", "On top", "Translucent",
42 "Addition", "Normal", "Transparent", "Dark room"};
43 constexpr int kNameCount = sizeof(kNames) / sizeof(kNames[0]);
44 return (value >= 0 && value < kNameCount) ? kNames[value] : "Unknown";
45}
46
47const char* GetCollisionName(int value) {
48 static constexpr const char* kNames[] = {"One", "Both", "Both + Scroll",
49 "Moving Floor", "Moving Water"};
50 constexpr int kNameCount = sizeof(kNames) / sizeof(kNames[0]);
51 return (value >= 0 && value < kNameCount) ? kNames[value] : "Unknown";
52}
53
54std::string GetLayer2ModeName(int value) {
55 // ZScream distinguishes the reserved mode 1 from Nothing (mode 0).
56 if (value == 1)
57 return "One";
58 return value >= 0 && value < 8 ? zelda3::RoomEffect[value] : "Unknown";
59}
60
61} // namespace
62
64 DungeonCanvasViewer& viewer, zelda3::Room& room, int room_id,
65 RoomPropertyLayout layout, const std::function<void()>& draw_pit_damage) {
66 auto* rooms = viewer.rooms();
67 if (!rooms || room_id < 0 || room_id >= static_cast<int>(rooms->size()))
68 return;
69 const bool compact = layout == RoomPropertyLayout::kCompact;
70 const bool stack_choices =
71 ImGui::GetContentRegionAvail().x < ImGui::GetFontSize() * 25.0f;
72 const ImGuiID error_id =
73 ImGui::GetID(absl::StrFormat("RoomMetadataError/%d", room_id).c_str());
74 // Combo selections run inside a popup window. Keep errors in the host pane.
75 auto* inspector_storage = ImGui::GetStateStorage();
76 const gui::InputScalarTargetIdentity identity{
77 reinterpret_cast<uintptr_t>(rooms), static_cast<uint64_t>(room_id)};
78 auto apply = [&](RoomMetadataField field, int value, int index = 0) {
79 const auto status = viewer.EditRoomMetadata(
80 room_id, {.field = field, .value = value, .index = index});
81 inspector_storage->SetBool(error_id, !status.ok());
82 };
83 auto begin_properties = [](const char* id, float label_width = 104.0f) {
84 if (!ImGui::BeginTable(
85 id, 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp)) {
86 return false;
87 }
88 ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed,
89 label_width);
90 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch, 1.0f);
91 return true;
92 };
93 auto property_row = [](const char* label) {
94 // Advance by one label/value pair; four-column tables pair short fields.
95 ImGui::TableNextColumn();
96 ImGui::AlignTextToFramePadding();
97 ImGui::TextUnformatted(label);
98 ImGui::TableNextColumn();
99 ImGui::SetNextItemWidth(-1);
100 };
101 auto draw_hex = [&](const char* label, const char* id, int value,
102 int max_value, RoomMetadataField field, int index = 0) {
103 property_row(label);
104 ImGui::SetNextItemWidth(
105 ImGui::CalcTextSize(max_value > 0xFF ? "0000" : "000").x +
106 ImGui::GetStyle().FramePadding.x * 2.0f);
107 auto target = identity;
108 target.element = static_cast<uint64_t>(field);
109 target.component = static_cast<uint64_t>(index);
111 id, ImGuiDataType_S32, &value, max_value > 0xFF ? "%03X" : "%02X",
112 ImGuiInputTextFlags_CharsHexadecimal, target)) {
113 apply(field, value, index);
114 }
115 {
116 gui::AutoWidgetScope automation_scope(compact ? "Dungeon/RoomProperties"
117 : "Dungeon/Workbench");
118 gui::AutoRegisterLastItem("input_hex", id + 2, label);
119 }
120 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
121 const char* description = label;
123 description = "Sprite graphics set";
124 else if (field == RoomMetadataField::kFloor1)
125 description = "Background 1 floor pattern";
126 else if (field == RoomMetadataField::kFloor2)
127 description = "Background 2 floor pattern";
128 ImGui::SetTooltip("%s (hex 00-%X). Enter or leave the field to apply.",
129 description, max_value);
130 }
131 };
132 auto draw_choice = [&](const char* label, const char* id, int value,
133 int count, RoomMetadataField field, auto name) {
134 if (stack_choices) {
135 ImGui::TextUnformatted(label);
136 ImGui::SetNextItemWidth(-1);
137 } else {
138 property_row(label);
139 }
140 const std::string preview = name(value);
141 const bool open = ImGui::BeginCombo(id, preview.c_str());
142 {
143 gui::AutoWidgetScope automation_scope(compact ? "Dungeon/RoomProperties"
144 : "Dungeon/Workbench");
145 gui::AutoRegisterLastItem("combo", id + 2, label);
146 }
147 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
148 ImGui::SetTooltip("%s: %s (0x%02X)", label, preview.c_str(), value);
149 }
150 if (open) {
151 for (int option = 0; option < count; ++option) {
152 const std::string option_label = name(option);
153 ImGui::PushID(option);
154 if (ImGui::Selectable(option_label.c_str(), value == option)) {
155 apply(field, option);
156 }
157 {
158 gui::AutoWidgetScope automation_scope(
159 compact ? "Dungeon/RoomProperties" : "Dungeon/Workbench");
160 gui::AutoRegisterLastItem("selectable",
161 absl::StrFormat("%s/%d", id + 2, option));
162 }
163 if (value == option) {
164 ImGui::SetItemDefaultFocus();
165 }
166 if (ImGui::IsItemHovered())
167 ImGui::SetTooltip("%s (0x%02X)", option_label.c_str(), option);
168 ImGui::PopID();
169 }
170 ImGui::EndCombo();
171 }
172 };
173 auto choice_group = [&](const char* id, float label_width, auto draw) {
174 if (stack_choices) {
175 draw();
176 } else if (begin_properties(id, label_width)) {
177 draw();
178 ImGui::EndTable();
179 }
180 };
181 auto label_width = [](std::initializer_list<const char*> labels) {
182 float width = 0.0f;
183 for (const auto* label : labels)
184 width = std::max(width, ImGui::CalcTextSize(label).x);
185 return width;
186 };
187
188 ImGui::BeginDisabled(viewer.header_read_only() ||
190 if (compact) {
191 if (ImGui::BeginTable("##CompactRoomGraphics", 4,
192 ImGuiTableFlags_SizingStretchProp)) {
193 ImGui::TableSetupColumn("Property 1", ImGuiTableColumnFlags_WidthFixed,
194 label_width({"Layout", "Palette"}));
195 ImGui::TableSetupColumn("Value 1", ImGuiTableColumnFlags_WidthStretch);
196 ImGui::TableSetupColumn("Property 2", ImGuiTableColumnFlags_WidthFixed,
197 label_width({"Blockset", "Spriteset"}));
198 ImGui::TableSetupColumn("Value 2", ImGuiTableColumnFlags_WidthStretch);
199 draw_hex("Layout", "##Lyr", room.layout_id(), 0x07,
201 draw_hex("Blockset", "##BS", room.blockset(), 0x51,
203 draw_hex("Palette", "##Pal", room.palette(), 0x47,
205 draw_hex("Spriteset", "##SS", room.spriteset(),
207 ImGui::EndTable();
208 }
209 ImGui::EndDisabled();
210 if (inspector_storage->GetBool(error_id))
211 ImGui::TextWrapped(
212 "Edit not applied. Hover the field for its supported range.");
213 return;
214 }
215
216 const bool show_all = (layout == RoomPropertyLayout::kFull);
217 const bool show_core = show_all ||
220 const bool show_mechanics = show_all ||
221 (layout == RoomPropertyLayout::kMechanics) ||
223 const bool show_message =
224 show_all || (layout == RoomPropertyLayout::kMechanics);
225 const bool show_tags =
226 show_all || (layout == RoomPropertyLayout::kTags) || show_mechanics;
227
228 if (show_tags) {
229 choice_group("##WorkbenchRoomTags", label_width({"Tag 1", "Tag 2"}), [&] {
230 const auto tag_name = [&](int value) {
231 return dungeon_project_labels::GetRoomTagLabel(viewer.project(), value);
232 };
233 for (int index = 0; index < 2; ++index) {
234 const int tag = index == 0 ? room.tag1() : room.tag2();
235 draw_choice(
236 index == 0 ? "Tag 1" : "Tag 2",
237 index == 0 ? "##RoomHeaderTag1" : "##RoomHeaderTag2", tag, 0x40,
239 tag_name);
240 }
241 });
242 }
243
244 if (inspector_storage->GetBool(error_id)) {
245 ImGui::TextWrapped(
246 "Edit not applied. Check that this room is editable and the value "
247 "is within the field's supported range. Hover the field for its "
248 "range.");
249 }
250
251 if (show_core) {
252 if (show_all) {
253 ImGui::SeparatorText("Room properties");
254 }
255 const bool horizontal = layout == RoomPropertyLayout::kCoreGraphicsRow;
256 const float available = ImGui::GetContentRegionAvail().x;
257 const float property_width =
258 label_width({"Layout", "Blockset", "Floor 1", "Floor 2", "Palette",
259 "Spriteset", "Message", "Pit damage"});
260 const float value_width =
261 ImGui::CalcTextSize("0000").x + ImGui::GetStyle().FramePadding.x * 2.0f;
262 const float pair_width =
263 property_width + value_width + ImGui::GetStyle().CellPadding.x * 4.0f;
264 const int field_count = 7 + (draw_pit_damage ? 1 : 0);
265 const int pairs =
266 horizontal ? std::clamp(static_cast<int>(std::floor(
267 available / std::max(pair_width, 1.0f))),
268 1, field_count)
269 : 2;
270 const ImGuiTableFlags graphics_flags =
271 ImGuiTableFlags_RowBg |
272 (horizontal
273 ? ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX
274 : ImGuiTableFlags_SizingStretchProp);
275 if (ImGui::BeginTable("##WorkbenchRoomGraphics", pairs * 2,
276 graphics_flags)) {
277 for (int pair = 0; pair < pairs; ++pair) {
278 ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed,
279 property_width);
280 ImGui::TableSetupColumn("Value",
281 horizontal ? ImGuiTableColumnFlags_WidthFixed
282 : ImGuiTableColumnFlags_WidthStretch,
283 horizontal ? value_width : 1.0f);
284 }
285 draw_hex("Layout", "##RoomHeaderLayout", room.layout_id(), 0x07,
287 draw_hex("Blockset", "##RoomHeaderBlockset", room.blockset(), 0x51,
289 draw_hex("Floor 1", "##RoomHeaderFloor1", room.floor1(), 0x0F,
291 draw_hex("Floor 2", "##RoomHeaderFloor2", room.floor2(), 0x0F,
293 draw_hex("Palette", "##RoomHeaderPalette", room.palette(), 0x47,
295 draw_hex("Spriteset", "##RoomHeaderSpriteset", room.spriteset(),
297 if (horizontal) {
298 draw_hex("Message", "##RoomHeaderMessage", room.message_id(), 0x0FFF,
300 if (draw_pit_damage) {
301 property_row("Pit damage");
302 draw_pit_damage();
303 }
304 }
305 ImGui::EndTable();
306 }
307 }
308
309 if (show_message) {
310 if (begin_properties("##WorkbenchRoomMessage", label_width({"Message"}))) {
311 draw_hex("Message", "##RoomHeaderMessage", room.message_id(), 0x0FFF,
313 ImGui::EndTable();
314 }
315 }
316 if (show_mechanics) {
317 choice_group(
318 "##WorkbenchRoomHeader",
319 label_width({"Layer 2 type", "Layer 2 mode", "Collision"}), [&] {
320 draw_choice("Layer 2 type", "##RoomHeaderBg2",
321 static_cast<int>(room.bg2()), 9, RoomMetadataField::kBg2,
322 GetBg2ModeName);
323 draw_choice("Layer 2 mode", "##RoomHeaderEffect", room.effect(), 8,
324 RoomMetadataField::kEffect, GetLayer2ModeName);
325 draw_choice("Collision", "##RoomHeaderCollision", room.collision(), 5,
326 RoomMetadataField::kCollision, GetCollisionName);
327 });
328 }
329 ImGui::EndDisabled();
330}
331
333 const zelda3::RoomObject& object,
334 int canvas_x, int canvas_y) {
335 std::string name = zelda3::GetObjectName(object.id_);
336 std::string info_text;
337 if (object.id_ >= 0x100) {
338 info_text =
339 absl::StrFormat("0x%03X %s (X:%d Y:%d S:0x%02X)", object.id_,
340 name.c_str(), object.x_, object.y_, object.size_);
341 } else {
342 info_text =
343 absl::StrFormat("0x%02X %s (X:%d Y:%d S:0x%02X)", object.id_,
344 name.c_str(), object.x_, object.y_, object.size_);
345 }
346
347 gui::DrawText(rt, info_text, canvas_x, canvas_y - 12);
348}
349
351 LOG_DEBUG("[LoadAndRender]", "START room_id=%d", room_id);
352
353 if (room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
354 LOG_DEBUG("[LoadAndRender]", "ERROR: Invalid room ID");
355 return absl::InvalidArgumentError("Invalid room ID");
356 }
357
358 if (!rom_ || !rom_->is_loaded()) {
359 LOG_DEBUG("[LoadAndRender]", "ERROR: ROM not loaded");
360 return absl::FailedPreconditionError("ROM not loaded");
361 }
362
363 if (!rooms_) {
364 LOG_DEBUG("[LoadAndRender]", "ERROR: Room data not available");
365 return absl::FailedPreconditionError("Room data not available");
366 }
367
368 auto* room_ptr = rooms_->TryEnsureRoom(room_id);
369 if (!room_ptr) {
370 LOG_DEBUG("[LoadAndRender]", "ERROR: Room data unavailable");
371 return absl::InvalidArgumentError("Invalid room ID");
372 }
373 auto& room = *room_ptr;
374 LOG_DEBUG("[LoadAndRender]", "Got room reference");
375
376 if (!game_data_) {
377 LOG_ERROR("[LoadAndRender]", "GameData not available");
378 return absl::FailedPreconditionError("GameData not available");
379 }
380 const auto& dungeon_main = game_data_->palette_groups.dungeon_main;
381 if (!dungeon_main.empty()) {
383 static_cast<uint64_t>(room.ResolveDungeonPaletteId());
384
385 const auto& full_palette = dungeon_main[current_palette_group_id_];
387 full_palette, game_data_);
388 LOG_DEBUG("[LoadAndRender]", "Palette loaded: group_id=%zu",
390 }
391
392 LOG_DEBUG("[LoadAndRender]", "Calling room.RenderRoomGraphics()...");
394 LOG_DEBUG("[LoadAndRender]",
395 "RenderRoomGraphics() complete - room buffers self-contained");
396
397 LOG_DEBUG("[LoadAndRender]", "SUCCESS");
398 return absl::OkStatus();
399}
400
402 ImGui::Separator();
403 if (header_read_only_) {
404 ImGui::BeginDisabled();
405 }
406
407 constexpr ImGuiTableFlags kPropsTableFlags =
408 ImGuiTableFlags_NoPadOuterX | ImGuiTableFlags_NoBordersInBody;
409
410 if (ImGui::BeginTable("##RoomPropsTable", 2, kPropsTableFlags)) {
411 const float nav_col_width = (ImGui::GetFrameHeight() * 4.0f) +
412 (ImGui::GetStyle().ItemSpacing.x * 3.0f) +
413 (ImGui::GetStyle().FramePadding.x * 2.0f);
414 ImGui::TableSetupColumn("NavCol", ImGuiTableColumnFlags_WidthFixed,
415 nav_col_width);
416 ImGui::TableSetupColumn("PropsCol", ImGuiTableColumnFlags_WidthStretch);
417
418 ImGui::TableNextRow();
419 ImGui::TableNextColumn();
420 DrawRoomNavigation(room_id);
421 ImGui::TableNextColumn();
422 DrawRoomPropertyTable(room, room_id);
423
425 ImGui::TableNextRow();
426 ImGui::TableNextColumn();
427 ImGui::TextDisabled(ICON_MD_SELECT_ALL " Select");
428 ImGui::TableNextColumn();
429 DrawLayerControls(room, room_id);
430 }
431
432 ImGui::EndTable();
433 }
434
435 if (header_read_only_) {
436 ImGui::EndDisabled();
437 }
439 ImGui::CollapsingHeader("Destinations##RoomDestinations")) {
441 }
442}
443
446 return;
447 }
448
449 auto room_if_valid = [](int candidate) -> std::optional<int> {
450 if (candidate < 0 || candidate >= zelda3::kNumberOfRooms) {
451 return std::nullopt;
452 }
453 return candidate;
454 };
455
456 const auto north =
457 room_if_valid(NeighborRoomId(room_id, zelda3::DoorDirection::North));
458 const auto south =
459 room_if_valid(NeighborRoomId(room_id, zelda3::DoorDirection::South));
460 const auto west =
461 room_if_valid(NeighborRoomId(room_id, zelda3::DoorDirection::West));
462 const auto east =
463 room_if_valid(NeighborRoomId(room_id, zelda3::DoorDirection::East));
464
465 auto make_tooltip = [&](const std::optional<int>& target,
466 const char* direction) -> std::string {
467 if (!target.has_value()) {
468 return "";
469 }
470 return absl::StrFormat(
471 "%s: [%03X] %s", direction, *target,
473 };
474
475 auto nav_button = [&](const char* id, ImGuiDir dir,
476 const std::optional<int>& target,
477 const std::string& tooltip) {
478 const bool enabled = target.has_value();
479 if (!enabled) {
480 ImGui::BeginDisabled();
481 }
482 const bool pressed = ImGui::ArrowButton(id, dir);
483 if (!enabled) {
484 ImGui::EndDisabled();
485 }
486 if (enabled && ImGui::IsItemHovered() && !tooltip.empty()) {
487 ImGui::SetTooltip("%s", tooltip.c_str());
488 }
489 if (pressed && enabled) {
491 room_swap_callback_(room_id, *target);
492 } else if (room_navigation_callback_) {
494 }
495 }
496 };
497
498 ImGui::PushID(room_id);
499 ImGui::BeginGroup();
500 nav_button("##RoomNavWest", ImGuiDir_Left, west, make_tooltip(west, "West"));
501 ImGui::SameLine();
502 nav_button("##RoomNavNorth", ImGuiDir_Up, north,
503 make_tooltip(north, "North"));
504 ImGui::SameLine();
505 nav_button("##RoomNavSouth", ImGuiDir_Down, south,
506 make_tooltip(south, "South"));
507 ImGui::SameLine();
508 nav_button("##RoomNavEast", ImGuiDir_Right, east, make_tooltip(east, "East"));
509 ImGui::EndGroup();
510 ImGui::PopID();
511}
512
514 int room_id) {
515 ImGui::AlignTextToFramePadding();
516 ImGui::Text(ICON_MD_TUNE " %03X", room_id);
517 if (room.HasUnsavedChanges()) {
518 ImGui::SameLine(0, 6);
519 ImGui::TextColored(gui::ConvertColorToImVec4(
520 gui::ThemeManager::Get().GetCurrentTheme().warning),
521 ICON_MD_EDIT " Pending");
522 if (ImGui::IsItemHovered()) {
523 ImGui::SetTooltip(tr(
524 "Room changes are pending in the editor. Apply Room writes them to "
525 "the loaded ROM buffer."));
526 }
527 }
528 ImGui::SameLine();
529
530 if (pin_callback_) {
532 is_pinned_ ? "Unpin Room" : "Pin Room",
533 gui::ScaledSize(30.0f, 30.0f), is_pinned_)) {
535 }
536 ImGui::SameLine();
537 }
538
541 show_room_details_ ? "Hide Details" : "Show Details")) {
543 }
544 ImGui::SameLine();
546
547 DrawDungeonRoomPropertyFields(*this, room, room_id,
549
550 if (show_room_details_) {
551 ImGui::TextDisabled(tr("Floor: %d | Effect: %d | Tag1: %d | Tag2: %d"),
552 room.floor1(), room.effect(), room.tag1(), room.tag2());
553 if (ImGui::CollapsingHeader(tr("Chest contents"))) {
554 DrawDungeonChestEditor(room_id, room, *this);
555 }
556 }
557}
558
560 if (!CanNavigateRooms() || recently_visited_rooms_.size() <= 1) {
561 return;
562 }
563
564 ImGui::PushID("RecentRooms");
565 ImGui::TextDisabled(ICON_MD_HISTORY);
566 if (ImGui::IsItemHovered()) {
567 ImGui::SetTooltip(tr("Recently visited rooms"));
568 }
569
570 int rendered = 0;
571 for (int recent_room : recently_visited_rooms_) {
572 if (recent_room == room_id) {
573 continue;
574 }
575 ImGui::SameLine(0, 3);
576 const std::string button_label =
577 absl::StrFormat("%03X##RecentRoom%d", recent_room, rendered);
578 if (ImGui::SmallButton(button_label.c_str())) {
579 NavigateToRoom(recent_room);
581 }
582 if (ImGui::IsItemHovered()) {
583 ImGui::SetTooltip(
584 "[%03X] %s", recent_room,
585 dungeon_project_labels::GetRoomLabel(project_, recent_room).c_str());
586 }
587 ++rendered;
588 }
589 ImGui::PopID();
590 if (rendered > 0) {
591 ImGui::SameLine();
592 }
593}
594
596 DrawDungeonLayerControls(*this, room_id, ImGui::GetFrameHeight());
597 ImGui::SameLine();
598 if (ImGui::Button(tr("View")))
599 ImGui::OpenPopup("##RoomViewOptions");
600 if (ImGui::BeginPopup("##RoomViewOptions")) {
602 ImGui::EndPopup();
603 }
604}
605
607 int room_id) {
608 auto& interaction = object_interaction_;
609
610 interaction.SetLayersMerged(GetRoomLayerManager(room_id).AreLayersMerged());
611 int current_filter = interaction.GetLayerFilter();
612
613 auto radio = [&](const char* label, int filter) {
614 if (ImGui::RadioButton(label, current_filter == filter)) {
615 interaction.SetLayerFilter(filter);
616 }
617 ImGui::SameLine();
618 };
619
620 radio("All", ObjectSelection::kLayerAll);
621 radio("L1", ObjectSelection::kLayer1);
622 radio("L2", ObjectSelection::kLayer2);
623 radio("L3", ObjectSelection::kLayer3);
624}
625
626} // namespace yaze::editor
bool is_loaded() const
Definition rom.h:199
absl::Status LoadAndRenderRoomGraphics(int room_id)
absl::Status EditRoomMetadata(int room_id, const RoomMetadataEdit &edit)
DungeonObjectInteraction object_interaction_
const project::YazeProject * project_
std::function< void(bool)> pin_callback_
void DrawLayerControls(zelda3::Room &room, int room_id)
zelda3::RoomLayerManager & GetRoomLayerManager(int room_id)
const project::YazeProject * project() const
void DrawRoomHeader(zelda3::Room &room, int room_id)
std::function< void(int)> room_navigation_callback_
void DisplayObjectInfo(const gui::CanvasRuntime &rt, const zelda3::RoomObject &object, int canvas_x, int canvas_y)
std::function< void(int, int)> room_swap_callback_
void DrawRoomPropertyTable(zelda3::Room &room, int room_id)
zelda3::Room * TryEnsureRoom(int room_id)
static constexpr int kLayerAll
RAII scope that enables automatic widget registration.
static ThemeManager & Get()
uint16_t message_id() const
Definition room.h:1029
uint8_t blockset() const
Definition room.h:1015
bool HasUnsavedChanges() const
Definition room.h:662
void ReloadGraphics(std::optional< uint8_t > entrance_blockset=std::nullopt)
Definition room.cc:1047
TagKey tag2() const
Definition room.h:988
uint8_t floor2() const
Definition room.h:1042
uint8_t palette() const
Definition room.h:1019
TagKey tag1() const
Definition room.h:987
CollisionKey collision() const
Definition room.h:989
uint8_t spriteset() const
Definition room.h:1018
EffectKey effect() const
Definition room.h:986
uint8_t floor1() const
Definition room.h:1041
int ResolveDungeonPaletteId() const
Definition room.cc:921
background2 bg2() const
Definition room.h:985
uint8_t layout_id() const
Definition room.h:1026
#define ICON_MD_EXPAND_LESS
Definition icons.h:702
#define ICON_MD_TUNE
Definition icons.h:2022
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_SELECT_ALL
Definition icons.h:1680
#define ICON_MD_PUSH_PIN
Definition icons.h:1529
#define ICON_MD_EXPAND_MORE
Definition icons.h:703
#define ICON_MD_HISTORY
Definition icons.h:946
#define LOG_DEBUG(category, format,...)
Definition log.h:133
#define LOG_ERROR(category, format,...)
Definition log.h:140
std::string GetRoomTagLabel(const project::YazeProject *project, int id)
std::string GetRoomLabel(const project::YazeProject *project, int room_id)
Editors are the view controllers for the application.
void DrawDungeonOverlayControls(DungeonCanvasViewer &viewer)
int NeighborRoomId(int room_id, zelda3::DoorDirection dir)
void DrawDungeonDestinationEditor(DungeonCanvasViewer &viewer)
void DrawDungeonRoomPropertyFields(DungeonCanvasViewer &viewer, zelda3::Room &room, int room_id, RoomPropertyLayout layout, const std::function< void()> &draw_pit_damage)
void DrawDungeonChestEditor(int room_id, zelda3::Room &room, DungeonCanvasViewer &viewer)
void DrawDungeonLayerControls(DungeonCanvasViewer &viewer, int room_id, float height)
bool ThemedIconButton(const char *icon, const char *tooltip, const ImVec2 &size, bool is_active, bool is_disabled, const char *panel_id, const char *anim_id)
Draw a standard icon button with theme-aware colors.
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:140
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
ImVec2 ScaledSize(float base_width, float base_height)
Returns a DPI-scaled version of a fixed pixel size.
Definition ui_config.h:148
void DrawText(const CanvasRuntime &rt, const std::string &text, int x, int y)
bool InputScalarDeferred(const char *label, ImGuiDataType data_type, void *data, const char *format, ImGuiInputTextFlags flags, InputScalarTargetIdentity target_identity)
Definition input.cc:360
constexpr int kMaxDungeonSpriteset
gfx::PaletteGroup BuildDungeonRenderPaletteGroupFromGameData(const gfx::SnesPalette &dungeon_palette, const GameData *game_data)
Definition room.cc:191
std::string GetObjectName(int object_id)
constexpr int kNumberOfRooms
const std::string RoomEffect[8]
Definition room.cc:270
@ South
Bottom wall (horizontal door, 4x3 tiles)
@ North
Top wall (horizontal door, 4x3 tiles)
@ East
Right wall (vertical door, 3x4 tiles)
@ West
Left wall (vertical door, 3x4 tiles)
Draw a scalar editor that commits the model value atomically.
Definition input.h:61
gfx::PaletteGroupMap palette_groups
Definition game_data.h:95
Automatic widget registration helpers for ImGui Test Engine integration.