From 458cc85db27c83694cd8988ef7ae428aa68de566 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Mon, 16 Jan 2023 21:02:53 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E7=81=AF=E6=9D=A1=E4=BD=8D=E7=BD=AE=E6=97=B6=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E9=94=99=E4=B9=B1=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/completed-led-strip.tsx | 193 +---------------- .../components/draggable-strip.tsx | 196 ++++++++++++++++++ .../components/led-strip-editor.tsx | 5 +- src/configurator/configurator.tsx | 5 +- 4 files changed, 210 insertions(+), 189 deletions(-) create mode 100644 src/configurator/components/draggable-strip.tsx diff --git a/src/configurator/components/completed-led-strip.tsx b/src/configurator/components/completed-led-strip.tsx index cc0f9a6..8c5fd23 100644 --- a/src/configurator/components/completed-led-strip.tsx +++ b/src/configurator/components/completed-led-strip.tsx @@ -1,19 +1,6 @@ import debug from 'debug'; import { isNil, lensPath, set, splitEvery, update } from 'ramda'; -import { - createRef, - FC, - Fragment, - MouseEventHandler, - ReactEventHandler, - ReactNode, - RefObject, - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; +import { FC, useEffect, useMemo, useState } from 'react'; import tw, { css, styled } from 'twin.macro'; import { Borders, borders } from '../../constants/border'; import { useLedCount } from '../contents/led-count'; @@ -21,9 +8,10 @@ import { DisplayConfig, LedStripConfigOfBorders } from '../models/display-config import { LedStripConfig } from '../models/led-strip-config'; import { PixelRgb } from '../models/pixel-rgb'; import { ScreenshotDto } from '../models/screenshot.dto'; +import { DraggableStrip } from './draggable-strip'; import { StyledPixel } from './styled-pixel'; -const logger = debug('app:completed-led-strip'); +export const logger = debug('app:completed-led-strip'); interface CompletedLedStripProps { screenshots: ScreenshotDto[]; @@ -99,7 +87,7 @@ export const CompletedLedStrip: FC = ({ }, [ledCount, borderLedStrips, overrideBorderLedStrips]); const strips = useMemo(() => { - return (overrideBorderLedStrips ?? borderLedStrips).map(({ config, pixels }, index) => + return borderLedStrips.map(({ config, pixels }, index) => config ? ( = ({ ); }} onConfigFinish={(c) => { - const indexOfDisplay = Math.round(index / borders.length); + const indexOfDisplay = Math.floor(index / borders.length); const xLens = lensPath([ borders[index % borders.length], ]); @@ -122,7 +110,6 @@ export const CompletedLedStrip: FC = ({ screenshots[indexOfDisplay].config.led_strip_of_borders, ), }; - logger('Change DisplayConfig. %o', displayConfig); onDisplayConfigChange?.(displayConfig); }} /> @@ -130,7 +117,7 @@ export const CompletedLedStrip: FC = ({
), ); - }, [borderLedStrips, overrideBorderLedStrips]); + }, [borderLedStrips, screenshots]); useEffect(() => { setOverrideBorderLedStrips(undefined); @@ -143,172 +130,4 @@ export const CompletedLedStrip: FC = ({ ); }; -interface DraggableStripProp { - config: LedStripConfig; - pixels: PixelRgb[]; - index: number; - onConfigChange?: (config: LedStripConfig) => void; - onConfigFinish?: (config: LedStripConfig) => void; -} -const DraggableStrip: FC = ({ - config, - pixels, - index, - onConfigChange, - onConfigFinish, -}) => { - const ledItems = pixels.map((rgb, i) => ( - - )); - - const { ledCount } = useLedCount(); - - const startXRef = useRef(0); - const currentXRef = useRef(0); - const configRef = useRef(); - // const currentDiffRef = useRef(0); - const [currentDiff, setCurrentDiff] = useState(0); - const isDragRef = useRef(false); - const handleMouseMoveRef = useRef<(ev: MouseEvent) => void>(); - const [boxTranslateX, setBoxTranslateX] = useState(0); - - const [placeholders, placeholderRefs]: [ReactNode[], RefObject[]] = - useMemo( - () => - new Array(ledCount) - .fill(undefined) - .map((_, i) => { - const ref = createRef(); - const n = ( - - ); - return [n, ref] as [ReactNode, RefObject]; - }) - .reduce( - ([nList, refList], [n, ref]) => [ - [...nList, n], - [...refList, ref], - ], - [[], []] as [ReactNode[], RefObject[]], - ), - [ledCount], - ); - - const handleMouseDown: MouseEventHandler = useCallback( - (ev) => { - startXRef.current = ev.pageX; - ev.currentTarget.requestPointerLock(); - isDragRef.current = true; - - const placeholderPositions = placeholderRefs.map((it) => { - if (!it.current) { - return [0, 0]; - } - const viewportOffset = it.current.getBoundingClientRect(); - return [viewportOffset.left, viewportOffset.right] as [number, number]; - }); - - logger('placeholderPositions: %o', placeholderPositions); - - // set init position - const initPos = placeholderPositions.findIndex( - ([l, r]) => l <= ev.pageX && r >= ev.pageX, - ); - setCurrentDiff(initPos); - let prevMatch = 0; - - if (handleMouseMoveRef.current) { - document.body.removeEventListener('mousemove', handleMouseMoveRef.current); - } - handleMouseMoveRef.current = (ev) => { - if (!isDragRef.current) { - return; - } - currentXRef.current = ev.pageX; - setBoxTranslateX(currentXRef.current - startXRef.current); - const match = placeholderPositions.findIndex( - ([l, r]) => l <= currentXRef.current && r >= currentXRef.current, - ); - if (match === -1) { - return; - } - - if (match === prevMatch) { - return; - } - prevMatch = match; - - const diff = match - initPos; - const newValue: LedStripConfig = { - ...config, - global_start_position: config.global_start_position + diff, - global_end_position: config.global_end_position + diff, - }; - configRef.current = newValue; - logger('change config. new: $o', newValue); - onConfigChange?.(newValue); - }; - document.body.addEventListener('mousemove', handleMouseMoveRef.current); - }, - [placeholderRefs], - ); - - // move event. - useEffect(() => { - const handleMouseUp = (ev: MouseEvent) => { - startXRef.current = 0; - isDragRef.current = false; - if (configRef.current) { - onConfigFinish?.(configRef.current); - } - document.exitPointerLock(); - if (handleMouseMoveRef.current) { - document.body.removeEventListener('mousemove', handleMouseMoveRef.current); - } - }; - document.body.addEventListener('mouseup', handleMouseUp); - return () => { - document.body.removeEventListener('mouseup', handleMouseUp); - }; - }, []); - // reset translateX when config updated. - useEffect(() => { - startXRef.current = currentXRef.current; - setCurrentDiff(0); - }, [config]); - - return ( - - {placeholders} - {ledItems} -
-
- ); -}; diff --git a/src/configurator/components/draggable-strip.tsx b/src/configurator/components/draggable-strip.tsx new file mode 100644 index 0000000..b815372 --- /dev/null +++ b/src/configurator/components/draggable-strip.tsx @@ -0,0 +1,196 @@ +import { + createRef, + FC, + Fragment, + MouseEventHandler, + ReactNode, + RefObject, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { css } from 'twin.macro'; +import { useLedCount } from '../contents/led-count'; +import { LedStripConfig } from '../models/led-strip-config'; +import { PixelRgb } from '../models/pixel-rgb'; +import { StyledPixel } from './styled-pixel'; +import { logger } from './completed-led-strip'; + +interface DraggableStripProp { + config: LedStripConfig; + pixels: PixelRgb[]; + index: number; + onConfigChange?: (config: LedStripConfig) => void; + onConfigFinish?: (config: LedStripConfig) => void; +} +export const DraggableStrip: FC = ({ + config, + pixels, + index, + onConfigChange, + onConfigFinish, +}) => { + const { ledCount } = useLedCount(); + + const startXRef = useRef(0); + const currentXRef = useRef(0); + const configRef = useRef(); + const [availableConfig, setAvailableConfig] = useState(config); + // const currentDiffRef = useRef(0); + const isDragRef = useRef(false); + const handleMouseMoveRef = useRef<(ev: MouseEvent) => void>(); + const [boxTranslateX, setBoxTranslateX] = useState(0); + + const ledItems = useMemo( + () => + pixels.map((rgb, i) => ( + + )), + [pixels, availableConfig], + ); + + const [placeholders, placeholderRefs]: [ReactNode[], RefObject[]] = + useMemo( + () => + new Array(ledCount) + .fill(undefined) + .map((_, i) => { + const ref = createRef(); + const n = ( + + ); + return [n, ref] as [ReactNode, RefObject]; + }) + .reduce( + ([nList, refList], [n, ref]) => [ + [...nList, n], + [...refList, ref], + ], + [[], []] as [ReactNode[], RefObject[]], + ), + [ledCount], + ); + + // start and moving + const handleMouseDown: MouseEventHandler = useCallback( + (ev) => { + startXRef.current = ev.pageX; + ev.currentTarget.requestPointerLock(); + isDragRef.current = true; + logger('handleMouseDown, config: %o', config); + + const placeholderPositions = placeholderRefs.map((it) => { + if (!it.current) { + return [0, 0]; + } + const viewportOffset = it.current.getBoundingClientRect(); + return [viewportOffset.left, viewportOffset.right] as [number, number]; + }); + + logger('placeholderPositions: %o', placeholderPositions); + + // set init position + const initPos = placeholderPositions.findIndex( + ([l, r]) => l <= ev.pageX && r >= ev.pageX, + ); + let prevMatch = 0; + + if (handleMouseMoveRef.current) { + document.body.removeEventListener('mousemove', handleMouseMoveRef.current); + } + handleMouseMoveRef.current = (ev) => { + if (!isDragRef.current) { + return; + } + currentXRef.current = ev.pageX; + setBoxTranslateX(currentXRef.current - startXRef.current); + const match = placeholderPositions.findIndex( + ([l, r]) => l <= currentXRef.current && r >= currentXRef.current, + ); + if (match === -1) { + return; + } + + if (match === prevMatch) { + return; + } + prevMatch = match; + + const diff = match - initPos; + const newValue: LedStripConfig = { + ...config, + global_start_position: config.global_start_position + diff, + global_end_position: config.global_end_position + diff, + }; + configRef.current = newValue; + setAvailableConfig(newValue); + logger('change config. old: %o, new: %o', config, newValue); + onConfigChange?.(newValue); + }; + document.body.addEventListener('mousemove', handleMouseMoveRef.current); + }, + [placeholderRefs, availableConfig, setAvailableConfig, config], + ); + + // move event. + useEffect(() => { + const handleMouseUp = (ev: MouseEvent) => { + if (configRef.current && isDragRef.current) { + onConfigFinish?.(configRef.current); + } + startXRef.current = 0; + isDragRef.current = false; + document.exitPointerLock(); + if (handleMouseMoveRef.current) { + document.body.removeEventListener('mousemove', handleMouseMoveRef.current); + } + }; + document.body.addEventListener('mouseup', handleMouseUp); + return () => { + document.body.removeEventListener('mouseup', handleMouseUp); + }; + }, [onConfigFinish]); + // reset translateX when config updated. + useEffect(() => { + startXRef.current = currentXRef.current; + setAvailableConfig(config); + setBoxTranslateX(0); + logger('useEffect, config: %o', config); + }, [config]); + + return ( + + {placeholders} + {ledItems} +
+
+ ); +}; diff --git a/src/configurator/components/led-strip-editor.tsx b/src/configurator/components/led-strip-editor.tsx index f88ce86..2a88d06 100644 --- a/src/configurator/components/led-strip-editor.tsx +++ b/src/configurator/components/led-strip-editor.tsx @@ -1,7 +1,7 @@ import { HTMLAttributes, useCallback } from 'react'; import { FC } from 'react'; import { LedStripConfig } from '../models/led-strip-config'; -import tw, { css, styled, theme } from 'twin.macro'; +import tw, { styled } from 'twin.macro'; import { faLeftRight, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -52,6 +52,9 @@ export const LedStripEditor: FC = ({ + {`s: ${config?.global_start_position ?? 'x'}, e: ${ + config?.global_end_position ?? 'x' + }`} ); }; diff --git a/src/configurator/configurator.tsx b/src/configurator/configurator.tsx index 882d274..7f20802 100644 --- a/src/configurator/configurator.tsx +++ b/src/configurator/configurator.tsx @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api'; -import { FC, Fragment, useCallback, useEffect, useMemo, useState } from 'react'; +import { FC, useEffect, useMemo, useState } from 'react'; import tw, { styled } from 'twin.macro'; import { useAsync, useAsyncCallback } from 'react-async-hook'; import { DisplayWithLedStrips } from './components/display-with-led-strips'; @@ -12,6 +12,9 @@ import { faSpinner } from '@fortawesome/free-solid-svg-icons'; import { update } from 'ramda'; import { CompletedLedStrip } from './components/completed-led-strip'; import { LedCountProvider } from './contents/led-count'; +import debug from 'debug'; + +const logger = debug('app:configurator'); const getPickerConfig = () => invoke('get_picker_config'); const getScreenshotOfDisplays = () =>