diff --git a/src/app/editor/overworld/entity.cc b/src/app/editor/overworld/entity.cc index 57205e14..29852199 100644 --- a/src/app/editor/overworld/entity.cc +++ b/src/app/editor/overworld/entity.cc @@ -126,50 +126,70 @@ bool DrawEntranceInserterPopup() { return set_done; } -// TODO: Implement deleting OverworldEntrance objects, currently only hides them bool DrawOverworldEntrancePopup(zelda3::OverworldEntrance &entrance) { static bool set_done = false; if (set_done) { set_done = false; + return true; } - if (ImGui::BeginPopupModal("Entrance editor", NULL, + + if (ImGui::BeginPopupModal("Entrance Editor", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("Entrance ID: %d", entrance.entrance_id_); + ImGui::Separator(); + gui::InputHexWord("Map ID", &entrance.map_id_); gui::InputHexByte("Entrance ID", &entrance.entrance_id_, kInputFieldSize + 20); - gui::InputHex("X", &entrance.x_); - gui::InputHex("Y", &entrance.y_); - - if (Button(ICON_MD_DONE)) { - ImGui::CloseCurrentPopup(); - } - SameLine(); - if (Button(ICON_MD_CANCEL)) { + gui::InputHex("X Position", &entrance.x_); + gui::InputHex("Y Position", &entrance.y_); + + ImGui::Checkbox("Is Hole", &entrance.is_hole_); + + ImGui::Separator(); + + if (Button("Save")) { set_done = true; ImGui::CloseCurrentPopup(); } - SameLine(); - if (Button(ICON_MD_DELETE)) { + ImGui::SameLine(); + if (Button("Delete")) { entrance.deleted = true; + set_done = true; ImGui::CloseCurrentPopup(); } + ImGui::SameLine(); + if (Button("Cancel")) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); } return set_done; } -// TODO: Implement deleting OverworldExit objects void DrawExitInserterPopup() { if (ImGui::BeginPopup("Exit Inserter")) { static int exit_id = 0; + static int room_id = 0; + static int x_pos = 0; + static int y_pos = 0; + + ImGui::Text("Insert New Exit"); + ImGui::Separator(); + gui::InputHex("Exit ID", &exit_id); + gui::InputHex("Room ID", &room_id); + gui::InputHex("X Position", &x_pos); + gui::InputHex("Y Position", &y_pos); - if (Button(ICON_MD_DONE)) { + if (Button("Create Exit")) { + // This would need to be connected to the overworld editor to actually create the exit ImGui::CloseCurrentPopup(); } SameLine(); - if (Button(ICON_MD_CANCEL)) { + if (Button("Cancel")) { ImGui::CloseCurrentPopup(); } @@ -424,30 +444,35 @@ void DrawSpriteTable(std::function onSpriteSelect) { } } -// TODO: Implement deleting OverworldSprite objects void DrawSpriteInserterPopup() { if (ImGui::BeginPopup("Sprite Inserter")) { static int new_sprite_id = 0; - Text("Add Sprite"); - BeginChild("ScrollRegion", ImVec2(250, 250), true, + static int x_pos = 0; + static int y_pos = 0; + + ImGui::Text("Add New Sprite"); + ImGui::Separator(); + + BeginChild("ScrollRegion", ImVec2(250, 200), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); DrawSpriteTable([](int selected_id) { new_sprite_id = selected_id; }); EndChild(); + + ImGui::Separator(); + ImGui::Text("Position:"); + gui::InputHex("X Position", &x_pos); + gui::InputHex("Y Position", &y_pos); - if (Button(ICON_MD_DONE)) { - // Add the new item to the overworld + if (Button("Add Sprite")) { + // This would need to be connected to the overworld editor to actually create the sprite new_sprite_id = 0; + x_pos = 0; + y_pos = 0; ImGui::CloseCurrentPopup(); } SameLine(); - if (Button(ICON_MD_DELETE)) { - new_sprite_id = -1; - ImGui::CloseCurrentPopup(); - } - SameLine(); - - if (Button(ICON_MD_CANCEL)) { + if (Button("Cancel")) { ImGui::CloseCurrentPopup(); } diff --git a/src/app/editor/overworld/map_properties.cc b/src/app/editor/overworld/map_properties.cc index a9e81436..e24ec424 100644 --- a/src/app/editor/overworld/map_properties.cc +++ b/src/app/editor/overworld/map_properties.cc @@ -5,6 +5,8 @@ #include "app/gui/icons.h" #include "app/gui/input.h" #include "app/zelda3/overworld/overworld_map.h" +#include "app/editor/overworld/overworld_editor.h" +#include "app/editor/overworld/ui_constants.h" #include "imgui/imgui.h" namespace yaze { @@ -16,28 +18,28 @@ using ImGui::Separator; using ImGui::TableNextColumn; using ImGui::Text; -// Static constants -constexpr const char* kWorldList[] = {"Light World", "Dark World", "Special World"}; -constexpr const char* kGamePartComboString[] = {"Light World", "Dark World", "Special World"}; +// Using centralized UI constants void MapPropertiesSystem::DrawSimplifiedMapSettings(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) { - // Enhanced settings table with popup buttons for quick access - if (BeginTable("SimplifiedMapSettings", 8, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit, ImVec2(0, 0), -1)) { + bool& show_overlay_preview, int& game_state, int& current_mode) { + // Enhanced settings table with popup buttons for quick access and integrated toolset + if (BeginTable("SimplifiedMapSettings", 10, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit, ImVec2(0, 0), -1)) { ImGui::TableSetupColumn("World", ImGuiTableColumnFlags_WidthFixed, 100); ImGui::TableSetupColumn("Map", ImGuiTableColumnFlags_WidthFixed, 60); ImGui::TableSetupColumn("Area Size", ImGuiTableColumnFlags_WidthFixed, 100); ImGui::TableSetupColumn("Lock", ImGuiTableColumnFlags_WidthFixed, 60); ImGui::TableSetupColumn("Graphics", ImGuiTableColumnFlags_WidthFixed, 90); ImGui::TableSetupColumn("Palettes", ImGuiTableColumnFlags_WidthFixed, 90); - ImGui::TableSetupColumn("Overlays", ImGuiTableColumnFlags_WidthFixed, 90); ImGui::TableSetupColumn("Properties", ImGuiTableColumnFlags_WidthFixed, 100); + ImGui::TableSetupColumn("Tools", ImGuiTableColumnFlags_WidthFixed, 120); + ImGui::TableSetupColumn("View", ImGuiTableColumnFlags_WidthFixed, 120); + ImGui::TableSetupColumn("Quick", ImGuiTableColumnFlags_WidthFixed, 100); TableNextColumn(); ImGui::SetNextItemWidth(90.f); - if (ImGui::Combo("##world", ¤t_world, kWorldList, 3)) { + if (ImGui::Combo("##world", ¤t_world, kWorldNames, 3)) { // World changed, update current map if needed if (current_map >= 0x40 && current_world == 0) { current_map -= 0x40; @@ -56,10 +58,9 @@ void MapPropertiesSystem::DrawSimplifiedMapSettings(int& current_world, int& cur TableNextColumn(); static uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied]; if (asm_version != 0xFF) { - static const char *area_size_names[] = {"Small (1x1)", "Large (2x2)", "Wide (2x1)", "Tall (1x2)"}; int current_area_size = static_cast(overworld_->overworld_map(current_map)->area_size()); ImGui::SetNextItemWidth(90.f); - if (ImGui::Combo("##AreaSize", ¤t_area_size, area_size_names, 4)) { + if (ImGui::Combo("##AreaSize", ¤t_area_size, kAreaSizeNames, 4)) { overworld_->mutable_overworld_map(current_map)->SetAreaSize(static_cast(current_area_size)); RefreshOverworldMap(); } @@ -74,28 +75,50 @@ void MapPropertiesSystem::DrawSimplifiedMapSettings(int& current_world, int& cur HOVER_HINT(current_map_lock ? "Unlock Map" : "Lock Map"); TableNextColumn(); - if (ImGui::Button("Graphics", ImVec2(80, 0))) { + if (ImGui::Button("Graphics", ImVec2(kSmallButtonWidth, 0))) { ImGui::OpenPopup("GraphicsPopup"); } HOVER_HINT("Graphics Settings"); - DrawGraphicsPopup(current_map); + DrawGraphicsPopup(current_map, game_state); TableNextColumn(); - if (ImGui::Button("Palettes", ImVec2(80, 0))) { + if (ImGui::Button("Palettes", ImVec2(kSmallButtonWidth, 0))) { ImGui::OpenPopup("PalettesPopup"); } HOVER_HINT("Palette Settings"); - DrawPalettesPopup(current_map, show_custom_bg_color_editor); - - // Overlays are now integrated into Properties popup + DrawPalettesPopup(current_map, game_state, show_custom_bg_color_editor); TableNextColumn(); - if (ImGui::Button("Properties", ImVec2(90, 0))) { + if (ImGui::Button("Properties", ImVec2(kMediumButtonWidth, 0))) { ImGui::OpenPopup("PropertiesPopup"); } - HOVER_HINT("Map Properties"); + HOVER_HINT("Map Properties & Overlays"); DrawPropertiesPopup(current_map, show_map_properties_panel, show_overlay_preview, game_state); + TableNextColumn(); + // Editing Tools + if (ImGui::Button("Tools", ImVec2(kSmallButtonWidth, 0))) { + ImGui::OpenPopup("ToolsPopup"); + } + HOVER_HINT("Editing Tools"); + DrawToolsPopup(current_mode); + + TableNextColumn(); + // View Controls + if (ImGui::Button("View", ImVec2(kSmallButtonWidth, 0))) { + ImGui::OpenPopup("ViewPopup"); + } + HOVER_HINT("View Controls"); + DrawViewPopup(); + + TableNextColumn(); + // Quick Access Tools + if (ImGui::Button("Quick", ImVec2(kSmallButtonWidth, 0))) { + ImGui::OpenPopup("QuickPopup"); + } + HOVER_HINT("Quick Access Tools"); + DrawQuickAccessPopup(); + ImGui::EndTable(); } } @@ -291,8 +314,11 @@ void MapPropertiesSystem::SetupCanvasContextMenu(gui::Canvas& canvas, int curren } // Private method implementations -void MapPropertiesSystem::DrawGraphicsPopup(int current_map) { +void MapPropertiesSystem::DrawGraphicsPopup(int current_map, int game_state) { if (ImGui::BeginPopup("GraphicsPopup")) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(kCompactItemSpacing, kCompactFramePadding)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(kCompactItemSpacing, kCompactFramePadding)); + ImGui::Text("Graphics Settings"); ImGui::Separator(); @@ -303,15 +329,8 @@ void MapPropertiesSystem::DrawGraphicsPopup(int current_map) { RefreshOverworldMap(); } - if (gui::InputHexByte("Sprite GFX 1", - overworld_->mutable_overworld_map(current_map)->mutable_sprite_graphics(1), - kInputFieldSize)) { - RefreshMapProperties(); - RefreshOverworldMap(); - } - - if (gui::InputHexByte("Sprite GFX 2", - overworld_->mutable_overworld_map(current_map)->mutable_sprite_graphics(2), + if (gui::InputHexByte(absl::StrFormat("Sprite GFX (%s)", kGameStateNames[game_state]).c_str(), + overworld_->mutable_overworld_map(current_map)->mutable_sprite_graphics(game_state), kInputFieldSize)) { RefreshMapProperties(); RefreshOverworldMap(); @@ -345,8 +364,11 @@ void MapPropertiesSystem::DrawGraphicsPopup(int current_map) { } } -void MapPropertiesSystem::DrawPalettesPopup(int current_map, bool& show_custom_bg_color_editor) { +void MapPropertiesSystem::DrawPalettesPopup(int current_map, int game_state, bool& show_custom_bg_color_editor) { if (ImGui::BeginPopup("PalettesPopup")) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(kCompactItemSpacing, kCompactFramePadding)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(kCompactItemSpacing, kCompactFramePadding)); + ImGui::Text("Palette Settings"); ImGui::Separator(); @@ -369,15 +391,8 @@ void MapPropertiesSystem::DrawPalettesPopup(int current_map, bool& show_custom_b } } - if (gui::InputHexByte("Sprite Palette 1", - overworld_->mutable_overworld_map(current_map)->mutable_sprite_palette(1), - kInputFieldSize)) { - RefreshMapProperties(); - RefreshOverworldMap(); - } - - if (gui::InputHexByte("Sprite Palette 2", - overworld_->mutable_overworld_map(current_map)->mutable_sprite_palette(2), + if (gui::InputHexByte(absl::StrFormat("Sprite Palette (%s)", kGameStateNames[game_state]).c_str(), + overworld_->mutable_overworld_map(current_map)->mutable_sprite_palette(game_state), kInputFieldSize)) { RefreshMapProperties(); RefreshOverworldMap(); @@ -417,7 +432,7 @@ void MapPropertiesSystem::DrawPropertiesPopup(int current_map, bool& show_map_pr DrawOverlayControls(current_map, show_overlay_preview); ImGui::SetNextItemWidth(100.f); - if (ImGui::Combo("Game State", &game_state, kGamePartComboString, 3)) { + if (ImGui::Combo("Game State", &game_state, kGameStateNames, 3)) { RefreshMapProperties(); RefreshOverworldMap(); } @@ -501,7 +516,7 @@ void MapPropertiesSystem::DrawSpritePropertiesTab(int current_map) { TableNextColumn(); static int game_state = 0; ImGui::SetNextItemWidth(100.f); - if (ImGui::Combo("##GameState", &game_state, kGamePartComboString, 3)) { + if (ImGui::Combo("##GameState", &game_state, kGameStateNames, 3)) { RefreshMapProperties(); RefreshOverworldMap(); } @@ -680,51 +695,77 @@ void MapPropertiesSystem::DrawOverlayControls(int current_map, bool& show_overla // Determine if this is a special overworld map (0x80-0x9F) bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0); - if (asm_version == 0xFF) { - // Vanilla ROM - read-only overlay info - auto *current_map_ptr = overworld_->overworld_map(current_map); - if (current_map_ptr->has_vanilla_overlay()) { - ImGui::Text("Vanilla Overlay: 0x%04X", current_map_ptr->vanilla_overlay_id()); - - // Show overlay description - uint16_t overlay_id = current_map_ptr->vanilla_overlay_id(); - std::string overlay_desc = GetOverlayDescription(overlay_id); - ImGui::Text("Description: %s", overlay_desc.c_str()); - - // Preview checkbox for vanilla - if (ImGui::Checkbox("Preview Overlay on Map", &show_overlay_preview)) { - // Toggle overlay preview - } - } else { - ImGui::Text("No vanilla overlay for this map"); - } - } else if (is_special_overworld_map && asm_version < 3) { - // Special overworld maps (0x80-0x9F) require ZSCustomOverworld v3+ - ImGui::Text("Special overworld maps require ZSCustomOverworld v3+"); - ImGui::Text("Current version: v%d", asm_version); + if (is_special_overworld_map) { + // Special overworld maps (0x80-0x9F) do not support subscreen overlays + ImGui::Text("Special overworld maps (0x80-0x9F) do not support"); + ImGui::Text("subscreen overlays (visual effects)."); ImGui::Text("Map 0x%02X is a special overworld map", current_map); } else { - // Light World (0x00-0x3F) and Dark World (0x40-0x7F) maps always support overlays - // Special overworld maps (0x80-0x9F) support overlays with v3+ + // Light World (0x00-0x3F) and Dark World (0x40-0x7F) maps support subscreen overlays for all versions + + // Subscreen Overlay Section + ImGui::Text("Subscreen Overlay (Visual Effects)"); + ImGui::SameLine(); + if (ImGui::Button("?")) { + ImGui::OpenPopup("SubscreenOverlayHelp"); + } + if (ImGui::BeginPopup("SubscreenOverlayHelp")) { + ImGui::Text("Subscreen overlays are visual effects like fog, rain, canopy,"); + ImGui::Text("and backgrounds that are displayed using tile16 graphics."); + ImGui::Text("They reference special area maps (0x80-0x9F) for their tile data."); + ImGui::EndPopup(); + } + uint16_t current_overlay = overworld_->mutable_overworld_map(current_map)->subscreen_overlay(); - if (gui::InputHexWord("Subscreen Overlay", ¤t_overlay, kInputFieldSize + 20)) { + if (gui::InputHexWord("Subscreen Overlay ID", ¤t_overlay, kInputFieldSize + 20)) { overworld_->mutable_overworld_map(current_map)->set_subscreen_overlay(current_overlay); RefreshMapProperties(); RefreshOverworldMap(); } + HOVER_HINT("Subscreen overlay ID - visual effects like fog, rain, backgrounds"); - // Show overlay description + // Show subscreen overlay description std::string overlay_desc = GetOverlayDescription(current_overlay); ImGui::Text("Description: %s", overlay_desc.c_str()); // Preview checkbox - if (ImGui::Checkbox("Preview Overlay on Map", &show_overlay_preview)) { - // Toggle overlay preview + if (ImGui::Checkbox("Preview Subscreen Overlay on Map", &show_overlay_preview)) { + // Toggle subscreen overlay preview + } + HOVER_HINT("Show semi-transparent preview of subscreen overlay on the map"); + + ImGui::Separator(); + + // Interactive Overlay Section (for vanilla ROMs) + if (asm_version == 0xFF) { + ImGui::Text("Interactive Overlay (Holes/Changes)"); + ImGui::SameLine(); + if (ImGui::Button("?")) { + ImGui::OpenPopup("InteractiveOverlayHelp"); + } + if (ImGui::BeginPopup("InteractiveOverlayHelp")) { + ImGui::Text("Interactive overlays reveal holes or change elements on top"); + ImGui::Text("of the map. They use tile16 graphics and are present in"); + ImGui::Text("vanilla ROMs. ZSCustomOverworld expands this functionality."); + ImGui::EndPopup(); + } + + auto *current_map_ptr = overworld_->overworld_map(current_map); + if (current_map_ptr->has_overlay()) { + ImGui::Text("Interactive Overlay ID: 0x%04X", current_map_ptr->overlay_id()); + ImGui::Text("Overlay Data Size: %d bytes", static_cast(current_map_ptr->overlay_data().size())); + } else { + ImGui::Text("No interactive overlay data for this map"); + } + HOVER_HINT("Interactive overlay for revealing holes/changing elements (read-only in vanilla)"); } - // Show version info for special maps - if (is_special_overworld_map) { - ImGui::Text("Special overworld map (v%d)", asm_version); + // Show version info + if (asm_version == 0xFF) { + ImGui::Text("Vanilla ROM - subscreen overlays reference special area maps"); + ImGui::Text("(0x80-0x9F) for visual effects like fog, rain, backgrounds."); + } else { + ImGui::Text("ZSCustomOverworld v%d", asm_version); } } } @@ -758,33 +799,25 @@ std::string MapPropertiesSystem::GetOverlayDescription(uint16_t overlay_id) { void MapPropertiesSystem::DrawOverlayPreviewOnMap(int current_map, int current_world, bool show_overlay_preview) { if (!show_overlay_preview || !maps_bmp_ || !canvas_) return; - // Get overlay information based on ROM version and map type + // Get subscreen overlay information based on ROM version and map type uint16_t overlay_id = 0x00FF; - bool has_overlay = false; + bool has_subscreen_overlay = false; static uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied]; bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0); - if (asm_version == 0xFF) { - // Vanilla ROM - use vanilla overlay - auto *current_map_ptr = overworld_->overworld_map(current_map); - if (current_map_ptr->has_vanilla_overlay()) { - overlay_id = current_map_ptr->vanilla_overlay_id(); - has_overlay = true; - } - } else if (is_special_overworld_map && asm_version < 3) { - // Special overworld maps require v3+ - no overlay support + if (is_special_overworld_map) { + // Special overworld maps (0x80-0x9F) do not support subscreen overlays return; - } else { - // Light World (0x00-0x3F) and Dark World (0x40-0x7F) maps always support overlays - // Special overworld maps (0x80-0x9F) support overlays with v3+ - overlay_id = overworld_->overworld_map(current_map)->subscreen_overlay(); - has_overlay = (overlay_id != 0x00FF); } - if (!has_overlay) return; + // Light World (0x00-0x3F) and Dark World (0x40-0x7F) maps support subscreen overlays for all versions + overlay_id = overworld_->overworld_map(current_map)->subscreen_overlay(); + has_subscreen_overlay = (overlay_id != 0x00FF); - // Map overlay ID to special area map for bitmap + if (!has_subscreen_overlay) return; + + // Map subscreen overlay ID to special area map for bitmap int overlay_map_index = -1; if (overlay_id >= 0x80 && overlay_id < 0xA0) { overlay_map_index = overlay_id; @@ -792,11 +825,11 @@ void MapPropertiesSystem::DrawOverlayPreviewOnMap(int current_map, int current_w if (overlay_map_index < 0 || overlay_map_index >= zelda3::kNumOverworldMaps) return; - // Get the overlay map's bitmap + // Get the subscreen overlay map's bitmap const auto &overlay_bitmap = (*maps_bmp_)[overlay_map_index]; if (!overlay_bitmap.is_active()) return; - // Calculate position for overlay preview on the current map + // Calculate position for subscreen overlay preview on the current map int current_map_x = current_map % 8; int current_map_y = current_map / 8; if (current_world == 1) { @@ -811,15 +844,15 @@ void MapPropertiesSystem::DrawOverlayPreviewOnMap(int current_map, int current_w int map_x = current_map_x * kOverworldMapSize * scale; int map_y = current_map_y * kOverworldMapSize * scale; - // Determine if this is a background or foreground overlay + // Determine if this is a background or foreground subscreen overlay bool is_background_overlay = (overlay_id == 0x0095 || overlay_id == 0x0096 || overlay_id == 0x009C); // Set alpha for semi-transparent preview ImU32 overlay_color = is_background_overlay ? - IM_COL32(255, 255, 255, 128) : // Background overlays - lighter - IM_COL32(255, 255, 255, 180); // Foreground overlays - more opaque + IM_COL32(255, 255, 255, 128) : // Background subscreen overlays - lighter + IM_COL32(255, 255, 255, 180); // Foreground subscreen overlays - more opaque - // Draw the overlay bitmap with semi-transparency + // Draw the subscreen overlay bitmap with semi-transparency canvas_->draw_list()->AddImage( (ImTextureID)(intptr_t)overlay_bitmap.texture(), ImVec2(map_x, map_y), @@ -829,5 +862,120 @@ void MapPropertiesSystem::DrawOverlayPreviewOnMap(int current_map, int current_w overlay_color); } +void MapPropertiesSystem::DrawToolsPopup(int& current_mode) { + if (ImGui::BeginPopup("ToolsPopup")) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(kCompactItemSpacing, kCompactFramePadding)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(kCompactItemSpacing, kCompactFramePadding)); + + ImGui::Text("Editing Tools"); + ImGui::Separator(); + + // Row 1: Navigation and Drawing + if (ImGui::Button(ICON_MD_PAN_TOOL_ALT " Pan", ImVec2(kCompactButtonWidth, 0))) { + current_mode = 7; + } + HOVER_HINT("Pan tool (1)"); + ImGui::SameLine(); + if (ImGui::Button(ICON_MD_DRAW " Draw", ImVec2(kCompactButtonWidth, 0))) { + current_mode = 0; + } + HOVER_HINT("Draw tile tool (2)"); + ImGui::SameLine(); + if (ImGui::Button(ICON_MD_DOOR_FRONT " Ent", ImVec2(kCompactButtonWidth, 0))) { + current_mode = 1; + } + HOVER_HINT("Edit entrances (3)"); + + // Row 2: Entities + if (ImGui::Button(ICON_MD_DOOR_BACK " Exit", ImVec2(kCompactButtonWidth, 0))) { + current_mode = 2; + } + HOVER_HINT("Edit exits (4)"); + ImGui::SameLine(); + if (ImGui::Button(ICON_MD_GRASS " Item", ImVec2(kCompactButtonWidth, 0))) { + current_mode = 3; + } + HOVER_HINT("Edit items (5)"); + ImGui::SameLine(); + if (ImGui::Button(ICON_MD_PEST_CONTROL_RODENT " Spr", ImVec2(kCompactButtonWidth, 0))) { + current_mode = 4; + } + HOVER_HINT("Edit sprites (6)"); + + // Row 3: Advanced + if (ImGui::Button(ICON_MD_ADD_LOCATION " Trans", ImVec2(kCompactButtonWidth, 0))) { + current_mode = 5; + } + HOVER_HINT("Edit transports (7)"); + ImGui::SameLine(); + if (ImGui::Button(ICON_MD_MUSIC_NOTE " Music", ImVec2(kCompactButtonWidth, 0))) { + current_mode = 6; + } + HOVER_HINT("Edit music (8)"); + + ImGui::PopStyleVar(2); + ImGui::EndPopup(); + } +} + +void MapPropertiesSystem::DrawViewPopup() { + if (ImGui::BeginPopup("ViewPopup")) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(kCompactItemSpacing, kCompactFramePadding)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(kCompactItemSpacing, kCompactFramePadding)); + + ImGui::Text("View Controls"); + ImGui::Separator(); + + // Horizontal layout for view controls + if (ImGui::Button(ICON_MD_ZOOM_OUT, ImVec2(kIconButtonWidth, 0))) { + // This would need to be connected to the canvas zoom function + // For now, just show the option + } + HOVER_HINT("Zoom out on the canvas"); + ImGui::SameLine(); + if (ImGui::Button(ICON_MD_ZOOM_IN, ImVec2(kIconButtonWidth, 0))) { + // This would need to be connected to the canvas zoom function + // For now, just show the option + } + HOVER_HINT("Zoom in on the canvas"); + ImGui::SameLine(); + if (ImGui::Button(ICON_MD_OPEN_IN_FULL, ImVec2(kIconButtonWidth, 0))) { + // This would need to be connected to the fullscreen toggle + // For now, just show the option + } + HOVER_HINT("Toggle fullscreen canvas (F11)"); + + ImGui::PopStyleVar(2); + ImGui::EndPopup(); + } +} + +void MapPropertiesSystem::DrawQuickAccessPopup() { + if (ImGui::BeginPopup("QuickPopup")) { + ImGui::Text("Quick Access"); + ImGui::Separator(); + + if (ImGui::Button(ICON_MD_GRID_VIEW " Tile16 Editor")) { + // This would need to be connected to the Tile16 editor toggle + // For now, just show the option + } + HOVER_HINT("Open Tile16 Editor (Ctrl+T)"); + + if (ImGui::Button(ICON_MD_CONTENT_COPY " Copy Map")) { + // This would need to be connected to the copy map function + // For now, just show the option + } + HOVER_HINT("Copy current map to clipboard"); + + if (ImGui::Button(ICON_MD_LOCK " Lock Map (Ctrl+L)")) { + // This would need to be connected to the map lock toggle + // For now, just show the option + } + HOVER_HINT("Lock/unlock current map"); + + ImGui::EndPopup(); + } +} + } // namespace editor } // namespace yaze diff --git a/src/app/editor/overworld/map_properties.h b/src/app/editor/overworld/map_properties.h index 6245a87c..c9e96dfa 100644 --- a/src/app/editor/overworld/map_properties.h +++ b/src/app/editor/overworld/map_properties.h @@ -5,6 +5,13 @@ #include "app/rom.h" #include "app/gui/canvas.h" +// Forward declaration +namespace yaze { +namespace editor { +class OverworldEditor; +} +} + namespace yaze { namespace editor { @@ -19,7 +26,7 @@ class MapPropertiesSystem { void DrawSimplifiedMapSettings(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); + bool& show_overlay_preview, int& game_state, int& current_mode); void DrawMapPropertiesPanel(int current_map, bool& show_map_properties_panel); @@ -37,8 +44,8 @@ class MapPropertiesSystem { private: // Property category drawers - void DrawGraphicsPopup(int current_map); - void DrawPalettesPopup(int current_map, bool& show_custom_bg_color_editor); + void DrawGraphicsPopup(int current_map, int game_state); + void DrawPalettesPopup(int current_map, int game_state, bool& show_custom_bg_color_editor); void DrawPropertiesPopup(int current_map, bool& show_map_properties_panel, bool& show_overlay_preview, int& game_state); @@ -47,6 +54,11 @@ class MapPropertiesSystem { void DrawOverlayControls(int current_map, bool& show_overlay_preview); std::string GetOverlayDescription(uint16_t overlay_id); + // Integrated toolset popup functions + void DrawToolsPopup(int& current_mode); + void DrawViewPopup(); + void DrawQuickAccessPopup(); + // Tab content drawers void DrawBasicPropertiesTab(int current_map); void DrawSpritePropertiesTab(int current_map); @@ -63,9 +75,7 @@ class MapPropertiesSystem { std::array* maps_bmp_; gui::Canvas* canvas_; - // Static constants - static constexpr float kInputFieldSize = 30.f; - static constexpr int kOverworldMapSize = 512; + // Using centralized UI constants from ui_constants.h }; } // namespace editor diff --git a/src/app/editor/overworld/overworld_editor.cc b/src/app/editor/overworld/overworld_editor.cc index 3c85c4b7..6cd0a52d 100644 --- a/src/app/editor/overworld/overworld_editor.cc +++ b/src/app/editor/overworld/overworld_editor.cc @@ -10,7 +10,6 @@ #include "app/core/features.h" #include "app/core/platform/clipboard.h" #include "app/core/window.h" -#include "app/editor/graphics/palette_editor.h" #include "app/editor/overworld/entity.h" #include "app/editor/overworld/map_properties.h" #include "app/gfx/arena.h" @@ -74,80 +73,73 @@ void OverworldEditor::Initialize() { } }); - gui::AddTableColumn(toolset_table_, "##Undo", [&]() { - if (Button(ICON_MD_UNDO)) status_ = Undo(); - }); - gui::AddTableColumn(toolset_table_, "##Redo", [&]() { - if (Button(ICON_MD_REDO)) status_ = Redo(); - }); - gui::AddTableColumn(toolset_table_, "##Sep1", ICON_MD_MORE_VERT); - gui::AddTableColumn(toolset_table_, "##ZoomOut", [&]() { - if (Button(ICON_MD_ZOOM_OUT)) ow_map_canvas_.ZoomOut(); - }); - gui::AddTableColumn(toolset_table_, "##ZoomIn", [&]() { - if (Button(ICON_MD_ZOOM_IN)) ow_map_canvas_.ZoomIn(); - }); - gui::AddTableColumn(toolset_table_, "##Fullscreen", [&]() { - if (Button(ICON_MD_OPEN_IN_FULL)) - overworld_canvas_fullscreen_ = !overworld_canvas_fullscreen_; - HOVER_HINT("Fullscreen Canvas"); - }); - gui::AddTableColumn(toolset_table_, "##Sep2", ICON_MD_MORE_VERT); + // Core editing tools gui::AddTableColumn(toolset_table_, "##Pan", [&]() { if (Selectable(ICON_MD_PAN_TOOL_ALT, current_mode == EditingMode::PAN)) { current_mode = EditingMode::PAN; ow_map_canvas_.set_draggable(true); } - HOVER_HINT("Pan (Right click and drag)"); + HOVER_HINT("Pan (1) - Middle click and drag"); }); gui::AddTableColumn(toolset_table_, "##DrawTile", [&]() { if (Selectable(ICON_MD_DRAW, current_mode == EditingMode::DRAW_TILE)) { current_mode = EditingMode::DRAW_TILE; } - HOVER_HINT("Draw Tile"); + HOVER_HINT("Draw Tile (2)"); }); gui::AddTableColumn(toolset_table_, "##Entrances", [&]() { if (Selectable(ICON_MD_DOOR_FRONT, current_mode == EditingMode::ENTRANCES)) current_mode = EditingMode::ENTRANCES; - HOVER_HINT("Entrances"); + HOVER_HINT("Entrances (3)"); }); gui::AddTableColumn(toolset_table_, "##Exits", [&]() { if (Selectable(ICON_MD_DOOR_BACK, current_mode == EditingMode::EXITS)) current_mode = EditingMode::EXITS; - HOVER_HINT("Exits"); + HOVER_HINT("Exits (4)"); }); gui::AddTableColumn(toolset_table_, "##Items", [&]() { if (Selectable(ICON_MD_GRASS, current_mode == EditingMode::ITEMS)) current_mode = EditingMode::ITEMS; - HOVER_HINT("Items"); + HOVER_HINT("Items (5)"); }); gui::AddTableColumn(toolset_table_, "##Sprites", [&]() { if (Selectable(ICON_MD_PEST_CONTROL_RODENT, current_mode == EditingMode::SPRITES)) current_mode = EditingMode::SPRITES; - HOVER_HINT("Sprites"); + HOVER_HINT("Sprites (6)"); }); gui::AddTableColumn(toolset_table_, "##Transports", [&]() { if (Selectable(ICON_MD_ADD_LOCATION, current_mode == EditingMode::TRANSPORTS)) current_mode = EditingMode::TRANSPORTS; - HOVER_HINT("Transports"); + HOVER_HINT("Transports (7)"); }); gui::AddTableColumn(toolset_table_, "##Music", [&]() { if (Selectable(ICON_MD_MUSIC_NOTE, current_mode == EditingMode::MUSIC)) current_mode = EditingMode::MUSIC; - HOVER_HINT("Music"); + HOVER_HINT("Music (8)"); }); + + // View controls + gui::AddTableColumn(toolset_table_, "##ZoomOut", [&]() { + if (Button(ICON_MD_ZOOM_OUT)) ow_map_canvas_.ZoomOut(); + HOVER_HINT("Zoom Out"); + }); + gui::AddTableColumn(toolset_table_, "##ZoomIn", [&]() { + if (Button(ICON_MD_ZOOM_IN)) ow_map_canvas_.ZoomIn(); + HOVER_HINT("Zoom In"); + }); + gui::AddTableColumn(toolset_table_, "##Fullscreen", [&]() { + if (Button(ICON_MD_OPEN_IN_FULL)) + overworld_canvas_fullscreen_ = !overworld_canvas_fullscreen_; + HOVER_HINT("Fullscreen Canvas (F11)"); + }); + + // Quick access tools gui::AddTableColumn(toolset_table_, "##Tile16Editor", [&]() { if (Button(ICON_MD_GRID_VIEW)) show_tile16_editor_ = !show_tile16_editor_; - HOVER_HINT("Tile16 Editor"); + HOVER_HINT("Tile16 Editor (Ctrl+T)"); }); - gui::AddTableColumn(toolset_table_, "##GfxGroupEditor", [&]() { - if (Button(ICON_MD_TABLE_CHART)) - show_gfx_group_editor_ = !show_gfx_group_editor_; - HOVER_HINT("Gfx Group Editor"); - }); - gui::AddTableColumn(toolset_table_, "##sep3", ICON_MD_MORE_VERT); gui::AddTableColumn(toolset_table_, "##CopyMap", [&]() { if (Button(ICON_MD_CONTENT_COPY)) { std::vector png_data; @@ -161,31 +153,6 @@ void OverworldEditor::Initialize() { } HOVER_HINT("Copy Map to Clipboard"); }); - gui::AddTableColumn(toolset_table_, "##Palette", [&]() { - status_ = DisplayPalette(palette_, overworld_.is_loaded()); - }); - gui::AddTableColumn(toolset_table_, "##Sep4", ICON_MD_MORE_VERT); - gui::AddTableColumn(toolset_table_, "##Properties", [&]() { - Checkbox("Properties", &show_properties_editor_); - }); - gui::AddTableColumn(toolset_table_, "##MapLock", [&]() { - if (Button(current_map_lock_ ? ICON_MD_LOCK : ICON_MD_LOCK_OPEN)) { - current_map_lock_ = !current_map_lock_; - } - HOVER_HINT(current_map_lock_ ? "Unlock Map" : "Lock Map"); - }); - gui::AddTableColumn(toolset_table_, "##CustomBG", [&]() { - if (Button(ICON_MD_PALETTE)) { - show_custom_bg_color_editor_ = !show_custom_bg_color_editor_; - } - HOVER_HINT("Custom Background Colors"); - }); - gui::AddTableColumn(toolset_table_, "##Overlay", [&]() { - if (Button(ICON_MD_LAYERS)) { - show_overlay_editor_ = !show_overlay_editor_; - } - HOVER_HINT("Overlay Editor"); - }); } absl::Status OverworldEditor::Load() { @@ -263,9 +230,11 @@ void OverworldEditor::DrawToolset() { ImGui::End(); } - // TODO: Customizable shortcuts for the Overworld Editor + // Keyboard shortcuts for the Overworld Editor if (!ImGui::IsAnyItemActive()) { using enum EditingMode; + + // Tool shortcuts if (ImGui::IsKeyDown(ImGuiKey_1)) { current_mode = PAN; } else if (ImGui::IsKeyDown(ImGuiKey_2)) { @@ -283,6 +252,21 @@ void OverworldEditor::DrawToolset() { } else if (ImGui::IsKeyDown(ImGuiKey_8)) { current_mode = MUSIC; } + + // View shortcuts + if (ImGui::IsKeyDown(ImGuiKey_F11)) { + overworld_canvas_fullscreen_ = !overworld_canvas_fullscreen_; + } + + // Toggle map lock with L key + if (ImGui::IsKeyDown(ImGuiKey_L) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) { + current_map_lock_ = !current_map_lock_; + } + + // Toggle Tile16 editor with T key + if (ImGui::IsKeyDown(ImGuiKey_T) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) { + show_tile16_editor_ = !show_tile16_editor_; + } } } @@ -848,7 +832,8 @@ void OverworldEditor::DrawOverworldCanvas() { if (core::FeatureFlags::get().overworld.kLoadCustomOverworld) { map_properties_system_->DrawSimplifiedMapSettings( current_world_, current_map_, current_map_lock_, show_map_properties_panel_, - show_custom_bg_color_editor_, show_overlay_editor_, show_overlay_preview_, game_state_); + show_custom_bg_color_editor_, show_overlay_editor_, show_overlay_preview_, game_state_, + reinterpret_cast(current_mode)); } else { DrawOverworldMapSettings(); } @@ -1531,56 +1516,49 @@ void OverworldEditor::DrawOverlayEditor() { Text("Current Map: %d (0x%02X)", current_map_, current_map_); - // Show vanilla overlay information - auto *current_map = overworld_.overworld_map(current_map_); - if (current_map->has_vanilla_overlay()) { - Text("Vanilla Overlay ID: 0x%04X", current_map->vanilla_overlay_id()); - Text("Overlay Data Size: %d bytes", - static_cast(current_map->vanilla_overlay_data().size())); + // Show vanilla subscreen overlay information + Text("Vanilla ROM - Subscreen Overlays:"); + Text("Subscreen overlays in vanilla ROMs reference special area maps"); + Text("(0x80-0x9F) for visual effects like fog, rain, backgrounds."); + + Separator(); + if (Checkbox("Show Subscreen Overlay Preview", &show_overlay_preview_)) { + // Toggle subscreen overlay preview + } - Separator(); - if (Checkbox("Show Overlay Preview", &show_overlay_preview_)) { - // Toggle overlay preview - } - - if (show_overlay_preview_) { - DrawOverlayPreview(); - } - } else { - Text("No vanilla overlay data for this map"); + if (show_overlay_preview_) { + DrawOverlayPreview(); } Separator(); Text( - "Note: Vanilla overlays are read-only. Use ZSCustomOverworld v1+ for " - "editable overlays."); + "Note: Vanilla subscreen overlays are read-only. Use ZSCustomOverworld v1+ for " + "editable subscreen overlays."); return; } - if (asm_version < 1) { - Text("Overlay editor is only available in ZSCustomOverworld v1+"); - return; - } + // Subscreen overlays are available for all versions for LW and DW maps + // Check if subscreen overlays are enabled (for custom overworld ROMs) + if (asm_version != 0xFF) { + bool overlay_enabled = + (*rom_)[zelda3::OverworldCustomSubscreenOverlayEnabled] != 0x00; + if (Checkbox("Enable Subscreen Overlays", &overlay_enabled)) { + (*rom_)[zelda3::OverworldCustomSubscreenOverlayEnabled] = + overlay_enabled ? 0x01 : 0x00; + } - // Check if subscreen overlays are enabled - bool overlay_enabled = - (*rom_)[zelda3::OverworldCustomSubscreenOverlayEnabled] != 0x00; - if (Checkbox("Enable Subscreen Overlays", &overlay_enabled)) { - (*rom_)[zelda3::OverworldCustomSubscreenOverlayEnabled] = - overlay_enabled ? 0x01 : 0x00; - } - - if (!overlay_enabled) { - Text("Subscreen overlays are disabled."); - return; + if (!overlay_enabled) { + Text("Subscreen overlays are disabled."); + return; + } } Separator(); - // Display current map's overlay + // Display current map's subscreen overlay Text("Current Map: %d (0x%02X)", current_map_, current_map_); - // Get current overlay ID + // Get current subscreen overlay ID uint16_t current_overlay = (*rom_)[zelda3::OverworldCustomSubscreenOverlayArray + (current_map_ * 2)] | @@ -1588,8 +1566,8 @@ void OverworldEditor::DrawOverlayEditor() { (current_map_ * 2) + 1] << 8); - // Overlay ID input - if (gui::InputHexWord("Overlay ID", ¤t_overlay, 100)) { + // Subscreen overlay ID input + if (gui::InputHexWord("Subscreen Overlay ID", ¤t_overlay, 100)) { // Write to ROM (*rom_)[zelda3::OverworldCustomSubscreenOverlayArray + (current_map_ * 2)] = current_overlay & 0xFF; @@ -1606,8 +1584,8 @@ void OverworldEditor::DrawOverlayEditor() { Separator(); - // Show overlay information - Text("Overlay Information:"); + // Show subscreen overlay information + Text("Subscreen Overlay Information:"); Text("ID: 0x%04X", current_overlay); if (current_overlay == 0x00FF) { @@ -1638,19 +1616,16 @@ void OverworldEditor::DrawOverlayEditor() { void OverworldEditor::DrawOverlayPreview() { if (!show_overlay_preview_) return; - auto *current_map = overworld_.overworld_map(current_map_); - if (!current_map->has_vanilla_overlay()) return; - - Text("Overlay Preview:"); + Text("Subscreen Overlay Preview:"); Separator(); - // Get the overlay ID to determine what visual effect this is - uint16_t overlay_id = current_map->vanilla_overlay_id(); + // Get the subscreen overlay ID from the current map + uint16_t overlay_id = overworld_.overworld_map(current_map_)->subscreen_overlay(); - // Show overlay information - Text("Overlay ID: 0x%04X", overlay_id); + // Show subscreen overlay information + Text("Subscreen Overlay ID: 0x%04X", overlay_id); - // Show overlay description based on common overlay IDs + // Show subscreen overlay description based on common overlay IDs std::string overlay_desc = ""; if (overlay_id == 0x0093) { overlay_desc = "Triforce Room Curtain"; @@ -1671,49 +1646,49 @@ void OverworldEditor::DrawOverlayPreview() { } else if (overlay_id == 0x009F) { overlay_desc = "Rain Effect (Misery Mire)"; } else if (overlay_id == 0x00FF) { - overlay_desc = "No Overlay"; + overlay_desc = "No Subscreen Overlay"; } else { - overlay_desc = "Custom overlay effect"; + overlay_desc = "Custom subscreen overlay effect"; } Text("Description: %s", overlay_desc.c_str()); Separator(); - // Map overlay ID to special area map for preview + // Map subscreen overlay ID to special area map for preview int overlay_map_index = -1; if (overlay_id >= 0x80 && overlay_id < 0xA0) { overlay_map_index = overlay_id; } if (overlay_map_index >= 0 && overlay_map_index < zelda3::kNumOverworldMaps) { - Text("Overlay Source Map: %d (0x%02X)", overlay_map_index, overlay_map_index); + Text("Subscreen Overlay Source Map: %d (0x%02X)", overlay_map_index, overlay_map_index); - // Get the overlay map's bitmap + // Get the subscreen overlay map's bitmap const auto &overlay_bitmap = maps_bmp_[overlay_map_index]; if (overlay_bitmap.is_active()) { - // Display the overlay map bitmap + // Display the subscreen overlay map bitmap ImVec2 image_size(256, 256); // Scale down for preview ImGui::Image((ImTextureID)(intptr_t)overlay_bitmap.texture(), image_size); Separator(); - Text("This overlay would be displayed semi-transparently"); + Text("This subscreen overlay would be displayed semi-transparently"); Text("on top of the current map when active."); // Show drawing order info - if (overlay_id == 0x0095 || overlay_id == 0x0096) { - Text("Note: This overlay is drawn as a background"); + if (overlay_id == 0x0095 || overlay_id == 0x0096 || overlay_id == 0x009C) { + Text("Note: This subscreen overlay is drawn as a background"); Text("(behind the main map tiles)."); } else { - Text("Note: This overlay is drawn on top of"); + Text("Note: This subscreen overlay is drawn on top of"); Text("the main map tiles."); } } else { - Text("Overlay map bitmap not available"); + Text("Subscreen overlay map bitmap not available"); } } else { - Text("Unknown overlay ID: 0x%04X", overlay_id); - Text("Could not determine overlay source map"); + Text("Unknown subscreen overlay ID: 0x%04X", overlay_id); + Text("Could not determine subscreen overlay source map"); } } @@ -1785,15 +1760,15 @@ void OverworldEditor::DrawOverworldContextMenu() { current_map_ = hovered_map; } - if (MenuItem("Overlay Settings")) { + if (MenuItem("Subscreen Overlay Settings")) { show_overlay_editor_ = true; current_map_ = hovered_map; } } else if (asm_version == 0xFF) { - // Show vanilla overlay information - auto *hovered_map_obj = overworld_.overworld_map(hovered_map); - if (hovered_map_obj->has_vanilla_overlay()) { - if (MenuItem("View Vanilla Overlay")) { + // Show vanilla subscreen overlay information for LW and DW maps only + bool is_special_overworld_map = (hovered_map >= 0x80 && hovered_map < 0xA0); + if (!is_special_overworld_map) { + if (MenuItem("View Subscreen Overlay")) { show_overlay_editor_ = true; current_map_ = hovered_map; } diff --git a/src/app/editor/overworld/overworld_editor.h b/src/app/editor/overworld/overworld_editor.h index f48cb881..530d1435 100644 --- a/src/app/editor/overworld/overworld_editor.h +++ b/src/app/editor/overworld/overworld_editor.h @@ -278,7 +278,7 @@ class OverworldEditor : public Editor, public gfx::GfxContext { gui::CanvasGridSize::k16x16}; gui::Canvas properties_canvas_; - gui::Table toolset_table_{"##ToolsetTable0", 25, kToolsetTableFlags}; + gui::Table toolset_table_{"##ToolsetTable0", 12, kToolsetTableFlags}; gui::Table map_settings_table_{kOWMapTable.data(), 8, kOWMapFlags, ImVec2(0, 0)}; diff --git a/src/app/editor/overworld/tile16_editor.cc b/src/app/editor/overworld/tile16_editor.cc index ea907bb5..5ebd4b93 100644 --- a/src/app/editor/overworld/tile16_editor.cc +++ b/src/app/editor/overworld/tile16_editor.cc @@ -72,44 +72,34 @@ absl::Status Tile16Editor::Update() { } if (BeginMenu("Edit")) { - if (MenuItem("Copy Current Tile16")) { + if (MenuItem("Copy Current Tile16", "Ctrl+C")) { RETURN_IF_ERROR(CopyTile16ToClipboard(current_tile16_)); } - if (MenuItem("Paste to Current Tile16")) { + if (MenuItem("Paste to Current Tile16", "Ctrl+V")) { RETURN_IF_ERROR(PasteTile16FromClipboard()); } - Separator(); - if (MenuItem("Save to Scratch Space 1")) { - RETURN_IF_ERROR(SaveTile16ToScratchSpace(0)); - } - if (MenuItem("Save to Scratch Space 2")) { - RETURN_IF_ERROR(SaveTile16ToScratchSpace(1)); - } - if (MenuItem("Save to Scratch Space 3")) { - RETURN_IF_ERROR(SaveTile16ToScratchSpace(2)); - } - if (MenuItem("Save to Scratch Space 4")) { - RETURN_IF_ERROR(SaveTile16ToScratchSpace(3)); - } - Separator(); - if (MenuItem("Load from Scratch Space 1")) { - RETURN_IF_ERROR(LoadTile16FromScratchSpace(0)); - } - if (MenuItem("Load from Scratch Space 2")) { - RETURN_IF_ERROR(LoadTile16FromScratchSpace(1)); - } - if (MenuItem("Load from Scratch Space 3")) { - RETURN_IF_ERROR(LoadTile16FromScratchSpace(2)); - } - if (MenuItem("Load from Scratch Space 4")) { - RETURN_IF_ERROR(LoadTile16FromScratchSpace(3)); - } EndMenu(); } - if (BeginMenu("Help")) { - if (MenuItem("About Tile16 Editor")) { - OpenPopup("About Tile16 Editor"); + if (BeginMenu("Scratch Space")) { + for (int i = 0; i < 4; i++) { + std::string slot_name = "Slot " + std::to_string(i + 1); + if (scratch_space_used_[i]) { + if (MenuItem((slot_name + " (Load)").c_str())) { + RETURN_IF_ERROR(LoadTile16FromScratchSpace(i)); + } + if (MenuItem((slot_name + " (Save)").c_str())) { + RETURN_IF_ERROR(SaveTile16ToScratchSpace(i)); + } + if (MenuItem((slot_name + " (Clear)").c_str())) { + RETURN_IF_ERROR(ClearScratchSpace(i)); + } + } else { + if (MenuItem((slot_name + " (Save)").c_str())) { + RETURN_IF_ERROR(SaveTile16ToScratchSpace(i)); + } + } + if (i < 3) Separator(); } EndMenu(); } @@ -350,38 +340,43 @@ absl::Status Tile16Editor::UpdateTile16Edit() { // Actions column TableNextColumn(); - Text("Actions:"); + Text("Quick Actions:"); - // Clipboard actions - if (Button("Copy Current Tile16")) { - RETURN_IF_ERROR(CopyTile16ToClipboard(current_tile16_)); - } - SameLine(); - if (Button("Paste to Current Tile16")) { - RETURN_IF_ERROR(PasteTile16FromClipboard()); + // Clipboard actions in a more compact layout + if (BeginTable("##ClipboardActions", 2, ImGuiTableFlags_SizingFixedFit)) { + TableNextColumn(); + if (Button("Copy", ImVec2(60, 0))) { + RETURN_IF_ERROR(CopyTile16ToClipboard(current_tile16_)); + } + TableNextColumn(); + if (Button("Paste", ImVec2(60, 0))) { + RETURN_IF_ERROR(PasteTile16FromClipboard()); + } + EndTable(); } - // Scratch space actions - Separator(); + // Scratch space in a compact 2x2 grid Text("Scratch Space:"); - - // Create a grid of 4 buttons for scratch space - for (int i = 0; i < 4; i++) { - if (i > 0) SameLine(); - - if (scratch_space_used_[i]) { - if (Button(("Slot " + std::to_string(i)).c_str())) { - RETURN_IF_ERROR(LoadTile16FromScratchSpace(i)); - } - SameLine(); - if (Button(("Clear##" + std::to_string(i)).c_str())) { - RETURN_IF_ERROR(ClearScratchSpace(i)); - } - } else { - if (Button(("Empty##" + std::to_string(i)).c_str())) { - RETURN_IF_ERROR(SaveTile16ToScratchSpace(i)); + if (BeginTable("##ScratchSpace", 2, ImGuiTableFlags_SizingFixedFit)) { + for (int i = 0; i < 4; i++) { + TableNextColumn(); + std::string slot_name = "Slot " + std::to_string(i + 1); + + if (scratch_space_used_[i]) { + if (Button((slot_name + " (Load)").c_str(), ImVec2(80, 0))) { + RETURN_IF_ERROR(LoadTile16FromScratchSpace(i)); + } + SameLine(); + if (Button("Clear", ImVec2(40, 0))) { + RETURN_IF_ERROR(ClearScratchSpace(i)); + } + } else { + if (Button((slot_name + " (Empty)").c_str(), ImVec2(120, 0))) { + RETURN_IF_ERROR(SaveTile16ToScratchSpace(i)); + } } } + EndTable(); } EndTable(); diff --git a/src/app/editor/overworld/ui_constants.h b/src/app/editor/overworld/ui_constants.h new file mode 100644 index 00000000..bf8db719 --- /dev/null +++ b/src/app/editor/overworld/ui_constants.h @@ -0,0 +1,46 @@ +#ifndef YAZE_APP_EDITOR_OVERWORLD_UI_CONSTANTS_H +#define YAZE_APP_EDITOR_OVERWORLD_UI_CONSTANTS_H + +namespace yaze { +namespace editor { + +// Game State Labels +inline constexpr const char* kGameStateNames[] = { + "Rain & Rescue Zelda", + "Pendants", + "Crystals" +}; + +// World Labels +inline constexpr const char* kWorldNames[] = { + "Light World", + "Dark World", + "Special World" +}; + +// Area Size Names +inline constexpr const char* kAreaSizeNames[] = { + "Small (1x1)", + "Large (2x2)", + "Wide (2x1)", + "Tall (1x2)" +}; + +// UI Styling Constants +inline constexpr float kInputFieldSize = 30.f; +inline constexpr float kCompactButtonWidth = 60.f; +inline constexpr float kIconButtonWidth = 30.f; +inline constexpr float kSmallButtonWidth = 80.f; +inline constexpr float kMediumButtonWidth = 90.f; +inline constexpr float kLargeButtonWidth = 100.f; + +// Spacing and Padding +inline constexpr float kCompactItemSpacing = 4.f; +inline constexpr float kCompactFramePadding = 2.f; + +// Map Size Constants - using the one from overworld_editor.h + +} // namespace editor +} // namespace yaze + +#endif // YAZE_APP_EDITOR_OVERWORLD_UI_CONSTANTS_H diff --git a/src/app/zelda3/overworld/overworld_map.cc b/src/app/zelda3/overworld/overworld_map.cc index 01681534..46b040ea 100644 --- a/src/app/zelda3/overworld/overworld_map.cc +++ b/src/app/zelda3/overworld/overworld_map.cc @@ -58,7 +58,7 @@ absl::Status OverworldMap::BuildMap(int count, int game_state, int world, RETURN_IF_ERROR(BuildTileset()) RETURN_IF_ERROR(BuildTiles16Gfx(tiles16, count)) RETURN_IF_ERROR(LoadPalette()); - RETURN_IF_ERROR(LoadVanillaOverlay()); + RETURN_IF_ERROR(LoadOverlay()); RETURN_IF_ERROR(BuildBitmap(world_blockset)) built_ = true; return absl::OkStatus(); @@ -825,18 +825,25 @@ absl::Status OverworldMap::LoadPalette() { return absl::OkStatus(); } -absl::Status OverworldMap::LoadVanillaOverlay() { +absl::Status OverworldMap::LoadOverlay() { uint8_t asm_version = (*rom_)[OverworldCustomASMHasBeenApplied]; - // Only load vanilla overlays if this is a vanilla ROM (asm_version == 0xFF) - if (asm_version != 0xFF) { - has_vanilla_overlay_ = false; - vanilla_overlay_id_ = 0; - vanilla_overlay_data_.clear(); + // Load overlays based on ROM version + if (asm_version == 0xFF) { + // Vanilla ROM - load overlay from overlay pointers + return LoadVanillaOverlayData(); + } else { + // Custom overworld ROM - use overlay from custom data + overlay_id_ = subscreen_overlay_; + has_overlay_ = (overlay_id_ != 0x00FF); + overlay_data_.clear(); return absl::OkStatus(); } +} + +absl::Status OverworldMap::LoadVanillaOverlayData() { - // Load vanilla overlay for this map + // Load vanilla overlay for this map (interactive overlays for revealing holes/changing elements) int address = (kOverlayPointersBank << 16) + ((*rom_)[kOverlayPointers + (index_ * 2) + 1] << 8) + (*rom_)[kOverlayPointers + (index_ * 2)]; @@ -855,26 +862,26 @@ absl::Status OverworldMap::LoadVanillaOverlay() { // Validate address if (address >= rom_->size()) { - has_vanilla_overlay_ = false; - vanilla_overlay_id_ = 0; - vanilla_overlay_data_.clear(); + has_overlay_ = false; + overlay_id_ = 0; + overlay_data_.clear(); return absl::OkStatus(); } - // Parse overlay data - vanilla_overlay_data_.clear(); + // Parse overlay data (interactive overlays) + overlay_data_.clear(); uint8_t b = (*rom_)[address]; // Parse overlay commands until we hit END (0x60) while (b != 0x60 && address < rom_->size()) { - vanilla_overlay_data_.push_back(b); + overlay_data_.push_back(b); // Handle different overlay commands switch (b) { case 0xA9: // LDA #$ if (address + 2 < rom_->size()) { - vanilla_overlay_data_.push_back((*rom_)[address + 1]); - vanilla_overlay_data_.push_back((*rom_)[address + 2]); + overlay_data_.push_back((*rom_)[address + 1]); + overlay_data_.push_back((*rom_)[address + 2]); address += 3; } else { address++; @@ -882,8 +889,8 @@ absl::Status OverworldMap::LoadVanillaOverlay() { break; case 0xA2: // LDX #$ if (address + 2 < rom_->size()) { - vanilla_overlay_data_.push_back((*rom_)[address + 1]); - vanilla_overlay_data_.push_back((*rom_)[address + 2]); + overlay_data_.push_back((*rom_)[address + 1]); + overlay_data_.push_back((*rom_)[address + 2]); address += 3; } else { address++; @@ -891,9 +898,9 @@ absl::Status OverworldMap::LoadVanillaOverlay() { break; case 0x8D: // STA $xxxx if (address + 3 < rom_->size()) { - vanilla_overlay_data_.push_back((*rom_)[address + 1]); - vanilla_overlay_data_.push_back((*rom_)[address + 2]); - vanilla_overlay_data_.push_back((*rom_)[address + 3]); + overlay_data_.push_back((*rom_)[address + 1]); + overlay_data_.push_back((*rom_)[address + 2]); + overlay_data_.push_back((*rom_)[address + 3]); address += 4; } else { address++; @@ -901,9 +908,9 @@ absl::Status OverworldMap::LoadVanillaOverlay() { break; case 0x9D: // STA $xxxx,x if (address + 3 < rom_->size()) { - vanilla_overlay_data_.push_back((*rom_)[address + 1]); - vanilla_overlay_data_.push_back((*rom_)[address + 2]); - vanilla_overlay_data_.push_back((*rom_)[address + 3]); + overlay_data_.push_back((*rom_)[address + 1]); + overlay_data_.push_back((*rom_)[address + 2]); + overlay_data_.push_back((*rom_)[address + 3]); address += 4; } else { address++; @@ -911,10 +918,10 @@ absl::Status OverworldMap::LoadVanillaOverlay() { break; case 0x8F: // STA $xxxxxx if (address + 4 < rom_->size()) { - vanilla_overlay_data_.push_back((*rom_)[address + 1]); - vanilla_overlay_data_.push_back((*rom_)[address + 2]); - vanilla_overlay_data_.push_back((*rom_)[address + 3]); - vanilla_overlay_data_.push_back((*rom_)[address + 4]); + overlay_data_.push_back((*rom_)[address + 1]); + overlay_data_.push_back((*rom_)[address + 2]); + overlay_data_.push_back((*rom_)[address + 3]); + overlay_data_.push_back((*rom_)[address + 4]); address += 5; } else { address++; @@ -925,9 +932,9 @@ absl::Status OverworldMap::LoadVanillaOverlay() { break; case 0x4C: // JMP if (address + 3 < rom_->size()) { - vanilla_overlay_data_.push_back((*rom_)[address + 1]); - vanilla_overlay_data_.push_back((*rom_)[address + 2]); - vanilla_overlay_data_.push_back((*rom_)[address + 3]); + overlay_data_.push_back((*rom_)[address + 1]); + overlay_data_.push_back((*rom_)[address + 2]); + overlay_data_.push_back((*rom_)[address + 3]); address += 4; } else { address++; @@ -947,12 +954,12 @@ absl::Status OverworldMap::LoadVanillaOverlay() { // Add the END command if we found it if (b == 0x60) { - vanilla_overlay_data_.push_back(0x60); + overlay_data_.push_back(0x60); } // Set overlay ID based on map index (simplified) - vanilla_overlay_id_ = index_; - has_vanilla_overlay_ = !vanilla_overlay_data_.empty(); + overlay_id_ = index_; + has_overlay_ = !overlay_data_.empty(); return absl::OkStatus(); } diff --git a/src/app/zelda3/overworld/overworld_map.h b/src/app/zelda3/overworld/overworld_map.h index 58ca2054..280db89d 100644 --- a/src/app/zelda3/overworld/overworld_map.h +++ b/src/app/zelda3/overworld/overworld_map.h @@ -105,7 +105,8 @@ class OverworldMap : public gfx::GfxContext { void LoadAreaGraphics(); absl::Status LoadPalette(); - absl::Status LoadVanillaOverlay(); + absl::Status LoadOverlay(); + absl::Status LoadVanillaOverlayData(); absl::Status BuildTileset(); absl::Status BuildTiles16Gfx(std::vector& tiles16, int count); absl::Status BuildBitmap(OverworldBlockset& world_blockset); @@ -148,10 +149,10 @@ class OverworldMap : public gfx::GfxContext { auto custom_tileset(int index) const { return custom_gfx_ids_[index]; } - // Vanilla overlay accessors - auto vanilla_overlay_id() const { return vanilla_overlay_id_; } - auto has_vanilla_overlay() const { return has_vanilla_overlay_; } - const auto& vanilla_overlay_data() const { return vanilla_overlay_data_; } + // Overlay accessors (interactive overlays) + auto overlay_id() const { return overlay_id_; } + auto has_overlay() const { return has_overlay_; } + const auto& overlay_data() const { return overlay_data_; } // Mosaic expanded accessors const std::array& mosaic_expanded() const { return mosaic_expanded_; } @@ -233,9 +234,9 @@ class OverworldMap : public gfx::GfxContext { static_graphics_.fill(0); mosaic_expanded_.fill(false); area_size_ = AreaSizeEnum::SmallArea; - vanilla_overlay_id_ = 0; - has_vanilla_overlay_ = false; - vanilla_overlay_data_.clear(); + overlay_id_ = 0; + has_overlay_ = false; + overlay_data_.clear(); } private: @@ -287,10 +288,10 @@ class OverworldMap : public gfx::GfxContext { std::array mosaic_expanded_; - // Vanilla overlay support - uint16_t vanilla_overlay_id_ = 0; - bool has_vanilla_overlay_ = false; - std::vector vanilla_overlay_data_; + // Overlay support (interactive overlays that reveal holes/change elements) + uint16_t overlay_id_ = 0; + bool has_overlay_ = false; + std::vector overlay_data_; std::vector current_blockset_; std::vector current_gfx_;