diff options
| author | user <user@clank> | 2026-08-14 14:53:34 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-14 14:53:34 +0200 |
| commit | 7f9e2a5eb2607667eb46811b2f22aba8dff09834 (patch) | |
| tree | d300225f31a8485e2119478aaf23e991a748ad1f /tests | |
| parent | sl0ppty: a floor under splitting, and an arrow saying which way (diff) | |
| download | slosh-7f9e2a5eb2607667eb46811b2f22aba8dff09834.tar.gz slosh-7f9e2a5eb2607667eb46811b2f22aba8dff09834.tar.xz slosh-7f9e2a5eb2607667eb46811b2f22aba8dff09834.zip | |
sl0ppty: the resize gap says it is a handle
The gap between two panes has always been draggable and has always looked
exactly like nothing. Resting on one now marks it dotted, and the mark doubles
and goes bold once you actually have hold of it — because "you could move
this" and "you are moving this" are different claims, and the second should
not have to be inferred from the panes changing size underneath you.
Dotted for a possibility, weight for a commitment: the same grammar the split
guide already uses, so there is one visual language to learn rather than two.
Vertical boundaries get vertical marks and horizontal ones horizontal, along
the axis the boundary actually runs.
It arms on dwell like the split guide, because crossing a gap on the way to
the pane on the other side is the most ordinary mouse movement there is, and a
pointer already carrying a pane is not shopping for a boundary — a title drag
passing over a gap arms nothing.
The hint is tested against the very rect registered as that gap's hit, in the
same loop iteration that registers it, so it cannot appear anywhere the click
would not land without having to trust a lookup to agree.
One thing that would have made this silently useless: app_next_timeout only
scheduled a repaint for hovers over `border:` and `title:`, so a hint that
arms on dwell over `edge:` would only have appeared when some unrelated event
happened to repaint the frame — visible when the session was busy and not when
it was idle, which is the worst way for it to be wrong. Everything that arms
on dwell has to be listed there, and now is.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_drag.py | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/tests/test_drag.py b/tests/test_drag.py index b392f3c..36fa83d 100644 --- a/tests/test_drag.py +++ b/tests/test_drag.py @@ -6,6 +6,7 @@ split is equal weights, and every layout pass is still the same pure function of the tree and the rect. """ import sys +import time from harness import Session, check, report @@ -212,6 +213,104 @@ def test_drop_target_is_visible(): s.send(rf"\e[<0;{right['x'] + 5};{right['y'] + 3}m") +# ---- the resize zone announces itself -------------------------------------- + +GRIP_V, GRAB_V = "\u250a", "\u2551" # dotted / doubled, vertical boundary +GRIP_H, GRAB_H = "\u2508", "\u2550" # dotted / doubled, horizontal boundary + + +def test_the_gap_says_it_is_a_handle(): + with Session(SH, cols=120, rows=26) as s: + s.settle() + s.key("\\\\") + s.settle(200) + left, right = s.panes() + gx, gy = left["x"] + left["w"], left["y"] + 3 + + check("an idle gap is blank", GRIP_V not in s.snapshot().screen(), "") + + # Crossing a gap on the way somewhere is the most ordinary mouse + # movement there is, so contact alone must not arm it. + s.send(rf"\e[<35;{gx + 1};{gy + 1}M") + s.settle(60) + check("contact alone does not arm it", + GRIP_V not in s.snapshot().screen(), "") + + time.sleep(0.35) + s.settle(60) + snap = s.snapshot() + check("resting on it says it can be moved", GRIP_V in snap.screen(), "") + check("and does not yet claim it is being moved", + GRAB_V not in snap.screen(), "") + + pos = snap.find(GRIP_V) + check("the hint is in the gap, not in either pane", + pos and left["x"] + left["w"] <= pos[0] < right["x"], str(pos)) + + +def test_the_hint_changes_while_resizing(): + with Session(SH, cols=120, rows=26) as s: + s.settle() + s.key("\\\\") + s.settle(200) + left, right = s.panes() + gx, gy = left["x"] + left["w"], left["y"] + 3 + before = left["w"] + + s.send(rf"\e[<0;{gx + 1};{gy + 1}M") + s.send(rf"\e[<32;{gx + 6};{gy + 1}M") + s.settle(80) + snap = s.snapshot() + check("a resize in progress reads differently from a hover", + GRAB_V in snap.screen() and GRIP_V not in snap.screen(), "") + + s.send(rf"\e[<0;{gx + 6};{gy + 1}m") + s.settle(150) + snap = s.snapshot() + check("and the boundary actually moved", + s.panes()[0]["w"] > before, f'{before} -> {s.panes()[0]["w"]}') + check("both hints are gone once it is dropped", + GRAB_V not in snap.screen() and GRIP_V not in snap.screen(), "") + + +def test_a_horizontal_boundary_uses_horizontal_marks(): + with Session(SH, cols=120, rows=26) as s: + s.settle() + s.key("-") # split into rows + s.settle(200) + top, bottom = s.panes() + gx, gy = top["x"] + 6, top["y"] + top["h"] + + s.send(rf"\e[<35;{gx + 1};{gy + 1}M") + time.sleep(0.35) + s.settle(60) + snap = s.snapshot() + check("a row boundary hints along its own axis", + GRIP_H in snap.screen() and GRIP_V not in snap.screen(), "") + pos = snap.find(GRIP_H) + check("in the gap between the two rows", + pos and top["y"] + top["h"] <= pos[1] < bottom["y"], str(pos)) + + +def test_no_resize_hint_during_another_drag(): + """A pointer already carrying a pane is not shopping for a boundary.""" + with Session(SH, cols=120, rows=26) as s: + s.settle() + s.key("\\\\") + s.settle(200) + left, right = s.panes() + gx, gy = left["x"] + left["w"], left["y"] + 3 + + s.send(rf"\e[<0;{left['x'] + 5};{left['y'] + 1}M") # grab the title + s.send(rf"\e[<32;{gx + 1};{gy + 1}M") # drag over the gap + time.sleep(0.35) + s.settle(80) + check("a title drag over a gap arms nothing", + GRIP_V not in s.snapshot().screen(), "") + s.send(rf"\e[<0;{gx + 1};{gy + 1}m") + s.settle(80) + + if __name__ == "__main__": test_keyboard_resize() test_vertical_resize() @@ -220,4 +319,8 @@ if __name__ == "__main__": test_title_drag_reorders() test_drag_edge_cases() test_drop_target_is_visible() + test_the_gap_says_it_is_a_handle() + test_the_hint_changes_while_resizing() + test_a_horizontal_boundary_uses_horizontal_marks() + test_no_resize_hint_during_another_drag() sys.exit(report()) |
