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:
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,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,
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -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';
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user