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.
92
93 // Legacy setter - kept for backwards compatibility
98
99 // Main interaction handling
102 void PlaceObjectAtPosition(int room_x, int room_y);
103
104 void DrawSelectionHighlights(); // Draw highlights for selected objects
106 const std::vector<zelda3::RoomObject>& objects); // Draw hover indicator
107
108 // Drag and select box functionality
109 void DrawGhostPreview(); // Draw ghost preview for object placement
110
111 // Coordinate conversion
112 std::pair<int, int> RoomToCanvasCoordinates(int room_x, int room_y) const;
113 std::pair<int, int> CanvasToRoomCoordinates(int canvas_x, int canvas_y) const;
114 bool IsWithinCanvasBounds(int canvas_x, int canvas_y, int margin = 32) const;
115
116 // State management
117 void SetCurrentRoom(DungeonRoomStore* rooms, int room_id);
118 void SetPreviewObject(const zelda3::RoomObject& object, bool loaded);
127 const auto& handler = entity_coordinator_.tile_handler();
128 return handler.IsPlacementActive() ? &handler.GetPreviewObject() : nullptr;
129 }
130 bool SetPlacementPreviewSize(uint8_t size) {
132 }
133 bool SetPlacementPreviewLayer(int layer) {
135 }
138 bool force_refresh = false) {
139 bool palette_changed = current_palette_group_.name() != group.name() ||
140 current_palette_group_.size() != group.size();
141 for (int i = 0; !palette_changed && i < static_cast<int>(group.size());
142 ++i) {
143 palette_changed =
145 }
146 if (!palette_changed && !force_refresh) {
147 return;
148 }
149
154 }
155
156 // Mode manager access
159
160 // Mode queries - delegate to mode manager
164
165 void CancelPlacement();
166 // Finish the active drag or paint stroke before a discrete editor command.
167 void HandleMouseRelease();
168
169 // Door placement mode
187
188 // Sprite placement mode
189 void SetSpritePlacementMode(bool enabled, uint8_t sprite_id = 0);
196 uint8_t GetPreviewSpriteId() const {
197 return mode_manager_.GetModeState().preview_sprite_id.value_or(0);
198 }
204
205 // Item placement mode
206 void SetItemPlacementMode(bool enabled, uint8_t item_id = 0);
210 void SetPreviewItemId(uint8_t id) {
212 }
213 uint8_t GetPreviewItemId() const {
214 return mode_manager_.GetModeState().preview_item_id.value_or(0);
215 }
221
222 // Selection state - delegates to ObjectSelection
223 std::vector<size_t> GetSelectedObjectIndices() const {
225 }
226 void SetSelectedObjects(const std::vector<size_t>& indices) {
229 for (size_t idx : indices) {
231 }
232 }
236 void ClearSelection();
237 bool IsObjectSelected(size_t index) const {
238 return selection_.IsObjectSelected(index);
239 }
240 size_t GetSelectionCount() const { return selection_.GetSelectionCount(); }
241
242 // Selection change notification
243 void SetSelectionChangeCallback(std::function<void()> callback) {
244 selection_.SetSelectionChangedCallback(std::move(callback));
245 }
251
252 // Helper for click selection with proper mode handling
253
254 // Object manipulation
255 void HandleScrollWheelResize(); // Resize selected objects with scroll wheel
256
257 // Move the current canvas selection by one editor nudge step. Tile objects
258 // move by room-tile units; doors, sprites, and items use their native grids.
259 // Mixed selections move together so keyboard nudging follows the same grammar
260 // as marquee and additive selection.
261 bool NudgeSelected(int delta_x, int delta_y);
262 absl::Status HandleDeleteSelected();
264 absl::Status HandleCopySelected();
265 absl::Status HandlePasteObjects();
266 absl::Status HandleDuplicateSelected();
267 absl::Status HandlePasteAt(int pixel_x, int pixel_y);
268 const absl::Status& selection_edit_status() const {
270 }
274 bool HasClipboardData() const { return !clipboard().empty(); }
275
276 // Inspector-friendly mutation helpers (with undo + rerender integration).
277 // These are intended for UI panels that want to edit a single object without
278 // duplicating mutation/invalidation boilerplate.
279 bool SetObjectId(size_t index, int16_t id);
280 bool SetObjectSize(size_t index, uint8_t size);
281 bool SetObjectLayer(size_t index, zelda3::RoomObject::LayerType layer);
282
283 // Stored placement assignment for selected objects. Stream 2 is available
284 // only when every selected object belongs to the room object stream; torches
285 // and pushable blocks use a two-value special-table draw selector instead.
286 bool CanAssignSelectedObjectsToLayer(int target_layer) const;
287 bool SendSelectedToLayer(int target_layer);
288
289 // Object ordering (changes draw order within the layer)
290 // SNES draws objects in list order - first objects appear behind, last on top
291 void
292 SendSelectedToFront(); // Move to end of list (drawn last, appears on top)
293 void
294 SendSelectedToBack(); // Move to start of list (drawn first, appears behind)
295 void BringSelectedForward(); // Move up one position in list
296 void SendSelectedBackward(); // Move down one position in list
297
298 // Layer filter access (delegates to ObjectSelection)
299 void SetLayerFilter(int layer) { selection_.SetLayerFilter(layer); }
300 int GetLayerFilter() const { return selection_.GetLayerFilter(); }
303 const char* GetLayerFilterName() const {
305 }
306 void SetLayersMerged(bool merged) { selection_.SetLayersMerged(merged); }
307 bool AreLayersMerged() const { return selection_.AreLayersMerged(); }
308
309 // Check keyboard shortcuts for layer operations
311
312 // Callbacks - stored in interaction_context_ (single source of truth)
314 std::function<void(const zelda3::RoomObject&)> callback) {
315 object_placed_callback_ = std::move(callback);
316 }
317 void SetCacheInvalidationCallback(std::function<void()> callback) {
318 interaction_context_.on_invalidate_cache = std::move(callback);
320 }
321 void SetMutationCallback(std::function<void()> callback) {
322 interaction_context_.on_mutation = std::move(callback);
324 }
326 std::function<absl::Status(const DungeonSelectionEditPlan&, bool)> edit,
327 std::function<void()> finish,
328 std::function<void(const absl::Status&)> error = {}) {
329 interaction_context_.on_selection_edit = std::move(edit);
332 }
337 editor_system_ = system;
338 }
339
340 // Entity selection (doors, sprites, items)
341 void SelectEntity(EntityType type, size_t index);
349
350 // Draw entity selection highlights
352 void DrawDoorSnapIndicators(); // Show valid snap positions during door drag
353
354 // Callbacks for entity changes
355 void SetEntityChangedCallback(std::function<void()> callback) {
356 interaction_context_.on_entity_changed = std::move(callback);
358 }
360 std::function<void(int, std::optional<size_t>, int, int)> callback) {
361 interaction_context_.on_door_pair_navigation = std::move(callback);
363 }
364
365 private:
371
376
377 // Unified interaction context and coordinator for entity handling
380
381 // Unified mode state machine - replaces scattered boolean flags
383
384 // Helper to calculate object bounds
385 std::pair<int, int> CalculateObjectBounds(const zelda3::RoomObject& object);
386
387 // Refactored input handlers
388 void HandleLeftClick(const ImVec2& canvas_mouse_pos);
389 void UpdateCollisionPainting(const ImVec2& canvas_mouse_pos);
390 void UpdateWaterFillPainting(const ImVec2& canvas_mouse_pos);
391 void HandleObjectSelectionStart(const ImVec2& canvas_mouse_pos);
392 void HandleEmptySpaceClick(const ImVec2& canvas_mouse_pos);
393 void FinishPaintStroke();
394 bool HandleKeyboardNudge();
395
396 // Ghost preview bitmap (persists across frames for placement preview)
406 // Direct viewer use retains a local clipboard; editor-owned viewers bind the
407 // session clipboard so separate room panels can reuse one selection.
410
411 // Unified selection system - replaces legacy selection state
413
414 // Callbacks - stored only in interaction_context_ (no duplication)
415 std::function<void(const zelda3::RoomObject&)> object_placed_callback_;
416
417 // Entity selection state (doors, sprites, items)
418 // Note: entity selection is owned by InteractionCoordinator/handlers.
419};
420
421} // namespace editor
422} // namespace yaze
423
424#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:49
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)
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 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)
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)
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