This commit is contained in:
mario
2025-03-07 13:47:44 +07:00
commit c4efec5a14
3358 changed files with 303774 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
const path = require('path');
const webpackCommon = require('./../../../.webpack/webpack.base.js');
const SRC_DIR = path.join(__dirname, '../src');
const DIST_DIR = path.join(__dirname, '../dist');
const ENTRY = {
app: `${SRC_DIR}/index.ts`,
};
module.exports = (env, argv) => {
return webpackCommon(env, argv, { SRC_DIR, DIST_DIR, ENTRY });
};

View File

@@ -0,0 +1,54 @@
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const pkg = require('./../package.json');
const webpackCommon = require('./../../../.webpack/webpack.base.js');
const ROOT_DIR = path.join(__dirname, './../');
const SRC_DIR = path.join(__dirname, '../src');
const DIST_DIR = path.join(__dirname, '../dist');
const ENTRY = {
app: `${SRC_DIR}/index.ts`,
};
module.exports = (env, argv) => {
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR, ENTRY });
return merge(commonConfig, {
stats: {
colors: true,
hash: true,
timings: true,
assets: true,
chunks: false,
chunkModules: false,
modules: false,
children: false,
warnings: true,
},
optimization: {
minimize: true,
sideEffects: false,
},
output: {
path: ROOT_DIR,
library: 'ohif-mode-basic-test',
libraryTarget: 'umd',
libraryExport: 'default',
filename: pkg.main,
},
externals: [/\b(vtk.js)/, /\b(dcmjs)/, /\b(gl-matrix)/, /^@ohif/, /^@cornerstonejs/],
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
}),
// new MiniCssExtractPlugin({
// filename: './dist/[name].css',
// chunkFilename: './dist/[id].css',
// }),
],
});
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
MIT License
Copyright (c) 2023 Open Health Imaging Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,5 @@
# Test mode
This mode is used to test the basic functionality of the OHIF viewer
in a controlled environment. It is not intended to be used for
development or production.

View File

@@ -0,0 +1 @@
module.exports = require('../../babel.config.js');

View File

@@ -0,0 +1,54 @@
{
"name": "@ohif/mode-test",
"version": "3.9.1",
"description": "Basic mode for testing",
"author": "OHIF",
"license": "MIT",
"repository": "OHIF/Viewers",
"main": "dist/ohif-mode-test.umd.js",
"module": "src/index.ts",
"engines": {
"node": ">=14",
"npm": ">=6",
"yarn": ">=1.16.0"
},
"files": [
"dist",
"README.md"
],
"publishConfig": {
"access": "public"
},
"keywords": [
"ohif-mode"
],
"scripts": {
"clean": "shx rm -rf dist",
"clean:deep": "yarn run clean && shx rm -rf node_modules",
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
"dev:cornerstone": "yarn run dev",
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
"build:package": "yarn run build",
"start": "yarn run dev",
"test:unit": "jest --watchAll",
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.9.1",
"@ohif/extension-cornerstone": "3.9.1",
"@ohif/extension-cornerstone-dicom-sr": "3.9.1",
"@ohif/extension-default": "3.9.1",
"@ohif/extension-dicom-pdf": "3.9.1",
"@ohif/extension-dicom-video": "3.9.1",
"@ohif/extension-measurement-tracking": "3.9.1",
"@ohif/extension-test": "3.9.1"
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"i18next": "^17.0.3"
},
"devDependencies": {
"webpack": "5.94.0",
"webpack-merge": "^5.7.3"
}
}

View File

@@ -0,0 +1,5 @@
import packageJson from '../package.json';
const id = packageJson.name;
export { id };

View File

@@ -0,0 +1,220 @@
import { hotkeys } from '@ohif/core';
import toolbarButtons from './toolbarButtons';
import { id } from './id';
import initToolGroups from './initToolGroups';
import moreTools from './moreTools';
import i18n from 'i18next';
// Allow this mode by excluding non-imaging modalities such as SR, SEG
// Also, SM is not a simple imaging modalities, so exclude it.
const NON_IMAGE_MODALITIES = ['ECG', 'SR', 'SEG', 'RTSTRUCT'];
const ohif = {
layout: '@ohif/extension-default.layoutTemplateModule.viewerLayout',
sopClassHandler: '@ohif/extension-default.sopClassHandlerModule.stack',
wsiSopClassHandler:
'@ohif/extension-cornerstone.sopClassHandlerModule.DicomMicroscopySopClassHandler',
thumbnailList: '@ohif/extension-default.panelModule.seriesList',
measurements: '@ohif/extension-default.panelModule.measurements',
};
const tracked = {
measurements: '@ohif/extension-measurement-tracking.panelModule.trackedMeasurements',
thumbnailList: '@ohif/extension-measurement-tracking.panelModule.seriesList',
viewport: '@ohif/extension-measurement-tracking.viewportModule.cornerstone-tracked',
};
const dicomsr = {
sopClassHandler: '@ohif/extension-cornerstone-dicom-sr.sopClassHandlerModule.dicom-sr',
viewport: '@ohif/extension-cornerstone-dicom-sr.viewportModule.dicom-sr',
};
const dicomvideo = {
sopClassHandler: '@ohif/extension-dicom-video.sopClassHandlerModule.dicom-video',
viewport: '@ohif/extension-dicom-video.viewportModule.dicom-video',
};
const dicompdf = {
sopClassHandler: '@ohif/extension-dicom-pdf.sopClassHandlerModule.dicom-pdf',
viewport: '@ohif/extension-dicom-pdf.viewportModule.dicom-pdf',
};
const dicomSeg = {
sopClassHandler: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg',
viewport: '@ohif/extension-cornerstone-dicom-seg.viewportModule.dicom-seg',
};
const cornerstone = {
panel: '@ohif/extension-cornerstone.panelModule.panelSegmentation',
};
const dicomPmap = {
sopClassHandler: '@ohif/extension-cornerstone-dicom-pmap.sopClassHandlerModule.dicom-pmap',
viewport: '@ohif/extension-cornerstone-dicom-pmap.viewportModule.dicom-pmap',
};
const extensionDependencies = {
// Can derive the versions at least process.env.from npm_package_version
'@ohif/extension-default': '^3.0.0',
'@ohif/extension-cornerstone': '^3.0.0',
'@ohif/extension-measurement-tracking': '^3.0.0',
'@ohif/extension-cornerstone-dicom-sr': '^3.0.0',
'@ohif/extension-cornerstone-dicom-seg': '^3.0.0',
'@ohif/extension-cornerstone-dicom-pmap': '^3.0.0',
'@ohif/extension-dicom-pdf': '^3.0.1',
'@ohif/extension-dicom-video': '^3.0.1',
'@ohif/extension-test': '^0.0.1',
};
function modeFactory() {
return {
// TODO: We're using this as a route segment
// We should not be.
id,
routeName: 'basic-test',
displayName: i18n.t('Modes:Basic Test Mode'),
/**
* Lifecycle hooks
*/
onModeEnter: ({ servicesManager, extensionManager, commandsManager }: withAppTypes) => {
const { measurementService, toolbarService, toolGroupService, customizationService } =
servicesManager.services;
measurementService.clearMeasurements();
// Init Default and SR ToolGroups
initToolGroups(extensionManager, toolGroupService, commandsManager);
// init customizations
customizationService.addModeCustomizations([
'@ohif/extension-test.customizationModule.custom-context-menu',
]);
toolbarService.addButtons([...toolbarButtons, ...moreTools]);
toolbarService.createButtonSection('primary', [
'MeasurementTools',
'Zoom',
'WindowLevel',
'Pan',
'Capture',
'Layout',
'MPR',
'Crosshairs',
'MoreTools',
]);
},
onModeExit: ({ servicesManager }: withAppTypes) => {
const {
toolGroupService,
syncGroupService,
segmentationService,
cornerstoneViewportService,
uiDialogService,
uiModalService,
} = servicesManager.services;
uiDialogService.dismissAll();
uiModalService.hide();
toolGroupService.destroy();
syncGroupService.destroy();
segmentationService.destroy();
cornerstoneViewportService.destroy();
},
validationTags: {
study: [],
series: [],
},
isValidMode: function ({ modalities }) {
const modalities_list = modalities.split('\\');
// Exclude non-image modalities
return {
valid: !!modalities_list.filter(modality => NON_IMAGE_MODALITIES.indexOf(modality) === -1)
.length,
description:
'The mode does not support studies that ONLY include the following modalities: SM, ECG, SR, SEG',
};
},
routes: [
{
path: 'basic-test',
/*init: ({ servicesManager, extensionManager }) => {
//defaultViewerRouteInit
},*/
layoutTemplate: () => {
return {
id: ohif.layout,
props: {
// Use the first two for an untracked view
// leftPanels: [ohif.thumbnailList],
// rightPanels: [dicomSeg.panel, ohif.measurements],
leftPanels: [tracked.thumbnailList],
rightPanels: [cornerstone.panel, tracked.measurements],
// rightPanelClosed: true, // optional prop to start with collapse panels
viewports: [
{
namespace: tracked.viewport,
displaySetsToDisplay: [
ohif.sopClassHandler,
dicomvideo.sopClassHandler,
ohif.wsiSopClassHandler,
],
},
{
namespace: dicomsr.viewport,
displaySetsToDisplay: [dicomsr.sopClassHandler],
},
{
namespace: dicomvideo.viewport,
displaySetsToDisplay: [dicomvideo.sopClassHandler],
},
{
namespace: dicompdf.viewport,
displaySetsToDisplay: [dicompdf.sopClassHandler],
},
{
namespace: dicomSeg.viewport,
displaySetsToDisplay: [dicomSeg.sopClassHandler],
},
{
namespace: dicomPmap.viewport,
displaySetsToDisplay: [dicomPmap.sopClassHandler],
},
],
},
};
},
},
],
extensions: extensionDependencies,
// Default protocol gets self-registered by default in the init
hangingProtocol: 'default',
// Order is important in sop class handlers when two handlers both use
// the same sop class under different situations. In that case, the more
// general handler needs to come last. For this case, the dicomvideo must
// come first to remove video transfer syntax before ohif uses images
sopClassHandlers: [
dicomvideo.sopClassHandler,
dicomSeg.sopClassHandler,
ohif.wsiSopClassHandler,
ohif.sopClassHandler,
dicompdf.sopClassHandler,
dicomsr.sopClassHandler,
],
hotkeys: {
// Don't store the hotkeys for basic-test-mode under the same key
// because they get customized by tests
name: 'basic-test-hotkeys',
hotkeys: [...hotkeys.defaults.hotkeyBindings],
},
};
}
const mode = {
id,
modeFactory,
extensionDependencies,
};
export default mode;

View File

@@ -0,0 +1,275 @@
const colours = {
'viewport-0': 'rgb(200, 0, 0)',
'viewport-1': 'rgb(200, 200, 0)',
'viewport-2': 'rgb(0, 200, 0)',
};
const colorsByOrientation = {
axial: 'rgb(200, 0, 0)',
sagittal: 'rgb(200, 200, 0)',
coronal: 'rgb(0, 200, 0)',
};
function initDefaultToolGroup(extensionManager, toolGroupService, commandsManager, toolGroupId) {
const utilityModule = extensionManager.getModuleEntry(
'@ohif/extension-cornerstone.utilityModule.tools'
);
const { toolNames, Enums } = utilityModule.exports;
const tools = {
active: [
{
toolName: toolNames.WindowLevel,
bindings: [{ mouseButton: Enums.MouseBindings.Primary }],
},
{
toolName: toolNames.Pan,
bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }],
},
{
toolName: toolNames.Zoom,
bindings: [{ mouseButton: Enums.MouseBindings.Secondary }],
},
{
toolName: toolNames.StackScroll,
bindings: [{ mouseButton: Enums.MouseBindings.Wheel }],
},
],
passive: [
{ toolName: toolNames.Length },
{
toolName: toolNames.ArrowAnnotate,
configuration: {
getTextCallback: (callback, eventDetails) =>
commandsManager.runCommand('arrowTextCallback', {
callback,
eventDetails,
}),
changeTextCallback: (data, eventDetails, callback) =>
commandsManager.runCommand('arrowTextCallback', {
callback,
data,
eventDetails,
}),
},
},
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.Probe },
{ toolName: toolNames.EllipticalROI },
{ toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },
{ toolName: toolNames.CobbAngle },
{ toolName: toolNames.Magnify },
{ toolName: toolNames.WindowLevelRegion },
{ toolName: toolNames.UltrasoundDirectional },
{ toolName: toolNames.PlanarFreehandROI },
{ toolName: toolNames.SplineROI },
{ toolName: toolNames.LivewireContour },
],
// enabled
enabled: [{ toolName: toolNames.ImageOverlayViewer }],
// disabled
disabled: [{ toolName: toolNames.ReferenceLines }, { toolName: toolNames.AdvancedMagnify }],
};
toolGroupService.createToolGroupAndAddTools(toolGroupId, tools);
}
function initSRToolGroup(extensionManager, toolGroupService, commandsManager) {
const SRUtilityModule = extensionManager.getModuleEntry(
'@ohif/extension-cornerstone-dicom-sr.utilityModule.tools'
);
const CS3DUtilityModule = extensionManager.getModuleEntry(
'@ohif/extension-cornerstone.utilityModule.tools'
);
const { toolNames: SRToolNames } = SRUtilityModule.exports;
const { toolNames, Enums } = CS3DUtilityModule.exports;
const tools = {
active: [
{
toolName: toolNames.WindowLevel,
bindings: [
{
mouseButton: Enums.MouseBindings.Primary,
},
],
},
{
toolName: toolNames.Pan,
bindings: [
{
mouseButton: Enums.MouseBindings.Auxiliary,
},
],
},
{
toolName: toolNames.Zoom,
bindings: [
{
mouseButton: Enums.MouseBindings.Secondary,
},
],
},
{
toolName: toolNames.StackScroll,
bindings: [{ mouseButton: Enums.MouseBindings.Wheel }],
},
],
passive: [
{ toolName: SRToolNames.SRLength },
{ toolName: SRToolNames.SRArrowAnnotate },
{ toolName: SRToolNames.SRBidirectional },
{ toolName: SRToolNames.SREllipticalROI },
{ toolName: SRToolNames.SRCircleROI },
{ toolName: toolNames.WindowLevelRegion },
],
enabled: [
{
toolName: SRToolNames.DICOMSRDisplay,
bindings: [],
},
],
// disabled
};
const toolGroupId = 'SRToolGroup';
toolGroupService.createToolGroupAndAddTools(toolGroupId, tools);
}
function initMPRToolGroup(extensionManager, toolGroupService, commandsManager) {
const utilityModule = extensionManager.getModuleEntry(
'@ohif/extension-cornerstone.utilityModule.tools'
);
const serviceManager = extensionManager._servicesManager;
const { cornerstoneViewportService } = serviceManager.services;
const { toolNames, Enums } = utilityModule.exports;
const tools = {
active: [
{
toolName: toolNames.WindowLevel,
bindings: [{ mouseButton: Enums.MouseBindings.Primary }],
},
{
toolName: toolNames.Pan,
bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }],
},
{
toolName: toolNames.Zoom,
bindings: [{ mouseButton: Enums.MouseBindings.Secondary }],
},
{
toolName: toolNames.StackScroll,
bindings: [{ mouseButton: Enums.MouseBindings.Wheel }],
},
],
passive: [
{ toolName: toolNames.Length },
{
toolName: toolNames.ArrowAnnotate,
configuration: {
getTextCallback: (callback, eventDetails) =>
commandsManager.runCommand('arrowTextCallback', {
callback,
eventDetails,
}),
changeTextCallback: (data, eventDetails, callback) =>
commandsManager.runCommand('arrowTextCallback', {
callback,
data,
eventDetails,
}),
},
},
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.Probe },
{ toolName: toolNames.EllipticalROI },
{ toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },
{ toolName: toolNames.WindowLevelRegion },
{ toolName: toolNames.PlanarFreehandROI },
{ toolName: toolNames.SplineROI },
],
disabled: [
{
toolName: toolNames.Crosshairs,
configuration: {
viewportIndicators: false,
autoPan: {
enabled: false,
panSize: 10,
},
getReferenceLineColor: viewportId => {
const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
const viewportOptions = viewportInfo?.viewportOptions;
if (viewportOptions) {
return (
colours[viewportOptions.id] ||
colorsByOrientation[viewportOptions.orientation] ||
'#0c0'
);
} else {
console.warn('missing viewport?', viewportId);
return '#0c0';
}
},
},
},
{ toolName: toolNames.ReferenceLines },
],
// enabled
// disabled
};
toolGroupService.createToolGroupAndAddTools('mpr', tools);
}
function initVolume3DToolGroup(extensionManager, toolGroupService) {
const utilityModule = extensionManager.getModuleEntry(
'@ohif/extension-cornerstone.utilityModule.tools'
);
const { toolNames, Enums } = utilityModule.exports;
const tools = {
active: [
{
toolName: toolNames.TrackballRotateTool,
bindings: [{ mouseButton: Enums.MouseBindings.Primary }],
},
{
toolName: toolNames.Zoom,
bindings: [{ mouseButton: Enums.MouseBindings.Secondary }],
},
{
toolName: toolNames.Pan,
bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }],
},
],
};
toolGroupService.createToolGroupAndAddTools('volume3d', tools);
}
function initToolGroups(extensionManager, toolGroupService, commandsManager) {
initDefaultToolGroup(extensionManager, toolGroupService, commandsManager, 'default');
initSRToolGroup(extensionManager, toolGroupService, commandsManager);
initMPRToolGroup(extensionManager, toolGroupService, commandsManager);
initVolume3DToolGroup(extensionManager, toolGroupService);
}
export default initToolGroups;

View File

@@ -0,0 +1,212 @@
import type { RunCommand } from '@ohif/core/types';
import { EVENTS } from '@cornerstonejs/core';
import { ToolbarService, ViewportGridService } from '@ohif/core';
import { setToolActiveToolbar } from './toolbarButtons';
const { createButton } = ToolbarService;
const ReferenceLinesListeners: RunCommand = [
{
commandName: 'setSourceViewportForReferenceLinesTool',
context: 'CORNERSTONE',
},
];
const moreTools = [
{
id: 'MoreTools',
uiType: 'ohif.splitButton',
props: {
groupId: 'MoreTools',
evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
primary: createButton({
id: 'Reset',
icon: 'tool-reset',
tooltip: 'Reset View',
label: 'Reset',
commands: 'resetViewport',
evaluate: 'evaluate.action',
}),
secondary: {
icon: 'chevron-down',
label: '',
tooltip: 'More Tools',
},
items: [
createButton({
id: 'Reset',
icon: 'tool-reset',
label: 'Reset View',
tooltip: 'Reset View',
commands: 'resetViewport',
evaluate: 'evaluate.action',
}),
createButton({
id: 'rotate-right',
icon: 'tool-rotate-right',
label: 'Rotate Right',
tooltip: 'Rotate +90',
commands: 'rotateViewportCW',
evaluate: 'evaluate.action',
}),
createButton({
id: 'flipHorizontal',
icon: 'tool-flip-horizontal',
label: 'Flip Horizontal',
tooltip: 'Flip Horizontally',
commands: 'flipViewportHorizontal',
evaluate: 'evaluate.viewportProperties.toggle',
}),
createButton({
id: 'ImageSliceSync',
icon: 'link',
label: 'Image Slice Sync',
tooltip: 'Enable position synchronization on stack viewports',
commands: {
commandName: 'toggleSynchronizer',
commandOptions: {
type: 'imageSlice',
},
},
listeners: {
[EVENTS.VIEWPORT_NEW_IMAGE_SET]: {
commandName: 'toggleImageSliceSync',
commandOptions: { toggledState: true },
},
},
evaluate: 'evaluate.cornerstone.synchronizer',
}),
createButton({
id: 'ReferenceLines',
icon: 'tool-referenceLines',
label: 'Reference Lines',
tooltip: 'Show Reference Lines',
commands: 'toggleEnabledDisabledToolbar',
listeners: {
[ViewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED]: ReferenceLinesListeners,
[ViewportGridService.EVENTS.VIEWPORTS_READY]: ReferenceLinesListeners,
},
evaluate: 'evaluate.cornerstoneTool.toggle',
}),
createButton({
id: 'ImageOverlayViewer',
icon: 'toggle-dicom-overlay',
label: 'Image Overlay',
tooltip: 'Toggle Image Overlay',
commands: 'toggleEnabledDisabledToolbar',
evaluate: 'evaluate.cornerstoneTool.toggle',
}),
createButton({
id: 'StackScroll',
icon: 'tool-stack-scroll',
label: 'Stack Scroll',
tooltip: 'Stack Scroll',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'invert',
icon: 'tool-invert',
label: 'Invert',
tooltip: 'Invert Colors',
commands: 'invertViewport',
evaluate: 'evaluate.viewportProperties.toggle',
}),
createButton({
id: 'Probe',
icon: 'tool-probe',
label: 'Probe',
tooltip: 'Probe',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'Cine',
icon: 'tool-cine',
label: 'Cine',
tooltip: 'Cine',
commands: 'toggleCine',
evaluate: 'evaluate.cine',
}),
createButton({
id: 'Angle',
icon: 'tool-angle',
label: 'Angle',
tooltip: 'Angle',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'CobbAngle',
icon: 'icon-tool-cobb-angle',
label: 'Cobb Angle',
tooltip: 'Cobb Angle',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'Magnify',
icon: 'tool-magnify',
label: 'Zoom-in',
tooltip: 'Zoom-in',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'RectangleROI',
icon: 'tool-rectangle',
label: 'Rectangle',
tooltip: 'Rectangle',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'CalibrationLine',
icon: 'tool-calibration',
label: 'Calibration',
tooltip: 'Calibration Line',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'TagBrowser',
icon: 'dicom-tag-browser',
label: 'Dicom Tag Browser',
tooltip: 'Dicom Tag Browser',
commands: 'openDICOMTagViewer',
}),
createButton({
id: 'AdvancedMagnify',
icon: 'icon-tool-loupe',
label: 'Magnify Probe',
tooltip: 'Magnify Probe',
commands: 'toggleActiveDisabledToolbar',
evaluate: 'evaluate.cornerstoneTool.toggle.ifStrictlyDisabled',
}),
createButton({
id: 'UltrasoundDirectionalTool',
icon: 'icon-tool-ultrasound-bidirectional',
label: 'Ultrasound Directional',
tooltip: 'Ultrasound Directional',
commands: setToolActiveToolbar,
evaluate: [
'evaluate.cornerstoneTool',
{
name: 'evaluate.modality.supported',
supportedModalities: ['US'],
},
],
}),
createButton({
id: 'WindowLevelRegion',
icon: 'icon-tool-window-region',
label: 'Window Level Region',
tooltip: 'Window Level Region',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
],
},
},
];
export default moreTools;

View File

@@ -0,0 +1,253 @@
// 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
import {
// ListMenu,
WindowLevelMenuItem,
} from '@ohif/ui';
import { defaults, ToolbarService } from '@ohif/core';
import type { Button } from '@ohif/core/types';
const { windowLevelPresets } = defaults;
const { createButton } = ToolbarService;
/**
*
* @param {*} preset - preset number (from above import)
* @param {*} title
* @param {*} subtitle
*/
function _createWwwcPreset(preset, title, subtitle) {
return {
id: preset.toString(),
title,
subtitle,
commands: [
{
commandName: 'setWindowLevel',
commandOptions: {
...windowLevelPresets[preset],
},
context: 'CORNERSTONE',
},
],
};
}
export const setToolActiveToolbar = {
commandName: 'setToolActiveToolbar',
commandOptions: {
toolGroupIds: ['default', 'mpr', 'SRToolGroup'],
},
};
const toolbarButtons: Button[] = [
{
id: 'MeasurementTools',
uiType: 'ohif.splitButton',
props: {
groupId: 'MeasurementTools',
// group evaluate to determine which item should move to the top
evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
primary: createButton({
id: 'Length',
icon: 'tool-length',
label: 'Length',
tooltip: 'Length Tool',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
secondary: {
icon: 'chevron-down',
tooltip: 'More Measure Tools',
},
items: [
createButton({
id: 'Length',
icon: 'tool-length',
label: 'Length',
tooltip: 'Length Tool',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'Bidirectional',
icon: 'tool-bidirectional',
label: 'Bidirectional',
tooltip: 'Bidirectional Tool',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'ArrowAnnotate',
icon: 'tool-annotate',
label: 'Annotation',
tooltip: 'Arrow Annotate',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'EllipticalROI',
icon: 'tool-ellipse',
label: 'Ellipse',
tooltip: 'Ellipse ROI',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'CircleROI',
icon: 'tool-circle',
label: 'Circle',
tooltip: 'Circle Tool',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'PlanarFreehandROI',
icon: 'icon-tool-freehand-roi',
label: 'Freehand ROI',
tooltip: 'Freehand ROI',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'SplineROI',
icon: 'icon-tool-spline-roi',
label: 'Spline ROI',
tooltip: 'Spline ROI',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'LivewireContour',
icon: 'icon-tool-livewire',
label: 'Livewire tool',
tooltip: 'Livewire tool',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
],
},
},
{
id: 'Zoom',
uiType: 'ohif.radioGroup',
props: {
icon: 'tool-zoom',
label: 'Zoom',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
},
},
// Window Level
{
id: 'WindowLevel',
uiType: 'ohif.splitButton',
props: {
groupId: 'WindowLevel',
primary: createButton({
id: 'WindowLevel',
icon: 'tool-window-level',
label: 'Window Level',
tooltip: 'Window Level',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
secondary: {
icon: 'chevron-down',
label: 'W/L Manual',
tooltip: 'W/L Presets',
},
renderer: WindowLevelMenuItem,
items: [
_createWwwcPreset(1, 'Soft tissue', '400 / 40'),
_createWwwcPreset(2, 'Lung', '1500 / -600'),
_createWwwcPreset(3, 'Liver', '150 / 90'),
_createWwwcPreset(4, 'Bone', '2500 / 480'),
_createWwwcPreset(5, 'Brain', '80 / 40'),
],
},
},
// Pan...
{
id: 'Pan',
uiType: 'ohif.radioGroup',
props: {
type: 'tool',
icon: 'tool-move',
label: 'Pan',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
},
},
{
id: 'MPR',
uiType: 'ohif.radioGroup',
props: {
icon: 'icon-mpr',
label: 'MPR',
commands: [
{
commandName: 'toggleHangingProtocol',
commandOptions: {
protocolId: 'mpr',
},
},
],
evaluate: 'evaluate.mpr',
},
},
{
id: 'TrackBallRotate',
type: 'ohif.radioGroup',
props: {
type: 'tool',
icon: 'tool-3d-rotate',
label: '3D Rotate',
commands: setToolActiveToolbar,
},
},
{
id: 'Capture',
uiType: 'ohif.radioGroup',
props: {
icon: 'tool-capture',
label: 'Capture',
commands: 'showDownloadViewportModal',
evaluate: [
'evaluate.action',
{
name: 'evaluate.viewport.supported',
unsupportedViewportTypes: ['video', 'wholeSlide'],
},
],
},
},
{
id: 'Layout',
uiType: 'ohif.layoutSelector',
props: {
rows: 3,
columns: 4,
evaluate: 'evaluate.action',
commands: 'setViewportGridLayout',
},
},
{
id: 'Crosshairs',
uiType: 'ohif.radioGroup',
props: {
type: 'tool',
icon: 'tool-crosshair',
label: 'Crosshairs',
commands: {
commandName: 'setToolActiveToolbar',
commandOptions: {
toolGroupIds: ['mpr'],
},
},
evaluate: 'evaluate.cornerstoneTool',
},
},
];
export default toolbarButtons;