Create new ToolbarButton type for Layout Selector; wire up custom UI; prep for viewportGridService usage

This commit is contained in:
dannyrb 2020-06-15 00:51:36 -04:00
parent 83eb24337c
commit 9146a9ee32
18 changed files with 166 additions and 162 deletions

View File

@ -0,0 +1,41 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { LayoutSelector as OHIFLayoutSelector, ToolbarButton } from '@ohif/ui';
function LayoutSelector() {
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
function LayoutSelector() {
if (isOpen) {
setIsOpen(false);
}
}
window.addEventListener('click', LayoutSelector);
return () => {
window.removeEventListener('click', LayoutSelector);
};
}, [isOpen]);
const dropdownContent = isOpen ? OHIFLayoutSelector : undefined;
return (
<ToolbarButton
id="Layout"
label="Grid Layout"
icon="tool-layout"
onClick={() => {
setIsOpen(!isOpen);
}}
dropdownContent={dropdownContent}
isActive={isOpen}
type="primary"
/>
);
}
LayoutSelector.propTypes = {
children: PropTypes.any.isRequired,
};
export default LayoutSelector;

View File

@ -2,18 +2,18 @@ import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { ToolbarButton } from '@ohif/ui'; import { ToolbarButton } from '@ohif/ui';
function NestedToolbar({ children }) { function NestedMenu({ children }) {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
useEffect(() => { useEffect(() => {
function closeNestedToolbar() { function closeNestedMenu() {
if (isOpen) { if (isOpen) {
setIsOpen(false); setIsOpen(false);
} }
} }
window.addEventListener('click', closeNestedToolbar); window.addEventListener('click', closeNestedMenu);
return () => { return () => {
window.removeEventListener('click', closeNestedToolbar); window.removeEventListener('click', closeNestedMenu);
}; };
}, [isOpen]); }, [isOpen]);
@ -34,8 +34,8 @@ function NestedToolbar({ children }) {
); );
} }
NestedToolbar.propTypes = { NestedMenu.propTypes = {
children: PropTypes.any.isRequired, children: PropTypes.any.isRequired,
}; };
export default NestedToolbar; export default NestedMenu;

View File

@ -3,7 +3,7 @@ import classnames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { SidePanel } from '@ohif/ui'; import { SidePanel } from '@ohif/ui';
import Header from './Header.jsx'; import Header from './Header.jsx';
import NestedToolbar from './NestedToolbar.jsx'; import NestedMenu from './ToolbarButtonNestedMenu.jsx';
function ViewerLayout({ function ViewerLayout({
// From Extension Module Params // From Extension Module Params
@ -90,14 +90,14 @@ function ViewerLayout({
return <Component key={id} id={id} {...componentProps} />; return <Component key={id} id={id} {...componentProps} />;
} else { } else {
return ( return (
<NestedToolbar> <NestedMenu>
<div className="flex"> <div className="flex">
{toolDef.map(x => { {toolDef.map(x => {
const { id, Component, componentProps } = x; const { id, Component, componentProps } = x;
return <Component key={id} id={id} {...componentProps} />; return <Component key={id} id={id} {...componentProps} />;
})} })}
</div> </div>
</NestedToolbar> </NestedMenu>
); );
} }
})} })}

View File

@ -1,68 +0,0 @@
// SEE:
// https://github.com/OHIF/Viewers/blob/b58aa4575ab72fe3f493cc5a4261b4f8256516ab/platform/viewer/src/appExtensions/MeasurementsPanel/index.js#L18-L49
import React from 'react';
import { useViewportGrid } from '@ohif/ui';
function getCommandsModule({ servicesManager }) {
const { UIDialogService } = servicesManager.services;
const definitions = {
toggleLayoutSelectionDialog: {
commandFn: () => {
if (!UIDialogService) {
window.alert(
'Unable to show dialog; no UI Dialog Service available.'
);
return;
}
// TODO: use SimpleDialog component
// TODO: update position on window resize
// TODO: Expand service API to check if dialog w/ ID is already open
// TODO: Import and call `useViewportGrid`
UIDialogService.dismiss({ id: 'layoutSelection' });
UIDialogService.create({
id: 'layoutSelection',
centralize: true,
isDraggable: false,
showOverlay: true,
content: Test,
});
},
storeContexts: [],
options: {},
context: 'VIEWER',
},
};
return {
definitions,
defaultContext: 'VIEWER',
};
}
function Test() {
const [
{ numCols, numRows, activeViewportIndex, viewports },
dispatch,
] = useViewportGrid();
return (
<div
onClick={() => {
dispatch({
type: 'SET_LAYOUT',
payload: {
numCols: 2,
numRows: 2,
},
});
}}
style={{ color: 'white' }}
>
Hello World!
</div>
);
}
export default getCommandsModule;

View File

@ -1,5 +1,6 @@
import { ToolbarButton } from '@ohif/ui'; import { ToolbarButton } from '@ohif/ui';
import ToolbarDivider from './Toolbar/ToolbarDivider.jsx'; import ToolbarDivider from './Toolbar/ToolbarDivider.jsx';
import ToolbarLayoutSelector from './Toolbar/ToolbarLayoutSelector.jsx';
export default function getToolbarModule({ commandsManager, servicesManager }) { export default function getToolbarModule({ commandsManager, servicesManager }) {
const toolbarService = servicesManager.services.ToolBarService; const toolbarService = servicesManager.services.ToolBarService;
@ -59,6 +60,15 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
toolbarService.setButtons(allButtons); toolbarService.setButtons(allButtons);
}, },
}, },
{
name: 'ohif.layoutSelector',
defaultComponent: ToolbarLayoutSelector,
requiredConfig: [],
optionalConfig: [],
requiredProps: [],
optionalProps: [],
clickHandler: (evt, clickedBtn, btnSectionName) => {},
},
{ {
name: 'ohif.toggle', name: 'ohif.toggle',
defaultComponent: ToolbarButton, defaultComponent: ToolbarButton,
@ -76,7 +86,9 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
// Run button logic/command // Run button logic/command
// MAKE SURE THIS SUPPORTS TOGGLE! // MAKE SURE THIS SUPPORTS TOGGLE!
commandsManager.runCommand(props.commandName, props.commandOptions); // commandsManager.runCommand(props.commandName, props.commandOptions);
// What if just toggled "content"?
// commandName OR content?
// Set buttons & trigger notification // Set buttons & trigger notification
toolbarService.setButtons(allButtons); toolbarService.setButtons(allButtons);

View File

@ -1,4 +1,3 @@
import getCommandsModule from './getCommandsModule.js';
import getContextModule from './getContextModule.js'; import getContextModule from './getContextModule.js';
import getDataSourcesModule from './getDataSourcesModule.js'; import getDataSourcesModule from './getDataSourcesModule.js';
import getLayoutTemplateModule from './getLayoutTemplateModule.js'; import getLayoutTemplateModule from './getLayoutTemplateModule.js';
@ -12,7 +11,6 @@ export default {
* Only required property. Should be a unique value across all extensions. * Only required property. Should be a unique value across all extensions.
*/ */
id, id,
getCommandsModule,
getContextModule, getContextModule,
getDataSourcesModule, getDataSourcesModule,
getLayoutTemplateModule, getLayoutTemplateModule,

View File

@ -1,68 +0,0 @@
// SEE:
// https://github.com/OHIF/Viewers/blob/b58aa4575ab72fe3f493cc5a4261b4f8256516ab/platform/viewer/src/appExtensions/MeasurementsPanel/index.js#L18-L49
import React from 'react';
import { useViewportGrid } from '@ohif/ui';
function getCommandsModule({ servicesManager }) {
const { UIDialogService } = servicesManager.services;
const definitions = {
toggleLayoutSelectionDialog: {
commandFn: () => {
if (!UIDialogService) {
window.alert(
'Unable to show dialog; no UI Dialog Service available.'
);
return;
}
// TODO: use SimpleDialog component
// TODO: update position on window resize
// TODO: Expand service API to check if dialog w/ ID is already open
// TODO: Import and call `useViewportGrid`
UIDialogService.dismiss({ id: 'layoutSelection' });
UIDialogService.create({
id: 'layoutSelection',
centralize: true,
isDraggable: false,
showOverlay: true,
content: Test,
});
},
storeContexts: [],
options: {},
context: 'VIEWER',
},
};
return {
definitions,
defaultContext: 'VIEWER',
};
}
function Test() {
const [
{ numCols, numRows, activeViewportIndex, viewports },
dispatch,
] = useViewportGrid();
return (
<div
onClick={() => {
dispatch({
type: 'SET_LAYOUT',
payload: {
numCols: 2,
numRows: 2,
},
});
}}
style={{ color: 'white' }}
>
Hello World!
</div>
);
}
export default getCommandsModule;

View File

@ -1,4 +1,3 @@
import getCommandsModule from './getCommandsModule.js';
import getContextModule from './getContextModule.js'; import getContextModule from './getContextModule.js';
import getPanelModule from './getPanelModule.js'; import getPanelModule from './getPanelModule.js';
import getViewportModule from './getViewportModule.js'; import getViewportModule from './getViewportModule.js';
@ -8,7 +7,6 @@ export default {
* Only required property. Should be a unique value across all extensions. * Only required property. Should be a unique value across all extensions.
*/ */
id: 'org.ohif.measurement-tracking', id: 'org.ohif.measurement-tracking',
getCommandsModule,
getContextModule, getContextModule,
getPanelModule, getPanelModule,
getViewportModule, getViewportModule,

View File

@ -128,7 +128,9 @@ const definitions = [
}, },
]; ];
export default { export default [];
definitions,
defaultContext: 'ACTIVE_VIEWPORT::VTK', // export default {
}; // definitions,
// defaultContext: 'ACTIVE_VIEWPORT::VTK',
// };

View File

@ -35,7 +35,7 @@ export default function mode({ modeConfiguration }) {
'Wwwc', 'Wwwc',
'Pan', 'Pan',
'Capture', 'Capture',
// 'Layout', // toggle --> command to open layout dialog? needs to know when it should be off? (promise?) 'Layout',
'Divider', 'Divider',
['Zoom', 'Wwwc'], ['Zoom', 'Wwwc'],
]); ]);

View File

@ -1,3 +1,6 @@
// TODO: torn, can either bake this here; or have to create a whole new button type
// Only ways that you can pass in a custom React component for render :l
export default [ export default [
// Divider // Divider
{ {
@ -60,8 +63,11 @@ export default [
type: 'primary', type: 'primary',
}, },
}, },
// Layout {
// Expanded/Nested? id: 'Layout',
type: 'ohif.layoutSelector',
},
// ~~ Primary: NESTED
// ~~ Secondary // ~~ Secondary
{ {
id: 'Annotate', id: 'Annotate',

View File

@ -154,8 +154,6 @@ export default class ToolBarService {
if (btn.props.clickHandler) { if (btn.props.clickHandler) {
btn.clickHandler(evt, btn, btnSection); btn.clickHandler(evt, btn, btnSection);
} }
this._trySetButtonActive(id);
}; };
return { return {

View File

@ -41,6 +41,7 @@ export {
InputMultiSelect, InputMultiSelect,
InputText, InputText,
Label, Label,
LayoutSelector,
MeasurementTable, MeasurementTable,
Modal, Modal,
NavBar, NavBar,

View File

@ -0,0 +1,80 @@
// // SEE:
// // https://github.com/OHIF/Viewers/blob/b58aa4575ab72fe3f493cc5a4261b4f8256516ab/platform/viewer/src/appExtensions/MeasurementsPanel/index.js#L18-L49
// import React from 'react';
// import { useViewportGrid } from '@ohif/ui';
// function getCommandsModule({ servicesManager }) {
// const { UIDialogService } = servicesManager.services;
// const definitions = {
// toggleLayoutSelectionDialog: {
// commandFn: () => {
// if (!UIDialogService) {
// window.alert(
// 'Unable to show dialog; no UI Dialog Service available.'
// );
// return;
// }
// // TODO: use SimpleDialog component
// // TODO: update position on window resize
// // TODO: Expand service API to check if dialog w/ ID is already open
// // TODO: Import and call `useViewportGrid`
// UIDialogService.dismiss({ id: 'layoutSelection' });
// UIDialogService.create({
// id: 'layoutSelection',
// centralize: true,
// isDraggable: false,
// showOverlay: true,
// content: Test,
// });
// },
// storeContexts: [],
// options: {},
// context: 'VIEWER',
// },
// };
// return {
// definitions,
// defaultContext: 'VIEWER',
// };
// }
// function Test() {
// const [
// { numCols, numRows, activeViewportIndex, viewports },
// dispatch,
// ] = useViewportGrid();
// return (
// <div
// onClick={() => {
// dispatch({
// type: 'SET_LAYOUT',
// payload: {
// numCols: 2,
// numRows: 2,
// },
// });
// }}
// style={{ color: 'white' }}
// >
// Hello World!
// </div>
// );
// }
// export default getCommandsModule;
import React from 'react';
function LayoutSelector() {
return (
<>
<div>LAYOUT SELECTOR PLACEHOLDER!</div>
</>
);
}
export default LayoutSelector;

View File

@ -0,0 +1,2 @@
import LayoutSelector from './LayoutSelector';
export default LayoutSelector;

View File

@ -60,7 +60,7 @@ ToolbarButton.propTypes = {
icon: PropTypes.string.isRequired, icon: PropTypes.string.isRequired,
label: PropTypes.string.isRequired, label: PropTypes.string.isRequired,
/** Tooltip content can be replaced for a customized content by passing a node to this value. */ /** Tooltip content can be replaced for a customized content by passing a node to this value. */
dropdownContent: PropTypes.node, dropdownContent: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
}; };
export default ToolbarButton; export default ToolbarButton;

View File

@ -65,7 +65,7 @@ const Tooltip = ({ content, isSticky, position, tight, children }) => {
} }
)} )}
> >
{content} {typeof content === 'function' ? content() : content}
<svg <svg
className="absolute h-4 text-primary-dark stroke-secondary-main" className="absolute h-4 text-primary-dark stroke-secondary-main"
style={arrowPositionStyle[position]} style={arrowPositionStyle[position]}
@ -87,7 +87,7 @@ Tooltip.defaultProps = {
}; };
Tooltip.propTypes = { Tooltip.propTypes = {
content: PropTypes.node.isRequired, content: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
position: PropTypes.oneOf([ position: PropTypes.oneOf([
'bottom', 'bottom',
'bottom-left', 'bottom-left',

View File

@ -12,6 +12,7 @@ import InputLabelWrapper from './InputLabelWrapper';
import InputMultiSelect from './InputMultiSelect'; import InputMultiSelect from './InputMultiSelect';
import InputText from './InputText'; import InputText from './InputText';
import Label from './Label'; import Label from './Label';
import LayoutSelector from './LayoutSelector';
import MeasurementTable from './MeasurementTable'; import MeasurementTable from './MeasurementTable';
import Modal from './Modal'; import Modal from './Modal';
import NavBar from './NavBar'; import NavBar from './NavBar';
@ -60,6 +61,7 @@ export {
InputMultiSelect, InputMultiSelect,
InputText, InputText,
Label, Label,
LayoutSelector,
MeasurementTable, MeasurementTable,
Modal, Modal,
NavBar, NavBar,