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
130 auto& tile_handler = entity_coordinator_.tile_handler();
131 if (tile_handler.IsPlacementActive()) {
132 tile_handler.SetPreviewObject(preview_object_);
133 }
134 }
135
136 // Mode manager access
139
140 // Mode queries - delegate to mode manager
144
145 void CancelPlacement();
146
147 // Door placement mode
165
166 // Sprite placement mode
167 void SetSpritePlacementMode(bool enabled, uint8_t sprite_id = 0);
174 uint8_t GetPreviewSpriteId() const {
175 return mode_manager_.GetModeState().preview_sprite_id.value_or(0);
176 }
182
183 // Item placement mode
184 void SetItemPlacementMode(bool enabled, uint8_t item_id = 0);
188 void SetPreviewItemId(uint8_t id) {
190 }
191 uint8_t GetPreviewItemId() const {
192 return mode_manager_.GetModeState().preview_item_id.value_or(0);
193 }
199
200 // Selection state - delegates to ObjectSelection
201 std::vector<size_t> GetSelectedObjectIndices() const {
203 }
204 void SetSelectedObjects(const std::vector<size_t>& indices) {
207 for (size_t idx : indices) {
209 }
210 }
214 void ClearSelection();
215 bool IsObjectSelected(size_t index) const {
216 return selection_.IsObjectSelected(index);
217 }
218 size_t GetSelectionCount() const { return selection_.GetSelectionCount(); }
219
220 // Selection change notification
221 void SetSelectionChangeCallback(std::function<void()> callback) {
222 selection_.SetSelectionChangedCallback(std::move(callback));
223 }
224
225 // Helper for click selection with proper mode handling
226
227 // Object manipulation
228 void HandleScrollWheelResize(); // Resize selected objects with scroll wheel
229
230 // Move the current canvas selection by one editor nudge step. Tile objects
231 // move by room-tile units; doors, sprites, and items use their native grids.
232 // Mixed selections move together so keyboard nudging follows the same grammar
233 // as marquee and additive selection.
234 bool NudgeSelected(int delta_x, int delta_y);
237 void HandleCopySelected();
238 void HandlePasteObjects();
243
244 // Inspector-friendly mutation helpers (with undo + rerender integration).
245 // These are intended for UI panels that want to edit a single object without
246 // duplicating mutation/invalidation boilerplate.
247 bool SetObjectId(size_t index, int16_t id);
248 bool SetObjectSize(size_t index, uint8_t size);
249 bool SetObjectLayer(size_t index, zelda3::RoomObject::LayerType layer);
250
251 // Stored placement assignment for selected objects. Stream 2 is available
252 // only when every selected object belongs to the room object stream; torches
253 // and pushable blocks use a two-value special-table draw selector instead.
254 bool CanAssignSelectedObjectsToLayer(int target_layer) const;
255 bool SendSelectedToLayer(int target_layer);
256
257 // Object ordering (changes draw order within the layer)
258 // SNES draws objects in list order - first objects appear behind, last on top
259 void
260 SendSelectedToFront(); // Move to end of list (drawn last, appears on top)
261 void
262 SendSelectedToBack(); // Move to start of list (drawn first, appears behind)
263 void BringSelectedForward(); // Move up one position in list
264 void SendSelectedBackward(); // Move down one position in list
265
266 // Layer filter access (delegates to ObjectSelection)
267 void SetLayerFilter(int layer) { selection_.SetLayerFilter(layer); }
268 int GetLayerFilter() const { return selection_.GetLayerFilter(); }
271 const char* GetLayerFilterName() const {
273 }
274 void SetLayersMerged(bool merged) { selection_.SetLayersMerged(merged); }
275 bool AreLayersMerged() const { return selection_.AreLayersMerged(); }
276
277 // Check keyboard shortcuts for layer operations
279
280 // Callbacks - stored in interaction_context_ (single source of truth)
282 std::function<void(const zelda3::RoomObject&)> callback) {
283 object_placed_callback_ = std::move(callback);
284 }
285 void SetCacheInvalidationCallback(std::function<void()> callback) {
286 interaction_context_.on_invalidate_cache = std::move(callback);
288 }
289 void SetMutationCallback(std::function<void()> callback) {
290 interaction_context_.on_mutation = std::move(callback);
292 }
294 editor_system_ = system;
295 }
296
297 // Entity selection (doors, sprites, items)
298 void SelectEntity(EntityType type, size_t index);
306
307 // Draw entity selection highlights
309 void DrawDoorSnapIndicators(); // Show valid snap positions during door drag
310
311 // Callbacks for entity changes
312 void SetEntityChangedCallback(std::function<void()> callback) {
313 interaction_context_.on_entity_changed = std::move(callback);
315 }
317 std::function<void(int, std::optional<size_t>, int, int)> callback) {
318 interaction_context_.on_door_pair_navigation = std::move(callback);
320 }
321
322 private:
327
332
333 // Unified interaction context and coordinator for entity handling
336
337 // Unified mode state machine - replaces scattered boolean flags
339
340 // Helper to calculate object bounds
341 std::pair<int, int> CalculateObjectBounds(const zelda3::RoomObject& object);
342
343 // Refactored input handlers
344 void HandleLeftClick(const ImVec2& canvas_mouse_pos);
345 void UpdateCollisionPainting(const ImVec2& canvas_mouse_pos);
346 void UpdateWaterFillPainting(const ImVec2& canvas_mouse_pos);
347 void HandleObjectSelectionStart(const ImVec2& canvas_mouse_pos);
348 void HandleEmptySpaceClick(const ImVec2& canvas_mouse_pos);
349 void HandleMouseRelease();
350 bool HandleKeyboardNudge();
351
353 std::vector<zelda3::Sprite> sprites;
354 std::vector<zelda3::PotItem> items;
359
360 bool HasData() const { return !sprites.empty() || !items.empty(); }
361 void Clear() {
362 sprites.clear();
363 items.clear();
364 origin_pixel_x = 0;
365 origin_pixel_y = 0;
366 origin_tile_x = 0;
367 origin_tile_y = 0;
368 }
369 };
370
371 void CopySelectedEntitiesToClipboard(bool clipboard_origin_set);
372 std::vector<SelectedEntity> PasteEntityClipboardAt(int target_pixel_x,
373 int target_pixel_y);
374
375 // Preview object state (used by ModeState but kept here for ghost bitmap)
377
378 // Ghost preview bitmap (persists across frames for placement preview)
381
382 // Unified selection system - replaces legacy selection state
384
385 // Callbacks - stored only in interaction_context_ (no duplication)
386 std::function<void(const zelda3::RoomObject&)> object_placed_callback_;
387
388 // Entity selection state (doors, sprites, items)
389 // Note: entity selection is owned by InteractionCoordinator/handlers.
390};
391
392} // namespace editor
393} // namespace yaze
394
395#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)
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.
bool HasClipboardData() const
Check if clipboard has data.
void SetPreviewObject(const zelda3::RoomObject &object)
Set object for placement.
Modern, robust canvas for drawing and manipulating graphics.
Definition canvas.h:64
auto global_scale() const
Definition canvas.h:397
auto zero_point() const
Definition canvas.h:348
auto scrolling() const
Definition canvas.h:350
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< 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