LengthIndicator is now draggable

This commit is contained in:
Aria Minaei 2021-08-01 09:55:43 +02:00
parent acf0283449
commit c6c37992ac

View file

@ -1,24 +1,20 @@
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 from 'react' import React, {useMemo, useRef} 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'
import {topStripHeight} from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/TopStrip' import {topStripHeight} from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/TopStrip'
import useRefAndState from '@theatre/studio/utils/useRefAndState'
import type {CommitOrDiscard} from '@theatre/studio/StudioStore/StudioStore'
import useDrag from '@theatre/studio/uiComponents/useDrag'
import getStudio from '@theatre/studio/getStudio'
import type Sheet from '@theatre/core/sheets/Sheet'
const coverWidth = 1000 const coverWidth = 1000
const Cover = styled.div`
position: absolute;
top: 0;
left: 0;
background-color: rgb(23 23 23 / 43%);
width: ${coverWidth}px;
z-index: ${() => zIndexes.lengthIndicatorCover};
transform-origin: left top;
`
const Strip = styled.div` const Strip = styled.div`
position: absolute; position: absolute;
top: 0; top: 0;
@ -26,7 +22,7 @@ const Strip = styled.div`
width: 4px; width: 4px;
z-index: ${() => zIndexes.lengthIndicatorStrip}; z-index: ${() => zIndexes.lengthIndicatorStrip};
pointer-events: auto; pointer-events: auto;
cursor: pointer; cursor: ew-resize;
&:after { &:after {
display: block; display: block;
@ -39,7 +35,8 @@ const Strip = styled.div`
background-color: #000000a6; background-color: #000000a6;
} }
&:hover:after { &:hover:after,
&.dragging:after {
background-color: #000000; background-color: #000000;
} }
` `
@ -49,23 +46,43 @@ const Info = styled.div`
top: ${topStripHeight + 4}px; top: ${topStripHeight + 4}px;
font-size: 10px; font-size: 10px;
left: 4px; left: 4px;
color: gray; color: #eee;
white-space: nowrap; white-space: nowrap;
display: none; display: none;
${Strip}:hover & { ${Strip}:hover &, ${Strip}.dragging & {
display: block; display: block;
} }
` `
const LengthIndicator: React.FC<{ const Cover = styled.div`
position: absolute;
top: 0;
left: 0;
background-color: rgb(23 23 23 / 43%);
width: ${coverWidth}px;
z-index: ${() => zIndexes.lengthIndicatorCover};
transform-origin: left top;
${Strip}:hover ~ &, ${Strip}.dragging ~ & {
background-color: rgb(23 23 23 / 60%);
}
`
type IProps = {
layoutP: Pointer<SequenceEditorPanelLayout> layoutP: Pointer<SequenceEditorPanelLayout>
}> = ({layoutP}) => { }
const LengthIndicator: React.FC<IProps> = ({layoutP}) => {
const [stripRef, stripNode] = useRefAndState<HTMLDivElement | null>(null)
const [isDraggingD] = useDragStrip(stripNode, {layoutP})
return usePrism(() => { return usePrism(() => {
const sheet = val(layoutP.sheet) const sheet = val(layoutP.sheet)
const height = val(layoutP.rightDims.height) const height = val(layoutP.rightDims.height)
const sequenceLength = sheet.getSequence().length const sequence = sheet.getSequence()
const sequenceLength = sequence.length
const startInUnitSpace = sequenceLength const startInUnitSpace = sequenceLength
let startX = val(layoutP.clippedSpace.fromUnitSpace)(startInUnitSpace) let startX = val(layoutP.clippedSpace.fromUnitSpace)(startInUnitSpace)
@ -86,12 +103,17 @@ const LengthIndicator: React.FC<{
<> <>
<Strip <Strip
title="Change Sequence Length" title="Change Sequence Length"
ref={stripRef}
style={{ style={{
height: height + 'px', height: height + 'px',
transform: `translateX(${translateX === 0 ? -1000 : translateX}px)`, transform: `translateX(${translateX === 0 ? -1000 : translateX}px)`,
}} }}
className={val(isDraggingD) ? 'dragging' : ''}
> >
<Info>Sequence Length: {sequenceLength}</Info> <Info>
sequence.length:{' '}
{sequence.positionFormatter.formatForPlayhead(sequenceLength)}
</Info>
</Strip> </Strip>
<Cover <Cover
title="Length" title="Length"
@ -110,7 +132,63 @@ const LengthIndicator: React.FC<{
/> />
</> </>
) )
}, [layoutP]) }, [layoutP, stripRef, isDraggingD])
}
function useDragStrip(node: HTMLDivElement | null, props: IProps) {
const propsRef = useRef(props)
propsRef.current = props
const isDragging = useMemo(() => new Box(false), [])
const gestureHandlers = useMemo<Parameters<typeof useDrag>[1]>(() => {
let toUnitSpace: SequenceEditorPanelLayout['scaledSpace']['toUnitSpace']
let tempTransaction: CommitOrDiscard | undefined
let propsAtStartOfDrag: IProps
let sheet: Sheet
let initialLength: number
return {
lockCursorTo: 'ew-resize',
onDragStart(event) {
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)
if (tempTransaction) {
tempTransaction.discard()
tempTransaction = undefined
}
tempTransaction = getStudio()!.tempTransaction(({stateEditors}) => {
stateEditors.coreByProject.historic.sheetsById.sequence.setLength({
...sheet.address,
length: initialLength + delta,
})
})
},
onDragEnd(dragHappened) {
isDragging.set(false)
if (dragHappened) {
if (tempTransaction) {
tempTransaction.commit()
}
} else {
if (tempTransaction) {
tempTransaction.discard()
}
}
tempTransaction = undefined
},
}
}, [])
useDrag(node, gestureHandlers)
return [isDragging.derivation]
} }
export default LengthIndicator export default LengthIndicator