Feature: Allow orbit in sketch mode via setting (#4990)
* feat: enable/disable free camera aka allow orbit in sketch mode mvp * fix: removing comments * fix: logic for enabling and disabling in and out of sketch mode * fix: fmt, linter, tsc fixes * fix: added comment * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * fix: current,prev check to no op the useeffect if the values are the same --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
@ -108,6 +108,8 @@ export class CameraControls {
|
|||||||
interactionGuards: MouseGuard = cameraMouseDragGuards.Zoo
|
interactionGuards: MouseGuard = cameraMouseDragGuards.Zoo
|
||||||
isFovAnimationInProgress = false
|
isFovAnimationInProgress = false
|
||||||
perspectiveFovBeforeOrtho = 45
|
perspectiveFovBeforeOrtho = 45
|
||||||
|
// NOTE: Duplicated state across Provider and singleton. Mapped from settingsMachine
|
||||||
|
_setting_allowOrbitInSketchMode = false
|
||||||
get isPerspective() {
|
get isPerspective() {
|
||||||
return this.camera instanceof PerspectiveCamera
|
return this.camera instanceof PerspectiveCamera
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ export const ModelingMachineProvider = ({
|
|||||||
auth,
|
auth,
|
||||||
settings: {
|
settings: {
|
||||||
context: {
|
context: {
|
||||||
app: { theme, enableSSAO },
|
app: { theme, enableSSAO, allowOrbitInSketchMode },
|
||||||
modeling: {
|
modeling: {
|
||||||
defaultUnit,
|
defaultUnit,
|
||||||
cameraProjection,
|
cameraProjection,
|
||||||
@ -121,6 +121,7 @@ export const ModelingMachineProvider = ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
} = useSettingsAuthContext()
|
} = useSettingsAuthContext()
|
||||||
|
const previousAllowOrbitInSketchMode = useRef(allowOrbitInSketchMode.current)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { context, send: fileMachineSend } = useFileContext()
|
const { context, send: fileMachineSend } = useFileContext()
|
||||||
const { file } = useLoaderData() as IndexLoaderData
|
const { file } = useLoaderData() as IndexLoaderData
|
||||||
@ -634,7 +635,8 @@ export const ModelingMachineProvider = ({
|
|||||||
input.plane
|
input.plane
|
||||||
)
|
)
|
||||||
await kclManager.updateAst(modifiedAst, false)
|
await kclManager.updateAst(modifiedAst, false)
|
||||||
sceneInfra.camControls.enableRotate = false
|
sceneInfra.camControls.enableRotate =
|
||||||
|
sceneInfra.camControls._setting_allowOrbitInSketchMode
|
||||||
sceneInfra.camControls.syncDirection = 'clientToEngine'
|
sceneInfra.camControls.syncDirection = 'clientToEngine'
|
||||||
|
|
||||||
await letEngineAnimateAndSyncCamAfter(
|
await letEngineAnimateAndSyncCamAfter(
|
||||||
@ -647,6 +649,7 @@ export const ModelingMachineProvider = ({
|
|||||||
zAxis: input.zAxis,
|
zAxis: input.zAxis,
|
||||||
yAxis: input.yAxis,
|
yAxis: input.yAxis,
|
||||||
origin: [0, 0, 0],
|
origin: [0, 0, 0],
|
||||||
|
animateTargetId: input.planeId,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
'animate-to-sketch': fromPromise(
|
'animate-to-sketch': fromPromise(
|
||||||
@ -671,6 +674,7 @@ export const ModelingMachineProvider = ({
|
|||||||
origin: info.sketchDetails.origin.map(
|
origin: info.sketchDetails.origin.map(
|
||||||
(a) => a / sceneInfra._baseUnitMultiplier
|
(a) => a / sceneInfra._baseUnitMultiplier
|
||||||
) as [number, number, number],
|
) as [number, number, number],
|
||||||
|
animateTargetId: info?.sketchDetails?.faceId || '',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@ -1188,6 +1192,41 @@ export const ModelingMachineProvider = ({
|
|||||||
}
|
}
|
||||||
}, [engineCommandManager.engineConnection, modelingSend])
|
}, [engineCommandManager.engineConnection, modelingSend])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Only trigger this if the state actually changes, if it stays the same do not reload the camera
|
||||||
|
if (
|
||||||
|
previousAllowOrbitInSketchMode.current === allowOrbitInSketchMode.current
|
||||||
|
) {
|
||||||
|
//no op
|
||||||
|
previousAllowOrbitInSketchMode.current = allowOrbitInSketchMode.current
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const inSketchMode = modelingState.matches('Sketch')
|
||||||
|
|
||||||
|
// If you are in sketch mode and you disable the orbit, return back to the normal view to the target
|
||||||
|
if (!allowOrbitInSketchMode.current) {
|
||||||
|
const targetId = modelingState.context.sketchDetails?.animateTargetId
|
||||||
|
if (inSketchMode && targetId) {
|
||||||
|
letEngineAnimateAndSyncCamAfter(engineCommandManager, targetId)
|
||||||
|
.then(() => {})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error(
|
||||||
|
'failed to sync engine and client scene after disabling allow orbit in sketch mode'
|
||||||
|
)
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// While you are in sketch mode you should be able to control the enable rotate
|
||||||
|
// Once you exit it goes back to normal
|
||||||
|
if (inSketchMode) {
|
||||||
|
sceneInfra.camControls.enableRotate = allowOrbitInSketchMode.current
|
||||||
|
}
|
||||||
|
|
||||||
|
previousAllowOrbitInSketchMode.current = allowOrbitInSketchMode.current
|
||||||
|
}, [allowOrbitInSketchMode])
|
||||||
|
|
||||||
// Allow using the delete key to delete solids
|
// Allow using the delete key to delete solids
|
||||||
useHotkeys(['backspace', 'delete', 'del'], () => {
|
useHotkeys(['backspace', 'delete', 'del'], () => {
|
||||||
modelingSend({ type: 'Delete selection' })
|
modelingSend({ type: 'Delete selection' })
|
||||||
|
@ -137,6 +137,11 @@ export const SettingsAuthProviderBase = ({
|
|||||||
sceneInfra.theme = opposingTheme
|
sceneInfra.theme = opposingTheme
|
||||||
sceneEntitiesManager.updateSegmentBaseColor(opposingTheme)
|
sceneEntitiesManager.updateSegmentBaseColor(opposingTheme)
|
||||||
},
|
},
|
||||||
|
setAllowOrbitInSketchMode: ({ context }) => {
|
||||||
|
sceneInfra.camControls._setting_allowOrbitInSketchMode =
|
||||||
|
context.app.allowOrbitInSketchMode.current
|
||||||
|
// ModelingMachineProvider will do a use effect to trigger the camera engine sync
|
||||||
|
},
|
||||||
toastSuccess: ({ event }) => {
|
toastSuccess: ({ event }) => {
|
||||||
if (!('data' in event)) return
|
if (!('data' in event)) return
|
||||||
const eventParts = event.type.replace(/^set./, '').split('.') as [
|
const eventParts = event.type.replace(/^set./, '').split('.') as [
|
||||||
|
@ -190,6 +190,14 @@ export function createSettings() {
|
|||||||
inputType: 'boolean',
|
inputType: 'boolean',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
allowOrbitInSketchMode: new Setting<boolean>({
|
||||||
|
defaultValue: false,
|
||||||
|
description: 'Toggle free camera while in sketch mode',
|
||||||
|
validate: (v) => typeof v === 'boolean',
|
||||||
|
commandConfig: {
|
||||||
|
inputType: 'boolean',
|
||||||
|
},
|
||||||
|
}),
|
||||||
onboardingStatus: new Setting<OnboardingStatus>({
|
onboardingStatus: new Setting<OnboardingStatus>({
|
||||||
defaultValue: '',
|
defaultValue: '',
|
||||||
// TODO: this could be better but we don't have a TS side real enum
|
// TODO: this could be better but we don't have a TS side real enum
|
||||||
|
@ -41,6 +41,8 @@ export function configurationToSettingsPayload(
|
|||||||
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
||||||
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
||||||
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
||||||
|
allowOrbitInSketchMode:
|
||||||
|
configuration?.settings?.app?.allow_orbit_in_sketch_mode,
|
||||||
projectDirectory: configuration?.settings?.project?.directory,
|
projectDirectory: configuration?.settings?.project?.directory,
|
||||||
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
||||||
},
|
},
|
||||||
@ -80,6 +82,8 @@ export function projectConfigurationToSettingsPayload(
|
|||||||
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
||||||
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
||||||
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
||||||
|
allowOrbitInSketchMode:
|
||||||
|
configuration?.settings?.app?.allow_orbit_in_sketch_mode,
|
||||||
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
||||||
},
|
},
|
||||||
modeling: {
|
modeling: {
|
||||||
|
@ -133,6 +133,8 @@ export interface SketchDetails {
|
|||||||
zAxis: [number, number, number]
|
zAxis: [number, number, number]
|
||||||
yAxis: [number, number, number]
|
yAxis: [number, number, number]
|
||||||
origin: [number, number, number]
|
origin: [number, number, number]
|
||||||
|
// face id or plane id, both are strings
|
||||||
|
animateTargetId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SegmentOverlay {
|
export interface SegmentOverlay {
|
||||||
|
@ -43,6 +43,7 @@ export const settingsMachine = setup({
|
|||||||
'Execute AST': () => {},
|
'Execute AST': () => {},
|
||||||
toastSuccess: () => {},
|
toastSuccess: () => {},
|
||||||
setClientSideSceneUnits: () => {},
|
setClientSideSceneUnits: () => {},
|
||||||
|
setAllowOrbitInSketchMode: () => {},
|
||||||
persistSettings: () => {},
|
persistSettings: () => {},
|
||||||
resetSettings: assign(({ context, event }) => {
|
resetSettings: assign(({ context, event }) => {
|
||||||
if (!('level' in event)) return {}
|
if (!('level' in event)) return {}
|
||||||
@ -157,6 +158,15 @@ export const settingsMachine = setup({
|
|||||||
actions: ['setSettingAtLevel', 'toastSuccess'],
|
actions: ['setSettingAtLevel', 'toastSuccess'],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'set.app.allowOrbitInSketchMode': {
|
||||||
|
target: 'persisting settings',
|
||||||
|
actions: [
|
||||||
|
'setSettingAtLevel',
|
||||||
|
'toastSuccess',
|
||||||
|
'setAllowOrbitInSketchMode',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
'set.modeling.cameraProjection': {
|
'set.modeling.cameraProjection': {
|
||||||
target: 'persisting settings',
|
target: 'persisting settings',
|
||||||
|
|
||||||
@ -183,6 +193,7 @@ export const settingsMachine = setup({
|
|||||||
'setClientSideSceneUnits',
|
'setClientSideSceneUnits',
|
||||||
'Execute AST',
|
'Execute AST',
|
||||||
'setClientTheme',
|
'setClientTheme',
|
||||||
|
'setAllowOrbitInSketchMode',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -194,6 +205,7 @@ export const settingsMachine = setup({
|
|||||||
'setClientSideSceneUnits',
|
'setClientSideSceneUnits',
|
||||||
'Execute AST',
|
'Execute AST',
|
||||||
'setClientTheme',
|
'setClientTheme',
|
||||||
|
'setAllowOrbitInSketchMode',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -121,6 +121,9 @@ pub struct AppSettings {
|
|||||||
/// When the user is idle, and this is true, the stream will be torn down.
|
/// When the user is idle, and this is true, the stream will be torn down.
|
||||||
#[serde(default, alias = "streamIdleMode", skip_serializing_if = "is_default")]
|
#[serde(default, alias = "streamIdleMode", skip_serializing_if = "is_default")]
|
||||||
stream_idle_mode: bool,
|
stream_idle_mode: bool,
|
||||||
|
/// When the user is idle, and this is true, the stream will be torn down.
|
||||||
|
#[serde(default, alias = "allowOrbitInSketchMode", skip_serializing_if = "is_default")]
|
||||||
|
allow_orbit_in_sketch_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: When we remove backwards compatibility with the old settings file, we can remove this.
|
// TODO: When we remove backwards compatibility with the old settings file, we can remove this.
|
||||||
@ -586,6 +589,7 @@ textWrapping = true
|
|||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
stream_idle_mode: false,
|
stream_idle_mode: false,
|
||||||
|
allow_orbit_in_sketch_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::In,
|
base_unit: UnitLength::In,
|
||||||
@ -647,6 +651,7 @@ includeSettings = false
|
|||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
stream_idle_mode: false,
|
stream_idle_mode: false,
|
||||||
|
allow_orbit_in_sketch_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::Yd,
|
base_unit: UnitLength::Yd,
|
||||||
@ -713,6 +718,7 @@ defaultProjectName = "projects-$nnn"
|
|||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
stream_idle_mode: false,
|
stream_idle_mode: false,
|
||||||
|
allow_orbit_in_sketch_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::Yd,
|
base_unit: UnitLength::Yd,
|
||||||
@ -791,6 +797,7 @@ projectDirectory = "/Users/macinatormax/Documents/kittycad-modeling-projects""#;
|
|||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
stream_idle_mode: false,
|
stream_idle_mode: false,
|
||||||
|
allow_orbit_in_sketch_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::Mm,
|
base_unit: UnitLength::Mm,
|
||||||
|
@ -124,6 +124,7 @@ includeSettings = false
|
|||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
stream_idle_mode: false,
|
stream_idle_mode: false,
|
||||||
|
allow_orbit_in_sketch_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::Yd,
|
base_unit: UnitLength::Yd,
|
||||||
|
Reference in New Issue
Block a user