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"
17
18namespace yaze::editor {
19
25
28 return;
29 }
30
32 auto insert_menu = BuildInsertContextMenu();
33 insert_menu.separator_after = true;
34 canvas_.AddContextMenuItem(insert_menu);
35}
36
38 int room_id) {
39 gui::CanvasMenuItem selection_menu;
40 selection_menu.label = "Selection";
41 selection_menu.icon = ICON_MD_SELECT_ALL;
42 selection_menu.subitems = BuildSelectionContextMenuItems(room_id);
43 return selection_menu;
44}
45
61
63 auto enabled_if = [](bool enabled) {
64 return [enabled]() {
65 return enabled;
66 };
67 };
68
69 gui::CanvasMenuItem insert_menu;
70 insert_menu.label = "Insert";
71 insert_menu.icon = ICON_MD_ADD_CIRCLE;
72
73 gui::CanvasMenuItem insert_object_item("Object...", ICON_MD_WIDGETS,
74 [this]() {
77 }
78 });
79 insert_object_item.enabled_condition =
80 enabled_if(show_object_panel_callback_ != nullptr);
81 insert_menu.subitems.push_back(std::move(insert_object_item));
82
83 gui::CanvasMenuItem insert_sprite_item("Sprite...", ICON_MD_PERSON, [this]() {
86 }
87 });
88 insert_sprite_item.enabled_condition =
89 enabled_if(show_sprite_panel_callback_ != nullptr);
90 insert_menu.subitems.push_back(std::move(insert_sprite_item));
91
92 gui::CanvasMenuItem insert_item_item("Item...", ICON_MD_INVENTORY, [this]() {
95 }
96 });
97 insert_item_item.enabled_condition =
98 enabled_if(show_item_panel_callback_ != nullptr);
99 insert_menu.subitems.push_back(std::move(insert_item_item));
100
101 const bool door_mode = object_interaction_.IsDoorPlacementActive();
102 insert_menu.subitems.emplace_back(
103 door_mode ? "Cancel Door Placement" : "Door (Normal)", ICON_MD_DOOR_FRONT,
104 [this, door_mode]() {
107 });
108
109 return insert_menu;
110}
111
112std::optional<zelda3::RoomObject>
114 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
115 return std::nullopt;
116 }
117
118 const ImGuiIO& io = ImGui::GetIO();
119 ImVec2 screen_position = io.MousePos;
120 if (!ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
121 if (const auto popup_anchor = canvas_.context_menu_open_screen_position();
122 popup_anchor.has_value()) {
123 screen_position = *popup_anchor;
124 }
125 }
126 const DungeonCanvasTransform transform(
128 const auto [canvas_x, canvas_y] =
129 transform.ScreenToRoomPixelCoordinates(screen_position);
130 if (!dungeon_coords::IsWithinBounds(canvas_x, canvas_y)) {
131 return std::nullopt;
132 }
133 const auto hovered_index = object_interaction_.entity_coordinator()
134 .tile_handler()
135 .GetEntityAtPosition(canvas_x, canvas_y);
136 if (!hovered_index.has_value()) {
137 return std::nullopt;
138 }
139
140 const auto& objects = (*rooms_)[room_id].GetTileObjects();
141 if (*hovered_index >= objects.size()) {
142 return std::nullopt;
143 }
144 return objects[*hovered_index];
145}
146
147std::vector<gui::CanvasMenuItem>
152
153std::vector<gui::CanvasMenuItem>
155 int room_id, std::optional<zelda3::RoomObject> context_object) {
156 auto& interaction = object_interaction_;
157 const auto selected = interaction.GetSelectedObjectIndices();
158 const bool has_selection = !selected.empty();
159 const bool single_selection = selected.size() == 1;
160 const bool group_selection = selected.size() > 1;
161 const bool has_clipboard = interaction.HasClipboardData();
162 const bool placing_object = interaction.IsObjectLoaded();
163 const bool valid_room =
164 rooms_ && room_id >= 0 && room_id < zelda3::kNumberOfRooms;
165 const bool room_has_objects =
166 valid_room && !(*rooms_)[room_id].GetTileObjects().empty();
167 bool has_room_stream_object = false;
168 bool has_special_layer_object = false;
169 if (has_selection && valid_room) {
170 const auto& objects = (*rooms_)[room_id].GetTileObjects();
171 for (const size_t index : selected) {
172 if (index >= objects.size()) {
173 continue;
174 }
175 if (zelda3::UsesRoomObjectStream(objects[index])) {
176 has_room_stream_object = true;
177 } else {
178 has_special_layer_object = true;
179 }
180 }
181 }
182
183 std::vector<gui::CanvasMenuItem> items;
184
185 bool can_edit_selected_graphics = false;
186 std::function<void()> edit_selected_graphics;
187 bool can_edit_selected_tiles = false;
188 std::function<void()> edit_selected_tiles;
189 if (single_selection && valid_room) {
190 auto& room = (*rooms_)[room_id];
191 const auto& objects = room.GetTileObjects();
192 if (selected[0] < objects.size()) {
193 const auto object = objects[selected[0]];
194 can_edit_selected_graphics = edit_graphics_callback_ != nullptr ||
196 edit_selected_graphics = [this, room_id, object]() {
198 edit_graphics_callback_(room_id, object);
199 } else if (show_room_graphics_callback_) {
201 }
202 };
203 can_edit_selected_tiles =
204 edit_object_tiles_callback_ != nullptr &&
206 edit_selected_tiles = [this, room_id, object]() {
208 edit_object_tiles_callback_(room_id, object);
209 }
210 };
211 }
212 }
213
214 auto enabled_if = [](bool enabled) {
215 return [enabled]() {
216 return enabled;
217 };
218 };
219 auto paste_item = [&]() {
221 "Paste", ICON_MD_CONTENT_PASTE,
222 [&interaction]() { interaction.HandlePasteObjects(); }, "Ctrl+V");
223 item.enabled_condition = enabled_if(has_clipboard);
224 return item;
225 };
226 auto disabled_item = [](const char* label, const char* icon,
227 const char* shortcut = nullptr) {
229 item.label = label;
230 item.icon = icon;
231 if (shortcut != nullptr) {
232 item.shortcut = shortcut;
233 }
234 item.enabled_condition = []() {
235 return false;
236 };
237 return item;
238 };
239 auto layer_item = [&interaction](const char* label, int layer,
240 const char* shortcut) {
241 return gui::CanvasMenuItem(
242 label, ICON_MD_LAYERS,
243 [&interaction, layer]() { interaction.SendSelectedToLayer(layer); },
244 shortcut);
245 };
246
247 gui::CanvasMenuItem sample_item("Use Object as Brush", ICON_MD_COLORIZE,
248 [this, context_object]() {
249 if (context_object.has_value()) {
250 SetPreviewObject(*context_object);
251 }
252 });
253 sample_item.enabled_condition = enabled_if(context_object.has_value());
254 sample_item.separator_after = true;
255 items.push_back(std::move(sample_item));
256
257 if (has_selection) {
258 items.emplace_back(
259 "Cut", ICON_MD_CONTENT_CUT,
260 [&interaction]() {
261 interaction.HandleCopySelected();
262 interaction.HandleDeleteSelected();
263 },
264 "Ctrl+X");
265 items.emplace_back(
266 "Copy", ICON_MD_CONTENT_COPY,
267 [&interaction]() { interaction.HandleCopySelected(); }, "Ctrl+C");
268 items.push_back(paste_item());
269 items.emplace_back(
270 "Delete", ICON_MD_DELETE,
271 [&interaction]() { interaction.HandleDeleteSelected(); }, "Del");
272
273 items.emplace_back(
274 "Bring to Front", ICON_MD_FLIP_TO_FRONT,
275 [&interaction]() { interaction.SendSelectedToFront(); },
276 "Ctrl+Shift+]");
277 items.emplace_back(
278 "Send to Back", ICON_MD_FLIP_TO_BACK,
279 [&interaction]() { interaction.SendSelectedToBack(); }, "Ctrl+Shift+[");
280
281 gui::CanvasMenuItem z_order;
282 z_order.label = "Z Order";
283 z_order.icon = ICON_MD_LAYERS;
284 z_order.subitems.emplace_back(
285 "Bring Forward", ICON_MD_ARROW_UPWARD,
286 [&interaction]() { interaction.BringSelectedForward(); }, "Ctrl+]");
287 z_order.subitems.emplace_back(
288 "Send Backward", ICON_MD_ARROW_DOWNWARD,
289 [&interaction]() { interaction.SendSelectedBackward(); }, "Ctrl+[");
290 items.push_back(std::move(z_order));
291
292 if (has_room_stream_object && !has_special_layer_object) {
293 items.push_back(layer_item("Object Stream: Primary", 0, "1"));
294 items.push_back(layer_item("Object Stream: BG2 Overlay", 1, "2"));
295 items.push_back(layer_item("Object Stream: BG1 Overlay", 2, "3"));
296 } else if (has_special_layer_object && !has_room_stream_object) {
297 items.push_back(layer_item("Upper Layer (BG1)", 0, "1"));
298 items.push_back(layer_item("Lower Layer (BG2)", 1, "2"));
299 } else {
300 items.push_back(
301 layer_item("Placement 0: Primary / Upper Layer (BG1)", 0, "1"));
302 items.push_back(
303 layer_item("Placement 1: BG2 Overlay / Lower Layer (BG2)", 1, "2"));
304 }
305
306 gui::CanvasMenuItem yaze_more;
307 yaze_more.label = "More";
308 yaze_more.icon = ICON_MD_MORE_HORIZ;
309 yaze_more.subitems.emplace_back(
310 "Duplicate", ICON_MD_CONTENT_PASTE,
311 [&interaction]() {
312 interaction.HandleCopySelected();
313 interaction.HandlePasteObjects();
314 },
315 "Ctrl+D");
316 if (group_selection) {
317 yaze_more.subitems.push_back(
318 disabled_item("Save As New Layout...", ICON_MD_SAVE_AS, nullptr));
319 }
320 items.push_back(std::move(yaze_more));
321 }
322
323 if (can_edit_selected_graphics) {
324 items.emplace_back("Edit Graphics...", ICON_MD_IMAGE,
325 std::move(edit_selected_graphics));
326 }
327 if (can_edit_selected_tiles) {
328 items.emplace_back("Edit Object Tiles...", ICON_MD_GRID_ON,
329 std::move(edit_selected_tiles));
330 }
331
332 const bool has_entity_selection = interaction.HasEntitySelection();
333 if (has_entity_selection && !has_selection) {
334 items.emplace_back(
335 "Delete", ICON_MD_DELETE,
336 [&interaction]() { interaction.HandleDeleteSelected(); }, "Del");
337 }
338
339 if (!has_selection && !has_entity_selection) {
340 items.push_back(paste_item());
341 items.push_back(disabled_item("Delete", ICON_MD_DELETE, "Del"));
342 gui::CanvasMenuItem delete_all_item(
343 "Delete All", ICON_MD_DELETE_FOREVER,
344 [&interaction]() { interaction.HandleDeleteAllObjects(); });
345 delete_all_item.enabled_condition = enabled_if(room_has_objects);
346 items.push_back(std::move(delete_all_item));
347 }
348
349 if (placing_object) {
350 gui::CanvasMenuItem cancel_item(
351 "Cancel Placement", ICON_MD_CANCEL,
352 [&interaction]() { interaction.CancelPlacement(); }, "Esc");
353 if (!items.empty()) {
354 items.back().separator_after = true;
355 }
356 items.push_back(std::move(cancel_item));
357 }
358
359 return items;
360}
361
363 gui::CanvasMenuItem room_menu;
364 room_menu.label = "Room";
365 room_menu.icon = ICON_MD_HOME;
367 room_menu.subitems.emplace_back(
368 "Apply Room to ROM", ICON_MD_SAVE,
369 [this, room_id]() { save_room_callback_(room_id); }, "Ctrl+Shift+S");
370 }
371 room_menu.subitems.emplace_back(
372 "Re-render Room", ICON_MD_REFRESH,
373 [this, room_id]() {
374 if (rooms_ && room_id >= 0 && room_id < zelda3::kNumberOfRooms) {
375 (*rooms_)[room_id].RenderRoomGraphics();
376 }
377 },
378 "Ctrl+R");
379 if (rooms_ && !(*rooms_)[room_id].GetTileObjects().empty()) {
380 room_menu.subitems.emplace_back(
381 "Delete All Objects", ICON_MD_DELETE_FOREVER,
383 }
384 return room_menu;
385}
386
388 gui::CanvasMenuItem report_menu;
389 report_menu.label = "Capture Issue";
390 report_menu.icon = ICON_MD_BUG_REPORT;
391 report_menu.subitems.emplace_back(
392 "Room Rendering...", ICON_MD_BUG_REPORT, [this, room_id]() {
393 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
394 return;
395 }
397 absl::StrFormat("Capture Room 0x%03X Rendering Issue", room_id),
398 absl::StrFormat("Room 0x%03X render mismatch", room_id),
399 "Dungeon Render Issue Report",
400 BuildDrawIssueReport((*rooms_)[room_id], room_id), room_id,
403 });
404 report_menu.subitems.emplace_back(
405 "Room Palette...", ICON_MD_PALETTE, [this, room_id]() {
406 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
407 return;
408 }
410 absl::StrFormat("Capture Room 0x%03X Palette Issue", room_id),
411 absl::StrFormat("Room 0x%03X palette mismatch", room_id),
412 "Dungeon Palette Issue Report",
413 BuildDrawIssueReport((*rooms_)[room_id], room_id), room_id,
415 });
418 report_menu.subitems.emplace_back(
419 "Current Selection...", ICON_MD_FACT_CHECK, [this, room_id]() {
420 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
421 return;
422 }
424 absl::StrFormat("Capture Selection Issue for Room 0x%03X",
425 room_id),
426 absl::StrFormat("Room 0x%03X selection or entity mismatch",
427 room_id),
428 "Dungeon Selection Issue Report",
429 BuildSelectionIssueReport((*rooms_)[room_id], room_id), room_id,
432 });
433 }
434 return report_menu;
435}
436
437std::optional<gui::CanvasMenuItem> DungeonCanvasViewer::BuildOpenContextMenu() {
438 gui::CanvasMenuItem open_menu;
439 open_menu.label = "Open";
440 open_menu.icon = ICON_MD_OPEN_IN_NEW;
442 open_menu.subitems.emplace_back("Room Matrix", ICON_MD_GRID_VIEW,
443 [this]() { show_room_matrix_callback_(); });
444 }
446 open_menu.subitems.emplace_back("Room Graphics", ICON_MD_IMAGE, [this]() {
448 });
449 }
451 open_menu.subitems.emplace_back("Door Editor", ICON_MD_DOOR_FRONT,
452 [this]() { show_door_editor_callback_(); });
453 }
455 open_menu.subitems.emplace_back("Entrance List", ICON_MD_LOGIN, [this]() {
457 });
458 }
459 if (open_menu.subitems.empty()) {
460 return std::nullopt;
461 }
462 return open_menu;
463}
464
466 int room_id) {
467 gui::CanvasMenuItem copy_export_menu;
468 copy_export_menu.label = "Copy / Export";
469 copy_export_menu.icon = ICON_MD_CONTENT_COPY;
470 copy_export_menu.subitems.emplace_back(
471 "Copy Room Summary", ICON_MD_ASSIGNMENT, [this, room_id]() {
472 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
473 return;
474 }
475 ImGui::SetClipboardText(
476 BuildRoomMetadataSummary((*rooms_)[room_id], room_id).c_str());
477 });
478 copy_export_menu.subitems.emplace_back(
479 "Copy Room ID", ICON_MD_CONTENT_COPY, [room_id]() {
480 ImGui::SetClipboardText(absl::StrFormat("0x%03X", room_id).c_str());
481 });
482 if (rooms_ && room_id >= 0 && room_id < zelda3::kNumberOfRooms) {
483 const std::string room_label = zelda3::GetRoomLabel(room_id);
484 copy_export_menu.subitems.emplace_back(
485 "Copy Room Name", ICON_MD_CONTENT_COPY,
486 [room_label]() { ImGui::SetClipboardText(room_label.c_str()); });
487 }
488 copy_export_menu.subitems.emplace_back(
489 "Export Layout Template...", ICON_MD_FILE_DOWNLOAD, [this, room_id]() {
490 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
491 return;
492 }
493 auto& room = (*rooms_)[room_id];
494 auto result = zelda3::ExportRoomLayoutTemplate(room);
495 if (result.ok()) {
496 ImGui::SetClipboardText(result.value().c_str());
497 }
498 });
499 return copy_export_menu;
500}
501
503 int room_id) {
504 gui::CanvasMenuItem layers_menu;
505 layers_menu.label = "Layers";
506 layers_menu.icon = ICON_MD_VISIBILITY;
507
508 gui::CanvasMenuItem bg1_layout_item("BG1 Layout", [this, room_id]() {
509 auto& mgr = GetRoomLayerManager(room_id);
510 mgr.SetLayerVisible(zelda3::LayerType::BG1_Layout,
511 !mgr.IsLayerVisible(zelda3::LayerType::BG1_Layout));
512 });
513 bg1_layout_item.checked_condition = [this, room_id]() {
514 return GetRoomLayerManager(room_id).IsLayerVisible(
516 };
517 layers_menu.subitems.push_back(std::move(bg1_layout_item));
518
519 gui::CanvasMenuItem bg1_objects_item("BG1 Objects", [this, room_id]() {
520 auto& mgr = GetRoomLayerManager(room_id);
521 mgr.SetLayerVisible(zelda3::LayerType::BG1_Objects,
522 !mgr.IsLayerVisible(zelda3::LayerType::BG1_Objects));
523 });
524 bg1_objects_item.checked_condition = [this, room_id]() {
525 return GetRoomLayerManager(room_id).IsLayerVisible(
527 };
528 layers_menu.subitems.push_back(std::move(bg1_objects_item));
529
530 gui::CanvasMenuItem bg2_layout_item("BG2 Layout", [this, room_id]() {
531 auto& mgr = GetRoomLayerManager(room_id);
532 mgr.SetLayerVisible(zelda3::LayerType::BG2_Layout,
533 !mgr.IsLayerVisible(zelda3::LayerType::BG2_Layout));
534 });
535 bg2_layout_item.checked_condition = [this, room_id]() {
536 return GetRoomLayerManager(room_id).IsLayerVisible(
538 };
539 layers_menu.subitems.push_back(std::move(bg2_layout_item));
540
541 gui::CanvasMenuItem bg2_objects_item("BG2 Objects", [this, room_id]() {
542 auto& mgr = GetRoomLayerManager(room_id);
543 mgr.SetLayerVisible(zelda3::LayerType::BG2_Objects,
544 !mgr.IsLayerVisible(zelda3::LayerType::BG2_Objects));
545 });
546 bg2_objects_item.checked_condition = [this, room_id]() {
547 return GetRoomLayerManager(room_id).IsLayerVisible(
549 };
550 layers_menu.subitems.push_back(std::move(bg2_objects_item));
551
552 gui::CanvasMenuItem sprites_item("Sprites", ICON_MD_PERSON, [this]() {
554 });
555 sprites_item.checked_condition = [this]() {
557 };
558 layers_menu.subitems.push_back(std::move(sprites_item));
559
560 gui::CanvasMenuItem pot_items_item("Pot Items", ICON_MD_INVENTORY, [this]() {
562 });
563 pot_items_item.checked_condition = [this]() {
565 };
566 layers_menu.subitems.push_back(std::move(pot_items_item));
567
568 return layers_menu;
569}
570
572 gui::CanvasMenuItem overlays_menu;
573 overlays_menu.label = "Overlays";
574 overlays_menu.icon = ICON_MD_LAYERS;
575
576 gui::CanvasMenuItem coordinates_item(
577 "Coordinates", ICON_MD_MY_LOCATION,
579 coordinates_item.checked_condition = [this]() {
581 };
582 overlays_menu.subitems.push_back(std::move(coordinates_item));
583
584 gui::CanvasMenuItem minecart_toggle(
585 "Minecart Tracks", ICON_MD_TRAIN,
587 minecart_toggle.enabled_condition = [this]() {
588 return minecart_track_panel_ != nullptr;
589 };
590 minecart_toggle.checked_condition = [this]() {
592 };
593 overlays_menu.subitems.push_back(std::move(minecart_toggle));
594
595 gui::CanvasMenuItem custom_collision_item(
596 "Custom Collision", ICON_MD_GRID_ON, [this]() {
598 });
599 custom_collision_item.checked_condition = [this]() {
601 };
602 overlays_menu.subitems.push_back(std::move(custom_collision_item));
603
604 gui::CanvasMenuItem track_collision_item(
605 "Track Collision", ICON_MD_LAYERS, [this]() {
607 });
608 track_collision_item.checked_condition = [this]() {
610 };
611 overlays_menu.subitems.push_back(std::move(track_collision_item));
612
613 gui::CanvasMenuItem camera_quadrants_item(
614 "Camera Quadrants", ICON_MD_GRID_VIEW, [this]() {
616 });
617 camera_quadrants_item.checked_condition = [this]() {
619 };
620 overlays_menu.subitems.push_back(std::move(camera_quadrants_item));
621
622 gui::CanvasMenuItem minecart_sprites_item(
623 "Minecart Sprites", ICON_MD_TRAIN, [this]() {
625 });
626 minecart_sprites_item.checked_condition = [this]() {
628 };
629 overlays_menu.subitems.push_back(std::move(minecart_sprites_item));
630
632 gui::CanvasMenuItem collision_legend_item(
633 "Collision Legend", ICON_MD_INFO, [this]() {
635 });
636 collision_legend_item.checked_condition = [this]() {
638 };
639 overlays_menu.subitems.push_back(std::move(collision_legend_item));
640 }
641
642 gui::CanvasMenuItem object_bounds_item(
643 "Object Bounds", ICON_MD_CROP_SQUARE,
645 object_bounds_item.checked_condition = [this]() {
646 return show_object_bounds_;
647 };
648 overlays_menu.subitems.push_back(std::move(object_bounds_item));
649
650 return overlays_menu;
651}
652
654 gui::CanvasMenuItem debug_menu;
655 debug_menu.label = "Debug";
656 debug_menu.icon = ICON_MD_BUG_REPORT;
657
658 debug_menu.subitems.push_back(gui::CanvasMenuItem(
659 "Room Info", ICON_MD_INFO,
661 debug_menu.subitems.back().checked_condition = [this]() {
663 };
664
665 debug_menu.subitems.push_back(gui::CanvasMenuItem(
666 "Texture Debug", ICON_MD_IMAGE,
667 [this]() { show_texture_debug_ = !show_texture_debug_; }));
668 debug_menu.subitems.back().checked_condition = [this]() {
669 return show_texture_debug_;
670 };
671
672 gui::CanvasMenuItem object_bounds_menu;
673 object_bounds_menu.label = "Object Bounds Filter";
674 object_bounds_menu.icon = ICON_MD_CROP_SQUARE;
675
676 object_bounds_menu.subitems.push_back(
677 gui::CanvasMenuItem("Type 1 (0x00-0xFF)", [this]() {
680 }));
681 object_bounds_menu.subitems.back().checked_condition = [this]() {
683 };
684 object_bounds_menu.subitems.push_back(
685 gui::CanvasMenuItem("Type 2 (0x100-0x1FF)", [this]() {
688 }));
689 object_bounds_menu.subitems.back().checked_condition = [this]() {
691 };
692 object_bounds_menu.subitems.push_back(
693 gui::CanvasMenuItem("Type 3 (0xF00-0xFFF)", [this]() {
696 }));
697 object_bounds_menu.subitems.back().checked_condition = [this]() {
699 };
700
702 sep.label = "---";
703 sep.enabled_condition = []() {
704 return false;
705 };
706 object_bounds_menu.subitems.push_back(std::move(sep));
707
708 object_bounds_menu.subitems.push_back(
709 gui::CanvasMenuItem("Primary / Upper layer (BG1)", [this]() {
712 }));
713 object_bounds_menu.subitems.back().checked_condition = [this]() {
715 };
716 object_bounds_menu.subitems.push_back(
717 gui::CanvasMenuItem("BG2 overlay / Lower layer (BG2)", [this]() {
720 }));
721 object_bounds_menu.subitems.back().checked_condition = [this]() {
723 };
724 object_bounds_menu.subitems.push_back(
725 gui::CanvasMenuItem("BG1 overlay (room stream only)", [this]() {
728 }));
729 object_bounds_menu.subitems.back().checked_condition = [this]() {
731 };
732 debug_menu.subitems.push_back(std::move(object_bounds_menu));
733
734 debug_menu.subitems.push_back(
736 [this]() { show_layer_info_ = !show_layer_info_; }));
737 debug_menu.subitems.back().checked_condition = [this]() {
738 return show_layer_info_;
739 };
740
741 debug_menu.subitems.push_back(
742 gui::CanvasMenuItem("Force Reload", ICON_MD_REFRESH, [this, room_id]() {
743 if (rooms_ && room_id >= 0 && room_id < zelda3::kNumberOfRooms) {
744 (*rooms_)[room_id].ReloadGraphics(current_entrance_blockset_);
745 }
746 }));
747
748 debug_menu.subitems.push_back(
749 gui::CanvasMenuItem("Log Room State", ICON_MD_PRINT, [this, room_id]() {
750 if (!rooms_ || room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
751 return;
752 }
753 const auto& room = (*rooms_)[room_id];
754 LOG_DEBUG("DungeonDebug", "=== Room %03X Debug ===", room_id);
755 LOG_DEBUG("DungeonDebug", "Blockset: %d, Palette: %d, Layout: %d",
756 room.blockset(), room.palette(), room.layout_id());
757 LOG_DEBUG("DungeonDebug", "Objects: %zu, Sprites: %zu",
758 room.GetTileObjects().size(), room.GetSprites().size());
759 LOG_DEBUG("DungeonDebug", "BG1: %dx%d, BG2: %dx%d",
760 room.bg1_buffer().bitmap().width(),
761 room.bg1_buffer().bitmap().height(),
762 room.bg2_buffer().bitmap().width(),
763 room.bg2_buffer().bitmap().height());
764 }));
765
766 return debug_menu;
767}
768
769} // namespace yaze::editor
bool is_loaded() const
Definition rom.h:155
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::string BuildDrawIssueReport(const zelda3::Room &room, 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_object_tiles_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)
gui::CanvasMenuItem BuildSelectionContextMenu(int room_id)
std::string BuildRoomMetadataSummary(const zelda3::Room &room, int room_id) const
gui::CanvasMenuItem BuildReportContextMenu(int room_id)
std::function< void()> show_object_panel_callback_
zelda3::RoomLayerManager & GetRoomLayerManager(int room_id)
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:403
void ClearContextMenuItems()
Definition canvas.cc:874
void AddContextMenuItem(const gui::CanvasMenuItem &item)
Definition canvas.cc:851
auto zero_point() const
Definition canvas.h:354
auto scrolling() const
Definition canvas.h:356
std::optional< ImVec2 > context_menu_open_screen_position() const
Definition canvas.h:201
static bool IsEditableStandardObject(int16_t object_id)
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_SELECT_ALL
Definition icons.h:1680
#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