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
|
||||
isFovAnimationInProgress = false
|
||||
perspectiveFovBeforeOrtho = 45
|
||||
// NOTE: Duplicated state across Provider and singleton. Mapped from settingsMachine
|
||||
_setting_allowOrbitInSketchMode = false
|
||||
get isPerspective() {
|
||||
return this.camera instanceof PerspectiveCamera
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ export const ModelingMachineProvider = ({
|
||||
auth,
|
||||
settings: {
|
||||
context: {
|
||||
app: { theme, enableSSAO },
|
||||
app: { theme, enableSSAO, allowOrbitInSketchMode },
|
||||
modeling: {
|
||||
defaultUnit,
|
||||
cameraProjection,
|
||||
@ -121,6 +121,7 @@ export const ModelingMachineProvider = ({
|
||||
},
|
||||
},
|
||||
} = useSettingsAuthContext()
|
||||
const previousAllowOrbitInSketchMode = useRef(allowOrbitInSketchMode.current)
|
||||
const navigate = useNavigate()
|
||||
const { context, send: fileMachineSend } = useFileContext()
|
||||
const { file } = useLoaderData() as IndexLoaderData
|
||||
@ -634,7 +635,8 @@ export const ModelingMachineProvider = ({
|
||||
input.plane
|
||||
)
|
||||
await kclManager.updateAst(modifiedAst, false)
|
||||
sceneInfra.camControls.enableRotate = false
|
||||
sceneInfra.camControls.enableRotate =
|
||||
sceneInfra.camControls._setting_allowOrbitInSketchMode
|
||||
sceneInfra.camControls.syncDirection = 'clientToEngine'
|
||||
|
||||
await letEngineAnimateAndSyncCamAfter(
|
||||
@ -647,6 +649,7 @@ export const ModelingMachineProvider = ({
|
||||
zAxis: input.zAxis,
|
||||
yAxis: input.yAxis,
|
||||
origin: [0, 0, 0],
|
||||
animateTargetId: input.planeId,
|
||||
}
|
||||
}),
|
||||
'animate-to-sketch': fromPromise(
|
||||
@ -671,6 +674,7 @@ export const ModelingMachineProvider = ({
|
||||
origin: info.sketchDetails.origin.map(
|
||||
(a) => a / sceneInfra._baseUnitMultiplier
|
||||
) as [number, number, number],
|
||||
animateTargetId: info?.sketchDetails?.faceId || '',
|
||||
}
|
||||
}
|
||||
),
|
||||
@ -1188,6 +1192,41 @@ export const ModelingMachineProvider = ({
|
||||
}
|
||||
}, [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
|
||||
useHotkeys(['backspace', 'delete', 'del'], () => {
|
||||
modelingSend({ type: 'Delete selection' })
|
||||
|
@ -137,6 +137,11 @@ export const SettingsAuthProviderBase = ({
|
||||
sceneInfra.theme = 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 }) => {
|
||||
if (!('data' in event)) return
|
||||
const eventParts = event.type.replace(/^set./, '').split('.') as [
|
||||
|
@ -190,6 +190,14 @@ export function createSettings() {
|
||||
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>({
|
||||
defaultValue: '',
|
||||
// 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,
|
||||
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
||||
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
||||
allowOrbitInSketchMode:
|
||||
configuration?.settings?.app?.allow_orbit_in_sketch_mode,
|
||||
projectDirectory: configuration?.settings?.project?.directory,
|
||||
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
||||
},
|
||||
@ -80,6 +82,8 @@ export function projectConfigurationToSettingsPayload(
|
||||
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
||||
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
||||
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
||||
allowOrbitInSketchMode:
|
||||
configuration?.settings?.app?.allow_orbit_in_sketch_mode,
|
||||
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
||||
},
|
||||
modeling: {
|
||||
|
@ -133,6 +133,8 @@ export interface SketchDetails {
|
||||
zAxis: [number, number, number]
|
||||
yAxis: [number, number, number]
|
||||
origin: [number, number, number]
|
||||
// face id or plane id, both are strings
|
||||
animateTargetId?: string
|
||||
}
|
||||
|
||||
export interface SegmentOverlay {
|
||||
|
@ -43,6 +43,7 @@ export const settingsMachine = setup({
|
||||
'Execute AST': () => {},
|
||||
toastSuccess: () => {},
|
||||
setClientSideSceneUnits: () => {},
|
||||
setAllowOrbitInSketchMode: () => {},
|
||||
persistSettings: () => {},
|
||||
resetSettings: assign(({ context, event }) => {
|
||||
if (!('level' in event)) return {}
|
||||
@ -157,6 +158,15 @@ export const settingsMachine = setup({
|
||||
actions: ['setSettingAtLevel', 'toastSuccess'],
|
||||
},
|
||||
|
||||
'set.app.allowOrbitInSketchMode': {
|
||||
target: 'persisting settings',
|
||||
actions: [
|
||||
'setSettingAtLevel',
|
||||
'toastSuccess',
|
||||
'setAllowOrbitInSketchMode',
|
||||
],
|
||||
},
|
||||
|
||||
'set.modeling.cameraProjection': {
|
||||
target: 'persisting settings',
|
||||
|
||||
@ -183,6 +193,7 @@ export const settingsMachine = setup({
|
||||
'setClientSideSceneUnits',
|
||||
'Execute AST',
|
||||
'setClientTheme',
|
||||
'setAllowOrbitInSketchMode',
|
||||
],
|
||||
},
|
||||
|
||||
@ -194,6 +205,7 @@ export const settingsMachine = setup({
|
||||
'setClientSideSceneUnits',
|
||||
'Execute AST',
|
||||
'setClientTheme',
|
||||
'setAllowOrbitInSketchMode',
|
||||
],
|
||||
},
|
||||
|
||||
|
@ -121,6 +121,9 @@ pub struct AppSettings {
|
||||
/// When the user is idle, and this is true, the stream will be torn down.
|
||||
#[serde(default, alias = "streamIdleMode", skip_serializing_if = "is_default")]
|
||||
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.
|
||||
@ -586,6 +589,7 @@ textWrapping = true
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
allow_orbit_in_sketch_mode: false,
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::In,
|
||||
@ -647,6 +651,7 @@ includeSettings = false
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
allow_orbit_in_sketch_mode: false,
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::Yd,
|
||||
@ -713,6 +718,7 @@ defaultProjectName = "projects-$nnn"
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
allow_orbit_in_sketch_mode: false,
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::Yd,
|
||||
@ -791,6 +797,7 @@ projectDirectory = "/Users/macinatormax/Documents/kittycad-modeling-projects""#;
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
allow_orbit_in_sketch_mode: false,
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::Mm,
|
||||
|
@ -124,6 +124,7 @@ includeSettings = false
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
allow_orbit_in_sketch_mode: false,
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::Yd,
|
||||
|
Reference in New Issue
Block a user