LengthIndicator is now draggable
This commit is contained in:
parent
acf0283449
commit
c6c37992ac
1 changed files with 98 additions and 20 deletions
|
@ -1,24 +1,20 @@
|
|||
import {usePrism} from '@theatre/dataverse-react'
|
||||
import type {Pointer} from '@theatre/dataverse'
|
||||
import {Box} from '@theatre/dataverse'
|
||||
import {val} from '@theatre/dataverse'
|
||||
import React from 'react'
|
||||
import React, {useMemo, useRef} 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'
|
||||
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 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`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -26,7 +22,7 @@ const Strip = styled.div`
|
|||
width: 4px;
|
||||
z-index: ${() => zIndexes.lengthIndicatorStrip};
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
cursor: ew-resize;
|
||||
|
||||
&:after {
|
||||
display: block;
|
||||
|
@ -39,7 +35,8 @@ const Strip = styled.div`
|
|||
background-color: #000000a6;
|
||||
}
|
||||
|
||||
&:hover:after {
|
||||
&:hover:after,
|
||||
&.dragging:after {
|
||||
background-color: #000000;
|
||||
}
|
||||
`
|
||||
|
@ -49,23 +46,43 @@ const Info = styled.div`
|
|||
top: ${topStripHeight + 4}px;
|
||||
font-size: 10px;
|
||||
left: 4px;
|
||||
color: gray;
|
||||
color: #eee;
|
||||
white-space: nowrap;
|
||||
display: none;
|
||||
|
||||
${Strip}:hover & {
|
||||
${Strip}:hover &, ${Strip}.dragging & {
|
||||
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}) => {
|
||||
}
|
||||
|
||||
const LengthIndicator: React.FC<IProps> = ({layoutP}) => {
|
||||
const [stripRef, stripNode] = useRefAndState<HTMLDivElement | null>(null)
|
||||
const [isDraggingD] = useDragStrip(stripNode, {layoutP})
|
||||
|
||||
return usePrism(() => {
|
||||
const sheet = val(layoutP.sheet)
|
||||
const height = val(layoutP.rightDims.height)
|
||||
|
||||
const sequenceLength = sheet.getSequence().length
|
||||
const sequence = sheet.getSequence()
|
||||
const sequenceLength = sequence.length
|
||||
const startInUnitSpace = sequenceLength
|
||||
|
||||
let startX = val(layoutP.clippedSpace.fromUnitSpace)(startInUnitSpace)
|
||||
|
@ -86,12 +103,17 @@ const LengthIndicator: React.FC<{
|
|||
<>
|
||||
<Strip
|
||||
title="Change Sequence Length"
|
||||
ref={stripRef}
|
||||
style={{
|
||||
height: height + '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>
|
||||
<Cover
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue