yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_canvas_context_menu.cc
Go to the documentation of this file.
2
3#include <optional>
4#include <string>
5#include <utility>
6
7#include "absl/strings/str_format.h"
10#include "app/gui/core/icons.h"
11#include "imgui/imgui.h"
12#include "util/log.h"
16
17namespace yaze::editor {
18
24
27 return;
28 }
29
30 for (auto& item : BuildSelectionContextMenuItems(room_id)) {
31 canvas_.AddContextMenuItem(std::move(item));
32 }
33 auto insert_menu = BuildInsertContextMenu();
34 insert_menu.separator_after = true;
35 canvas_.AddContextMenuItem(insert_menu);
36}
37
53
55 auto enabled_if = [](bool enabled) {
56 return [enabled]() {
57 return enabled;
58 };
59 };
60
61 gui::CanvasMenuItem insert_menu;
62 insert_menu.label = "Insert";
63 insert_menu.icon = ICON_MD_ADD_CIRCLE;
64
65 gui::CanvasMenuItem insert_object_item("Object...", ICON_MD_WIDGETS,
66 [this]() {
69 }
70 });
71 insert_object_item.enabled_condition =
72 enabled_if(show_object_panel_callback_ != nullptr);
73 insert_menu.subitems.push_back(std::move(insert_object_item));
74
75 gui::CanvasMenuItem insert_sprite_item("Sprite...", ICON_MD_PERSON, [this]() {
78 }
79 });
80 insert_sprite_item.enabled_condition =
81 enabled_if(show_sprite_panel_callback_ != nullptr);
82 insert_menu.subitems.push_back(std::move(insert_sprite_item));
83
84 gui::CanvasMenuItem insert_item_item("Item...", ICON_MD_INVENTORY, [this]() {
87 }
88 });
89 insert_item_item.enabled_condition =
90 enabled_if(show_item_panel_callback_ != nullptr);
91 insert_menu.subitems.push_back(std::move(insert_item_item));
92
93 const bool door_mode = object_interaction_.IsDoorPlacementActive();
94 insert_menu.subitems.emplace_back(
95 door_mode ? "Cancel Door Placement" : "Door (Normal)", ICON_MD_DOOR_FRONT,
96 [this, door_mode]() {
99 });
100
101 return insert_menu;
102}
103
104std::optional<zelda3::RoomObject>
106 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
107 return std::nullopt;
108 }
109
110 const ImGuiIO& io = ImGui::GetIO();
111 const DungeonCanvasTransform transform(
113 const auto [canvas_x, canvas_y] =
114 transform.ScreenToRoomPixelCoordinates(io.MousePos);
115 if (!dungeon_coords::IsWithinBounds(canvas_x, canvas_y)) {
116 return std::nullopt;
117 }
118 const auto hovered_index = object_interaction_.entity_coordinator()
119 .tile_handler()
120 .GetEntityAtPosition(canvas_x, canvas_y);
121 if (!hovered_index.has_value()) {
122 return std::nullopt;
123 }
124
125 const auto& objects = (*rooms_)[room_id].GetTileObjects();
126 if (*hovered_index >= objects.size()) {
127 return std::nullopt;
128 }
129 return objects[*hovered_index];
130}
131
132std::vector<gui::CanvasMenuItem>
134 auto& interaction = object_interaction_;
135 const auto selected = interaction.GetSelectedObjectIndices();
136 const bool has_selection = !selected.empty();
137 const bool single_selection = selected.size() == 1;
138 const bool group_selection = selected.size() > 1;
139 const bool has_clipboard = interaction.HasClipboardData();
140 const bool placing_object = interaction.IsObjectLoaded();
141 const bool valid_room =
142 rooms_ && room_id >= 0 && room_id < zelda3::kNumberOfRooms;
143 const bool room_has_objects =
144 valid_room && !(*rooms_)[room_id].GetTileObjects().empty();
145 bool has_room_stream_object = false;
146 bool has_special_layer_object = false;
147 if (has_selection && valid_room) {
148 const auto& objects = (*rooms_)[room_id].GetTileObjects();
149 for (const size_t index : selected) {
150 if (index >= objects.size()) {
151 continue;
152 }
153 if (zelda3::UsesRoomObjectStream(objects[index])) {
154 has_room_stream_object = true;
155 } else {
156 has_special_layer_object = true;
157 }
158 }
159 }
160
161 std::vector<gui::CanvasMenuItem> items;
162
163 bool can_edit_selected_graphics = false;
164 std::function<void()> edit_selected_graphics;
165 if (single_selection && rooms_) {
166 auto& room = (*rooms_)[room_id];
167 const auto& objects = room.GetTileObjects();
168 if (selected[0] < objects.size()) {
169 const auto object = objects[selected[0]];
170 can_edit_selected_graphics = edit_graphics_callback_ != nullptr ||
172 edit_selected_graphics = [this, room_id, object]() {
174 edit_graphics_callback_(room_id, object);
175 } else if (show_room_graphics_callback_) {
177 }
178 };
179 }
180 }
181
182 auto enabled_if = [](bool enabled) {
183 return [enabled]() {
184 return enabled;
185 };
186 };
187 auto paste_item = [&]() {
189 "Paste", ICON_MD_CONTENT_PASTE,
190 [&interaction]() { interaction.HandlePasteObjects(); }, "Ctrl+V");
191 item.enabled_condition = enabled_if(has_clipboard);
192 return item;
193 };
194 auto disabled_item = [](const char* label, const char* icon,
195 const char* shortcut = nullptr) {
197 item.label = label;
198 item.icon = icon;
199 if (shortcut != nullptr) {
200 item.shortcut = shortcut;
201 }
202 item.enabled_condition = []() {
203 return false;
204 };
205 return item;
206 };
207 auto layer_item = [&interaction](const char* label, int layer,
208 const char* shortcut) {
209 return gui::CanvasMenuItem(
210 label, ICON_MD_LAYERS,
211 [&interaction, layer]() { interaction.SendSelectedToLayer(layer); },
212 shortcut);
213 };
214
215 const auto context_sample_object = GetObjectUnderContextCursor(room_id);
216 std::optional<size_t> sample_item_index;
217 if (context_sample_object.has_value()) {
218 sample_item_index = items.size();
219 items.emplace_back("Sample Object", ICON_MD_COLORIZE,
220 [this, object = *context_sample_object]() {
221 SetPreviewObject(object);
222 });
223 }
224
225 if (has_selection) {
226 items.emplace_back(
227 "Cut", ICON_MD_CONTENT_CUT,
228 [&interaction]() {
229 interaction.HandleCopySelected();
230 interaction.HandleDeleteSelected();
231 },
232 "Ctrl+X");
233 items.emplace_back(
234 "Copy", ICON_MD_CONTENT_COPY,
235 [&interaction]() { interaction.HandleCopySelected(); }, "Ctrl+C");
236 items.push_back(paste_item());
237 items.emplace_back(
238 "Delete", ICON_MD_DELETE,
239 [&interaction]() { interaction.HandleDeleteSelected(); }, "Del");
240
241 items.emplace_back(
242 "Bring to Front", ICON_MD_FLIP_TO_FRONT,
243 [&interaction]() { interaction.SendSelectedToFront(); },
244 "Ctrl+Shift+]");
245 items.emplace_back(
246 "Send to Back", ICON_MD_FLIP_TO_BACK,
247 [&interaction]() { interaction.SendSelectedToBack(); }, "Ctrl+Shift+[");
248
249 gui::CanvasMenuItem z_order;
250 z_order.label = "Z Order";
251 z_order.icon = ICON_MD_LAYERS;
252 z_order.subitems.emplace_back(
253 "Bring Forward", ICON_MD_ARROW_UPWARD,
254 [&interaction]() { interaction.BringSelectedForward(); }, "Ctrl+]");
255 z_order.subitems.emplace_back(
256 "Send Backward", ICON_MD_ARROW_DOWNWARD,
257 [&interaction]() { interaction.SendSelectedBackward(); }, "Ctrl+[");
258 items.push_back(std::move(z_order));
259
260 if (has_room_stream_object && !has_special_layer_object) {
261 items.push_back(layer_item("Object Stream: Primary", 0, "1"));
262 items.push_back(layer_item("Object Stream: BG2 Overlay", 1, "2"));
263 items.push_back(layer_item("Object Stream: BG1 Overlay", 2, "3"));
264 } else if (has_special_layer_object && !has_room_stream_object) {
265 items.push_back(layer_item("Upper Layer (BG1)", 0, "1"));
266 items.push_back(layer_item("Lower Layer (BG2)", 1, "2"));
267 } else {
268 items.push_back(
269 layer_item("Placement 0: Primary / Upper Layer (BG1)", 0, "1"));
270 items.push_back(
271 layer_item("Placement 1: BG2 Overlay / Lower Layer (BG2)", 1, "2"));
272 }
273
274 gui::CanvasMenuItem yaze_more;
275 yaze_more.label = "More";
276 yaze_more.icon = ICON_MD_MORE_HORIZ;
277 yaze_more.subitems.emplace_back(
278 "Duplicate", ICON_MD_CONTENT_PASTE,
279 [&interaction]() {
280 interaction.HandleCopySelected();
281 interaction.HandlePasteObjects();
282 },
283 "Ctrl+D");
284 if (group_selection) {
285 yaze_more.subitems.push_back(
286 disabled_item("Save As New Layout...", ICON_MD_SAVE_AS, nullptr));
287 }
288 items.push_back(std::move(yaze_more));
289 }
290
291 if (can_edit_selected_graphics) {
292 items.emplace_back("Edit Graphics...", ICON_MD_IMAGE,
293 std::move(edit_selected_graphics));
294 }
295
296 const bool has_entity_selection = interaction.HasEntitySelection();
297 if (has_entity_selection && !has_selection) {
298 items.emplace_back(
299 "Delete", ICON_MD_DELETE,
300 [&interaction]() { interaction.HandleDeleteSelected(); }, "Del");
301 }
302
303 if (!has_selection && !has_entity_selection) {
304 items.push_back(paste_item());
305 items.push_back(disabled_item("Delete", ICON_MD_DELETE, "Del"));
306 gui::CanvasMenuItem delete_all_item(
307 "Delete All", ICON_MD_DELETE_FOREVER,
308 [&interaction]() { interaction.HandleDeleteAllObjects(); });
309 delete_all_item.enabled_condition = enabled_if(room_has_objects);
310 items.push_back(std::move(delete_all_item));
311 }
312
313 if (placing_object) {
314 gui::CanvasMenuItem cancel_item(
315 "Cancel Placement", ICON_MD_CANCEL,
316 [&interaction]() { interaction.CancelPlacement(); }, "Esc");
317 if (!items.empty()) {
318 items.back().separator_after = true;
319 }
320 items.push_back(std::move(cancel_item));
321 }
322
323 if (sample_item_index.has_value() && items.size() > *sample_item_index + 1) {
324 items[*sample_item_index].separator_after = true;
325 }
326
327 if (!items.empty()) {
328 items.back().separator_after = true;
329 }
330 return items;
331}
332
334 gui::CanvasMenuItem room_menu;
335 room_menu.label = "Room";
336 room_menu.icon = ICON_MD_HOME;
338 room_menu.subitems.emplace_back(
339 "Apply Room to ROM", ICON_MD_SAVE,
340 [this, room_id]() { save_room_callback_(room_id); }, "Ctrl+Shift+S");
341 }
342 room_menu.subitems.emplace_back(
343 "Re-render Room", ICON_MD_REFRESH,
344 [this, room_id]() {
345 if (rooms_ && room_id >= 0 && room_id < zelda3::kNumberOfRooms) {
346 (*rooms_)[room_id].RenderRoomGraphics();
347 }
348 },
349 "Ctrl+R");
350 if (rooms_ && !(*rooms_)[room_id].GetTileObjects().empty()) {
351 room_menu.subitems.emplace_back(
352 "Delete All Objects", ICON_MD_DELETE_FOREVER,
354 }
355 return room_menu;
356}
357
359 gui::CanvasMenuItem report_menu;
360 report_menu.label = "Report";
361 report_menu.icon = ICON_MD_BUG_REPORT;
362 report_menu.subitems.emplace_back(
363 "Render Issue...", ICON_MD_BUG_REPORT, [this, room_id]() {
364 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
365 return;
366 }
368 absl::StrFormat("Report Room 0x%03X Render Issue", room_id),
369 absl::StrFormat("Room 0x%03X render mismatch", room_id),
370 "Dungeon Render Issue Report",
371 BuildDrawIssueReport((*rooms_)[room_id], room_id), room_id,
374 });
375 report_menu.subitems.emplace_back(
376 "Palette Issue...", ICON_MD_PALETTE, [this, room_id]() {
377 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
378 return;
379 }
381 absl::StrFormat("Report Room 0x%03X Palette Issue", room_id),
382 absl::StrFormat("Room 0x%03X palette mismatch", room_id),
383 "Dungeon Palette Issue Report",
384 BuildDrawIssueReport((*rooms_)[room_id], room_id), room_id,
386 });
389 report_menu.subitems.emplace_back(
390 "Selection Issue...", ICON_MD_FACT_CHECK, [this, room_id]() {
391 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
392 return;
393 }
395 absl::StrFormat("Report Selection Issue for Room 0x%03X",
396 room_id),
397 absl::StrFormat("Room 0x%03X selection or entity mismatch",
398 room_id),
399 "Dungeon Selection Issue Report",
400 BuildSelectionIssueReport((*rooms_)[room_id], room_id), room_id,
403 });
404 }
405 return report_menu;
406}
407
408std::optional<gui::CanvasMenuItem> DungeonCanvasViewer::BuildOpenContextMenu() {
409 gui::CanvasMenuItem open_menu;
410 open_menu.label = "Open";
411 open_menu.icon = ICON_MD_OPEN_IN_NEW;
413 open_menu.subitems.emplace_back("Room Matrix", ICON_MD_GRID_VIEW,
414 [this]() { show_room_matrix_callback_(); });
415 }
417 open_menu.subitems.emplace_back("Room Graphics", ICON_MD_IMAGE, [this]() {
419 });
420 }
422 open_menu.subitems.emplace_back("Door Editor", ICON_MD_DOOR_FRONT,
423 [this]() { show_door_editor_callback_(); });
424 }
426 open_menu.subitems.emplace_back("Entrance List", ICON_MD_LOGIN, [this]() {
428 });
429 }
430 if (open_menu.subitems.empty()) {
431 return std::nullopt;
432 }
433 return open_menu;
434}
435
437 int room_id) {
438 gui::CanvasMenuItem copy_export_menu;
439 copy_export_menu.label = "Copy / Export";
440 copy_export_menu.icon = ICON_MD_CONTENT_COPY;
441 copy_export_menu.subitems.emplace_back(
442 "Copy Room Summary", ICON_MD_ASSIGNMENT, [this, room_id]() {
443 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
444 return;
445 }
446 ImGui::SetClipboardText(
447 BuildRoomMetadataSummary((*rooms_)[room_id], room_id).c_str());
448 });
449 copy_export_menu.subitems.emplace_back(
450 "Copy Room ID", ICON_MD_CONTENT_COPY, [room_id]() {
451 ImGui::SetClipboardText(absl::StrFormat("0x%03X", room_id).c_str());
452 });
453 if (rooms_ && room_id >= 0 && room_id < zelda3::kNumberOfRooms) {
454 const std::string room_label = zelda3::GetRoomLabel(room_id);
455 copy_export_menu.subitems.emplace_back(
456 "Copy Room Name", ICON_MD_CONTENT_COPY,
457 [room_label]() { ImGui::SetClipboardText(room_label.c_str()); });
458 }
459 copy_export_menu.subitems.emplace_back(
460 "Export Layout Template...", ICON_MD_FILE_DOWNLOAD, [this, room_id]() {
461 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
462 return;
463 }
464 auto& room = (*rooms_)[room_id];
465 auto result = zelda3::ExportRoomLayoutTemplate(room);
466 if (result.ok()) {
467 ImGui::SetClipboardText(result.value().c_str());
468 }
469 });
470 return copy_export_menu;
471}
472
474 int room_id) {
475 gui::CanvasMenuItem layers_menu;
476 layers_menu.label = "Layers";
477 layers_menu.icon = ICON_MD_VISIBILITY;
478
479 gui::CanvasMenuItem bg1_layout_item("BG1 Layout", [this, room_id]() {
480 auto& mgr = GetRoomLayerManager(room_id);
481 mgr.SetLayerVisible(zelda3::LayerType::BG1_Layout,
482 !mgr.IsLayerVisible(zelda3::LayerType::BG1_Layout));
483 });
484 bg1_layout_item.checked_condition = [this, room_id]() {
485 return GetRoomLayerManager(room_id).IsLayerVisible(
487 };
488 layers_menu.subitems.push_back(std::move(bg1_layout_item));
489
490 gui::CanvasMenuItem bg1_objects_item("BG1 Objects", [this, room_id]() {
491 auto& mgr = GetRoomLayerManager(room_id);
492 mgr.SetLayerVisible(zelda3::LayerType::BG1_Objects,
493 !mgr.IsLayerVisible(zelda3::LayerType::BG1_Objects));
494 });
495 bg1_objects_item.checked_condition = [this, room_id]() {
496 return GetRoomLayerManager(room_id).IsLayerVisible(
498 };
499 layers_menu.subitems.push_back(std::move(bg1_objects_item));
500
501 gui::CanvasMenuItem bg2_layout_item("BG2 Layout", [this, room_id]() {
502 auto& mgr = GetRoomLayerManager(room_id);
503 mgr.SetLayerVisible(zelda3::LayerType::BG2_Layout,
504 !mgr.IsLayerVisible(zelda3::LayerType::BG2_Layout));
505 });
506 bg2_layout_item.checked_condition = [this, room_id]() {
507 return GetRoomLayerManager(room_id).IsLayerVisible(
509 };
510 layers_menu.subitems.push_back(std::move(bg2_layout_item));
511
512 gui::CanvasMenuItem bg2_objects_item("BG2 Objects", [this, room_id]() {
513 auto& mgr = GetRoomLayerManager(room_id);
514 mgr.SetLayerVisible(zelda3::LayerType::BG2_Objects,
515 !mgr.IsLayerVisible(zelda3::LayerType::BG2_Objects));
516 });
517 bg2_objects_item.checked_condition = [this, room_id]() {
518 return GetRoomLayerManager(room_id).IsLayerVisible(
520 };
521 layers_menu.subitems.push_back(std::move(bg2_objects_item));
522
523 gui::CanvasMenuItem sprites_item("Sprites", ICON_MD_PERSON, [this]() {
525 });
526 sprites_item.checked_condition = [this]() {
528 };
529 layers_menu.subitems.push_back(std::move(sprites_item));
530
531 gui::CanvasMenuItem pot_items_item("Pot Items", ICON_MD_INVENTORY, [this]() {
533 });
534 pot_items_item.checked_condition = [this]() {
536 };
537 layers_menu.subitems.push_back(std::move(pot_items_item));
538
539 return layers_menu;
540}
541
543 gui::CanvasMenuItem overlays_menu;
544 overlays_menu.label = "Overlays";
545 overlays_menu.icon = ICON_MD_LAYERS;
546
547 gui::CanvasMenuItem coordinates_item(
548 "Coordinates", ICON_MD_MY_LOCATION,
550 coordinates_item.checked_condition = [this]() {
552 };
553 overlays_menu.subitems.push_back(std::move(coordinates_item));
554
555 gui::CanvasMenuItem minecart_toggle(
556 "Minecart Tracks", ICON_MD_TRAIN,
558 minecart_toggle.enabled_condition = [this]() {
559 return minecart_track_panel_ != nullptr;
560 };
561 minecart_toggle.checked_condition = [this]() {
563 };
564 overlays_menu.subitems.push_back(std::move(minecart_toggle));
565
566 gui::CanvasMenuItem custom_collision_item(
567 "Custom Collision", ICON_MD_GRID_ON, [this]() {
569 });
570 custom_collision_item.checked_condition = [this]() {
572 };
573 overlays_menu.subitems.push_back(std::move(custom_collision_item));
574
575 gui::CanvasMenuItem track_collision_item(
576 "Track Collision", ICON_MD_LAYERS, [this]() {
578 });
579 track_collision_item.checked_condition = [this]() {
581 };
582 overlays_menu.subitems.push_back(std::move(track_collision_item));
583
584 gui::CanvasMenuItem camera_quadrants_item(
585 "Camera Quadrants", ICON_MD_GRID_VIEW, [this]() {
587 });
588 camera_quadrants_item.checked_condition = [this]() {
590 };
591 overlays_menu.subitems.push_back(std::move(camera_quadrants_item));
592
593 gui::CanvasMenuItem minecart_sprites_item(
594 "Minecart Sprites", ICON_MD_TRAIN, [this]() {
596 });
597 minecart_sprites_item.checked_condition = [this]() {
599 };
600 overlays_menu.subitems.push_back(std::move(minecart_sprites_item));
601
603 gui::CanvasMenuItem collision_legend_item(
604 "Collision Legend", ICON_MD_INFO, [this]() {
606 });
607 collision_legend_item.checked_condition = [this]() {
609 };
610 overlays_menu.subitems.push_back(std::move(collision_legend_item));
611 }
612
613 gui::CanvasMenuItem object_bounds_item(
614 "Object Bounds", ICON_MD_CROP_SQUARE,
616 object_bounds_item.checked_condition = [this]() {
617 return show_object_bounds_;
618 };
619 overlays_menu.subitems.push_back(std::move(object_bounds_item));
620
621 return overlays_menu;
622}
623
625 gui::CanvasMenuItem debug_menu;
626 debug_menu.label = "Debug";
627 debug_menu.icon = ICON_MD_BUG_REPORT;
628
629 debug_menu.subitems.push_back(gui::CanvasMenuItem(
630 "Room Info", ICON_MD_INFO,
632 debug_menu.subitems.back().checked_condition = [this]() {
634 };
635
636 debug_menu.subitems.push_back(gui::CanvasMenuItem(
637 "Texture Debug", ICON_MD_IMAGE,
638 [this]() { show_texture_debug_ = !show_texture_debug_; }));
639 debug_menu.subitems.back().checked_condition = [this]() {
640 return show_texture_debug_;
641 };
642
643 gui::CanvasMenuItem object_bounds_menu;
644 object_bounds_menu.label = "Object Bounds Filter";
645 object_bounds_menu.icon = ICON_MD_CROP_SQUARE;
646
647 object_bounds_menu.subitems.push_back(
648 gui::CanvasMenuItem("Type 1 (0x00-0xFF)", [this]() {
651 }));
652 object_bounds_menu.subitems.back().checked_condition = [this]() {
654 };
655 object_bounds_menu.subitems.push_back(
656 gui::CanvasMenuItem("Type 2 (0x100-0x1FF)", [this]() {
659 }));
660 object_bounds_menu.subitems.back().checked_condition = [this]() {
662 };
663 object_bounds_menu.subitems.push_back(
664 gui::CanvasMenuItem("Type 3 (0xF00-0xFFF)", [this]() {
667 }));
668 object_bounds_menu.subitems.back().checked_condition = [this]() {
670 };
671
673 sep.label = "---";
674 sep.enabled_condition = []() {
675 return false;
676 };
677 object_bounds_menu.subitems.push_back(std::move(sep));
678
679 object_bounds_menu.subitems.push_back(
680 gui::CanvasMenuItem("Primary / Upper layer (BG1)", [this]() {
683 }));
684 object_bounds_menu.subitems.back().checked_condition = [this]() {
686 };
687 object_bounds_menu.subitems.push_back(
688 gui::CanvasMenuItem("BG2 overlay / Lower layer (BG2)", [this]() {
691 }));
692 object_bounds_menu.subitems.back().checked_condition = [this]() {
694 };
695 object_bounds_menu.subitems.push_back(
696 gui::CanvasMenuItem("BG1 overlay (room stream only)", [this]() {
699 }));
700 object_bounds_menu.subitems.back().checked_condition = [this]() {
702 };
703 debug_menu.subitems.push_back(std::move(object_bounds_menu));
704
705 debug_menu.subitems.push_back(
707 [this]() { show_layer_info_ = !show_layer_info_; }));
708 debug_menu.subitems.back().checked_condition = [this]() {
709 return show_layer_info_;
710 };
711
712 debug_menu.subitems.push_back(
713 gui::CanvasMenuItem("Force Reload", ICON_MD_REFRESH, [this, room_id]() {
714 if (rooms_ && room_id >= 0 && room_id < zelda3::kNumberOfRooms) {
715 (*rooms_)[room_id].ReloadGraphics(current_entrance_blockset_);
716 }
717 }));
718
719 debug_menu.subitems.push_back(
720 gui::CanvasMenuItem("Log Room State", ICON_MD_PRINT, [this, room_id]() {
721 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
722 return;
723 }
724 const auto& room = (*rooms_)[room_id];
725 LOG_DEBUG("DungeonDebug", "=== Room %03X Debug ===", room_id);
726 LOG_DEBUG("DungeonDebug", "Blockset: %d, Palette: %d, Layout: %d",
727 room.blockset(), room.palette(), room.layout_id());
728 LOG_DEBUG("DungeonDebug", "Objects: %zu, Sprites: %zu",
729 room.GetTileObjects().size(), room.GetSprites().size());
730 LOG_DEBUG("DungeonDebug", "BG1: %dx%d, BG2: %dx%d",
731 room.bg1_buffer().bitmap().width(),
732 room.bg1_buffer().bitmap().height(),
733 room.bg2_buffer().bitmap().width(),
734 room.bg2_buffer().bitmap().height());
735 }));
736
737 return debug_menu;
738}
739
740} // namespace yaze::editor
bool is_loaded() const
Definition rom.h:144
std::pair< int, int > ScreenToRoomPixelCoordinates(ImVec2 screen) const
std::optional< zelda3::RoomObject > GetObjectUnderContextCursor(int room_id)
gui::CanvasMenuItem BuildLayerVisibilityContextMenu(int room_id)
gui::CanvasMenuItem BuildRoomContextMenu(int room_id)
gui::CanvasMenuItem BuildDebugContextMenu(int room_id)
std::vector< gui::CanvasMenuItem > BuildSelectionContextMenuItems(int room_id)
std::function< void()> show_door_editor_callback_
std::function< void(int, const zelda3::RoomObject &) edit_graphics_callback_)
std::function< void()> show_entrance_list_callback_
DungeonObjectInteraction object_interaction_
void OpenIssueReportPopup(const std::string &title, const std::string &summary, const std::string &kind_label, const std::string &diagnostics, int room_id, int default_category_index)
std::string BuildRoomMetadataSummary(const zelda3::Room &room, int room_id) const
gui::CanvasMenuItem BuildReportContextMenu(int room_id)
void SetPreviewObject(const zelda3::RoomObject &object)
std::function< void()> show_object_panel_callback_
zelda3::RoomLayerManager & GetRoomLayerManager(int room_id)
std::string BuildDrawIssueReport(const zelda3::Room &room, int room_id) const
std::function< void()> show_room_matrix_callback_
std::function< void()> show_room_graphics_callback_
std::function< void()> show_item_panel_callback_
std::function< void()> show_sprite_panel_callback_
std::optional< gui::CanvasMenuItem > BuildOpenContextMenu()
MinecartTrackEditorPanel * minecart_track_panel_
std::string BuildSelectionIssueReport(const zelda3::Room &room, int room_id) const
gui::CanvasMenuItem BuildCopyExportContextMenu(int room_id)
std::function< void(int)> save_room_callback_
std::vector< size_t > GetSelectedObjectIndices() const
InteractionCoordinator & entity_coordinator()
Get the interaction coordinator for entity handling.
void SetDoorPlacementMode(bool enabled, zelda3::DoorType type=zelda3::DoorType::NormalDoor)
std::optional< size_t > GetEntityAtPosition(int canvas_x, int canvas_y) const override
Get entity at canvas position.
auto global_scale() const
Definition canvas.h:397
void ClearContextMenuItems()
Definition canvas.cc:863
void AddContextMenuItem(const gui::CanvasMenuItem &item)
Definition canvas.cc:840
auto zero_point() const
Definition canvas.h:348
auto scrolling() const
Definition canvas.h:350
bool IsLayerVisible(LayerType layer) const
#define ICON_MD_GRID_VIEW
Definition icons.h:897
#define ICON_MD_COLORIZE
Definition icons.h:441
#define ICON_MD_MY_LOCATION
Definition icons.h:1270
#define ICON_MD_CONTENT_CUT
Definition icons.h:466
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_CANCEL
Definition icons.h:364
#define ICON_MD_TRAIN
Definition icons.h:2005
#define ICON_MD_FILE_DOWNLOAD
Definition icons.h:744
#define ICON_MD_SAVE_AS
Definition icons.h:1646
#define ICON_MD_REFRESH
Definition icons.h:1572
#define ICON_MD_FLIP_TO_FRONT
Definition icons.h:802
#define ICON_MD_ARROW_DOWNWARD
Definition icons.h:180
#define ICON_MD_VISIBILITY
Definition icons.h:2101
#define ICON_MD_BUG_REPORT
Definition icons.h:327
#define ICON_MD_WIDGETS
Definition icons.h:2156
#define ICON_MD_MORE_HORIZ
Definition icons.h:1241
#define ICON_MD_LOGIN
Definition icons.h:1146
#define ICON_MD_CONTENT_PASTE
Definition icons.h:467
#define ICON_MD_HOME
Definition icons.h:953
#define ICON_MD_GRID_ON
Definition icons.h:896
#define ICON_MD_FACT_CHECK
Definition icons.h:721
#define ICON_MD_LAYERS
Definition icons.h:1068
#define ICON_MD_INVENTORY
Definition icons.h:1011
#define ICON_MD_DOOR_FRONT
Definition icons.h:613
#define ICON_MD_CROP_SQUARE
Definition icons.h:500
#define ICON_MD_ARROW_UPWARD
Definition icons.h:189
#define ICON_MD_IMAGE
Definition icons.h:982
#define ICON_MD_PERSON
Definition icons.h:1415
#define ICON_MD_ASSIGNMENT
Definition icons.h:194
#define ICON_MD_SAVE
Definition icons.h:1644
#define ICON_MD_DELETE
Definition icons.h:530
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_OPEN_IN_NEW
Definition icons.h:1354
#define ICON_MD_CONTENT_COPY
Definition icons.h:465
#define ICON_MD_DELETE_FOREVER
Definition icons.h:531
#define ICON_MD_PRINT
Definition icons.h:1515
#define ICON_MD_FLIP_TO_BACK
Definition icons.h:801
#define ICON_MD_ADD_CIRCLE
Definition icons.h:95
#define LOG_DEBUG(category, format,...)
Definition log.h:103
bool IsWithinBounds(int canvas_x, int canvas_y, int margin=0)
Check if coordinates are within room bounds.
Editors are the view controllers for the application.
DungeonIssueCategory GetDefaultSelectionIssueCategory(const DungeonObjectInteraction &object_interaction)
constexpr int ToIssueCategoryIndex(DungeonIssueCategory category)
@ NormalDoor
Normal door (upper layer)
std::string GetRoomLabel(int id)
Convenience function to get a room label.
absl::StatusOr< std::string > ExportRoomLayoutTemplate(const Room &room)
Export a room's layout as a JSON template string.
bool UsesRoomObjectStream(const RoomObject &object)
constexpr int kNumberOfRooms
Declarative menu item definition.
Definition canvas_menu.h:64
std::function< bool()> checked_condition
Definition canvas_menu.h:91
std::vector< CanvasMenuItem > subitems
Definition canvas_menu.h:94
std::function< bool()> enabled_condition
Definition canvas_menu.h:81