diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx index 6811b5b..3683356 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx @@ -9,14 +9,11 @@ import useDrag from '@theatre/studio/uiComponents/useDrag' import useRefAndState from '@theatre/studio/utils/useRefAndState' import {val} from '@theatre/dataverse' import {lighten} from 'polished' -import React, {useMemo, useRef} from 'react' +import React, {useMemo, useRef, useState} from 'react' import styled from 'styled-components' import type KeyframeEditor from './KeyframeEditor' -import type {FrameStampPositionLock} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' -import { - attributeNameThatLocksFramestamp, - useFrameStampPosition, -} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' +import {useLockFrameStampPosition} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' +import {attributeNameThatLocksFramestamp} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' export const dotSize = 6 const hitZoneSize = 12 @@ -112,7 +109,8 @@ function useKeyframeContextMenu(node: HTMLDivElement | null, props: IProps) { } function useDragKeyframe(node: HTMLDivElement | null, props: IProps) { - const {getLock} = useFrameStampPosition() + const [isDragging, setIsDragging] = useState(false) + useLockFrameStampPosition(isDragging, props.keyframe.position) const propsRef = useRef(props) propsRef.current = props @@ -121,7 +119,6 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) { let toUnitSpace: SequenceEditorPanelLayout['scaledSpace']['toUnitSpace'] let tempTransaction: CommitOrDiscard | undefined let propsAtStartOfDrag: IProps - let frameStampPositionLock: FrameStampPositionLock let selectionDragHandlers: | ReturnType @@ -130,6 +127,7 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) { return { lockCursorTo: 'ew-resize', onDragStart(event) { + setIsDragging(true) if (propsRef.current.selection) { const {selection, leaf} = propsRef.current const {sheetObject} = leaf @@ -145,9 +143,6 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) { propsAtStartOfDrag = propsRef.current toUnitSpace = val(propsAtStartOfDrag.layoutP.scaledSpace.toUnitSpace) - - frameStampPositionLock = getLock() - frameStampPositionLock.set(propsAtStartOfDrag.keyframe.position) }, onDrag(dx, dy, event) { if (selectionDragHandlers) { @@ -155,9 +150,6 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) { return } const delta = toUnitSpace(dx) - const original = - propsAtStartOfDrag.trackData.keyframes[propsAtStartOfDrag.index] - frameStampPositionLock.set(original.position + delta) if (tempTransaction) { tempTransaction.discard() @@ -177,7 +169,7 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) { }) }, onDragEnd(dragHappened) { - frameStampPositionLock.unlock() + setIsDragging(false) if (selectionDragHandlers) { selectionDragHandlers.onDragEnd?.(dragHappened) diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/LengthIndicator.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/LengthIndicator.tsx index 5a8c9d3..9e636c1 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/LengthIndicator.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/LengthIndicator.tsx @@ -1,8 +1,7 @@ import {usePrism} from '@theatre/dataverse-react' import type {Pointer} from '@theatre/dataverse' -import {Box} from '@theatre/dataverse' import {val} from '@theatre/dataverse' -import React, {useMemo, useRef} from 'react' +import React, {useMemo, useRef, useState} from 'react' import styled from 'styled-components' import type {SequenceEditorPanelLayout} from '@theatre/studio/panels/SequenceEditorPanel/layout/layout' import {zIndexes} from '@theatre/studio/panels/SequenceEditorPanel/SequenceEditorPanel' @@ -13,7 +12,10 @@ import useDrag from '@theatre/studio/uiComponents/useDrag' import getStudio from '@theatre/studio/getStudio' import type Sheet from '@theatre/core/sheets/Sheet' import usePopover from '@theatre/studio/uiComponents/Popover/usePopover' -import {attributeNameThatLocksFramestamp} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' +import { + attributeNameThatLocksFramestamp, + useLockFrameStampPosition, +} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' const coverWidth = 1000 @@ -159,7 +161,9 @@ const LengthIndicator: React.FC = ({layoutP}) => { function useDragBulge(node: HTMLDivElement | null, props: IProps) { const propsRef = useRef(props) propsRef.current = props - const isDragging = useMemo(() => new Box(false), []) + const [isDragging, setIsDragging] = useState(false) + + useLockFrameStampPosition(isDragging, -1) const gestureHandlers = useMemo[1]>(() => { let toUnitSpace: SequenceEditorPanelLayout['scaledSpace']['toUnitSpace'] @@ -171,12 +175,12 @@ function useDragBulge(node: HTMLDivElement | null, props: IProps) { return { lockCursorTo: 'ew-resize', onDragStart(event) { + setIsDragging(true) propsAtStartOfDrag = propsRef.current sheet = val(propsRef.current.layoutP.sheet) initialLength = sheet.getSequence().length toUnitSpace = val(propsAtStartOfDrag.layoutP.scaledSpace.toUnitSpace) - isDragging.set(true) }, onDrag(dx, dy, event) { const delta = toUnitSpace(dx) @@ -192,7 +196,7 @@ function useDragBulge(node: HTMLDivElement | null, props: IProps) { }) }, onDragEnd(dragHappened) { - isDragging.set(false) + setIsDragging(false) if (dragHappened) { if (tempTransaction) { tempTransaction.commit() @@ -209,7 +213,7 @@ function useDragBulge(node: HTMLDivElement | null, props: IProps) { useDrag(node, gestureHandlers) - return [isDragging.derivation] + return [isDragging] } export default LengthIndicator diff --git a/theatre/studio/src/panels/SequenceEditorPanel/FrameStampPositionProvider.tsx b/theatre/studio/src/panels/SequenceEditorPanel/FrameStampPositionProvider.tsx index 6c9bcf8..551d2b0 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/FrameStampPositionProvider.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/FrameStampPositionProvider.tsx @@ -3,10 +3,17 @@ import {Atom, prism, val} from '@theatre/dataverse' import mousePositionD from '@theatre/studio/utils/mousePositionD' import type {$IntentionalAny} from '@theatre/shared/utils/types' import {inRange, last} from 'lodash-es' -import React, {createContext, useCallback, useContext, useMemo} from 'react' +import React, { + createContext, + useCallback, + useContext, + useLayoutEffect, + useMemo, + useRef, +} from 'react' import type {SequenceEditorPanelLayout} from './layout/layout' -export type FrameStampPositionLock = { +type FrameStampPositionLock = { unlock: () => void set: (pointerPositonInUnitSpace: number) => void } @@ -93,7 +100,27 @@ const FrameStampPositionProvider: React.FC<{ return {children} } -export const useFrameStampPosition = () => useContext(context) +export const useFrameStampPositionD = () => useContext(context).currentD + +export const useLockFrameStampPosition = (shouldLock: boolean, val: number) => { + const {getLock} = useContext(context) + const lockRef = useRef>() + + useLayoutEffect(() => { + if (!shouldLock) return + lockRef.current = getLock() + + return () => { + lockRef.current!.unlock() + } + }, [shouldLock]) + + useLayoutEffect(() => { + if (shouldLock) { + lockRef.current!.set(val) + } + }, [val]) +} /** * This attribute is used so that when the cursor hovers over a keyframe, @@ -129,8 +156,6 @@ const pointerPositionInUnitSpace = ( } } - // if (mousePos.composedPath()) - const {clientX, clientY} = mousePos const {screenX: x, screenY: y, width: rightWidth, height} = rightDims diff --git a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/Dot.tsx b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/Dot.tsx index 58b4526..188f902 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/Dot.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/Dot.tsx @@ -6,13 +6,12 @@ import useDrag from '@theatre/studio/uiComponents/useDrag' import useRefAndState from '@theatre/studio/utils/useRefAndState' import type {VoidFn} from '@theatre/shared/utils/types' import {val} from '@theatre/dataverse' -import React, {useMemo, useRef} from 'react' +import React, {useMemo, useRef, useState} from 'react' import styled from 'styled-components' import type KeyframeEditor from './KeyframeEditor' import type {Keyframe} from '@theatre/core/projects/store/types/SheetState_Historic' -import type {FrameStampPositionLock} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' +import {useLockFrameStampPosition} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' import {attributeNameThatLocksFramestamp} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' -import {useFrameStampPosition} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' export const dotSize = 6 @@ -80,7 +79,8 @@ const Dot: React.FC = (props) => { export default Dot function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void { - const {getLock} = useFrameStampPosition() + const [isDragging, setIsDragging] = useState(false) + useLockFrameStampPosition(isDragging, _props.keyframe.position) const propsRef = useRef(_props) propsRef.current = _props @@ -92,11 +92,11 @@ function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void { let verticalToExtremumSpace: SequenceEditorPanelLayout['graphEditorVerticalSpace']['toExtremumSpace'] let unlockExtremums: VoidFn | undefined let keepSpeeds = false - let frameStampPositionLock: FrameStampPositionLock return { lockCursorTo: 'move', onDragStart(event) { + setIsDragging(true) keepSpeeds = !!event.altKey propsAtStartOfDrag = propsRef.current @@ -106,8 +106,6 @@ function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void { propsAtStartOfDrag.layoutP.graphEditorVerticalSpace.toExtremumSpace, ) unlockExtremums = propsAtStartOfDrag.extremumSpace.lock() - frameStampPositionLock = getLock() - frameStampPositionLock.set(propsAtStartOfDrag.keyframe.position) }, onDrag(dx, dy) { const original = @@ -128,7 +126,6 @@ function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void { value: original.value + dYInValueSpace, handles: [...original.handles], } - frameStampPositionLock.set(cur.position) updatedKeyframes.push(cur) if (keepSpeeds) { @@ -189,7 +186,7 @@ function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void { }) }, onDragEnd(dragHappened) { - frameStampPositionLock.unlock() + setIsDragging(false) if (unlockExtremums) { const unlock = unlockExtremums unlockExtremums = undefined diff --git a/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/FrameStamp.tsx b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/FrameStamp.tsx index e2dd25f..e7bc5d4 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/FrameStamp.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/FrameStamp.tsx @@ -7,7 +7,7 @@ import styled from 'styled-components' import {stampsGridTheme} from '@theatre/studio/panels/SequenceEditorPanel/FrameGrid/StampsGrid' import {zIndexes} from '@theatre/studio/panels/SequenceEditorPanel/SequenceEditorPanel' import {topStripTheme} from './TopStrip' -import {useFrameStampPosition} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' +import {useFrameStampPositionD} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' const Label = styled.div` position: absolute; @@ -36,7 +36,7 @@ const Line = styled.div` const FrameStamp: React.FC<{ layoutP: Pointer }> = React.memo(({layoutP}) => { - const posInUnitSpace = useVal(useFrameStampPosition().currentD) + const posInUnitSpace = useVal(useFrameStampPositionD()) const unitSpaceToClippedSpace = useVal(layoutP.clippedSpace.fromUnitSpace) const {sequence, formatter, clippedSpaceWidth} = usePrism(() => { const sequence = val(layoutP.sheet).getSequence()