Skip to content

Commit c9fda0d

Browse files
authored
Merge pull request #419 from itsdouges/disabled-editor-handles
Add disabled state to transform / pivot handles
2 parents a0e9678 + 8bedbca commit c9fda0d

File tree

22 files changed

+239
-114
lines changed

22 files changed

+239
-114
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ pnpm dev
2121

2222
**Important**
2323

24-
When making a change to the packages, the `vite` cache of the examples needs to be cleared (delete `node_modules/.vite` inside the running example). Rebuilding the libraries is not necassary unless types have changed.
24+
When making a change to the packages, the `vite` cache of the examples needs to be cleared (delete `node_modules/.vite` inside the running example). Rebuilding the libraries is not necessary unless types have changed.

examples/editor/app.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ const SelectablePivotHandles = forwardRef<
628628
<group ref={groupRef} onClick={() => useSceneStore.setState({ selected: target })}>
629629
<PivotHandles
630630
size={size}
631-
enabled={isSelected}
631+
hidden={!isSelected}
632632
apply={(state, target) => applyWithAudioEffect(state, target, apply)}
633633
ref={ref}
634634
>

packages/handle/src/handles/index.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import type { Vector2Tuple, ColorRepresentation } from 'three'
1+
import type { Vector2Tuple } from 'three'
22
import type { Axis } from '../state.js'
33

44
export type HandlesProperties =
55
| boolean
66
| {
7-
x?: boolean | Vector2Tuple
8-
y?: boolean | Vector2Tuple
9-
z?: boolean | Vector2Tuple
10-
e?: boolean | Vector2Tuple
7+
x?: boolean | Vector2Tuple | 'disabled'
8+
y?: boolean | Vector2Tuple | 'disabled'
9+
z?: boolean | Vector2Tuple | 'disabled'
10+
e?: boolean | Vector2Tuple | 'disabled'
1111
}
12+
| 'disabled'
1213
| Axis
1314
| 'e'
1415

packages/handle/src/handles/material.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ColorRepresentation, LineBasicMaterial, MeshBasicMaterial } from 'three'
1+
import { Color, ColorRepresentation, LineBasicMaterial, MeshBasicMaterial } from 'three'
22
import { HandlesContext } from './context.js'
33

44
export const handleXRayMaterialProperties = {
@@ -18,14 +18,22 @@ export function setupHandlesContextHoverMaterial(
1818
hoverColor,
1919
hoverOpacity,
2020
opacity,
21+
disabled = false,
2122
}: {
2223
color: ColorRepresentation
24+
disabled?: boolean
2325
opacity?: number
2426
hoverColor?: ColorRepresentation
2527
hoverOpacity?: number
2628
},
2729
) {
28-
if (hoverColor == null && hoverOpacity == null) {
30+
if ((hoverColor == null && hoverOpacity == null) || disabled) {
31+
material.color.set(color)
32+
material.opacity = opacity ?? 1
33+
if (disabled) {
34+
material.opacity *= 0.5
35+
material.color.lerp(new Color(1, 1, 1), 0.5)
36+
}
2937
return
3038
}
3139
hoverColor ??= color

packages/handle/src/handles/pivot/rotate.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class PivotAxisRotationHandle extends RegisteredHandle {
1717
}
1818

1919
bind(defaultColor: ColorRepresentation, config?: HandlesProperties) {
20-
const options = extractHandleTransformOptions(this.axis, config)
20+
const { options, disabled } = extractHandleTransformOptions(this.axis, config)
2121
if (options === false) {
2222
return undefined
2323
}
@@ -28,6 +28,7 @@ export class PivotAxisRotationHandle extends RegisteredHandle {
2828
const cleanupHover = setupHandlesContextHoverMaterial(this.context, material, this.tag, {
2929
color: defaultColor,
3030
hoverColor: 0xffff40,
31+
disabled,
3132
})
3233

3334
const visualizationMesh = new Mesh(new TorusGeometry(0.45, 0.0075, 3, 64, Math.PI / 2), material)
@@ -42,13 +43,13 @@ export class PivotAxisRotationHandle extends RegisteredHandle {
4243
interactionMesh.rotation.set(0, Math.PI / 2, Math.PI / 2)
4344
this.add(interactionMesh)
4445

45-
const unregister = this.context.registerHandle(this.store, interactionMesh, this.tag)
46+
const unregister = disabled ? undefined : this.context.registerHandle(this.store, interactionMesh, this.tag)
4647

4748
return () => {
4849
material.dispose()
4950
interactionMesh.geometry.dispose()
5051
visualizationMesh.geometry.dispose()
51-
unregister()
52+
unregister?.()
5253
cleanupHover?.()
5354
this.remove(visualizationMesh)
5455
this.remove(interactionMesh)

packages/handle/src/handles/pivot/scale.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class PivotAxisScaleHandle extends RegisteredHandle {
1717
}
1818

1919
bind(defaultColor: ColorRepresentation, config?: HandlesProperties) {
20-
const options = extractHandleTransformOptions(this.axis, config)
20+
const { options, disabled } = extractHandleTransformOptions(this.axis, config)
2121
if (options === false) {
2222
return undefined
2323
}
@@ -26,21 +26,22 @@ export class PivotAxisScaleHandle extends RegisteredHandle {
2626
const cleanupHover = setupHandlesContextHoverMaterial(this.context, material, this.tag, {
2727
color: defaultColor,
2828
hoverColor: 0xffff40,
29+
disabled,
2930
})
3031

3132
const mesh = new Mesh(new SphereGeometry(0.04), material)
3233
mesh.renderOrder = Infinity
3334
mesh.pointerEventsOrder = Infinity
3435
mesh.position.x = 0.68
3536

36-
const unregister = this.context.registerHandle(this.store, mesh, this.tag)
37+
const unregister = disabled ? undefined : this.context.registerHandle(this.store, mesh, this.tag)
3738

3839
this.add(mesh)
3940

4041
return () => {
4142
material.dispose()
4243
mesh.geometry.dispose()
43-
unregister()
44+
unregister?.()
4445
cleanupHover?.()
4546
this.remove(mesh)
4647
}

packages/handle/src/handles/registered.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { extractHandleTransformOptions } from './utils.js'
55

66
export class RegisteredHandle extends Group {
77
public readonly store: HandleStore<unknown>
8-
protected options: Exclude<ReturnType<typeof extractHandleTransformOptions>, false> | undefined
8+
protected options: Exclude<ReturnType<typeof extractHandleTransformOptions>['options'], false> | undefined
99
protected readonly tag: string
1010

1111
constructor(

packages/handle/src/handles/rotate/axis.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export class AxisRotateHandle extends RegisteredHandle {
9797
}
9898

9999
bind(defaultColor: ColorRepresentation, config?: HandlesProperties) {
100-
const options = extractHandleTransformOptions(this.axis, config)
100+
const { options, disabled } = extractHandleTransformOptions(this.axis, config)
101101
if (options === false) {
102102
return undefined
103103
}
@@ -108,6 +108,7 @@ export class AxisRotateHandle extends RegisteredHandle {
108108
const cleanupHover = setupHandlesContextHoverMaterial(this.context, material, this.tag, {
109109
color: defaultColor,
110110
hoverColor: 0xffff00,
111+
disabled,
111112
})
112113
const visualizationMesh = new Mesh(createCircleGeometry(0.5, 0.5), material)
113114
visualizationMesh.renderOrder = Infinity
@@ -120,13 +121,13 @@ export class AxisRotateHandle extends RegisteredHandle {
120121
interactionMesh.rotation.set(0, -Math.PI / 2, -Math.PI / 2)
121122
this.add(interactionMesh)
122123

123-
const unregister = this.context.registerHandle(this.store, interactionMesh, this.tag)
124+
const unregister = disabled ? undefined : this.context.registerHandle(this.store, interactionMesh, this.tag)
124125

125126
return () => {
126127
material.dispose()
127128
interactionMesh.geometry.dispose()
128129
visualizationMesh.geometry.dispose()
129-
unregister()
130+
unregister?.()
130131
cleanupHover?.()
131132
this.remove(interactionMesh)
132133
this.remove(visualizationMesh)

packages/handle/src/handles/rotate/free.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class FreeRotateHandle extends RegisteredHandle {
3838
}
3939

4040
bind(config?: HandlesProperties) {
41-
const options = extractHandleTransformOptions(this.axis, config)
41+
const { options, disabled } = extractHandleTransformOptions(this.axis, config)
4242
if (options === false) {
4343
return undefined
4444
}
@@ -50,6 +50,7 @@ export class FreeRotateHandle extends RegisteredHandle {
5050
color: 0xffffff,
5151
hoverColor: 0xffff00,
5252
opacity: 0.25,
53+
disabled,
5354
})
5455
const visualizationMesh = new Mesh(createCircleGeometry(0.5, 1), material)
5556
visualizationMesh.renderOrder = Infinity
@@ -61,14 +62,14 @@ export class FreeRotateHandle extends RegisteredHandle {
6162
interactionMesh.pointerEventsOrder = Infinity
6263
this.add(interactionMesh)
6364

64-
const unregister = this.context.registerHandle(this.store, interactionMesh, this.tag)
65+
const unregister = disabled ? undefined : this.context.registerHandle(this.store, interactionMesh, this.tag)
6566

6667
return () => {
6768
this.pointerEvents = 'none'
6869
material.dispose()
6970
interactionMesh.geometry.dispose()
7071
visualizationMesh.geometry.dispose()
71-
unregister()
72+
unregister?.()
7273
cleanupHover?.()
7374
this.remove(interactionMesh)
7475
this.remove(visualizationMesh)

packages/handle/src/handles/rotate/screen.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export class ScreenSpaceRotateHandle extends RegisteredHandle {
4242
}
4343

4444
bind(config?: HandlesProperties) {
45-
const options = extractHandleTransformOptions(this.axis, config)
45+
const { options, disabled } = extractHandleTransformOptions(this.axis, config)
4646
if (options === false) {
4747
return undefined
4848
}
@@ -54,6 +54,7 @@ export class ScreenSpaceRotateHandle extends RegisteredHandle {
5454
color: 0xffff00,
5555
hoverColor: 0xffff00,
5656
opacity: 0.5,
57+
disabled,
5758
})
5859
const visualizationMesh = new Mesh(createCircleGeometry(0.75, 1), material)
5960
visualizationMesh.renderOrder = Infinity
@@ -66,13 +67,13 @@ export class ScreenSpaceRotateHandle extends RegisteredHandle {
6667
interactionMesh.pointerEventsOrder = Infinity
6768
this.add(interactionMesh)
6869

69-
const unregister = this.context.registerHandle(this.store, interactionMesh, this.tag)
70+
const unregister = disabled ? undefined : this.context.registerHandle(this.store, interactionMesh, this.tag)
7071

7172
return () => {
7273
material.dispose()
7374
interactionMesh.geometry.dispose()
7475
visualizationMesh.geometry.dispose()
75-
unregister()
76+
unregister?.()
7677
cleanupHover?.()
7778
this.remove(interactionMesh)
7879
this.remove(visualizationMesh)

0 commit comments

Comments
 (0)