diff --git a/packages/plugin-r3f/src/components/editorStuff.ts b/packages/plugin-r3f/src/components/editorStuff.ts index 9104ff5..7090830 100644 --- a/packages/plugin-r3f/src/components/editorStuff.ts +++ b/packages/plugin-r3f/src/components/editorStuff.ts @@ -13,7 +13,7 @@ const editorSheetObjectConfig = types.compound({ showAxes: types.boolean(true, {label: 'Axes'}), showGrid: types.boolean(true, {label: 'Grid'}), showOverlayIcons: types.boolean(false, {label: 'Overlay Icons'}), - resolution: types.number(1440, { + resolution: types.number(500, { label: 'Resolution', range: [0, 1000], }), diff --git a/packages/plugin-r3f/src/store.ts b/packages/plugin-r3f/src/store.ts index 64782ca..1182931 100644 --- a/packages/plugin-r3f/src/store.ts +++ b/packages/plugin-r3f/src/store.ts @@ -18,21 +18,25 @@ export type TransformControlsMode = 'translate' | 'rotate' | 'scale' export type TransformControlsSpace = 'world' | 'local' 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({ position: types.compound({ - x: types.number(0), - y: types.number(0), - z: types.number(0), + x: positionComp, + y: positionComp, + z: positionComp, }), rotation: types.compound({ - x: types.number(0), - y: types.number(0), - z: types.number(0), + x: rotationComp, + y: rotationComp, + z: rotationComp, }), scale: types.compound({ - x: types.number(1), - y: types.number(1), - z: types.number(1), + x: scaleComp, + y: scaleComp, + z: scaleComp, }), }) diff --git a/theatre/core/src/propTypes/index.ts b/theatre/core/src/propTypes/index.ts index 67032dd..b9f0455 100644 --- a/theatre/core/src/propTypes/index.ts +++ b/theatre/core/src/propTypes/index.ts @@ -13,11 +13,40 @@ export interface PropTypeConfig_Number extends IBasePropType { type: 'number' default: 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 = ( defaultValue: number, - opts?: Pick & PropTypeConfigExtras, + opts?: { + nudgeFn?: PropTypeConfig_Number['nudgeFn'] + range?: PropTypeConfig_Number['range'] + nudgeMultiplier?: number + } & PropTypeConfigExtras, ): PropTypeConfig_Number => { return { type: 'number', @@ -26,6 +55,9 @@ export const number = ( [s]: 'TheatrePropType', ...(opts ? opts : {}), label: opts?.label, + nudgeFn: opts?.nudgeFn ?? defaultNumberNudgeFn, + nudgeMultiplier: + typeof opts?.nudgeMultiplier === 'number' ? opts.nudgeMultiplier : 1, } } diff --git a/theatre/studio/src/panels/DetailPanel/propEditors/NumberPropEditor.tsx b/theatre/studio/src/panels/DetailPanel/propEditors/NumberPropEditor.tsx index 2a013f0..370c079 100644 --- a/theatre/studio/src/panels/DetailPanel/propEditors/NumberPropEditor.tsx +++ b/theatre/studio/src/panels/DetailPanel/propEditors/NumberPropEditor.tsx @@ -1,7 +1,7 @@ import type {PropTypeConfig_Number} from '@theatre/core/propTypes' import type SheetObject from '@theatre/core/sheetObjects/SheetObject' import BasicNumberInput from '@theatre/studio/uiComponents/form/BasicNumberInput' -import React from 'react' +import React, {useCallback} from 'react' import {useEditingToolsForPrimitiveProp} from './utils/useEditingToolsForPrimitiveProp' import {SingleRowPropEditor} from './utils/SingleRowPropEditor' @@ -12,6 +12,13 @@ const NumberPropEditor: React.FC<{ }> = ({propConfig, pointerToProp, obj}) => { const stuff = useEditingToolsForPrimitiveProp(pointerToProp, obj) + const nudge = useCallback( + (params: {deltaX: number; deltaFraction: number; magnitude: number}) => { + return propConfig.nudgeFn({...params, config: propConfig}) + }, + [propConfig], + ) + return ( ) diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/LengthIndicator/LengthEditorPopover.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/LengthIndicator/LengthEditorPopover.tsx index 85206eb..7f260d3 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/LengthIndicator/LengthEditorPopover.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/LengthIndicator/LengthEditorPopover.tsx @@ -4,6 +4,7 @@ import styled from 'styled-components' import type {SequenceEditorPanelLayout} from '@theatre/studio/panels/SequenceEditorPanel/layout/layout' import {usePrism, useVal} from '@theatre/dataverse-react' import getStudio from '@theatre/studio/getStudio' +import type {BasicNumberInputNudgeFn} from '@theatre/studio/uiComponents/form/BasicNumberInput' import BasicNumberInput from '@theatre/studio/uiComponents/form/BasicNumberInput' import type {CommitOrDiscard} from '@theatre/studio/StudioStore/StudioStore' import {propNameText} from '@theatre/studio/panels/DetailPanel/propEditors/utils/SingleRowPropEditor' @@ -23,6 +24,8 @@ const Label = styled.div` white-space: nowrap; ` +const nudge: BasicNumberInputNudgeFn = ({deltaX}) => deltaX * 0.25 + const LengthEditorPopover: React.FC<{ layoutP: Pointer /** @@ -87,6 +90,7 @@ const LengthEditorPopover: React.FC<{ isValid={greaterThanZero} inputRef={inputRef} onBlur={onRequestClose} + nudge={nudge} /> ) diff --git a/theatre/studio/src/uiComponents/form/BasicNumberInput.tsx b/theatre/studio/src/uiComponents/form/BasicNumberInput.tsx index 2ae711a..c5946cb 100644 --- a/theatre/studio/src/uiComponents/form/BasicNumberInput.tsx +++ b/theatre/studio/src/uiComponents/form/BasicNumberInput.tsx @@ -73,6 +73,7 @@ const FillIndicator = styled.div` background-color: #2d5561; z-index: -1; border-radius: 2px; + pointer-events: none; ${Container}.dragging &, ${Container}.noFocus:hover & { background-color: #338198; @@ -103,6 +104,12 @@ type IState = IState_NoFocus | IState_EditingViaKeyboard | IState_Dragging const alwaysValid = (v: number) => true +export type BasicNumberInputNudgeFn = (params: { + deltaX: number + deltaFraction: number + magnitude: number +}) => number + const BasicNumberInput: React.FC<{ value: number 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. */ onBlur?: () => void + nudge: BasicNumberInputNudgeFn }> = (propsA) => { const [stateA, setState] = useState({mode: 'noFocus'}) const isValid = propsA.isValid ?? alwaysValid @@ -207,8 +215,11 @@ const BasicNumberInput: React.FC<{ }) } + let inputWidth: number + const transitionToDraggingMode = () => { const curValue = refs.current.props.value + inputWidth = inputRef.current?.getBoundingClientRect().width! setState({ 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 newValue = curState.valueBeforeDragging + dx + + const newValue = + curState.valueBeforeDragging + + propsA.nudge({ + deltaX, + deltaFraction: deltaX / inputWidth, + magnitude: 1, + }) setState({ ...curState, diff --git a/theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/RightClickMenu.tsx b/theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/RightClickMenu.tsx index 0f8a942..df05206 100644 --- a/theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/RightClickMenu.tsx +++ b/theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/RightClickMenu.tsx @@ -23,6 +23,7 @@ const Container = styled.ul` min-width: ${minWidth}px; z-index: 10000; background: ${transparentize(0.2, '#111')}; + backdrop-filter: blur(2px); color: white; list-style-type: none; padding: 2px 0;