diff --git a/extensions/cornerstone/src/index.js b/extensions/cornerstone/src/index.js
index 0d30d2232..985663238 100644
--- a/extensions/cornerstone/src/index.js
+++ b/extensions/cornerstone/src/index.js
@@ -23,7 +23,7 @@ export default {
/**
* Only required property. Should be a unique value across all extensions.
*/
- id: 'cornerstone',
+ id: 'org.ohif.cornerstone',
/**
*
@@ -39,10 +39,14 @@ export default {
const onNewImageHandler = jumpData => {
commandsManager.runCommand('jumpToImage', jumpData);
};
- return ;
+ return (
+
+ );
};
- return ExtendedOHIFCornerstoneViewport;
+ return [
+ { name: 'cornerstone', component: ExtendedOHIFCornerstoneViewport },
+ ];
},
getToolbarModule() {
return toolbarModule;
diff --git a/extensions/cornerstone/src/init.js b/extensions/cornerstone/src/init.js
index e2f807838..27e962b80 100644
--- a/extensions/cornerstone/src/init.js
+++ b/extensions/cornerstone/src/init.js
@@ -15,8 +15,6 @@ import measurementServiceMappingsFactory from './utils/measurementServiceMapping
export default function init({ servicesManager, configuration }) {
const { UIDialogService, MeasurementService } = servicesManager.services;
- debugger;
-
const callInputDialog = (data, event, callback) => {
if (UIDialogService) {
let dialogId = UIDialogService.create({
diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js
index 74f7aa44a..e4c8f9dc9 100644
--- a/extensions/default/src/DicomWebDataSource/index.js
+++ b/extensions/default/src/DicomWebDataSource/index.js
@@ -165,8 +165,6 @@ function createDicomWebApi(dicomWebConfig) {
}
});
- debugger;
-
return imageIds;
},
});
diff --git a/modes/example/src/index.js b/modes/example/src/index.js
index fd48b5e58..706d0ca11 100644
--- a/modes/example/src/index.js
+++ b/modes/example/src/index.js
@@ -12,12 +12,25 @@ export default function mode({ modeConfiguration }) {
routes: [
{
path: 'viewer',
- preInit: ({ toolbarManager }) => {
- toolbarManager &&
- toolbarManager.setDefaultLoadOut([
- [], // Primary
- [], // Secondary
- ]);
+ init: ({ toolbarManager }) => {
+ toolbarManager.addButtons([
+ {
+ id: 'StackScroll', // If id not given will use default in button definition.
+ namespace: 'org.ohif.cornerstone.toolbarModule.StackScroll',
+ },
+ {
+ id: 'Zoom',
+ namespace: 'org.ohif.cornerstone.toolbarModule.Zoom',
+ },
+ ]);
+
+ // Could import layout selector here from org.ohif.default (when it exists!)
+ toolbarManager.setToolBarLayout([
+ // Primary
+ ['StackScroll', { label: 'More', subMenu: ['Zoom'] }],
+ // Secondary
+ ['StackScroll'],
+ ]);
},
layoutTemplate: ({ routeProps }) => {
return {
diff --git a/platform/core/src/ToolBarManager.js b/platform/core/src/ToolBarManager.js
new file mode 100644
index 000000000..d94b1488c
--- /dev/null
+++ b/platform/core/src/ToolBarManager.js
@@ -0,0 +1,55 @@
+export default class toolBarManager {
+ constructor(extensionManager) {
+ this.toolBarLayout = [];
+ this.buttons = {};
+ this.extensionManager = extensionManager;
+ }
+
+ addButtons(buttons) {
+ buttons.forEach(button => {
+ const buttonDefinition = this.extensionManager.getModuleEntry(
+ button.namespace
+ );
+
+ const id = button.id || buttonDefinition.id;
+
+ this.buttons[id] = buttonDefinition;
+ });
+
+ console.log(this.buttons);
+ }
+
+ setToolBarLayout(layouts) {
+ const toolBarLayout = [];
+
+ layouts.forEach(layout => {
+ const toolBarDefinitions = [];
+
+ layout.forEach(element => {
+ if (typeof element === 'object') {
+ // process submenu.
+
+ const subMenuDefinition = { label: element.label, subMenu: [] };
+
+ element.subMenu.forEach(subMenuElement => {
+ const button = this.buttons[subMenuElement];
+
+ subMenuDefinition.subMenu.push(button);
+ });
+
+ toolBarDefinitions.push(subMenuDefinition);
+ } else {
+ const button = this.buttons[element];
+
+ toolBarDefinitions.push(button);
+ }
+ });
+
+ toolBarLayout.push(toolBarDefinitions);
+ });
+
+ this.toolBarLayout = toolBarLayout;
+
+ console.log(this.toolBarLayout);
+ }
+}
diff --git a/platform/core/src/extensions/ExtensionManager.js b/platform/core/src/extensions/ExtensionManager.js
index 5fab3d8f3..27b0f2b44 100644
--- a/platform/core/src/extensions/ExtensionManager.js
+++ b/platform/core/src/extensions/ExtensionManager.js
@@ -17,6 +17,9 @@ export default class ExtensionManager {
this.modules[moduleType] = [];
});
this.dataSourceMap = {};
+
+ console.log('modules map');
+ console.log(this.modulesMap);
}
/**
@@ -55,11 +58,9 @@ export default class ExtensionManager {
let extensionId = extension.id;
if (!extensionId) {
- extensionId = Math.random()
- .toString(36)
- .substr(2, 5);
-
- log.warn(`Extension ID not set. Using random string ID: ${extensionId}`);
+ // Note: Mode framework cannot function without IDs.
+ log.warn(extension);
+ throw new Error(`Extension ID not set`);
}
if (this.registeredExtensionIds.includes(extensionId)) {
@@ -89,25 +90,43 @@ export default class ExtensionManager {
);
if (extensionModule) {
- this._initSpecialModuleTypes(
- extensionId,
- moduleType,
- extensionModule,
- dataSources
- );
+ switch (moduleType) {
+ case MODULE_TYPES.COMMANDS:
+ this._initCommandsModule(extensionModule);
+ break;
+ case MODULE_TYPES.DATA_SOURCE:
+ this._initDataSourcesModule(
+ extensionModule,
+ extensionId,
+ dataSources
+ );
+ break;
+ case MODULE_TYPES.TOOLBAR:
+ this._initToolBarModule(extensionModule, extensionId);
+ break;
+
+ case MODULE_TYPES.PANEL:
+ case MODULE_TYPES.SOP_CLASS_HANDLER:
+ case MODULE_TYPES.VIEWPORT:
+ case MODULE_TYPES.CONTEXT:
+ case MODULE_TYPES.LAYOUT_TEMPLATE:
+ // Default for most extension points,
+ // Just adds each entry ready for consumption by mode.
+ if (!extensionModule.forEach) {
+ debugger;
+ }
+
+ extensionModule.forEach(element => {
+ this.modulesMap[
+ `${extensionId}.${moduleType}.${element.name}`
+ ] = element;
+ });
+ }
this.modules[moduleType].push({
extensionId,
module: extensionModule,
});
-
- // TODO -> deal with command modules.
-
- extensionModule.forEach(element => {
- this.modulesMap[
- `${extensionId}.${moduleType}.${element.name}`
- ] = element;
- });
}
});
@@ -124,6 +143,27 @@ 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
@@ -162,64 +202,52 @@ export default class ExtensionManager {
}
};
- _initSpecialModuleTypes = (
- extensionId,
- moduleType,
- extensionModule,
- dataSources
- ) => {
- switch (moduleType) {
- case 'commandsModule': {
- const { definitions, defaultContext } = extensionModule;
- if (!definitions || Object.keys(definitions).length === 0) {
- log.warn('Commands Module contains no command definitions');
- return;
+ _initDataSourcesModule(extensionModule, extensionId, dataSources) {
+ extensionModule.forEach(element => {
+ const namespace = `${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`;
+
+ dataSources.forEach(dataSource => {
+ if (dataSource.namespace === namespace) {
+ const dataSourceInstance = element.createDataSource(
+ dataSource.configuration
+ );
+
+ if (this.dataSourceMap[dataSource.sourceName]) {
+ this.dataSourceMap[dataSource.sourceName].push(dataSourceInstance);
+ } else {
+ this.dataSourceMap[dataSource.sourceName] = [dataSourceInstance];
+ }
}
- this._initCommandsModule(definitions, defaultContext);
- break;
- }
- case 'dataSourcesModule': {
- extensionModule.forEach(element => {
- const namespace = `${extensionId}.${moduleType}.${element.name}`;
+ });
+ });
- dataSources.forEach(dataSource => {
- if (dataSource.namespace === namespace) {
- const dataSourceInstance = element.createDataSource(
- dataSource.configuration
- );
-
- if (this.dataSourceMap[dataSource.sourceName]) {
- this.dataSourceMap[dataSource.sourceName].push(
- dataSourceInstance
- );
- } else {
- this.dataSourceMap[dataSource.sourceName] = [
- dataSourceInstance,
- ];
- }
- }
- });
- });
-
- break;
- }
- default:
- // code block
- }
- };
+ extensionModule.forEach(element => {
+ this.modulesMap[
+ `${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`
+ ] = element;
+ });
+ }
/**
*
* @private
* @param {Object[]} commandDefinitions
*/
- _initCommandsModule = (commandDefinitions, defaultContext = 'VIEWER') => {
+ _initCommandsModule = extensionModule => {
+ let { definitions, defaultContext } = extensionModule;
+ if (!definitions || Object.keys(definitions).length === 0) {
+ log.warn('Commands Module contains no command definitions');
+ return;
+ }
+
+ defaultContext = defaultContext || 'VIEWER';
+
if (!this._commandsManager.getContext(defaultContext)) {
this._commandsManager.createContext(defaultContext);
}
- Object.keys(commandDefinitions).forEach(commandName => {
- const commandDefinition = commandDefinitions[commandName];
+ Object.keys(definitions).forEach(commandName => {
+ const commandDefinition = definitions[commandName];
const commandHasContextThatDoesNotExist =
commandDefinition.context &&
!this._commandsManager.getContext(commandDefinition.context);
diff --git a/platform/core/src/index.js b/platform/core/src/index.js
index 6d4c691e1..296d91b6d 100644
--- a/platform/core/src/index.js
+++ b/platform/core/src/index.js
@@ -20,6 +20,7 @@ import ui from './ui';
import user from './user.js';
import dicomMetadataStore from './dicomMetadataStore';
import displaySetManager from './displaySetManager';
+import ToolBarManager from './ToolBarManager';
import utils, { hotkeys } from './utils/';
import {
@@ -68,6 +69,7 @@ const OHIF = {
IWebApiDataSource,
dicomMetadataStore,
displaySetManager,
+ ToolBarManager,
};
export {
@@ -105,6 +107,7 @@ export {
IWebApiDataSource,
dicomMetadataStore,
displaySetManager,
+ ToolBarManager,
};
export { OHIF };
diff --git a/platform/viewer/src/appInit.js b/platform/viewer/src/appInit.js
index d489808b3..508c34dc7 100644
--- a/platform/viewer/src/appInit.js
+++ b/platform/viewer/src/appInit.js
@@ -47,8 +47,6 @@ function appInit(appConfigOrFunc, defaultExtensions) {
MeasurementService,
]);
- debugger;
-
/**
* Example: [ext1, ext2, ext3]
* Example2: [[ext1, config], ext2, [ext3, config]]
diff --git a/platform/viewer/src/routes/ModeRoute.js b/platform/viewer/src/routes/ModeRoute.js
index 5feacb448..b17848324 100644
--- a/platform/viewer/src/routes/ModeRoute.js
+++ b/platform/viewer/src/routes/ModeRoute.js
@@ -1,5 +1,5 @@
import React, { useContext, useEffect, useCallback } from 'react';
-import { displaySetManager } from '@ohif/core';
+import { displaySetManager, ToolBarManager } from '@ohif/core';
import ViewModelContext from './ViewModelContext';
import Compose from './Compose';
@@ -9,15 +9,21 @@ export default function ModeRoute({
dataSourceName,
extensionManager,
}) {
- const { routes, sopClassHandlers, extensions } = mode;
+ const { routes, sopClassHandlers, extensions, init } = mode;
const dataSources = extensionManager.getDataSources(dataSourceName);
+ const toolbarManager = new ToolBarManager(extensionManager);
+
// TODO: For now assume one unique datasource.
const dataSource = dataSources[0];
+ const route = routes[0];
+
+ route.init({ toolbarManager });
console.log(dataSource);
+ // Add toolbar state to the view model context?
const { displaySetInstanceUids, setDisplaySetInstanceUids } = useContext(
ViewModelContext
);
@@ -42,11 +48,9 @@ export default function ModeRoute({
createDisplaySets();
}, [mode, dataSourceName, location]);
- // Deal with toolbar.
-
// Only handling one route per mode for now
// You can test via http://localhost:3000/example-mode/dicomweb
- const layoutTemplateData = routes[0].layoutTemplate({ location });
+ const layoutTemplateData = route.layoutTemplate({ location });
const layoutTemplateModuleEntry = extensionManager.getModuleEntry(
layoutTemplateData.id
);