yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
canvas_navigation_manager.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_OVERWORLD_CANVAS_NAVIGATION_MANAGER_H
2#define YAZE_APP_EDITOR_OVERWORLD_CANVAS_NAVIGATION_MANAGER_H
3
4#include <array>
5#include <functional>
6#include <memory>
7#include <optional>
8#include <vector>
9
10#include "absl/status/status.h"
12#include "app/gfx/core/bitmap.h"
16#include "rom/rom.h"
17#include "zelda3/common.h"
19
20namespace yaze::editor {
21
22// Forward declarations
23class OverworldEntityRenderer;
24
31 ImVec2 residual{0.0f, 0.0f};
32 float idle_seconds = 0.0f;
33
38 ImVec2 Consume(ImVec2 wheel, float dt, float step_px, float snap_px);
39};
40
43ImVec2 ScrollForZoomAtAnchor(ImVec2 scroll, ImVec2 anchor, float old_scale,
44 float new_scale);
45
46// =============================================================================
47// CanvasNavigationManager
48// =============================================================================
49//
50// Extracted from OverworldEditor to encapsulate all canvas navigation logic:
51// - Map hover detection and lazy loading (CheckForCurrentMap)
52// - Pan and zoom controls
53// - Map interaction (context menus, lock toggle)
54// - Background preloading of adjacent maps
55// - Blockset selector synchronization
56//
57// The manager holds pointers to shared editor state (via NavigationContext)
58// and uses callbacks for operations that remain in the editor (e.g. map
59// refresh, texture creation).
60// =============================================================================
61
64 // Canvas references
66
67 // Data model
69 Rom* rom = nullptr;
70
71 // Selection state (mutable pointers into editor fields)
72 int* current_map = nullptr;
73 int* current_world = nullptr;
74 int* current_parent = nullptr;
75 int* current_tile16 = nullptr;
76 int* hovered_map = nullptr;
77
78 // Mode state
80 bool* current_map_lock = nullptr;
81 bool* is_dragging_entity = nullptr;
82
83 // Graphics
84 std::array<gfx::Bitmap, zelda3::kExpandedMapCount>* maps_bmp = nullptr;
86
87 // Widgets (read-only pointer to editor's unique_ptr)
88 std::unique_ptr<gui::TileSelectorWidget>* blockset_selector = nullptr;
89};
90
93 std::function<void()> refresh_overworld_map;
94 std::function<absl::Status()> refresh_tile16_blockset;
95 std::function<void(int)> ensure_map_texture;
96 std::function<void(int, bool)> select_map_for_editing;
97 std::function<bool()> pick_tile16_from_hovered_canvas;
99 std::function<bool()> is_entity_hovered;
101 std::function<void()> open_map_properties;
102};
103
107 bool left_released = false;
108 bool left_dragged = false; // Moved past the drag threshold while down.
109 // The left press this release ends also landed on this canvas, on the map
110 // now under the cursor. False for a press that dismissed a popup or menu,
111 // or began on another window or another map.
112 bool left_press_owned = false;
113 bool right_clicked = false;
114 bool shift = false;
115 bool entity_hovered = false;
116};
117
124bool IsMapSelectClick(const MapClickInput& input);
125
127 public:
129
131 void Initialize(const CanvasNavigationContext& context,
132 const CanvasNavigationCallbacks& callbacks);
133
134 // ===========================================================================
135 // Map Detection and Loading
136 // ===========================================================================
137
140 absl::Status CheckForCurrentMap();
141
142 // Update hover and unpinned selection using scaled canvas-local coordinates.
143 // Separate from rendering so all edit modes share the same tracking policy.
144 std::optional<int> TrackMapAtCanvasPosition(ImVec2 scaled_position);
145
146 // ===========================================================================
147 // Map Interaction
148 // ===========================================================================
149
154
159
160 // ===========================================================================
161 // Pan and Zoom
162 // ===========================================================================
163 //
164 // All scrolling of the canvas child goes through this manager:
165 // BeginCanvasViewport() immediately before BeginChild: applies zoom,
166 // drag pan and wheel input via SetNextWindowScroll
167 // so the frame draws with its final scroll.
168 // EndCanvasViewport() inside the child after BeginCanvas: records the
169 // viewport rect, scroll and hover for next frame.
170 // The child is created with ImGuiWindowFlags_NoScrollWithMouse so ImGui's
171 // own fractional wheel scroll never runs on the canvas.
172
173 void BeginCanvasViewport();
174 void EndCanvasViewport(bool canvas_item_hovered);
175
177 void ZoomIn();
178
180 void ZoomOut();
181
183 void ZoomToFit();
184
186 void ResetOverworldView();
187
189 void CenterOverworldView();
190
192 void CenterOnMap(int map_id);
193 void CenterOnWorldTile(int world_x, int world_y);
194
195 bool is_panning() const { return pan_active_; }
196
200
201 // ===========================================================================
202 // Blockset Selector Synchronization
203 // ===========================================================================
204
208
211
212 // ===========================================================================
213 // Background Pre-loading
214 // ===========================================================================
215
217 void QueueAdjacentMapsForPreload(int center_map);
218
220 void ProcessPreloadQueue();
221
222 private:
225
226 // Map under the cursor: the hover-tracked map, else the canvas position.
227 std::optional<int> MapUnderCursor() const;
228
229 // Left press owned by this canvas (see MapClickInput::left_press_owned):
230 // ImGuiIO::MouseClickedTime of that press and the map it landed on.
231 double left_press_time_ = -1.0;
232 std::optional<int> left_press_map_;
233
234 // Hover debounce state
236 float hover_time_ = 0.0f;
237 static constexpr float kHoverBuildDelay = 0.15f;
238
239 // Background pre-loading state
240 std::vector<int> preload_queue_;
241 static constexpr float kPreloadStartDelay = 0.3f;
242
243 // Zoom by `steps` of kOverworldZoomStep about a viewport-local anchor.
244 void ZoomBySteps(int steps, ImVec2 anchor);
245 void SetScaleAboutAnchor(float new_scale, ImVec2 anchor);
246 ImVec2 ClampScroll(ImVec2 scroll) const;
247 ImVec2 ContentSize() const;
248
249 // Viewport state recorded by EndCanvasViewport (previous frame).
250 ImVec2 viewport_min_{0.0f, 0.0f};
251 ImVec2 viewport_size_{0.0f, 0.0f};
252 ImVec2 last_scroll_{0.0f, 0.0f};
255 bool viewport_known_ = false;
256
257 std::optional<ImVec2> hover_follow_suspended_at_;
258
259 // Scroll to apply at the next BeginCanvasViewport.
260 std::optional<ImVec2> pending_scroll_;
261 std::optional<int> pending_center_map_;
262
263 // Wheel state
265 float zoom_residual_ = 0.0f;
266 float zoom_idle_seconds_ = 0.0f;
267
268 // Drag pan: content stays pinned to the point grabbed at mouse-down.
269 int pan_button_ = -1;
270 bool pan_active_ = false;
271 ImVec2 pan_anchor_mouse_{0.0f, 0.0f};
272 ImVec2 pan_anchor_scroll_{0.0f, 0.0f};
273};
274
275} // namespace yaze::editor
276
277#endif // YAZE_APP_EDITOR_OVERWORLD_CANVAS_NAVIGATION_MANAGER_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:49
void ScrollBlocksetCanvasToCurrentTile()
Scroll the blockset (tile16 selector) to show the currently selected tile16.
absl::Status CheckForCurrentMap()
Detect which map the mouse is over, trigger lazy loading, draw the selection outline,...
void CenterOnMap(int map_id)
Center the viewport on map_id (same world grid).
void UpdateBlocksetSelectorState()
Push current tile count and selection into the blockset widget.
void ProcessPreloadQueue()
Process one map from the preload queue (call once per frame).
void SetScaleAboutAnchor(float new_scale, ImVec2 anchor)
std::optional< int > TrackMapAtCanvasPosition(ImVec2 scaled_position)
void CenterOnWorldTile(int world_x, int world_y)
void QueueAdjacentMapsForPreload(int center_map)
Queue the 4-connected neighbors of center_map for lazy build.
void Initialize(const CanvasNavigationContext &context, const CanvasNavigationCallbacks &callbacks)
Initialize with shared state and callbacks.
void HandleMapInteraction()
Click selection (see IsMapSelectClick) and double-click to open properties. The paint-tool right-clic...
void ZoomToFit()
Scale so the whole current world fits the viewport.
void ZoomOut()
Decrease canvas zoom by one step, keeping the view center fixed.
void CenterOverworldView()
Center the viewport on the current map.
bool SelectMapUnderCursor()
Make the map under the cursor the current map, ignoring the pin (the pin, if on, then holds this map)...
void EndCanvasViewport(bool canvas_item_hovered)
void ZoomIn()
Increase canvas zoom by one step, keeping the view center fixed.
void ResetOverworldView()
Reset scroll to top-left and scale to 1.0.
Modern, robust canvas for drawing and manipulating graphics.
Definition canvas.h:64
Editors are the view controllers for the application.
ImVec2 ScrollForZoomAtAnchor(ImVec2 scroll, ImVec2 anchor, float old_scale, float new_scale)
bool IsMapSelectClick(const MapClickInput &input)
Callbacks for operations that remain in the OverworldEditor.
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< void()> open_map_properties
Opens (and focuses) the Map Properties window. Double-click target.
Shared state pointers that the navigation manager reads/writes.
std::array< gfx::Bitmap, zelda3::kExpandedMapCount > * maps_bmp
std::unique_ptr< gui::TileSelectorWidget > * blockset_selector
One frame of canvas mouse input, reduced to what map selection needs.
ImVec2 Consume(ImVec2 wheel, float dt, float step_px, float snap_px)
Tilemap structure for SNES tile-based graphics management.
Definition tilemap.h:118