WIP aggregate editing popover working but !clean
This commit is contained in:
parent
069902e054
commit
38e6a4ba36
7 changed files with 194 additions and 89 deletions
|
@ -17,18 +17,86 @@ import type {KeyframeWithPathToPropFromCommonRoot} from '@theatre/studio/store/t
|
|||
import {commonRootOfPathsToProps} from '@theatre/shared/utils/addresses'
|
||||
import type {ILogger} from '@theatre/shared/logger'
|
||||
import DopeSnap from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/DopeSnap'
|
||||
import type {EditingOptionsTree} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover'
|
||||
import {useKeyframeInlineEditorPopover} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover'
|
||||
import type {
|
||||
SequenceEditorTree_PrimitiveProp,
|
||||
SequenceEditorTree_PropWithChildren,
|
||||
SequenceEditorTree_SheetObject,
|
||||
} from '@theatre/studio/panels/SequenceEditorPanel/layout/tree'
|
||||
import type {KeyframeWithTrack} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/collectAggregateKeyframes'
|
||||
|
||||
type IAggregateKeyframeDotProps = {
|
||||
editorProps: IAggregateKeyframeEditorProps
|
||||
utils: IAggregateKeyframeEditorUtils
|
||||
}
|
||||
|
||||
function sheetObjectBuild(
|
||||
viewModel: SequenceEditorTree_SheetObject,
|
||||
keyframes: KeyframeWithTrack[],
|
||||
): EditingOptionsTree | null {
|
||||
const children = viewModel.children
|
||||
.map((a) =>
|
||||
a.type === 'propWithChildren'
|
||||
? propWithChildrenBuild(a, keyframes)
|
||||
: primitivePropBuild(a, keyframes),
|
||||
)
|
||||
.filter((a): a is EditingOptionsTree => a !== null)
|
||||
if (children.length === 0) return null
|
||||
return {
|
||||
type: 'sheetObject',
|
||||
sheetObject: viewModel.sheetObject,
|
||||
children,
|
||||
}
|
||||
}
|
||||
function propWithChildrenBuild(
|
||||
viewModel: SequenceEditorTree_PropWithChildren,
|
||||
keyframes: KeyframeWithTrack[],
|
||||
): EditingOptionsTree | null {
|
||||
const children = viewModel.children
|
||||
.map((a) =>
|
||||
a.type === 'propWithChildren'
|
||||
? propWithChildrenBuild(a, keyframes)
|
||||
: primitivePropBuild(a, keyframes),
|
||||
)
|
||||
.filter((a): a is EditingOptionsTree => a !== null)
|
||||
if (children.length === 0) return null
|
||||
return {
|
||||
type: 'propWithChildren',
|
||||
pathToProp: viewModel.pathToProp,
|
||||
propConfig: viewModel.propConf,
|
||||
children,
|
||||
}
|
||||
}
|
||||
function primitivePropBuild(
|
||||
viewModelLeaf: SequenceEditorTree_PrimitiveProp,
|
||||
keyframes: KeyframeWithTrack[],
|
||||
): EditingOptionsTree | null {
|
||||
const keyframe = keyframes.find((kf) => kf.track.id === viewModelLeaf.trackId)
|
||||
if (!keyframe) return null
|
||||
return {
|
||||
type: 'primitiveProp',
|
||||
keyframe: keyframe.kf,
|
||||
pathToProp: viewModelLeaf.pathToProp,
|
||||
propConfig: viewModelLeaf.propConf,
|
||||
sheetObject: viewModelLeaf.sheetObject,
|
||||
trackId: viewModelLeaf.trackId,
|
||||
}
|
||||
}
|
||||
|
||||
export function AggregateKeyframeDot(
|
||||
props: React.PropsWithChildren<IAggregateKeyframeDotProps>,
|
||||
) {
|
||||
const logger = useLogger('AggregateKeyframeDot')
|
||||
const {cur} = props.utils
|
||||
|
||||
const [inlineEditorPopover, openEditor, _, isInlineEditorPopoverOpen] =
|
||||
useKeyframeInlineEditorPopover(
|
||||
props.editorProps.viewModel.type === 'sheetObject'
|
||||
? sheetObjectBuild(props.editorProps.viewModel, cur.keyframes)
|
||||
: propWithChildrenBuild(props.editorProps.viewModel, cur.keyframes),
|
||||
)
|
||||
|
||||
const presence = usePresence(props.utils.itemKey)
|
||||
presence.useRelations(
|
||||
() =>
|
||||
|
@ -57,6 +125,7 @@ export function AggregateKeyframeDot(
|
|||
// Need this for the dragging logic to be able to get the keyframe props
|
||||
// based on the position.
|
||||
{...DopeSnap.includePositionSnapAttrs(cur.position)}
|
||||
onClick={(e) => openEditor(e, ref.current!)}
|
||||
/>
|
||||
<AggregateKeyframeVisualDot
|
||||
flag={presence.flag}
|
||||
|
@ -64,6 +133,7 @@ export function AggregateKeyframeDot(
|
|||
isSelected={cur.selected}
|
||||
/>
|
||||
{contextMenu}
|
||||
{inlineEditorPopover}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,28 +1,19 @@
|
|||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import type {
|
||||
PropTypeConfig,
|
||||
PropTypeConfig_AllSimples,
|
||||
} from '@theatre/core/propTypes'
|
||||
import type {IEditingTools} from '@theatre/studio/propEditors/utils/IEditingTools'
|
||||
import type {PropConfigForType} from '@theatre/studio/propEditors/utils/PropConfigForType'
|
||||
import type {PropTypeConfig_AllSimples} from '@theatre/core/propTypes'
|
||||
import type {ISimplePropEditorReactProps} from '@theatre/studio/propEditors/simpleEditors/ISimplePropEditorReactProps'
|
||||
import {simplePropEditorByPropType} from '@theatre/studio/propEditors/simpleEditors/simplePropEditorByPropType'
|
||||
|
||||
import SingleKeyframeSimplePropEditor from './DeterminePropEditorForSingleKeyframe/SingleKeyframeSimplePropEditor'
|
||||
|
||||
type IDeterminePropEditorForSingleKeyframeProps<
|
||||
K extends PropTypeConfig['type'],
|
||||
> = {
|
||||
editingTools: IEditingTools<PropConfigForType<K>['valueType']>
|
||||
propConfig: PropConfigForType<K>
|
||||
keyframeValue: PropConfigForType<K>['valueType']
|
||||
displayLabel?: string
|
||||
}
|
||||
import type {
|
||||
EditingOptionsTree,
|
||||
PrimitivePropEditingOptions,
|
||||
} from './useSingleKeyframeInlineEditorPopover'
|
||||
import last from 'lodash-es/last'
|
||||
import {useTempTransactionEditingTools} from './useTempTransactionEditingTools'
|
||||
|
||||
const SingleKeyframePropEditorContainer = styled.div`
|
||||
padding: 2px;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
|
@ -30,7 +21,7 @@ const SingleKeyframePropEditorContainer = styled.div`
|
|||
min-width: 100px;
|
||||
}
|
||||
`
|
||||
const SingleKeyframePropLabel = styled.span`
|
||||
const SingleKeyframePropLabel = styled.div`
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
|
@ -42,6 +33,10 @@ const SingleKeyframePropLabel = styled.span`
|
|||
color: #919191;
|
||||
`
|
||||
|
||||
const IndentedThing = styled.div`
|
||||
margin-left: 24px;
|
||||
`
|
||||
|
||||
/**
|
||||
* Given a propConfig, this function gives the corresponding prop editor for
|
||||
* use in the dope sheet inline prop editor on a keyframe.
|
||||
|
@ -52,35 +47,73 @@ const SingleKeyframePropLabel = styled.span`
|
|||
*
|
||||
* @param p - propConfig object for any type of prop.
|
||||
*/
|
||||
export function DeterminePropEditorForSingleKeyframe(
|
||||
p: IDeterminePropEditorForSingleKeyframeProps<PropTypeConfig['type']>,
|
||||
) {
|
||||
const propConfig = p.propConfig
|
||||
|
||||
if (propConfig.type === 'compound') {
|
||||
throw new Error(
|
||||
'We do not yet support editing compound props for a keyframe',
|
||||
export function DeterminePropEditorForKeyframeTree(p: EditingOptionsTree) {
|
||||
if (p.type === 'sheetObject') {
|
||||
return (
|
||||
<>
|
||||
<SingleKeyframePropLabel>
|
||||
{p.sheetObject.address.objectKey}
|
||||
</SingleKeyframePropLabel>
|
||||
<IndentedThing>
|
||||
{p.children.map((c, i) => (
|
||||
<DeterminePropEditorForKeyframeTree key={i} {...c} />
|
||||
))}
|
||||
</IndentedThing>
|
||||
</>
|
||||
)
|
||||
} else if (propConfig.type === 'enum') {
|
||||
} else if (p.type === 'propWithChildren') {
|
||||
const label = p.propConfig.label ?? last(p.pathToProp)
|
||||
return (
|
||||
<>
|
||||
<SingleKeyframePropLabel>{label}</SingleKeyframePropLabel>
|
||||
<IndentedThing>
|
||||
{p.children.map((c, i) => (
|
||||
<DeterminePropEditorForKeyframeTree key={i} {...c} />
|
||||
))}
|
||||
</IndentedThing>
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
return <BeepBoop {...p} />
|
||||
}
|
||||
}
|
||||
|
||||
function BeepBoop(p: PrimitivePropEditingOptions) {
|
||||
const label = p.propConfig.label ?? last(p.pathToProp)
|
||||
const editingTools = useEditingToolsForKeyframeEditorPopover(p)
|
||||
|
||||
if (p.propConfig.type === 'enum') {
|
||||
// notice: enums are not implemented, yet.
|
||||
return <></>
|
||||
} else {
|
||||
const PropEditor = simplePropEditorByPropType[propConfig.type]
|
||||
|
||||
const PropEditor = simplePropEditorByPropType[
|
||||
p.propConfig.type
|
||||
] as React.VFC<ISimplePropEditorReactProps<PropTypeConfig_AllSimples>>
|
||||
return (
|
||||
<SingleKeyframePropEditorContainer>
|
||||
<SingleKeyframePropLabel>{p.displayLabel}</SingleKeyframePropLabel>
|
||||
<SingleKeyframePropLabel>{label}</SingleKeyframePropLabel>
|
||||
<SingleKeyframeSimplePropEditor
|
||||
SimpleEditorComponent={
|
||||
PropEditor as React.VFC<
|
||||
ISimplePropEditorReactProps<PropTypeConfig_AllSimples>
|
||||
>
|
||||
}
|
||||
propConfig={propConfig}
|
||||
editingTools={p.editingTools}
|
||||
keyframeValue={p.keyframeValue}
|
||||
SimpleEditorComponent={PropEditor}
|
||||
propConfig={p.propConfig}
|
||||
editingTools={editingTools}
|
||||
keyframeValue={p.keyframe.value}
|
||||
/>
|
||||
</SingleKeyframePropEditorContainer>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function useEditingToolsForKeyframeEditorPopover(
|
||||
props: PrimitivePropEditingOptions,
|
||||
) {
|
||||
const obj = props.sheetObject
|
||||
return useTempTransactionEditingTools(({stateEditors}, value) => {
|
||||
const newKeyframe = {...props.keyframe, value}
|
||||
stateEditors.coreByProject.historic.sheetsById.sequence.replaceKeyframes({
|
||||
...obj.address,
|
||||
trackId: props.trackId,
|
||||
keyframes: [newKeyframe],
|
||||
snappingFunction: obj.sheet.getSequence().closestGridPosition,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
snapToNone,
|
||||
snapToSome,
|
||||
} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/KeyframeSnapTarget'
|
||||
import {useSingleKeyframeInlineEditorPopover} from './useSingleKeyframeInlineEditorPopover'
|
||||
import {useKeyframeInlineEditorPopover} from './useSingleKeyframeInlineEditorPopover'
|
||||
import usePresence, {
|
||||
PresenceFlag,
|
||||
} from '@theatre/studio/uiComponents/usePresence'
|
||||
|
@ -95,22 +95,21 @@ const HitZone = styled.div<{isInlineEditorPopoverOpen: boolean}>`
|
|||
type ISingleKeyframeDotProps = ISingleKeyframeEditorProps
|
||||
|
||||
/** The ◆ you can grab onto in "keyframe editor" (aka "dope sheet" in other programs) */
|
||||
const SingleKeyframeDot: React.VFC<ISingleKeyframeDotProps> = React.memo(
|
||||
(props) => {
|
||||
const SingleKeyframeDot: React.VFC<ISingleKeyframeDotProps> = (props) => {
|
||||
const logger = useLogger('SingleKeyframeDot', props.keyframe.id)
|
||||
const presence = usePresence(props.itemKey)
|
||||
const [ref, node] = useRefAndState<HTMLDivElement | null>(null)
|
||||
|
||||
const [contextMenu] = useSingleKeyframeContextMenu(node, logger, props)
|
||||
const [inlineEditorPopover, openEditor, _, isInlineEditorPopoverOpen] =
|
||||
useSingleKeyframeInlineEditorPopover({
|
||||
useKeyframeInlineEditorPopover({
|
||||
type: 'primitiveProp',
|
||||
keyframe: props.keyframe,
|
||||
pathToProp: props.leaf.pathToProp,
|
||||
propConf: props.leaf.propConf,
|
||||
propConfig: props.leaf.propConf,
|
||||
sheetObject: props.leaf.sheetObject,
|
||||
trackId: props.leaf.trackId,
|
||||
})
|
||||
|
||||
const [isDragging] = useDragForSingleKeyframeDot(node, props, {
|
||||
onClickFromDrag(dragStartEvent) {
|
||||
openEditor(dragStartEvent, ref.current!)
|
||||
|
|
|
@ -1,53 +1,51 @@
|
|||
import React from 'react'
|
||||
import last from 'lodash-es/last'
|
||||
import usePopover from '@theatre/studio/uiComponents/Popover/usePopover'
|
||||
import BasicPopover from '@theatre/studio/uiComponents/Popover/BasicPopover'
|
||||
import {useTempTransactionEditingTools} from './useTempTransactionEditingTools'
|
||||
import {DeterminePropEditorForSingleKeyframe} from './DeterminePropEditorForSingleKeyframe'
|
||||
import {DeterminePropEditorForKeyframeTree} from './DeterminePropEditorForSingleKeyframe'
|
||||
import type {SequenceTrackId} from '@theatre/shared/utils/ids'
|
||||
import type {Keyframe} from '@theatre/core/projects/store/types/SheetState_Historic'
|
||||
import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
|
||||
import type {PropTypeConfig} from '@theatre/core/propTypes'
|
||||
import type {
|
||||
PropTypeConfig_AllSimples,
|
||||
PropTypeConfig_Compound,
|
||||
PropTypeConfig_Enum,
|
||||
} from '@theatre/core/propTypes'
|
||||
import type {PathToProp} from '@theatre/shared/utils/addresses'
|
||||
import type {UnknownValidCompoundProps} from '@theatre/core/propTypes/internals'
|
||||
|
||||
/** The editor that pops up when directly clicking a Keyframe. */
|
||||
export function useSingleKeyframeInlineEditorPopover(
|
||||
props: SingleKeyframeEditingOptions,
|
||||
export function useKeyframeInlineEditorPopover(
|
||||
props: EditingOptionsTree | null,
|
||||
) {
|
||||
const editingTools = useEditingToolsForKeyframeEditorPopover(props)
|
||||
const label = props.propConf.label ?? last(props.pathToProp)
|
||||
|
||||
return usePopover({debugName: 'useKeyframeInlineEditorPopover'}, () => (
|
||||
<BasicPopover showPopoverEdgeTriangle>
|
||||
<DeterminePropEditorForSingleKeyframe
|
||||
propConfig={props.propConf}
|
||||
editingTools={editingTools}
|
||||
keyframeValue={props.keyframe.value}
|
||||
displayLabel={label != null ? String(label) : undefined}
|
||||
/>
|
||||
{props === null ? undefined : (
|
||||
<DeterminePropEditorForKeyframeTree {...props} />
|
||||
)}
|
||||
</BasicPopover>
|
||||
))
|
||||
}
|
||||
|
||||
type SingleKeyframeEditingOptions = {
|
||||
export type EditingOptionsTree =
|
||||
| SheetObjectEditingOptionsTree
|
||||
| PropWithChildrenEditingOptionsTree
|
||||
| PrimitivePropEditingOptions
|
||||
type SheetObjectEditingOptionsTree = {
|
||||
type: 'sheetObject'
|
||||
sheetObject: SheetObject
|
||||
children: EditingOptionsTree[]
|
||||
}
|
||||
type PropWithChildrenEditingOptionsTree = {
|
||||
type: 'propWithChildren'
|
||||
propConfig: PropTypeConfig_Compound<UnknownValidCompoundProps>
|
||||
pathToProp: PathToProp
|
||||
children: EditingOptionsTree[]
|
||||
}
|
||||
export type PrimitivePropEditingOptions = {
|
||||
type: 'primitiveProp'
|
||||
keyframe: Keyframe
|
||||
propConf: PropTypeConfig
|
||||
propConfig: PropTypeConfig_AllSimples | PropTypeConfig_Enum // note: enums are not implemented yet
|
||||
sheetObject: SheetObject
|
||||
trackId: SequenceTrackId
|
||||
pathToProp: PathToProp
|
||||
}
|
||||
|
||||
function useEditingToolsForKeyframeEditorPopover(
|
||||
props: SingleKeyframeEditingOptions,
|
||||
) {
|
||||
const obj = props.sheetObject
|
||||
return useTempTransactionEditingTools(({stateEditors}, value) => {
|
||||
const newKeyframe = {...props.keyframe, value}
|
||||
stateEditors.coreByProject.historic.sheetsById.sequence.replaceKeyframes({
|
||||
...obj.address,
|
||||
trackId: props.trackId,
|
||||
keyframes: [newKeyframe],
|
||||
snappingFunction: obj.sheet.getSequence().closestGridPosition,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
useCssCursorLock,
|
||||
} from '@theatre/studio/uiComponents/PointerEventsHandler'
|
||||
import DopeSnap from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/DopeSnap'
|
||||
import {useSingleKeyframeInlineEditorPopover} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover'
|
||||
import {useKeyframeInlineEditorPopover} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover'
|
||||
import usePresence, {
|
||||
PresenceFlag,
|
||||
} from '@theatre/studio/uiComponents/usePresence'
|
||||
|
@ -71,7 +71,7 @@ const GraphEditorDotNonScalar: React.VFC<IProps> = (props) => {
|
|||
const curValue = props.which === 'left' ? 0 : 1
|
||||
|
||||
const [inlineEditorPopover, openEditor, _, _isInlineEditorPopoverOpen] =
|
||||
useSingleKeyframeInlineEditorPopover({
|
||||
useKeyframeInlineEditorPopover({
|
||||
keyframe: props.keyframe,
|
||||
pathToProp: props.pathToProp,
|
||||
propConf: props.propConfig,
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
useCssCursorLock,
|
||||
} from '@theatre/studio/uiComponents/PointerEventsHandler'
|
||||
import DopeSnap from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/DopeSnap'
|
||||
import {useSingleKeyframeInlineEditorPopover} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover'
|
||||
import {useKeyframeInlineEditorPopover} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover'
|
||||
import usePresence, {
|
||||
PresenceFlag,
|
||||
} from '@theatre/studio/uiComponents/usePresence'
|
||||
|
@ -71,7 +71,7 @@ const GraphEditorDotScalar: React.VFC<IProps> = (props) => {
|
|||
|
||||
const cyInExtremumSpace = props.extremumSpace.fromValueSpace(curValue)
|
||||
const [inlineEditorPopover, openEditor, _, _isInlineEditorPopoverOpen] =
|
||||
useSingleKeyframeInlineEditorPopover({
|
||||
useKeyframeInlineEditorPopover({
|
||||
keyframe: props.keyframe,
|
||||
pathToProp: props.pathToProp,
|
||||
propConf: props.propConfig,
|
||||
|
|
|
@ -18,6 +18,7 @@ import {prism, val, valueDerivation} from '@theatre/dataverse'
|
|||
import logger from '@theatre/shared/logger'
|
||||
import {titleBarHeight} from '@theatre/studio/panels/BasePanel/common'
|
||||
import type {Studio} from '@theatre/studio/Studio'
|
||||
import type {UnknownValidCompoundProps} from '@theatre/core/propTypes/internals'
|
||||
|
||||
/**
|
||||
* Base "view model" for each row with common
|
||||
|
@ -73,6 +74,7 @@ export type SequenceEditorTree_PropWithChildren =
|
|||
SequenceEditorTree_Row<'propWithChildren'> & {
|
||||
isCollapsed: boolean
|
||||
sheetObject: SheetObject
|
||||
propConf: PropTypeConfig_Compound<UnknownValidCompoundProps>
|
||||
pathToProp: PathToProp
|
||||
children: Array<
|
||||
SequenceEditorTree_PropWithChildren | SequenceEditorTree_PrimitiveProp
|
||||
|
@ -233,6 +235,7 @@ export const calculateSequenceEditorTree = (
|
|||
addProp_compound(
|
||||
sheetObject,
|
||||
trackMapping,
|
||||
conf,
|
||||
pathToProp,
|
||||
conf,
|
||||
arrayOfChildren,
|
||||
|
@ -259,6 +262,7 @@ export const calculateSequenceEditorTree = (
|
|||
function addProp_compound(
|
||||
sheetObject: SheetObject,
|
||||
trackMapping: IPropPathToTrackIdTree,
|
||||
propConf: PropTypeConfig_Compound<UnknownValidCompoundProps>,
|
||||
pathToProp: PathToProp,
|
||||
conf: PropTypeConfig_Compound<$FixMe>,
|
||||
arrayOfChildren: Array<
|
||||
|
@ -276,6 +280,7 @@ export const calculateSequenceEditorTree = (
|
|||
const row: SequenceEditorTree_PropWithChildren = {
|
||||
type: 'propWithChildren',
|
||||
isCollapsed,
|
||||
propConf,
|
||||
pathToProp,
|
||||
sheetItemKey: createStudioSheetItemKey.forSheetObjectProp(
|
||||
sheetObject,
|
||||
|
|
Loading…
Reference in a new issue