Nudging behavior on number props can now be customized
This commit is contained in:
parent
74724d7ec1
commit
36017c6a73
7 changed files with 81 additions and 14 deletions
|
@ -13,7 +13,7 @@ const editorSheetObjectConfig = types.compound({
|
||||||
showAxes: types.boolean(true, {label: 'Axes'}),
|
showAxes: types.boolean(true, {label: 'Axes'}),
|
||||||
showGrid: types.boolean(true, {label: 'Grid'}),
|
showGrid: types.boolean(true, {label: 'Grid'}),
|
||||||
showOverlayIcons: types.boolean(false, {label: 'Overlay Icons'}),
|
showOverlayIcons: types.boolean(false, {label: 'Overlay Icons'}),
|
||||||
resolution: types.number(1440, {
|
resolution: types.number(500, {
|
||||||
label: 'Resolution',
|
label: 'Resolution',
|
||||||
range: [0, 1000],
|
range: [0, 1000],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -18,21 +18,25 @@ export type TransformControlsMode = 'translate' | 'rotate' | 'scale'
|
||||||
export type TransformControlsSpace = 'world' | 'local'
|
export type TransformControlsSpace = 'world' | 'local'
|
||||||
export type ViewportShading = 'wireframe' | 'flat' | 'solid' | 'rendered'
|
export type ViewportShading = 'wireframe' | 'flat' | 'solid' | 'rendered'
|
||||||
|
|
||||||
|
const positionComp = types.number(1, {nudgeMultiplier: 0.1})
|
||||||
|
const rotationComp = types.number(1, {nudgeMultiplier: 0.02})
|
||||||
|
const scaleComp = types.number(1, {nudgeMultiplier: 0.1})
|
||||||
|
|
||||||
export const baseSheetObjectType = types.compound({
|
export const baseSheetObjectType = types.compound({
|
||||||
position: types.compound({
|
position: types.compound({
|
||||||
x: types.number(0),
|
x: positionComp,
|
||||||
y: types.number(0),
|
y: positionComp,
|
||||||
z: types.number(0),
|
z: positionComp,
|
||||||
}),
|
}),
|
||||||
rotation: types.compound({
|
rotation: types.compound({
|
||||||
x: types.number(0),
|
x: rotationComp,
|
||||||
y: types.number(0),
|
y: rotationComp,
|
||||||
z: types.number(0),
|
z: rotationComp,
|
||||||
}),
|
}),
|
||||||
scale: types.compound({
|
scale: types.compound({
|
||||||
x: types.number(1),
|
x: scaleComp,
|
||||||
y: types.number(1),
|
y: scaleComp,
|
||||||
z: types.number(1),
|
z: scaleComp,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,40 @@ export interface PropTypeConfig_Number extends IBasePropType<number> {
|
||||||
type: 'number'
|
type: 'number'
|
||||||
default: number
|
default: number
|
||||||
range?: [min: number, max: number]
|
range?: [min: number, max: number]
|
||||||
|
nudgeFn: NumberNudgeFn
|
||||||
|
nudgeMultiplier: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NumberNudgeFn = (p: {
|
||||||
|
deltaX: number
|
||||||
|
deltaFraction: number
|
||||||
|
magnitude: number
|
||||||
|
config: PropTypeConfig_Number
|
||||||
|
}) => number
|
||||||
|
|
||||||
|
const defaultNumberNudgeFn: NumberNudgeFn = ({
|
||||||
|
config,
|
||||||
|
deltaX,
|
||||||
|
deltaFraction,
|
||||||
|
magnitude,
|
||||||
|
}) => {
|
||||||
|
const {range} = config
|
||||||
|
if (range) {
|
||||||
|
return (
|
||||||
|
deltaFraction * (range[1] - range[0]) * magnitude * config.nudgeMultiplier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return deltaX * magnitude * config.nudgeMultiplier
|
||||||
}
|
}
|
||||||
|
|
||||||
export const number = (
|
export const number = (
|
||||||
defaultValue: number,
|
defaultValue: number,
|
||||||
opts?: Pick<PropTypeConfig_Number, 'range'> & PropTypeConfigExtras,
|
opts?: {
|
||||||
|
nudgeFn?: PropTypeConfig_Number['nudgeFn']
|
||||||
|
range?: PropTypeConfig_Number['range']
|
||||||
|
nudgeMultiplier?: number
|
||||||
|
} & PropTypeConfigExtras,
|
||||||
): PropTypeConfig_Number => {
|
): PropTypeConfig_Number => {
|
||||||
return {
|
return {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
@ -26,6 +55,9 @@ export const number = (
|
||||||
[s]: 'TheatrePropType',
|
[s]: 'TheatrePropType',
|
||||||
...(opts ? opts : {}),
|
...(opts ? opts : {}),
|
||||||
label: opts?.label,
|
label: opts?.label,
|
||||||
|
nudgeFn: opts?.nudgeFn ?? defaultNumberNudgeFn,
|
||||||
|
nudgeMultiplier:
|
||||||
|
typeof opts?.nudgeMultiplier === 'number' ? opts.nudgeMultiplier : 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type {PropTypeConfig_Number} from '@theatre/core/propTypes'
|
import type {PropTypeConfig_Number} from '@theatre/core/propTypes'
|
||||||
import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
|
import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
|
||||||
import BasicNumberInput from '@theatre/studio/uiComponents/form/BasicNumberInput'
|
import BasicNumberInput from '@theatre/studio/uiComponents/form/BasicNumberInput'
|
||||||
import React from 'react'
|
import React, {useCallback} from 'react'
|
||||||
import {useEditingToolsForPrimitiveProp} from './utils/useEditingToolsForPrimitiveProp'
|
import {useEditingToolsForPrimitiveProp} from './utils/useEditingToolsForPrimitiveProp'
|
||||||
import {SingleRowPropEditor} from './utils/SingleRowPropEditor'
|
import {SingleRowPropEditor} from './utils/SingleRowPropEditor'
|
||||||
|
|
||||||
|
@ -12,6 +12,13 @@ const NumberPropEditor: React.FC<{
|
||||||
}> = ({propConfig, pointerToProp, obj}) => {
|
}> = ({propConfig, pointerToProp, obj}) => {
|
||||||
const stuff = useEditingToolsForPrimitiveProp<number>(pointerToProp, obj)
|
const stuff = useEditingToolsForPrimitiveProp<number>(pointerToProp, obj)
|
||||||
|
|
||||||
|
const nudge = useCallback(
|
||||||
|
(params: {deltaX: number; deltaFraction: number; magnitude: number}) => {
|
||||||
|
return propConfig.nudgeFn({...params, config: propConfig})
|
||||||
|
},
|
||||||
|
[propConfig],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleRowPropEditor {...{stuff, propConfig, pointerToProp}}>
|
<SingleRowPropEditor {...{stuff, propConfig, pointerToProp}}>
|
||||||
<BasicNumberInput
|
<BasicNumberInput
|
||||||
|
@ -20,6 +27,7 @@ const NumberPropEditor: React.FC<{
|
||||||
discardTemporaryValue={stuff.discardTemporaryValue}
|
discardTemporaryValue={stuff.discardTemporaryValue}
|
||||||
permenantlySetValue={stuff.permenantlySetValue}
|
permenantlySetValue={stuff.permenantlySetValue}
|
||||||
range={propConfig.range}
|
range={propConfig.range}
|
||||||
|
nudge={nudge}
|
||||||
/>
|
/>
|
||||||
</SingleRowPropEditor>
|
</SingleRowPropEditor>
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,6 +4,7 @@ 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 {usePrism, useVal} from '@theatre/dataverse-react'
|
import {usePrism, useVal} from '@theatre/dataverse-react'
|
||||||
import getStudio from '@theatre/studio/getStudio'
|
import getStudio from '@theatre/studio/getStudio'
|
||||||
|
import type {BasicNumberInputNudgeFn} from '@theatre/studio/uiComponents/form/BasicNumberInput'
|
||||||
import BasicNumberInput from '@theatre/studio/uiComponents/form/BasicNumberInput'
|
import BasicNumberInput from '@theatre/studio/uiComponents/form/BasicNumberInput'
|
||||||
import type {CommitOrDiscard} from '@theatre/studio/StudioStore/StudioStore'
|
import type {CommitOrDiscard} from '@theatre/studio/StudioStore/StudioStore'
|
||||||
import {propNameText} from '@theatre/studio/panels/DetailPanel/propEditors/utils/SingleRowPropEditor'
|
import {propNameText} from '@theatre/studio/panels/DetailPanel/propEditors/utils/SingleRowPropEditor'
|
||||||
|
@ -23,6 +24,8 @@ const Label = styled.div`
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const nudge: BasicNumberInputNudgeFn = ({deltaX}) => deltaX * 0.25
|
||||||
|
|
||||||
const LengthEditorPopover: React.FC<{
|
const LengthEditorPopover: React.FC<{
|
||||||
layoutP: Pointer<SequenceEditorPanelLayout>
|
layoutP: Pointer<SequenceEditorPanelLayout>
|
||||||
/**
|
/**
|
||||||
|
@ -87,6 +90,7 @@ const LengthEditorPopover: React.FC<{
|
||||||
isValid={greaterThanZero}
|
isValid={greaterThanZero}
|
||||||
inputRef={inputRef}
|
inputRef={inputRef}
|
||||||
onBlur={onRequestClose}
|
onBlur={onRequestClose}
|
||||||
|
nudge={nudge}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|
|
@ -73,6 +73,7 @@ const FillIndicator = styled.div`
|
||||||
background-color: #2d5561;
|
background-color: #2d5561;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
${Container}.dragging &, ${Container}.noFocus:hover & {
|
${Container}.dragging &, ${Container}.noFocus:hover & {
|
||||||
background-color: #338198;
|
background-color: #338198;
|
||||||
|
@ -103,6 +104,12 @@ type IState = IState_NoFocus | IState_EditingViaKeyboard | IState_Dragging
|
||||||
|
|
||||||
const alwaysValid = (v: number) => true
|
const alwaysValid = (v: number) => true
|
||||||
|
|
||||||
|
export type BasicNumberInputNudgeFn = (params: {
|
||||||
|
deltaX: number
|
||||||
|
deltaFraction: number
|
||||||
|
magnitude: number
|
||||||
|
}) => number
|
||||||
|
|
||||||
const BasicNumberInput: React.FC<{
|
const BasicNumberInput: React.FC<{
|
||||||
value: number
|
value: number
|
||||||
temporarilySetValue: (v: number) => void
|
temporarilySetValue: (v: number) => void
|
||||||
|
@ -117,6 +124,7 @@ const BasicNumberInput: React.FC<{
|
||||||
* before this, so use this for UI purposes such as closing a popover.
|
* before this, so use this for UI purposes such as closing a popover.
|
||||||
*/
|
*/
|
||||||
onBlur?: () => void
|
onBlur?: () => void
|
||||||
|
nudge: BasicNumberInputNudgeFn
|
||||||
}> = (propsA) => {
|
}> = (propsA) => {
|
||||||
const [stateA, setState] = useState<IState>({mode: 'noFocus'})
|
const [stateA, setState] = useState<IState>({mode: 'noFocus'})
|
||||||
const isValid = propsA.isValid ?? alwaysValid
|
const isValid = propsA.isValid ?? alwaysValid
|
||||||
|
@ -207,8 +215,11 @@ const BasicNumberInput: React.FC<{
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let inputWidth: number
|
||||||
|
|
||||||
const transitionToDraggingMode = () => {
|
const transitionToDraggingMode = () => {
|
||||||
const curValue = refs.current.props.value
|
const curValue = refs.current.props.value
|
||||||
|
inputWidth = inputRef.current?.getBoundingClientRect().width!
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
mode: 'dragging',
|
mode: 'dragging',
|
||||||
|
@ -238,9 +249,16 @@ const BasicNumberInput: React.FC<{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDrag = (dx: number, _dy: number) => {
|
const onDrag = (deltaX: number, _dy: number) => {
|
||||||
const curState = refs.current.state as IState_Dragging
|
const curState = refs.current.state as IState_Dragging
|
||||||
const newValue = curState.valueBeforeDragging + dx
|
|
||||||
|
const newValue =
|
||||||
|
curState.valueBeforeDragging +
|
||||||
|
propsA.nudge({
|
||||||
|
deltaX,
|
||||||
|
deltaFraction: deltaX / inputWidth,
|
||||||
|
magnitude: 1,
|
||||||
|
})
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
...curState,
|
...curState,
|
||||||
|
|
|
@ -23,6 +23,7 @@ const Container = styled.ul`
|
||||||
min-width: ${minWidth}px;
|
min-width: ${minWidth}px;
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
background: ${transparentize(0.2, '#111')};
|
background: ${transparentize(0.2, '#111')};
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
color: white;
|
color: white;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding: 2px 0;
|
padding: 2px 0;
|
||||||
|
|
Loading…
Reference in a new issue