yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
room_matrix_content.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_DUNGEON_WORKSPACE_ROOM_MATRIX_CONTENT_H_
2#define YAZE_APP_EDITOR_DUNGEON_WORKSPACE_ROOM_MATRIX_CONTENT_H_
3
4#include <algorithm>
5#include <cctype>
6#include <cmath>
7#include <functional>
8#include <optional>
9#include <string>
10#include <vector>
11#include "util/i18n/tr.h"
12
13#include "absl/strings/str_format.h"
24#include "app/gui/core/icons.h"
25#include "imgui/imgui.h"
26#include "zelda3/dungeon/room.h"
29
30namespace yaze {
31namespace editor {
32
50 public:
58 RoomMatrixContent(int* current_room_id, ImVector<int>* active_rooms,
59 std::function<void(int)> on_room_selected,
60 std::function<void(int, int)> on_room_swap = nullptr,
61 DungeonRoomStore* rooms = nullptr)
62 : current_room_id_(current_room_id),
63 active_rooms_(active_rooms),
64 rooms_(rooms),
65 on_room_selected_(std::move(on_room_selected)),
66 on_room_swap_(std::move(on_room_swap)) {}
67
68 // ==========================================================================
69 // WindowContent Identity
70 // ==========================================================================
71
72 std::string GetId() const override { return "dungeon.room_matrix"; }
73 std::string GetDisplayName() const override { return "Room Matrix"; }
74 std::string GetIcon() const override { return ICON_MD_GRID_VIEW; }
75 std::string GetEditorCategory() const override { return "Dungeon"; }
76 int GetPriority() const override { return 30; }
77 std::string GetWorkflowGroup() const override { return "Core"; }
78 float GetPreferredWidth() const override { return 440.0f; }
79
81 std::function<void(int, RoomSelectionIntent)> callback) {
82 on_room_intent_ = std::move(callback);
83 }
84
85 void SetRenderContextCallback(std::function<void(int)> callback) {
86 prepare_render_context_ = std::move(callback);
87 }
88
89 // Project dungeon ownership and warp tags for the census overlay.
95 // The window manager can retain this panel after its editor is destroyed.
97 census_.SetEnabled(false);
99 SetRooms(nullptr);
100 current_room_id_ = nullptr;
101 active_rooms_ = nullptr;
103 on_room_swap_ = {};
104 on_room_intent_ = {};
107 }
109 if (!navigation_shortcut_focus_ || ImGui::GetCurrentContext() == nullptr) {
110 return false;
111 }
112 return navigation_shortcut_last_draw_frame_ >= ImGui::GetFrameCount() - 1;
113 }
114
115 // ==========================================================================
116 // WindowContent Drawing
117 // ==========================================================================
118
119 void Draw(bool* p_open) override {
121 return;
122 navigation_shortcut_last_draw_frame_ = ImGui::GetFrameCount();
124 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows);
125
126 const auto& theme = AgentUI::GetTheme();
127
128 // 16 wide x 19 tall = 304 cells (296 rooms + 8 empty)
129 constexpr int kRoomsPerRow = 16;
130 constexpr int kRoomsPerCol = 19;
131 constexpr int kTotalRooms = 0x128; // 296 rooms (0x00-0x127)
132 constexpr float kCellSpacing = 1.0f;
133
134 Rom* census_rom = rooms_ ? rooms_->rom() : nullptr;
135 census_.Update(census_rom);
136 DrawMatrixHeader(census_rom);
137 const bool census_on = census_.enabled() && census_.census() != nullptr;
138
139 const ImVec2 avail = ImGui::GetContentRegionAvail();
140 const float panel_width = std::max(1.0f, avail.x);
141 const float panel_height =
142 std::max(1.0f, avail.y - ImGui::GetStyle().ItemSpacing.y);
143 const float cell_size_by_width =
144 (panel_width - kCellSpacing * (kRoomsPerRow - 1)) / kRoomsPerRow;
145 const float cell_size_by_height =
146 (panel_height - kCellSpacing * (kRoomsPerCol - 1)) / kRoomsPerCol;
147 const float cell_size = std::max(
148 1.0f, std::floor(std::min({cell_size_by_width, cell_size_by_height,
149 24.0f * ImGui::GetFontSize() / 13.0f})));
150
151 const float grid_width =
152 kRoomsPerRow * cell_size + kCellSpacing * (kRoomsPerRow - 1);
153 const float grid_height =
154 kRoomsPerCol * cell_size + kCellSpacing * (kRoomsPerCol - 1);
155 const float x_offset = std::max(0.0f, (panel_width - grid_width) * 0.5f);
156 const float y_offset = std::max(0.0f, (panel_height - grid_height) * 0.5f);
157
158 ImDrawList* draw_list = ImGui::GetWindowDrawList();
159 const ImVec2 grid_origin = ImGui::GetCursorScreenPos();
160 ImVec2 canvas_pos = grid_origin;
161 canvas_pos.x += x_offset;
162 canvas_pos.y += y_offset;
163
164 int room_index = 0;
165 for (int row = 0; row < kRoomsPerCol; row++) {
166 for (int col = 0; col < kRoomsPerRow; col++) {
167 int room_id = room_index;
168 bool is_valid_room = (room_id < kTotalRooms);
169 const bool matches_filter =
170 MatchesSearchFilter(room_id) &&
171 (!census_on || census_.MatchesChips(room_id));
172
173 ImVec2 cell_min =
174 ImVec2(canvas_pos.x + col * (cell_size + kCellSpacing),
175 canvas_pos.y + row * (cell_size + kCellSpacing));
176 ImVec2 cell_max =
177 ImVec2(cell_min.x + cell_size, cell_min.y + cell_size);
178
179 if (is_valid_room) {
180 // Keep the palette hue stable whether a room is loaded or unopened.
181 ImU32 bg_color = census_on ? census_.FillColor(room_id)
182 : GetRoomColor(room_id, theme);
183 if (!matches_filter) {
184 bg_color = BlendRoomColor(
185 bg_color, ImGui::ColorConvertFloat4ToU32(theme.panel_bg_darker),
186 0.72f);
187 }
188
189 bool is_current = (*current_room_id_ == room_id);
190 bool is_open = rooms_ && rooms_->GetIfLoaded(room_id);
191 for (int i = 0; i < active_rooms_->Size; i++) {
192 if ((*active_rooms_)[i] == room_id) {
193 is_open = true;
194 break;
195 }
196 }
197
198 if ((is_open || is_current) && matches_filter) {
199 ImVec4 color = ImGui::ColorConvertU32ToFloat4(bg_color);
200 float h, s, v;
201 ImGui::ColorConvertRGBtoHSV(color.x, color.y, color.z, h, s, v);
202 ImGui::ColorConvertHSVtoRGB(h, s, v + (1.0f - v) * 0.22f, color.x,
203 color.y, color.z);
204 bg_color = ImGui::ColorConvertFloat4ToU32(color);
205 }
206 draw_list->AddRectFilled(cell_min, cell_max, bg_color);
207 // An inset outline stays inside the cell, including the last row.
208 if (is_current || is_open) {
209 const ImU32 outline =
210 is_current ? ImGui::ColorConvertFloat4ToU32(
211 theme.dungeon_selection_primary)
212 : IM_COL32(255, 255, 255, matches_filter ? 130 : 45);
213 draw_list->AddRect(ImVec2(cell_min.x + 1, cell_min.y + 1),
214 ImVec2(cell_max.x - 1, cell_max.y - 1), outline,
215 0, 0, is_current ? 2.0f : 1.0f);
216 }
217
218 if (census_on) {
219 DrawCensusCellMarks(draw_list, room_id, cell_min, cell_max,
220 matches_filter, theme);
221 }
222
223 // Scale the three-digit IDs to the actual cell; never spill into
224 // adjacent rooms. Tiny docks retain full IDs in the hover tooltip.
225 if (cell_size >= 14.0f) {
226 const std::string label = absl::StrFormat("%03X", room_id);
227 const ImVec2 normal_size = ImGui::CalcTextSize(label.c_str());
228 const float scale =
229 std::min(1.0f, (cell_size - 2.0f) / normal_size.x);
230 const ImVec2 text_pos(
231 cell_min.x + (cell_size - normal_size.x * scale) * 0.5f,
232 cell_min.y + (cell_size - normal_size.y * scale) * 0.5f);
233 const ImVec4 color = ImGui::ColorConvertU32ToFloat4(bg_color);
234 const float luminance =
235 color.x * 0.2126f + color.y * 0.7152f + color.z * 0.0722f;
236 const ImU32 ink = luminance > 0.55f ? IM_COL32(15, 15, 15, 255)
237 : IM_COL32(245, 245, 245, 255);
238 draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize() * scale,
239 text_pos, ink, label.c_str());
240 }
241
242 // Handle clicks
243 ImGui::SetCursorScreenPos(cell_min);
244 char btn_id[32];
245 snprintf(btn_id, sizeof(btn_id), "##room%d", room_id);
246 ImGui::InvisibleButton(btn_id, ImVec2(cell_size, cell_size));
248 absl::StrFormat("Room 0x%03X", room_id));
249
250 if (ImGui::IsItemClicked()) {
251 if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
252 // Double-click: open as standalone panel
253 if (on_room_intent_) {
255 } else if (on_room_selected_) {
256 on_room_selected_(room_id);
257 }
258 } else if (on_room_selected_) {
259 on_room_selected_(room_id);
260 }
261 }
262
263 gui::ItemContextMenu(nullptr, [&, room_id]() {
264 const bool can_swap =
266 *current_room_id_ < kTotalRooms && *current_room_id_ != room_id;
267
268 std::vector<gui::MenuItemSpec> items;
269 items.emplace_back(is_open ? "Focus Room" : "Open in Workbench",
270 ICON_MD_ARROW_FORWARD, [this, room_id]() {
271 if (on_room_intent_) {
273 room_id,
275 } else if (on_room_selected_) {
276 on_room_selected_(room_id);
277 }
278 });
279 items.emplace_back(
280 tr("Open as Panel"), ICON_MD_OPEN_IN_NEW, [this, room_id]() {
281 if (on_room_intent_) {
282 on_room_intent_(room_id,
284 } else if (on_room_selected_) {
285 on_room_selected_(room_id);
286 }
287 });
288 items.back().separator_after = true;
289
290 items.push_back(gui::CopyToClipboardItem(
291 tr("Copy Room ID"), absl::StrFormat("0x%03X", room_id)));
292 items.push_back(gui::CopyToClipboardItem(
293 tr("Copy Room Name"), zelda3::GetRoomLabel(room_id)));
294 items.back().separator_after = true;
295
296 items.push_back(gui::MenuItemSpec::Conditional(
297 tr("Swap With Current Room"),
298 [this, room_id]() {
300 },
301 [can_swap]() { return can_swap; }));
302 items.back().icon = ICON_MD_SWAP_HORIZ;
303 return items;
304 });
305
306 // Tooltip with room info and thumbnail preview
307 if (ImGui::IsItemHovered()) {
308 ImGui::BeginTooltip();
309 // Use unified ResourceLabelProvider for room names
310 ImGui::Text("%s", zelda3::GetRoomLabel(room_id).c_str());
311 ImGui::TextDisabled(tr("Room 0x%02X"), room_id);
312 if (census_on) {
313 ImGui::Separator();
314 census_.DrawTooltip(room_id);
315 ImGui::Separator();
316 }
317
318 if (is_current) {
319 ImGui::TextColored(theme.dungeon_selection_primary,
320 ICON_MD_MY_LOCATION " Current workbench room");
321 } else if (is_open) {
322 ImGui::TextColored(theme.status_success,
323 ICON_MD_TAB " Open in editor");
324 }
325
326 if (rooms_) {
327 auto* loaded_room = rooms_->GetIfLoaded(room_id);
328 if (loaded_room != nullptr) {
329 // Show palette info
330 ImGui::TextDisabled(tr("Palette: %d | Blockset: %d"),
331 loaded_room->palette(),
332 loaded_room->blockset());
333
334 // Show thumbnail preview of the room
337 auto& preview_bitmap = PrepareCanonicalRoomComposite(
338 *loaded_room, tooltip_composite_output_);
341 if (preview_bitmap.is_active() &&
342 preview_bitmap.texture() != 0) {
343 ImGui::Separator();
344 // Render at thumbnail size (80x80 from 512x512)
345 constexpr float kThumbnailSize = 80.0f;
346 ImGui::Image((ImTextureID)(intptr_t)preview_bitmap.texture(),
347 ImVec2(kThumbnailSize, kThumbnailSize));
348 }
349 }
350 }
351
352 ImGui::Separator();
353 ImGui::TextDisabled(tr("Click to %s"),
354 (is_open || is_current) ? "focus" : "open");
355 ImGui::TextDisabled(tr("Double-click to open as panel"));
356 ImGui::TextDisabled(tr("Right-click for actions"));
357 ImGui::EndTooltip();
358 }
359 } else {
360 // Empty cell
361 draw_list->AddRectFilled(
362 cell_min, cell_max,
363 ImGui::ColorConvertFloat4ToU32(theme.panel_bg_darker));
364 }
365
366 room_index++;
367 }
368 }
369
370 // Cell buttons move the cursor. Reserve the grid once from its origin,
371 // rather than adding another full grid below the last cell.
372 ImGui::SetCursorScreenPos(grid_origin);
373 ImGui::Dummy(ImVec2(panel_width, grid_height + y_offset));
374 }
375
377 if (rooms_ != rooms) {
378 rooms_ = rooms;
381 }
382 }
383
384 private:
385 std::function<void(int)> prepare_render_context_;
387 const float button_width = ImGui::GetFrameHeight();
388 const float spacing = ImGui::GetStyle().ItemSpacing.x;
389 const bool has_filter = search_filter_[0] != '\0';
390 ImGui::SetNextItemWidth(
391 std::max(1.0f, ImGui::GetContentRegionAvail().x -
392 (button_width + spacing) * (has_filter ? 2 : 1)));
393 ImGui::InputTextWithHint("##RoomSearch", "Room ID or name...",
394 search_filter_, IM_ARRAYSIZE(search_filter_));
395 if (has_filter) {
396 ImGui::SameLine();
397 if (ImGui::Button(ICON_MD_CLOSE "##ClearFilter", ImVec2(button_width, 0)))
398 search_filter_[0] = '\0';
399 if (ImGui::IsItemHovered())
400 ImGui::SetTooltip(tr("Clear room filter"));
401 }
402 ImGui::SameLine();
403 if (ImGui::Button(ICON_MD_MORE_HORIZ "##MatrixOptions",
404 ImVec2(button_width, 0)))
405 ImGui::OpenPopup("##MatrixOptionsPopup");
406 gui::AutoRegisterLastItem("button", "Room matrix options");
407 if (ImGui::IsItemHovered())
408 ImGui::SetTooltip(tr("Room colors and census"));
409 if (ImGui::BeginPopup("##MatrixOptionsPopup")) {
410 ImGui::TextDisabled("Room palette colors (same swatch as ZScream)");
411 ImGui::TextUnformatted("Brighter + thin outline: open room");
412 ImGui::TextUnformatted("Accent outline: current room");
413 ImGui::Separator();
415 ImGui::EndPopup();
416 }
417 const std::string caption = absl::StrFormat(
419 // Clip long custom names to one line, with the full name on hover.
420 const ImVec2 pos = ImGui::GetCursorScreenPos();
421 const ImVec2 size(ImGui::GetContentRegionAvail().x,
422 ImGui::GetTextLineHeight());
423 auto* draw = ImGui::GetWindowDrawList();
424 draw->PushClipRect(pos, ImVec2(pos.x + size.x, pos.y + size.y), true);
425 draw->AddText(pos, ImGui::GetColorU32(ImGuiCol_TextDisabled),
426 caption.c_str());
427 draw->PopClipRect();
428 ImGui::Dummy(size);
429 if (ImGui::IsItemHovered()) {
430 ImGui::BeginTooltip();
431 ImGui::TextUnformatted(caption.c_str());
432 ImGui::TextDisabled("%d loaded rooms",
433 rooms_ ? static_cast<int>(rooms_->LoadedCount())
434 : active_rooms_->Size);
435 if (const auto meta = GetRoomMetadata(*current_room_id_))
436 ImGui::TextDisabled("Palette %02X / Room GFX %02X", meta->first,
437 meta->second);
438 ImGui::TextDisabled(
439 "Click a room to open. Double-click for a separate panel.");
440 ImGui::EndTooltip();
441 }
442 }
443
444 // Census marks: free/reclaimable outline, largest-free-block halo, orphan
445 // corner.
446 void DrawCensusCellMarks(ImDrawList* draw_list, int room_id,
447 const ImVec2& cell_min, const ImVec2& cell_max,
448 bool matches_filter,
449 const AgentUITheme& theme) const {
450 const ImU32 dim_target =
451 ImGui::ColorConvertFloat4ToU32(theme.panel_bg_darker);
452 if (census_.InLargestFreeBlock(room_id)) {
453 draw_list->AddRect(
454 ImVec2(cell_min.x - 1.5f, cell_min.y - 1.5f),
455 ImVec2(cell_max.x + 1.5f, cell_max.y + 1.5f),
456 RoomMatrixCensusOverlay::BlockHaloColor(matches_filter ? 0.5f : 0.2f),
457 0.0f, 0, 2.0f);
458 }
459 if (auto outline = census_.StatusOutline(room_id); outline.has_value()) {
460 ImU32 color = *outline;
461 if (!matches_filter) {
462 color = BlendRoomColor(color, dim_target, 0.55f);
463 }
464 draw_list->AddRect(ImVec2(cell_min.x + 1.0f, cell_min.y + 1.0f),
465 ImVec2(cell_max.x - 1.0f, cell_max.y - 1.0f), color,
466 0.0f, 0, 2.0f);
467 }
468 if (census_.IsOrphan(room_id)) {
469 const float corner = std::max(4.0f, (cell_max.x - cell_min.x) * 0.3f);
471 if (!matches_filter) {
472 color = BlendRoomColor(color, dim_target, 0.55f);
473 }
474 draw_list->AddTriangleFilled(ImVec2(cell_max.x - corner, cell_min.y),
475 ImVec2(cell_max.x, cell_min.y),
476 ImVec2(cell_max.x, cell_min.y + corner),
477 color);
478 }
479 }
480
481 bool MatchesSearchFilter(int room_id) const {
482 if (search_filter_[0] == '\0') {
483 return true;
484 }
485
486 const std::string filter = NormalizeForSearch(search_filter_);
487 char id_buf[16];
488 snprintf(id_buf, sizeof(id_buf), "%02X", room_id);
489 char hex_buf[16];
490 snprintf(hex_buf, sizeof(hex_buf), "0x%02X", room_id);
491
492 const std::string room_label =
494 const std::string id_text = NormalizeForSearch(id_buf);
495 const std::string hex_text = NormalizeForSearch(hex_buf);
496 return room_label.find(filter) != std::string::npos ||
497 id_text.find(filter) != std::string::npos ||
498 hex_text.find(filter) != std::string::npos;
499 }
500
501 static std::string NormalizeForSearch(const std::string& value) {
502 std::string lowered;
503 lowered.reserve(value.size());
504 for (unsigned char ch : value) {
505 lowered.push_back(static_cast<char>(std::tolower(ch)));
506 }
507 return lowered;
508 }
509
510 static ImU32 BlendRoomColor(ImU32 source, ImU32 target, float blend) {
511 ImVec4 src = ImGui::ColorConvertU32ToFloat4(source);
512 ImVec4 dst = ImGui::ColorConvertU32ToFloat4(target);
513 src.x = (src.x * (1.0f - blend)) + (dst.x * blend);
514 src.y = (src.y * (1.0f - blend)) + (dst.y * blend);
515 src.z = (src.z * (1.0f - blend)) + (dst.z * blend);
516 src.w = 1.0f;
517 return ImGui::ColorConvertFloat4ToU32(src);
518 }
519
520 std::optional<std::pair<int, int>> GetRoomMetadata(int room_id) const {
521 if (!rooms_ || room_id < 0 ||
522 room_id >= static_cast<int>(DungeonRoomStore::kRoomCount)) {
523 return std::nullopt;
524 }
525
526 if (const auto* room = rooms_->GetIfLoaded(room_id); room != nullptr) {
527 return std::make_pair(static_cast<int>(room->palette()),
528 static_cast<int>(room->blockset()));
529 }
530
531 Rom* rom = rooms_->rom();
532 if (rom == nullptr || !rom->is_loaded()) {
533 return std::nullopt;
534 }
535
536 zelda3::Room header_room = zelda3::LoadRoomHeaderFromRom(rom, room_id);
537 return std::make_pair(static_cast<int>(header_room.palette()),
538 static_cast<int>(header_room.blockset()));
539 }
540
541 // ZScream's MapPicturebox uses CGRAM [4, 2]: the fourth opaque
542 // color in the first dungeon row (stored index 3; transparent is implicit).
543 // Resolve the palette through the same two-level lookup as Room rendering.
544 // Header-only reads avoid materializing/rendering all 296 rooms, and reading
545 // GameData each frame keeps unsaved palette edits visible immediately.
546 ImU32 GetRoomColor(int room_id, const AgentUITheme& theme) const {
547 if (rooms_ && rooms_->rom() && rooms_->rom()->is_loaded() &&
548 rooms_->game_data() && room_id >= 0 &&
549 room_id < static_cast<int>(DungeonRoomStore::kRoomCount)) {
550 const auto& palettes = rooms_->game_data()->palette_groups.dungeon_main;
551 if (!palettes.empty()) {
552 int palette_id;
553 if (const auto* room = rooms_->GetIfLoaded(room_id)) {
554 palette_id = room->ResolveDungeonPaletteId();
555 } else {
556 auto header = zelda3::LoadRoomHeaderFromRom(rooms_->rom(), room_id);
557 header.SetGameData(rooms_->game_data());
558 palette_id = header.ResolveDungeonPaletteId();
559 }
560 const auto& palette = palettes.palette_ref(palette_id);
561 if (palette.size() > 3) {
562 const auto color = palette[3].rgb();
563 return IM_COL32(color.x, color.y, color.z, 255);
564 }
565 }
566 }
567 return ImGui::ColorConvertFloat4ToU32(theme.panel_bg_color);
568 }
569
570 int* current_room_id_ = nullptr;
571 ImVector<int>* active_rooms_ = nullptr;
573 std::function<void(int)> on_room_selected_;
574 std::function<void(int, int)> on_room_swap_;
575 std::function<void(int, RoomSelectionIntent)> on_room_intent_;
580 char search_filter_[64] = "";
581};
582
583} // namespace editor
584} // namespace yaze
585
586#endif // YAZE_APP_EDITOR_DUNGEON_WORKSPACE_ROOM_MATRIX_CONTENT_H_
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:49
bool is_loaded() const
Definition rom.h:187
static constexpr size_t kRoomCount
zelda3::Room * GetIfLoaded(int room_id)
zelda3::GameData * game_data() const
"Census" overlay for the Room Matrix.
const zelda3::RoomCensus * census() const
std::function< const core::HackManifest *()> ManifestProvider
std::optional< ImU32 > StatusOutline(int room_id) const
void SetManifestProvider(ManifestProvider provider)
WindowContent for displaying a visual 16x19 grid of all dungeon rooms.
std::function< void(int)> prepare_render_context_
std::function< void(int)> on_room_selected_
static std::string NormalizeForSearch(const std::string &value)
std::function< void(int, RoomSelectionIntent)> on_room_intent_
void SetCensusManifestProvider(RoomMatrixCensusOverlay::ManifestProvider provider)
static ImU32 BlendRoomColor(ImU32 source, ImU32 target, float blend)
std::string GetIcon() const override
Material Design icon for this panel.
std::optional< std::pair< int, int > > GetRoomMetadata(int room_id) const
void SetRooms(DungeonRoomStore *rooms)
std::string GetEditorCategory() const override
Editor category this panel belongs to.
void DrawCensusCellMarks(ImDrawList *draw_list, int room_id, const ImVec2 &cell_min, const ImVec2 &cell_max, bool matches_filter, const AgentUITheme &theme) const
float GetPreferredWidth() const override
Get preferred width for this panel (optional)
std::string GetWorkflowGroup() const override
Optional workflow group for hack-centric actions.
int GetPriority() const override
Get display priority for menu ordering.
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
RoomMatrixContent(int *current_room_id, ImVector< int > *active_rooms, std::function< void(int)> on_room_selected, std::function< void(int, int)> on_room_swap=nullptr, DungeonRoomStore *rooms=nullptr)
Construct a room matrix panel.
void Draw(bool *p_open) override
Draw the panel content.
bool MatchesSearchFilter(int room_id) const
std::string GetId() const override
Unique identifier for this panel.
std::function< void(int, int)> on_room_swap_
ImU32 GetRoomColor(int room_id, const AgentUITheme &theme) const
RoomCompositeOutput tooltip_composite_output_
RoomMatrixCensusOverlay & census_overlay()
void SetRenderContextCallback(std::function< void(int)> callback)
void SetRoomIntentCallback(std::function< void(int, RoomSelectionIntent)> callback)
Base interface for all logical window content components.
void ProcessTextureQueue(IRenderer *renderer)
Definition arena.cc:211
static Arena & Get()
Definition arena.cc:24
uint8_t blockset() const
Definition room.h:1015
uint8_t palette() const
Definition room.h:1019
#define ICON_MD_GRID_VIEW
Definition icons.h:897
#define ICON_MD_MY_LOCATION
Definition icons.h:1270
#define ICON_MD_ARROW_FORWARD
Definition icons.h:184
#define ICON_MD_SWAP_HORIZ
Definition icons.h:1896
#define ICON_MD_MORE_HORIZ
Definition icons.h:1241
#define ICON_MD_TAB
Definition icons.h:1930
#define ICON_MD_OPEN_IN_NEW
Definition icons.h:1354
#define ICON_MD_CLOSE
Definition icons.h:418
const AgentUITheme & GetTheme()
gfx::Bitmap & PrepareCanonicalRoomComposite(zelda3::Room &room, RoomCompositeOutput &output)
RoomSelectionIntent
Intent for room selection in the dungeon editor.
void EnsureCompositeBitmapTextureQueued(Bitmap &composite)
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
bool ItemContextMenu(const char *id, const std::function< std::vector< MenuItemSpec >()> &build, ImGuiPopupFlags flags)
Right-click menu for the last submitted ImGui item.
MenuItemSpec CopyToClipboardItem(const std::string &label, const std::string &text)
Room LoadRoomHeaderFromRom(Rom *rom, int room_id)
Definition room.cc:680
std::string GetRoomLabel(int id)
Convenience function to get a room label.
Centralized theme colors for Agent UI components.
Definition agent_theme.h:19
static CanvasMenuItem Conditional(const std::string &lbl, std::function< void()> cb, std::function< bool()> condition)
gfx::PaletteGroupMap palette_groups
Definition game_data.h:95
Automatic widget registration helpers for ImGui Test Engine integration.