137 const bool has_selection = !selected.empty();
138 const bool single_selection = selected.size() == 1;
139 const bool group_selection = selected.size() > 1;
140 const bool has_clipboard = interaction.HasClipboardData();
141 const bool placing_object = interaction.IsObjectLoaded();
142 const bool valid_room =
144 const bool room_has_objects =
145 valid_room && !(*rooms_)[room_id].GetTileObjects().empty();
146 bool has_room_stream_object =
false;
147 bool has_special_layer_object =
false;
148 if (has_selection && valid_room) {
149 const auto& objects = (*rooms_)[room_id].GetTileObjects();
150 for (
const size_t index : selected) {
151 if (index >= objects.size()) {
155 has_room_stream_object =
true;
157 has_special_layer_object =
true;
162 std::vector<gui::CanvasMenuItem> items;
164 bool can_edit_selected_graphics =
false;
165 std::function<void()> edit_selected_graphics;
166 bool can_edit_selected_tiles =
false;
167 std::function<void()> edit_selected_tiles;
168 if (single_selection && valid_room) {
169 auto& room = (*rooms_)[room_id];
170 const auto& objects = room.GetTileObjects();
171 if (selected[0] < objects.size()) {
172 const auto object = objects[selected[0]];
175 edit_selected_graphics = [
this, room_id, object]() {
182 can_edit_selected_tiles =
185 edit_selected_tiles = [
this, room_id, object]() {
193 auto enabled_if = [](
bool enabled) {
198 auto paste_item = [&]() {
201 [&interaction]() { interaction.HandlePasteObjects(); },
"Ctrl+V");
205 auto disabled_item = [](
const char* label,
const char* icon,
206 const char* shortcut =
nullptr) {
210 if (shortcut !=
nullptr) {
218 auto layer_item = [&interaction](
const char* label,
int layer,
219 const char* shortcut) {
222 [&interaction, layer]() { interaction.SendSelectedToLayer(layer); },
227 std::optional<size_t> sample_item_index;
228 if (context_sample_object.has_value()) {
229 sample_item_index = items.size();
231 [
this,
object = *context_sample_object]() {
240 interaction.HandleCopySelected();
241 interaction.HandleDeleteSelected();
246 [&interaction]() { interaction.HandleCopySelected(); },
"Ctrl+C");
247 items.push_back(paste_item());
250 [&interaction]() { interaction.HandleDeleteSelected(); },
"Del");
254 [&interaction]() { interaction.SendSelectedToFront(); },
258 [&interaction]() { interaction.SendSelectedToBack(); },
"Ctrl+Shift+[");
261 z_order.
label =
"Z Order";
265 [&interaction]() { interaction.BringSelectedForward(); },
"Ctrl+]");
268 [&interaction]() { interaction.SendSelectedBackward(); },
"Ctrl+[");
269 items.push_back(std::move(z_order));
271 if (has_room_stream_object && !has_special_layer_object) {
272 items.push_back(layer_item(
"Object Stream: Primary", 0,
"1"));
273 items.push_back(layer_item(
"Object Stream: BG2 Overlay", 1,
"2"));
274 items.push_back(layer_item(
"Object Stream: BG1 Overlay", 2,
"3"));
275 }
else if (has_special_layer_object && !has_room_stream_object) {
276 items.push_back(layer_item(
"Upper Layer (BG1)", 0,
"1"));
277 items.push_back(layer_item(
"Lower Layer (BG2)", 1,
"2"));
280 layer_item(
"Placement 0: Primary / Upper Layer (BG1)", 0,
"1"));
282 layer_item(
"Placement 1: BG2 Overlay / Lower Layer (BG2)", 1,
"2"));
286 yaze_more.
label =
"More";
291 interaction.HandleCopySelected();
292 interaction.HandlePasteObjects();
295 if (group_selection) {
299 items.push_back(std::move(yaze_more));
302 if (can_edit_selected_graphics) {
304 std::move(edit_selected_graphics));
306 if (can_edit_selected_tiles) {
308 std::move(edit_selected_tiles));
311 const bool has_entity_selection = interaction.HasEntitySelection();
312 if (has_entity_selection && !has_selection) {
315 [&interaction]() { interaction.HandleDeleteSelected(); },
"Del");
318 if (!has_selection && !has_entity_selection) {
319 items.push_back(paste_item());
323 [&interaction]() { interaction.HandleDeleteAllObjects(); });
325 items.push_back(std::move(delete_all_item));
328 if (placing_object) {
331 [&interaction]() { interaction.CancelPlacement(); },
"Esc");
332 if (!items.empty()) {
335 items.push_back(std::move(cancel_item));
338 if (sample_item_index.has_value() && items.size() > *sample_item_index + 1) {
339 items[*sample_item_index].separator_after =
true;
342 if (!items.empty()) {
343 items.back().separator_after =
true;
641 debug_menu.
label =
"Debug";
647 debug_menu.
subitems.back().checked_condition = [
this]() {
654 debug_menu.
subitems.back().checked_condition = [
this]() {
659 object_bounds_menu.
label =
"Object Bounds Filter";
662 object_bounds_menu.
subitems.push_back(
667 object_bounds_menu.
subitems.back().checked_condition = [
this]() {
670 object_bounds_menu.
subitems.push_back(
675 object_bounds_menu.
subitems.back().checked_condition = [
this]() {
678 object_bounds_menu.
subitems.push_back(
683 object_bounds_menu.
subitems.back().checked_condition = [
this]() {
692 object_bounds_menu.
subitems.push_back(std::move(sep));
694 object_bounds_menu.
subitems.push_back(
699 object_bounds_menu.
subitems.back().checked_condition = [
this]() {
702 object_bounds_menu.
subitems.push_back(
707 object_bounds_menu.
subitems.back().checked_condition = [
this]() {
710 object_bounds_menu.
subitems.push_back(
715 object_bounds_menu.
subitems.back().checked_condition = [
this]() {
718 debug_menu.
subitems.push_back(std::move(object_bounds_menu));
723 debug_menu.
subitems.back().checked_condition = [
this]() {
739 const auto& room = (*rooms_)[room_id];
740 LOG_DEBUG(
"DungeonDebug",
"=== Room %03X Debug ===", room_id);
741 LOG_DEBUG(
"DungeonDebug",
"Blockset: %d, Palette: %d, Layout: %d",
742 room.blockset(), room.palette(), room.layout_id());
743 LOG_DEBUG(
"DungeonDebug",
"Objects: %zu, Sprites: %zu",
744 room.GetTileObjects().size(), room.GetSprites().size());
745 LOG_DEBUG(
"DungeonDebug",
"BG1: %dx%d, BG2: %dx%d",
746 room.bg1_buffer().bitmap().width(),
747 room.bg1_buffer().bitmap().height(),
748 room.bg2_buffer().bitmap().width(),
749 room.bg2_buffer().bitmap().height());