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