From 9146a9ee32a064407ef5b3d87aa9030b12d3e1a0 Mon Sep 17 00:00:00 2001 From: dannyrb Date: Mon, 15 Jun 2020 00:51:36 -0400 Subject: [PATCH] Create new ToolbarButton type for Layout Selector; wire up custom UI; prep for viewportGridService usage --- .../src/Toolbar/ToolbarLayoutSelector.jsx | 41 ++++++++++ ...oolbar.jsx => ToolbarButtonNestedMenu.jsx} | 12 +-- extensions/default/src/ViewerLayout/index.jsx | 6 +- extensions/default/src/getCommandsModule.js | 68 ---------------- extensions/default/src/getToolbarModule.js | 14 +++- extensions/default/src/index.js | 2 - .../src/getCommandsModule.js | 68 ---------------- extensions/measurement-tracking/src/index.js | 2 - extensions/vtk/src/toolbarModule.js | 10 ++- modes/longitudinal/src/index.js | 2 +- modes/longitudinal/src/toolbarButtons.js | 10 ++- .../services/ToolBarService/ToolBarService.js | 2 - platform/ui/index.js | 1 + .../LayoutSelector/LayoutSelector.jsx | 80 +++++++++++++++++++ .../ui/src/components/LayoutSelector/index.js | 2 + .../ToolbarButton/ToolbarButton.jsx | 2 +- .../ui/src/components/Tooltip/Tooltip.jsx | 4 +- platform/ui/src/components/index.js | 2 + 18 files changed, 166 insertions(+), 162 deletions(-) create mode 100644 extensions/default/src/Toolbar/ToolbarLayoutSelector.jsx rename extensions/default/src/ViewerLayout/{NestedToolbar.jsx => ToolbarButtonNestedMenu.jsx} (72%) delete mode 100644 extensions/default/src/getCommandsModule.js delete mode 100644 extensions/measurement-tracking/src/getCommandsModule.js create mode 100644 platform/ui/src/components/LayoutSelector/LayoutSelector.jsx create mode 100644 platform/ui/src/components/LayoutSelector/index.js diff --git a/extensions/default/src/Toolbar/ToolbarLayoutSelector.jsx b/extensions/default/src/Toolbar/ToolbarLayoutSelector.jsx new file mode 100644 index 000000000..345db2a57 --- /dev/null +++ b/extensions/default/src/Toolbar/ToolbarLayoutSelector.jsx @@ -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 ( + { + setIsOpen(!isOpen); + }} + dropdownContent={dropdownContent} + isActive={isOpen} + type="primary" + /> + ); +} + +LayoutSelector.propTypes = { + children: PropTypes.any.isRequired, +}; + +export default LayoutSelector; diff --git a/extensions/default/src/ViewerLayout/NestedToolbar.jsx b/extensions/default/src/ViewerLayout/ToolbarButtonNestedMenu.jsx similarity index 72% rename from extensions/default/src/ViewerLayout/NestedToolbar.jsx rename to extensions/default/src/ViewerLayout/ToolbarButtonNestedMenu.jsx index dae97bd0a..097257e75 100644 --- a/extensions/default/src/ViewerLayout/NestedToolbar.jsx +++ b/extensions/default/src/ViewerLayout/ToolbarButtonNestedMenu.jsx @@ -2,18 +2,18 @@ import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { ToolbarButton } from '@ohif/ui'; -function NestedToolbar({ children }) { +function NestedMenu({ children }) { const [isOpen, setIsOpen] = useState(false); useEffect(() => { - function closeNestedToolbar() { + function closeNestedMenu() { if (isOpen) { setIsOpen(false); } } - window.addEventListener('click', closeNestedToolbar); + window.addEventListener('click', closeNestedMenu); return () => { - window.removeEventListener('click', closeNestedToolbar); + window.removeEventListener('click', closeNestedMenu); }; }, [isOpen]); @@ -34,8 +34,8 @@ function NestedToolbar({ children }) { ); } -NestedToolbar.propTypes = { +NestedMenu.propTypes = { children: PropTypes.any.isRequired, }; -export default NestedToolbar; +export default NestedMenu; diff --git a/extensions/default/src/ViewerLayout/index.jsx b/extensions/default/src/ViewerLayout/index.jsx index 856fc84d4..8e410b262 100644 --- a/extensions/default/src/ViewerLayout/index.jsx +++ b/extensions/default/src/ViewerLayout/index.jsx @@ -3,7 +3,7 @@ import classnames from 'classnames'; import PropTypes from 'prop-types'; import { SidePanel } from '@ohif/ui'; import Header from './Header.jsx'; -import NestedToolbar from './NestedToolbar.jsx'; +import NestedMenu from './ToolbarButtonNestedMenu.jsx'; function ViewerLayout({ // From Extension Module Params @@ -90,14 +90,14 @@ function ViewerLayout({ return ; } else { return ( - +
{toolDef.map(x => { const { id, Component, componentProps } = x; return ; })}
-
+ ); } })} diff --git a/extensions/default/src/getCommandsModule.js b/extensions/default/src/getCommandsModule.js deleted file mode 100644 index 325825ef2..000000000 --- a/extensions/default/src/getCommandsModule.js +++ /dev/null @@ -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 ( -
{ - dispatch({ - type: 'SET_LAYOUT', - payload: { - numCols: 2, - numRows: 2, - }, - }); - }} - style={{ color: 'white' }} - > - Hello World! -
- ); -} - -export default getCommandsModule; diff --git a/extensions/default/src/getToolbarModule.js b/extensions/default/src/getToolbarModule.js index 5c0c173f1..a3777a523 100644 --- a/extensions/default/src/getToolbarModule.js +++ b/extensions/default/src/getToolbarModule.js @@ -1,5 +1,6 @@ import { ToolbarButton } from '@ohif/ui'; import ToolbarDivider from './Toolbar/ToolbarDivider.jsx'; +import ToolbarLayoutSelector from './Toolbar/ToolbarLayoutSelector.jsx'; export default function getToolbarModule({ commandsManager, servicesManager }) { const toolbarService = servicesManager.services.ToolBarService; @@ -59,6 +60,15 @@ export default function getToolbarModule({ commandsManager, servicesManager }) { toolbarService.setButtons(allButtons); }, }, + { + name: 'ohif.layoutSelector', + defaultComponent: ToolbarLayoutSelector, + requiredConfig: [], + optionalConfig: [], + requiredProps: [], + optionalProps: [], + clickHandler: (evt, clickedBtn, btnSectionName) => {}, + }, { name: 'ohif.toggle', defaultComponent: ToolbarButton, @@ -76,7 +86,9 @@ export default function getToolbarModule({ commandsManager, servicesManager }) { // Run button logic/command // 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 toolbarService.setButtons(allButtons); diff --git a/extensions/default/src/index.js b/extensions/default/src/index.js index 8099cde61..a426be014 100644 --- a/extensions/default/src/index.js +++ b/extensions/default/src/index.js @@ -1,4 +1,3 @@ -import getCommandsModule from './getCommandsModule.js'; import getContextModule from './getContextModule.js'; import getDataSourcesModule from './getDataSourcesModule.js'; import getLayoutTemplateModule from './getLayoutTemplateModule.js'; @@ -12,7 +11,6 @@ export default { * Only required property. Should be a unique value across all extensions. */ id, - getCommandsModule, getContextModule, getDataSourcesModule, getLayoutTemplateModule, diff --git a/extensions/measurement-tracking/src/getCommandsModule.js b/extensions/measurement-tracking/src/getCommandsModule.js deleted file mode 100644 index 325825ef2..000000000 --- a/extensions/measurement-tracking/src/getCommandsModule.js +++ /dev/null @@ -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 ( -
{ - dispatch({ - type: 'SET_LAYOUT', - payload: { - numCols: 2, - numRows: 2, - }, - }); - }} - style={{ color: 'white' }} - > - Hello World! -
- ); -} - -export default getCommandsModule; diff --git a/extensions/measurement-tracking/src/index.js b/extensions/measurement-tracking/src/index.js index 7aa5cc79b..bbc50e2a0 100644 --- a/extensions/measurement-tracking/src/index.js +++ b/extensions/measurement-tracking/src/index.js @@ -1,4 +1,3 @@ -import getCommandsModule from './getCommandsModule.js'; import getContextModule from './getContextModule.js'; import getPanelModule from './getPanelModule.js'; import getViewportModule from './getViewportModule.js'; @@ -8,7 +7,6 @@ export default { * Only required property. Should be a unique value across all extensions. */ id: 'org.ohif.measurement-tracking', - getCommandsModule, getContextModule, getPanelModule, getViewportModule, diff --git a/extensions/vtk/src/toolbarModule.js b/extensions/vtk/src/toolbarModule.js index 832acae34..3e7dceb76 100644 --- a/extensions/vtk/src/toolbarModule.js +++ b/extensions/vtk/src/toolbarModule.js @@ -128,7 +128,9 @@ const definitions = [ }, ]; -export default { - definitions, - defaultContext: 'ACTIVE_VIEWPORT::VTK', -}; +export default []; + +// export default { +// definitions, +// defaultContext: 'ACTIVE_VIEWPORT::VTK', +// }; diff --git a/modes/longitudinal/src/index.js b/modes/longitudinal/src/index.js index 1012f7c7d..717d301e0 100644 --- a/modes/longitudinal/src/index.js +++ b/modes/longitudinal/src/index.js @@ -35,7 +35,7 @@ export default function mode({ modeConfiguration }) { 'Wwwc', 'Pan', 'Capture', - // 'Layout', // toggle --> command to open layout dialog? needs to know when it should be off? (promise?) + 'Layout', 'Divider', ['Zoom', 'Wwwc'], ]); diff --git a/modes/longitudinal/src/toolbarButtons.js b/modes/longitudinal/src/toolbarButtons.js index 53309cbc9..5f9b4beb4 100644 --- a/modes/longitudinal/src/toolbarButtons.js +++ b/modes/longitudinal/src/toolbarButtons.js @@ -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 [ // Divider { @@ -60,8 +63,11 @@ export default [ type: 'primary', }, }, - // Layout - // Expanded/Nested? + { + id: 'Layout', + type: 'ohif.layoutSelector', + }, + // ~~ Primary: NESTED // ~~ Secondary { id: 'Annotate', diff --git a/platform/core/src/services/ToolBarService/ToolBarService.js b/platform/core/src/services/ToolBarService/ToolBarService.js index 0a49d5080..95cc1b431 100644 --- a/platform/core/src/services/ToolBarService/ToolBarService.js +++ b/platform/core/src/services/ToolBarService/ToolBarService.js @@ -154,8 +154,6 @@ export default class ToolBarService { if (btn.props.clickHandler) { btn.clickHandler(evt, btn, btnSection); } - - this._trySetButtonActive(id); }; return { diff --git a/platform/ui/index.js b/platform/ui/index.js index c726b37f5..db85039d9 100644 --- a/platform/ui/index.js +++ b/platform/ui/index.js @@ -41,6 +41,7 @@ export { InputMultiSelect, InputText, Label, + LayoutSelector, MeasurementTable, Modal, NavBar, diff --git a/platform/ui/src/components/LayoutSelector/LayoutSelector.jsx b/platform/ui/src/components/LayoutSelector/LayoutSelector.jsx new file mode 100644 index 000000000..4226b1b56 --- /dev/null +++ b/platform/ui/src/components/LayoutSelector/LayoutSelector.jsx @@ -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 ( +//
{ +// dispatch({ +// type: 'SET_LAYOUT', +// payload: { +// numCols: 2, +// numRows: 2, +// }, +// }); +// }} +// style={{ color: 'white' }} +// > +// Hello World! +//
+// ); +// } + +// export default getCommandsModule; + +import React from 'react'; + +function LayoutSelector() { + return ( + <> +
LAYOUT SELECTOR PLACEHOLDER!
+ + ); +} + +export default LayoutSelector; diff --git a/platform/ui/src/components/LayoutSelector/index.js b/platform/ui/src/components/LayoutSelector/index.js new file mode 100644 index 000000000..1b6044375 --- /dev/null +++ b/platform/ui/src/components/LayoutSelector/index.js @@ -0,0 +1,2 @@ +import LayoutSelector from './LayoutSelector'; +export default LayoutSelector; diff --git a/platform/ui/src/components/ToolbarButton/ToolbarButton.jsx b/platform/ui/src/components/ToolbarButton/ToolbarButton.jsx index 99ad2fa84..904d0dcf3 100644 --- a/platform/ui/src/components/ToolbarButton/ToolbarButton.jsx +++ b/platform/ui/src/components/ToolbarButton/ToolbarButton.jsx @@ -60,7 +60,7 @@ ToolbarButton.propTypes = { icon: PropTypes.string.isRequired, label: PropTypes.string.isRequired, /** 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; diff --git a/platform/ui/src/components/Tooltip/Tooltip.jsx b/platform/ui/src/components/Tooltip/Tooltip.jsx index 8645b3846..115646a78 100644 --- a/platform/ui/src/components/Tooltip/Tooltip.jsx +++ b/platform/ui/src/components/Tooltip/Tooltip.jsx @@ -65,7 +65,7 @@ const Tooltip = ({ content, isSticky, position, tight, children }) => { } )} > - {content} + {typeof content === 'function' ? content() : content}