From 3f2a9032f147d1964a75a52a75da4a6910c94f22 Mon Sep 17 00:00:00 2001 From: Fulop <43729152+fulopkovacs@users.noreply.github.com> Date: Thu, 3 Mar 2022 09:54:54 +0100 Subject: [PATCH] Make it possible to move the playhead to an exact position (#92) --- .../RightOverlay/Playhead.tsx | 71 ++++++++++----- .../RightOverlay/PlayheadPositionPopover.tsx | 91 +++++++++++++++++++ 2 files changed, 138 insertions(+), 24 deletions(-) create mode 100644 theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/PlayheadPositionPopover.tsx diff --git a/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/Playhead.tsx b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/Playhead.tsx index ba0a130..33ac9b7 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/Playhead.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/Playhead.tsx @@ -16,6 +16,9 @@ import { useLockFrameStampPosition, } from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' import {pointerEventsAutoInNormalMode} from '@theatre/studio/css' +import usePopover from '@theatre/studio/uiComponents/Popover/usePopover' +import BasicPopover from '@theatre/studio/uiComponents/Popover/BasicPopover' +import PlayheadPositionPopover from './PlayheadPositionPopover' const Container = styled.div<{isVisible: boolean}>` --thumbColor: #00e0ff; @@ -150,6 +153,20 @@ const Playhead: React.FC<{layoutP: Pointer}> = ({ }) => { const [thumbRef, thumbNode] = useRefAndState(null) + const [popoverNode, openPopover, closePopover, isPopoverOpen] = usePopover( + {}, + () => { + return ( + + + + ) + }, + ) + const gestureHandlers = useMemo((): Parameters[1] => { const setIsSeeking = val(layoutP.seeker.setIsSeeking) @@ -215,32 +232,38 @@ const Playhead: React.FC<{layoutP: Pointer}> = ({ posInClippedSpace <= val(layoutP.clippedSpace.width) return ( - - - - - - {sequence.positionFormatter.formatForPlayhead( - sequence.closestGridPosition(posInUnitSpace), - )} - - - - + {popoverNode} + - + {...{[attributeNameThatLocksFramestamp]: 'hide'}} + > + { + openPopover(e, thumbNode!) + }} + > + + + + {sequence.positionFormatter.formatForPlayhead( + sequence.closestGridPosition(posInUnitSpace), + )} + + + + + + ) - }, [layoutP]) + }, [layoutP, thumbRef, popoverNode]) } export default Playhead diff --git a/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/PlayheadPositionPopover.tsx b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/PlayheadPositionPopover.tsx new file mode 100644 index 0000000..15ffa15 --- /dev/null +++ b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/PlayheadPositionPopover.tsx @@ -0,0 +1,91 @@ +import styled from 'styled-components' +import type {SequenceEditorPanelLayout} from '@theatre/studio/panels/SequenceEditorPanel/layout/layout' +import {usePrism} from '@theatre/react' +import type {BasicNumberInputNudgeFn} from '@theatre/studio/uiComponents/form/BasicNumberInput' +import BasicNumberInput from '@theatre/studio/uiComponents/form/BasicNumberInput' +import {propNameText} from '@theatre/studio/panels/DetailPanel/propEditors/utils/SingleRowPropEditor' +import {useLayoutEffect, useMemo, useRef} from 'react' +import React from 'react' +import {val} from '@theatre/dataverse' +import type {Pointer} from '@theatre/dataverse' +import clamp from 'lodash-es/clamp' + +const greaterThanZero = (v: number) => isFinite(v) && v > 0 + +const Container = styled.div` + display: flex; + gap: 8px; + padding: 4px 8px; + height: 28px; + align-items: center; +` + +const Label = styled.div` + ${propNameText}; + white-space: nowrap; +` + +const nudge: BasicNumberInputNudgeFn = ({deltaX}) => deltaX * 0.25 + +const PlayheadPositionPopover: React.FC<{ + layoutP: Pointer + /** + * Called when user hits enter/escape + */ + onRequestClose: () => void +}> = ({layoutP, onRequestClose}) => { + const sheet = val(layoutP.sheet) + const sequence = sheet.getSequence() + + const fns = useMemo(() => { + let tempPosition: number | undefined + const originalPosition = sequence.position + + return { + temporarilySetValue(newPosition: number): void { + if (tempPosition) { + tempPosition = undefined + } + tempPosition = clamp(newPosition, 0, sequence.length) + sequence.position = tempPosition + }, + discardTemporaryValue(): void { + if (tempPosition) { + tempPosition = undefined + sequence.position = originalPosition + } + }, + permenantlySetValue(newPosition: number): void { + if (tempPosition) { + tempPosition = undefined + } + sequence.position = clamp(newPosition, 0, sequence.length) + }, + } + }, [layoutP, sequence]) + + const inputRef = useRef(null) + useLayoutEffect(() => { + inputRef.current!.focus() + }, []) + + return usePrism(() => { + const sequence = sheet.getSequence() + + return ( + + + + + ) + }, [sheet, fns, inputRef]) +} + +export default PlayheadPositionPopover