yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
map_properties.cc
Go to the documentation of this file.
2
3#include "absl/strings/str_format.h"
10#include "app/gui/core/input.h"
14#include "imgui/imgui.h"
17
18namespace yaze {
19namespace editor {
20
21using ImGui::BeginTable;
22// HOVER_HINT is defined in util/macro.h
23using ImGui::Separator;
24using ImGui::TableNextColumn;
25using ImGui::Text;
26
27// Using centralized UI constants
28
30 int& current_world, int& current_map, bool& current_map_lock,
31 bool& show_map_properties_panel, bool& show_custom_bg_color_editor,
32 bool& show_overlay_editor, bool& show_overlay_preview, int& game_state,
33 EditingMode& current_mode, EntityEditMode& entity_edit_mode) {
34 (void)show_overlay_editor; // Reserved for future use
35 (void)show_custom_bg_color_editor; // Now handled by sidebar
36 (void)game_state; // Now handled by sidebar
37 (void)show_overlay_preview; // Reserved
38
39 // Simplified canvas toolbar - Navigation and Mode controls
40 if (BeginTable("CanvasToolbar", 7,
41 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit,
42 ImVec2(0, 0), -1)) {
43 ImGui::TableSetupColumn("World", ImGuiTableColumnFlags_WidthFixed,
45 ImGui::TableSetupColumn("Map", ImGuiTableColumnFlags_WidthFixed,
47 ImGui::TableSetupColumn("Area Size", ImGuiTableColumnFlags_WidthFixed,
49 ImGui::TableSetupColumn("Lock", ImGuiTableColumnFlags_WidthFixed,
51 ImGui::TableSetupColumn("Mode", ImGuiTableColumnFlags_WidthFixed,
52 80.0f); // Mouse/Paint
53 ImGui::TableSetupColumn(
54 "Entity", ImGuiTableColumnFlags_WidthStretch); // Entity status
55 ImGui::TableSetupColumn("Sidebar", ImGuiTableColumnFlags_WidthFixed, 40.0f);
56
57 TableNextColumn();
58 ImGui::SetNextItemWidth(kComboWorldWidth);
59 ImGui::Combo("##world", &current_world, kWorldNames, 3);
60
61 TableNextColumn();
62 ImGui::Text("%d (0x%02X)", current_map, current_map);
63
64 TableNextColumn();
65 // Use centralized version detection
67
68 // ALL ROMs support Small/Large. Only v3+ supports Wide/Tall.
69 int current_area_size =
70 static_cast<int>(overworld_->overworld_map(current_map)->area_size());
71 ImGui::SetNextItemWidth(kComboAreaSizeWidth);
72
74 // v3+ ROM: Show all 4 area size options
75 if (ImGui::Combo("##AreaSize", &current_area_size, kAreaSizeNames, 4)) {
76 auto status = overworld_->ConfigureMultiAreaMap(
77 current_map, static_cast<zelda3::AreaSizeEnum>(current_area_size));
78 if (status.ok()) {
79 RefreshSiblingMapGraphics(current_map, true);
81 }
82 }
83 } else {
84 // Vanilla/v1/v2 ROM: Show only Small/Large (first 2 options)
85 const char* limited_names[] = {"Small (1x1)", "Large (2x2)"};
86 int limited_size = (current_area_size == 0 || current_area_size == 1)
87 ? current_area_size
88 : 0;
89
90 if (ImGui::Combo("##AreaSize", &limited_size, limited_names, 2)) {
91 // limited_size is 0 (Small) or 1 (Large)
92 auto size = (limited_size == 1) ? zelda3::AreaSizeEnum::LargeArea
94 auto status = overworld_->ConfigureMultiAreaMap(current_map, size);
95 if (status.ok()) {
96 RefreshSiblingMapGraphics(current_map, true);
98 }
99 }
100
101 if (rom_version == zelda3::OverworldVersion::kVanilla ||
103 HOVER_HINT("Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
104 }
105 }
106
107 TableNextColumn();
108 if (ImGui::Button(current_map_lock ? ICON_MD_LOCK : ICON_MD_LOCK_OPEN,
109 ImVec2(40, 0))) {
110 current_map_lock = !current_map_lock;
111 }
112 HOVER_HINT(current_map_lock ? "Unlock Map" : "Lock Map");
113
114 TableNextColumn();
115 // Mode Controls
116 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
118 ImVec2(30, 0))) {
119 current_mode = EditingMode::MOUSE;
121 }
122 HOVER_HINT("Mouse Mode (1)\nNavigate, pan, and manage entities");
123
124 ImGui::SameLine();
126 ImVec2(30, 0))) {
127 current_mode = EditingMode::DRAW_TILE;
129 }
130 HOVER_HINT("Tile Paint Mode (2)\nDraw tiles on the map");
131 ImGui::PopStyleVar();
132
133 TableNextColumn();
134 // Entity Status
135 if (entity_edit_mode != EntityEditMode::NONE) {
136 const char* entity_icon = "";
137 const char* entity_label = "";
138 switch (entity_edit_mode) {
140 entity_icon = ICON_MD_DOOR_FRONT;
141 entity_label = "Entrances";
142 break;
144 entity_icon = ICON_MD_DOOR_BACK;
145 entity_label = "Exits";
146 break;
148 entity_icon = ICON_MD_GRASS;
149 entity_label = "Items";
150 break;
152 entity_icon = ICON_MD_PEST_CONTROL_RODENT;
153 entity_label = "Sprites";
154 break;
156 entity_icon = ICON_MD_ADD_LOCATION;
157 entity_label = "Transports";
158 break;
160 entity_icon = ICON_MD_MUSIC_NOTE;
161 entity_label = "Music";
162 break;
163 default:
164 break;
165 }
166 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "%s %s", entity_icon,
167 entity_label);
168 }
169
170 TableNextColumn();
171 // Sidebar Toggle
172 if (ImGui::Button(ICON_MD_TUNE, ImVec2(40, 0))) {
173 show_map_properties_panel = !show_map_properties_panel;
174 }
175 HOVER_HINT("Toggle Map Properties Sidebar");
176
177 ImGui::EndTable();
178 }
179}
180
182 int current_map, bool& show_map_properties_panel) {
183 (void)show_map_properties_panel; // Used by caller for window state
184 if (!overworld_->is_loaded()) {
185 Text("No overworld loaded");
186 return;
187 }
188
189 // Header with map info and lock status
190 ImGui::BeginGroup();
191 Text("Current Map: %d (0x%02X)", current_map, current_map);
192 ImGui::EndGroup();
193
194 Separator();
195
196 // Create tabs for different property categories
197 if (ImGui::BeginTabBar("MapPropertiesTabs",
198 ImGuiTabBarFlags_FittingPolicyScroll)) {
199 // Basic Properties Tab
200 if (ImGui::BeginTabItem("Basic Properties")) {
201 DrawBasicPropertiesTab(current_map);
202 ImGui::EndTabItem();
203 }
204
205 // Sprite Properties Tab
206 if (ImGui::BeginTabItem("Sprite Properties")) {
207 DrawSpritePropertiesTab(current_map);
208 ImGui::EndTabItem();
209 }
210
211 // Custom Overworld Features Tab
213 if (rom_version != zelda3::OverworldVersion::kVanilla &&
214 ImGui::BeginTabItem("Custom Features")) {
215 DrawCustomFeaturesTab(current_map);
216 ImGui::EndTabItem();
217 }
218
219 // Tile Graphics Tab
220 if (ImGui::BeginTabItem("Tile Graphics")) {
221 DrawTileGraphicsTab(current_map);
222 ImGui::EndTabItem();
223 }
224
225 // Music Tab
226 if (ImGui::BeginTabItem("Music")) {
227 DrawMusicTab(current_map);
228 ImGui::EndTabItem();
229 }
230
231 ImGui::EndTabBar();
232 }
233}
234
236 int current_map, bool& show_custom_bg_color_editor) {
237 (void)show_custom_bg_color_editor; // Used by caller for window state
238 if (!overworld_->is_loaded()) {
239 Text("No overworld loaded");
240 return;
241 }
242
245 Text("Custom background colors require ZSCustomOverworld v2+");
246 return;
247 }
248
249 Text("Custom Background Color Editor");
250 Separator();
251
252 // Read enable flag from ROM (not static - must reflect current ROM state)
253 bool use_area_specific_bg_color =
255 if (ImGui::Checkbox("Use Area-Specific Background Color",
256 &use_area_specific_bg_color)) {
257 // Update ROM data when checkbox is toggled
259 use_area_specific_bg_color ? 0x01 : 0x00;
260 }
261
262 if (use_area_specific_bg_color) {
263 // Get current color
264 uint16_t current_color =
265 overworld_->overworld_map(current_map)->area_specific_bg_color();
266 gfx::SnesColor snes_color(current_color);
267
268 // Convert to ImVec4 for color picker
269 ImVec4 color_vec = gui::ConvertSnesColorToImVec4(snes_color);
270
271 if (ImGui::ColorPicker4(
272 "Background Color", (float*)&color_vec,
273 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHex)) {
274 // Convert back to SNES color and update
275 gfx::SnesColor new_snes_color = gui::ConvertImVec4ToSnesColor(color_vec);
277 ->set_area_specific_bg_color(new_snes_color.snes());
278
279 // Update ROM
280 int rom_address =
282 (*rom_)[rom_address] = new_snes_color.snes() & 0xFF;
283 (*rom_)[rom_address + 1] = (new_snes_color.snes() >> 8) & 0xFF;
284 }
285
286 Text("SNES Color: 0x%04X", current_color);
287 }
288}
289
291 bool& show_overlay_editor) {
292 (void)show_overlay_editor; // Used by caller for window state
293 if (!overworld_->is_loaded()) {
294 Text("No overworld loaded");
295 return;
296 }
297
299
300 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
301 ICON_MD_LAYERS " Visual Effects Configuration");
302 ImGui::Text("Map: 0x%02X", current_map);
303 Separator();
304
305 if (rom_version == zelda3::OverworldVersion::kVanilla) {
306 ImGui::TextColored(
307 ImVec4(1.0f, 0.8f, 0.4f, 1.0f), ICON_MD_INFO
308 " Enhanced overlay editing requires ZSCustomOverworld v1+");
309 ImGui::Separator();
310 ImGui::TextWrapped(
311 "Subscreen overlays are a vanilla feature used for atmospheric effects "
312 "like fog, rain, and forest canopy. ZSCustomOverworld expands this by "
313 "allowing per-area overlay configuration and additional "
314 "customization.");
315 return;
316 }
317
318 // Help section
319 if (ImGui::CollapsingHeader(ICON_MD_HELP_OUTLINE " What are Visual Effects?",
320 ImGuiTreeNodeFlags_DefaultOpen)) {
321 ImGui::Indent();
322 ImGui::TextWrapped(
323 "Visual effects (subscreen overlays) are semi-transparent layers drawn "
324 "on top of or behind your map. They reference special area maps "
325 "(0x80-0x9F) "
326 "for their tile16 graphics data.");
327 ImGui::Spacing();
328 ImGui::Text("Common uses:");
329 ImGui::BulletText("Fog effects (Lost Woods, Skull Woods)");
330 ImGui::BulletText("Rain (Misery Mire)");
331 ImGui::BulletText("Forest canopy (Lost Woods)");
332 ImGui::BulletText("Sky backgrounds (Death Mountain)");
333 ImGui::BulletText("Under bridge views");
334 ImGui::Unindent();
335 ImGui::Separator();
336 }
337
338 // Read enable flag from ROM (not static - must reflect current ROM state)
339 bool use_subscreen_overlay =
341 if (ImGui::Checkbox(ICON_MD_VISIBILITY " Enable Visual Effect for This Area",
342 &use_subscreen_overlay)) {
343 // Update ROM data when checkbox is toggled
345 use_subscreen_overlay ? 0x01 : 0x00;
346 }
347 if (ImGui::IsItemHovered()) {
348 ImGui::SetTooltip("Enable/disable visual effect overlay for this map area");
349 }
350
351 if (use_subscreen_overlay) {
352 ImGui::Spacing();
353 uint16_t current_overlay =
354 overworld_->overworld_map(current_map)->subscreen_overlay();
355 if (gui::InputHexWord(ICON_MD_PHOTO " Visual Effect Map ID",
356 &current_overlay, kInputFieldSize + 30)) {
358 ->set_subscreen_overlay(current_overlay);
359
360 // Update ROM
361 int rom_address =
363 (*rom_)[rom_address] = current_overlay & 0xFF;
364 (*rom_)[rom_address + 1] = (current_overlay >> 8) & 0xFF;
365 }
366 if (ImGui::IsItemHovered()) {
367 ImGui::SetTooltip(
368 "ID of the special area map (0x80-0x9F) to use for\n"
369 "visual effects. That map's tile16 data will be drawn\n"
370 "as a semi-transparent layer on this area.");
371 }
372
373 // Show description
374 std::string overlay_desc = GetOverlayDescription(current_overlay);
375 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), ICON_MD_INFO " %s",
376 overlay_desc.c_str());
377
378 ImGui::Separator();
379 if (ImGui::CollapsingHeader(ICON_MD_LIGHTBULB
380 " Common Visual Effect IDs")) {
381 ImGui::Indent();
382 ImGui::BulletText("0x0093 - Triforce Room Curtain");
383 ImGui::BulletText("0x0094 - Under the Bridge");
384 ImGui::BulletText("0x0095 - Sky Background (LW Death Mountain)");
385 ImGui::BulletText("0x0096 - Pyramid Background");
386 ImGui::BulletText("0x0097 - Fog Overlay (Master Sword Area)");
387 ImGui::BulletText("0x009C - Lava Background (DW Death Mountain)");
388 ImGui::BulletText("0x009D - Fog Overlay (Lost/Skull Woods)");
389 ImGui::BulletText("0x009E - Tree Canopy (Forest)");
390 ImGui::BulletText("0x009F - Rain Effect (Misery Mire)");
391 ImGui::BulletText("0x00FF - No Overlay (Disabled)");
392 ImGui::Unindent();
393 }
394 } else {
395 ImGui::Spacing();
396 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), ICON_MD_BLOCK
397 " No visual effects enabled for this area");
398 }
399}
400
402 gui::Canvas& canvas, int current_map, bool current_map_lock,
403 bool& show_map_properties_panel, bool& show_custom_bg_color_editor,
404 bool& show_overlay_editor, int current_mode) {
405 (void)current_map; // Used for future context-sensitive menu items
406 // Clear any existing context menu items
407 canvas.ClearContextMenuItems();
408
409 // Add entity insertion submenu (only in MOUSE mode)
410 if (current_mode == 0 && entity_insert_callback_) { // 0 = EditingMode::MOUSE
411 gui::CanvasMenuItem entity_menu;
412 entity_menu.label = ICON_MD_ADD_LOCATION " Insert Entity";
413
414 // Entrance submenu item
415 gui::CanvasMenuItem entrance_item;
416 entrance_item.label = ICON_MD_DOOR_FRONT " Entrance";
417 entrance_item.callback = [this]() {
419 entity_insert_callback_("entrance");
420 }
421 };
422 entity_menu.subitems.push_back(entrance_item);
423
424 // Hole submenu item
425 gui::CanvasMenuItem hole_item;
426 hole_item.label = ICON_MD_CYCLONE " Hole";
427 hole_item.callback = [this]() {
430 }
431 };
432 entity_menu.subitems.push_back(hole_item);
433
434 // Exit submenu item
435 gui::CanvasMenuItem exit_item;
436 exit_item.label = ICON_MD_DOOR_BACK " Exit";
437 exit_item.callback = [this]() {
440 }
441 };
442 entity_menu.subitems.push_back(exit_item);
443
444 // Item submenu item
445 gui::CanvasMenuItem item_item;
446 item_item.label = ICON_MD_GRASS " Item";
447 item_item.callback = [this]() {
450 }
451 };
452 entity_menu.subitems.push_back(item_item);
453
454 // Sprite submenu item
455 gui::CanvasMenuItem sprite_item;
456 sprite_item.label = ICON_MD_PEST_CONTROL_RODENT " Sprite";
457 sprite_item.callback = [this]() {
459 entity_insert_callback_("sprite");
460 }
461 };
462 entity_menu.subitems.push_back(sprite_item);
463
464 canvas.AddContextMenuItem(entity_menu);
465
466 // Add "Edit Tile16" option in MOUSE mode
468 gui::CanvasMenuItem tile16_edit_item;
469 tile16_edit_item.label = ICON_MD_GRID_VIEW " Edit Tile16";
470 tile16_edit_item.callback = [this]() {
473 }
474 };
475 canvas.AddContextMenuItem(tile16_edit_item);
476 }
477 }
478
479 // Add overworld-specific context menu items
480 gui::CanvasMenuItem lock_item;
481 lock_item.label = current_map_lock ? "Unlock Map" : "Lock to This Map";
482 lock_item.callback = [&current_map_lock]() {
483 current_map_lock = !current_map_lock;
484 };
485 canvas.AddContextMenuItem(lock_item);
486
487 // Area Configuration
488 gui::CanvasMenuItem properties_item;
489 properties_item.label = ICON_MD_TUNE " Area Configuration";
490 properties_item.callback = [&show_map_properties_panel]() {
491 show_map_properties_panel = true;
492 };
493 canvas.AddContextMenuItem(properties_item);
494
495 // Custom overworld features (only show if v3+)
498 // Custom Background Color
499 gui::CanvasMenuItem bg_color_item;
500 bg_color_item.label = ICON_MD_FORMAT_COLOR_FILL " Custom Background Color";
501 bg_color_item.callback = [&show_custom_bg_color_editor]() {
502 show_custom_bg_color_editor = true;
503 };
504 canvas.AddContextMenuItem(bg_color_item);
505
506 // Visual Effects Editor
507 gui::CanvasMenuItem overlay_item;
508 overlay_item.label = ICON_MD_LAYERS " Visual Effects";
509 overlay_item.callback = [&show_overlay_editor]() {
510 show_overlay_editor = true;
511 };
512 canvas.AddContextMenuItem(overlay_item);
513 }
514
515 // Canvas controls
516 gui::CanvasMenuItem reset_view_item;
517 reset_view_item.label = ICON_MD_RESTORE " Reset View";
518 reset_view_item.callback = [&canvas]() {
519 canvas.set_global_scale(1.0f);
520 canvas.set_scrolling(ImVec2(0, 0));
521 };
522 canvas.AddContextMenuItem(reset_view_item);
523
524 gui::CanvasMenuItem zoom_in_item;
525 zoom_in_item.label = ICON_MD_ZOOM_IN " Zoom In";
526 zoom_in_item.callback = [&canvas]() {
527 float scale =
529 canvas.set_global_scale(scale);
530 };
531 canvas.AddContextMenuItem(zoom_in_item);
532
533 gui::CanvasMenuItem zoom_out_item;
534 zoom_out_item.label = ICON_MD_ZOOM_OUT " Zoom Out";
535 zoom_out_item.callback = [&canvas]() {
536 float scale =
538 canvas.set_global_scale(scale);
539 };
540 canvas.AddContextMenuItem(zoom_out_item);
541}
542
543// Private method implementations
544void MapPropertiesSystem::DrawGraphicsPopup(int current_map, int game_state) {
547 .c_str())) {
548 ImGui::PushID("GraphicsPopup"); // Fix ImGui duplicate ID warnings
549
550 // Use theme-aware spacing instead of hardcoded constants
552 float padding = gui::LayoutHelpers::GetButtonPadding();
553 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
554 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
555
556 ImGui::Text("Graphics Settings");
557 ImGui::Separator();
558
559 // Area Graphics
560 if (gui::InputHexByte(ICON_MD_IMAGE " Area Graphics",
562 ->mutable_area_graphics(),
564 // CORRECT ORDER: Properties first, then graphics reload
565
566 // 1. Propagate properties to siblings FIRST (calls LoadAreaGraphics on
567 // siblings)
569
570 // 2. Force immediate refresh of current map
571 (*maps_bmp_)[current_map].set_modified(true);
572 overworld_->mutable_overworld_map(current_map)->LoadAreaGraphics();
573
574 // 3. Refresh siblings immediately
575 RefreshSiblingMapGraphics(current_map);
576
577 // 4. Update tile selector
579
580 // 5. Final refresh
582 }
583 HOVER_HINT("Main tileset graphics for this map area");
584
585 // Sprite Graphics
586 if (gui::InputHexByte(absl::StrFormat(ICON_MD_PETS " Sprite GFX (%s)",
587 kGameStateNames[game_state])
588 .c_str(),
590 ->mutable_sprite_graphics(game_state),
592 ForceRefreshGraphics(current_map);
595 }
596 HOVER_HINT("Sprite graphics sheet for current game state");
597
598 auto rom_version_gfx = zelda3::OverworldVersionHelper::GetVersion(*rom_);
600 if (gui::InputHexByte(ICON_MD_ANIMATION " Animated GFX",
602 ->mutable_animated_gfx(),
604 ForceRefreshGraphics(current_map);
608 }
609 HOVER_HINT("Animated tile graphics (water, lava, etc.)");
610 }
611
612 // Custom Tile Graphics - Only available for v1+ ROMs
614 rom_version_gfx)) {
615 ImGui::Separator();
616 ImGui::Text(ICON_MD_GRID_VIEW " Custom Tile Graphics");
617 ImGui::Separator();
618
619 // Show the 8 custom graphics IDs in a 2-column layout for density
620 if (BeginTable("CustomTileGraphics", 2, ImGuiTableFlags_SizingFixedFit)) {
621 for (int i = 0; i < 8; i++) {
622 TableNextColumn();
623 std::string label = absl::StrFormat(ICON_MD_LAYERS " Sheet %d", i);
624 if (gui::InputHexByte(label.c_str(),
626 ->mutable_custom_tileset(i),
627 90.f)) {
628 ForceRefreshGraphics(current_map);
632 }
633 if (ImGui::IsItemHovered()) {
634 ImGui::SetTooltip("Custom graphics sheet %d (0x00-0xFF)", i);
635 }
636 }
637 ImGui::EndTable();
638 }
639 } else if (rom_version_gfx == zelda3::OverworldVersion::kVanilla) {
640 ImGui::Separator();
641 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
642 ICON_MD_INFO " Custom Tile Graphics");
643 ImGui::TextWrapped(
644 "Custom tile graphics require ZSCustomOverworld v1+.\n"
645 "Upgrade your ROM to access 8 customizable graphics sheets.");
646 }
647
648 ImGui::PopStyleVar(2); // Pop the 2 style variables we pushed
649 ImGui::PopID(); // Pop GraphicsPopup ID scope
650 ImGui::EndPopup();
651 }
652}
653
654void MapPropertiesSystem::DrawPalettesPopup(int current_map, int game_state,
655 bool& show_custom_bg_color_editor) {
658 .c_str())) {
659 ImGui::PushID("PalettesPopup"); // Fix ImGui duplicate ID warnings
660
661 // Use theme-aware spacing instead of hardcoded constants
663 float padding = gui::LayoutHelpers::GetButtonPadding();
664 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
665 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
666
667 ImGui::Text("Palette Settings");
668 ImGui::Separator();
669
670 // Area Palette
671 if (gui::InputHexByte(ICON_MD_PALETTE " Area Palette",
673 ->mutable_area_palette(),
676 auto status = RefreshMapPalette();
678 }
679 HOVER_HINT("Main color palette for background tiles");
680
681 // Read fresh to reflect ROM upgrades
682 auto rom_version_pal = zelda3::OverworldVersionHelper::GetVersion(*rom_);
684 rom_version_pal)) {
685 if (gui::InputHexByte(ICON_MD_COLOR_LENS " Main Palette",
687 ->mutable_main_palette(),
690 auto status = RefreshMapPalette();
692 }
693 HOVER_HINT("Extended main palette (ZSCustomOverworld v2+)");
694 }
695
696 // Sprite Palette
697 if (gui::InputHexByte(absl::StrFormat(ICON_MD_COLORIZE " Sprite Pal (%s)",
698 kGameStateNames[game_state])
699 .c_str(),
701 ->mutable_sprite_palette(game_state),
705 }
706 HOVER_HINT("Color palette for sprites in current game state");
707
708 ImGui::Separator();
709 if (ImGui::Button(ICON_MD_FORMAT_COLOR_FILL " Custom Background Color",
710 ImVec2(-1, 0))) {
711 show_custom_bg_color_editor = !show_custom_bg_color_editor;
712 }
713 HOVER_HINT("Open custom background color editor (v2+)");
714
715 ImGui::PopStyleVar(2); // Pop the 2 style variables we pushed
716 ImGui::PopID(); // Pop PalettesPopup ID scope
717 ImGui::EndPopup();
718 }
719}
720
722 bool& show_map_properties_panel,
723 bool& show_overlay_preview,
724 int& game_state) {
727 .c_str())) {
728 ImGui::PushID("ConfigPopup"); // Fix ImGui duplicate ID warnings
729
730 // Use theme-aware spacing instead of hardcoded constants
732 float padding = gui::LayoutHelpers::GetButtonPadding();
733 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
734 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
735
736 ImGui::Text(ICON_MD_TUNE " Area Configuration");
737 ImGui::Separator();
738
739 // Basic Properties in 2-column layout for density
740 if (BeginTable("BasicProps", 2, ImGuiTableFlags_SizingFixedFit)) {
741 // Message ID
742 TableNextColumn();
743 ImGui::Text(ICON_MD_MESSAGE " Message");
744 TableNextColumn();
745 if (gui::InputHexWordCustom("##MsgId",
747 ->mutable_message_id(),
751 }
752 if (ImGui::IsItemHovered()) {
753 ImGui::SetTooltip("Message ID shown when entering this area");
754 }
755
756 // Game State
757 TableNextColumn();
758 ImGui::Text(ICON_MD_GAMEPAD " Game State");
759 TableNextColumn();
760 ImGui::SetNextItemWidth(kComboGameStateWidth);
761 if (ImGui::Combo("##GameState", &game_state, kGameStateNames, 3)) {
764 }
765 if (ImGui::IsItemHovered()) {
766 ImGui::SetTooltip(
767 "Affects sprite graphics/palettes based on story progress");
768 }
769
770 ImGui::EndTable();
771 }
772
773 // Area Configuration Section
774 ImGui::Separator();
775 ImGui::Text(ICON_MD_ASPECT_RATIO " Area Configuration");
776 ImGui::Separator();
777
778 // ALL ROMs support Small/Large. Only v3+ supports Wide/Tall.
779 uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
780
781 int current_area_size =
782 static_cast<int>(overworld_->overworld_map(current_map)->area_size());
783 ImGui::SetNextItemWidth(kComboAreaSizeWidth);
784
785 if (asm_version >= 3 && asm_version != 0xFF) {
786 // v3+ ROM: Show all 4 area size options
787 if (ImGui::Combo(ICON_MD_PHOTO_SIZE_SELECT_LARGE " Size",
788 &current_area_size, kAreaSizeNames, 4)) {
789 auto status = overworld_->ConfigureMultiAreaMap(
790 current_map, static_cast<zelda3::AreaSizeEnum>(current_area_size));
791 if (status.ok()) {
792 RefreshSiblingMapGraphics(current_map, true);
794 }
795 }
796 HOVER_HINT("Map area size (1x1, 2x2, 2x1, 1x2 screens)");
797 } else {
798 // Vanilla/v1/v2 ROM: Show only Small/Large
799 const char* limited_names[] = {"Small (1x1)", "Large (2x2)"};
800 int limited_size = (current_area_size == 0 || current_area_size == 1)
801 ? current_area_size
802 : 0;
803
804 if (ImGui::Combo(ICON_MD_PHOTO_SIZE_SELECT_LARGE " Size", &limited_size,
805 limited_names, 2)) {
806 auto size = (limited_size == 1) ? zelda3::AreaSizeEnum::LargeArea
808 auto status = overworld_->ConfigureMultiAreaMap(current_map, size);
809 if (status.ok()) {
810 RefreshSiblingMapGraphics(current_map, true);
812 }
813 }
814 HOVER_HINT("Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
815 }
816
817 // Visual Effects Section
818 ImGui::Separator();
819 ImGui::Text(ICON_MD_AUTO_FIX_HIGH " Visual Effects");
820 ImGui::Separator();
821
822 DrawMosaicControls(current_map);
823 DrawOverlayControls(current_map, show_overlay_preview);
824
825 // Advanced Options Section
826 ImGui::Separator();
827 if (ImGui::Button(ICON_MD_OPEN_IN_NEW " Full Configuration Panel",
828 ImVec2(-1, 0))) {
829 show_map_properties_panel = true;
830 ImGui::CloseCurrentPopup();
831 }
832 HOVER_HINT("Open detailed area configuration with all settings tabs");
833
834 ImGui::PopStyleVar(2); // Pop the 2 style variables we pushed
835 ImGui::PopID(); // Pop ConfigPopup ID scope
836 ImGui::EndPopup();
837 }
838}
839
841 if (BeginTable("BasicProperties", 2,
842 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
843 ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 180);
844 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
845
846 TableNextColumn();
847 ImGui::Text(ICON_MD_IMAGE " Area Graphics");
848 TableNextColumn();
849 if (gui::InputHexByte("##AreaGfx",
851 ->mutable_area_graphics(),
853 // CORRECT ORDER: Properties first, then graphics reload
855 (*maps_bmp_)[current_map].set_modified(true);
856 overworld_->mutable_overworld_map(current_map)->LoadAreaGraphics();
857 RefreshSiblingMapGraphics(current_map);
860 }
861 if (ImGui::IsItemHovered()) {
862 ImGui::SetTooltip("Main tileset graphics for this map area");
863 }
864
865 TableNextColumn();
866 ImGui::Text(ICON_MD_PALETTE " Area Palette");
867 TableNextColumn();
868 if (gui::InputHexByte("##AreaPal",
870 ->mutable_area_palette(),
873 auto status = RefreshMapPalette();
875 }
876 if (ImGui::IsItemHovered()) {
877 ImGui::SetTooltip("Color palette for background tiles");
878 }
879
880 TableNextColumn();
881 ImGui::Text(ICON_MD_MESSAGE " Message ID");
882 TableNextColumn();
883 if (gui::InputHexWord("##MsgId",
885 ->mutable_message_id(),
886 kInputFieldSize + 20)) {
889 }
890 if (ImGui::IsItemHovered()) {
891 ImGui::SetTooltip("Message displayed when entering this area");
892 }
893
894 TableNextColumn();
895 ImGui::Text(ICON_MD_BLUR_ON " Mosaic Effect");
896 TableNextColumn();
897 if (ImGui::Checkbox(
898 "##mosaic",
899 overworld_->mutable_overworld_map(current_map)->mutable_mosaic())) {
902 }
903 if (ImGui::IsItemHovered()) {
904 ImGui::SetTooltip("Enable pixelated mosaic transition effect");
905 }
906
907 // Add music editing controls with icons
908 TableNextColumn();
909 ImGui::Text(ICON_MD_MUSIC_NOTE " Music (Beginning)");
910 TableNextColumn();
911 if (gui::InputHexByte("##Music0",
913 ->mutable_area_music(0),
916 }
917 if (ImGui::IsItemHovered()) {
918 ImGui::SetTooltip("Music track before rescuing Zelda");
919 }
920
921 TableNextColumn();
922 ImGui::Text(ICON_MD_MUSIC_NOTE " Music (Zelda)");
923 TableNextColumn();
924 if (gui::InputHexByte("##Music1",
926 ->mutable_area_music(1),
929 }
930 if (ImGui::IsItemHovered()) {
931 ImGui::SetTooltip("Music track after rescuing Zelda");
932 }
933
934 TableNextColumn();
935 ImGui::Text(ICON_MD_MUSIC_NOTE " Music (Master Sword)");
936 TableNextColumn();
937 if (gui::InputHexByte("##Music2",
939 ->mutable_area_music(2),
942 }
943 if (ImGui::IsItemHovered()) {
944 ImGui::SetTooltip("Music track after obtaining Master Sword");
945 }
946
947 TableNextColumn();
948 ImGui::Text(ICON_MD_MUSIC_NOTE " Music (Agahnim)");
949 TableNextColumn();
950 if (gui::InputHexByte("##Music3",
952 ->mutable_area_music(3),
955 }
956 if (ImGui::IsItemHovered()) {
957 ImGui::SetTooltip("Music track after defeating Agahnim (Dark World)");
958 }
959
960 ImGui::EndTable();
961 }
962}
963
965 if (BeginTable("SpriteProperties", 2,
966 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
967 ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 180);
968 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
969
970 TableNextColumn();
971 ImGui::Text(ICON_MD_GAMEPAD " Game State");
972 TableNextColumn();
973 static int game_state = 0;
974 ImGui::SetNextItemWidth(120.f);
975 if (ImGui::Combo("##GameState", &game_state, kGameStateNames, 3)) {
978 }
979 if (ImGui::IsItemHovered()) {
980 ImGui::SetTooltip("Affects which sprite graphics/palettes are used");
981 }
982
983 TableNextColumn();
984 ImGui::Text(ICON_MD_PETS " Sprite Graphics 1");
985 TableNextColumn();
986 if (gui::InputHexByte("##SprGfx1",
988 ->mutable_sprite_graphics(1),
992 }
993 if (ImGui::IsItemHovered()) {
994 ImGui::SetTooltip("First sprite graphics sheet for Zelda rescued state");
995 }
996
997 TableNextColumn();
998 ImGui::Text(ICON_MD_PETS " Sprite Graphics 2");
999 TableNextColumn();
1000 if (gui::InputHexByte("##SprGfx2",
1001 overworld_->mutable_overworld_map(current_map)
1002 ->mutable_sprite_graphics(2),
1003 kInputFieldSize)) {
1006 }
1007 if (ImGui::IsItemHovered()) {
1008 ImGui::SetTooltip(
1009 "Second sprite graphics sheet for Master Sword obtained state");
1010 }
1011
1012 TableNextColumn();
1013 ImGui::Text(ICON_MD_COLORIZE " Sprite Palette 1");
1014 TableNextColumn();
1015 if (gui::InputHexByte("##SprPal1",
1016 overworld_->mutable_overworld_map(current_map)
1017 ->mutable_sprite_palette(1),
1018 kInputFieldSize)) {
1021 }
1022 if (ImGui::IsItemHovered()) {
1023 ImGui::SetTooltip("Color palette for sprites - Zelda rescued state");
1024 }
1025
1026 TableNextColumn();
1027 ImGui::Text(ICON_MD_COLORIZE " Sprite Palette 2");
1028 TableNextColumn();
1029 if (gui::InputHexByte("##SprPal2",
1030 overworld_->mutable_overworld_map(current_map)
1031 ->mutable_sprite_palette(2),
1032 kInputFieldSize)) {
1035 }
1036 if (ImGui::IsItemHovered()) {
1037 ImGui::SetTooltip(
1038 "Color palette for sprites - Master Sword obtained state");
1039 }
1040
1041 ImGui::EndTable();
1042 }
1043}
1044
1046 if (BeginTable("CustomFeatures", 2,
1047 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1048 ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 180);
1049 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
1050
1051 TableNextColumn();
1052 ImGui::Text(ICON_MD_PHOTO_SIZE_SELECT_LARGE " Area Size");
1053 TableNextColumn();
1054 // ALL ROMs support Small/Large. Only v3+ supports Wide/Tall.
1055 auto rom_version_basic = zelda3::OverworldVersionHelper::GetVersion(*rom_);
1056
1057 int current_area_size =
1058 static_cast<int>(overworld_->overworld_map(current_map)->area_size());
1059 ImGui::SetNextItemWidth(130.f);
1060
1061 if (zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version_basic)) {
1062 // v3+ ROM: Show all 4 area size options
1063 static const char* all_sizes[] = {"Small (1x1)", "Large (2x2)",
1064 "Wide (2x1)", "Tall (1x2)"};
1065 if (ImGui::Combo("##AreaSize", &current_area_size, all_sizes, 4)) {
1066 auto status = overworld_->ConfigureMultiAreaMap(
1067 current_map, static_cast<zelda3::AreaSizeEnum>(current_area_size));
1068 if (status.ok()) {
1069 RefreshSiblingMapGraphics(current_map, true);
1071 }
1072 }
1073 if (ImGui::IsItemHovered()) {
1074 ImGui::SetTooltip(
1075 "Map size: Small (1x1), Large (2x2), Wide (2x1), Tall (1x2)");
1076 }
1077 } else {
1078 // Vanilla/v1/v2 ROM: Show only Small/Large
1079 static const char* limited_sizes[] = {"Small (1x1)", "Large (2x2)"};
1080 int limited_size = (current_area_size == 0 || current_area_size == 1)
1081 ? current_area_size
1082 : 0;
1083
1084 if (ImGui::Combo("##AreaSize", &limited_size, limited_sizes, 2)) {
1085 auto size = (limited_size == 1) ? zelda3::AreaSizeEnum::LargeArea
1087 auto status = overworld_->ConfigureMultiAreaMap(current_map, size);
1088 if (status.ok()) {
1089 RefreshSiblingMapGraphics(current_map, true);
1091 }
1092 }
1093 if (ImGui::IsItemHovered()) {
1094 ImGui::SetTooltip(
1095 "Map size: Small (1x1), Large (2x2). Wide/Tall require v3+");
1096 }
1097 }
1098
1100 rom_version_basic)) {
1101 TableNextColumn();
1102 ImGui::Text(ICON_MD_COLOR_LENS " Main Palette");
1103 TableNextColumn();
1104 if (gui::InputHexByte("##MainPal",
1105 overworld_->mutable_overworld_map(current_map)
1106 ->mutable_main_palette(),
1107 kInputFieldSize)) {
1109 auto status = RefreshMapPalette();
1111 }
1112 if (ImGui::IsItemHovered()) {
1113 ImGui::SetTooltip("Extended main palette (ZSCustomOverworld v2+)");
1114 }
1115 }
1116
1118 rom_version_basic)) {
1119 TableNextColumn();
1120 ImGui::Text(ICON_MD_ANIMATION " Animated GFX");
1121 TableNextColumn();
1122 if (gui::InputHexByte("##AnimGfx",
1123 overworld_->mutable_overworld_map(current_map)
1124 ->mutable_animated_gfx(),
1125 kInputFieldSize)) {
1128 }
1129 if (ImGui::IsItemHovered()) {
1130 ImGui::SetTooltip("Animated tile graphics ID (water, lava, etc.)");
1131 }
1132
1133 TableNextColumn();
1134 ImGui::Text(ICON_MD_LAYERS " Subscreen Overlay");
1135 TableNextColumn();
1136 if (gui::InputHexWord("##SubOverlay",
1137 overworld_->mutable_overworld_map(current_map)
1138 ->mutable_subscreen_overlay(),
1139 kInputFieldSize + 20)) {
1142 }
1143 if (ImGui::IsItemHovered()) {
1144 ImGui::SetTooltip("Visual effects overlay ID (fog, rain, backgrounds)");
1145 }
1146 }
1147
1148 ImGui::EndTable();
1149 }
1150}
1151
1154
1155 // Only show custom tile graphics for v1+ ROMs
1157 ImGui::Text(ICON_MD_GRID_VIEW " Custom Tile Graphics (8 sheets)");
1158 Separator();
1159
1160 if (BeginTable("TileGraphics", 2,
1161 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1162 ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed,
1163 180);
1164 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
1165
1166 for (int i = 0; i < 8; i++) {
1167 TableNextColumn();
1168 ImGui::Text(ICON_MD_LAYERS " Sheet %d", i);
1169 TableNextColumn();
1170 if (gui::InputHexByte(absl::StrFormat("##TileGfx%d", i).c_str(),
1171 overworld_->mutable_overworld_map(current_map)
1172 ->mutable_custom_tileset(i),
1173 kInputFieldSize)) {
1174 overworld_->mutable_overworld_map(current_map)->LoadAreaGraphics();
1175 ForceRefreshGraphics(current_map);
1176 RefreshSiblingMapGraphics(current_map);
1180 }
1181 if (ImGui::IsItemHovered()) {
1182 ImGui::SetTooltip("Custom graphics sheet %d (0x00-0xFF)", i);
1183 }
1184 }
1185
1186 ImGui::EndTable();
1187 }
1188
1189 Separator();
1190 ImGui::TextWrapped(
1191 "These 8 sheets allow custom tile graphics per map. "
1192 "Each sheet references a graphics ID loaded into VRAM.");
1193 } else {
1194 // Vanilla ROM - show info message
1195 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1196 ICON_MD_INFO " Custom Tile Graphics");
1197 ImGui::Separator();
1198 ImGui::TextWrapped(
1199 "Custom tile graphics are not available in vanilla ROMs.\n\n"
1200 "To enable this feature, upgrade your ROM to ZSCustomOverworld v1+, "
1201 "which provides 8 customizable graphics sheets per map for advanced "
1202 "tileset customization.");
1203 }
1204}
1205
1207 ImGui::Text(ICON_MD_MUSIC_NOTE " Music Settings for Game States");
1208 Separator();
1209
1210 if (BeginTable("MusicSettings", 2,
1211 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1212 ImGui::TableSetupColumn("Game State", ImGuiTableColumnFlags_WidthFixed,
1213 220);
1214 ImGui::TableSetupColumn("Music Track ID",
1215 ImGuiTableColumnFlags_WidthStretch);
1216
1217 const char* music_state_names[] = {
1218 ICON_MD_PLAY_ARROW " Beginning (Pre-Zelda)",
1219 ICON_MD_FAVORITE " Zelda Rescued",
1220 ICON_MD_OFFLINE_BOLT " Master Sword Obtained",
1221 ICON_MD_CASTLE " Agahnim Defeated"};
1222
1223 const char* music_descriptions[] = {
1224 "Music before rescuing Zelda from the castle",
1225 "Music after rescuing Zelda from Hyrule Castle",
1226 "Music after obtaining the Master Sword from the Lost Woods",
1227 "Music after defeating Agahnim (Dark World music)"};
1228
1229 for (int i = 0; i < 4; i++) {
1230 TableNextColumn();
1231 ImGui::Text("%s", music_state_names[i]);
1232
1233 TableNextColumn();
1234 if (gui::InputHexByte(absl::StrFormat("##Music%d", i).c_str(),
1235 overworld_->mutable_overworld_map(current_map)
1236 ->mutable_area_music(i),
1237 kInputFieldSize)) {
1239
1240 // Update the ROM directly since music is not automatically saved
1241 int music_address = 0;
1242 switch (i) {
1243 case 0:
1244 music_address = zelda3::kOverworldMusicBeginning + current_map;
1245 break;
1246 case 1:
1247 music_address = zelda3::kOverworldMusicZelda + current_map;
1248 break;
1249 case 2:
1250 music_address = zelda3::kOverworldMusicMasterSword + current_map;
1251 break;
1252 case 3:
1253 music_address = zelda3::kOverworldMusicAgahnim + current_map;
1254 break;
1255 }
1256
1257 if (music_address > 0) {
1258 (*rom_)[music_address] =
1259 *overworld_->mutable_overworld_map(current_map)
1260 ->mutable_area_music(i);
1261 }
1262 }
1263 if (ImGui::IsItemHovered()) {
1264 ImGui::SetTooltip("%s", music_descriptions[i]);
1265 }
1266 }
1267
1268 ImGui::EndTable();
1269 }
1270
1271 Separator();
1272 ImGui::TextWrapped(
1273 "Music tracks control the background music for different "
1274 "game progression states on this overworld map.");
1275
1276 // Show common music track IDs for reference in a collapsing section
1277 Separator();
1278 if (ImGui::CollapsingHeader(ICON_MD_HELP_OUTLINE " Common Music Track IDs",
1279 ImGuiTreeNodeFlags_DefaultOpen)) {
1280 ImGui::Indent();
1281 ImGui::BulletText("0x02 - Overworld Theme");
1282 ImGui::BulletText("0x05 - Kakariko Village");
1283 ImGui::BulletText("0x07 - Lost Woods");
1284 ImGui::BulletText("0x09 - Dark World Theme");
1285 ImGui::BulletText("0x0F - Ganon's Tower");
1286 ImGui::BulletText("0x11 - Death Mountain");
1287 ImGui::Unindent();
1288 }
1289}
1290
1296
1302
1305 return refresh_map_palette_();
1306 }
1307 return absl::OkStatus();
1308}
1309
1312 return refresh_tile16_blockset_();
1313 }
1314 return absl::OkStatus();
1315}
1316
1319 force_refresh_graphics_(map_index);
1320 }
1321}
1322
1324 bool include_self) {
1325 if (!overworld_ || !maps_bmp_ || map_index < 0 ||
1326 map_index >= zelda3::kNumOverworldMaps) {
1327 return;
1328 }
1329
1330 auto* map = overworld_->mutable_overworld_map(map_index);
1331 if (map->area_size() == zelda3::AreaSizeEnum::SmallArea) {
1332 return; // No siblings for small areas
1333 }
1334
1335 int parent_id = map->parent();
1336 std::vector<int> siblings;
1337
1338 switch (map->area_size()) {
1340 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1341 break;
1343 siblings = {parent_id, parent_id + 1};
1344 break;
1346 siblings = {parent_id, parent_id + 8};
1347 break;
1348 default:
1349 return;
1350 }
1351
1352 for (int sibling : siblings) {
1353 if (sibling >= 0 && sibling < zelda3::kNumOverworldMaps) {
1354 // Skip self unless include_self is true
1355 if (sibling == map_index && !include_self) {
1356 continue;
1357 }
1358
1359 // Mark as modified FIRST
1360 (*maps_bmp_)[sibling].set_modified(true);
1361
1362 // Load graphics from ROM
1363 overworld_->mutable_overworld_map(sibling)->LoadAreaGraphics();
1364
1365 // CRITICAL FIX: Force immediate refresh on the sibling
1366 // This will trigger the callback to OverworldEditor's
1367 // RefreshChildMapOnDemand
1368 ForceRefreshGraphics(sibling);
1369 }
1370 }
1371
1372 // After marking all siblings, trigger a refresh
1373 // This ensures all marked maps get processed
1375}
1376
1380 ImGui::Separator();
1381 ImGui::Text("Mosaic Effects (per direction):");
1382
1383 auto* current_map_ptr = overworld_->mutable_overworld_map(current_map);
1384 std::array<bool, 4> mosaic_expanded = current_map_ptr->mosaic_expanded();
1385 const char* direction_names[] = {"North", "South", "East", "West"};
1386
1387 for (int i = 0; i < 4; i++) {
1388 if (ImGui::Checkbox(direction_names[i], &mosaic_expanded[i])) {
1389 current_map_ptr->set_mosaic_expanded(i, mosaic_expanded[i]);
1392 }
1393 }
1394 } else {
1395 if (ImGui::Checkbox(
1396 "Mosaic Effect",
1397 overworld_->mutable_overworld_map(current_map)->mutable_mosaic())) {
1400 }
1401 }
1402}
1403
1405 bool& show_overlay_preview) {
1407
1408 // Determine if this is a special overworld map (0x80-0x9F)
1409 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1410
1411 if (is_special_overworld_map) {
1412 // Special overworld maps (0x80-0x9F) serve as visual effect sources
1413 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1414 ICON_MD_INFO " Special Area Map (0x%02X)", current_map);
1415 ImGui::Separator();
1416 ImGui::TextWrapped(
1417 "This is a special area map (0x80-0x9F) used as a visual effect "
1418 "source. These maps provide the graphics data for subscreen overlays "
1419 "like fog, rain, forest canopy, and sky backgrounds that appear on "
1420 "normal maps (0x00-0x7F).");
1421 ImGui::Spacing();
1422 ImGui::TextWrapped(
1423 "You can edit the tile16 data here to customize how the visual effects "
1424 "appear when referenced by other maps.");
1425 } else {
1426 // Light World (0x00-0x3F) and Dark World (0x40-0x7F) maps support subscreen
1427 // overlays
1428
1429 // Comprehensive help section
1430 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1431 ICON_MD_HELP_OUTLINE " Visual Effects Overview");
1432 ImGui::SameLine();
1433 if (ImGui::Button(ICON_MD_INFO "##HelpButton")) {
1436 .c_str());
1437 }
1438
1439 if (ImGui::BeginPopup(gui::MakePopupId(gui::EditorNames::kOverworld,
1441 .c_str())) {
1442 ImGui::Text(ICON_MD_HELP " Understanding Overlay Types");
1443 ImGui::Separator();
1444
1445 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), ICON_MD_LAYERS
1446 " 1. Subscreen Overlays (Visual Effects)");
1447 ImGui::Indent();
1448 ImGui::BulletText("Displayed as semi-transparent layers");
1449 ImGui::BulletText("Reference special area maps (0x80-0x9F)");
1450 ImGui::BulletText("Examples: fog, rain, forest canopy, sky");
1451 ImGui::BulletText("Purely visual - don't affect collision");
1452 ImGui::Unindent();
1453
1454 ImGui::Spacing();
1455 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1456 ICON_MD_EDIT_NOTE " 2. Map Overlays (Interactive)");
1457 ImGui::Indent();
1458 ImGui::BulletText("Dynamic tile16 changes on the map");
1459 ImGui::BulletText("Used for bridges appearing, holes opening");
1460 ImGui::BulletText("Stored as tile16 ID arrays");
1461 ImGui::BulletText("Affect collision and interaction");
1462 ImGui::BulletText("Triggered by game events/progression");
1463 ImGui::Unindent();
1464
1465 ImGui::Separator();
1466 ImGui::TextWrapped(
1467 "Note: Subscreen overlays are what you configure here. "
1468 "Map overlays are event-driven and edited separately.");
1469
1470 ImGui::EndPopup();
1471 }
1472 ImGui::Separator();
1473
1474 // Subscreen Overlay Section
1475 ImGui::Text(ICON_MD_LAYERS " Subscreen Overlay (Visual Effects)");
1476
1477 uint16_t current_overlay =
1478 overworld_->mutable_overworld_map(current_map)->subscreen_overlay();
1479 if (gui::InputHexWord("Visual Effect Map ID", &current_overlay,
1480 kInputFieldSize + 20)) {
1481 overworld_->mutable_overworld_map(current_map)
1482 ->set_subscreen_overlay(current_overlay);
1485 }
1486 if (ImGui::IsItemHovered()) {
1487 ImGui::SetTooltip(
1488 "References a special area map (0x80-0x9F) for visual effects.\n"
1489 "The referenced map's tile16 data is drawn as a semi-transparent\n"
1490 "layer on top of or behind this area for atmospheric effects.");
1491 }
1492
1493 // Show subscreen overlay description with color coding
1494 std::string overlay_desc = GetOverlayDescription(current_overlay);
1495 if (current_overlay == 0x00FF) {
1496 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), ICON_MD_CHECK " %s",
1497 overlay_desc.c_str());
1498 } else if (current_overlay >= 0x80 && current_overlay < 0xA0) {
1499 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1500 ICON_MD_VISIBILITY " %s", overlay_desc.c_str());
1501 } else {
1502 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1503 ICON_MD_HELP_OUTLINE " %s", overlay_desc.c_str());
1504 }
1505
1506 // Preview checkbox with better labeling
1507 ImGui::Spacing();
1508 if (ImGui::Checkbox(ICON_MD_PREVIEW " Preview Visual Effect on Map",
1509 &show_overlay_preview)) {
1510 // Toggle subscreen overlay preview
1511 }
1512 if (ImGui::IsItemHovered()) {
1513 ImGui::SetTooltip(
1514 "Shows a semi-transparent preview of the visual effect overlay\n"
1515 "drawn on top of the current map in the editor canvas.\n\n"
1516 "This preview shows how the subscreen overlay will appear in-game.");
1517 }
1518
1519 ImGui::Separator();
1520
1521 // Interactive/Dynamic Map Overlay Section (for vanilla ROMs)
1522 if (rom_version == zelda3::OverworldVersion::kVanilla) {
1523 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1524 ICON_MD_EDIT_NOTE " Map Overlay (Interactive)");
1525 ImGui::SameLine();
1526 if (ImGui::Button(ICON_MD_INFO "##MapOverlayHelp")) {
1527 ImGui::OpenPopup(
1530 .c_str());
1531 }
1532 if (ImGui::BeginPopup(
1535 .c_str())) {
1536 ImGui::Text(ICON_MD_HELP " Map Overlays (Interactive Tile Changes)");
1537 ImGui::Separator();
1538 ImGui::TextWrapped(
1539 "Map overlays are different from visual effect overlays. "
1540 "They contain tile16 data that dynamically replaces tiles on "
1541 "the map based on game events or progression.");
1542 ImGui::Spacing();
1543 ImGui::Text("Common uses:");
1544 ImGui::BulletText("Bridges appearing over water");
1545 ImGui::BulletText("Holes revealing secret passages");
1546 ImGui::BulletText("Rocks/bushes being moved");
1547 ImGui::BulletText("Environmental changes from story events");
1548 ImGui::Spacing();
1549 ImGui::TextWrapped(
1550 "These are triggered by game code and stored as separate "
1551 "tile data arrays in the ROM. ZSCustomOverworld v3+ provides "
1552 "extended control over these features.");
1553 ImGui::EndPopup();
1554 }
1555
1556 auto* current_map_ptr = overworld_->overworld_map(current_map);
1557 ImGui::Spacing();
1558 if (current_map_ptr->has_overlay()) {
1559 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1560 ICON_MD_CHECK " Overlay ID: 0x%04X",
1561 current_map_ptr->overlay_id());
1562 ImGui::Text(ICON_MD_STORAGE " Data Size: %d bytes",
1563 static_cast<int>(current_map_ptr->overlay_data().size()));
1564 ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.4f, 1.0f),
1565 ICON_MD_INFO " Read-only in vanilla ROM");
1566 } else {
1567 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1568 ICON_MD_BLOCK " No map overlay data for this area");
1569 }
1570 }
1571
1572 // Show version and capability info
1573 ImGui::Separator();
1574 if (rom_version == zelda3::OverworldVersion::kVanilla) {
1575 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
1576 ICON_MD_INFO " Vanilla ROM");
1577 ImGui::BulletText("Visual effects use maps 0x80-0x9F");
1578 ImGui::BulletText("Map overlays are read-only");
1579 } else {
1580 const char* version_name =
1582 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), ICON_MD_UPGRADE " %s",
1583 version_name);
1584 ImGui::BulletText("Enhanced visual effect control");
1586 ImGui::BulletText("Extended overlay system");
1587 ImGui::BulletText("Custom area sizes support");
1588 }
1589 }
1590 }
1591}
1592
1593std::string MapPropertiesSystem::GetOverlayDescription(uint16_t overlay_id) {
1594 if (overlay_id == 0x0093) {
1595 return "Triforce Room Curtain";
1596 } else if (overlay_id == 0x0094) {
1597 return "Under the Bridge";
1598 } else if (overlay_id == 0x0095) {
1599 return "Sky Background (LW Death Mountain)";
1600 } else if (overlay_id == 0x0096) {
1601 return "Pyramid Background";
1602 } else if (overlay_id == 0x0097) {
1603 return "First Fog Overlay (Master Sword Area)";
1604 } else if (overlay_id == 0x009C) {
1605 return "Lava Background (DW Death Mountain)";
1606 } else if (overlay_id == 0x009D) {
1607 return "Second Fog Overlay (Lost Woods/Skull Woods)";
1608 } else if (overlay_id == 0x009E) {
1609 return "Tree Canopy (Forest)";
1610 } else if (overlay_id == 0x009F) {
1611 return "Rain Effect (Misery Mire)";
1612 } else if (overlay_id == 0x00FF) {
1613 return "No Overlay";
1614 } else {
1615 return "Custom overlay";
1616 }
1617}
1618
1620 int current_world,
1621 bool show_overlay_preview) {
1622 gfx::ScopedTimer timer("map_properties_draw_overlay_preview");
1623
1624 if (!show_overlay_preview || !maps_bmp_ || !canvas_)
1625 return;
1626
1627 // Get subscreen overlay information based on ROM version and map type
1628 uint16_t overlay_id = 0x00FF;
1629 bool has_subscreen_overlay = false;
1630
1631 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1632
1633 if (is_special_overworld_map) {
1634 // Special overworld maps (0x80-0x9F) do not support subscreen overlays
1635 return;
1636 }
1637
1638 // Light World (0x00-0x3F) and Dark World (0x40-0x7F) maps support subscreen
1639 // overlays for all versions
1640 overlay_id = overworld_->overworld_map(current_map)->subscreen_overlay();
1641 has_subscreen_overlay = (overlay_id != 0x00FF);
1642
1643 if (!has_subscreen_overlay)
1644 return;
1645
1646 // Map subscreen overlay ID to special area map for bitmap
1647 int overlay_map_index = -1;
1648 if (overlay_id >= 0x80 && overlay_id < 0xA0) {
1649 overlay_map_index = overlay_id;
1650 }
1651
1652 if (overlay_map_index < 0 || overlay_map_index >= zelda3::kNumOverworldMaps)
1653 return;
1654
1655 // Get the subscreen overlay map's bitmap
1656 const auto& overlay_bitmap = (*maps_bmp_)[overlay_map_index];
1657 if (!overlay_bitmap.is_active() || !overlay_bitmap.texture())
1658 return;
1659
1660 // Calculate position for subscreen overlay preview on the current map
1661 int current_map_x = current_map % 8;
1662 int current_map_y = current_map / 8;
1663 if (current_world == 1) {
1664 current_map_x = (current_map - 0x40) % 8;
1665 current_map_y = (current_map - 0x40) / 8;
1666 } else if (current_world == 2) {
1667 current_map_x = (current_map - 0x80) % 8;
1668 current_map_y = (current_map - 0x80) / 8;
1669 }
1670
1671 int scale = static_cast<int>(canvas_->global_scale());
1672 int map_x = current_map_x * kOverworldMapSize * scale;
1673 int map_y = current_map_y * kOverworldMapSize * scale;
1674
1675 // Determine if this is a background or foreground subscreen overlay
1676 bool is_background_overlay =
1677 (overlay_id == 0x0095 || overlay_id == 0x0096 || overlay_id == 0x009C);
1678
1679 // Set alpha for semi-transparent preview
1680 ImU32 overlay_color =
1681 is_background_overlay ? IM_COL32(255, 255, 255, 128)
1682 : // Background subscreen overlays - lighter
1683 IM_COL32(255, 255, 255,
1684 180); // Foreground subscreen overlays - more opaque
1685
1686 // Draw the subscreen overlay bitmap with semi-transparency
1687 canvas_->draw_list()->AddImage(
1688 (ImTextureID)(intptr_t)overlay_bitmap.texture(), ImVec2(map_x, map_y),
1689 ImVec2(map_x + kOverworldMapSize * scale,
1690 map_y + kOverworldMapSize * scale),
1691 ImVec2(0, 0), ImVec2(1, 1), overlay_color);
1692}
1693
1695 if (ImGui::BeginPopup(gui::MakePopupId(gui::EditorNames::kOverworld,
1697 .c_str())) {
1698 ImGui::PushID("ViewPopup"); // Fix ImGui duplicate ID warnings
1699
1700 // Use theme-aware spacing instead of hardcoded constants
1702 float padding = gui::LayoutHelpers::GetButtonPadding();
1703 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
1704 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
1705
1706 ImGui::Text("View Controls");
1707 ImGui::Separator();
1708
1709 // Horizontal layout for view controls
1710 if (ImGui::Button(ICON_MD_ZOOM_OUT, ImVec2(kIconButtonWidth, 0))) {
1711 float new_scale = std::max(kOverworldMinZoom,
1713 canvas_->set_global_scale(new_scale);
1714 }
1715 HOVER_HINT("Zoom out on the canvas");
1716 ImGui::SameLine();
1717 if (ImGui::Button(ICON_MD_ZOOM_IN, ImVec2(kIconButtonWidth, 0))) {
1718 float new_scale = std::min(kOverworldMaxZoom,
1720 canvas_->set_global_scale(new_scale);
1721 }
1722 HOVER_HINT("Zoom in on the canvas");
1723 ImGui::SameLine();
1724 if (ImGui::Button(ICON_MD_OPEN_IN_FULL, ImVec2(kIconButtonWidth, 0))) {
1726 }
1727 HOVER_HINT("Reset zoom to 100%");
1728
1729 ImGui::PopStyleVar(2); // Pop the 2 style variables we pushed
1730 ImGui::PopID(); // Pop ViewPopup ID scope
1731 ImGui::EndPopup();
1732 }
1733}
1734
1736 if (ImGui::BeginPopup(gui::MakePopupId(gui::EditorNames::kOverworld,
1738 .c_str())) {
1739 ImGui::PushID("QuickPopup"); // Fix ImGui duplicate ID warnings
1740
1741 // Use theme-aware spacing instead of hardcoded constants
1743 float padding = gui::LayoutHelpers::GetButtonPadding();
1744 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
1745 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
1746
1747 ImGui::Text("Quick Access");
1748 ImGui::Separator();
1749
1750 // Horizontal layout for quick access buttons
1751 if (ImGui::Button(ICON_MD_GRID_VIEW, ImVec2(kIconButtonWidth, 0))) {
1752 // This would need to be connected to the Tile16 editor toggle
1753 // For now, just show the option
1754 }
1755 HOVER_HINT("Open Tile16 Editor (Ctrl+T)");
1756 ImGui::SameLine();
1757
1758 if (ImGui::Button(ICON_MD_CONTENT_COPY, ImVec2(kIconButtonWidth, 0))) {
1759 // This would need to be connected to the copy map function
1760 // For now, just show the option
1761 }
1762 HOVER_HINT("Copy current map to clipboard");
1763 ImGui::SameLine();
1764
1765 if (ImGui::Button(ICON_MD_LOCK, ImVec2(kIconButtonWidth, 0))) {
1766 // This would need to be connected to the map lock toggle
1767 // For now, just show the option
1768 }
1769 HOVER_HINT("Lock/unlock current map (Ctrl+L)");
1770
1771 ImGui::PopStyleVar(2); // Pop the 2 style variables we pushed
1772 ImGui::PopID(); // Pop QuickPopup ID scope
1773 ImGui::EndPopup();
1774 }
1775}
1776
1777} // namespace editor
1778} // namespace yaze
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp_
std::function< void()> edit_tile16_callback_
void SetupCanvasContextMenu(gui::Canvas &canvas, int current_map, bool current_map_lock, bool &show_map_properties_panel, bool &show_custom_bg_color_editor, bool &show_overlay_editor, int current_mode=0)
void DrawOverlayEditor(int current_map, bool &show_overlay_editor)
void DrawPropertiesPopup(int current_map, bool &show_map_properties_panel, bool &show_overlay_preview, int &game_state)
RefreshPaletteCallback refresh_tile16_blockset_
void DrawOverlayPreviewOnMap(int current_map, int current_world, bool show_overlay_preview)
void DrawMosaicControls(int current_map)
void DrawMapPropertiesPanel(int current_map, bool &show_map_properties_panel)
std::function< void(const std::string &) entity_insert_callback_)
void DrawSpritePropertiesTab(int current_map)
RefreshPaletteCallback refresh_map_palette_
void DrawBasicPropertiesTab(int current_map)
void DrawCustomFeaturesTab(int current_map)
void DrawPalettesPopup(int current_map, int game_state, bool &show_custom_bg_color_editor)
void DrawCustomBackgroundColorEditor(int current_map, bool &show_custom_bg_color_editor)
void DrawCanvasToolbar(int &current_world, int &current_map, bool &current_map_lock, bool &show_map_properties_panel, bool &show_custom_bg_color_editor, bool &show_overlay_editor, bool &show_overlay_preview, int &game_state, EditingMode &current_mode, EntityEditMode &entity_edit_mode)
void RefreshSiblingMapGraphics(int map_index, bool include_self=false)
void DrawTileGraphicsTab(int current_map)
ForceRefreshGraphicsCallback force_refresh_graphics_
std::string GetOverlayDescription(uint16_t overlay_id)
void DrawOverlayControls(int current_map, bool &show_overlay_preview)
void DrawGraphicsPopup(int current_map, int game_state)
RAII timer for automatic timing management.
SNES Color container.
Definition snes_color.h:110
constexpr uint16_t snes() const
Get SNES 15-bit color.
Definition snes_color.h:193
Modern, robust canvas for drawing and manipulating graphics.
Definition canvas.h:150
void set_scrolling(ImVec2 scroll)
Definition canvas.h:446
auto global_scale() const
Definition canvas.h:494
void SetUsageMode(CanvasUsage usage)
Definition canvas.cc:237
auto draw_list() const
Definition canvas.h:442
void ClearContextMenuItems()
Definition canvas.cc:776
void AddContextMenuItem(const gui::CanvasMenuItem &item)
Definition canvas.cc:753
void set_global_scale(float scale)
Definition canvas.h:453
static float GetButtonPadding()
static float GetStandardSpacing()
static bool SupportsCustomBGColors(OverworldVersion version)
Check if ROM supports custom background colors per area (v2+)
static OverworldVersion GetVersion(const Rom &rom)
Detect ROM version from ASM marker byte.
static bool SupportsAreaEnum(OverworldVersion version)
Check if ROM supports area enum system (v3+ only)
static bool SupportsAnimatedGFX(OverworldVersion version)
Check if ROM supports animated GFX selection (v3+)
static bool SupportsExpandedSpace(OverworldVersion version)
Check if ROM uses expanded ROM space for overworld data.
static const char * GetVersionName(OverworldVersion version)
Get human-readable version name for display/logging.
auto is_loaded() const
Definition overworld.h:528
auto overworld_map(int i) const
Definition overworld.h:473
auto mutable_overworld_map(int i)
Definition overworld.h:479
absl::Status ConfigureMultiAreaMap(int parent_index, AreaSizeEnum size)
Configure a multi-area map structure (Large/Wide/Tall)
Definition overworld.cc:309
struct snes_color snes_color
SNES color in 15-bit RGB format (BGR555)
#define ICON_MD_BLOCK
Definition icons.h:269
#define ICON_MD_GRID_VIEW
Definition icons.h:897
#define ICON_MD_COLORIZE
Definition icons.h:441
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_STORAGE
Definition icons.h:1865
#define ICON_MD_PETS
Definition icons.h:1431
#define ICON_MD_UPGRADE
Definition icons.h:2047
#define ICON_MD_LOCK_OPEN
Definition icons.h:1142
#define ICON_MD_LOCK
Definition icons.h:1140
#define ICON_MD_LIGHTBULB
Definition icons.h:1083
#define ICON_MD_PHOTO_SIZE_SELECT_LARGE
Definition icons.h:1459
#define ICON_MD_OFFLINE_BOLT
Definition icons.h:1344
#define ICON_MD_PLAY_ARROW
Definition icons.h:1479
#define ICON_MD_CHECK
Definition icons.h:397
#define ICON_MD_DRAW
Definition icons.h:625
#define ICON_MD_TUNE
Definition icons.h:2022
#define ICON_MD_ZOOM_OUT
Definition icons.h:2196
#define ICON_MD_OPEN_IN_FULL
Definition icons.h:1353
#define ICON_MD_MESSAGE
Definition icons.h:1201
#define ICON_MD_VISIBILITY
Definition icons.h:2101
#define ICON_MD_GRASS
Definition icons.h:891
#define ICON_MD_FORMAT_COLOR_FILL
Definition icons.h:830
#define ICON_MD_DOOR_BACK
Definition icons.h:612
#define ICON_MD_CASTLE
Definition icons.h:380
#define ICON_MD_AUTO_FIX_HIGH
Definition icons.h:218
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1264
#define ICON_MD_RESTORE
Definition icons.h:1605
#define ICON_MD_ASPECT_RATIO
Definition icons.h:192
#define ICON_MD_LAYERS
Definition icons.h:1068
#define ICON_MD_ANIMATION
Definition icons.h:157
#define ICON_MD_DOOR_FRONT
Definition icons.h:613
#define ICON_MD_BLUR_ON
Definition icons.h:281
#define ICON_MD_IMAGE
Definition icons.h:982
#define ICON_MD_PREVIEW
Definition icons.h:1512
#define ICON_MD_FAVORITE
Definition icons.h:727
#define ICON_MD_HELP_OUTLINE
Definition icons.h:935
#define ICON_MD_ADD_LOCATION
Definition icons.h:100
#define ICON_MD_ZOOM_IN
Definition icons.h:2194
#define ICON_MD_MOUSE
Definition icons.h:1251
#define ICON_MD_EDIT_NOTE
Definition icons.h:650
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_OPEN_IN_NEW
Definition icons.h:1354
#define ICON_MD_PEST_CONTROL_RODENT
Definition icons.h:1430
#define ICON_MD_CONTENT_COPY
Definition icons.h:465
#define ICON_MD_COLOR_LENS
Definition icons.h:440
#define ICON_MD_PHOTO
Definition icons.h:1451
#define ICON_MD_CYCLONE
Definition icons.h:514
#define ICON_MD_GAMEPAD
Definition icons.h:866
#define ICON_MD_HELP
Definition icons.h:933
#define HOVER_HINT(string)
Definition macro.h:24
constexpr const char * kAreaSizeNames[]
constexpr unsigned int kOverworldMapSize
constexpr float kOverworldMaxZoom
constexpr float kTableColumnWorld
constexpr float kOverworldMinZoom
constexpr const char * kWorldNames[]
constexpr float kHexByteInputWidth
constexpr float kComboWorldWidth
constexpr float kTableColumnMap
constexpr float kTableColumnAreaSize
constexpr float kOverworldZoomStep
constexpr float kComboGameStateWidth
constexpr float kInputFieldSize
Definition entity.cc:23
constexpr const char * kGameStateNames[]
Definition ui_constants.h:8
constexpr float kIconButtonWidth
constexpr float kHexWordInputWidth
constexpr float kComboAreaSizeWidth
constexpr float kTableColumnLock
constexpr const char * kOverworld
Definition popup_id.h:53
constexpr const char * kPalettesPopup
Definition popup_id.h:75
constexpr const char * kGraphicsPopup
Definition popup_id.h:74
constexpr const char * kOverlayTypesHelp
Definition popup_id.h:79
constexpr const char * kInteractiveOverlayHelp
Definition popup_id.h:80
constexpr const char * kViewPopup
Definition popup_id.h:77
constexpr const char * kQuickPopup
Definition popup_id.h:78
constexpr const char * kConfigPopup
Definition popup_id.h:76
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
Definition input.cc:344
bool ToggleButton(const char *label, bool active, const ImVec2 &size)
ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor &color)
Convert SnesColor to standard ImVec4 for display.
Definition color.cc:20
bool InputHexWordCustom(const char *label, uint16_t *data, float input_width)
Definition input.cc:726
std::string MakePopupId(size_t session_id, const std::string &editor_name, const std::string &popup_name)
Generate session-aware popup IDs to prevent conflicts in multi-editor layouts.
Definition popup_id.h:23
gfx::SnesColor ConvertImVec4ToSnesColor(const ImVec4 &color)
Convert standard ImVec4 to SnesColor.
Definition color.cc:33
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
Definition input.cc:370
constexpr int OverworldCustomAreaSpecificBGEnabled
constexpr int kNumOverworldMaps
Definition common.h:85
constexpr int kOverworldMusicBeginning
Definition overworld.h:120
AreaSizeEnum
Area size enumeration for v3+ ROMs.
constexpr int OverworldCustomASMHasBeenApplied
Definition common.h:89
constexpr int kOverworldMusicAgahnim
Definition overworld.h:123
@ kVanilla
0xFF in ROM, no ZScream ASM applied
constexpr int kOverworldMusicMasterSword
Definition overworld.h:122
constexpr int kOverworldMusicZelda
Definition overworld.h:121
constexpr int OverworldCustomSubscreenOverlayEnabled
constexpr int OverworldCustomAreaSpecificBGPalette
constexpr int OverworldCustomSubscreenOverlayArray
SNES color in 15-bit RGB format (BGR555)
Definition yaze.h:218
Declarative menu item definition.
Definition canvas_menu.h:64
std::vector< CanvasMenuItem > subitems
Definition canvas_menu.h:91
std::function< void()> callback
Definition canvas_menu.h:75