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 <cstdint>
7#include <initializer_list>
8#include <optional>
9#include <string>
10
11#include "absl/status/status.h"
12#include "absl/strings/str_format.h"
21#include "app/gui/core/icons.h"
22#include "app/gui/core/input.h"
28#include "imgui/imgui.h"
29#include "util/log.h"
30#include "util/macro.h"
33
34namespace yaze::editor {
35
36namespace {
37
38const char* GetBg2ModeName(int value) {
39 static constexpr const char* kNames[] = {
40 "Off", "Parallax", "Dark", "On top", "Translucent",
41 "Addition", "Normal", "Transparent", "Dark room"};
42 constexpr int kNameCount = sizeof(kNames) / sizeof(kNames[0]);
43 return (value >= 0 && value < kNameCount) ? kNames[value] : "Unknown";
44}
45
46const char* GetCollisionName(int value) {
47 static constexpr const char* kNames[] = {"One", "Both", "Both + Scroll",
48 "Moving Floor", "Moving Water"};
49 constexpr int kNameCount = sizeof(kNames) / sizeof(kNames[0]);
50 return (value >= 0 && value < kNameCount) ? kNames[value] : "Unknown";
51}
52
53std::string GetLayer2ModeName(int value) {
54 // ZScream distinguishes the reserved mode 1 from Nothing (mode 0).
55 if (value == 1)
56 return "One";
57 return value >= 0 && value < 8 ? zelda3::RoomEffect[value] : "Unknown";
58}
59
60} // namespace
61
63 zelda3::Room& room, int room_id,
64 RoomPropertyLayout layout) {
65 auto* rooms = viewer.rooms();
66 if (!rooms || room_id < 0 || room_id >= static_cast<int>(rooms->size()))
67 return;
68 const bool compact = layout == RoomPropertyLayout::kCompact;
69 const bool stack_choices =
70 ImGui::GetContentRegionAvail().x < ImGui::GetFontSize() * 25.0f;
71 const ImGuiID error_id =
72 ImGui::GetID(absl::StrFormat("RoomMetadataError/%d", room_id).c_str());
73 // Combo selections run inside a popup window. Keep errors in the host pane.
74 auto* inspector_storage = ImGui::GetStateStorage();
75 const gui::InputScalarTargetIdentity identity{
76 reinterpret_cast<uintptr_t>(rooms), static_cast<uint64_t>(room_id)};
77 auto apply = [&](RoomMetadataField field, int value, int index = 0) {
78 const auto status = viewer.EditRoomMetadata(
79 room_id, {.field = field, .value = value, .index = index});
80 inspector_storage->SetBool(error_id, !status.ok());
81 };
82 auto begin_properties = [](const char* id, float label_width = 104.0f) {
83 if (!ImGui::BeginTable(
84 id, 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp)) {
85 return false;
86 }
87 ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed,
88 label_width);
89 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch, 1.0f);
90 return true;
91 };
92 auto property_row = [](const char* label) {
93 // Advance by one label/value pair; four-column tables pair short fields.
94 ImGui::TableNextColumn();
95 ImGui::AlignTextToFramePadding();
96 ImGui::TextUnformatted(label);
97 ImGui::TableNextColumn();
98 ImGui::SetNextItemWidth(-1);
99 };
100 auto draw_hex = [&](const char* label, const char* id, int value,
101 int max_value, RoomMetadataField field, int index = 0) {
102 property_row(label);
103 auto target = identity;
104 target.element = static_cast<uint64_t>(field);
105 target.component = static_cast<uint64_t>(index);
107 id, ImGuiDataType_S32, &value, max_value > 0xFF ? "%03X" : "%02X",
108 ImGuiInputTextFlags_CharsHexadecimal, target)) {
109 apply(field, value, index);
110 }
111 {
112 gui::AutoWidgetScope automation_scope(compact ? "Dungeon/RoomProperties"
113 : "Dungeon/Workbench");
114 gui::AutoRegisterLastItem("input_hex", id + 2, label);
115 }
116 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
117 const char* description = label;
119 description = "Sprite graphics set";
120 else if (field == RoomMetadataField::kFloor1)
121 description = "Background 1 floor pattern";
122 else if (field == RoomMetadataField::kFloor2)
123 description = "Background 2 floor pattern";
124 ImGui::SetTooltip("%s (hex 00-%X). Enter or leave the field to apply.",
125 description, max_value);
126 }
127 };
128 auto draw_choice = [&](const char* label, const char* id, int value,
129 int count, RoomMetadataField field, auto name) {
130 if (stack_choices) {
131 ImGui::TextUnformatted(label);
132 ImGui::SetNextItemWidth(-1);
133 } else {
134 property_row(label);
135 }
136 const std::string preview = name(value);
137 const bool open = ImGui::BeginCombo(id, preview.c_str());
138 {
139 gui::AutoWidgetScope automation_scope(compact ? "Dungeon/RoomProperties"
140 : "Dungeon/Workbench");
141 gui::AutoRegisterLastItem("combo", id + 2, label);
142 }
143 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
144 ImGui::SetTooltip("%s: %s (0x%02X)", label, preview.c_str(), value);
145 }
146 if (open) {
147 for (int option = 0; option < count; ++option) {
148 const std::string option_label = name(option);
149 ImGui::PushID(option);
150 if (ImGui::Selectable(option_label.c_str(), value == option)) {
151 apply(field, option);
152 }
153 {
154 gui::AutoWidgetScope automation_scope(
155 compact ? "Dungeon/RoomProperties" : "Dungeon/Workbench");
156 gui::AutoRegisterLastItem("selectable",
157 absl::StrFormat("%s/%d", id + 2, option));
158 }
159 if (value == option) {
160 ImGui::SetItemDefaultFocus();
161 }
162 if (ImGui::IsItemHovered())
163 ImGui::SetTooltip("%s (0x%02X)", option_label.c_str(), option);
164 ImGui::PopID();
165 }
166 ImGui::EndCombo();
167 }
168 };
169 auto choice_group = [&](const char* id, float label_width, auto draw) {
170 if (stack_choices) {
171 draw();
172 } else if (begin_properties(id, label_width)) {
173 draw();
174 ImGui::EndTable();
175 }
176 };
177 auto label_width = [](std::initializer_list<const char*> labels) {
178 float width = 0.0f;
179 for (const auto* label : labels)
180 width = std::max(width, ImGui::CalcTextSize(label).x);
181 return width;
182 };
183
184 ImGui::BeginDisabled(viewer.header_read_only() ||
186 if (compact) {
187 if (ImGui::BeginTable("##CompactRoomGraphics", 4,
188 ImGuiTableFlags_SizingStretchProp)) {
189 ImGui::TableSetupColumn("Property 1", ImGuiTableColumnFlags_WidthFixed,
190 label_width({"Layout", "Palette"}));
191 ImGui::TableSetupColumn("Value 1", ImGuiTableColumnFlags_WidthStretch);
192 ImGui::TableSetupColumn("Property 2", ImGuiTableColumnFlags_WidthFixed,
193 label_width({"Blockset", "Spriteset"}));
194 ImGui::TableSetupColumn("Value 2", ImGuiTableColumnFlags_WidthStretch);
195 draw_hex("Layout", "##Lyr", room.layout_id(), 0x07,
197 draw_hex("Blockset", "##BS", room.blockset(), 0x51,
199 draw_hex("Palette", "##Pal", room.palette(), 0x47,
201 draw_hex("Spriteset", "##SS", room.spriteset(),
203 ImGui::EndTable();
204 }
205 ImGui::EndDisabled();
206 if (inspector_storage->GetBool(error_id))
207 ImGui::TextWrapped(
208 "Edit not applied. Hover the field for its supported range.");
209 return;
210 }
211 choice_group("##WorkbenchRoomTags", label_width({"Tag 1", "Tag 2"}), [&] {
212 const auto tag_name = [&](int value) {
213 return dungeon_project_labels::GetRoomTagLabel(viewer.project(), value);
214 };
215 for (int index = 0; index < 2; ++index) {
216 const int tag = index == 0 ? room.tag1() : room.tag2();
217 draw_choice(
218 index == 0 ? "Tag 1" : "Tag 2",
219 index == 0 ? "##RoomHeaderTag1" : "##RoomHeaderTag2", tag, 0x40,
221 tag_name);
222 }
223 });
224
225 if (inspector_storage->GetBool(error_id)) {
226 ImGui::TextWrapped(
227 "Edit not applied. Check that this room is editable and the value "
228 "is within the field's supported range. Hover the field for its "
229 "range.");
230 }
231
232 ImGui::SeparatorText("Room properties");
233 if (ImGui::BeginTable(
234 "##WorkbenchRoomGraphics", 4,
235 ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp)) {
236 ImGui::TableSetupColumn("Property 1", ImGuiTableColumnFlags_WidthFixed,
237 label_width({"Layout", "Floor 1", "Palette"}));
238 ImGui::TableSetupColumn("Value 1", ImGuiTableColumnFlags_WidthStretch,
239 1.0f);
240 ImGui::TableSetupColumn("Property 2", ImGuiTableColumnFlags_WidthFixed,
241 label_width({"Blockset", "Floor 2", "Spriteset"}));
242 ImGui::TableSetupColumn("Value 2", ImGuiTableColumnFlags_WidthStretch,
243 1.0f);
244 draw_hex("Layout", "##RoomHeaderLayout", room.layout_id(), 0x07,
246 draw_hex("Blockset", "##RoomHeaderBlockset", room.blockset(), 0x51,
248 draw_hex("Floor 1", "##RoomHeaderFloor1", room.floor1(), 0x0F,
250 draw_hex("Floor 2", "##RoomHeaderFloor2", room.floor2(), 0x0F,
252 draw_hex("Palette", "##RoomHeaderPalette", room.palette(), 0x47,
254 draw_hex("Spriteset", "##RoomHeaderSpriteset", room.spriteset(),
256 ImGui::EndTable();
257 }
258 if (begin_properties("##WorkbenchRoomMessage", label_width({"Message"}))) {
259 draw_hex("Message", "##RoomHeaderMessage", room.message_id(), 0x0FFF,
261 ImGui::EndTable();
262 }
263 choice_group(
264 "##WorkbenchRoomHeader",
265 label_width({"Layer 2 type", "Layer 2 mode", "Collision"}), [&] {
266 draw_choice("Layer 2 type", "##RoomHeaderBg2",
267 static_cast<int>(room.bg2()), 9, RoomMetadataField::kBg2,
268 GetBg2ModeName);
269 draw_choice("Layer 2 mode", "##RoomHeaderEffect", room.effect(), 8,
270 RoomMetadataField::kEffect, GetLayer2ModeName);
271 draw_choice("Collision", "##RoomHeaderCollision", room.collision(), 5,
272 RoomMetadataField::kCollision, GetCollisionName);
273 });
274 ImGui::EndDisabled();
275}
276
278 const zelda3::RoomObject& object,
279 int canvas_x, int canvas_y) {
280 std::string name = zelda3::GetObjectName(object.id_);
281 std::string info_text;
282 if (object.id_ >= 0x100) {
283 info_text =
284 absl::StrFormat("0x%03X %s (X:%d Y:%d S:0x%02X)", object.id_,
285 name.c_str(), object.x_, object.y_, object.size_);
286 } else {
287 info_text =
288 absl::StrFormat("0x%02X %s (X:%d Y:%d S:0x%02X)", object.id_,
289 name.c_str(), object.x_, object.y_, object.size_);
290 }
291
292 gui::DrawText(rt, info_text, canvas_x, canvas_y - 12);
293}
294
296 LOG_DEBUG("[LoadAndRender]", "START room_id=%d", room_id);
297
298 if (room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
299 LOG_DEBUG("[LoadAndRender]", "ERROR: Invalid room ID");
300 return absl::InvalidArgumentError("Invalid room ID");
301 }
302
303 if (!rom_ || !rom_->is_loaded()) {
304 LOG_DEBUG("[LoadAndRender]", "ERROR: ROM not loaded");
305 return absl::FailedPreconditionError("ROM not loaded");
306 }
307
308 if (!rooms_) {
309 LOG_DEBUG("[LoadAndRender]", "ERROR: Room data not available");
310 return absl::FailedPreconditionError("Room data not available");
311 }
312
313 auto* room_ptr = rooms_->TryEnsureRoom(room_id);
314 if (!room_ptr) {
315 LOG_DEBUG("[LoadAndRender]", "ERROR: Room data unavailable");
316 return absl::InvalidArgumentError("Invalid room ID");
317 }
318 auto& room = *room_ptr;
319 LOG_DEBUG("[LoadAndRender]", "Got room reference");
320
321 if (!game_data_) {
322 LOG_ERROR("[LoadAndRender]", "GameData not available");
323 return absl::FailedPreconditionError("GameData not available");
324 }
325 const auto& dungeon_main = game_data_->palette_groups.dungeon_main;
326 if (!dungeon_main.empty()) {
328 static_cast<uint64_t>(room.ResolveDungeonPaletteId());
329
330 const auto& full_palette = dungeon_main[current_palette_group_id_];
332 full_palette, game_data_);
333 LOG_DEBUG("[LoadAndRender]", "Palette loaded: group_id=%zu",
335 }
336
337 LOG_DEBUG("[LoadAndRender]", "Calling room.RenderRoomGraphics()...");
338 room.ReloadGraphics(current_entrance_blockset_);
339 LOG_DEBUG("[LoadAndRender]",
340 "RenderRoomGraphics() complete - room buffers self-contained");
341
342 LOG_DEBUG("[LoadAndRender]", "SUCCESS");
343 return absl::OkStatus();
344}
345
347 ImGui::Separator();
348 if (header_read_only_) {
349 ImGui::BeginDisabled();
350 }
351
352 constexpr ImGuiTableFlags kPropsTableFlags =
353 ImGuiTableFlags_NoPadOuterX | ImGuiTableFlags_NoBordersInBody;
354
355 if (ImGui::BeginTable("##RoomPropsTable", 2, kPropsTableFlags)) {
356 const float nav_col_width = (ImGui::GetFrameHeight() * 4.0f) +
357 (ImGui::GetStyle().ItemSpacing.x * 3.0f) +
358 (ImGui::GetStyle().FramePadding.x * 2.0f);
359 ImGui::TableSetupColumn("NavCol", ImGuiTableColumnFlags_WidthFixed,
360 nav_col_width);
361 ImGui::TableSetupColumn("PropsCol", ImGuiTableColumnFlags_WidthStretch);
362
363 ImGui::TableNextRow();
364 ImGui::TableNextColumn();
365 DrawRoomNavigation(room_id);
366 ImGui::TableNextColumn();
367 DrawRoomPropertyTable(room, room_id);
368
370 ImGui::TableNextRow();
371 ImGui::TableNextColumn();
372 ImGui::TextDisabled(ICON_MD_SELECT_ALL " Select");
373 ImGui::TableNextColumn();
374 DrawLayerControls(room, room_id);
375 }
376
377 ImGui::EndTable();
378 }
379
380 if (header_read_only_) {
381 ImGui::EndDisabled();
382 }
384 ImGui::CollapsingHeader("Destinations##RoomDestinations")) {
386 }
387}
388
391 return;
392 }
393
394 auto room_if_valid = [](int candidate) -> std::optional<int> {
395 if (candidate < 0 || candidate >= zelda3::kNumberOfRooms) {
396 return std::nullopt;
397 }
398 return candidate;
399 };
400
401 const auto north =
402 room_if_valid(NeighborRoomId(room_id, zelda3::DoorDirection::North));
403 const auto south =
404 room_if_valid(NeighborRoomId(room_id, zelda3::DoorDirection::South));
405 const auto west =
406 room_if_valid(NeighborRoomId(room_id, zelda3::DoorDirection::West));
407 const auto east =
408 room_if_valid(NeighborRoomId(room_id, zelda3::DoorDirection::East));
409
410 auto make_tooltip = [&](const std::optional<int>& target,
411 const char* direction) -> std::string {
412 if (!target.has_value()) {
413 return "";
414 }
415 return absl::StrFormat(
416 "%s: [%03X] %s", direction, *target,
418 };
419
420 auto nav_button = [&](const char* id, ImGuiDir dir,
421 const std::optional<int>& target,
422 const std::string& tooltip) {
423 const bool enabled = target.has_value();
424 if (!enabled) {
425 ImGui::BeginDisabled();
426 }
427 const bool pressed = ImGui::ArrowButton(id, dir);
428 if (!enabled) {
429 ImGui::EndDisabled();
430 }
431 if (enabled && ImGui::IsItemHovered() && !tooltip.empty()) {
432 ImGui::SetTooltip("%s", tooltip.c_str());
433 }
434 if (pressed && enabled) {
436 room_swap_callback_(room_id, *target);
437 } else if (room_navigation_callback_) {
439 }
440 }
441 };
442
443 ImGui::PushID(room_id);
444 ImGui::BeginGroup();
445 nav_button("##RoomNavWest", ImGuiDir_Left, west, make_tooltip(west, "West"));
446 ImGui::SameLine();
447 nav_button("##RoomNavNorth", ImGuiDir_Up, north,
448 make_tooltip(north, "North"));
449 ImGui::SameLine();
450 nav_button("##RoomNavSouth", ImGuiDir_Down, south,
451 make_tooltip(south, "South"));
452 ImGui::SameLine();
453 nav_button("##RoomNavEast", ImGuiDir_Right, east, make_tooltip(east, "East"));
454 ImGui::EndGroup();
455 ImGui::PopID();
456}
457
459 int room_id) {
460 ImGui::AlignTextToFramePadding();
461 ImGui::Text(ICON_MD_TUNE " %03X", room_id);
462 if (room.HasUnsavedChanges()) {
463 ImGui::SameLine(0, 6);
464 ImGui::TextColored(gui::ConvertColorToImVec4(
465 gui::ThemeManager::Get().GetCurrentTheme().warning),
466 ICON_MD_EDIT " Pending");
467 if (ImGui::IsItemHovered()) {
468 ImGui::SetTooltip(tr(
469 "Room changes are pending in the editor. Apply Room writes them to "
470 "the loaded ROM buffer."));
471 }
472 }
473 ImGui::SameLine();
474
475 if (pin_callback_) {
477 is_pinned_ ? "Unpin Room" : "Pin Room",
478 gui::ScaledSize(30.0f, 30.0f), is_pinned_)) {
480 }
481 ImGui::SameLine();
482 }
483
486 show_room_details_ ? "Hide Details" : "Show Details")) {
488 }
489 ImGui::SameLine();
491
492 DrawDungeonRoomPropertyFields(*this, room, room_id,
494
495 if (show_room_details_) {
496 ImGui::TextDisabled(tr("Floor: %d | Effect: %d | Tag1: %d | Tag2: %d"),
497 room.floor1(), room.effect(), room.tag1(), room.tag2());
498 if (ImGui::CollapsingHeader(tr("Chest contents"))) {
499 DrawDungeonChestEditor(room_id, room, *this);
500 }
501 }
502}
503
505 if (!CanNavigateRooms() || recently_visited_rooms_.size() <= 1) {
506 return;
507 }
508
509 ImGui::PushID("RecentRooms");
510 ImGui::TextDisabled(ICON_MD_HISTORY);
511 if (ImGui::IsItemHovered()) {
512 ImGui::SetTooltip(tr("Recently visited rooms"));
513 }
514
515 int rendered = 0;
516 for (int recent_room : recently_visited_rooms_) {
517 if (recent_room == room_id) {
518 continue;
519 }
520 ImGui::SameLine(0, 3);
521 const std::string button_label =
522 absl::StrFormat("%03X##RecentRoom%d", recent_room, rendered);
523 if (ImGui::SmallButton(button_label.c_str())) {
524 NavigateToRoom(recent_room);
526 }
527 if (ImGui::IsItemHovered()) {
528 ImGui::SetTooltip(
529 "[%03X] %s", recent_room,
530 dungeon_project_labels::GetRoomLabel(project_, recent_room).c_str());
531 }
532 ++rendered;
533 }
534 ImGui::PopID();
535 if (rendered > 0) {
536 ImGui::SameLine();
537 }
538}
539
541 DrawDungeonLayerControls(*this, room_id, ImGui::GetFrameHeight());
542 ImGui::SameLine();
543 if (ImGui::Button(tr("View")))
544 ImGui::OpenPopup("##RoomViewOptions");
545 if (ImGui::BeginPopup("##RoomViewOptions")) {
547 ImGui::EndPopup();
548 }
549}
550
552 int room_id) {
553 auto& interaction = object_interaction_;
554
555 interaction.SetLayersMerged(GetRoomLayerManager(room_id).AreLayersMerged());
556 int current_filter = interaction.GetLayerFilter();
557
558 auto radio = [&](const char* label, int filter) {
559 if (ImGui::RadioButton(label, current_filter == filter)) {
560 interaction.SetLayerFilter(filter);
561 }
562 ImGui::SameLine();
563 };
564
565 radio("All", ObjectSelection::kLayerAll);
566 radio("L1", ObjectSelection::kLayer1);
567 radio("L2", ObjectSelection::kLayer2);
568 radio("L3", ObjectSelection::kLayer3);
569}
570
571} // namespace yaze::editor
bool is_loaded() const
Definition rom.h:187
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
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
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)
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:392
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:56
gfx::PaletteGroupMap palette_groups
Definition game_data.h:95
Automatic widget registration helpers for ImGui Test Engine integration.