diff --git a/extensions/vtk/src/commandsModule.js b/extensions/vtk/src/commandsModule.js
index 677a50fc1..d57156712 100644
--- a/extensions/vtk/src/commandsModule.js
+++ b/extensions/vtk/src/commandsModule.js
@@ -18,6 +18,7 @@ const { BlendMode } = Constants;
// TODO: Put this somewhere else
let apis = {};
let currentSlabThickness = 0.1;
+let defaultSlabThickness = 0.1;
function getCrosshairCallbackForIndex(index) {
return ({ worldPos }) => {
@@ -117,6 +118,7 @@ function switchMPRInteractors(api, istyle) {
let currentSlabThickness;
if (currentIStyle.getSlabThickness && istyle.getSlabThickness) {
currentSlabThickness = currentIStyle.getSlabThickness();
+ defaultSlabThickness = currentSlabThickness;
}
renderWindow.getInteractor().setInteractorStyle(istyle);
@@ -182,7 +184,7 @@ const actions = {
switchMPRInteractors(api, istyle);
});
},
- setSlabThickness: slabThickness => {
+ setSlabThickness: ({ slabThickness }) => {
currentSlabThickness = slabThickness;
apis.forEach(api => {
@@ -191,15 +193,6 @@ const actions = {
if (istyle.setSlabThickness) {
istyle.setSlabThickness(currentSlabThickness);
-
- // TODO: Do this inside the interactors in a setSlabThickness function instead
- const renderer = api.genericRenderWindow.getRenderer();
- const camera = renderer.getActiveCamera();
- const dist = camera.getDistance();
- const near = dist - currentSlabThickness / 2;
- const far = dist + currentSlabThickness / 2;
-
- camera.setClippingRange(near, far);
}
renderWindow.render();
@@ -220,6 +213,32 @@ const actions = {
renderWindow.render();
});
},
+ setBlendModeToComposite: () => {
+ apis.forEach(api => {
+ const renderWindow = api.genericRenderWindow.getRenderWindow();
+ const istyle = renderWindow.getInteractor().getInteractorStyle();
+
+ const mapper = api.volumes[0].getMapper();
+ if (mapper.setBlendModeToComposite) {
+ mapper.setBlendModeToComposite();
+ }
+
+ if (istyle.setSlabThickness) {
+ istyle.setSlabThickness(defaultSlabThickness);
+ }
+ renderWindow.render();
+ });
+ },
+ setBlendModeToMaximumIntensity: () => {
+ apis.forEach(api => {
+ const renderWindow = api.genericRenderWindow.getRenderWindow();
+ const mapper = api.volumes[0].getMapper();
+ if (mapper.setBlendModeToMaximumIntensity) {
+ mapper.setBlendModeToMaximumIntensity();
+ }
+ renderWindow.render();
+ });
+ },
setBlendMode: ({ blendMode }) => {
apis.forEach(api => {
const renderWindow = api.genericRenderWindow.getRenderWindow();
@@ -338,12 +357,12 @@ const definitions = {
options: {},
},
setBlendModeToComposite: {
- commandFn: actions.setBlendMode,
+ commandFn: actions.setBlendModeToComposite,
storeContexts: [],
options: { blendMode: BlendMode.COMPOSITE_BLEND },
},
setBlendModeToMaximumIntensity: {
- commandFn: actions.setBlendMode,
+ commandFn: actions.setBlendModeToMaximumIntensity,
storeContexts: [],
options: { blendMode: BlendMode.MAXIMUM_INTENSITY_BLEND },
},
diff --git a/extensions/vtk/src/toolbarComponents/SlabThicknessToolbarComponent.js b/extensions/vtk/src/toolbarComponents/SlabThicknessToolbarComponent.js
new file mode 100644
index 000000000..50327f3e4
--- /dev/null
+++ b/extensions/vtk/src/toolbarComponents/SlabThicknessToolbarComponent.js
@@ -0,0 +1,207 @@
+import React, { useState, useEffect } from 'react';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+import { Range, Checkbox, Select } from '@ohif/ui';
+
+import './slab-thickness-toolbar-button.styl';
+
+const SLIDER = {
+ MIN: 0.1,
+ MAX: 1000,
+ STEP: 0.1,
+};
+
+const ToolbarLabel = props => {
+ const { label } = props;
+ return
{label}
;
+};
+
+const ToolbarSlider = props => {
+ const { value, min, max, onChange } = props;
+ return (
+
+
+
+
+ );
+};
+
+const _getSelectOptions = button => {
+ return button.operationButtons.map(button => {
+ return {
+ key: button.label,
+ value: button.id,
+ };
+ });
+};
+
+const _getClassNames = (isActive, className) => {
+ return classnames('toolbar-button', 'slab-thickness', className, {
+ active: isActive,
+ });
+};
+
+const _applySlabThickness = (
+ value,
+ modeChecked,
+ toolbarClickCallback,
+ button
+) => {
+ if (!modeChecked || !toolbarClickCallback) {
+ return;
+ }
+
+ const { actionButton } = button;
+
+ const generateOperation = (operation, value) => {
+ // Combine slider value into slider operation
+ const generatedOperation = { ...operation };
+ generatedOperation.commandOptions = {
+ ...operation.commandOptions,
+ slabThickness: value,
+ };
+
+ return generatedOperation;
+ };
+
+ const operation = generateOperation(actionButton, value);
+ toolbarClickCallback(operation, event);
+};
+
+const _applyModeOperation = (
+ operation,
+ modeChecked,
+ toolbarClickCallback,
+ button
+) => {
+ // in case modeChecked has not being triggered by user yet
+ if (typeof modeChecked !== 'boolean') {
+ return;
+ }
+
+ const { deactivateButton } = button;
+
+ const _operation = modeChecked ? operation : deactivateButton;
+ if (toolbarClickCallback && _operation) {
+ toolbarClickCallback(_operation);
+ }
+};
+
+const _getInitialState = currentSelectedOption => {
+ return {
+ value: SLIDER.MIN,
+ sliderMin: SLIDER.MIN,
+ sliderMax: SLIDER.MAX,
+ modeChecked: undefined,
+ operation: currentSelectedOption,
+ };
+};
+
+const INITIAL_OPTION_INDEX = 0;
+const _getInitialtSelectedOption = (button = {}) => {
+ return (
+ button.operationButtons && button.operationButtons[INITIAL_OPTION_INDEX]
+ );
+};
+
+function SlabThicknessToolbarComponent({
+ parentContext,
+ toolbarClickCallback,
+ button,
+ activeButtons,
+ isActive,
+ className,
+}) {
+ const currentSelectedOption = _getInitialtSelectedOption(button);
+ const [state, setState] = useState(_getInitialState(currentSelectedOption));
+ const { label, operationButtons } = button;
+ const _className = _getClassNames(isActive, className);
+ const selectOptions = _getSelectOptions(button);
+ function onChangeSelect(selectedValue) {
+ // find select value
+ const operation = operationButtons.find(
+ button => button.id === selectedValue
+ );
+
+ if (operation === state.operation) {
+ return;
+ }
+
+ setState({ ...state, operation });
+ }
+
+ function onChangeCheckbox(checked) {
+ setState({ ...state, modeChecked: checked });
+ }
+
+ function onChangeSlider(event) {
+ const value = Number(event.target.value);
+
+ if (value !== state.value) {
+ setState({ ...state, value, modeChecked: true });
+ }
+ }
+
+ useEffect(() => {
+ _applyModeOperation(
+ state.operation,
+ state.modeChecked,
+ toolbarClickCallback,
+ button
+ );
+ }, [state.modeChecked, state.operation]);
+
+ useEffect(() => {
+ _applySlabThickness(
+ state.value,
+ state.modeChecked,
+ toolbarClickCallback,
+ button
+ );
+ }, [state.operation, state.modeChecked, state.value]);
+
+ return (
+
+ );
+}
+
+SlabThicknessToolbarComponent.propTypes = {
+ parentContext: PropTypes.object.isRequired,
+ toolbarClickCallback: PropTypes.func.isRequired,
+ button: PropTypes.object.isRequired,
+ activeButtons: PropTypes.array.isRequired,
+ isActive: PropTypes.bool,
+ className: PropTypes.string,
+};
+
+export default SlabThicknessToolbarComponent;
diff --git a/extensions/vtk/src/toolbarComponents/slab-thickness-toolbar-button.styl b/extensions/vtk/src/toolbarComponents/slab-thickness-toolbar-button.styl
new file mode 100644
index 000000000..c8441e89f
--- /dev/null
+++ b/extensions/vtk/src/toolbarComponents/slab-thickness-toolbar-button.styl
@@ -0,0 +1,55 @@
+.slab-thickness
+ display: flex;
+ flex-direction: row;
+ align-items: flex-end;
+ height: 60px;
+ margin-top: -12px;
+ &:hover
+ color: var(--default-color);
+ .container
+ padding-right: 10px;
+ height: inherit;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ .toolbar-slider-container
+ width: 80px;
+ margin: 0px 2px 2px 2px;
+ font-size: 12px;
+ &:hover
+ color: var(--hover-color);
+ input
+ height: 20px;
+ padding-top: 6px;
+ &::-moz-range-thumb
+ height: 16px;
+ margin-top: -7px;
+ &::-webkit-slider-thumb
+ height: 16px;
+ margin-top: -7px;
+ .controller
+ width: 62px;
+ .ohif-check-container
+ margin-bottom: 5px;
+ padding-left: 18px;
+ .ohif-check-label
+ text-transform: capitalize;
+ &:hover
+ color: var(--hover-color);
+ .ohif-checkbox
+ border-radius: 3px;
+ background-color: white;
+ width: 12px;
+ height: 12px;
+ top: 22%;
+ &.ohif-checked:after
+ background-color: var(--active-color);
+ top: 17%;
+ left: 17%;
+ .select-ohif
+ color: var(--default-color);
+ border-color: var(--default-color);
+ background-color: black;
+ background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007CB2%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');
+ &:hover
+ color: var(--hover-color);
diff --git a/extensions/vtk/src/toolbarModule.js b/extensions/vtk/src/toolbarModule.js
index 9f2832047..805644dd2 100644
--- a/extensions/vtk/src/toolbarModule.js
+++ b/extensions/vtk/src/toolbarModule.js
@@ -1,3 +1,5 @@
+import SlabThicknessToolbarComponent from './toolbarComponents/SlabThicknessToolbarComponent';
+
const TOOLBAR_BUTTON_TYPES = {
COMMAND: 'command',
SET_TOOL_ACTIVE: 'setToolActive',
@@ -31,6 +33,7 @@ const definitions = [
commandName: 'enableRotateTool',
commandOptions: {},
},
+ /*
{
id: 'setBlendModeToComposite',
label: 'Disable MIP',
@@ -68,6 +71,50 @@ const definitions = [
commandName: 'decreaseSlabThickness',
commandOptions: {},
},
+ */
+ {
+ id: 'changeSlabThickness',
+ label: 'Slab Thickness',
+ icon: 'soft-tissue',
+ CustomComponent: SlabThicknessToolbarComponent,
+ commandName: 'setSlabThickness',
+ actionButton: {
+ id: 'setSlabThickness',
+ label: 'slider',
+ type: TOOLBAR_BUTTON_TYPES.COMMAND,
+ commandName: 'setSlabThickness',
+ commandOptions: {},
+ },
+ deactivateButton: {
+ id: 'setBlendModeToComposite',
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setBlendModeToComposite',
+ commandOptions: {},
+ },
+ operationButtons: [
+ {
+ id: 'setBlendModeToMaximumIntensity',
+ label: 'MIP',
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setBlendModeToMaximumIntensity',
+ commandOptions: {},
+ },
+ {
+ id: 'setBlendModeToMinimumIntensity',
+ label: 'MinIP',
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setBlendModeToMinimumIntensity',
+ commandOptions: {},
+ },
+ {
+ id: 'setBlendModeToAverageIntensity',
+ label: 'AvgIP',
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setBlendModeToAverageIntensity',
+ commandOptions: {},
+ },
+ ],
+ },
];
export default {
diff --git a/platform/ui/src/components/checkbox/checkbox.js b/platform/ui/src/components/checkbox/checkbox.js
index 5f1f16ea3..0315bab02 100644
--- a/platform/ui/src/components/checkbox/checkbox.js
+++ b/platform/ui/src/components/checkbox/checkbox.js
@@ -6,15 +6,29 @@ export class Checkbox extends Component {
static propTypes = {
label: PropTypes.string.isRequired,
checked: PropTypes.bool,
+ onChange: PropTypes.func,
};
constructor(props) {
super(props);
- this.state = { checked: props.checked, label: props.label };
+ this.state = { checked: !!props.checked, label: props.label };
}
handleChange(e) {
- this.setState({ checked: e.target.checked });
+ const checked = e.target.checked;
+ this.setState({ checked });
+ if (this.props.onChange) this.props.onChange(checked);
+ }
+
+ componentDidUpdate(props) {
+ const { checked = false, label } = props;
+
+ if (this.state.checked !== checked || this.state.label !== label) {
+ this.setState({
+ checked,
+ label,
+ });
+ }
}
render() {
@@ -32,9 +46,7 @@ export class Checkbox extends Component {
{
- this.handleChange(e);
- }}
+ onChange={this.handleChange.bind(this)}
/>
{checkbox}
{this.state.label}
diff --git a/platform/ui/src/components/index.js b/platform/ui/src/components/index.js
index bc9beb74a..34b3d421e 100644
--- a/platform/ui/src/components/index.js
+++ b/platform/ui/src/components/index.js
@@ -13,6 +13,7 @@ import {
UserPreferencesModal,
} from './userPreferencesModal';
+import { Checkbox } from './checkbox';
import { CineDialog } from './cineDialog';
import { QuickSwitch } from './quickSwitch';
import { RoundedButtonGroup } from './roundedButtonGroup';
@@ -23,6 +24,7 @@ import { ToolbarSection } from './toolbarSection';
import { Tooltip } from './tooltip';
export {
+ Checkbox,
CineDialog,
ExampleDropTarget,
LayoutButton,
diff --git a/platform/ui/src/elements/form/Range.css b/platform/ui/src/elements/form/Range.css
index 434a8486f..3bdaa94c2 100644
--- a/platform/ui/src/elements/form/Range.css
+++ b/platform/ui/src/elements/form/Range.css
@@ -2,6 +2,7 @@
margin: 0;
width: 100%;
-webkit-appearance: none;
+ background-color: transparent;
}
.range:focus {
diff --git a/platform/ui/src/elements/form/Range.js b/platform/ui/src/elements/form/Range.js
index a8647a8fa..479668431 100644
--- a/platform/ui/src/elements/form/Range.js
+++ b/platform/ui/src/elements/form/Range.js
@@ -11,7 +11,7 @@ class Range extends React.Component {
handleChange = event => {
this.setState({ value: event.target.value });
- if (this.props.onChange) this.props.onChange();
+ if (this.props.onChange) this.props.onChange(event);
};
render() {
@@ -21,6 +21,7 @@ class Range extends React.Component {
value={this.state.value}
min={this.props.min}
max={this.props.max}
+ step={this.props.step || 1}
onChange={this.handleChange}
id={this.props.id}
className="range"
diff --git a/platform/ui/src/elements/form/Select.css b/platform/ui/src/elements/form/Select.css
index 0ea43c5a9..3f420fd39 100644
--- a/platform/ui/src/elements/form/Select.css
+++ b/platform/ui/src/elements/form/Select.css
@@ -34,10 +34,6 @@
}
.select-ohif:focus {
- border-color: #aaa;
- box-shadow: 0 0 1px 3px rgba(59, 153, 252, 0.7);
- box-shadow: 0 0 0 3px -moz-mac-focusring;
- color: #222;
outline: none;
}
diff --git a/platform/ui/src/elements/form/Select.js b/platform/ui/src/elements/form/Select.js
index 5652f9a8c..fe8a79dbb 100644
--- a/platform/ui/src/elements/form/Select.js
+++ b/platform/ui/src/elements/form/Select.js
@@ -11,8 +11,9 @@ class Select extends Component {
}
handleChange = event => {
- this.setState({ value: event.target.value });
- if (this.props.onChange) this.props.onChange();
+ const value = event.target.value;
+ this.setState({ value });
+ if (this.props.onChange) this.props.onChange(value);
};
render() {
diff --git a/platform/ui/src/index.js b/platform/ui/src/index.js
index 90a121e9a..ba4d32550 100644
--- a/platform/ui/src/index.js
+++ b/platform/ui/src/index.js
@@ -1,4 +1,5 @@
import {
+ Checkbox,
CineDialog,
ExampleDropTarget,
LayoutButton,
@@ -25,7 +26,7 @@ import {
import { ICONS, Icon } from './elements';
// Alias this for now as not all dependents are using strict versioning
-import { DropdownMenu as Dropdown } from './elements/form';
+import { DropdownMenu as Dropdown, Range, Select } from './elements/form';
import ExpandableToolMenu from './viewer/ExpandableToolMenu.js';
import LayoutManager from './LayoutChooser/LayoutManager.js';
import LayoutPanelDropTarget from './LayoutChooser/LayoutPanelDropTarget.js';
@@ -38,6 +39,7 @@ import ViewerbaseDragDropContext from './utils/viewerbaseDragDropContext.js';
export {
ICONS,
//
+ Checkbox,
CineDialog,
Dropdown,
ExpandableToolMenu,
@@ -53,8 +55,10 @@ export {
OverlayTrigger,
PlayClipButton,
QuickSwitch,
+ Range,
RoundedButtonGroup,
ScrollableArea,
+ Select,
SelectTree,
SimpleDialog,
StudyBrowser,
diff --git a/platform/ui/src/viewer/ExpandableToolMenu.js b/platform/ui/src/viewer/ExpandableToolMenu.js
index 0934e212f..e7df9cc34 100644
--- a/platform/ui/src/viewer/ExpandableToolMenu.js
+++ b/platform/ui/src/viewer/ExpandableToolMenu.js
@@ -108,16 +108,8 @@ class ExpandableToolMenu extends React.Component {
};
render() {
- return (
-
+ const getToolBarButtonComponent = () => {
+ return (
+ );
+ };
+
+ const toolbarComponent = getToolBarButtonComponent();
+
+ return (
+
+ {toolbarComponent}
);
}
diff --git a/platform/viewer/src/connectedComponents/ToolbarRow.js b/platform/viewer/src/connectedComponents/ToolbarRow.js
index 1612f44e0..ef5705d0c 100644
--- a/platform/viewer/src/connectedComponents/ToolbarRow.js
+++ b/platform/viewer/src/connectedComponents/ToolbarRow.js
@@ -229,6 +229,7 @@ function _getButtonComponents(toolbarButtons, activeButtons) {
});
}
+
/**
* A handy way for us to handle different button types. IE. firing commands for
* buttons, or initiation built in behavior.