6#define IM_PI 3.14159265358979323846f
22#include <unordered_map>
27#include "absl/status/status.h"
28#include "absl/strings/str_format.h"
29#include "imgui/imgui.h"
105 for (
size_t i = 0; i < lhs.
items.size(); ++i) {
146 const int clamped_world = std::clamp(current_world, 0, 2);
147 int normalized_map = current_map;
153 const int normalized_world = std::clamp(normalized_map / 0x40, 0, 2);
155 normalized_world != current_world || normalized_map != current_map;
156 current_world = normalized_world;
157 current_map = normalized_map;
166 "Gfx Groups: selection syncs with the Graphics editor for this ROM "
168 "(this surface uses its own preview canvases).");
179 std::make_unique<EntityMutationService>(
overworld_);
204 [
this](
int map_index,
bool respect_pin) {
212 [
this](
const std::vector<OverworldPropertyEdit>& edits,
213 const std::string& description) {
217 [
this](
const std::string&
type,
int id,
const std::string& label) {
230 toolbar_ = std::make_unique<OverworldToolbar>();
231 toolbar_->on_world_changed = [
this](
int world) {
234 toolbar_->on_refresh_graphics = [
this]() {
240 toolbar_->on_refresh_map = [
this]() {
244 toolbar_->on_save_to_scratch = [
this]() {
247 toolbar_->on_load_from_scratch = [
this]() {
250 toolbar_->on_upgrade_rom_version = [
this](int) {
251 ImGui::OpenPopup(
"UpgradeROMVersion");
256 toolbar_->on_rename_resource_label = [
this](
const std::string&
type,
int id,
257 const std::string& label) {
297 const int step = shift_held ? 16 : 1;
304 "overworld.entity_workbench"));
314 switch (entity->entity_type_) {
331 const size_t session_id =
346 const size_t session_id =
361 std::make_unique<OverworldInteractionCoordinator>(std::move(sink));
401 tile_painting_ = std::make_unique<TilePaintingManager>(deps, callbacks);
442 canvas_nav_ = std::make_unique<CanvasNavigationManager>();
468 LOG_DEBUG(
"OverworldEditor",
"Loading overworld.");
470 return absl::FailedPreconditionError(
"ROM not loaded");
495 [
this](
const std::vector<Tile16Commit>& commits) -> absl::Status {
497 for (
const auto& commit : commits) {
498 if (commit.tile_id >= 0 &&
499 commit.tile_id <
static_cast<int>(tiles16->size())) {
500 (*tiles16)[commit.tile_id] = commit.tile_data;
511 "Overworld editor refreshed after Tile16 changes");
512 return absl::OkStatus();
518 [
this](
const std::string& entity_type) {
534 [
this](
const std::string& group_name,
int palette_index) {
536 if (group_name ==
"ow_main" || group_name ==
"ow_animated" ||
537 group_name ==
"ow_aux" || group_name ==
"grass") {
539 "Palette change detected: %s, refreshing current map",
547 LOG_DEBUG(
"OverworldEditor",
"Registered as palette listener (ID: %d)",
554 if (!scratch_status.ok()) {
555 LOG_WARN(
"OverworldEditor",
"Failed to load scratch pad: %s",
556 std::string(scratch_status.message()).c_str());
565 return absl::OkStatus();
574 return absl::OkStatus();
579 return absl::OkStatus();
617 ImGui::SetNextWindowSize(ImVec2(400, 500), ImGuiCond_FirstUseEver);
631 ImGui::SetNextWindowSize(ImVec2(500, 450), ImGuiCond_FirstUseEver);
632 if (ImGui::Begin(
ICON_MD_LAYERS " Visual Effects Editor###OverlayEditor",
649 workbench->DrawPopups();
652 if (ImGui::BeginPopupModal(
"UpgradeROMVersion",
nullptr,
653 ImGuiWindowFlags_AlwaysAutoResize)) {
657 tr(
"This will apply the ZSCustomOverworld ASM patch to your ROM,\n"
658 "enabling advanced overworld features."));
661 const uint8_t current_version =
664 ImGui::Text(tr(
"Current Version: %s"),
665 current_version == 0xFF
667 : absl::StrFormat(
"v%d", current_version).c_str());
669 static int target_version = 3;
670 ImGui::RadioButton(tr(
"v2 (Basic features)"), &target_version, 2);
672 ImGui::RadioButton(tr(
"v3 (All features)"), &target_version, 3);
676 if (ImGui::Button(
ICON_MD_CHECK " Apply Upgrade", ImVec2(150.0f, 0.0f))) {
677 auto upgrade_status =
680 : absl::FailedPreconditionError(
"Upgrade system not initialized");
681 if (upgrade_status.ok()) {
687 ImGui::CloseCurrentPopup();
690 LOG_ERROR(
"OverworldEditor",
"Upgrade failed: %s",
691 upgrade_status.message().data());
695 if (ImGui::Button(
ICON_MD_CANCEL " Cancel", ImVec2(150.0f, 0.0f))) {
696 ImGui::CloseCurrentPopup();
711 return absl::OkStatus();
735 "Normalized stale overworld selection to world=%d map=%d",
775 map_texture_->PrimeWorldMaps(world, process_texture_queue);
781 const int clamped_world = std::clamp(world, 0, 2);
783 const int world_start = clamped_world * 0x40;
785 if (maps_remaining <= 0) {
825 "overworld.entity_workbench"));
839 "overworld.entity_workbench"));
851 "overworld.entity_workbench"));
867 workbench->SetActiveEntity(item);
890 *items = snapshot.
items;
893 auto* selected_item =
898 workbench->SetActiveEntity(selected_item);
914 std::string description) {
916 if (ItemSnapshotsEqual(before, after)) {
921 std::move(before), std::move(after),
925 std::move(description)));
930 if (!selected_item) {
933 "Select an overworld item first (Item Mode: key 5)",
943 *selected_item, offset_x, offset_y);
947 if (duplicate_or.ok()) {
948 duplicate_result.
entity = *duplicate_or;
949 duplicate_result.
status = absl::OkStatus();
951 duplicate_result.
status = duplicate_or.status();
953 "Failed to duplicate overworld item: " +
954 std::string(duplicate_or.status().message());
957 if (!duplicate_result.
ok()) {
961 ?
"Failed to duplicate overworld item"
968 auto* duplicated_item =
973 workbench->SetActiveEntity(duplicated_item);
976 absl::StrFormat(
"Duplicate overworld item 0x%02X",
977 static_cast<int>(duplicated_item->id_)));
981 absl::StrFormat(
"Duplicated item 0x%02X",
982 static_cast<int>(duplicated_item->id_)),
990 if (!selected_item) {
995 auto status =
NudgeItem(selected_item, delta_x, delta_y);
1007 workbench->SetActiveEntity(selected_item);
1010 std::move(before_snapshot),
1011 absl::StrFormat(
"Move overworld item 0x%02X (%+d,%+d)",
1012 static_cast<int>(selected_item->id_), delta_x, delta_y));
1019 if (!selected_item) {
1025 const uint8_t deleted_item_id = selected_identity.
id_;
1026 absl::Status remove_status =
1027 absl::FailedPreconditionError(
"Entity mutation service not initialized");
1034 if (!remove_status.ok()) {
1042 auto* nearest_item =
1050 workbench->SetActiveEntity(nearest_item);
1057 absl::StrFormat(
"Delete overworld item 0x%02X",
1058 static_cast<int>(deleted_item_id)));
1063 absl::StrFormat(
"Deleted item 0x%02X (selected nearest 0x%02X)",
1064 static_cast<int>(deleted_item_id),
1065 static_cast<int>(nearest_item->id_)),
1069 absl::StrFormat(
"Deleted overworld item 0x%02X",
1070 static_cast<int>(deleted_item_id)),
1083 return absl::FailedPreconditionError(
"Clipboard unavailable");
1088 std::vector<int> ids;
1093 static_cast<int>(std::floor(std::min(start.x, end.x) / 16.0f));
1095 static_cast<int>(std::floor(std::max(start.x, end.x) / 16.0f));
1097 static_cast<int>(std::floor(std::min(start.y, end.y) / 16.0f));
1099 static_cast<int>(std::floor(std::max(start.y, end.y) / 16.0f));
1100 const int width = end_x - start_x + 1;
1101 const int height = end_y - start_y + 1;
1102 ids.reserve(width * height);
1105 for (
int y = start_y; y <= end_y; ++y) {
1106 for (
int x = start_x; x <= end_x; ++x) {
1115 return absl::OkStatus();
1123 return absl::OkStatus();
1125 return absl::FailedPreconditionError(
"Nothing selected to copy");
1130 return absl::FailedPreconditionError(
"Clipboard unavailable");
1133 return absl::FailedPreconditionError(
"Clipboard empty");
1137 return absl::FailedPreconditionError(
"No paste target");
1146 const ImVec2 anchor =
1147 ImVec2(scaled_anchor.x / scale, scaled_anchor.y / scale);
1150 const int tile16_x =
1152 const int tile16_y =
1155 auto& selected_world =
1162 const int superY = local_map / 8;
1163 const int superX = local_map % 8;
1170 if (width * height !=
static_cast<int>(ids.size())) {
1171 return absl::InternalError(
"Clipboard dimensions mismatch");
1174 bool any_changed =
false;
1175 for (
int dy = 0; dy < height; ++dy) {
1176 for (
int dx = 0; dx < width; ++dx) {
1177 const int id = ids[dy * width + dx];
1178 const int gx = tile16_x + dx;
1179 const int gy = tile16_y + dy;
1181 const int global_x = superX * 32 + gx;
1182 const int global_y = superY * 32 + gy;
1183 if (global_x < 0 || global_x >= 256 || global_y < 0 || global_y >= 256)
1185 const int old_tile_id = selected_world[global_x][global_y];
1186 if (old_tile_id ==
id) {
1191 selected_world[global_x][global_y] = id;
1201 return absl::OkStatus();
1207 return absl::OkStatus();
1216 return absl::OkStatus();
1226 const bool saving_maps =
1238 manifest, write_policy, ranges,
"overworld maps",
"OverworldEditor",
1245 if (profile.has_expanded_tile32) {
1250 if (profile.has_expanded_tile16) {
1271 return absl::OkStatus();
1291 auto now = std::chrono::steady_clock::now();
1310 .tile_changes = {{{x, y}, old_tile_id}},
1324 std::vector<OverworldTileChange> changes;
1326 for (
const auto& [coords, old_tile_id] :
1328 auto [x, y] = coords;
1329 int new_tile_id = world_tiles[x][y];
1330 changes.push_back({x, y, old_tile_id, new_tile_id});
1332 auto action = std::make_unique<OverworldTilePaintAction>(
1334 std::move(changes), &
overworld_, [
this]() { RefreshOverworldMap(); });
1343 return absl::FailedPreconditionError(
"MapPropertiesSystem not initialized");
1355 before.
value = before_value;
1360 if (after_value == before_value) {
1361 return absl::OkStatus();
1365 after.
value = after_value;
1372 return absl::OkStatus();
1376 const std::vector<OverworldPropertyEdit>& edits,
1377 const std::string& description,
bool record_undo) {
1379 return absl::FailedPreconditionError(
"MapPropertiesSystem not initialized");
1381 if (edits.empty()) {
1382 return absl::OkStatus();
1386 for (
const auto& edit : edits) {
1389 return absl::OkStatus();
1394 std::vector<OverworldPropertyEdit> before_edits;
1395 std::vector<OverworldPropertyEdit> after_edits;
1396 before_edits.reserve(edits.size());
1397 after_edits.reserve(edits.size());
1399 for (
const auto& edit : edits) {
1405 if (!before_value.ok()) {
1406 for (
auto it = before_edits.rbegin(); it != before_edits.rend(); ++it) {
1409 return before_value.status();
1413 before.
value = *before_value;
1414 const absl::Status apply_status =
1416 if (!apply_status.ok()) {
1417 for (
auto it = before_edits.rbegin(); it != before_edits.rend(); ++it) {
1420 return apply_status;
1424 if (!after_value.ok()) {
1426 for (
auto it = before_edits.rbegin(); it != before_edits.rend(); ++it) {
1429 return after_value.status();
1431 if (*after_value == *before_value) {
1436 after.
value = *after_value;
1437 before_edits.push_back(std::move(before));
1438 after_edits.push_back(std::move(after));
1441 if (after_edits.empty()) {
1442 return absl::OkStatus();
1445 const std::string action_description =
1447 ? absl::StrFormat(
"Edit %d overworld map properties",
1448 static_cast<int>(after_edits.size()))
1451 before_edits, after_edits,
1455 action_description));
1456 return absl::OkStatus();
1460 const std::string& type,
int id,
const std::string& label) {
1462 return absl::FailedPreconditionError(
"No project is open");
1466 const std::string before =
1470 const std::string after =
1472 if (after == before) {
1473 return absl::OkStatus();
1478 [
this,
type,
id](
const std::string& value) {
1482 absl::StrFormat(
"Rename %s 0x%02X",
type,
id)));
1483 return absl::OkStatus();
1501 LOG_DEBUG(
"OverworldEditor",
"Loading overworld.");
1517 LOG_DEBUG(
"OverworldEditor",
"Loading overworld graphics (optimized).");
1531 "Loading overworld tileset (deferred textures).");
1544 LOG_DEBUG(
"OverworldEditor",
"Loading overworld tile16 graphics.");
1573 return absl::OkStatus();
1578 const int depth = 0x10;
1579 for (
int i = 0; i < 3; i++)
1581 int width = sprite.width();
1582 int height = sprite.height();
1583 if (width == 0 || height == 0) {
1590 *sprite.preview_graphics());
1596 return absl::OkStatus();
1619 map_texture_ = std::make_unique<OverworldMapTextureCoordinator>(ctx);
1642 map_refresh_ = std::make_unique<MapRefreshCoordinator>(ctx);
1673 LOG_WARN(
"OverworldEditor",
"Failed to refresh selected Tile16 %d: %s",
1674 tile_id, status.message().data());
1682 const size_t session_id =
1707 return absl::OkStatus();
1724 const char* world_label =
"LW";
1740 "Map", absl::StrFormat(
"%s #%02X", world_label,
current_map_ & 0xFF));
1744 const char* mode_label =
"Draw";
1747 mode_label =
"Entrances";
1750 mode_label =
"Exits";
1753 mode_label =
"Items";
1756 mode_label =
"Sprites";
1759 mode_label =
"Transports";
1762 mode_label =
"Music";
1767 mode_label =
"Mouse";
1770 mode_label =
"Draw";
1773 mode_label =
"Fill";
void set_dirty(bool dirty)
bool loaded() const
Check if the manifest has been loaded.
UndoManager undo_manager_
EditorDependencies dependencies_
void SetHostSurfaceHint(std::string hint)
Main UI class for editing overworld maps in A Link to the Past.
std::unique_ptr< UsageStatisticsCard > usage_stats_card_
absl::Status Clear() override
std::unique_ptr< MapPropertiesSystem > map_properties_system_
std::unique_ptr< OverworldCanvasRenderer > canvas_renderer_
OverworldEntityWorkbench * GetWorkbench()
Resolve the entity workbench window content (may be null).
void HandleMapInteraction()
bool overworld_canvas_fullscreen_
bool map_blockset_loaded_
void InitMapTextureCoordinator()
zelda3::OverworldEntranceTileTypes entrance_tiletypes_
void HandleTile16Edit()
Handle tile16 editing from context menu (MOUSE mode) Gets the tile16 under the cursor and opens the T...
std::optional< OverworldUndoPoint > current_paint_operation_
void PushItemUndoAction(OverworldItemsSnapshot before, std::string description)
absl::Status CheckForCurrentMap()
Check for map changes and refresh if needed.
void CreateUndoPoint(int map_id, int world, int x, int y, int old_tile_id)
absl::Status LoadScratchToSelection()
void ForceRefreshGraphics(int map_index)
void RequestTile16Selection(int tile_id)
void RestoreItemUndoSnapshot(const OverworldItemsSnapshot &snapshot)
std::vector< int > selected_tile16_ids_
absl::Status ApplyOverworldPropertyEdit(const OverworldPropertyEdit &edit, bool record_undo=true)
gfx::Bitmap current_gfx_bmp_
gfx::Tilemap tile16_blockset_
void InitCanvasNavigationManager()
Initialize the canvas navigation manager (called during Initialize)
void InitMapRefreshCoordinator()
Initialize the map refresh coordinator (called during Initialize)
std::optional< zelda3::OverworldItem > selected_item_identity_
void CycleTileSelection(int delta)
Tile16Editor tile16_editor_
std::unique_ptr< zelda3::OverworldUpgradeSystem > upgrade_system_
gui::Canvas ow_map_canvas_
void NotifyEntityModified(zelda3::GameEntity *entity)
Notify that an entity has been modified, marking ROM as dirty.
void SwitchToWorld(int world)
absl::Status Undo() override
void HandleEntityInsertion(const std::string &entity_type)
Handle entity insertion from context menu.
std::unique_ptr< MapRefreshCoordinator > map_refresh_
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > maps_bmp_
std::unique_ptr< OverworldMapTextureCoordinator > map_texture_
static bool NormalizeMapSelection(int ¤t_world, int ¤t_map)
Clamp a possibly stale world/map selection back into a valid overworld range.
bool PickTile16FromHoveredCanvas()
bool show_map_properties_panel_
void RefreshOverworldMap()
void CheckForOverworldEdits()
Check for tile edits - delegates to TilePaintingManager.
void UpdateBlocksetWithPendingTileChanges()
void RefreshMapProperties()
void ContributeStatus(StatusBar *status_bar) override
~OverworldEditor() override
void RefreshSiblingMapGraphics(int map_index, bool include_self=false)
gui::Canvas scratch_canvas_
void PrimeWorldMaps(int world, bool process_texture_queue=false)
absl::Status ApplyOverworldPropertyEdits(const std::vector< OverworldPropertyEdit > &edits, const std::string &description, bool record_undo=true)
void RefreshOverworldMapOnDemand(int map_index)
gui::Canvas current_gfx_canvas_
void Initialize() override
bool show_overlay_editor_
std::unique_ptr< OverworldSidebar > sidebar_
absl::Status Redo() override
void SetupCanvasAutomation()
std::chrono::steady_clock::time_point last_paint_time_
void InvalidateGraphicsCache(int map_id=-1)
Invalidate cached graphics for a specific map or all maps.
std::optional< int > pending_tile16_selection_after_gfx_
absl::Status RenameProjectResourceLabelWithUndo(const std::string &type, int id, const std::string &label)
absl::Status SaveCurrentSelectionToScratch()
zelda3::OverworldItem * GetSelectedItem()
Resolve selected item identity to the current live item pointer.
bool NormalizeCurrentSelectionState()
Clamp and synchronize stale map/world selection before panels draw.
bool DuplicateSelectedItem(int offset_x=16, int offset_y=0)
Duplicate selected item with optional pixel offset.
absl::Status RefreshMapPalette()
void DrawOverworldCanvas()
Draw the main overworld canvas.
gui::Canvas blockset_canvas_
absl::Status RefreshTile16Blockset()
zelda3::Overworld & overworld()
Access the underlying Overworld data.
void SetCurrentEntity(zelda3::GameEntity *entity)
Set the currently active entity for editing.
absl::Status LoadScratchPad()
void UpdateBlocksetSelectorState()
void FinalizePaintOperation()
std::unique_ptr< OverworldEntityRenderer > entity_renderer_
auto & GetWorldTiles(int world)
absl::Status Load() override
absl::Status UpdateGfxGroupEditor()
void EnsureMapTexture(int map_index)
Ensure a specific map has its texture created.
std::vector< gfx::Bitmap > sprite_previews_
std::unique_ptr< CanvasNavigationManager > canvas_nav_
absl::Status Copy() override
bool NudgeSelectedItem(int delta_x, int delta_y)
Move selected item by signed pixel deltas.
EntityEditMode entity_edit_mode_
std::unique_ptr< OverworldToolbar > toolbar_
GfxGroupEditor gfx_group_editor_
void ProcessDeferredTextures()
Create textures for deferred map bitmaps on demand.
absl::Status Update() final
std::unique_ptr< gui::TileSelectorWidget > blockset_selector_
absl::Status Paste() override
void ScrollBlocksetCanvasToCurrentTile()
Scroll the blockset canvas to show the current selected tile16.
static constexpr auto kPaintBatchTimeout
bool DeleteSelectedItem()
Delete selected item and preserve nearest-item selection continuity.
std::unique_ptr< TilePaintingManager > tile_painting_
gui::Canvas graphics_bin_canvas_
gfx::BitmapTable current_graphics_set_
bool show_custom_bg_color_editor_
zelda3::Overworld overworld_
absl::Status LoadGraphics()
Load the Bitmap objects for each OverworldMap.
absl::Status LoadSpriteGraphics()
gfx::IRenderer * renderer_
OverworldItemsSnapshot CaptureItemUndoSnapshot() const
absl::Status Save() override
void InitInteractionCoordinator()
std::unique_ptr< DebugWindowCard > debug_window_card_
void SelectMapForEditing(int map_id, bool respect_pin=true)
std::unique_ptr< OverworldInteractionCoordinator > interaction_coordinator_
zelda3::GameEntity * current_entity_
void HandleKeyboardShortcuts()
Handle overworld keyboard shortcuts and edit-mode hotkeys.
gui::Canvas properties_canvas_
std::unique_ptr< EntityMutationService > entity_mutation_service_
gfx::SnesPalette palette_
gfx::Bitmap tile16_blockset_bmp_
void ClearSelectedItem()
Clear active item selection.
void InitTilePaintingManager()
Initialize the tile painting manager (called after graphics load)
bool SelectItemByIdentity(const zelda3::OverworldItem &item_identity)
Select an overworld item using value identity matching.
Authoritative component for entity editing state and UI.
void OpenContextMenuFor(zelda3::GameEntity *entity)
void SetActiveEntity(zelda3::GameEntity *entity)
A session-aware status bar displayed at the bottom of the application.
void SetCustomSegment(const std::string &key, const std::string &value)
Set a custom segment with key-value pair.
void SetEditorMode(const std::string &mode)
Set the current editor mode or tool.
int current_tile16() const
absl::Status SetCurrentTile(int id)
void set_on_changes_committed(std::function< absl::Status(const std::vector< Tile16Commit > &)> callback)
bool has_pending_changes() const
Check if any tiles have uncommitted changes.
void RequestTileSwitch(int target_tile_id)
absl::Status Initialize(gfx::Bitmap &tile16_blockset_bmp, gfx::Bitmap ¤t_gfx_bmp, std::array< uint8_t, 0x200 > &all_tiles_types)
bool is_tile_modified(int tile_id) const
Check if a specific tile has pending changes.
void set_palette(const gfx::SnesPalette &palette)
void set_on_current_tile_changed(std::function< void(int)> callback)
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
void Push(std::unique_ptr< UndoAction > action)
absl::Status Redo()
Redo the top action. Returns error if stack is empty.
absl::Status Undo()
Undo the top action. Returns error if stack is empty.
size_t GetActiveSessionId() const
bool OpenWindow(size_t session_id, const std::string &base_window_id)
WindowContent * GetWindowContent(const std::string &window_id)
Get a WindowContent instance by ID.
bool ToggleWindow(size_t session_id, const std::string &base_window_id)
void RegisterPanelAlias(const std::string &legacy_base_id, const std::string &canonical_base_id)
Register a legacy panel ID alias that resolves to a canonical ID.
void MarkWindowRecentlyUsed(const std::string &window_id)
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
int RegisterPaletteListener(PaletteChangeCallback callback)
Register a callback for palette change notifications.
void UnregisterPaletteListener(int listener_id)
Unregister a palette change listener.
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
SDL_Surface * surface() const
RAII timer for automatic timing management.
auto selected_tile_pos() const
auto global_scale() const
auto select_rect_active() const
void SetUsageMode(CanvasUsage usage)
auto drawn_tile_position() const
void ClearContextMenuItems()
const ImVector< ImVec2 > & points() const
auto selected_points() const
Base class for all overworld and dungeon entities.
enum yaze::zelda3::GameEntity::EntityType entity_type_
Represents an overworld exit that transitions from dungeon to overworld.
absl::Status SaveMap32Expanded()
Save expanded tile32 definitions (v1+ ROMs)
void set_current_world(int world)
absl::Status Load(Rom *rom)
Load all overworld data from ROM.
const std::vector< uint8_t > & current_graphics() const
absl::Status SaveMapProperties()
Save per-area graphics, palettes, and messages.
std::vector< std::pair< uint32_t, uint32_t > > GetProjectedWriteRanges() const
Get the projected write ranges (PC offsets) for overworld map saves.
absl::Status SaveMap32Tiles()
Save tile32 definitions to ROM.
const gfx::SnesPalette & current_area_palette() const
absl::Status SaveMap16Tiles()
Save tile16 definitions to ROM.
absl::Status CreateTile32Tilemap()
Build tile32 tilemap from current tile16 data.
auto overworld_map(int i) const
const std::vector< uint8_t > & tile16_blockset_data() const
absl::Status SaveCustomOverworldData()
Save all v2/v3 property tables using the ROM's current feature flags.
void set_current_map(int i)
absl::Status SaveEntrances()
Save entrance warp points to ROM.
absl::Status SaveExits()
Save exit return points to ROM.
absl::Status EnsureMapBuilt(int map_index)
Build a map on-demand if it hasn't been built yet.
absl::Status SaveItems()
Save hidden overworld items to ROM.
uint16_t GetTile(int x, int y) const
absl::Status SaveOverworldMaps()
Save compressed map tile data to ROM.
auto mutable_all_tiles_types()
auto mutable_sprites(int state)
absl::Status SaveMap16Expanded()
Save expanded tile16 definitions (v1+ ROMs)
absl::Status SaveMusic()
Save per-area music IDs.
#define ICON_MD_FORMAT_COLOR_FILL
#define LOG_DEBUG(category, format,...)
#define LOG_ERROR(category, format,...)
#define LOG_WARN(category, format,...)
#define PRINT_IF_ERROR(expression)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
bool ItemIdentityMatchesForUndo(const zelda3::OverworldItem &lhs, const zelda3::OverworldItem &rhs)
bool ItemSnapshotsEqual(const OverworldItemsSnapshot &lhs, const OverworldItemsSnapshot &rhs)
Editors are the view controllers for the application.
absl::Status RenameProjectResourceLabel(project::YazeProject *project, const std::string &type, int id, const std::string &label)
absl::Status ValidateHackManifestSaveConflicts(const core::HackManifest &manifest, project::RomWritePolicy write_policy, const std::vector< std::pair< uint32_t, uint32_t > > &ranges, absl::string_view save_scope, const char *log_tag, ToastManager *toast_manager)
absl::Status RemoveItemByIdentity(zelda3::Overworld *overworld, const zelda3::OverworldItem &item_identity)
Remove an item by value identity instead of pointer identity.
constexpr unsigned int kOverworldMapSize
absl::Status NudgeItem(zelda3::OverworldItem *item, int delta_x, int delta_y)
Move an item by pixel deltas with overworld bounds clamping.
zelda3::OverworldItem * FindNearestItemForSelection(zelda3::Overworld *overworld, const zelda3::OverworldItem &anchor_identity)
Find the best next item to keep selection continuity after deletion.
zelda3::OverworldItem * FindItemByIdentity(zelda3::Overworld *overworld, const zelda3::OverworldItem &item_identity)
Find a live item by value identity.
std::string DescribeOverworldPropertyEdit(const OverworldPropertyEdit &edit)
constexpr int kTile16Size
std::string GetProjectResourceLabel(const project::YazeProject *project, const std::string &type, int id)
absl::StatusOr< zelda3::OverworldItem * > DuplicateItemByIdentity(zelda3::Overworld *overworld, const zelda3::OverworldItem &item_identity, int offset_x, int offset_y)
Duplicate an existing item by identity with a positional offset.
Tilemap CreateTilemap(IRenderer *renderer, const std::vector< uint8_t > &data, int width, int height, int tile_size, int num_tiles, const SnesPalette &palette)
void CenterText(const char *text)
constexpr int kNumTile16Individual
constexpr int kNumOverworldMaps
constexpr int OverworldCustomASMHasBeenApplied
OverworldRomProfile DetectOverworldRomProfile(const Rom &rom)
absl::StatusOr< OverworldEntranceTileTypes > LoadEntranceTileTypes(Rom *rom)
#define RETURN_IF_ERROR(expr)
struct yaze::core::FeatureFlags::Flags::Overworld overworld
Callbacks for operations that remain in the OverworldEditor.
std::function< void()> refresh_overworld_map
std::function< absl::Status()> refresh_tile16_blockset
std::function< void(int, bool)> select_map_for_editing
std::function< bool()> is_entity_hovered
Returns true if an entity is currently hovered (for pan suppression).
std::function< bool()> pick_tile16_from_hovered_canvas
std::function< void(int)> ensure_map_texture
Shared state pointers that the navigation manager reads/writes.
bool * show_map_properties_panel
std::unique_ptr< gui::TileSelectorWidget > * blockset_selector
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp
gui::Canvas * ow_map_canvas
zelda3::Overworld * overworld
bool * is_dragging_entity
gfx::Tilemap * tile16_blockset
EditingMode * current_mode
project::YazeProject * project
ToastManager * toast_manager
SharedClipboard * shared_clipboard
gfx::IRenderer * renderer
WorkspaceWindowManager * window_manager
std::string error_message
zelda3::GameEntity * entity
Context struct holding all data dependencies for map refresh operations. All pointers/references must...
gfx::Tilemap * tile16_blockset
gfx::SnesPalette * palette
zelda3::Overworld * overworld
std::function< void(int map_index)> ensure_map_texture
Callback to ensure a map texture is created (stays in OverworldEditor)
gfx::IRenderer * renderer
Tile16Editor * tile16_editor
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp
gfx::Bitmap * current_gfx_bmp
bool * map_blockset_loaded
gfx::BitmapTable * current_graphics_set
std::function< void(int map_index)> refresh_map_on_demand
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp
gfx::IRenderer * renderer
zelda3::Overworld * overworld
Sink for high-level commands emitted by the interaction coordinator.
std::function< void(zelda3::GameEntity *) on_entity_double_click)
std::function< void()> on_pick_tile_from_hover
std::function< void()> on_toggle_fullscreen
std::function< void(zelda3::GameEntity *) on_entity_context_menu)
std::function< bool()> can_edit_items
std::function< void()> on_toggle_tile16_editor
std::function< void()> on_toggle_brush
std::function< void()> on_duplicate_selected
std::function< void(int, int, bool)> on_nudge_selected
std::function< void()> on_undo
std::function< void(EditingMode)> on_set_editor_mode
std::function< void()> on_redo
std::function< void()> on_activate_fill
std::function< void(EntityEditMode)> on_set_entity_mode
std::function< void()> on_toggle_lock
std::function< void()> on_toggle_item_list
Snapshot of overworld item list + current item selection.
std::vector< zelda3::OverworldItem > items
std::optional< zelda3::OverworldItem > selected_item_identity
static constexpr const char * kItemList
static constexpr const char * kTile16Editor
std::vector< int > overworld_tile16_ids
bool has_overworld_tile16
Callbacks for undo integration and map refresh.
std::function< void(int tile_id)> request_tile16_selection
When set, eyedropper routes here (guarded RequestTileSwitch path).
std::function< void(int map_index)> refresh_overworld_map_on_demand
std::function< void()> scroll_blockset_to_current_tile
std::function< void()> finalize_paint_operation
std::function< void()> refresh_overworld_map
std::function< void(int map_id, int world, int x, int y, int old_tile_id)> create_undo_point
Shared state for the tile painting system.
Tile16Editor * tile16_editor
gui::Canvas * ow_map_canvas
zelda3::Overworld * overworld
std::vector< int > * selected_tile16_ids
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp
gfx::Tilemap * tile16_blockset
EditingMode * current_mode
Bitmap atlas
Master bitmap containing all tiles.
core::HackManifest hack_manifest