Skip to content

SceneOps: Slice F — Move entity to different scene node + improved node-reparent UX #629

Description

@fernandotonon

Parent epic: #623

Goal

The other half of the user's hierarchy request: move a whole mesh (entity) into a different scene node, and tighten the existing scene-node reparent (already present via SceneTreeModel::reparentNode) so users can actually find and use it.

Scope

Entity move

  • New helper SubMeshOps::moveEntityToNode(entity, targetNode, transformMode) -> bool where transformMode ∈ { keepWorld, keepLocal }.
  • Same convention as the bone-reparent in Slice B of Epic: Skel — Skeletal rigging & control #554:
    • Keep world (default): recomputes the entity's scene node's local TRS so the world transform is preserved.
    • Keep local: TRS unchanged; the entity visibly jumps to the new parent's space.
  • Multi-select: dragging multiple entities to a new parent preserves each one's world transform individually.
  • Undo: MoveEntityCommand stores the original parent + local TRS.

Node reparent UX polish

  • SceneTreeModel::reparentNode is already implemented but invisible to most users. Surface it:
    • Drag-and-drop a scene node onto another node in qml/SceneTreeNode.qml triggers reparent (with the same keep-world / keep-local picker on first use; remembered as a session default).
    • Right-click context menu: "Set parent…" picker dialog as a fallback.
    • Drag onto empty space (or onto the "Scene Root" entry at the top) detaches the node to root.
  • Validation feedback: the existing canReparent is used to highlight valid drop targets in green / invalid in red during drag, with a tooltip explaining "circular parent rejected" / "already a child" cases.
  • Group affordance: if multiple nodes are selected and the user picks "Group selected" from the context menu, route through the existing Manager::groupNodes so the new affordance shares the proven group-node path.
  • Ungroup affordance: right-click on a group node → "Ungroup" via existing Manager::ungroupNode.
  • Visual indicator for group nodes vs regular nodes in the tree (small icon distinguishing them).

Combined

  • Drag protocol: the scene tree learns a tiny drop-target taxonomy:
    • SubEntity dragged onto Entity → move submesh (Slice B).
    • Entity dragged onto SceneNode → move entity (this slice).
    • SceneNode dragged onto SceneNode → reparent (this slice).
    • Multiple SceneNodes dragged onto empty space → group (this slice via Manager::groupNodes).
    • The drop handler dispatches by source/target type.

Acceptance Criteria

  • Dragging an entity onto a different scene node moves it, with keep-world preserving the visual position.
  • Keep-local toggles the entity's apparent position correctly.
  • Multi-entity reparent preserves each entity's world transform.
  • Dragging a scene node onto another reparents via SceneTreeModel::reparentNode, with canReparent validation surfaced as drop-target highlight + tooltip.
  • Drop on root (empty space or "Scene Root" entry) detaches.
  • Group / Ungroup affordances surface in the right-click menu and route through Manager::groupNodes/ungroupNode.
  • Drop taxonomy correctly dispatches SubEntity / Entity / SceneNode drops.
  • Undo works for entity-move; existing undo for node reparent is verified.
  • Project save / load round-trips the new hierarchy.
  • Sentry breadcrumbs scene.tree.entity_move, scene.tree.node_reparent, scene.tree.group, scene.tree.ungroup.
  • Headless-CI test: entity move (keep-world + keep-local), node reparent, group of 3 nodes.

Effort

~5 days.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestscene-treeScene tree, submeshes, hierarchy operationsui

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions