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
22#include "imgui/imgui.h"
27#include "zelda3/dungeon/room.h"
30
31#include "rom/rom.h"
32
33namespace yaze {
34namespace editor {
35
45 public:
56
57 // ========================================================================
58 // Context and Configuration
59 // ========================================================================
60
73
83
84 // Last mutation/invalidation domain (best-effort). Used by editors to route
85 // undo capture and avoid expensive rerenders for overlay-only edits.
101 const std::vector<zelda3::CustomCollisionRoomEntry>& entries) {
105 }
106 return absl::UnimplementedError("No collision batch import callback");
107 }
109 return static_cast<bool>(interaction_context_.on_collision_batch_import);
110 }
112 std::function<
113 absl::Status(const std::vector<zelda3::CustomCollisionRoomEntry>&)>
114 callback) {
117 }
118
119 // Legacy setter - kept for backwards compatibility
124
125 // Main interaction handling
128 void PlaceObjectAtPosition(int room_x, int room_y);
129
130 void DrawSelectionHighlights(); // Draw highlights for selected objects
132 const std::vector<zelda3::RoomObject>& objects); // Draw hover indicator
133
134 // Drag and select box functionality
135 void DrawGhostPreview(); // Draw ghost preview for object placement
136
137 // Coordinate conversion
138 std::pair<int, int> RoomToCanvasCoordinates(int room_x, int room_y) const;
139 std::pair<int, int> CanvasToRoomCoordinates(int canvas_x, int canvas_y) const;
140 bool IsWithinCanvasBounds(int canvas_x, int canvas_y, int margin = 32) const;
141
142 // State management
143 void SetCurrentRoom(DungeonRoomStore* rooms, int room_id);
144 void SetPreviewObject(const zelda3::RoomObject& object, bool loaded);
153 const auto& handler = entity_coordinator_.tile_handler();
154 return handler.IsPlacementActive() ? &handler.GetPreviewObject() : nullptr;
155 }
156 bool SetPlacementPreviewSize(uint8_t size) {
158 }
159 bool SetPlacementPreviewLayer(int layer) {
161 }
164 bool force_refresh = false) {
165 bool palette_changed = current_palette_group_.name() != group.name() ||
166 current_palette_group_.size() != group.size();
167 for (int i = 0; !palette_changed && i < static_cast<int>(group.size());
168 ++i) {
169 palette_changed =
171 }
172 if (!palette_changed && !force_refresh) {
173 return;
174 }
175
180 }
181
182 // Mode manager access
185
186 // Mode queries - delegate to mode manager
190
191 void CancelPlacement();
192 // Finish the active drag or paint stroke before a discrete editor command.
193 void HandleMouseRelease();
194
195 // Door placement mode
213
214 // Sprite placement mode
215 void SetSpritePlacementMode(bool enabled, uint8_t sprite_id = 0);
222 uint8_t GetPreviewSpriteId() const {
223 return mode_manager_.GetModeState().preview_sprite_id.value_or(0);
224 }
230
231 // Item placement mode
232 void SetItemPlacementMode(bool enabled, uint8_t item_id = 0);
236 void SetPreviewItemId(uint8_t id) {
238 }
239 uint8_t GetPreviewItemId() const {
240 return mode_manager_.GetModeState().preview_item_id.value_or(0);
241 }
247
248 // Selection state - delegates to ObjectSelection
249 std::vector<size_t> GetSelectedObjectIndices() const {
251 }
252 void SetSelectedObjects(const std::vector<size_t>& indices) {
255 for (size_t idx : indices) {
257 }
258 }
262 void ClearSelection();
263 bool IsObjectSelected(size_t index) const {
264 return selection_.IsObjectSelected(index);
265 }
266 size_t GetSelectionCount() const { return selection_.GetSelectionCount(); }
267
268 // Selection change notification
269 void SetSelectionChangeCallback(std::function<void()> callback) {
270 selection_.SetSelectionChangedCallback(std::move(callback));
271 }
277
278 // Helper for click selection with proper mode handling
279
280 // Object manipulation
281 void HandleScrollWheelResize(); // Resize selected objects with scroll wheel
282
283 // Move the current canvas selection by one editor nudge step. Tile objects
284 // move by room-tile units; doors, sprites, and items use their native grids.
285 // Mixed selections move together so keyboard nudging follows the same grammar
286 // as marquee and additive selection.
287 bool NudgeSelected(int delta_x, int delta_y);
288 absl::Status HandleDeleteSelected();
290 absl::Status HandleCopySelected();
291 absl::Status HandlePasteObjects();
292 // Snap a pointer anchor while preserving the copied group's encoding grids.
293 absl::Status HandlePasteObjectsAt(int pixel_x, int pixel_y);
294 absl::Status HandleDuplicateSelected();
295 absl::Status HandlePasteAt(int pixel_x, int pixel_y);
296 const absl::Status& selection_edit_status() const {
298 }
302 bool HasClipboardData() const { return !clipboard().empty(); }
303
304 // Inspector-friendly mutation helpers (with undo + rerender integration).
305 // These are intended for UI panels that want to edit a single object without
306 // duplicating mutation/invalidation boilerplate.
307 bool SetObjectId(size_t index, int16_t id);
308 bool SetObjectSize(size_t index, uint8_t size);
309 bool SetObjectLayer(size_t index, zelda3::RoomObject::LayerType layer);
310
311 // Stored placement assignment for selected objects. Stream 2 is available
312 // only when every selected object belongs to the room object stream; torches
313 // and pushable blocks use a two-value special-table draw selector instead.
314 bool CanAssignSelectedObjectsToLayer(int target_layer) const;
315 bool SendSelectedToLayer(int target_layer);
316
317 // Object ordering (changes draw order within the layer)
318 // SNES draws objects in list order - first objects appear behind, last on top
319 void
320 SendSelectedToFront(); // Move to end of list (drawn last, appears on top)
321 void
322 SendSelectedToBack(); // Move to start of list (drawn first, appears behind)
323 void BringSelectedForward(); // Move up one position in list
324 void SendSelectedBackward(); // Move down one position in list
325
326 // Layer filter access (delegates to ObjectSelection)
327 void SetLayerFilter(int layer) { selection_.SetLayerFilter(layer); }
328 int GetLayerFilter() const { return selection_.GetLayerFilter(); }
331 const char* GetLayerFilterName() const {
333 }
334 void SetLayersMerged(bool merged) { selection_.SetLayersMerged(merged); }
335 bool AreLayersMerged() const { return selection_.AreLayersMerged(); }
336
337 // Check keyboard shortcuts for layer operations
339
340 // Callbacks - stored in interaction_context_ (single source of truth)
342 std::function<void(const zelda3::RoomObject&)> callback) {
343 object_placed_callback_ = std::move(callback);
344 }
345 void SetCacheInvalidationCallback(std::function<void()> callback) {
346 interaction_context_.on_invalidate_cache = std::move(callback);
348 }
349 void SetMutationCallback(std::function<void()> callback) {
350 interaction_context_.on_mutation = std::move(callback);
352 }
354 std::function<absl::Status(const DungeonSelectionEditPlan&, bool)> edit,
355 std::function<void()> finish,
356 std::function<void(const absl::Status&)> error = {}) {
357 interaction_context_.on_selection_edit = std::move(edit);
360 }
365 editor_system_ = system;
366 }
367
368 // Entity selection (doors, sprites, items)
369 void SelectEntity(EntityType type, size_t index);
377
378 // Draw entity selection highlights
380 void DrawDoorSnapIndicators(); // Show valid snap positions during door drag
381
382 // Callbacks for entity changes
383 void SetEntityChangedCallback(std::function<void()> callback) {
384 interaction_context_.on_entity_changed = std::move(callback);
386 }
388 std::function<void(int, std::optional<size_t>, int, int)> callback) {
389 interaction_context_.on_door_pair_navigation = std::move(callback);
391 }
392
393 private:
399
404
405 // Unified interaction context and coordinator for entity handling
408
409 // Unified mode state machine - replaces scattered boolean flags
411
412 // Helper to calculate object bounds
413 std::pair<int, int> CalculateObjectBounds(const zelda3::RoomObject& object);
414
415 // Refactored input handlers
416 void HandleLeftClick(const ImVec2& canvas_mouse_pos);
417 void UpdateCollisionPainting(const ImVec2& canvas_mouse_pos);
418 void UpdateWaterFillPainting(const ImVec2& canvas_mouse_pos);
419 void HandleObjectSelectionStart(const ImVec2& canvas_mouse_pos);
420 void HandleEmptySpaceClick(const ImVec2& canvas_mouse_pos);
421 void FinishPaintStroke();
422 bool HandleKeyboardNudge();
423
424 // Ghost preview bitmap (persists across frames for placement preview)
434 // Direct viewer use retains a local clipboard; editor-owned viewers bind the
435 // session clipboard so separate room panels can reuse one selection.
438
439 // Unified selection system - replaces legacy selection state
441
442 // Callbacks - stored only in interaction_context_ (no duplication)
443 std::function<void(const zelda3::RoomObject&)> object_placed_callback_;
444
445 // Entity selection state (doors, sprites, items)
446 // Note: entity selection is owned by InteractionCoordinator/handlers.
447};
448
449} // namespace editor
450} // namespace yaze
451
452#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:52
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
const zelda3::RoomObject * GetPlacementPreview() const
DungeonSelectionClipboard * shared_selection_clipboard_
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)
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 SetSelectionEditCallbacks(std::function< absl::Status(const DungeonSelectionEditPlan &, bool)> edit, std::function< void()> finish, std::function< void(const absl::Status &)> error={})
absl::Status HandlePasteAt(int pixel_x, int pixel_y)
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)
absl::Status ApplyCustomCollisionImportBatch(const std::vector< zelda3::CustomCollisionRoomEntry > &entries)
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)
const DungeonSelectionClipboard & clipboard() const
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 SetCollisionBatchImportCallback(std::function< absl::Status(const std::vector< zelda3::CustomCollisionRoomEntry > &)> callback)
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group, bool force_refresh=false)
void SelectEntity(EntityType type, size_t index)
const InteractionCoordinator & entity_coordinator() const
void CompleteObjectPlacement(const zelda3::RoomObject &object)
void SetDoorPlacementMode(bool enabled, zelda3::DoorType type=zelda3::DoorType::NormalDoor)
void SetSharedSelectionClipboard(DungeonSelectionClipboard *clipboard)
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)
absl::Status HandlePasteObjectsAt(int pixel_x, int pixel_y)
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.
const absl::Status & selection_edit_status() const
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 SetPlacementCallback(std::function< void(const zelda3::RoomObject &)> callback)
void RefreshPreviewGraphics()
Refresh graphics without replacing the current placement geometry.
PlacementPolicy GetPlacementPolicy() const
bool IsPlacementActive() const override
Check if placement mode is active.
void SetPlacementPolicy(PlacementPolicy policy)
Modern, robust canvas for drawing and manipulating graphics.
Definition canvas.h:64
auto global_scale() const
Definition canvas.h:413
auto zero_point() const
Definition canvas.h:364
auto scrolling() const
Definition canvas.h:366
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(const absl::Status &) on_selection_edit_error)
void NotifyInvalidateCache(MutationDomain domain=MutationDomain::kUnknown) const
Notify that cache invalidation is needed.
std::function< absl::Status(const std::vector< zelda3::CustomCollisionRoomEntry > &) on_collision_batch_import)
void NotifyMutation(MutationDomain domain=MutationDomain::kUnknown) const
Notify that a mutation is about to happen.
std::function< void()> on_selection_edit_finished
std::function< absl::Status(const DungeonSelectionEditPlan &, bool continuous) on_selection_edit)
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