Cleaner API for useFrameStampPosition()

This commit is contained in:
Aria Minaei 2021-08-01 18:09:07 +02:00
parent 0a3c699180
commit 74b6f93872
5 changed files with 56 additions and 38 deletions

View file

@ -9,14 +9,11 @@ import useDrag from '@theatre/studio/uiComponents/useDrag'
import useRefAndState from '@theatre/studio/utils/useRefAndState' import useRefAndState from '@theatre/studio/utils/useRefAndState'
import {val} from '@theatre/dataverse' import {val} from '@theatre/dataverse'
import {lighten} from 'polished' import {lighten} from 'polished'
import React, {useMemo, useRef} from 'react' import React, {useMemo, useRef, useState} from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import type KeyframeEditor from './KeyframeEditor' import type KeyframeEditor from './KeyframeEditor'
import type {FrameStampPositionLock} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' import {useLockFrameStampPosition} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider'
import { import {attributeNameThatLocksFramestamp} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider'
attributeNameThatLocksFramestamp,
useFrameStampPosition,
} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider'
export const dotSize = 6 export const dotSize = 6
const hitZoneSize = 12 const hitZoneSize = 12
@ -112,7 +109,8 @@ function useKeyframeContextMenu(node: HTMLDivElement | null, props: IProps) {
} }
function useDragKeyframe(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) const propsRef = useRef(props)
propsRef.current = props propsRef.current = props
@ -121,7 +119,6 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) {
let toUnitSpace: SequenceEditorPanelLayout['scaledSpace']['toUnitSpace'] let toUnitSpace: SequenceEditorPanelLayout['scaledSpace']['toUnitSpace']
let tempTransaction: CommitOrDiscard | undefined let tempTransaction: CommitOrDiscard | undefined
let propsAtStartOfDrag: IProps let propsAtStartOfDrag: IProps
let frameStampPositionLock: FrameStampPositionLock
let selectionDragHandlers: let selectionDragHandlers:
| ReturnType<DopeSheetSelection['getDragHandlers']> | ReturnType<DopeSheetSelection['getDragHandlers']>
@ -130,6 +127,7 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) {
return { return {
lockCursorTo: 'ew-resize', lockCursorTo: 'ew-resize',
onDragStart(event) { onDragStart(event) {
setIsDragging(true)
if (propsRef.current.selection) { if (propsRef.current.selection) {
const {selection, leaf} = propsRef.current const {selection, leaf} = propsRef.current
const {sheetObject} = leaf const {sheetObject} = leaf
@ -145,9 +143,6 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) {
propsAtStartOfDrag = propsRef.current propsAtStartOfDrag = propsRef.current
toUnitSpace = val(propsAtStartOfDrag.layoutP.scaledSpace.toUnitSpace) toUnitSpace = val(propsAtStartOfDrag.layoutP.scaledSpace.toUnitSpace)
frameStampPositionLock = getLock()
frameStampPositionLock.set(propsAtStartOfDrag.keyframe.position)
}, },
onDrag(dx, dy, event) { onDrag(dx, dy, event) {
if (selectionDragHandlers) { if (selectionDragHandlers) {
@ -155,9 +150,6 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) {
return return
} }
const delta = toUnitSpace(dx) const delta = toUnitSpace(dx)
const original =
propsAtStartOfDrag.trackData.keyframes[propsAtStartOfDrag.index]
frameStampPositionLock.set(original.position + delta)
if (tempTransaction) { if (tempTransaction) {
tempTransaction.discard() tempTransaction.discard()
@ -177,7 +169,7 @@ function useDragKeyframe(node: HTMLDivElement | null, props: IProps) {
}) })
}, },
onDragEnd(dragHappened) { onDragEnd(dragHappened) {
frameStampPositionLock.unlock() setIsDragging(false)
if (selectionDragHandlers) { if (selectionDragHandlers) {
selectionDragHandlers.onDragEnd?.(dragHappened) selectionDragHandlers.onDragEnd?.(dragHappened)

View file

@ -1,8 +1,7 @@
import {usePrism} from '@theatre/dataverse-react' import {usePrism} from '@theatre/dataverse-react'
import type {Pointer} from '@theatre/dataverse' import type {Pointer} from '@theatre/dataverse'
import {Box} from '@theatre/dataverse'
import {val} 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 styled from 'styled-components'
import type {SequenceEditorPanelLayout} from '@theatre/studio/panels/SequenceEditorPanel/layout/layout' import type {SequenceEditorPanelLayout} from '@theatre/studio/panels/SequenceEditorPanel/layout/layout'
import {zIndexes} from '@theatre/studio/panels/SequenceEditorPanel/SequenceEditorPanel' 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 getStudio from '@theatre/studio/getStudio'
import type Sheet from '@theatre/core/sheets/Sheet' import type Sheet from '@theatre/core/sheets/Sheet'
import usePopover from '@theatre/studio/uiComponents/Popover/usePopover' 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 const coverWidth = 1000
@ -159,7 +161,9 @@ const LengthIndicator: React.FC<IProps> = ({layoutP}) => {
function useDragBulge(node: HTMLDivElement | null, props: IProps) { function useDragBulge(node: HTMLDivElement | null, props: IProps) {
const propsRef = useRef(props) const propsRef = useRef(props)
propsRef.current = props propsRef.current = props
const isDragging = useMemo(() => new Box(false), []) const [isDragging, setIsDragging] = useState(false)
useLockFrameStampPosition(isDragging, -1)
const gestureHandlers = useMemo<Parameters<typeof useDrag>[1]>(() => { const gestureHandlers = useMemo<Parameters<typeof useDrag>[1]>(() => {
let toUnitSpace: SequenceEditorPanelLayout['scaledSpace']['toUnitSpace'] let toUnitSpace: SequenceEditorPanelLayout['scaledSpace']['toUnitSpace']
@ -171,12 +175,12 @@ function useDragBulge(node: HTMLDivElement | null, props: IProps) {
return { return {
lockCursorTo: 'ew-resize', lockCursorTo: 'ew-resize',
onDragStart(event) { onDragStart(event) {
setIsDragging(true)
propsAtStartOfDrag = propsRef.current propsAtStartOfDrag = propsRef.current
sheet = val(propsRef.current.layoutP.sheet) sheet = val(propsRef.current.layoutP.sheet)
initialLength = sheet.getSequence().length initialLength = sheet.getSequence().length
toUnitSpace = val(propsAtStartOfDrag.layoutP.scaledSpace.toUnitSpace) toUnitSpace = val(propsAtStartOfDrag.layoutP.scaledSpace.toUnitSpace)
isDragging.set(true)
}, },
onDrag(dx, dy, event) { onDrag(dx, dy, event) {
const delta = toUnitSpace(dx) const delta = toUnitSpace(dx)
@ -192,7 +196,7 @@ function useDragBulge(node: HTMLDivElement | null, props: IProps) {
}) })
}, },
onDragEnd(dragHappened) { onDragEnd(dragHappened) {
isDragging.set(false) setIsDragging(false)
if (dragHappened) { if (dragHappened) {
if (tempTransaction) { if (tempTransaction) {
tempTransaction.commit() tempTransaction.commit()
@ -209,7 +213,7 @@ function useDragBulge(node: HTMLDivElement | null, props: IProps) {
useDrag(node, gestureHandlers) useDrag(node, gestureHandlers)
return [isDragging.derivation] return [isDragging]
} }
export default LengthIndicator export default LengthIndicator

View file

@ -3,10 +3,17 @@ import {Atom, prism, val} from '@theatre/dataverse'
import mousePositionD from '@theatre/studio/utils/mousePositionD' import mousePositionD from '@theatre/studio/utils/mousePositionD'
import type {$IntentionalAny} from '@theatre/shared/utils/types' import type {$IntentionalAny} from '@theatre/shared/utils/types'
import {inRange, last} from 'lodash-es' 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' import type {SequenceEditorPanelLayout} from './layout/layout'
export type FrameStampPositionLock = { type FrameStampPositionLock = {
unlock: () => void unlock: () => void
set: (pointerPositonInUnitSpace: number) => void set: (pointerPositonInUnitSpace: number) => void
} }
@ -93,7 +100,27 @@ const FrameStampPositionProvider: React.FC<{
return <context.Provider value={value}>{children}</context.Provider> return <context.Provider value={value}>{children}</context.Provider>
} }
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<undefined | ReturnType<typeof getLock>>()
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, * 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 {clientX, clientY} = mousePos
const {screenX: x, screenY: y, width: rightWidth, height} = rightDims const {screenX: x, screenY: y, width: rightWidth, height} = rightDims

View file

@ -6,13 +6,12 @@ import useDrag from '@theatre/studio/uiComponents/useDrag'
import useRefAndState from '@theatre/studio/utils/useRefAndState' import useRefAndState from '@theatre/studio/utils/useRefAndState'
import type {VoidFn} from '@theatre/shared/utils/types' import type {VoidFn} from '@theatre/shared/utils/types'
import {val} 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 styled from 'styled-components'
import type KeyframeEditor from './KeyframeEditor' import type KeyframeEditor from './KeyframeEditor'
import type {Keyframe} from '@theatre/core/projects/store/types/SheetState_Historic' 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 {attributeNameThatLocksFramestamp} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider'
import {useFrameStampPosition} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider'
export const dotSize = 6 export const dotSize = 6
@ -80,7 +79,8 @@ const Dot: React.FC<IProps> = (props) => {
export default Dot export default Dot
function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void { 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) const propsRef = useRef(_props)
propsRef.current = _props propsRef.current = _props
@ -92,11 +92,11 @@ function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void {
let verticalToExtremumSpace: SequenceEditorPanelLayout['graphEditorVerticalSpace']['toExtremumSpace'] let verticalToExtremumSpace: SequenceEditorPanelLayout['graphEditorVerticalSpace']['toExtremumSpace']
let unlockExtremums: VoidFn | undefined let unlockExtremums: VoidFn | undefined
let keepSpeeds = false let keepSpeeds = false
let frameStampPositionLock: FrameStampPositionLock
return { return {
lockCursorTo: 'move', lockCursorTo: 'move',
onDragStart(event) { onDragStart(event) {
setIsDragging(true)
keepSpeeds = !!event.altKey keepSpeeds = !!event.altKey
propsAtStartOfDrag = propsRef.current propsAtStartOfDrag = propsRef.current
@ -106,8 +106,6 @@ function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void {
propsAtStartOfDrag.layoutP.graphEditorVerticalSpace.toExtremumSpace, propsAtStartOfDrag.layoutP.graphEditorVerticalSpace.toExtremumSpace,
) )
unlockExtremums = propsAtStartOfDrag.extremumSpace.lock() unlockExtremums = propsAtStartOfDrag.extremumSpace.lock()
frameStampPositionLock = getLock()
frameStampPositionLock.set(propsAtStartOfDrag.keyframe.position)
}, },
onDrag(dx, dy) { onDrag(dx, dy) {
const original = const original =
@ -128,7 +126,6 @@ function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void {
value: original.value + dYInValueSpace, value: original.value + dYInValueSpace,
handles: [...original.handles], handles: [...original.handles],
} }
frameStampPositionLock.set(cur.position)
updatedKeyframes.push(cur) updatedKeyframes.push(cur)
if (keepSpeeds) { if (keepSpeeds) {
@ -189,7 +186,7 @@ function useDragKeyframe(node: SVGCircleElement | null, _props: IProps): void {
}) })
}, },
onDragEnd(dragHappened) { onDragEnd(dragHappened) {
frameStampPositionLock.unlock() setIsDragging(false)
if (unlockExtremums) { if (unlockExtremums) {
const unlock = unlockExtremums const unlock = unlockExtremums
unlockExtremums = undefined unlockExtremums = undefined

View file

@ -7,7 +7,7 @@ import styled from 'styled-components'
import {stampsGridTheme} from '@theatre/studio/panels/SequenceEditorPanel/FrameGrid/StampsGrid' import {stampsGridTheme} from '@theatre/studio/panels/SequenceEditorPanel/FrameGrid/StampsGrid'
import {zIndexes} from '@theatre/studio/panels/SequenceEditorPanel/SequenceEditorPanel' import {zIndexes} from '@theatre/studio/panels/SequenceEditorPanel/SequenceEditorPanel'
import {topStripTheme} from './TopStrip' import {topStripTheme} from './TopStrip'
import {useFrameStampPosition} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' import {useFrameStampPositionD} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider'
const Label = styled.div` const Label = styled.div`
position: absolute; position: absolute;
@ -36,7 +36,7 @@ const Line = styled.div`
const FrameStamp: React.FC<{ const FrameStamp: React.FC<{
layoutP: Pointer<SequenceEditorPanelLayout> layoutP: Pointer<SequenceEditorPanelLayout>
}> = React.memo(({layoutP}) => { }> = React.memo(({layoutP}) => {
const posInUnitSpace = useVal(useFrameStampPosition().currentD) const posInUnitSpace = useVal(useFrameStampPositionD())
const unitSpaceToClippedSpace = useVal(layoutP.clippedSpace.fromUnitSpace) const unitSpaceToClippedSpace = useVal(layoutP.clippedSpace.fromUnitSpace)
const {sequence, formatter, clippedSpaceWidth} = usePrism(() => { const {sequence, formatter, clippedSpaceWidth} = usePrism(() => {
const sequence = val(layoutP.sheet).getSequence() const sequence = val(layoutP.sheet).getSequence()