Drag & Drop
There are two kinds of drag: a pointer drag inside the window (reordering a list, moving tabs, docking panes), and files or text dropped in from another application. The hooks only report what happened. Applying a drop to your data is up to you.
Reordering a list
useReorder takes the current order of item ids and each item’s response, in drawn order:
chips :: Var [Int] -> NanoUI ()
chips orderVar = rowWith (gap 6) $ do
order <- readVar orderVar -- orderVar <- newVar [0 .. 4] in setup
drawn <- forM order $ \i -> (i,) <$> chip i
r <- useReorder order drawn
writeVar orderVar (reorderOrder r)
reorderOrder changes on the frame the item is dropped. Draw from reorderPreview instead to move the other items aside during the drag. reorderDragging is the held item, and reorderMoved is set once the press has moved past the drag threshold, so a click can be ignored.
Gestures with useDrag
For anything else, useDrag tracks a thresholded drag across keyed sources. Allocate the handle once with newDrag in setup. Here it reorders tabs, with insertionIndex turning the pointer into a slot in the strip (Nothing outside it):
tabStrip :: DragHandle Text -> Var Text -> [Tab Text ()] -> NanoUI ()
tabStrip dragHandle active documents = do
headers <- tabBar' active documents
gesture <- useDrag dragHandle (tabHeaders headers)
for_ gesture $ \d -> when (dragPhase d == DragReleased) $ do
let rest = filter ((/= dragPayload d) . fst) (tabHeaders headers)
for_ (insertionIndex DragAxisX (tabStripRect headers) (map (respRect . snd) rest) (dragAt d)) $
moveTab (dragPayload d)
dragPhase is DragStarted, Dragging, DragReleased, or DragCancelled (Escape, a lost hold, or the source disappearing). The last two last one frame. Commit only on DragReleased.
Files and text from other applications
The SDL backend delivers the operating system’s drag and drop; the RGFW backend does not. dropZone draws a panel and reports the files and text dropped on it:
fileDrop :: NanoUI ()
fileDrop = do
(_, _, target) <- dropZone (fillW . padAll 12) (label "Drop files here")
when (dropReceived target) (mapM_ openFile (dropFiles target))
dropHovered is true while a drag is over the zone. useDrop rect does the same for any rectangle. Only the topmost layer receives the drop, so a zone behind a modal gets nothing.
Pane grids
paneGrid lays out dockable, splittable panes. Its response’s pgrDropTarget is the destination under the pointer, which pairs with a useDrag gesture:
dockPanes :: PaneGridConfig -> Maybe (Drag Word64) -> NanoUI ()
dockPanes cfg gesture = do
panes <- paneGrid cfg
case (gesture, pgrDropTarget panes) of
(Just d, Just target) | dragPhase d == DragReleased -> void (commitPaneDrop target)
_ -> pure ()
pgdLocation is BesidePane paneId edge or OutsideGrid edge; pgdRect and pgdPane help validate the drop. Save pgrTree when pgrCommitted is set.