feat: 🎸 MPR UI improvements. Added MinIP, AvgIP, slab thickness slider and mode toggle (#947)
This commit is contained in:
parent
ff5060f276
commit
c79c0c301d
@ -18,6 +18,7 @@ const { BlendMode } = Constants;
|
|||||||
// TODO: Put this somewhere else
|
// TODO: Put this somewhere else
|
||||||
let apis = {};
|
let apis = {};
|
||||||
let currentSlabThickness = 0.1;
|
let currentSlabThickness = 0.1;
|
||||||
|
let defaultSlabThickness = 0.1;
|
||||||
|
|
||||||
function getCrosshairCallbackForIndex(index) {
|
function getCrosshairCallbackForIndex(index) {
|
||||||
return ({ worldPos }) => {
|
return ({ worldPos }) => {
|
||||||
@ -117,6 +118,7 @@ function switchMPRInteractors(api, istyle) {
|
|||||||
let currentSlabThickness;
|
let currentSlabThickness;
|
||||||
if (currentIStyle.getSlabThickness && istyle.getSlabThickness) {
|
if (currentIStyle.getSlabThickness && istyle.getSlabThickness) {
|
||||||
currentSlabThickness = currentIStyle.getSlabThickness();
|
currentSlabThickness = currentIStyle.getSlabThickness();
|
||||||
|
defaultSlabThickness = currentSlabThickness;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderWindow.getInteractor().setInteractorStyle(istyle);
|
renderWindow.getInteractor().setInteractorStyle(istyle);
|
||||||
@ -182,7 +184,7 @@ const actions = {
|
|||||||
switchMPRInteractors(api, istyle);
|
switchMPRInteractors(api, istyle);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setSlabThickness: slabThickness => {
|
setSlabThickness: ({ slabThickness }) => {
|
||||||
currentSlabThickness = slabThickness;
|
currentSlabThickness = slabThickness;
|
||||||
|
|
||||||
apis.forEach(api => {
|
apis.forEach(api => {
|
||||||
@ -191,15 +193,6 @@ const actions = {
|
|||||||
|
|
||||||
if (istyle.setSlabThickness) {
|
if (istyle.setSlabThickness) {
|
||||||
istyle.setSlabThickness(currentSlabThickness);
|
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();
|
renderWindow.render();
|
||||||
@ -220,6 +213,32 @@ const actions = {
|
|||||||
renderWindow.render();
|
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 }) => {
|
setBlendMode: ({ blendMode }) => {
|
||||||
apis.forEach(api => {
|
apis.forEach(api => {
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||||
@ -338,12 +357,12 @@ const definitions = {
|
|||||||
options: {},
|
options: {},
|
||||||
},
|
},
|
||||||
setBlendModeToComposite: {
|
setBlendModeToComposite: {
|
||||||
commandFn: actions.setBlendMode,
|
commandFn: actions.setBlendModeToComposite,
|
||||||
storeContexts: [],
|
storeContexts: [],
|
||||||
options: { blendMode: BlendMode.COMPOSITE_BLEND },
|
options: { blendMode: BlendMode.COMPOSITE_BLEND },
|
||||||
},
|
},
|
||||||
setBlendModeToMaximumIntensity: {
|
setBlendModeToMaximumIntensity: {
|
||||||
commandFn: actions.setBlendMode,
|
commandFn: actions.setBlendModeToMaximumIntensity,
|
||||||
storeContexts: [],
|
storeContexts: [],
|
||||||
options: { blendMode: BlendMode.MAXIMUM_INTENSITY_BLEND },
|
options: { blendMode: BlendMode.MAXIMUM_INTENSITY_BLEND },
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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 <div className="toolbar-button-label">{label}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ToolbarSlider = props => {
|
||||||
|
const { value, min, max, onChange } = props;
|
||||||
|
return (
|
||||||
|
<div className="toolbar-slider-container">
|
||||||
|
<label htmlFor="toolbar-slider">{value}mm</label>
|
||||||
|
<Range
|
||||||
|
value={value}
|
||||||
|
min={min}
|
||||||
|
max={max}
|
||||||
|
step={SLIDER.STEP}
|
||||||
|
onChange={onChange}
|
||||||
|
id="toolbar-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div className={_className}>
|
||||||
|
<div className="container">
|
||||||
|
<ToolbarSlider
|
||||||
|
value={state.value}
|
||||||
|
min={state.sliderMin}
|
||||||
|
max={state.sliderMax}
|
||||||
|
onChange={onChangeSlider}
|
||||||
|
/>
|
||||||
|
<ToolbarLabel key="toolbar-label" label={label} />
|
||||||
|
</div>
|
||||||
|
<div className="controller">
|
||||||
|
<Checkbox
|
||||||
|
label="mode"
|
||||||
|
checked={state.modeChecked}
|
||||||
|
onChange={onChangeCheckbox}
|
||||||
|
></Checkbox>
|
||||||
|
<Select
|
||||||
|
key="toolbar-select"
|
||||||
|
options={selectOptions}
|
||||||
|
value={selectOptions[INITIAL_OPTION_INDEX].value}
|
||||||
|
onChange={onChangeSelect}
|
||||||
|
></Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
@ -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);
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
import SlabThicknessToolbarComponent from './toolbarComponents/SlabThicknessToolbarComponent';
|
||||||
|
|
||||||
const TOOLBAR_BUTTON_TYPES = {
|
const TOOLBAR_BUTTON_TYPES = {
|
||||||
COMMAND: 'command',
|
COMMAND: 'command',
|
||||||
SET_TOOL_ACTIVE: 'setToolActive',
|
SET_TOOL_ACTIVE: 'setToolActive',
|
||||||
@ -31,6 +33,7 @@ const definitions = [
|
|||||||
commandName: 'enableRotateTool',
|
commandName: 'enableRotateTool',
|
||||||
commandOptions: {},
|
commandOptions: {},
|
||||||
},
|
},
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
id: 'setBlendModeToComposite',
|
id: 'setBlendModeToComposite',
|
||||||
label: 'Disable MIP',
|
label: 'Disable MIP',
|
||||||
@ -68,6 +71,50 @@ const definitions = [
|
|||||||
commandName: 'decreaseSlabThickness',
|
commandName: 'decreaseSlabThickness',
|
||||||
commandOptions: {},
|
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 {
|
export default {
|
||||||
|
|||||||
@ -6,15 +6,29 @@ export class Checkbox extends Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
label: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
checked: PropTypes.bool,
|
checked: PropTypes.bool,
|
||||||
|
onChange: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { checked: props.checked, label: props.label };
|
this.state = { checked: !!props.checked, label: props.label };
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange(e) {
|
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() {
|
render() {
|
||||||
@ -32,9 +46,7 @@ export class Checkbox extends Component {
|
|||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={this.state.checked}
|
checked={this.state.checked}
|
||||||
onChange={e => {
|
onChange={this.handleChange.bind(this)}
|
||||||
this.handleChange(e);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
{checkbox}
|
{checkbox}
|
||||||
{this.state.label}
|
{this.state.label}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import {
|
|||||||
UserPreferencesModal,
|
UserPreferencesModal,
|
||||||
} from './userPreferencesModal';
|
} from './userPreferencesModal';
|
||||||
|
|
||||||
|
import { Checkbox } from './checkbox';
|
||||||
import { CineDialog } from './cineDialog';
|
import { CineDialog } from './cineDialog';
|
||||||
import { QuickSwitch } from './quickSwitch';
|
import { QuickSwitch } from './quickSwitch';
|
||||||
import { RoundedButtonGroup } from './roundedButtonGroup';
|
import { RoundedButtonGroup } from './roundedButtonGroup';
|
||||||
@ -23,6 +24,7 @@ import { ToolbarSection } from './toolbarSection';
|
|||||||
import { Tooltip } from './tooltip';
|
import { Tooltip } from './tooltip';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
Checkbox,
|
||||||
CineDialog,
|
CineDialog,
|
||||||
ExampleDropTarget,
|
ExampleDropTarget,
|
||||||
LayoutButton,
|
LayoutButton,
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.range:focus {
|
.range:focus {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ class Range extends React.Component {
|
|||||||
|
|
||||||
handleChange = event => {
|
handleChange = event => {
|
||||||
this.setState({ value: event.target.value });
|
this.setState({ value: event.target.value });
|
||||||
if (this.props.onChange) this.props.onChange();
|
if (this.props.onChange) this.props.onChange(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -21,6 +21,7 @@ class Range extends React.Component {
|
|||||||
value={this.state.value}
|
value={this.state.value}
|
||||||
min={this.props.min}
|
min={this.props.min}
|
||||||
max={this.props.max}
|
max={this.props.max}
|
||||||
|
step={this.props.step || 1}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
id={this.props.id}
|
id={this.props.id}
|
||||||
className="range"
|
className="range"
|
||||||
|
|||||||
@ -34,10 +34,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.select-ohif:focus {
|
.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;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,9 @@ class Select extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleChange = event => {
|
handleChange = event => {
|
||||||
this.setState({ value: event.target.value });
|
const value = event.target.value;
|
||||||
if (this.props.onChange) this.props.onChange();
|
this.setState({ value });
|
||||||
|
if (this.props.onChange) this.props.onChange(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
Checkbox,
|
||||||
CineDialog,
|
CineDialog,
|
||||||
ExampleDropTarget,
|
ExampleDropTarget,
|
||||||
LayoutButton,
|
LayoutButton,
|
||||||
@ -25,7 +26,7 @@ import {
|
|||||||
import { ICONS, Icon } from './elements';
|
import { ICONS, Icon } from './elements';
|
||||||
|
|
||||||
// Alias this for now as not all dependents are using strict versioning
|
// 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 ExpandableToolMenu from './viewer/ExpandableToolMenu.js';
|
||||||
import LayoutManager from './LayoutChooser/LayoutManager.js';
|
import LayoutManager from './LayoutChooser/LayoutManager.js';
|
||||||
import LayoutPanelDropTarget from './LayoutChooser/LayoutPanelDropTarget.js';
|
import LayoutPanelDropTarget from './LayoutChooser/LayoutPanelDropTarget.js';
|
||||||
@ -38,6 +39,7 @@ import ViewerbaseDragDropContext from './utils/viewerbaseDragDropContext.js';
|
|||||||
export {
|
export {
|
||||||
ICONS,
|
ICONS,
|
||||||
//
|
//
|
||||||
|
Checkbox,
|
||||||
CineDialog,
|
CineDialog,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
ExpandableToolMenu,
|
ExpandableToolMenu,
|
||||||
@ -53,8 +55,10 @@ export {
|
|||||||
OverlayTrigger,
|
OverlayTrigger,
|
||||||
PlayClipButton,
|
PlayClipButton,
|
||||||
QuickSwitch,
|
QuickSwitch,
|
||||||
|
Range,
|
||||||
RoundedButtonGroup,
|
RoundedButtonGroup,
|
||||||
ScrollableArea,
|
ScrollableArea,
|
||||||
|
Select,
|
||||||
SelectTree,
|
SelectTree,
|
||||||
SimpleDialog,
|
SimpleDialog,
|
||||||
StudyBrowser,
|
StudyBrowser,
|
||||||
|
|||||||
@ -108,16 +108,8 @@ class ExpandableToolMenu extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
const getToolBarButtonComponent = () => {
|
||||||
<OverlayTrigger
|
return (
|
||||||
key="menu-button"
|
|
||||||
trigger="click"
|
|
||||||
placement="bottom"
|
|
||||||
rootClose={true}
|
|
||||||
handleHide={this.onOverlayHide}
|
|
||||||
onClick={this.onExpandableToolClick}
|
|
||||||
overlay={this.toolbarMenuOverlay()}
|
|
||||||
>
|
|
||||||
<ToolbarButton
|
<ToolbarButton
|
||||||
key="menu-button"
|
key="menu-button"
|
||||||
type="tool"
|
type="tool"
|
||||||
@ -128,6 +120,22 @@ class ExpandableToolMenu extends React.Component {
|
|||||||
isExpandable={true}
|
isExpandable={true}
|
||||||
isExpanded={this.state.isExpanded}
|
isExpanded={this.state.isExpanded}
|
||||||
/>
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toolbarComponent = getToolBarButtonComponent();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OverlayTrigger
|
||||||
|
key="menu-button"
|
||||||
|
trigger="click"
|
||||||
|
placement="bottom"
|
||||||
|
rootClose={true}
|
||||||
|
handleHide={this.onOverlayHide}
|
||||||
|
onClick={this.onExpandableToolClick}
|
||||||
|
overlay={this.toolbarMenuOverlay()}
|
||||||
|
>
|
||||||
|
{toolbarComponent}
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -229,6 +229,7 @@ function _getButtonComponents(toolbarButtons, activeButtons) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handy way for us to handle different button types. IE. firing commands for
|
* A handy way for us to handle different button types. IE. firing commands for
|
||||||
* buttons, or initiation built in behavior.
|
* buttons, or initiation built in behavior.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user