orkmode/ui/qml
Levi Neely 1033820229 Add drag-and-drop structural moves with a live drop indicator
Drag a section by its ⠿ grip to restructure the outline. Vertical pointer
position chooses the insertion gap; horizontal position (indent) chooses
the depth. A live indicator shows the resolved target — an insertion bar
indented to the resolved level plus a ghost label ("L3 under \"B\"") —
computed by the same function that commits, so the preview is truthful.

Resolving the ambiguity (is this a new L2, an L3 sibling, or an L4
child?): at a gap between row A (level La, above) and row B (level Lb,
below), the legal depth range is [max(1, Lb), La + 1]. The pointer's
indent is clamped into that range; the parent is then computed by walking
A's ancestor chain to the row at level-1 (never guessed), and the
before-sibling is the first row after the gap at that level under that
parent. The dragged subtree is excluded, so it can't drop into itself.

Server (refile insert-before):
- refile_section gains a `before` parameter: insert the subtree
  immediately before that sibling instead of appending at the end of the
  parent. The ctl verb becomes
  `refile <doc> <id> <to-doc> [parent-id] [before-id]`, and a literal "-"
  in the parent slot means top level (so a before-id can be given while
  refiling to the top).

Model:
- moveSection/promoteSection/demoteSection/refileSection drive the move,
  promote, demote, and refile ctl verbs and reload on success.
- resolveDrop(draggedRow, gapAboveRow, desiredLevel) implements the
  clamp + ancestor-walk and returns {valid, level, parentId, parentTitle,
  beforeId}. sectionIdAt(row) exposes the row's id.

GUI:
- A drag grip per headline with a manual-drag MouseArea mapping the
  pointer to ListView content coords and calling resolveDrop live; the
  drop indicator overlay renders from the result; release commits via
  refileSection.

Verified: server tests (75 passed, +3: refile before-sibling same-doc,
before top-level, and the ctl "-" top-level placeholder). The drop
resolution was checked with a standalone harness over the ambiguous
C|E-gap cases (indent 1/2/3/4 → top-before-E / L2-under-A / L3-under-B /
L4-under-C, clamping, and self-drop exclusion). Live 9P confirmed
`refile d f d b c` (reparent + relevel + insert-before) and
`refile d f d - a` (promote to top, insert-before). GUI builds clean.
2026-10-02 16:00:54 +02:00
..
DatePickerDialog.qml Add in-place body editing with timestamp insertion 2026-10-02 15:18:08 +02:00
Main.qml Add an org path setting with a directory picker to Settings 2026-10-02 12:11:19 +02:00
OutlineView.qml Add drag-and-drop structural moves with a live drop indicator 2026-10-02 16:00:54 +02:00
SettingsDialog.qml Make the Settings dialog content scrollable 2026-10-02 12:14:12 +02:00