Skip to content

Commit ee76d85

Browse files
committed
feat(View): move interactor style up to View
The View component controls the interactor style, as that's the primary component for working with multiple views. Other changes: - Fixes the interactor style being deleted before it gets removed from the interactor.
1 parent 2df6b75 commit ee76d85

File tree

5 files changed

+97
-82
lines changed

5 files changed

+97
-82
lines changed

src/core-ts/RenderWindow.tsx

Lines changed: 4 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -17,62 +17,10 @@ import useResizeObserver from '../utils-ts/useResizeObserver';
1717
import useUnmount from '../utils-ts/useUnmount';
1818
import { OpenGLRenderWindowContext, RenderWindowContext } from './contexts';
1919
import useInteractor from './modules/useInteractor';
20-
import {
21-
ManipulatorSettings,
22-
useInteractorStyle,
23-
useInteractorStyleManipulatorSettings,
24-
} from './modules/useInteractorStyle';
25-
26-
export interface Props extends PropsWithChildren {
27-
/**
28-
* Configure the interactions
29-
*/
30-
interactorSettings?: ManipulatorSettings[];
31-
}
32-
33-
const DefaultProps = {
34-
interactorSettings: [
35-
{
36-
button: 1,
37-
action: 'Rotate',
38-
},
39-
{
40-
button: 2,
41-
action: 'Pan',
42-
},
43-
{
44-
button: 3,
45-
action: 'Zoom',
46-
scrollEnabled: true,
47-
},
48-
{
49-
button: 1,
50-
action: 'Pan',
51-
alt: true,
52-
},
53-
{
54-
button: 1,
55-
action: 'Zoom',
56-
control: true,
57-
},
58-
{
59-
button: 1,
60-
action: 'Select',
61-
shift: true,
62-
},
63-
{
64-
button: 1,
65-
action: 'Roll',
66-
alt: true,
67-
shift: true,
68-
},
69-
] as ManipulatorSettings[],
70-
};
71-
72-
// TODO Wrap in OpenGLRenderWindow by default
73-
export default forwardRef(function RenderWindow(props: Props, fwdRef) {
74-
const { interactorSettings = DefaultProps.interactorSettings } = props;
7520

21+
export type Props = PropsWithChildren;
22+
23+
export default forwardRef(function RenderWindow(props: Props, fwdRef) {
7624
const openGLRenderWindow = useContext(OpenGLRenderWindowContext);
7725
if (!openGLRenderWindow) throw new Error('No OpenGL Render Window!');
7826

@@ -110,11 +58,6 @@ export default forwardRef(function RenderWindow(props: Props, fwdRef) {
11058
getRenderWindow().setInteractor(getInteractor());
11159
});
11260

113-
const [getInteractorStyle, setInteractorStyle] =
114-
useInteractorStyle(getInteractor);
115-
116-
useInteractorStyleManipulatorSettings(getInteractorStyle, interactorSettings);
117-
11861
// --- rendering --- //
11962

12063
const [renderRequested, setRenderRequested] = useState(false);
@@ -153,11 +96,9 @@ export default forwardRef(function RenderWindow(props: Props, fwdRef) {
15396
() => ({
15497
get: getRenderWindow,
15598
getInteractor,
156-
getInteractorStyle,
157-
setInteractorStyle,
15899
requestRender: queueRender,
159100
}),
160-
[getRenderWindow, getInteractor, getInteractorStyle, setInteractorStyle]
101+
[getRenderWindow, getInteractor]
161102
);
162103

163104
useImperativeHandle(fwdRef, () => api);

src/core-ts/View.tsx

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import vtkInteractorStyle from '@kitware/vtk.js/Interaction/Style/InteractorStyle';
12
import { FixedVTKRenderWindowInteractor } from '@kitware/vtk.js/type-patches';
23
import { Bounds } from '@kitware/vtk.js/types';
34
import {
@@ -21,6 +22,11 @@ import {
2122
OpenGLRenderWindowContext,
2223
RenderWindowContext,
2324
} from './contexts';
25+
import {
26+
ManipulatorSettings,
27+
useInteractorStyle,
28+
useInteractorStyleManipulatorSettings,
29+
} from './modules/useInteractorStyle';
2430
import OpenGLRenderWindow, {
2531
Props as OpenGLRenderWindowProps,
2632
} from './OpenGLRenderWindow';
@@ -64,8 +70,51 @@ interface Props
6470
* Show/Hide orientation axes.
6571
*/
6672
// showOrientationAxes?: boolean;
73+
/**
74+
* Configure the interactions
75+
*/
76+
interactorSettings?: ManipulatorSettings[];
6777
}
6878

79+
const DefaultProps = {
80+
interactorSettings: [
81+
{
82+
button: 1,
83+
action: 'Rotate',
84+
},
85+
{
86+
button: 2,
87+
action: 'Pan',
88+
},
89+
{
90+
button: 3,
91+
action: 'Zoom',
92+
scrollEnabled: true,
93+
},
94+
{
95+
button: 1,
96+
action: 'Pan',
97+
alt: true,
98+
},
99+
{
100+
button: 1,
101+
action: 'Zoom',
102+
control: true,
103+
},
104+
{
105+
button: 1,
106+
action: 'Select',
107+
shift: true,
108+
},
109+
{
110+
button: 1,
111+
action: 'Roll',
112+
alt: true,
113+
shift: true,
114+
},
115+
] as ManipulatorSettings[],
116+
};
117+
69118
/**
70119
* A standalone View (not within a MultiViewRoot).
71120
*/
@@ -75,7 +124,6 @@ const SingleView = forwardRef(function SingleView(props: Props, fwdRef) {
75124
const renderWindowRef = useRef<IRenderWindow | null>(null);
76125
const rendererRef = useRef<IRenderer | null>(null);
77126

78-
const renderWindowProps = pick(props, 'interactorSettings');
79127
const rendererProps = pick(
80128
props,
81129
'background',
@@ -87,24 +135,38 @@ const SingleView = forwardRef(function SingleView(props: Props, fwdRef) {
87135

88136
const openGLRenderWindowProps = omit(
89137
props,
90-
...([
91-
...Object.keys(renderWindowProps),
92-
...Object.keys(rendererProps),
93-
] as (keyof Props)[])
138+
...([...Object.keys(rendererProps)] as (keyof Props)[])
94139
);
95140

141+
// --- interactor style --- //
142+
143+
const getInteractor = useCallback(
144+
() => renderWindowRef.current?.getInteractor() ?? null,
145+
[]
146+
);
147+
148+
const [getInteractorStyle, setInteractorStyle] =
149+
useInteractorStyle(getInteractor);
150+
151+
const { interactorSettings = DefaultProps.interactorSettings } = props;
152+
useInteractorStyleManipulatorSettings(getInteractorStyle, interactorSettings);
153+
154+
// --- api --- //
155+
96156
const api = useMemo<IView>(
97157
() => ({
98158
isInMultiViewRoot: () => false,
99159
getOpenGLRenderWindow: () => openGLRenderWindowRef.current,
100160
getRenderWindow: () => renderWindowRef.current,
101161
getRenderer: () => rendererRef.current,
162+
getInteractorStyle: () => getInteractorStyle(),
163+
setInteractorStyle: (style) => setInteractorStyle(style),
102164
requestRender: () => rendererRef.current?.requestRender(),
103165
getCamera: () => rendererRef.current?.get().getActiveCamera() ?? null,
104166
resetCamera: (boundsToUse?: Bounds) =>
105167
rendererRef.current?.resetCamera(boundsToUse),
106168
}),
107-
[]
169+
[getInteractorStyle, setInteractorStyle]
108170
);
109171

110172
useImperativeHandle(fwdRef, () => api);
@@ -114,7 +176,7 @@ const SingleView = forwardRef(function SingleView(props: Props, fwdRef) {
114176
{...openGLRenderWindowProps}
115177
ref={openGLRenderWindowRef}
116178
>
117-
<RenderWindow {...renderWindowProps} ref={renderWindowRef}>
179+
<RenderWindow ref={renderWindowRef}>
118180
<Renderer {...rendererProps} ref={rendererRef}>
119181
{props.children}
120182
</Renderer>
@@ -225,6 +287,12 @@ const ParentedView = forwardRef(function ParentedView(props: Props, fwdRef) {
225287
getOpenGLRenderWindow: () => openGLRenderWindowAPI,
226288
getRenderWindow: () => renderWindowAPI,
227289
getRenderer: () => rendererRef.current,
290+
// TODO
291+
getInteractorStyle: () => ({} as unknown as vtkInteractorStyle),
292+
// TODO
293+
setInteractorStyle: (style) => {
294+
console.log(style);
295+
},
228296
requestRender: () => rendererRef.current?.requestRender(),
229297
getCamera: () => rendererRef.current?.get().getActiveCamera() ?? null,
230298
resetCamera: (boundsToUse?: Bounds) =>
@@ -271,6 +339,8 @@ export default forwardRef(function View(props: Props, fwdRef) {
271339
getOpenGLRenderWindow: () => getView()?.getOpenGLRenderWindow() ?? null,
272340
getRenderWindow: () => getView()?.getRenderWindow() ?? null,
273341
getRenderer: () => getView()?.getRenderer() ?? null,
342+
getInteractorStyle: () => getView()?.getInteractorStyle() ?? null,
343+
setInteractorStyle: (style) => getView()?.setInteractorStyle(style),
274344
requestRender: () => getView()?.requestRender(),
275345
getCamera: () => getView()?.getCamera() ?? null,
276346
resetCamera: (boundsToUse?: Bounds) =>

src/core-ts/modules/useInteractor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor';
22
import { useEffect } from 'react';
3+
import { IOpenGLRenderWindow } from '../../types';
34
import deletionRegistry from '../../utils-ts/DeletionRegistry';
45
import useGetterRef from '../../utils-ts/useGetterRef';
56
import useUnmount from '../../utils-ts/useUnmount';
6-
import { IOpenGLRenderWindow } from '../OpenGLRenderWindow';
77

88
export default function useInteractor(openglRenderWindow: IOpenGLRenderWindow) {
99
const [interactorRef, getInteractor] = useGetterRef(() => {

src/core-ts/modules/useInteractorStyle.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import vtkMouseCameraTrackballZoomToMouseManipulator, {
2323
import vtkInteractorStyle from '@kitware/vtk.js/Interaction/Style/InteractorStyle';
2424
import vtkInteractorStyleManipulator from '@kitware/vtk.js/Interaction/Style/InteractorStyleManipulator';
2525
import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor';
26-
import { Nullable } from '@kitware/vtk.js/types';
2726
import deepEqual from 'deep-equal';
2827
import { useCallback, useEffect, useState } from 'react';
2928
import deletionRegistry from '../../utils-ts/DeletionRegistry';
@@ -116,10 +115,11 @@ export function useInteractorStyleManipulatorSettings(
116115
}
117116

118117
export function useInteractorStyle(
119-
getInteractor: () => vtkRenderWindowInteractor
118+
getInteractor: () => vtkRenderWindowInteractor | null
120119
) {
121-
const [externalStyle, setExternalStyle] =
122-
useState<Nullable<vtkInteractorStyle>>(null);
120+
const [externalStyle, setExternalStyle] = useState<vtkInteractorStyle | null>(
121+
null
122+
);
123123

124124
const [styleRef, getStyle] = useGetterRef<vtkInteractorStyle>(() => {
125125
setExternalStyle(null);
@@ -130,16 +130,22 @@ export function useInteractorStyle(
130130

131131
useEffect(() => {
132132
const interactor = getInteractor();
133-
const style = getStyle();
134-
deletionRegistry.incRefCount(interactor);
133+
if (!interactor) return;
134+
135+
const style = externalStyle ?? getStyle();
135136
interactor.setInteractorStyle(style);
137+
138+
deletionRegistry.incRefCount(interactor);
139+
deletionRegistry.incRefCount(style);
140+
136141
return () => {
137142
if (interactor.getInteractorStyle() === style) {
138143
interactor.setInteractorStyle(null);
139144
}
140145
deletionRegistry.decRefCount(interactor);
146+
deletionRegistry.incRefCount(style);
141147
};
142-
}, [getInteractor, getStyle]);
148+
});
143149

144150
useUnmount(() => {
145151
if (styleRef.current && !externalStyle) {

src/types.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ export interface IOpenGLRenderWindow {
4343
export interface IRenderWindow {
4444
get(): vtkRenderWindow;
4545
getInteractor(): vtkRenderWindowInteractor;
46-
getInteractorStyle(): vtkInteractorStyle;
47-
setInteractorStyle(style: vtkInteractorStyle): void;
4846
requestRender(): void;
4947
}
5048

@@ -61,8 +59,8 @@ export interface IView {
6159
getOpenGLRenderWindow(): IOpenGLRenderWindow | null;
6260
// getAPISpecificRenderWindow(): vtkOpenGLRenderWindow;
6361
// getInteractor(): vtkRenderWindowInteractor;
64-
// getInteractorStyle(): vtkInteractorStyle;
65-
// setInteractorStyle(style: vtkInteractorStyle): void;
62+
getInteractorStyle(): vtkInteractorStyle | null;
63+
setInteractorStyle(style: vtkInteractorStyle): void;
6664
requestRender(): void;
6765
getCamera(): vtkCamera | null;
6866
resetCamera(boundsToUse?: Bounds): void;

0 commit comments

Comments
 (0)