Skip to content

Commit

Permalink
fix(toolbar): allow customizable toolbar for active viewport and allo…
Browse files Browse the repository at this point in the history
…w active tool to be deactivated via a click (#3608)

Co-authored-by: Joe Boccanfuso <joe.boccanfuso@radicalimaging.com>
  • Loading branch information
wayfarer3130 and Joe Boccanfuso authored Oct 25, 2023
1 parent 2145b42 commit dd6d976
Show file tree
Hide file tree
Showing 18 changed files with 1,096 additions and 628 deletions.
9 changes: 2 additions & 7 deletions extensions/cornerstone/src/commandsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,13 +456,8 @@ function commandsModule({

const { viewport } = enabledElement;

if (viewport instanceof StackViewport) {
viewport.resetProperties();
viewport.resetCamera();
} else {
viewport.resetProperties();
viewport.resetCamera();
}
viewport.resetProperties?.();
viewport.resetCamera();

viewport.render();
},
Expand Down
25 changes: 20 additions & 5 deletions extensions/default/src/Toolbar/Toolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
import React, { useEffect, useState, useCallback } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import classnames from 'classnames';
import { useViewportGrid } from '@ohif/ui';

export default function Toolbar({ servicesManager }) {
export default function Toolbar({
servicesManager,
}: Types.Extensions.ExtensionParams): React.ReactElement {
const { toolbarService } = servicesManager.services;

const [viewportGrid, viewportGridService] = useViewportGrid();

const [toolbarButtons, setToolbarButtons] = useState([]);

useEffect(() => {
const { unsubscribe } = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_MODIFIED, () =>
setToolbarButtons(toolbarService.getButtonSection('primary'))
const updateToolbar = () => {
const toolGroupId =
viewportGridService.getActiveViewportOptionByKey('toolGroupId') ?? 'default';
setToolbarButtons(toolbarService.getButtonSection(toolGroupId));
};

const { unsubscribe } = toolbarService.subscribe(
toolbarService.EVENTS.TOOL_BAR_MODIFIED,
updateToolbar
);

updateToolbar();

return () => {
unsubscribe();
};
}, [toolbarService]);
}, [toolbarService, viewportGrid]);

const onInteraction = useCallback(
args => toolbarService.recordInteraction(args),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ ToolbarButtonWithServices.propTypes = {
state: PropTypes.shape({
primaryToolId: PropTypes.string,
toggles: PropTypes.objectOf(PropTypes.bool),
groups: PropTypes.objectOf(PropTypes.object),
groups: PropTypes.objectOf(PropTypes.any),
}).isRequired,
}).isRequired,
}).isRequired,
Expand Down
49 changes: 33 additions & 16 deletions modes/basic-test-mode/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import { hotkeys } from '@ohif/core';
import toolbarButtons from './toolbarButtons';
import { id } from './id';
import initToolGroups from './initToolGroups';
import moreTools from './moreTools';
import moreToolsMpr from './moreToolsMpr';

// 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 = ['SM', 'ECG', 'SR', 'SEG'];

const DEFAULT_TOOL_GROUP_ID = 'default';
const MPR_TOOL_GROUP_ID = 'mpr';

const ohif = {
layout: '@ohif/extension-default.layoutTemplateModule.viewerLayout',
sopClassHandler: '@ohif/extension-default.sopClassHandlerModule.stack',
Expand Down Expand Up @@ -77,21 +82,23 @@ function modeFactory() {
]);

let unsubscribe;
toolbarService.setDefaultTool({
groupId: 'WindowLevel',
itemId: 'WindowLevel',
interactionType: 'tool',
commands: [
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'WindowLevel',
},
context: 'CORNERSTONE',
},
],
});

const activateTool = () => {
toolbarService.recordInteraction({
groupId: 'WindowLevel',
interactionType: 'tool',
commands: [
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'WindowLevel',
},
context: 'CORNERSTONE',
},
],
});
toolbarService.recordInteraction(toolbarService.getDefaultTool());

// We don't need to reset the active tool whenever a viewport is getting
// added to the toolGroup.
Expand All @@ -106,18 +113,28 @@ function modeFactory() {
));

toolbarService.init(extensionManager);
toolbarService.addButtons(toolbarButtons);
toolbarService.createButtonSection('primary', [
toolbarService.addButtons([...toolbarButtons, ...moreTools, ...moreToolsMpr]);
toolbarService.createButtonSection(DEFAULT_TOOL_GROUP_ID, [
'MeasurementTools',
'Zoom',
'WindowLevel',
'Pan',
'Capture',
'Layout',
'MPR',
'Crosshairs',
'MoreTools',
]);
toolbarService.createButtonSection(MPR_TOOL_GROUP_ID, [
'MeasurementTools',
'Zoom',
'WindowLevel',
'Pan',
'Capture',
'Layout',
'MPR',
'Crosshairs',
'MoreToolsMpr',
]);
},
onModeExit: ({ servicesManager }) => {
const {
Expand Down
231 changes: 231 additions & 0 deletions modes/basic-test-mode/src/moreTools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
import type { RunCommand } from '@ohif/core/types';
import { EVENTS } from '@cornerstonejs/core';
import { ToolbarService } from '@ohif/core';

const ReferenceLinesCommands: RunCommand = [
{
commandName: 'setSourceViewportForReferenceLinesTool',
context: 'CORNERSTONE',
},
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'ReferenceLines',
},
context: 'CORNERSTONE',
},
];

const moreTools = [
{
id: 'MoreTools',
type: 'ohif.splitButton',
props: {
isRadio: true, // ?
groupId: 'MoreTools',
primary: ToolbarService._createActionButton(
'Reset',
'tool-reset',
'Reset View',
[
{
commandName: 'resetViewport',
},
],
'Reset'
),
secondary: {
icon: 'chevron-down',
label: '',
isActive: true,
tooltip: 'More Tools',
},
items: [
ToolbarService._createActionButton(
'Reset',
'tool-reset',
'Reset View',
[
{
commandName: 'resetViewport',
},
],
'Reset'
),
ToolbarService._createActionButton(
'rotate-right',
'tool-rotate-right',
'Rotate Right',
[
{
commandName: 'rotateViewportCW',
commandOptions: {},
context: 'CORNERSTONE',
},
],
'Rotate +90'
),
ToolbarService._createActionButton(
'flip-horizontal',
'tool-flip-horizontal',
'Flip Horizontally',
[
{
commandName: 'flipViewportHorizontal',
commandOptions: {},
context: 'CORNERSTONE',
},
],
'Flip Horizontally'
),
ToolbarService._createToggleButton(
'StackImageSync',
'link',
'Stack Image Sync',
[
{
commandName: 'toggleStackImageSync',
},
],
'Enable position synchronization on stack viewports',
{
listeners: {
[EVENTS.STACK_VIEWPORT_NEW_STACK]: {
commandName: 'toggleStackImageSync',
commandOptions: { toggledState: true },
},
},
}
),
ToolbarService._createToggleButton(
'ReferenceLines',
'tool-referenceLines', // change this with the new icon
'Reference Lines',
ReferenceLinesCommands,
'Show Reference Lines',
{
listeners: {
[EVENTS.STACK_VIEWPORT_NEW_STACK]: ReferenceLinesCommands,
[EVENTS.ACTIVE_VIEWPORT_ID_CHANGED]: ReferenceLinesCommands,
},
}
),
ToolbarService._createToolButton(
'StackScroll',
'tool-stack-scroll',
'Stack Scroll',
[
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'StackScroll',
},
context: 'CORNERSTONE',
},
],
'Stack Scroll'
),
ToolbarService._createActionButton(
'invert',
'tool-invert',
'Invert',
[
{
commandName: 'invertViewport',
commandOptions: {},
context: 'CORNERSTONE',
},
],
'Invert Colors'
),
ToolbarService._createToolButton(
'Probe',
'tool-probe',
'Probe',
[
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'DragProbe',
},
context: 'CORNERSTONE',
},
],
'Probe'
),
ToolbarService._createToggleButton(
'cine',
'tool-cine',
'Cine',
[
{
commandName: 'toggleCine',
context: 'CORNERSTONE',
},
],
'Cine'
),
ToolbarService._createToolButton(
'Angle',
'tool-angle',
'Angle',
[
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'Angle',
},
context: 'CORNERSTONE',
},
],
'Angle'
),
ToolbarService._createToolButton(
'Magnify',
'tool-magnify',
'Magnify',
[
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'Magnify',
},
context: 'CORNERSTONE',
},
],
'Magnify'
),
ToolbarService._createToolButton(
'Rectangle',
'tool-rectangle',
'Rectangle',
[
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'RectangleROI',
},
context: 'CORNERSTONE',
},
],
'Rectangle'
),
ToolbarService._createActionButton(
'TagBrowser',
'list-bullets',
'Dicom Tag Browser',
[
{
commandName: 'openDICOMTagViewer',
commandOptions: {},
context: 'DEFAULT',
},
],
'Dicom Tag Browser'
),
],
},
},
];

export default moreTools;
Loading

0 comments on commit dd6d976

Please sign in to comment.