yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_object_interaction.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_DUNGEON_DUNGEON_OBJECT_INTERACTION_H
2#define YAZE_APP_EDITOR_DUNGEON_DUNGEON_OBJECT_INTERACTION_H
3
4#include <functional>
5#include <memory>
6#include <optional>
7#include <utility>
8#include <vector>
9
21#include "imgui/imgui.h"
26#include "zelda3/dungeon/room.h"
29
30#include "rom/rom.h"
31
32namespace yaze {
33namespace editor {
34
44 public:
51
52 // ========================================================================
53 // Context and Configuration
54 // ========================================================================
55
68
78
79 // Last mutation/invalidation domain (best-effort). Used by editors to route
80 // undo capture and avoid expensive rerenders for overlay-only edits.
87
88 // Legacy setter - kept for backwards compatibility
93
94 // Main interaction handling
97 void PlaceObjectAtPosition(int room_x, int room_y);
98
99 void DrawSelectionHighlights(); // Draw highlights for selected objects
101 const std::vector<zelda3::RoomObject>& objects); // Draw hover indicator
102
103 // Drag and select box functionality
104 void DrawGhostPreview(); // Draw ghost preview for object placement
105
106 // Coordinate conversion
107 std::pair<int, int> RoomToCanvasCoordinates(int room_x, int room_y) const;
108 std::pair<int, int> CanvasToRoomCoordinates(int canvas_x, int canvas_y) const;
109 bool IsWithinCanvasBounds(int canvas_x, int canvas_y, int margin = 32) const;
110
111 // State management
112 void SetCurrentRoom(DungeonRoomStore* rooms, int room_id);
113 void SetPreviewObject(const zelda3::RoomObject& object, bool loaded);
115 bool force_refresh = false) {
116 bool palette_changed = current_palette_group_.name() != group.name() ||
117 current_palette_group_.size() != group.size();
118 for (int i = 0; !palette_changed && i < static_cast<int>(group.size());
119 ++i) {
120 palette_changed =
122 }
123 if (!palette_changed && !force_refresh) {
124 return;
125 }
126
131 }
132
133 // Mode manager access
136
137 // Mode queries - delegate to mode manager
141
142 void CancelPlacement();
143
144 // Door placement mode
162
163 // Sprite placement mode
164 void SetSpritePlacementMode(bool enabled, uint8_t sprite_id = 0);
171 uint8_t GetPreviewSpriteId() const {
172 return mode_manager_.GetModeState().preview_sprite_id.value_or(0);
173 }
179
180 // Item placement mode
181 void SetItemPlacementMode(bool enabled, uint8_t item_id = 0);
185 void SetPreviewItemId(uint8_t id) {
187 }
188 uint8_t GetPreviewItemId() const {
189 return mode_manager_.GetModeState().preview_item_id.value_or(0);
190 }
196
197 // Selection state - delegates to ObjectSelection
198 std::vector<size_t> GetSelectedObjectIndices() const {
200 }
201 void SetSelectedObjects(const std::vector<size_t>& indices) {
204 for (size_t idx : indices) {
206 }
207 }
211 void ClearSelection();
212 bool IsObjectSelected(size_t index) const {
213 return selection_.IsObjectSelected(index);
214 }
215 size_t GetSelectionCount() const { return selection_.GetSelectionCount(); }
216
217 // Selection change notification
218 void SetSelectionChangeCallback(std::function<void()> callback) {
219 selection_.SetSelectionChangedCallback(std::move(callback));
220 }
226
227 // Helper for click selection with proper mode handling
228
229 // Object manipulation
230 void HandleScrollWheelResize(); // Resize selected objects with scroll wheel
231
232 // Move the current canvas selection by one editor nudge step. Tile objects
233 // move by room-tile units; doors, sprites, and items use their native grids.
234 // Mixed selections move together so keyboard nudging follows the same grammar
235 // as marquee and additive selection.
236 bool NudgeSelected(int delta_x, int delta_y);
239 void HandleCopySelected();
240 void HandlePasteObjects();
245
246 // Inspector-friendly mutation helpers (with undo + rerender integration).
247 // These are intended for UI panels that want to edit a single object without
248 // duplicating mutation/invalidation boilerplate.
249 bool SetObjectId(size_t index, int16_t id);
250 bool SetObjectSize(size_t index, uint8_t size);
251 bool SetObjectLayer(size_t index, zelda3::RoomObject::LayerType layer);
252
253 // Stored placement assignment for selected objects. Stream 2 is available
254 // only when every selected object belongs to the room object stream; torches
255 // and pushable blocks use a two-value special-table draw selector instead.
256 bool CanAssignSelectedObjectsToLayer(int target_layer) const;
257 bool SendSelectedToLayer(int target_layer);
258
259 // Object ordering (changes draw order within the layer)
260 // SNES draws objects in list order - first objects appear behind, last on top
261 void
262 SendSelectedToFront(); // Move to end of list (drawn last, appears on top)
263 void
264 SendSelectedToBack(); // Move to start of list (drawn first, appears behind)
265 void BringSelectedForward(); // Move up one position in list
266 void SendSelectedBackward(); // Move down one position in list
267
268 // Layer filter access (delegates to ObjectSelection)
269 void SetLayerFilter(int layer) { selection_.SetLayerFilter(layer); }
270 int GetLayerFilter() const { return selection_.GetLayerFilter(); }
273 const char* GetLayerFilterName() const {
275 }
276 void SetLayersMerged(bool merged) { selection_.SetLayersMerged(merged); }
277 bool AreLayersMerged() const { return selection_.AreLayersMerged(); }
278
279 // Check keyboard shortcuts for layer operations
281
282 // Callbacks - stored in interaction_context_ (single source of truth)
284 std::function<void(const zelda3::RoomObject&)> callback) {
285 object_placed_callback_ = std::move(callback);
286 }
287 void SetCacheInvalidationCallback(std::function<void()> callback) {
288 interaction_context_.on_invalidate_cache = std::move(callback);
290 }
291 void SetMutationCallback(std::function<void()> callback) {
292 interaction_context_.on_mutation = std::move(callback);
294 }
296 editor_system_ = system;
297 }
298
299 // Entity selection (doors, sprites, items)
300 void SelectEntity(EntityType type, size_t index);
308
309 // Draw entity selection highlights
311 void DrawDoorSnapIndicators(); // Show valid snap positions during door drag
312
313 // Callbacks for entity changes
314 void SetEntityChangedCallback(std::function<void()> callback) {
315 interaction_context_.on_entity_changed = std::move(callback);
317 }
319 std::function<void(int, std::optional<size_t>, int, int)> callback) {
320 interaction_context_.on_door_pair_navigation = std::move(callback);
322 }
323
324 private:
329
334
335 // Unified interaction context and coordinator for entity handling
338
339 // Unified mode state machine - replaces scattered boolean flags
341
342 // Helper to calculate object bounds
343 std::pair<int, int> CalculateObjectBounds(const zelda3::RoomObject& object);
344
345 // Refactored input handlers
346 void HandleLeftClick(const ImVec2& canvas_mouse_pos);
347 void UpdateCollisionPainting(const ImVec2& canvas_mouse_pos);
348 void UpdateWaterFillPainting(const ImVec2& canvas_mouse_pos);
349 void HandleObjectSelectionStart(const ImVec2& canvas_mouse_pos);
350 void HandleEmptySpaceClick(const ImVec2& canvas_mouse_pos);
351 void HandleMouseRelease();
352 bool HandleKeyboardNudge();
353
355 std::vector<zelda3::Sprite> sprites;
356 std::vector<zelda3::PotItem> items;
361
362 bool HasData() const { return !sprites.empty() || !items.empty(); }
363 void Clear() {
364 sprites.clear();
365 items.clear();
366 origin_pixel_x = 0;
367 origin_pixel_y = 0;
368 origin_tile_x = 0;
369 origin_tile_y = 0;
370 }
371 };
372
373 void CopySelectedEntitiesToClipboard(bool clipboard_origin_set);
374 std::vector<SelectedEntity> PasteEntityClipboardAt(int target_pixel_x,
375 int target_pixel_y);
376
377 // Ghost preview bitmap (persists across frames for placement preview)
380
381 // Unified selection system - replaces legacy selection state
383
384 // Callbacks - stored only in interaction_context_ (no duplication)
385 std::function<void(const zelda3::RoomObject&)> object_placed_callback_;
386
387 // Entity selection state (doors, sprites, items)
388 // Note: entity selection is owned by InteractionCoordinator/handlers.
389};
390
391} // namespace editor
392} // namespace yaze
393
394#endif // YAZE_APP_EDITOR_DUNGEON_DUNGEON_OBJECT_INTERACTION_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:28
Handles object selection, placement, and interaction within the dungeon canvas.
void SetSelectedObjects(const std::vector< size_t > &indices)
void SetObjectSelectionVisibilityPredicate(std::function< bool(int, const zelda3::RoomObject &)> predicate)
DungeonCanvasTransform GetCanvasTransform() const
std::pair< int, int > CalculateObjectBounds(const zelda3::RoomObject &object)
bool IsWithinCanvasBounds(int canvas_x, int canvas_y, int margin=32) const
void SetCacheInvalidationCallback(std::function< void()> callback)
void HandleObjectSelectionStart(const ImVec2 &canvas_mouse_pos)
std::pair< int, int > RoomToCanvasCoordinates(int room_x, int room_y) const
void SetContext(const InteractionContext &ctx)
Set the unified interaction context.
void SetDoorPairNavigationCallback(std::function< void(int, std::optional< size_t >, int, int)> callback)
std::vector< SelectedEntity > PasteEntityClipboardAt(int target_pixel_x, int target_pixel_y)
void CopySelectedEntitiesToClipboard(bool clipboard_origin_set)
void SetItemPlacementMode(bool enabled, uint8_t item_id=0)
void DrawHoverHighlight(const std::vector< zelda3::RoomObject > &objects)
std::function< void(const zelda3::RoomObject &) object_placed_callback_)
void SetSpritePlacementMode(bool enabled, uint8_t sprite_id=0)
void SetEditorSystem(zelda3::DungeonEditorSystem *system)
bool SetObjectLayer(size_t index, zelda3::RoomObject::LayerType layer)
void SetObjectPlacedCallback(std::function< void(const zelda3::RoomObject &)> callback)
void HandleLeftClick(const ImVec2 &canvas_mouse_pos)
void SetCurrentRoom(DungeonRoomStore *rooms, int room_id)
std::vector< size_t > GetSelectedObjectIndices() const
void SetSelectionChangeCallback(std::function< void()> callback)
void UpdateWaterFillPainting(const ImVec2 &canvas_mouse_pos)
InteractionCoordinator & entity_coordinator()
Get the interaction coordinator for entity handling.
bool CanAssignSelectedObjectsToLayer(int target_layer) const
void SetMutationCallback(std::function< void()> callback)
void SetEntityChangedCallback(std::function< void()> callback)
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group, bool force_refresh=false)
void SelectEntity(EntityType type, size_t index)
const InteractionCoordinator & entity_coordinator() const
void SetDoorPlacementMode(bool enabled, zelda3::DoorType type=zelda3::DoorType::NormalDoor)
std::pair< int, int > CanvasToRoomCoordinates(int canvas_x, int canvas_y) const
void HandleEmptySpaceClick(const ImVec2 &canvas_mouse_pos)
void SetPreviewObject(const zelda3::RoomObject &object, bool loaded)
void UpdateCollisionPainting(const ImVec2 &canvas_mouse_pos)
const InteractionModeManager & mode_manager() const
Coordinates interaction mode switching and dispatches to handlers.
void SetContext(InteractionContext *ctx)
Set the shared interaction context.
Manages interaction mode state and transitions.
void CancelCurrentMode()
Cancel current mode and return to Select.
InteractionMode GetMode() const
Get current interaction mode.
ModeState & GetModeState()
Get mutable reference to mode state.
Manages object selection state and operations for the dungeon editor.
void SetSelectionChangedCallback(std::function< void()> callback)
Set callback to be invoked when selection changes.
bool IsMaskModeActive() const
Check if mask selection mode is active.
bool IsRectangleSelectionActive() const
Check if a rectangle selection is in progress.
int GetLayerFilter() const
Get the current active layer filter.
bool IsObjectSelected(size_t index) const
Check if an object is selected.
std::vector< size_t > GetSelectedIndices() const
Get all selected object indices.
bool AreLayersMerged() const
Check if layers are currently merged.
size_t GetSelectionCount() const
Get the number of selected objects.
void SelectObject(size_t index, SelectionMode mode=SelectionMode::Single)
Select a single object by index.
void ClearSelection()
Clear all selections.
const char * GetLayerFilterName() const
Get the name of the current layer filter for display.
void SetLayersMerged(bool merged)
Set whether layers are currently merged in the room.
void SetLayerFilter(int layer)
Set the active layer filter for selection.
bool IsLayerFilterActive() const
Check if layer filtering is active.
bool HasSelection() const
Check if any objects are selected.
void RefreshPreviewGraphics()
Refresh graphics without replacing the current placement geometry.
bool HasClipboardData() const
Check if clipboard has data.
Modern, robust canvas for drawing and manipulating graphics.
Definition canvas.h:64
auto global_scale() const
Definition canvas.h:403
auto zero_point() const
Definition canvas.h:354
auto scrolling() const
Definition canvas.h:356
MutationDomain
Domain/type of mutation for undo + invalidation routing.
EntityType
Type of entity that can be selected in the dungeon editor.
DoorType
Door types from ALTTP.
Definition door_types.h:33
@ NormalDoor
Normal door (upper layer)
Shared context for all interaction handlers.
std::function< void(int target_room_id, std::optional< size_t > target_door_index, int target_tile_x, int target_tile_y)> on_door_pair_navigation
std::function< void()> on_invalidate_cache
std::function< bool(int, const zelda3::RoomObject &) is_object_visible_for_selection)
std::function< void()> on_entity_changed
std::optional< zelda3::DoorType > preview_door_type
std::optional< uint8_t > preview_item_id
std::optional< uint8_t > preview_sprite_id
Represents a selected entity in the dungeon editor.
Represents a group of palettes.
const SnesPalette & palette_ref(int i) const