diff --git a/extensions/default/src/Toolbar/ToolbarDivider.jsx b/extensions/default/src/Toolbar/ToolbarDivider.jsx new file mode 100644 index 000000000..7e73deaf7 --- /dev/null +++ b/extensions/default/src/Toolbar/ToolbarDivider.jsx @@ -0,0 +1,7 @@ +import React from 'react'; + +export default function ToolbarDivider() { + return ( + + ); +} diff --git a/extensions/default/src/ViewerLayout/Header.jsx b/extensions/default/src/ViewerLayout/Header.jsx index ff1672604..e4bde8383 100644 --- a/extensions/default/src/ViewerLayout/Header.jsx +++ b/extensions/default/src/ViewerLayout/Header.jsx @@ -1,10 +1,9 @@ -import React, { useState } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; // -import { NavBar, Svg, Icon, IconButton, Toolbar } from '@ohif/ui'; +import { NavBar, Svg, Icon, IconButton } from '@ohif/ui'; -function Header({ tools, moreTools }) { - const [activeTool, setActiveTool] = useState('Zoom'); +function Header({ children }) { // const dropdownContent = [ // { // name: 'Soft tissue', @@ -14,80 +13,16 @@ function Header({ tools, moreTools }) { // { name: 'Liver', value: '150 / 90' }, // { name: 'Bone', value: '2500 / 480' }, // { name: 'Brain', value: '80 / 40' }, - // ]; + // ] - // TODO -> In ToolBarManager => Consume commandName and commandOptions and create onClick? - - /* - const tools = [ - { - id: 'Zoom', - label: 'Zoom', - icon: 'tool-zoom', - commandName: 'setToolActive', - commandOptions: { toolName: 'Zoom' }, - onClick: () => setActiveTool('Zoom'), - }, - { - id: 'Wwwc', - label: 'Levels', - icon: 'tool-window-level', - commandName: 'setToolActive', - commandOptions: { toolName: 'Wwwc' }, - onClick: () => setActiveTool('Wwwc'), - dropdownContent: ( -
- {dropdownContent.map((row, i) => ( -
-
- {row.name} - - {row.value} - -
- {i} -
- ))} -
- ), - }, - { - id: 'Pan', - label: 'Pan', - icon: 'tool-move', - commandName: 'setToolActive', - commandOptions: { toolName: 'Pan' }, - onClick: () => setActiveTool('Pan'), - }, - { - id: 'Capture', - label: 'Capture', - icon: 'tool-capture', - commandName: 'setToolActive', - commandOptions: { toolName: 'Capture' }, - onClick: () => setActiveTool('Capture'), - }, - { - id: 'Layout', - label: 'Layout', - icon: 'tool-layout', - commandName: 'setToolActive', - commandOptions: { toolName: 'Layout' }, - onClick: () => setActiveTool('Layout'), - }, - ]; - */ return ( -
+
-
+
+
{children}
- -
-
- + FOR INVESTIGATIONAL USE ONLY { - // Get buttons to pass to toolbars. - console.log(commandsManager); - - const firstTool = newToolBarLayout[0].tools[0]; - - const toolBarLayout = []; - - newToolBarLayout.forEach(newToolBar => { - const toolBar = { tools: [], moreTools: [] }; - - Object.keys(newToolBar).forEach(key => { - if (newToolBar[key].length) { - newToolBar[key].forEach(tool => { - const commandOptions = tool.commandOptions || {}; - - toolBar[key].push({ - context: tool.context, - icon: tool.icon, - id: tool.id, - label: tool.label, - type: 'setToolActive', - onClick: () => { - commandsManager.runCommand(tool.commandName, commandOptions); - }, - }); - }); - } - }); - - toolBarLayout.push(toolBar); - - // if (newToolBar.moreTools && newToolBar.moreTools.length) { - // newToolBar.moreTools.forEach(tool => { - // const commandOptions = tool.commandOptions || {}; - - // toolBar.push({ - // context: tool.context, - // icon: tool.icon, - // id: tool.id, - // label: tool.label, - // type: 'setToolActive', - // command: () => - // commandsManager.runCommand(tool.commandName, commandOptions), - // }); - // }); - // } - }); - - setToolBarLayout(toolBarLayout); - }; - - const [toolBarLayout, setToolBarLayout] = useState([ - { tools: [], moreTools: [] }, - { tools: [] }, - ]); + const [toolbars, setToolbars] = useState({ primary: [], secondary: [] }); useEffect(() => { const { unsubscribe } = ToolBarService.subscribe( ToolBarService.EVENTS.TOOL_BAR_MODIFIED, - handleToolBarSubscription + () => { + console.warn('~~~ TOOL BAR MODIFIED EVENT CAUGHT'); + const updatedToolbars = { + primary: ToolBarService.getButtonSection('primary'), + secondary: ToolBarService.getButtonSection('secondary'), + }; + setToolbars(updatedToolbars); + } ); return unsubscribe; - }, []); + }, [ToolBarService]); const leftPanelComponents = leftPanels.map(getPanelData); const rightPanelComponents = rightPanels.map(getPanelData); @@ -126,10 +78,16 @@ function ViewerLayout({ return (
-
+
+ {/* relative, flex, justify-center */} +
+ {toolbars.primary.map(toolDef => { + const { id, Component, componentProps } = toolDef; + + return ; + })} +
+
- + {toolbars.secondary.map(toolDef => { + const { id, Component, componentProps } = toolDef; + + return ; + })}
- {/* - viewportContents={[ - alert(`Series ${direction}`)} - studyData={{ - label: 'A', - isTracked: true, - isLocked: false, - studyDate: '07-Sep-2011', - currentSeries: 1, - seriesDescription: - 'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ', - modality: 'CT', - patientInformation: { - patientName: 'Smith, Jane', - patientSex: 'F', - patientAge: '59', - MRN: '10000001', - thickness: '5.0mm', - spacing: '1.25mm', - scanner: 'Aquilion', - }, - }} - > - , - alert(`Series ${direction}`)} - studyData={{ - label: 'A', - isTracked: false, - isLocked: true, - studyDate: '07-Sep-2010', - currentSeries: 2, - seriesDescription: - 'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ', - modality: 'SR', - patientInformation: { - patientName: 'Smith, Jane', - patientSex: 'F', - patientAge: '59', - MRN: '10000001', - thickness: '2.0mm', - spacing: '1.25mm', - scanner: 'Aquilion', - }, - }} - > - , - ]} - setActiveViewportIndex={setActiveViewportIndex} - activeViewportIndex={activeViewportIndex} - />*/}
{rightPanelComponents.length && ( @@ -227,14 +135,6 @@ ViewerLayout.propTypes = { }).isRequired, commandsManager: PropTypes.object, // From modes - // TODO: Not in love with this shape, - toolBarLayout: PropTypes.arrayOf( - PropTypes.shape({ - tools: PropTypes.array, - moreTools: PropTypes.array, - }) - ).isRequired, - //displaySetInstanceUids: PropTypes.any.isRequired, leftPanels: PropTypes.array, rightPanels: PropTypes.array, /** Responsible for rendering our grid of viewports; provided by consuming application */ diff --git a/extensions/default/src/getToolbarModule.js b/extensions/default/src/getToolbarModule.js index e6f855057..5c0c173f1 100644 --- a/extensions/default/src/getToolbarModule.js +++ b/extensions/default/src/getToolbarModule.js @@ -1,19 +1,86 @@ -const TOOLBAR_BUTTON_TYPES = { - COMMAND: 'command', - SET_TOOL_ACTIVE: 'setToolActive', - BUILT_IN: 'builtIn', -}; +import { ToolbarButton } from '@ohif/ui'; +import ToolbarDivider from './Toolbar/ToolbarDivider.jsx'; -const definitions = [ - { - id: 'Layout', - label: 'Layout', - icon: 'tool-layout', - commandName: 'toggleLayoutSelectionDialog', - commandOptions: { }, - }, -]; +export default function getToolbarModule({ commandsManager, servicesManager }) { + const toolbarService = servicesManager.services.ToolBarService; -export default function getToolbarModule() { - return { definitions, defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE' }; + return [ + { + name: 'ohif.divider', + defaultComponent: ToolbarDivider, + clickHandler: () => {}, + }, + { + name: 'ohif.action', + defaultComponent: ToolbarButton, + requiredConfig: [], + optionalConfig: [], + requiredProps: [], + optionalProps: [], + clickHandler: (evt, btn, btnSectionName) => { + const { props } = btn; + commandsManager.runCommand(props.commandName, props.commandOptions); + }, + }, + { + name: 'ohif.radioGroup', + defaultComponent: ToolbarButton, + requiredConfig: ['groupName'], + optionalConfig: [], + requiredProps: [], + optionalProps: [], + clickHandler: (evt, clickedBtn, btnSectionName) => { + const { props } = clickedBtn; + const allButtons = toolbarService.getButtons(); + + // Set all buttons in same group to inactive + Object.keys(allButtons).forEach(btnName => { + const btn = allButtons[btnName]; + const isRadioGroupBtn = + btn.config && + btn.config.groupName && + btn.type === 'ohif.radioGroup'; + + if ( + isRadioGroupBtn && + clickedBtn.config.groupName === btn.config.groupName + ) { + btn.props.isActive = false; + } + }); + + // Set our clicked button to active + allButtons[clickedBtn.id].props.isActive = true; + + // Run button logic/command + commandsManager.runCommand(props.commandName, props.commandOptions); + + // Set buttons & trigger notification + toolbarService.setButtons(allButtons); + }, + }, + { + name: 'ohif.toggle', + defaultComponent: ToolbarButton, + requiredConfig: [], + optionalConfig: [], + requiredProps: [], + optionalProps: [], + clickHandler: (evt, clickedBtn, btnSectionName) => { + const { props } = clickedBtn; + const allButtons = toolbarService.getButtons(); + const thisButton = allButtons[clickedBtn.id]; + + // Set our clicked button to active + thisButton.props.isActive = !thisButton.props.isActive; + + // Run button logic/command + // MAKE SURE THIS SUPPORTS TOGGLE! + commandsManager.runCommand(props.commandName, props.commandOptions); + + // Set buttons & trigger notification + toolbarService.setButtons(allButtons); + }, + }, + ]; } diff --git a/platform/core/src/extensions/ExtensionManager.js b/platform/core/src/extensions/ExtensionManager.js index 4e0fda85f..90c00bf7c 100644 --- a/platform/core/src/extensions/ExtensionManager.js +++ b/platform/core/src/extensions/ExtensionManager.js @@ -17,9 +17,6 @@ export default class ExtensionManager { this.modules[moduleType] = []; }); this.dataSourceMap = {}; - - console.log('modules map'); - console.log(this.modulesMap); } /** @@ -102,9 +99,6 @@ export default class ExtensionManager { ); break; case MODULE_TYPES.TOOLBAR: - this._initToolBarModule(extensionModule, extensionId); - break; - case MODULE_TYPES.VIEWPORT: case MODULE_TYPES.PANEL: case MODULE_TYPES.SOP_CLASS_HANDLER: @@ -112,7 +106,6 @@ export default class ExtensionManager { case MODULE_TYPES.LAYOUT_TEMPLATE: // Default for most extension points, // Just adds each entry ready for consumption by mode. - extensionModule.forEach(element => { this.modulesMap[ `${extensionId}.${moduleType}.${element.name}` @@ -141,27 +134,6 @@ export default class ExtensionManager { return this.dataSourceMap[dataSourceName]; }; - _initToolBarModule = (extensionModule, extensionId) => { - let { definitions, defaultContext } = extensionModule; - if (!definitions || Object.keys(definitions).length === 0) { - log.warn('Commands Module contains no command definitions'); - return; - } - - defaultContext = defaultContext || 'VIEWER'; - - definitions.forEach(definition => { - console.log(`${extensionId}.${MODULE_TYPES.TOOLBAR}.${definition.id}`); - - // TODO -> Deep copy instead of mutation? We only do this once, but would be better. - definition.context = definition.context || defaultContext; - - this.modulesMap[ - `${extensionId}.${MODULE_TYPES.TOOLBAR}.${definition.id}` - ] = definition; - }); - }; - /** * @private * @param {string} moduleType @@ -178,13 +150,13 @@ export default class ExtensionManager { try { const extensionModule = getModuleFn({ - getDataSources: this.getDataSources, // Why pass this in if we're passing in `extensionManager`? - servicesManager: this._servicesManager, - commandsManager: this._commandsManager, appConfig: this._appConfig, + getDataSources: this.getDataSources, // Why pass this in if we're passing in `extensionManager`? + commandsManager: this._commandsManager, + extensionManager: this, + servicesManager: this._servicesManager, configuration, api: this._api, - extensionManager: this, }); if (!extensionModule) {