Arrange tool, and a hold that is easier to find

An Arrange tool marks the corners of every image, Hide and own text
rectangle in blue and moves or resizes them by a plain drag, a press
elsewhere doing nothing.  The hold that does the same with any tool is
shorter (450 ms), with more slack, and shows all four corners.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ackandClaude Fable 5.1 committed 2026-10-14 00:01:45 +02:00
1 parent 94a3c1ba0e
commit 8ecf3e94a6
6 files changed
+260 -25

No files matched your search

+23 -6
View File
@@ -45,7 +45,7 @@ const focusSettleOn = !new URLSearchParams(location.search).has('no_focus_settle
* @typedef {object} PenTarget
* @property {(clientX: number, clientY: number) => [number, number]} toPage
* Convert a window position to page units.
* @property {() => 'pen' | 'eraser' | 'text' | 'hide'} tool The tool selected in the toolbar.
* @property {() => 'pen' | 'eraser' | 'text' | 'hide' | 'arrange'} tool The tool selected in the toolbar.
* @property {() => boolean} canWrite False while there is no page to write on.
* @property {() => void} beginStroke
* @property {(points: number[]) => void} addPoints
@@ -85,12 +85,14 @@ const ZOOM_DEAD_ZONE = 4;
/**
* A press that rests this long becomes a hold, which moves or scales the
* image under it (Andy's teacher, 2026-10-08; 600 ms so that a careful
* start of a stroke is not one). Moving farther than HOLD_SLACK_PX
* before then makes it a stroke after all.
* image, text block or Hide under it (Andy, 2026-10-08; 600 ms until
* 2026-10-13, when the hold was made easier to find: shorter, and with
* more slack for a pen held in the air). Longer than a tap, shorter than
* a pause in writing (the start of a stroke is not one). Moving farther
* than HOLD_SLACK_PX before that is a stroke, or erasing, as before.
*/
export const HOLD_MS = 600;
export const HOLD_SLACK_PX = 6;
export const HOLD_MS = 450;
export const HOLD_SLACK_PX = 10;
/**
* What the input device is delivering, for judging pen support.
@@ -121,6 +123,8 @@ export function attachPenInput(surface, target) {
/** @type {ReturnType<typeof setTimeout> | null} */
let holdTimer = null;
let holding = false;
/** With the Arrange tool: the press took hold at once, or found nothing and does nothing. */
let arranging = false;
let pressX = 0;
let pressY = 0;
/** @type {PointerEvent | null} The eraser's press, not yet erased with. */
@@ -246,6 +250,15 @@ export function attachPenInput(surface, target) {
erasedTexts = 0;
holding = false;
eraseWaiting = null;
// The Arrange tool holds at once: a press on an image, a text block
// or a Hide moves it, on a corner resizes it, and a press elsewhere
// does nothing (Andy, 2026-10-13).
if (tool === 'arrange' && !erasing) {
arranging = true;
holding = target.beginHold?.(event.clientX, event.clientY) ?? false;
trace(holding ? 'arrange: took hold' : 'arrange: nothing under the pointer');
return;
}
// Resting the pointer, with any tool, may become a hold on an image.
if (target.beginHold) {
pressX = event.clientX;
@@ -281,6 +294,7 @@ export function attachPenInput(surface, target) {
target.holdMove?.(event.clientX, event.clientY);
return;
}
if (arranging) return;
if (holdTimer !== null && Math.hypot(event.clientX - pressX, event.clientY - pressY) > HOLD_SLACK_PX) {
cancelHoldTimer();
eraseFromPress();
@@ -315,7 +329,10 @@ export function attachPenInput(surface, target) {
cancelHoldTimer();
if (holding) {
holding = false;
arranging = false;
target.holdEnd?.();
} else if (arranging) {
arranging = false;
} else if (zooming) {
zooming = false;
target.endZoom?.();