refactor: layout manager to viewer (#1026)

* docs: formatting

* Prefer numRows and numColumns to percentage width/height for layout

* fix: LayoutManager --> ViewportGrid (get out of UI component library)

* docs: remove outdated docs

* Don't expose ExampleDropTarget

* Revert thumnail entry drag source removal

* Update screaming tests

* fix drag-n-drop

* fix vtk mpr2d CC: @jamesapetts

* remove setSingleLayoutData

* remove vtk qualifier
This commit is contained in:
Danny Brown authored and GitHub committed 2019-10-11 12:03:59 -04:00
1 parent d6862e7418
commit b01b0108b0
33 files changed
+456 -613

No files matched your search

@@ -1,22 +0,0 @@
.viewport-container {
float: left;
position: relative;
border: var(--viewport-border-thickness) solid var(--ui-border-color);
}
.viewport-container.active {
border: var(--viewport-border-thickness) solid var(--active-color);
}
.EmptyViewport {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: var(--text-secondary-color);
}
.LayoutPanel {
width: 100%;
height: 100%;
}
@@ -1,162 +0,0 @@
import './LayoutManager.css';
import React, { Component } from 'react';
import LayoutPanelDropTarget from './LayoutPanelDropTarget.js';
import PropTypes from 'prop-types';
function defaultViewportPlugin(props) {
return <div>{JSON.stringify(props)}</div>;
}
function EmptyViewport() {
return (
<div className="EmptyViewport">
<p>Please drag a stack here to view images.</p>
</div>
);
}
export class LayoutManager extends Component {
static className = 'LayoutManager';
static defaultProps = {
viewportData: [],
layout: {
viewports: [
{
top: 0,
left: 0,
height: '100%',
width: '100%',
},
],
},
activeViewportIndex: 0,
supportsDragAndDrop: true,
availablePlugins: {
defaultViewportPlugin,
},
defaultPlugin: 'defaultViewportPlugin',
};
static propTypes = {
viewportData: PropTypes.array.isRequired,
supportsDragAndDrop: PropTypes.bool.isRequired,
activeViewportIndex: PropTypes.number.isRequired,
layout: PropTypes.object.isRequired,
availablePlugins: PropTypes.object.isRequired,
setViewportData: PropTypes.func,
studies: PropTypes.array,
children: PropTypes.node,
};
onDrop = ({ viewportIndex, item }) => {
if (this.props.setViewportData) {
this.props.setViewportData({ viewportIndex, item });
}
};
getPluginComponent = plugin => {
const pluginComponent = this.props.availablePlugins[
plugin || this.props.defaultPlugin
];
if (!pluginComponent) {
throw new Error(
`No Viewport Plugin available for plugin ${plugin}. Available plugins: ${JSON.stringify(
this.props.availablePlugins
)}`
);
}
return pluginComponent;
};
getChildComponent(plugin, data, viewportIndex, children) {
if (data.displaySet) {
const PluginComponent = this.getPluginComponent(plugin);
return (
<PluginComponent
viewportData={data}
viewportIndex={viewportIndex}
children={[children]}
/>
);
}
return <EmptyViewport />;
}
getContent(childComponent, supportsDragAndDrop, viewportIndex) {
if (supportsDragAndDrop) {
return (
<LayoutPanelDropTarget
onDrop={this.onDrop}
viewportIndex={viewportIndex}
>
{childComponent}
</LayoutPanelDropTarget>
);
}
return <div className="LayoutPanel">{childComponent}</div>;
}
render() {
if (!this.props.viewportData.length) {
return '';
}
const { supportsDragAndDrop, studies, viewportData } = this.props;
const viewports = this.props.layout.viewports;
const viewportElements = viewports.map((layout, viewportIndex) => {
const displaySet = viewportData[viewportIndex];
const data = {
displaySet,
studies,
};
// Use whichever plugin is currently in use in the panel
// unless nothing is specified. If nothing is specified
// and the display set has a plugin specified, use that.
//
// TODO: Change this logic to:
// - Plugins define how capable they are of displaying a SopClass
// - When updating a panel, ensure that the currently enabled plugin
// in the viewport is capable of rendering this display set. If not
// then use the most capable available plugin
let plugin = layout.plugin;
if (!layout.plugin && displaySet && displaySet.plugin) {
plugin = displaySet.plugin;
}
const childComponent = this.getChildComponent(
plugin,
data,
viewportIndex,
this.props.children
);
const content = this.getContent(
childComponent,
supportsDragAndDrop,
viewportIndex
);
let className = 'viewport-container';
if (this.props.activeViewportIndex === viewportIndex) {
className += ' active';
}
return (
<div key={viewportIndex} className={className} style={{ ...layout }}>
{content}
</div>
);
});
return <div className={LayoutManager.className}>{viewportElements}</div>;
}
}
export default LayoutManager;
@@ -1,12 +0,0 @@
.LayoutPanelDropTarget {
width: 100%;
height: 100%;
opacity: 1;
transition: 0.3s all ease;
}
.LayoutPanelDropTarget.hovered {
opacity: 0.5;
cursor: copy;
}
@@ -1,74 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { DropTarget } from 'react-dnd';
import './LayoutPanelDropTarget.css';
// Drag sources and drop targets only interact
// if they have the same string type.
const Types = {
THUMBNAIL: 'thumbnail',
};
const divTarget = {
drop(props, monitor, component) {
const item = monitor.getItem();
if (props.onDrop) {
props.onDrop({
viewportIndex: props.viewportIndex,
item,
});
}
return {
id: `LayoutPanelDropTarget-${props.viewportIndex}`,
viewportIndex: props.viewportIndex,
item,
};
},
};
// TODO: Find out why we can't move this into the Example app instead.
// It looks like the context isn't properly shared.
class LayoutPanelDropTarget extends Component {
static className = 'LayoutPanelDropTarget';
static defaultProps = {
isOver: false,
canDrop: false,
};
static propTypes = {
connectDropTarget: PropTypes.func.isRequired,
canDrop: PropTypes.bool.isRequired,
isOver: PropTypes.bool.isRequired,
viewportComponent: PropTypes.object,
};
render() {
const { canDrop, isOver, connectDropTarget } = this.props;
const isActive = canDrop && isOver;
let className = LayoutPanelDropTarget.className;
if (isActive) {
className += ' hovered';
} else if (canDrop) {
className += ' can-drop';
}
return connectDropTarget(
<div className={className}>{this.props.children}</div>
);
}
}
const collect = (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
canDrop: monitor.canDrop(),
isOver: monitor.isOver(),
});
export default DropTarget(Types.THUMBNAIL, divTarget, collect)(
LayoutPanelDropTarget
);
+1 -6
View File
@@ -1,8 +1,4 @@
import {
ExampleDropTarget,
StudyBrowser,
ThumbnailEntry,
} from './studyBrowser';
import { StudyBrowser, ThumbnailEntry } from './studyBrowser';
import { LayoutButton, LayoutChooser } from './layoutButton';
import { MeasurementTable, MeasurementTableItem } from './measurementTable';
import { Overlay, OverlayTrigger } from './overlayTrigger';
@@ -26,7 +22,6 @@ import { Tooltip } from './tooltip';
export {
Checkbox,
CineDialog,
ExampleDropTarget,
LayoutButton,
LayoutChooser,
MeasurementTable,
@@ -8,7 +8,8 @@ import {
onThumbnailClick,
onThumbnailDoubleClick,
} from './exampleStudies.js';
import { ExampleDropTarget, StudyBrowser } from './../index.js';
import ExampleDropTarget from './ExampleDropTarget.js';
import { StudyBrowser } from './../index.js';
class StudyBrowserContainer extends Component {
render() {
@@ -1,3 +1,2 @@
export { ExampleDropTarget } from './ExampleDropTarget.js';
export { StudyBrowser } from './StudyBrowser.js';
export { ThumbnailEntry } from './ThumbnailEntry.js';
-6
View File
@@ -1,7 +1,6 @@
import {
Checkbox,
CineDialog,
ExampleDropTarget,
LayoutButton,
LayoutChooser,
MeasurementTable,
@@ -28,8 +27,6 @@ import { ICONS, Icon } from './elements';
// Alias this for now as not all dependents are using strict versioning
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';
import PlayClipButton from './viewer/PlayClipButton.js';
import { ScrollableArea } from './ScrollableArea/ScrollableArea.js';
import Toolbar from './viewer/Toolbar.js';
@@ -43,12 +40,9 @@ export {
CineDialog,
Dropdown,
ExpandableToolMenu,
ExampleDropTarget,
Icon,
LayoutButton,
LayoutChooser,
LayoutManager,
LayoutPanelDropTarget,
MeasurementTable,
MeasurementTableItem,
Overlay,