|
1 | 1 | <script lang="ts"> |
2 | | - import { createEventDispatcher, onMount, onDestroy } from "svelte"; |
| 2 | + import { createEventDispatcher, onMount, onDestroy, getContext } from "svelte"; |
3 | 3 |
|
4 | 4 | import { evaluateMathExpression } from "@graphite/../wasm/pkg/graphite_wasm"; |
| 5 | + import type { Editor } from "@graphite/editor"; |
5 | 6 | import { PRESS_REPEAT_DELAY_MS, PRESS_REPEAT_INTERVAL_MS } from "@graphite/io-managers/input"; |
6 | 7 | import type { NumberInputMode, NumberInputIncrementBehavior, ActionShortcut } from "@graphite/messages"; |
7 | 8 | import { browserVersion, isDesktop } from "@graphite/utility-functions/platform"; |
|
16 | 17 |
|
17 | 18 | const dispatch = createEventDispatcher<{ value: number | undefined; startHistoryTransaction: undefined }>(); |
18 | 19 |
|
| 20 | + const editor = getContext<Editor>("editor"); |
| 21 | +
|
19 | 22 | // Content |
20 | 23 | /// When `value` is not provided (i.e. it's `undefined`), a dash is displayed. |
21 | 24 | export let value: number | undefined = undefined; |
|
80 | 83 | let initialValueBeforeDragging: number | undefined = undefined; |
81 | 84 | // Stores the total value change during the process of dragging the slider. Set to 0 when not dragging. |
82 | 85 | let cumulativeDragDelta = 0; |
| 86 | + // Track whether the Shift key is currently held down. |
| 87 | + let shiftKeyDown = false; |
83 | 88 | // Track whether the Ctrl key is currently held down. |
84 | 89 | let ctrlKeyDown = false; |
85 | 90 |
|
|
91 | 96 | ...(mode === "Range" ? { "--progress-factor": Math.min(Math.max((rangeSliderValueAsRendered - rangeMin) / (rangeMax - rangeMin), 0), 1) } : {}), |
92 | 97 | }; |
93 | 98 |
|
94 | | - // Keep track of the Ctrl key being held down. |
95 | | - const trackCtrl = (e: KeyboardEvent | MouseEvent) => (ctrlKeyDown = e.ctrlKey); |
| 99 | + // Keep track of the Shift and Ctrl key being held down. |
| 100 | + const trackShiftAndCtrl = (e: KeyboardEvent | MouseEvent) => { |
| 101 | + shiftKeyDown = e.shiftKey; |
| 102 | + ctrlKeyDown = e.ctrlKey; |
| 103 | + }; |
96 | 104 | onMount(() => { |
97 | | - addEventListener("keydown", trackCtrl); |
98 | | - addEventListener("keyup", trackCtrl); |
99 | | - addEventListener("mousemove", trackCtrl); |
| 105 | + addEventListener("keydown", trackShiftAndCtrl); |
| 106 | + addEventListener("keyup", trackShiftAndCtrl); |
| 107 | + addEventListener("mousemove", trackShiftAndCtrl); |
100 | 108 | }); |
101 | 109 | onDestroy(() => { |
102 | | - removeEventListener("keydown", trackCtrl); |
103 | | - removeEventListener("keyup", trackCtrl); |
104 | | - removeEventListener("mousemove", trackCtrl); |
| 110 | + removeEventListener("keydown", trackShiftAndCtrl); |
| 111 | + removeEventListener("keyup", trackShiftAndCtrl); |
| 112 | + removeEventListener("mousemove", trackShiftAndCtrl); |
105 | 113 | clearTimeout(repeatTimeout); |
106 | 114 | }); |
107 | 115 |
|
|
369 | 377 |
|
370 | 378 | // Enter dragging state |
371 | 379 | if (usePointerLock) target.requestPointerLock(); |
| 380 | + if (isDesktop()) { |
| 381 | + editor.handle.appWindowPointerLock(); |
| 382 | + } |
372 | 383 | initialValueBeforeDragging = value; |
373 | 384 | cumulativeDragDelta = 0; |
374 | 385 |
|
|
412 | 423 |
|
413 | 424 | // Calculate and then update the dragged value offset, slowed down by 10x when Shift is held. |
414 | 425 | if (ignoredFirstMovement && initialValueBeforeDragging !== undefined) { |
415 | | - const CHANGE_PER_DRAG_PX = 0.1; |
416 | | - const CHANGE_PER_DRAG_PX_SLOW = CHANGE_PER_DRAG_PX / 10; |
417 | | -
|
418 | | - const dragDelta = e.movementX * (e.shiftKey ? CHANGE_PER_DRAG_PX_SLOW : CHANGE_PER_DRAG_PX); |
419 | | - cumulativeDragDelta += dragDelta; |
420 | | -
|
421 | | - const combined = initialValueBeforeDragging + cumulativeDragDelta; |
422 | | - const combineSnapped = e.ctrlKey ? Math.round(combined) : combined; |
423 | | -
|
424 | | - const newValue = updateValue(combineSnapped); |
425 | | -
|
426 | | - // If the value was altered within the `updateValue()` call, we need to rectify the cumulative drag delta to account for the change. |
427 | | - if (newValue !== undefined) cumulativeDragDelta -= combineSnapped - newValue; |
| 426 | + pointerLockMoveUpdate(e.movementX, e.shiftKey, e.ctrlKey, initialValueBeforeDragging); |
| 427 | + } |
| 428 | + ignoredFirstMovement = true; |
| 429 | + }; |
| 430 | + // On desktop we don't get `pointermove` events while in pointer lock (cef doesn't support pointer lock). |
| 431 | + // We have to listen for our custom `pointerlockmove` events instead. |
| 432 | + const pointerLockMove = (e: Event) => { |
| 433 | + if (ignoredFirstMovement && initialValueBeforeDragging !== undefined && e instanceof CustomEvent) { |
| 434 | + const delta = (e.detail as { x: number }).x; |
| 435 | + pointerLockMoveUpdate(delta, shiftKeyDown, ctrlKeyDown, initialValueBeforeDragging); |
428 | 436 | } |
429 | 437 | ignoredFirstMovement = true; |
430 | 438 | }; |
|
443 | 451 | // Clean up the event listeners. |
444 | 452 | removeEventListener("pointerup", pointerUp); |
445 | 453 | removeEventListener("pointermove", pointerMove); |
| 454 | + removeEventListener("pointerlockmove", pointerLockMove); |
446 | 455 | if (usePointerLock) document.removeEventListener("pointerlockchange", pointerLockChange); |
447 | 456 | }; |
448 | 457 |
|
449 | 458 | addEventListener("pointerup", pointerUp); |
450 | 459 | addEventListener("pointermove", pointerMove); |
| 460 | + addEventListener("pointerlockmove", pointerLockMove); |
451 | 461 | if (usePointerLock) document.addEventListener("pointerlockchange", pointerLockChange); |
452 | 462 | } |
453 | 463 |
|
| 464 | + function pointerLockMoveUpdate(delta: number, slow: boolean, snapping: boolean, initialValue: number) { |
| 465 | + const CHANGE_PER_DRAG_PX = 0.1; |
| 466 | + const CHANGE_PER_DRAG_PX_SLOW = CHANGE_PER_DRAG_PX / 10; |
| 467 | +
|
| 468 | + const dragDelta = delta * (slow ? CHANGE_PER_DRAG_PX_SLOW : CHANGE_PER_DRAG_PX); |
| 469 | + cumulativeDragDelta += dragDelta; |
| 470 | +
|
| 471 | + const combined = initialValue + cumulativeDragDelta; |
| 472 | + const combineSnapped = snapping ? Math.round(combined) : combined; |
| 473 | +
|
| 474 | + const newValue = updateValue(combineSnapped); |
| 475 | +
|
| 476 | + // If the value was altered within the `updateValue()` call, we need to rectify the cumulative drag delta to account for the change. |
| 477 | + if (newValue !== undefined) cumulativeDragDelta -= combineSnapped - newValue; |
| 478 | + } |
| 479 | +
|
454 | 480 | // =============================== |
455 | 481 | // RANGE MODE: DRAGGING THE SLIDER |
456 | 482 | // =============================== |
|
0 commit comments