feat(289): Labeled markers (#362)
This commit is contained in:
parent
1fb69126fd
commit
4b4fe858f9
6 changed files with 137 additions and 3 deletions
|
@ -19,13 +19,16 @@ import type {UseDragOpts} from '@theatre/studio/uiComponents/useDrag'
|
|||
import type {CommitOrDiscard} from '@theatre/studio/StudioStore/StudioStore'
|
||||
import type {StudioHistoricStateSequenceEditorMarker} from '@theatre/studio/store/types'
|
||||
import {zIndexes} from '@theatre/studio/panels/SequenceEditorPanel/SequenceEditorPanel'
|
||||
import DopeSnap from './DopeSnap'
|
||||
import DopeSnap from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/DopeSnap'
|
||||
import {absoluteDims} from '@theatre/studio/utils/absoluteDims'
|
||||
import {DopeSnapHitZoneUI} from './DopeSnapHitZoneUI'
|
||||
import {DopeSnapHitZoneUI} from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/DopeSnapHitZoneUI'
|
||||
import {
|
||||
snapToAll,
|
||||
snapToNone,
|
||||
} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/KeyframeSnapTarget'
|
||||
import usePopover from '@theatre/studio/uiComponents/Popover/usePopover'
|
||||
import BasicPopover from '@theatre/studio/uiComponents/Popover/BasicPopover'
|
||||
import MarkerEditorPopover from './MarkerEditorPopover'
|
||||
|
||||
const MARKER_SIZE_W_PX = 12
|
||||
const MARKER_SIZE_H_PX = 12
|
||||
|
@ -164,11 +167,32 @@ const MarkerDotVisible: React.VFC<IMarkerDotVisibleProps> = ({
|
|||
marker,
|
||||
})
|
||||
|
||||
const {
|
||||
node: popoverNode,
|
||||
toggle: togglePopover,
|
||||
close: closePopover,
|
||||
} = usePopover({debugName: 'MarkerPopover'}, () => {
|
||||
return (
|
||||
<BasicPopover>
|
||||
<MarkerEditorPopover
|
||||
marker={marker}
|
||||
layoutP={layoutP}
|
||||
onRequestClose={closePopover}
|
||||
/>
|
||||
</BasicPopover>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextMenu}
|
||||
{popoverNode}
|
||||
<HitZone
|
||||
title={marker.label ? `Marker: ${marker.label}` : 'Marker'}
|
||||
ref={markRef}
|
||||
onClick={(e) => {
|
||||
togglePopover(e, markRef.current!)
|
||||
}}
|
||||
{...DopeSnapHitZoneUI.reactProps({
|
||||
isDragging,
|
||||
position: marker.position,
|
|
@ -0,0 +1,99 @@
|
|||
import type {Pointer} from '@theatre/dataverse'
|
||||
import React, {useLayoutEffect, useMemo, useRef} from 'react'
|
||||
import styled from 'styled-components'
|
||||
import type {SequenceEditorPanelLayout} from '@theatre/studio/panels/SequenceEditorPanel/layout/layout'
|
||||
import {useVal} from '@theatre/react'
|
||||
import getStudio from '@theatre/studio/getStudio'
|
||||
import type {BasicNumberInputNudgeFn} from '@theatre/studio/uiComponents/form/BasicNumberInput'
|
||||
import type {CommitOrDiscard} from '@theatre/studio/StudioStore/StudioStore'
|
||||
import {propNameTextCSS} from '@theatre/studio/propEditors/utils/propNameTextCSS'
|
||||
import type {StudioHistoricStateSequenceEditorMarker} from '@theatre/studio/store/types/historic'
|
||||
import BasicStringInput from '@theatre/studio/uiComponents/form/BasicStringInput'
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
/* padding: 4px 8px; */
|
||||
height: 28px;
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
const Label = styled.div`
|
||||
${propNameTextCSS};
|
||||
white-space: nowrap;
|
||||
`
|
||||
|
||||
const nudge: BasicNumberInputNudgeFn = ({deltaX}) => deltaX * 0.25
|
||||
|
||||
const MarkerEditorPopover: React.FC<{
|
||||
layoutP: Pointer<SequenceEditorPanelLayout>
|
||||
marker: StudioHistoricStateSequenceEditorMarker
|
||||
/**
|
||||
* Called when user hits enter/escape
|
||||
*/
|
||||
onRequestClose: (reason: string) => void
|
||||
}> = ({layoutP, marker}) => {
|
||||
const sheet = useVal(layoutP.sheet)
|
||||
|
||||
const fns = useMemo(() => {
|
||||
let tempTransaction: CommitOrDiscard | undefined
|
||||
|
||||
return {
|
||||
temporarilySetValue(newLabel: string): void {
|
||||
if (tempTransaction) {
|
||||
tempTransaction.discard()
|
||||
tempTransaction = undefined
|
||||
}
|
||||
tempTransaction = getStudio()!.tempTransaction(({stateEditors}) => {
|
||||
stateEditors.studio.historic.projects.stateByProjectId.stateBySheetId.sequenceEditor.updateMarker(
|
||||
{
|
||||
sheetAddress: sheet.address,
|
||||
markerId: marker.id,
|
||||
label: newLabel,
|
||||
},
|
||||
)
|
||||
})
|
||||
},
|
||||
discardTemporaryValue(): void {
|
||||
if (tempTransaction) {
|
||||
tempTransaction.discard()
|
||||
tempTransaction = undefined
|
||||
}
|
||||
},
|
||||
permanentlySetValue(newLabel: string): void {
|
||||
if (tempTransaction) {
|
||||
tempTransaction.discard()
|
||||
tempTransaction = undefined
|
||||
}
|
||||
getStudio()!.transaction(({stateEditors}) => {
|
||||
stateEditors.studio.historic.projects.stateByProjectId.stateBySheetId.sequenceEditor.updateMarker(
|
||||
{
|
||||
sheetAddress: sheet.address,
|
||||
markerId: marker.id,
|
||||
label: newLabel,
|
||||
},
|
||||
)
|
||||
})
|
||||
},
|
||||
}
|
||||
}, [layoutP, sheet])
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
useLayoutEffect(() => {
|
||||
inputRef.current!.focus()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{/* <Label>Marker</Label> */}
|
||||
<BasicStringInput
|
||||
value={marker.label ?? ''}
|
||||
{...fns}
|
||||
isValid={() => true}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default MarkerEditorPopover
|
|
@ -11,7 +11,7 @@ import HorizontalScrollbar from './HorizontalScrollbar'
|
|||
import Playhead from './Playhead'
|
||||
import TopStrip from './TopStrip'
|
||||
import FocusRangeCurtains from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/FocusRangeCurtains'
|
||||
import Markers from './Markers'
|
||||
import Markers from './Markers/Markers'
|
||||
|
||||
const Container = styled.div`
|
||||
position: absolute;
|
||||
|
|
|
@ -338,6 +338,16 @@ namespace stateEditors {
|
|||
pointableSetUtil.remove(currentMarkerSet, options.markerId),
|
||||
)
|
||||
}
|
||||
|
||||
export function updateMarker(options: {
|
||||
sheetAddress: SheetAddress
|
||||
markerId: SequenceMarkerId
|
||||
label: string
|
||||
}) {
|
||||
const currentMarkerSet = _ensureMarkers(options.sheetAddress)
|
||||
const marker = currentMarkerSet.byId[options.markerId]
|
||||
if (marker !== undefined) marker.label = options.label
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ export type PaneInstanceDescriptor = {
|
|||
*/
|
||||
export type StudioHistoricStateSequenceEditorMarker = {
|
||||
id: SequenceMarkerId
|
||||
label?: string
|
||||
/**
|
||||
* The position this marker takes in the sequence.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue