Function re_viewer::external::re_ui::drag_and_drop::find_drop_target
source · pub fn find_drop_target<ItemId>(
ui: &Ui,
item_context: &ItemContext<ItemId>,
item_rect: Rect,
body_rect: Option<Rect>,
item_height: f32
) -> Option<DropTarget<ItemId>>where
ItemId: Copy,
Expand description
Compute the geometry of the drag cursor and where the dragged item should be inserted.
This function performs the following tasks:
- based on
item_rect
andbody_rect
, establish the geometry of actual drop zones (see below) - test the mouse cursor against these zones
- if one is a match:
- compute the geometry of a drop insertion indicator
- use the context provided in
item_context
to return the “logical” drop target (ie. the target container and position within it)
This function implements the following logic:
insert insert last in container before me
before me (if any) or insert before me
│ │
╔═══▼═════════════════════════════▼══════════════════╗
║ │ ║
leaf item ║ ─────┴──────────────────────────────────────────── ║
║ ║
╚═════════════════════▲══════════════════════════════╝
│
insert after me
insert insert last in container before me
before me (if any) or insert before me
│ │
╔═══▼═════════════════════════════▼══════════════════╗
leaf item ║ │ ║
with body ║ ─────┴──────────────────────────────────────────── ║
║ ║
╚══════╦══════════════════════════════════════▲══════╣ ─┐
│ ║ │ ║ │
│ ║ insert ║ │
│ ║ after me ║ │
│ ╠══ ══╣ │
│ ║ no insertion possible ║ │
│ ║ here by definition of ║ │ body
│ ║ parent being a leaf ║ │
│ ╠══ ══╣ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
└──▲── ╚══════════════════════════▲══════════════════╝ ─┘
│ │
insert insert
after me after me
insert insert last in container before me
before me (if any) or insert before me
│ │
╔═══▼═════════════════════════════▼══════════════════╗
container item ║ │ ║
(empty/collapsed ║ ─────┼──────────────────────────────────────────── ║
body) ║ │ ║
╚═══▲═════════════════════════════▲══════════════════╝
│ │
insert insert inside me
after me at pos = 0
insert insert last in container before me
before me (if any) or insert before me
│ │
╔═══▼═════════════════════════════▼══════════════════╗
container item ║ │ ║
with body ║ ─────┴──────────────────────────────────────────── ║
║ ║
╚═▲════╦═════════════════════════════════════════════╣ ─┐
│ ║ ║ │
insert ║ ║ │
inside me ║ ║ │
at pos = 0 ╠══ ══╣ │
║ same logic ║ │
║ recursively ║ │ body
insert ║ applied here ║ │
after me ╠══ ══╣ │
│ ║ ║ │
┌─▼─── ║ ║ │
│ ║ ║ │
└───── ╚═════════════════════════════════════════════╝ ─┘
not a valid drop zone
│
╔═════════════════════════════════▼══════════════════╗
root container ║ ║
item ║ ────────────────────────────────────────────────── ║
║ ║
╚════════════════════════▲═══════════════════════════╝
│
insert inside me
at pos = 0
Here are a few observations of the above that help navigate the “if-statement-of-death” in the implementation:
- The top parts of the item are treated the same in most cases (root container is an exception).
- Handling of the body can be simplified by making the sensitive area either a small corner (container case), or the entire body (leaf case). Then, that area always maps to “insert after me”.
- The bottom parts have the most difference between cases and need case-by-case handling. In both leaf item cases, the entire bottom part maps to “insert after me”, though.
Note: in debug builds, press Alt
to visualize the drag zones while dragging.