@reekon-tools/boldr-cad 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/data/provider.d.ts +2 -1
- package/dist/data/sync.js +4 -1
- package/dist/data/sync.js.map +1 -1
- package/dist/editor/actions.js +10 -1
- package/dist/editor/actions.js.map +1 -1
- package/dist/editor/advance.d.ts +2 -0
- package/dist/editor/advance.js +23 -0
- package/dist/editor/advance.js.map +1 -0
- package/dist/editor/dimSize.d.ts +13 -0
- package/dist/editor/dimSize.js +50 -0
- package/dist/editor/dimSize.js.map +1 -0
- package/dist/editor/gestures.js +30 -7
- package/dist/editor/gestures.js.map +1 -1
- package/dist/editor/keypad.d.ts +8 -0
- package/dist/editor/keypad.js +15 -1
- package/dist/editor/keypad.js.map +1 -1
- package/dist/editor/laser.d.ts +9 -0
- package/dist/editor/laser.js +38 -12
- package/dist/editor/laser.js.map +1 -1
- package/dist/editor/ports.d.ts +9 -0
- package/dist/editor/ports.js +2 -0
- package/dist/editor/ports.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/model/clockwise.d.ts +11 -0
- package/dist/model/clockwise.js +123 -0
- package/dist/model/clockwise.js.map +1 -0
- package/dist/model/settings.d.ts +2 -0
- package/dist/model/settings.js +1 -1
- package/dist/model/settings.js.map +1 -1
- package/dist/react/BottomBar.js +43 -3
- package/dist/react/BottomBar.js.map +1 -1
- package/dist/react/PlanCanvas.native.js +15 -9
- package/dist/react/PlanCanvas.native.js.map +1 -1
- package/dist/react/host.d.ts +6 -0
- package/dist/react/host.js +11 -1
- package/dist/react/host.js.map +1 -1
- package/dist/react/ports.js +2 -1
- package/dist/react/ports.js.map +1 -1
- package/dist/react/store.d.ts +1 -1
- package/dist/react/store.js.map +1 -1
- package/dist/render/draw.d.ts +7 -0
- package/dist/render/draw.js +17 -8
- package/dist/render/draw.js.map +1 -1
- package/dist/render/navigate.d.ts +11 -6
- package/dist/render/navigate.js +34 -20
- package/dist/render/navigate.js.map +1 -1
- package/dist/tools/dim.d.ts +6 -0
- package/dist/tools/dim.js +28 -4
- package/dist/tools/dim.js.map +1 -1
- package/package.json +1 -1
- package/src/data/provider.ts +2 -2
- package/src/data/sync.ts +4 -1
- package/src/editor/actions.ts +6 -1
- package/src/editor/advance.ts +23 -0
- package/src/editor/dimSize.ts +53 -0
- package/src/editor/gestures.ts +31 -9
- package/src/editor/keypad.ts +17 -1
- package/src/editor/laser.ts +38 -10
- package/src/editor/ports.ts +10 -0
- package/src/index.ts +1 -2
- package/src/model/clockwise.ts +121 -0
- package/src/model/settings.ts +3 -1
- package/src/react/BottomBar.tsx +46 -2
- package/src/react/PlanCanvas.native.tsx +25 -12
- package/src/react/host.ts +11 -1
- package/src/react/ports.ts +3 -2
- package/src/react/store.ts +1 -1
- package/src/render/draw.ts +20 -9
- package/src/render/navigate.ts +31 -20
- package/src/tools/dim.ts +28 -4
- package/src/ui/domPorts.ts +2 -0
package/src/react/host.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyReading, laser } from '../editor/laser';
|
|
1
|
+
import { applyReading, laser, readingOverwrites } from '../editor/laser';
|
|
2
2
|
import { store } from '../model/store';
|
|
3
3
|
import { closeSurveyRun, setSurveyCursor, takeSurveyPoint } from '../tools/survey';
|
|
4
4
|
import { notify } from './store';
|
|
@@ -33,6 +33,16 @@ export function laserReading(inches: number, capture?: unknown): boolean {
|
|
|
33
33
|
return true;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Whether a reading of `inches`, passed to laserReading now, would replace a length or diameter already measured on
|
|
38
|
+
* the selected line, wall edge or curve (see readingOverwrites), for a host that warns first: hold the reading, ask,
|
|
39
|
+
* and pass it on only once the person agrees. Nothing changes by asking. False when no drawing is open to take it.
|
|
40
|
+
*/
|
|
41
|
+
export function laserReadingOverwrites(inches: number): boolean {
|
|
42
|
+
if (!editorHost.open || !store.project || !Number.isFinite(inches) || inches <= 0) return false;
|
|
43
|
+
return readingOverwrites(inches);
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
/**
|
|
37
47
|
* A point measured by a templating device (BOLDR's T1R), in inches, on the plan's axes: x to the right, y UP. Turning
|
|
38
48
|
* the device's own frame into that is the host's job, and it's where the handedness goes: a device whose angle turns
|
package/src/react/ports.ts
CHANGED
|
@@ -59,8 +59,8 @@ function hostRequest(spec: KeypadSpec): HostKeypadRequest {
|
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
/** A slider above the bar (an image's opacity or rotation, the tiles' size): opened, swapped for another, or closed by its button again. */
|
|
63
|
-
function toggleImagePop(kind: 'opacity' | 'rotate' | 'tilesize'): void {
|
|
62
|
+
/** A slider above the bar (an image's opacity or rotation, the tiles' or measurement tiles' size): opened, swapped for another, or closed by its button again. */
|
|
63
|
+
function toggleImagePop(kind: 'opacity' | 'rotate' | 'tilesize' | 'dimsize'): void {
|
|
64
64
|
ui.imgPop = ui.imgPop === kind ? null : kind;
|
|
65
65
|
ui.menu = false;
|
|
66
66
|
// (a toast would sit over the slider: it's done with once the slider opens)
|
|
@@ -153,6 +153,7 @@ export const reactPorts: EditorPorts = {
|
|
|
153
153
|
toggleImageOpacity() { toggleImagePop('opacity'); },
|
|
154
154
|
toggleImageRotation() { toggleImagePop('rotate'); },
|
|
155
155
|
toggleTileSize() { toggleImagePop('tilesize'); },
|
|
156
|
+
toggleDimSize() { toggleImagePop('dimsize'); },
|
|
156
157
|
editRoomName(roomId) { ui.drawer = 'rooms'; ui.renameRoom = roomId; notify(); },
|
|
157
158
|
setCursor(cursor, where = 'plan') { cursorTargets[where]?.(cursor); },
|
|
158
159
|
interacting: setInteracting,
|
package/src/react/store.ts
CHANGED
|
@@ -59,7 +59,7 @@ export const ui = sessionState(() => ({
|
|
|
59
59
|
* what's open above the bar: the selected image's opacity or turn, or the link tiles' size (sliders), or Open's
|
|
60
60
|
* question (here, or side by side)
|
|
61
61
|
*/
|
|
62
|
-
imgPop: null as null | 'opacity' | 'rotate' | 'tilesize' | 'open',
|
|
62
|
+
imgPop: null as null | 'opacity' | 'rotate' | 'tilesize' | 'dimsize' | 'open',
|
|
63
63
|
/** the tool each shared place on the rail draws with (the last picked; editor/mode.ts TOOL_GROUPS), and the menu of
|
|
64
64
|
a group's tools, open beside its place at x, y */
|
|
65
65
|
picked: { shapes: 'line', marks: 'arrow' } as Record<string, string>,
|
package/src/render/draw.ts
CHANGED
|
@@ -41,7 +41,8 @@ export function rr(c: C2D, x: number, y: number, w: number, h: number, r: number
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export interface ChipOpts {
|
|
44
|
-
|
|
44
|
+
/** `r`: its corners' radius (5) */
|
|
45
|
+
bg: string; fg: string; border?: [string, number?] | null; font?: string; pad?: number; h?: number; minW?: number; r?: number;
|
|
45
46
|
kind?: HitChip['kind']; id?: string; rot?: number;
|
|
46
47
|
/**
|
|
47
48
|
* 'link': a measurement of the job sets it. The chip is then Figma's linked measurement (2795:77149): a white badge
|
|
@@ -80,13 +81,22 @@ export function chipSize(c: C2D, text: string, { font = '600 12px', pad = 7, h =
|
|
|
80
81
|
return { w: Math.max(minW, c.measureText(text).width + room), h };
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
/**
|
|
85
|
+
* A measurement tile's size — a dimension's chip: its font, padding, height and corners — times the file's measurement
|
|
86
|
+
* tile size (settings.chipPct, editor/dimSize.ts). At 100%, chip()'s own: 12 px, 7, 22, 5.
|
|
87
|
+
*/
|
|
88
|
+
export function dimChip(): Pick<ChipOpts, 'font' | 'pad' | 'h' | 'r'> {
|
|
89
|
+
const k = settings.chipPct / 100;
|
|
90
|
+
return k === 1 ? {} : { font: '600 ' + 12 * k + 'px', pad: 7 * k, h: 22 * k, r: 5 * k };
|
|
91
|
+
}
|
|
92
|
+
|
|
83
93
|
/** Rounded label on the canvas; registers a hit region when `kind` is given. */
|
|
84
94
|
export function chip(c: C2D, text: string, cx: number, cy: number, opts: ChipOpts): number {
|
|
85
95
|
const { bg, fg, border, kind, id, rot = 0, mark } = opts;
|
|
86
96
|
const { w, h } = chipSize(c, text, opts), x = cx - w / 2, y = cy - h / 2;
|
|
87
97
|
c.save();
|
|
88
98
|
if (rot) { c.translate(cx, cy); c.rotate(rot); c.translate(-cx, -cy); }
|
|
89
|
-
rr(c, x, y, w, h, 5);
|
|
99
|
+
rr(c, x, y, w, h, opts.r ?? 5);
|
|
90
100
|
c.fillStyle = bg; c.fill();
|
|
91
101
|
if (border) { c.lineWidth = border[1] || 1; c.strokeStyle = border[0]; c.stroke(); }
|
|
92
102
|
c.fillStyle = fg; c.textAlign = 'center'; c.textBaseline = 'middle';
|
|
@@ -627,7 +637,7 @@ function drawDims(c: C2D, T: Xform, sk: Sketch): void {
|
|
|
627
637
|
}
|
|
628
638
|
c.restore();
|
|
629
639
|
}
|
|
630
|
-
const text = wrap(fmtAng(val)), opts: ChipOpts = { bg, fg, border, kind: 'dim', id, mark };
|
|
640
|
+
const text = wrap(fmtAng(val)), opts: ChipOpts = { bg, fg, border, kind: 'dim', id, mark, ...dimChip() };
|
|
631
641
|
// (left where it was drawn: 50 px out along the bisector, or as far as its corners stay clear of the corner — a
|
|
632
642
|
// linked chip is wider)
|
|
633
643
|
const sz = chipSize(c, text, opts), out = Math.max(50, Math.hypot(sz.w, sz.h) / 2 + 28);
|
|
@@ -636,7 +646,7 @@ function drawDims(c: C2D, T: Xform, sk: Sketch): void {
|
|
|
636
646
|
continue;
|
|
637
647
|
}
|
|
638
648
|
if (d.type === 'diam' && 'o' in A) {
|
|
639
|
-
drawDiameter(c, T, A.o, A.r, d, d.rad ? 'R ' + wrap(fmtLen(val / 2)) : 'Ø ' + wrap(fmtLen(val)), bad ? TH.red : ref ? TH.chipline : TH.blue, { bg, fg, border, kind: 'dim', id, mark }, ref);
|
|
649
|
+
drawDiameter(c, T, A.o, A.r, d, d.rad ? 'R ' + wrap(fmtLen(val / 2)) : 'Ø ' + wrap(fmtLen(val)), bad ? TH.red : ref ? TH.chipline : TH.blue, { bg, fg, border, kind: 'dim', id, mark, ...dimChip() }, ref);
|
|
640
650
|
continue;
|
|
641
651
|
}
|
|
642
652
|
if (!('a' in A)) continue;
|
|
@@ -650,7 +660,7 @@ function drawDims(c: C2D, T: Xform, sk: Sketch): void {
|
|
|
650
660
|
c.save(); if (ref) c.setLineDash([3, 3]); c.strokeStyle = bad ? TH.red : ref ? TH.chipline : TH.blue; c.lineWidth = 1.2;
|
|
651
661
|
c.beginPath(); c.moveTo(ax, ay); c.lineTo(bx, by); c.stroke(); c.restore();
|
|
652
662
|
}
|
|
653
|
-
chip(c, wrap(fmtLen(val)), mx, my, { bg, fg, border, kind: 'dim', id, mark });
|
|
663
|
+
chip(c, wrap(fmtLen(val)), mx, my, { bg, fg, border, kind: 'dim', id, mark, ...dimChip() });
|
|
654
664
|
}
|
|
655
665
|
}
|
|
656
666
|
|
|
@@ -664,14 +674,15 @@ function drawDims(c: C2D, T: Xform, sk: Sketch): void {
|
|
|
664
674
|
*/
|
|
665
675
|
function drawOpeningDims(c: C2D, T: Xform, sk: Sketch): void {
|
|
666
676
|
if (!settings.layers.dims || ed.mode !== 'draft') return;
|
|
667
|
-
|
|
677
|
+
// (the rows, and how far apart along them, grow with the measurement tiles: editor/dimSize.ts)
|
|
678
|
+
const k = settings.chipPct / 100, ROW = (26 * k) / T.s;
|
|
668
679
|
for (const id in sk.openings) {
|
|
669
680
|
const o = sk.openings[id], g = openingFrame(sk, id);
|
|
670
681
|
if (!g) continue;
|
|
671
682
|
const l = sk.lines[o.line], L = hyp(sk.points[l.b].x - g.A.x, sk.points[l.b].y - g.A.y);
|
|
672
683
|
const side = outsideSide(sk, o.line);
|
|
673
684
|
// automatic rows start 34 px past the wall face (clear of the H/V badges); a dragged dimension keeps its own offset
|
|
674
|
-
const k0 = g.t / 2 + 34 / T.s;
|
|
685
|
+
const k0 = g.t / 2 + (34 + 11 * (k - 1)) / T.s;
|
|
675
686
|
const kRow = (row: number) => side * (k0 + row * ROW);
|
|
676
687
|
/** screen point at `s` along the wall, `k` (signed, world) off its centerline */
|
|
677
688
|
const P = (s: number, k: number) => S(T, g.A.x + g.ux * s + g.nx * k, g.A.y + g.uy * s + g.ny * k);
|
|
@@ -699,14 +710,14 @@ function drawOpeningDims(c: C2D, T: Xform, sk: Sketch): void {
|
|
|
699
710
|
};
|
|
700
711
|
const label = (s0: number, s1: number, part: string, text: string, k: number, bg: string = TH.blue, fg = '#fff', border: [string, number] | null = null) => {
|
|
701
712
|
const [mx, my] = P((s0 + s1) / 2, k);
|
|
702
|
-
chip(c, text, mx, my, { bg, fg, border: odimSel(part) ? [TH.yellow, 2] : border, kind: 'odim', id });
|
|
713
|
+
chip(c, text, mx, my, { bg, fg, border: odimSel(part) ? [TH.yellow, 2] : border, kind: 'odim', id, ...dimChip() });
|
|
703
714
|
if (hits && hits.length) hits[hits.length - 1].part = part;
|
|
704
715
|
};
|
|
705
716
|
// automatic placement packs dimensions into rows so they don't overlap each other or the width chip;
|
|
706
717
|
// spans that only touch end to end share a row (a chained string)
|
|
707
718
|
const rows: [number, number][][] = [o.wOff == null ? [[g.s0, g.s1]] : []];
|
|
708
719
|
const place = (a: number, b: number) => {
|
|
709
|
-
const lo = Math.min(a, b), hi = Math.max(a, b), gap = 64 / T.s;
|
|
720
|
+
const lo = Math.min(a, b), hi = Math.max(a, b), gap = (64 * k) / T.s;
|
|
710
721
|
const clash = ([x, y]: [number, number]) => (lo < y - 1e-6 && hi > x + 1e-6) || Math.abs((lo + hi) / 2 - (x + y) / 2) < gap;
|
|
711
722
|
for (let r = 0; ; r++) {
|
|
712
723
|
rows[r] = rows[r] || [];
|
package/src/render/navigate.ts
CHANGED
|
@@ -59,46 +59,57 @@ export interface UiView extends NavView { seq: number }
|
|
|
59
59
|
/** What the drawing on screen was drawn at: its view, the latest of the fingers' views it includes, the screen size. */
|
|
60
60
|
export interface DrawnAt { view: NavView; seq: number; W: number; H: number }
|
|
61
61
|
|
|
62
|
-
/**
|
|
63
|
-
|
|
62
|
+
/**
|
|
63
|
+
* The pointers on the screen and what they're doing: the fingers that count (a finger a Pencil landed on doesn't — see
|
|
64
|
+
* navTouch), navigating or not, where they were last, and any Pencil down.
|
|
65
|
+
*/
|
|
66
|
+
export interface NavState { fingers: Record<number, { x: number; y: number }>; navigating: boolean; last: Pinch | null; pens: number[] }
|
|
64
67
|
|
|
65
68
|
export const NAV_DOWN = 0, NAV_MOVE = 1, NAV_UP = 2, NAV_CANCEL = 3;
|
|
66
69
|
|
|
67
70
|
/**
|
|
68
71
|
* One touch event, as the UI thread sees it: the fingers after it, and the view (moved if `moved`). Fingers navigate —
|
|
69
|
-
* pan, and zoom about their middle — once two are down, or
|
|
70
|
-
* view only (editor/gestures.ts decides the same on its side), until the last one lifts. A
|
|
71
|
-
*
|
|
72
|
-
*
|
|
72
|
+
* pan, and zoom about their middle — once two are down, or a finger lands while a Pencil is down or when the drawing is
|
|
73
|
+
* view only (editor/gestures.ts decides the same on its side), until the last one lifts. A finger already down and not
|
|
74
|
+
* navigating when a Pencil lands is set aside until it lifts. A pen or a mouse never navigates. `type` is NAV_DOWN… ;
|
|
75
|
+
* `kind` is the event's pointer, for a touch that doesn't say what it is itself; `allIds`, every pointer still down (on
|
|
76
|
+
* a down event: a finger that went without a word, a lost touch-up, is dropped so it can't hold a gesture open).
|
|
73
77
|
*/
|
|
74
78
|
export function navTouch(
|
|
75
|
-
st: NavState, type: number, kind: string, changed: { id: number; x: number; y: number }[], allIds: number[] | null,
|
|
79
|
+
st: NavState, type: number, kind: string, changed: { id: number; x: number; y: number; kind?: string }[], allIds: number[] | null,
|
|
76
80
|
readOnly: boolean, view: UiView, drawn: DrawnAt | null,
|
|
77
81
|
): { st: NavState; view: UiView; moved: boolean } {
|
|
78
82
|
'worklet';
|
|
79
|
-
const
|
|
80
|
-
if (kind !== 'touch') return { st: { ...st, pen }, view, moved: false };
|
|
83
|
+
const lost = (id: number) => type === NAV_DOWN && !!allIds && !allIds.includes(id);
|
|
81
84
|
const fingers: Record<number, { x: number; y: number }> = {};
|
|
82
|
-
for (const k in st.fingers)
|
|
83
|
-
|
|
84
|
-
if (type !== NAV_DOWN || !allIds || allIds.includes(id)) fingers[id] = st.fingers[id];
|
|
85
|
-
}
|
|
85
|
+
for (const k in st.fingers) if (!lost(Number(k))) fingers[Number(k)] = st.fingers[Number(k)];
|
|
86
|
+
let pens = st.pens.filter(id => !lost(id)), landed = false, moved = false;
|
|
86
87
|
for (const t of changed) {
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
const k = t.kind ?? kind;
|
|
89
|
+
if (type === NAV_UP || type === NAV_CANCEL) {
|
|
90
|
+
delete fingers[t.id];
|
|
91
|
+
pens = pens.filter(id => id !== t.id);
|
|
92
|
+
} else if (type === NAV_DOWN && k === 'pen') {
|
|
93
|
+
if (!pens.includes(t.id)) pens = [...pens, t.id];
|
|
94
|
+
// (fingers down and not navigating are let go of: their moves and lifts are no finger's from here)
|
|
95
|
+
if (!st.navigating) for (const f in fingers) delete fingers[f];
|
|
96
|
+
} else if (type === NAV_DOWN ? k === 'touch' : t.id in fingers) {
|
|
97
|
+
fingers[t.id] = { x: t.x, y: t.y };
|
|
98
|
+
if (type === NAV_DOWN) landed = true; else moved = true;
|
|
99
|
+
}
|
|
89
100
|
}
|
|
90
101
|
const pts = Object.keys(fingers).map(k => fingers[Number(k)]);
|
|
91
|
-
if (!pts.length) return { st: { fingers, navigating: false, last: null,
|
|
102
|
+
if (!pts.length) return { st: { fingers, navigating: false, last: null, pens }, view, moved: false };
|
|
92
103
|
let navigating = st.navigating, v = view;
|
|
93
104
|
if (!navigating) {
|
|
94
|
-
if (pts.length < 2 && !(
|
|
105
|
+
if (pts.length < 2 && !(landed && (pens.length > 0 || readOnly))) return { st: { fingers, navigating: false, last: null, pens }, view, moved: false };
|
|
95
106
|
navigating = true;
|
|
96
107
|
// start from the view the drawing on screen was drawn at, unless the fingers' own is newer
|
|
97
108
|
if (drawn && v.seq <= drawn.seq) v = { s: drawn.view.s, cx: drawn.view.cx, cy: drawn.view.cy, seq: drawn.seq };
|
|
98
109
|
}
|
|
99
|
-
const now = pinchOf(pts), was = st.last, next = { fingers, navigating, last: now,
|
|
100
|
-
// a finger came or went: carry on from here, no jump
|
|
101
|
-
if (type !== NAV_MOVE || !now || !was || was.n !== now.n || !drawn) return { st: next, view: v, moved: false };
|
|
110
|
+
const now = pinchOf(pts), was = st.last, next = { fingers, navigating, last: now, pens };
|
|
111
|
+
// a finger came or went: carry on from here, no jump (and a Pencil's move alone moves no view)
|
|
112
|
+
if (type !== NAV_MOVE || !moved || !now || !was || was.n !== now.n || !drawn) return { st: next, view: v, moved: false };
|
|
102
113
|
const to = navStep(v, was, now, drawn.W, drawn.H);
|
|
103
114
|
return { st: next, view: { s: to.s, cx: to.cx, cy: to.cy, seq: v.seq + 1 }, moved: true };
|
|
104
115
|
}
|
package/src/tools/dim.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { fmtAng, fmtLen } from '../units';
|
|
|
23
23
|
import { addOpeningDim } from './openings';
|
|
24
24
|
import type { PEv } from './registry';
|
|
25
25
|
import { keypadFresh, keypadOpen, keypadSetReading } from '../editor/keypad';
|
|
26
|
+
import { advanceAfterReading } from '../editor/advance';
|
|
26
27
|
import { cornerLines } from '../editor/selection';
|
|
27
28
|
import { closeKeypad, kpTyped, openKeypad, showConflict, toast, updateCtx, updateHint, type KeypadSpec } from '../editor/ports';
|
|
28
29
|
import { noScaleYet, pendingLabel, startingValue } from '../editor/scaleGate';
|
|
@@ -177,7 +178,11 @@ export function dimLine(lid: string, side?: 1 | -1): void {
|
|
|
177
178
|
onPress: () => { face = ch.face!; spec.sub = lengthSub(sk, lid, face); show(); if (keypadFresh() && !noScaleYet()) keypadSetReading(len()); },
|
|
178
179
|
})) : undefined,
|
|
179
180
|
onClose: () => { ed.sel = was; updateCtx(); requestDraw(); },
|
|
180
|
-
onDone: (v, capture) => {
|
|
181
|
+
onDone: (v, capture) => {
|
|
182
|
+
if (!(v > 0)) return;
|
|
183
|
+
// a laser reading's (it comes with its record) moves on to the next line clockwise; a typed one stays
|
|
184
|
+
if (addLength(v, capture !== undefined ? { capture } : {}) && capture !== undefined) advanceAfterReading(lid, side);
|
|
185
|
+
},
|
|
181
186
|
// (or a length of the job's, from its list: the line takes it, linked to it)
|
|
182
187
|
measurements: offersJobMeasurements() ? {
|
|
183
188
|
kind: 'length', pick: t => {
|
|
@@ -188,21 +193,32 @@ export function dimLine(lid: string, side?: 1 | -1): void {
|
|
|
188
193
|
},
|
|
189
194
|
} : undefined,
|
|
190
195
|
};
|
|
191
|
-
/** The line's length dimension, driving, measured where the keypad says (`extra`: what it's from). */
|
|
192
|
-
function addLength(v: number, extra: Partial<Constraint>):
|
|
196
|
+
/** The line's length dimension, driving, measured where the keypad says (`extra`: what it's from). Whether it took. */
|
|
197
|
+
function addLength(v: number, extra: Partial<Constraint>): boolean {
|
|
193
198
|
pushHistory();
|
|
194
199
|
const r = tryAddConstraint({ type: 'dist', a: l.a, b: l.b, kind: 'al', value: v, line: lid, driving: true, off: face ? (face * 30) / V().s : 0, ...(face ? { face } : {}), ...extra });
|
|
195
200
|
// a measurement of the job drives a line, or nothing: not one whose length the drawing already sets
|
|
201
|
+
let took = r.ok;
|
|
196
202
|
if (r.ok && r.ref && extra.measurementRef) {
|
|
197
203
|
delete SK().cons[r.id!];
|
|
198
204
|
dropHistory();
|
|
199
205
|
toast(LENGTH_SET_ALREADY, { warn: true });
|
|
206
|
+
took = false;
|
|
200
207
|
} else if (!r.ok) dropHistory();
|
|
201
208
|
afterEdit();
|
|
209
|
+
return took;
|
|
202
210
|
}
|
|
203
211
|
openKeypad(spec);
|
|
204
212
|
}
|
|
205
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Whether giving dimension `c` the value `v` replaces a value measured there: a driving one, entered (not a default
|
|
216
|
+
* nobody measured), changed by it. Not one linked to a measurement of the job: that's asked about anyway
|
|
217
|
+
* (askLinkedChange). What a host warns about before a reading overwrites (laserReadingOverwrites).
|
|
218
|
+
*/
|
|
219
|
+
export const replacesMeasured = (c: Constraint | undefined, v: number): boolean =>
|
|
220
|
+
!!c && c.driving !== false && !c.auto && !c.measurementRef && changesValue(c, v);
|
|
221
|
+
|
|
206
222
|
/** Why a measurement of the job can't drive a line the drawing already sets the length of. */
|
|
207
223
|
export const LENGTH_SET_ALREADY = 'The drawing already sets that line’s length. Free it first (make one of its dimensions a reference), then pick the measurement.';
|
|
208
224
|
/** Why a measurement of the job can't drive an angle the drawing already sets. */
|
|
@@ -587,7 +603,15 @@ export function editDim(id: string, done?: () => void, modeless = false, pick?:
|
|
|
587
603
|
label: ch.label!, on: onChoice(withFace(c, face), ch),
|
|
588
604
|
onPress: () => { face = onChoice(c, ch) ? null : { ...ch, l2: face?.l2 ?? ch.l2 }; if (keypadFresh()) keypadSetReading(now()); },
|
|
589
605
|
})),
|
|
590
|
-
onDone: (v, capture) => {
|
|
606
|
+
onDone: (v, capture) => {
|
|
607
|
+
const took = setDimValue(id, v * k, face ?? undefined, { capture });
|
|
608
|
+
done?.();
|
|
609
|
+
// a laser reading's (it comes with its record) on a line's length or a curve's diameter moves on to the next
|
|
610
|
+
// line clockwise; a typed one, or one the drawing refused or asked about, stays
|
|
611
|
+
const of = c.type === 'dist' ? c.line : c.type === 'diam' ? c.c : undefined;
|
|
612
|
+
if (took && capture !== undefined && of) advanceAfterReading(of, pick?.face || undefined);
|
|
613
|
+
},
|
|
614
|
+
overwrites: v => replacesMeasured(SK().cons[id], v * k),
|
|
591
615
|
// a line's length or an angle: or one of the job's, from its list — the dimension takes it, linked to it (a
|
|
592
616
|
// dimension already linked to another, re-linked)
|
|
593
617
|
measurements: ((c.type === 'dist' && c.line) || isAng) && offersJobMeasurements() ? {
|
package/src/ui/domPorts.ts
CHANGED
|
@@ -67,6 +67,8 @@ export const domPorts: EditorPorts = {
|
|
|
67
67
|
toggleImageRotation: anchor => toggleRotation(anchor as HTMLElement | undefined),
|
|
68
68
|
// (this interface has no link tiles: no host links)
|
|
69
69
|
toggleTileSize: () => {},
|
|
70
|
+
// (the harness's page has no slider for it: its hosts' editor does)
|
|
71
|
+
toggleDimSize: () => {},
|
|
70
72
|
editRoomName,
|
|
71
73
|
setCursor: cursor => { cvs.cv.style.cursor = cursor; },
|
|
72
74
|
// (this page's chrome stays put while a gesture moves)
|