Skip to content

Commit

Permalink
feat(controls): Add Settings menu to Model3D (#1377)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conrad Chan authored May 13, 2021
1 parent a3eb40c commit e37e30b
Show file tree
Hide file tree
Showing 18 changed files with 801 additions and 33 deletions.
26 changes: 26 additions & 0 deletions src/i18n/en-US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,40 @@ auto_generated=Auto-Generated
# 3D Preview
# Button tooltip for showing/hiding the list of animation clips
box3d_animation_clips=Animation clips
# Settings camera projection listbox item value: Perspective
box3d_camera_projection_perspective=Perspective
# Settings camera projection listbox item value: Orthographic
box3d_camera_projection_orthographic=Orthographic
# Button tooltip for resetting all user modified settings in the control bar and Settings panel, to their defaults. This includes render mode, rotation, camera position
box3d_reset=Reset
# Button tooltip for playing and pausing animations
box3d_toggle_animation=Play/pause animation
# Button tooltip for toggling VR display mode in any 3D preview
box3d_toggle_vr=Toggle VR display
# Settings render mode listbox item value: Lit
box3d_render_mode_lit=Lit
# Settings render mode listbox item value: Unlit
box3d_render_mode_unlit=Unlit
# Settings render mode listbox item value: Normals
box3d_render_mode_normals=Normals
# Settings render mode listbox item value: Shape
box3d_render_mode_shape=Shape
# Settings render mode listbox item value: UV Overlay
box3d_render_mode_uv_overlay=UV Overlay
# Settings
box3d_settings=Settings
# Settings render mode label
box3d_settings_render_label=Render mode
# Settings show grid label
box3d_settings_grid_label=Show grid
# Settings show wireframes label
box3d_settings_wireframes_label=Show wireframes
# Settings show skeletons label
box3d_settings_skeletons_label=Show skeletons
# Settings camera projection label
box3d_settings_projection_label=Camera Projection
# Settings rotate model label
box3d_settings_rotate_label=Rotate Model

# Annotations
# Placeholder text for create textarea in annotation dialog
Expand Down
45 changes: 37 additions & 8 deletions src/lib/viewers/box3d/model3d/Model3DControlsNew.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,42 @@ import React from 'react';
import AnimationControls, { Props as AnimationControlsProps } from '../../controls/model3d/AnimationControls';
import ControlsBar from '../../controls/controls-bar';
import FullscreenToggle, { Props as FullscreenToggleProps } from '../../controls/fullscreen';
import Model3DSettings, { Props as Model3DSettingsProps } from '../../controls/model3d/Model3DSettings';
import ResetControl, { Props as ResetControlProps } from '../../controls/model3d/ResetControl';

export type Props = AnimationControlsProps & FullscreenToggleProps & ResetControlProps;
export type Props = AnimationControlsProps &
FullscreenToggleProps &
Model3DSettingsProps &
ResetControlProps & {
onSettingsClose: () => void;
onSettingsOpen: () => void;
};

export default function Model3DControls({
animationClips,
cameraProjection,
currentAnimationClipId,
isPlaying,
onAnimationClipSelect,
onCameraProjectionChange,
onFullscreenToggle,
onPlayPause,
onRenderModeChange,
onRotateOnAxisChange,
onReset,
onSettingsClose,
onSettingsOpen,
onShowGridToggle,
onShowSkeletonsToggle,
onShowWireframesToggle,
renderMode,
showGrid,
showSkeletons,
showWireframes,
}: Props): JSX.Element {
const handleReset = (): void => {
// TODO: will need to reset the state to defaults
onReset();
};

return (
<ControlsBar>
<ResetControl onReset={handleReset} />
<ResetControl onReset={onReset} />
<AnimationControls
animationClips={animationClips}
currentAnimationClipId={currentAnimationClipId}
Expand All @@ -31,7 +46,21 @@ export default function Model3DControls({
onPlayPause={onPlayPause}
/>
{/* TODO: VR button */}
{/* TODO: Settings button */}
<Model3DSettings
cameraProjection={cameraProjection}
onCameraProjectionChange={onCameraProjectionChange}
onClose={onSettingsClose}
onOpen={onSettingsOpen}
onRenderModeChange={onRenderModeChange}
onRotateOnAxisChange={onRotateOnAxisChange}
onShowGridToggle={onShowGridToggle}
onShowSkeletonsToggle={onShowSkeletonsToggle}
onShowWireframesToggle={onShowWireframesToggle}
renderMode={renderMode}
showGrid={showGrid}
showSkeletons={showSkeletons}
showWireframes={showWireframes}
/>
<FullscreenToggle onFullscreenToggle={onFullscreenToggle} />
</ControlsBar>
);
Expand Down
70 changes: 64 additions & 6 deletions src/lib/viewers/box3d/model3d/Model3DViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,24 @@ class Model3DViewer extends Box3DViewer {
/** @property {Object[]} - List of Box3D instances added to the scene */
instances = [];

/** @property {boolean} - Boolean indicating whether the animation is playihng */
/** @property {boolean} - Boolean indicating whether the animation is playing */
isAnimationPlaying = false;

/** @property {string} - string indicating what the camera projection is */
projection = CAMERA_PROJECTION_PERSPECTIVE;

/** @property {string} - string indicating what the render mode is */
renderMode = RENDER_MODE_LIT;

/** @property {boolean} - Boolean indicating whether the grid is showing */
showGrid = DEFAULT_RENDER_GRID;

/** @property {boolean} - Boolean indicating whether the skeletons are showing */
showSkeletons = false;

/** @property {boolean} - Boolean indicating whether the wireframes are showing */
showWireframes = false;

/** @inheritdoc */
constructor(option) {
super(option);
Expand Down Expand Up @@ -204,11 +219,11 @@ class Model3DViewer extends Box3DViewer {
this.renderMode = defaults.defaultRenderMode || RENDER_MODE_LIT;
this.projection = defaults.cameraProjection || CAMERA_PROJECTION_PERSPECTIVE;
if (defaults.renderGrid === 'true') {
this.renderGrid = true;
this.showGrid = true;
} else if (defaults.renderGrid === 'false') {
this.renderGrid = false;
this.showGrid = false;
} else {
this.renderGrid = DEFAULT_RENDER_GRID;
this.showGrid = DEFAULT_RENDER_GRID;
}

if (this.axes.up !== DEFAULT_AXIS_UP || this.axes.forward !== DEFAULT_AXIS_FORWARD) {
Expand Down Expand Up @@ -334,7 +349,12 @@ class Model3DViewer extends Box3DViewer {
handleReset() {
super.handleReset();

this.isAnimationPlaying = false;
this.setAnimationState(false);
this.handleSetCameraProjection(this.projection);
this.handleSetRenderMode(this.renderMode);
this.handleShowGrid(true);
this.handleShowSkeletons(false);
this.handleShowWireframes(false);

if (this.controls) {
if (this.getViewerOption('useReactControls')) {
Expand All @@ -344,7 +364,7 @@ class Model3DViewer extends Box3DViewer {
this.controls.setCurrentProjectionMode(this.projection);
this.controls.handleSetSkeletonsVisible(false);
this.controls.handleSetWireframesVisible(false);
this.controls.handleSetGridVisible(this.renderGrid);
this.controls.handleSetGridVisible(this.showGrid);
}
}

Expand All @@ -363,6 +383,11 @@ class Model3DViewer extends Box3DViewer {
*/
handleSetRenderMode(mode = 'Lit') {
this.renderer.setRenderMode(mode);

if (this.controls && this.getViewerOption('useReactControls')) {
this.renderMode = mode;
this.renderUI();
}
}

/**
Expand All @@ -387,6 +412,11 @@ class Model3DViewer extends Box3DViewer {
*/
handleSetCameraProjection(projection) {
this.renderer.setCameraProjection(projection);

if (this.controls && this.getViewerOption('useReactControls')) {
this.projection = projection;
this.renderUI();
}
}

/**
Expand All @@ -398,6 +428,11 @@ class Model3DViewer extends Box3DViewer {
*/
handleShowSkeletons(visible) {
this.renderer.setSkeletonsVisible(visible);

if (this.controls && this.getViewerOption('useReactControls')) {
this.showSkeletons = visible;
this.renderUI();
}
}

/**
Expand All @@ -409,6 +444,11 @@ class Model3DViewer extends Box3DViewer {
*/
handleShowWireframes(visible) {
this.renderer.setWireframesVisible(visible);

if (this.controls && this.getViewerOption('useReactControls')) {
this.showWireframes = visible;
this.renderUI();
}
}

/**
Expand All @@ -420,6 +460,11 @@ class Model3DViewer extends Box3DViewer {
*/
handleShowGrid(visible) {
this.renderer.setGridVisible(visible);

if (this.controls && this.getViewerOption('useReactControls')) {
this.showGrid = visible;
this.renderUI();
}
}

renderUI() {
Expand All @@ -430,12 +475,25 @@ class Model3DViewer extends Box3DViewer {
this.controls.render(
<Model3DControlsNew
animationClips={this.animationClips}
cameraProjection={this.projection}
currentAnimationClipId={this.renderer.getAnimationClip()}
isPlaying={this.isAnimationPlaying}
onAnimationClipSelect={this.handleSelectAnimationClip}
onCameraProjectionChange={this.handleSetCameraProjection}
onFullscreenToggle={this.toggleFullscreen}
onPlayPause={this.handleToggleAnimation}
onRenderModeChange={this.handleSetRenderMode}
onReset={this.handleReset}
onRotateOnAxisChange={this.handleRotateOnAxis}
onSettingsClose={() => this.handleToggleHelpers(false)}
onSettingsOpen={() => this.handleToggleHelpers(true)}
onShowGridToggle={this.handleShowGrid}
onShowSkeletonsToggle={this.handleShowSkeletons}
onShowWireframesToggle={this.handleShowWireframes}
renderMode={this.renderMode}
showGrid={this.showGrid}
showSkeletons={this.showSkeletons}
showWireframes={this.showWireframes}
/>,
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,93 @@
import React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
import Model3DControls, { Props } from '../Model3DControlsNew';
import ResetControl from '../../../controls/model3d/ResetControl';
import AnimationControls from '../../../controls/model3d/AnimationControls';
import FullscreenToggle from '../../../controls/fullscreen';
import Model3DControls, { Props } from '../Model3DControlsNew';
import ResetControl from '../../../controls/model3d/ResetControl';
import Model3DSettings, { CameraProjection, RenderMode } from '../../../controls/model3d/Model3DSettings';

describe('lib/viewers/box3d/model3d/Model3DControlsNew', () => {
const getDefaults = (): Props => ({
animationClips: [],
cameraProjection: CameraProjection.PERSPECTIVE,
currentAnimationClipId: '123',
isPlaying: false,
onAnimationClipSelect: jest.fn(),
onCameraProjectionChange: jest.fn(),
onFullscreenToggle: jest.fn(),
onPlayPause: jest.fn(),
onRenderModeChange: jest.fn(),
onRotateOnAxisChange: jest.fn(),
onReset: jest.fn(),
onSettingsClose: jest.fn(),
onSettingsOpen: jest.fn(),
onShowGridToggle: jest.fn(),
onShowSkeletonsToggle: jest.fn(),
onShowWireframesToggle: jest.fn(),
renderMode: RenderMode.LIT,
showGrid: true,
showSkeletons: false,
showWireframes: false,
});

const getWrapper = (props: Partial<Props>): ShallowWrapper =>
shallow(<Model3DControls {...getDefaults()} {...props} />);

describe('render()', () => {
test('should return a valid wrapper', () => {
const onAnimationClipSelect = jest.fn();
const onCameraProjectionChange = jest.fn();
const onFullscreenToggle = jest.fn();
const onPlayPause = jest.fn();
const onRenderModeChange = jest.fn();
const onRotateOnAxisChange = jest.fn();
const onReset = jest.fn();
const onSettingsClose = jest.fn();
const onSettingsOpen = jest.fn();
const onShowGridToggle = jest.fn();
const onShowSkeletonsToggle = jest.fn();
const onShowWireframesToggle = jest.fn();

const wrapper = getWrapper({ onAnimationClipSelect, onFullscreenToggle, onPlayPause });
const wrapper = getWrapper({
onAnimationClipSelect,
onCameraProjectionChange,
onFullscreenToggle,
onPlayPause,
onRenderModeChange,
onRotateOnAxisChange,
onReset,
onSettingsClose,
onSettingsOpen,
onShowGridToggle,
onShowSkeletonsToggle,
onShowWireframesToggle,
});

expect(wrapper.find(ResetControl).props()).toMatchObject({
onReset,
});
expect(wrapper.find(AnimationControls).props()).toMatchObject({
animationClips: [],
currentAnimationClipId: '123',
isPlaying: false,
onAnimationClipSelect,
onPlayPause,
});
expect(wrapper.find(Model3DSettings).props()).toMatchObject({
cameraProjection: CameraProjection.PERSPECTIVE,
onCameraProjectionChange,
onClose: onSettingsClose,
onOpen: onSettingsOpen,
onRenderModeChange,
onRotateOnAxisChange,
onShowGridToggle,
onShowSkeletonsToggle,
onShowWireframesToggle,
renderMode: RenderMode.LIT,
showGrid: true,
showSkeletons: false,
showWireframes: false,
});
expect(wrapper.find(FullscreenToggle).prop('onFullscreenToggle')).toEqual(onFullscreenToggle);
});
});
Expand Down
Loading

0 comments on commit e37e30b

Please sign in to comment.