yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
overworld_editor.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_OVERWORLDEDITOR_H
2#define YAZE_APP_EDITOR_OVERWORLDEDITOR_H
3
4#include <chrono>
5#include <memory>
6#include <optional>
7
8#include "absl/status/status.h"
9#include "app/editor/editor.h"
35#include "app/gfx/core/bitmap.h"
39#include "app/gui/core/input.h"
42#include "imgui/imgui.h"
43#include "rom/rom.h"
46
47// =============================================================================
48// Overworld Editor - UI Layer
49// =============================================================================
50//
51// ARCHITECTURE OVERVIEW:
52// ----------------------
53// The OverworldEditor is the main UI class for editing overworld maps.
54// It orchestrates several subsystems:
55//
56// 1. TILE EDITING SYSTEM
57// - Tile16Editor: Popup for editing individual 16x16 tiles
58// - Tile selection and painting on the main canvas
59// - Undo/Redo stack for paint operations
60//
61// 2. ENTITY SYSTEM
62// - OverworldEntityRenderer: Draws entities on the canvas
63// - entity_operations.cc: Insertion/deletion logic
64// - overworld_entity_interaction.cc: Drag/drop and click handling
65//
66// 3. MAP PROPERTIES SYSTEM
67// - MapPropertiesSystem: Toolbar and context menus
68// - OverworldSidebar: Property editing tabs
69// - Graphics, palettes, music per area
70//
71// 4. CANVAS SYSTEM
72// - ow_map_canvas_: Main overworld display (4096x4096)
73// - blockset_canvas_: Tile16 selector
74// - scratch_canvas_: Layout workspace
75//
76// EDITING MODES:
77// --------------
78// - DRAW_TILE: Left-click paints tiles, right-click opens tile16 editor
79// - MOUSE: Left-click selects entities, right-click opens context menus
80//
81// KEY WORKFLOWS:
82// --------------
83// See README.md in this directory for complete workflow documentation.
84//
85// SUBSYSTEM ORGANIZATION:
86// -----------------------
87// The class is organized into logical sections marked with comment blocks.
88// Each section groups related methods and state for a specific subsystem.
89// =============================================================================
90
91namespace yaze {
92namespace editor {
93
94struct OverworldItemsSnapshot;
95
96// =============================================================================
97// Constants
98// =============================================================================
99
100constexpr unsigned int k4BPP = 4;
101constexpr unsigned int kByteSize = 3;
102constexpr unsigned int kMessageIdSize = 5;
103constexpr unsigned int kNumSheetsToLoad = 223;
106constexpr ImVec2 kCurrentGfxCanvasSize(0x100 + 1, 0x10 * 0x40 + 1);
107constexpr ImVec2 kBlocksetCanvasSize(0x100 + 1, 0x4000 + 1);
108constexpr ImVec2 kGraphicsBinCanvasSize(0x100 + 1, kNumSheetsToLoad * 0x40 + 1);
109
110constexpr ImGuiTableFlags kOWMapFlags =
111 ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable |
112 ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp;
113
114constexpr absl::string_view kWorldList =
115 "Light World\0Dark World\0Extra World\0";
116
117constexpr absl::string_view kGamePartComboString = "Part 0\0Part 1\0Part 2\0";
118
119constexpr absl::string_view kOWMapTable = "#MapSettingsTable";
120
139class OverworldEditor : public Editor, public gfx::GfxContext {
142
143 public:
144 // ===========================================================================
145 // Construction and Initialization
146 // ===========================================================================
147
152 // MapPropertiesSystem will be initialized after maps_bmp_ and canvas are
153 // ready
154 }
155
158 dependencies_ = deps;
159 }
160 ~OverworldEditor() override;
172
177
184
185 // ===========================================================================
186 // Editor Interface Implementation
187 // ===========================================================================
188
189 void Initialize() override;
190 absl::Status Load() override;
191 absl::Status Update() final;
192 absl::Status Undo() override;
193 absl::Status Redo() override;
194 absl::Status Cut() override { return absl::UnimplementedError("Cut"); }
195 absl::Status Copy() override;
196 absl::Status Paste() override;
198 absl::StatusOr<int> ApplyTile16Stencil(
199 int map_id, const std::vector<GuardedTileCell>& cells);
200 absl::Status Find() override { return absl::UnimplementedError("Find"); }
201 absl::Status Save() override;
202 absl::Status BeginSaveTransaction() override;
203 void RollbackSaveTransaction() override;
204 void CommitSaveTransaction() override;
205 absl::Status Clear() override;
208 (graphics_source_ && graphics_source_->any_dirty());
209 }
211 return graphics_source_ && graphics_source_->any_dirty();
212 }
213 absl::Status OpenProjectGraphicsSource();
214 absl::StatusOr<ProjectGraphicsImportPlan> PreviewProjectGraphicsImport(
215 const std::string& pack, const ProjectGraphicsImportBindings& bindings);
216 absl::Status ApplyProjectGraphicsImport(
217 const std::string& pack, const ProjectGraphicsImportBindings& bindings);
218 absl::Status PlaceProjectGraphicsImport(int world_x, int world_y);
219 absl::Status PublishProjectGraphicsSource();
221 std::function<project::YazeProject*()> provider) {
222 project_context_provider_ = std::move(provider);
223 }
224 absl::Status PrepareProjectSave();
226 void ContributeStatus(StatusBar* status_bar) override;
227 void DrawEditorMenu() override;
228 void DrawEditMenuItems() override;
230
233 // One 512x512 overworld screen for tools that draw areas outside this
234 // editor (the Cutscene Camera). Builds its texture on first use; nullptr
235 // for an invalid ID or a screen that is not built yet.
236 const gfx::Bitmap* AreaScreenBitmap(int map_id);
237
238 int jump_to_tab() { return jump_to_tab_; }
239 int jump_to_tab_ = -1;
240 // Regular entrance IDs share numbers with room IDs but not meaning; the
241 // dungeon editor resolves the entrance's room.
243
244 // ===========================================================================
245 // ROM State
246 // ===========================================================================
247
248 bool IsRomLoaded() const override { return rom_ && rom_->is_loaded(); }
249 std::string GetRomStatus() const override {
250 if (!rom_)
251 return "No ROM loaded";
252 if (!rom_->is_loaded())
253 return "ROM failed to load";
254 return absl::StrFormat("ROM loaded: %s", rom_->title());
255 }
256
257 Rom* rom() const { return rom_; }
259 return lyra_canvas_.EditAuthoring(std::move(after), overworld_,
261 }
262 // Project ownership is resolved through the session provider. The manager
263 // loads native assets before invoking either explicit lifecycle action.
264 absl::Status CreateLyraTerrain();
265 absl::Status OpenLyraTerrain(const std::string& path);
267 const std::string& project_path);
270 // Project terrain occupies the lower Special World rows without expanding
271 // the ROM model or materializing legacy maps for those IDs.
272 int DisplayedMapCount() const;
273 bool IsProjectTerrainMap(int map_id) const;
274 bool is_lyra_preview() const { return overworld_.is_lyra_preview(); }
278 absl::Status PaintLyraA0Terrain(int map_id, int x, int y, uint16_t tile);
279 absl::Status SaveLyraA0TerrainAs(const std::string& filename);
280 // A Lyra preview retains pointers and caches derived from one ROM image.
281 // Session replacement must be checked before the manager mutates the ROM.
282 absl::Status CheckRomReplacement(const Rom& replacement) const;
284
287 static bool NormalizeMapSelection(int& current_world, int& current_map,
288 int map_count = zelda3::kNumOverworldMaps);
289
291 void set_current_map(int map_id) {
292 if (map_id >= 0 && map_id < DisplayedMapCount()) {
293 // Finalize any pending paint operation before switching maps
296 current_map_ = map_id;
298 map_id / 0x40; // Calculate which world the map belongs to
299 if (const auto* map = overworld_.overworld_map(current_map_)) {
300 current_parent_ = map->parent();
301 } else {
303 }
304 if (!IsProjectTerrainMap(map_id)) {
307 }
308 }
309 }
310 void SetCurrentMap(int map_id) { set_current_map(map_id); }
311 void SelectMapForEditing(int map_id, bool respect_pin = true);
312
313 void set_current_tile16(int tile_id) { current_tile16_ = tile_id; }
314 int current_tile16_id() const { return current_tile16_; }
315 // Opens a Tile16's editable quadrants, focused on the requested quadrant.
316 // The selected map at invocation supplies the sheet and palette context.
317 absl::Status OpenGraphicsForTile16Quadrant(int tile16_id, int quadrant);
318 // Uses the map/tile captured by the context menu, not the hovered or pinned
319 // map. The clicked quadrant is focused first.
320 absl::Status OpenGraphicsForContextTile16(
321 const OverworldContextTarget& target);
323 return tile_painting_.get();
324 }
325 const gfx::Bitmap& map_bitmap(int map_id) const {
326 return maps_bmp_.at(map_id);
327 }
328 bool map_pinned() const { return current_map_lock_; }
329 int current_map_id() const { return current_map_; }
330 int current_world_id() const { return current_world_; }
331 int hovered_map_id() const { return hovered_map_; }
332
333 // ===========================================================================
334 // Graphics Loading
335 // ===========================================================================
336
344 absl::Status LoadGraphics();
345 absl::Status SyncProjectGraphicsPreview(bool force = false);
346
347 // ===========================================================================
348 // Entity Interaction API
349 // ===========================================================================
350
354
357 absl::Status ApplyEntranceEdit(zelda3::OverworldEntrance* target,
358 const zelda3::OverworldEntrance& draft);
359 absl::Status ApplyExitEdit(zelda3::OverworldExit* target,
360 const zelda3::OverworldExit& draft);
362
364 void RequestJumpToRoom(int room_id) { jump_to_tab_ = room_id; }
365
367 void RequestJumpToEntrance(int entrance_id) {
368 jump_to_entrance_ = entrance_id;
369 }
370
375
380
381 std::optional<OverworldEntityInsertionRequest> TakePendingEntityInsertion() {
382 auto request = std::move(pending_entity_insertion_);
384 return request;
385 }
386 std::string& insert_error() { return insert_error_; }
387
389 int game_state() const { return game_state_; }
390 // Preview only; does not rewrite story progression or entity placements.
391 void SetPreviewStoryState(int state);
392
393 void SetSelectionBrush(TileBrush brush);
394 void ClearSelectionBrush();
395 const TileBrush* selection_brush() const;
396 int GetTile16UsageCount(int tile_id) const;
397 std::string GetTile16ScopeLabel() const;
398
399 // ===========================================================================
400 // Entity System - Insertion and Editing
401 // ===========================================================================
402 // Entity operations are delegated to entity_operations.cc helper functions.
403 // Entity rendering is handled by OverworldEntityRenderer.
404 // Entity interaction (drag/drop) is in overworld_entity_interaction.cc.
405
408 void HandleEntityInsertion(const std::string& entity_type,
409 const OverworldContextTarget& target);
413 const std::optional<OverworldContextTarget>& target);
414 void DrawItemInsertPopup();
415 bool TryPlaceArmedItem();
416
419 void HandleTile16Edit(const OverworldContextTarget& target);
421
423 bool SelectItemByIdentity(const zelda3::OverworldItem& item_identity);
424
426 void ClearSelectedItem();
427
429 std::optional<zelda3::OverworldItem> selected_item_identity() const {
431 }
432
436
438 bool DuplicateSelectedItem(int offset_x = 16, int offset_y = 0);
439
441 bool NudgeSelectedItem(int delta_x, int delta_y);
442
444 bool DeleteSelectedItem();
445 bool DeleteItemByIdentity(const zelda3::OverworldItem& item_identity);
446
447 // ===========================================================================
448 // Keyboard Shortcuts
449 // ===========================================================================
450
452 if (tile_painting_)
453 tile_painting_->ToggleBrushTool();
454 }
456 if (tile_painting_)
457 tile_painting_->ActivateFillTool();
458 }
459 void CycleTileSelection(int delta);
460 // Map/view toggles bound through ShortcutManager (F11, Cmd/Ctrl+L,
461 // Cmd/Ctrl+T, Cmd/Ctrl+Shift+I).
462 void ToggleMapLock();
465 bool Tile16MenuEnabled() const;
468 void SetEditingMode(EditingMode mode);
470 void SelectAdjacentMap(int dx, int dy);
473 void JumpToMap(int map_id);
474 // Navigate to an inspected Tile16 without changing ROM or edit history.
475 void LocateOverworldTile(int map_id, int world_x, int world_y);
476 void SwitchToWorld(int world);
477 // View requests; applied when the canvas child begins (safe anywhere).
478 void ZoomIn();
479 void ZoomOut();
480 void ZoomToFit();
481 void ResetOverworldView();
482 void CenterOverworldView();
486 bool entities_visible() const { return show_entities_; }
487 void ToggleGrid();
488 bool grid_visible() const;
492
496 void RequestTile16Selection(int tile_id);
497
499
500 // ===========================================================================
501 // WindowContent View Hooks
502 // ===========================================================================
503 // These are used by focused WindowContent wrappers around Overworld views.
504 // Drawing is delegated to OverworldCanvasRenderer.
505
506 absl::Status DrawAreaGraphics() {
507 if (is_lyra_preview()) {
508 ImGui::TextDisabled("Lyra preview: area graphics editing unavailable");
509 return absl::OkStatus();
510 }
512 if (ImGui::Button("Edit / Import Project Graphics"))
514 if (!canvas_renderer_)
515 return absl::FailedPreconditionError("Renderer not initialized");
516 return canvas_renderer_->DrawAreaGraphics();
517 }
518 absl::Status DrawTile16Selector() {
519 if (is_lyra_preview()) {
520 ImGui::TextDisabled("Lyra preview: Tile16 editing unavailable");
521 return absl::OkStatus();
522 }
523 if (!canvas_renderer_)
524 return absl::FailedPreconditionError("Renderer not initialized");
525 return canvas_renderer_->DrawTile16Selector();
526 }
528 if (is_lyra_preview()) {
529 ImGui::TextDisabled("Lyra preview: map properties editing unavailable");
530 return;
531 }
534 canvas_renderer_->DrawMapProperties();
535 }
536
540 void InvalidateGraphicsCache(int map_id = -1) {
541 if (map_refresh_)
542 map_refresh_->InvalidateGraphicsCache(map_id);
543 }
544 absl::Status DrawScratchSpace();
546 if (is_lyra_preview()) {
547 ImGui::TextDisabled("Lyra preview: Tile8 editing unavailable");
548 return;
549 }
551 canvas_renderer_->DrawTile8Selector();
552 }
553 absl::Status UpdateGfxGroupEditor();
555 if (is_lyra_preview()) {
556 ImGui::TextDisabled("Lyra preview: overworld settings unavailable");
557 return;
558 }
561 canvas_renderer_->DrawV3Settings();
562 }
563
566
569
572 const Tile16Editor& tile16_editor() const { return tile16_editor_; }
573
577 return current_gfx_bmp_;
578 }
579
582
584 void DrawOverworldCanvas();
585
586 private:
587 void FocusLyraTerrain();
598 std::string ProjectGraphicsPath() const;
599 absl::Status ReloadProjectGraphics();
600 absl::Status RefreshPendingProjectGraphics();
601 absl::StatusOr<ProjectGraphicsImportContext> GraphicsImportContext();
602 std::shared_ptr<ProjectGraphicsSource> graphics_source_;
612 std::array<char, 1024> graphics_import_path_{};
613 std::optional<ProjectGraphicsImportAsset> graphics_import_asset_;
614 std::optional<ProjectGraphicsImportPlan> graphics_import_plan_;
619
620 // Identifies the exact descriptor image bound to this model. The session
621 // reload path may restore those bytes after a refused ROM replacement.
625 // ===========================================================================
626 // Entity Interaction System
627 // ===========================================================================
628 // Handles mouse interactions with entities in MOUSE mode.
629
631
634
635 // ===========================================================================
636 // Map Refresh System (delegated to MapRefreshCoordinator)
637 // ===========================================================================
638
643
644 // Convenience delegation methods for internal use
645 void RefreshChildMap(int map_index) {
646 if (map_refresh_ && !IsProjectTerrainMap(map_index))
647 map_refresh_->RefreshChildMap(map_index);
648 }
651 map_refresh_->RefreshOverworldMap();
652 }
653 void RefreshOverworldMapOnDemand(int map_index) {
654 if (map_refresh_ && !IsProjectTerrainMap(map_index))
655 map_refresh_->RefreshOverworldMapOnDemand(map_index);
656 }
657 void RefreshChildMapOnDemand(int map_index) {
658 if (map_refresh_ && !IsProjectTerrainMap(map_index))
659 map_refresh_->RefreshChildMapOnDemand(map_index);
660 }
661 absl::Status RefreshMapPalette(int map_id = -1) {
662 if (IsProjectTerrainMap(map_id < 0 ? current_map_ : map_id))
663 return absl::OkStatus();
664 if (map_refresh_)
665 return map_refresh_->RefreshMapPalette(map_id);
666 return absl::FailedPreconditionError(
667 "MapRefreshCoordinator not initialized");
668 }
669 void RefreshMapProperties(int map_id = -1) {
670 if (map_refresh_ &&
671 !IsProjectTerrainMap(map_id < 0 ? current_map_ : map_id))
672 map_refresh_->RefreshMapProperties(map_id);
673 }
674 absl::Status RefreshTile16Blockset() {
676 return absl::OkStatus();
677 if (map_refresh_)
678 return map_refresh_->RefreshTile16Blockset();
679 return absl::FailedPreconditionError(
680 "MapRefreshCoordinator not initialized");
681 }
684 map_refresh_->UpdateBlocksetWithPendingTileChanges();
685 }
686 void ForceRefreshGraphics(int map_index) {
687 if (map_refresh_ && !IsProjectTerrainMap(map_index))
688 map_refresh_->ForceRefreshGraphics(map_index);
689 }
690 void RefreshSiblingMapGraphics(int map_index, bool include_self = false) {
691 if (map_refresh_ && !IsProjectTerrainMap(map_index))
692 map_refresh_->RefreshSiblingMapGraphics(map_index, include_self);
693 }
694
695 // ===========================================================================
696 // Tile Editing System
697 // ===========================================================================
698 // Handles tile painting and selection on the main canvas.
699
702
705
707 absl::Status CheckForCurrentMap();
708
711
714
717
718 // Canvas navigation (delegated to CanvasNavigationManager)
723
724 // ===========================================================================
725 // Texture and Graphics Loading
726 // ===========================================================================
727
728 absl::Status LoadSpriteGraphics();
729
732
736
738 void EnsureMapTexture(int map_index);
739 void PrimeWorldMaps(int world, bool process_texture_queue = false);
740 // ===========================================================================
741 // Canvas Navigation (delegated to CanvasNavigationManager)
742 // ===========================================================================
743
744 // ===========================================================================
745 // Canvas Automation API
746 // ===========================================================================
747 // Integration with automation testing system.
748
751 bool AutomationSetTile(int x, int y, int tile_id);
752 int AutomationGetTile(int x, int y);
753
754 // ===========================================================================
755 // Scratch Space System
756 // ===========================================================================
757 // Workspace for planning tile layouts before placing them on the map.
758
759 absl::Status SaveCurrentSelectionToScratch();
760 absl::Status LoadScratchToSelection();
761 absl::Status ClearScratchSpace();
765 void UpdateScratchBitmapTile(int tile_x, int tile_y, int tile_id);
766 absl::Status LoadScratchPad();
767 absl::Status SaveScratchPad();
768 void BeginScratchEdit();
769 void FinishScratchEdit(const std::string& description);
770 absl::Status RestoreScratchState(const ScratchWorkspaceState& state);
771 absl::Status FlushScratchPadIfDirty();
774
775 // ===========================================================================
776 // Undo/Redo System
777 // ===========================================================================
778 // Tracks tile paint operations for undo/redo functionality.
779 // Operations within 500ms are batched to reduce undo point count.
780
782 int map_id = 0;
783 int world = 0; // 0=Light, 1=Dark, 2=Special
784 std::vector<std::pair<std::pair<int, int>, int>>
785 tile_changes; // ((x,y), old_tile_id)
786 std::chrono::steady_clock::time_point timestamp;
787 };
788
789 void CreateUndoPoint(int map_id, int world, int x, int y, int old_tile_id);
791 auto& GetWorldTiles(int world);
795 std::string description);
796 absl::Status ApplyOverworldPropertyEdit(const OverworldPropertyEdit& edit,
797 bool record_undo = true);
798 absl::Status ApplyOverworldPropertyEdits(
799 const std::vector<OverworldPropertyEdit>& edits,
800 const std::string& description, bool record_undo = true);
801 absl::Status RenameProjectResourceLabelWithUndo(const std::string& type,
802 int id,
803 const std::string& label);
804
805 // ===========================================================================
806 // Editing Mode State
807 // ===========================================================================
808
812
827
828 // ===========================================================================
829 // Current Selection State
830 // ===========================================================================
831
832 int current_world_ = 0; // 0=Light, 1=Dark, 2=Special
833 int current_map_ = 0; // Current map index (0-159)
834 int current_parent_ = 0; // Parent map for multi-area
835 int hovered_map_ = -1; // Physical screen under the cursor, or -1
837 int game_state_ = 1; // 0=Beginning, 1=Pendants, 2=Crystals
838 int current_tile16_ = 0; // Selected tile16 for painting
841
842 // Selected tile IDs for rectangle selection
843 std::vector<int> selected_tile16_ids_;
844
845 // ===========================================================================
846 // Loading State
847 // ===========================================================================
848
849 bool all_gfx_loaded_ = false;
851
855
856 // ===========================================================================
857 // Canvas Interaction State
858 // ===========================================================================
859
863 std::optional<OverworldItemsSnapshot> drag_item_snapshot_;
865 bool current_map_lock_ = false;
866
867 // ===========================================================================
868 // Property Windows (Standalone, Not PanelManager)
869 // ===========================================================================
870
873 // Area subscreen overlays (sky, fog, lava, canopy, rain) are shown by
874 // default, like the game; the toolbar toggle hides them.
876 bool show_entities_ = true;
877
878 // ===========================================================================
879 // UI Subsystem Components
880 // ===========================================================================
881
882 std::unique_ptr<OverworldCanvasRenderer> canvas_renderer_;
883 std::unique_ptr<CanvasNavigationManager> canvas_nav_;
884 std::unique_ptr<TilePaintingManager> tile_painting_;
885 std::unique_ptr<zelda3::OverworldUpgradeSystem> upgrade_system_;
886 std::unique_ptr<EntityMutationService> entity_mutation_service_;
887 std::unique_ptr<OverworldInteractionCoordinator> interaction_coordinator_;
888 std::unique_ptr<MapRefreshCoordinator> map_refresh_;
889 std::unique_ptr<OverworldMapTextureCoordinator> map_texture_;
890 std::unique_ptr<MapPropertiesSystem> map_properties_system_;
891 std::unique_ptr<OverworldSidebar> sidebar_;
892 std::unique_ptr<OverworldEntityRenderer> entity_renderer_;
893 std::unique_ptr<OverworldToolbar> toolbar_;
894
895 // ===========================================================================
896 // Scratch Space System (Unified Single Workspace)
897 // ===========================================================================
898
901 std::optional<ScratchWorkspaceState> scratch_edit_before_;
907 std::filesystem::path scratch_path_;
908 uint64_t scratch_name_id_ = 0;
909 std::array<char, 129> scratch_name_buffer_{};
910 uint64_t scratch_resize_id_ = 0;
911 std::array<int, 2> scratch_resize_dimensions_{16, 16};
916 ImVec2 scratch_select_min_{-1, -1};
917 ImVec2 scratch_select_max_{-1, -1};
918 bool scratch_selecting_ = false;
919 ImVec2 scratch_drag_start_{-1, -1};
922
923 // ===========================================================================
924 // Core Data References
925 // ===========================================================================
926
928
932
933 // Sub-editors
937
938 // ===========================================================================
939 // Graphics Data
940 // ===========================================================================
941
947 std::array<gfx::Bitmap, zelda3::kExpandedMapCount> maps_bmp_;
949 std::vector<gfx::Bitmap> sprite_previews_;
950
951 // ===========================================================================
952 // Overworld Data Layer
953 // ===========================================================================
954
958
959 // ===========================================================================
960 // Entity State
961 // ===========================================================================
962
964
967 std::optional<zelda3::OverworldItem> selected_item_identity_;
968 std::optional<OverworldEntityEditingTarget> editing_target_;
969
970 // Edit buffers for popups (session-specific)
975
976 // Deferred entity insertion (needed for popup flow from context menu)
977 std::optional<OverworldEntityInsertionRequest> pending_entity_insertion_;
978 std::optional<OverworldContextTarget> item_insert_target_;
981 uint8_t armed_item_id_ = 0;
982 std::string insert_error_;
983
984 // ===========================================================================
985 // Canvas Components
986 // ===========================================================================
987
994 std::unique_ptr<gui::TileSelectorWidget> blockset_selector_;
998 gui::Canvas scratch_canvas_{"ScratchSpace", ImVec2(320, 480),
1000
1001 // ===========================================================================
1002 // Panel Cards
1003 // ===========================================================================
1004
1005 std::unique_ptr<UsageStatisticsCard> usage_stats_card_;
1006 std::unique_ptr<DebugWindowCard> debug_window_card_;
1007
1008 absl::Status status_;
1009
1010 // ===========================================================================
1011 // Undo/Redo State
1012 // ===========================================================================
1013
1014 std::optional<OverworldUndoPoint> current_paint_operation_;
1015
1016 // ===========================================================================
1017 // Event Listeners
1018 // ===========================================================================
1019
1021};
1022} // namespace editor
1023} // namespace yaze
1024
1025#endif
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:52
bool is_loaded() const
Definition rom.h:199
auto title() const
Definition rom.h:211
Interface for editor classes.
Definition editor.h:252
UndoManager undo_manager_
Definition editor.h:383
project::YazeProject * project() const
Definition editor.h:370
virtual void SetDependencies(const EditorDependencies &deps)
Definition editor.h:257
zelda3::GameData * game_data() const
Definition editor.h:369
EditorDependencies dependencies_
Definition editor.h:382
EditorType type() const
Definition editor.h:355
EditorType type_
Definition editor.h:381
Editor-level service responsible for overworld entity mutations.
Manage graphics group configurations in a Rom.
std::function< absl::StatusOr< zelda3::RoomsetUsageReport >(int)> RoomsetUsageCallback
std::function< absl::StatusOr< zelda3::MainGroupUsageReport >(int, int)> MainUsageCallback
void SetRoomsetUsageCallback(RoomsetUsageCallback callback)
void SetMainUsageCallback(MainUsageCallback callback)
void SetWorkspaceState(GfxGroupWorkspaceState *state)
void SetUndoManager(UndoManager *undo)
void SetGameData(zelda3::GameData *data)
absl::Status EditAuthoring(core::LyraAuthoringState after, zelda3::Overworld &overworld, UndoManager &history)
void FinishStroke(UndoManager &history)
Handles all canvas drawing and panel rendering for the overworld editor.
Main UI class for editing overworld maps in A Link to the Past.
absl::Status ApplyEntranceEdit(zelda3::OverworldEntrance *target, const zelda3::OverworldEntrance &draft)
ProjectGraphicsImportBindings graphics_import_applied_bindings_
bool IsProjectTerrainMap(int map_id) const
void LocateOverworldTile(int map_id, int world_x, int world_y)
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).
zelda3::OverworldEntranceTileTypes entrance_tiletypes_
absl::Status SaveProjectTerrainAs(project::YazeProject *project, const std::string &project_path)
void OpenEntityContextMenu(zelda3::GameEntity *entity)
std::array< gfx::Bitmap, zelda3::kExpandedMapCount > maps_bmp_
zelda3::OverworldExit & edit_exit()
EditorContextSnapshot BuildContextSnapshot() const override
std::optional< OverworldUndoPoint > current_paint_operation_
absl::Status BeginSaveTransaction() override
void PushItemUndoAction(OverworldItemsSnapshot before, std::string description)
absl::Status CheckForCurrentMap()
Check for map changes and refresh if needed.
std::array< char, 1024 > graphics_import_path_
std::array< char, 129 > scratch_name_buffer_
void CreateUndoPoint(int map_id, int world, int x, int y, int old_tile_id)
absl::StatusOr< int > ApplyTile16Stencil(int map_id, const std::vector< GuardedTileCell > &cells)
Select map_id and apply a guarded stencil as one undoable paint.
absl::Status Cut() override
void ForceRefreshGraphics(int map_index)
zelda3::GameEntity * ResolveEditingEntity()
void RestoreItemUndoSnapshot(const OverworldItemsSnapshot &snapshot)
absl::Status EditProjectMapAuthoring(core::LyraAuthoringState after)
std::vector< int > selected_tile16_ids_
absl::Status ApplyOverworldPropertyEdit(const OverworldPropertyEdit &edit, bool record_undo=true)
zelda3::OverworldEntrance edit_entrance_
const gfx::Tilemap & tile16_blockset() const
Read-only access for integration tests that verify refresh output.
absl::Status ApplyProjectGraphicsImport(const std::string &pack, const ProjectGraphicsImportBindings &bindings)
void InitCanvasNavigationManager()
Initialize the canvas navigation manager (called during Initialize)
zelda3::OverworldGraphicsPreview graphics_preview_baseline_
void InitMapRefreshCoordinator()
Initialize the map refresh coordinator (called during Initialize)
void RequestItemInsertPopup(const std::optional< OverworldContextTarget > &target)
std::optional< zelda3::OverworldItem > selected_item_identity_
void SetSelectionBrush(TileBrush brush)
absl::Status RefreshMapPalette(int map_id=-1)
zelda3::OverworldBlockset refresh_blockset_
zelda3::OverworldItem & edit_item()
absl::Status PaintLyraA0Terrain(int map_id, int x, int y, uint16_t tile)
std::unique_ptr< zelda3::OverworldUpgradeSystem > upgrade_system_
void RequestJumpToEntrance(int entrance_id)
Trigger a jump to a dungeon entrance.
absl::Status SyncProjectGraphicsPreview(bool force=false)
void SetDependencies(const EditorDependencies &deps) override
bool DeleteItemByIdentity(const zelda3::OverworldItem &item_identity)
absl::StatusOr< ProjectGraphicsImportPlan > PreviewProjectGraphicsImport(const std::string &pack, const ProjectGraphicsImportBindings &bindings)
void HandleEntityInsertion(const std::string &entity_type, const OverworldContextTarget &target)
Handle entity insertion from context menu.
void NotifyEntityModified(zelda3::GameEntity *entity)
Notify that an entity has been modified, marking ROM as dirty.
absl::Status CheckRomReplacement(const Rom &replacement) const
absl::Status OpenLyraTerrain(const std::string &path)
std::optional< ScratchWorkspaceState > scratch_edit_before_
zelda3::GameEntity * dragged_entity_
std::unique_ptr< MapRefreshCoordinator > map_refresh_
void SelectAdjacentMap(int dx, int dy)
Alt+Arrow: select the neighbouring screen in the world grid and center it.
std::unique_ptr< OverworldMapTextureCoordinator > map_texture_
void CheckForOverworldEdits()
Check for tile edits - delegates to TilePaintingManager.
void UpdateScratchBitmapTile(int tile_x, int tile_y, int tile_id)
UsageStatisticsCard * usage_stats_card()
Access usage statistics card for panel.
const gfx::Bitmap & map_bitmap(int map_id) const
void ContributeStatus(StatusBar *status_bar) override
EntityMutationService * entity_mutation_service()
Access the entity mutation service.
void SetGameData(zelda3::GameData *game_data) override
void RefreshSiblingMapGraphics(int map_index, bool include_self=false)
void PrimeWorldMaps(int world, bool process_texture_queue=false)
std::optional< zelda3::OverworldItem > selected_item_identity() const
Get current selected item identity snapshot.
bool SampleContextTile16(const OverworldContextTarget &target)
std::optional< OverworldContextTarget > item_insert_target_
void SetProjectContextProvider(std::function< project::YazeProject *()> provider)
absl::Status ApplyOverworldPropertyEdits(const std::vector< OverworldPropertyEdit > &edits, const std::string &description, bool record_undo=true)
void set_current_map(int map_id)
Set the current map for editing (also updates world)
void RefreshOverworldMapOnDemand(int map_index)
void RefreshMapsForSheetEdits()
Mark maps for a graphics rebuild when a sheet they use changed in the session's sheet store (an unsav...
std::unique_ptr< OverworldSidebar > sidebar_
int GetTile16UsageCount(int tile_id) const
void InvalidateGraphicsCache(int map_id=-1)
Invalidate cached graphics for a specific map or all maps.
const TileBrush * selection_brush() const
DebugWindowCard * debug_window_card()
Access debug window card for panel.
void FinishScratchEdit(const std::string &description)
std::optional< int > pending_tile16_selection_after_gfx_
void HandleTile16Edit(const OverworldContextTarget &target)
Handle tile16 editing from context menu (MOUSE mode) Opens the Tile16 captured at menu-open through t...
static bool NormalizeMapSelection(int &current_world, int &current_map, int map_count=zelda3::kNumOverworldMaps)
Clamp a possibly stale world/map selection back into a valid overworld range.
void SetEditingMode(EditingMode mode)
Tool change from the toolbar or keys 1/2: also leaves entity modes.
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()
Handle overworld keyboard shortcuts and edit-mode hotkeys.
bool DuplicateSelectedItem(int offset_x=16, int offset_y=0)
Duplicate selected item with optional pixel offset.
bool AutomationSetTile(int x, int y, int tile_id)
Definition automation.cc:25
void DrawOverworldCanvas()
Draw the main overworld canvas.
void OpenEntityEditor(zelda3::GameEntity *entity)
zelda3::Overworld & overworld()
Access the underlying Overworld data.
void SetCurrentEntity(zelda3::GameEntity *entity)
Set the currently active entity for editing.
absl::Status RestoreScratchState(const ScratchWorkspaceState &state)
zelda3::OverworldItem edit_item_
std::optional< OverworldEntityInsertionRequest > TakePendingEntityInsertion()
std::optional< OverworldItemsSnapshot > drag_item_snapshot_
Item state before an in-progress canvas drag (drag undo).
std::string GetTile16ScopeLabel() const
void RefreshChildMap(int map_index)
std::unique_ptr< OverworldEntityRenderer > entity_renderer_
std::optional< OverworldEntityInsertionRequest > pending_entity_insertion_
absl::Status Load() override
friend class ProjectGraphicsImportWorkflowTestPeer
absl::Status RebuildScratchBitmapFromTileData()
std::filesystem::path scratch_path_
void EnsureMapTexture(int map_index)
Ensure a specific map has its texture created.
gui::AdaptiveSheetScaleMode scratch_scale_mode_
const gfx::Bitmap & current_gfx_bmp_for_testing() const
std::vector< gfx::Bitmap > sprite_previews_
absl::Status OpenGraphicsForTile16Quadrant(int tile16_id, int quadrant)
std::shared_ptr< ProjectGraphicsSource > graphics_source_
std::unique_ptr< CanvasNavigationManager > canvas_nav_
absl::Status SaveLyraA0TerrainAs(const std::string &filename)
OverworldEditor(Rom *rom, const EditorDependencies &deps)
std::string GetRomStatus() const override
bool NudgeSelectedItem(int delta_x, int delta_y)
Move selected item by signed pixel deltas.
const project::YazeProject * graphics_source_project_
const gfx::Bitmap * AreaScreenBitmap(int map_id)
std::unique_ptr< OverworldToolbar > toolbar_
bool IsRomLoaded() const override
Tile16Editor & tile16_editor()
Access the Tile16 Editor for panel integration.
void ProcessDeferredTextures()
Create textures for deferred map bitmaps on demand.
absl::Status OpenGraphicsForContextTile16(const OverworldContextTarget &target)
const Tile16Editor & tile16_editor() const
zelda3::OverworldEntrance & edit_entrance()
std::unique_ptr< gui::TileSelectorWidget > blockset_selector_
std::optional< OverworldEntityEditingTarget > editing_target_
zelda3::GameEntity * current_entity() const
project::YazeProject * TerrainProject() const
void RefreshMapProperties(int map_id=-1)
absl::Status Paste() override
void ScrollBlocksetCanvasToCurrentTile()
Scroll the blockset canvas to show the current selected tile16.
std::optional< ProjectGraphicsImportPlan > graphics_import_plan_
absl::Status PlaceProjectGraphicsImport(int world_x, int world_y)
bool DeleteSelectedItem()
Delete selected item and preserve nearest-item selection continuity.
std::unique_ptr< TilePaintingManager > tile_painting_
std::function< project::YazeProject *()> project_context_provider_
absl::Status LoadGraphics()
Load the Bitmap objects for each OverworldMap.
void RefreshChildMapOnDemand(int map_index)
absl::Status Find() override
void SetRoomsetGraphicsUsageCallback(GfxGroupEditor::RoomsetUsageCallback callback)
std::array< int, 2 > scratch_resize_dimensions_
OverworldItemsSnapshot CaptureItemUndoSnapshot() const
void RequestJumpToRoom(int room_id)
Trigger a jump to a dungeon room.
ProjectGraphicsImportBindings graphics_import_bindings_
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_
absl::StatusOr< ProjectGraphicsImportContext > GraphicsImportContext()
void SetEntityEditMode(EntityEditMode mode)
Entity focus (entrances/exits/items/sprites); NONE = all entities.
zelda3::OverworldExit edit_exit_
std::optional< ProjectGraphicsImportAsset > graphics_import_asset_
void PrepareForSessionTeardown() override
int AutomationGetTile(int x, int y)
Definition automation.cc:54
std::unique_ptr< EntityMutationService > entity_mutation_service_
absl::Status ApplyExitEdit(zelda3::OverworldExit *target, const zelda3::OverworldExit &draft)
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.
void SetMainGraphicsUsageCallback(GfxGroupEditor::MainUsageCallback callback)
const TilePaintingManager * tile_painting() const
Authoritative component for entity editing state and UI.
Allows the user to view and edit in game palettes.
A session-aware status bar displayed at the bottom of the application.
Definition status_bar.h:57
ImGui façade for Tile16 editing; domain state lives in Tile16EditSession.
void SetGameData(zelda3::GameData *game_data)
Manages tile painting, fill, selection, and eyedropper operations.
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:70
uint8_t at(int i) const
Definition bitmap.h:412
Shared graphical context across editors.
Defines an abstract interface for all rendering operations.
Definition irenderer.h:60
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
Modern, robust canvas for drawing and manipulating graphics.
Definition canvas.h:64
Base class for all overworld and dungeon entities.
Definition common.h:31
Represents an overworld exit that transitions from dungeon to overworld.
void set_current_world(int world)
Definition overworld.h:845
void SetGameData(GameData *game_data)
Definition overworld.h:427
bool lyra_a0_terrain_writable() const
Definition overworld.h:457
bool is_lyra_preview() const
Definition overworld.h:444
auto overworld_map(int i) const
Definition overworld.h:770
void set_current_map(int i)
Definition overworld.h:844
A class for managing sprites in the overworld and underworld.
Definition sprite.h:39
constexpr ImVec2 kOverworldCanvasSize(kOverworldMapSize *8, kOverworldMapSize *8)
constexpr absl::string_view kOWMapTable
constexpr ImGuiTableFlags kOWMapFlags
constexpr unsigned int kOverworldMapSize
constexpr absl::string_view kWorldList
constexpr absl::string_view kGamePartComboString
constexpr unsigned int kNumSheetsToLoad
constexpr ImVec2 kCurrentGfxCanvasSize(0x100+1, 0x10 *0x40+1)
constexpr ImVec2 kBlocksetCanvasSize(0x100+1, 0x4000+1)
constexpr ImVec2 kGraphicsBinCanvasSize(0x100+1, kNumSheetsToLoad *0x40+1)
constexpr unsigned int kByteSize
constexpr unsigned int k4BPP
constexpr unsigned int kMessageIdSize
std::unordered_map< int, std::unique_ptr< gfx::Bitmap > > BitmapTable
Definition bitmap.h:549
constexpr int kNumOverworldMaps
Definition common.h:85
std::vector< std::vector< uint16_t > > OverworldBlockset
Represents tile32 data for the overworld.
std::map< int, AreaGraphicsPreview > OverworldGraphicsPreview
Unified dependency container for all editor types.
Definition editor.h:170
project::YazeProject * project
Definition editor.h:174
GfxGroupWorkspaceState * gfx_group_workspace
Definition editor.h:179
std::vector< std::pair< std::pair< int, int >, int > > tile_changes
std::chrono::steady_clock::time_point timestamp
Snapshot of overworld item list + current item selection.
Tilemap structure for SNES tile-based graphics management.
Definition tilemap.h:118
Modern project structure with comprehensive settings consolidation.
Definition project.h:290