Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(segmentation-tools): toggle passive and active tool modes based on segment actions #4633

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions extensions/cornerstone-dicom-seg/src/getToolbarModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ export function getToolbarModule({ servicesManager }: withAppTypes) {
};
}

const activeSegmentation = segmentationService.getActiveSegmentation(viewportId);
if (!Object.keys(activeSegmentation.segments).length) {
return {
disabled: true,
className: '!text-common-bright !bg-black opacity-50',
disabledText: 'Add segment to enable this tool',
};
}

const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);

if (!toolGroup) {
Expand Down
1 change: 1 addition & 0 deletions extensions/cornerstone/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
toolbarService.registerEventForToolbarUpdate(segmentationService, [
segmentationService.EVENTS.SEGMENTATION_REMOVED,
segmentationService.EVENTS.SEGMENTATION_MODIFIED,
segmentationService.EVENTS.ACTIVE_SEGMENTATION_CHANGED,
]);

toolbarService.registerEventForToolbarUpdate(cornerstone.eventTarget, [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { updateLabelmapSegmentationImageReferences } from '@cornerstonejs/tools/
import { triggerSegmentationRepresentationModified } from '@cornerstonejs/tools/segmentation/triggerSegmentationEvents';
import { convertStackToVolumeLabelmap } from '@cornerstonejs/tools/segmentation/helpers/convertStackToVolumeLabelmap';
import { getLabelmapImageIds } from '@cornerstonejs/tools/segmentation';
import setSegToolModeForToolGroups from '../../utils/setSegToolModeForToolGroups';

const LABELMAP = csToolsEnums.SegmentationRepresentations.Labelmap;
const CONTOUR = csToolsEnums.SegmentationRepresentations.Contour;
Expand Down Expand Up @@ -65,6 +66,8 @@ const EVENTS = {
SEGMENTATION_DATA_MODIFIED: 'event::segmentation_data_modified',
// fired when the segmentation is removed
SEGMENTATION_REMOVED: 'event::segmentation_removed',
// fired when the active segmentation is changed
ACTIVE_SEGMENTATION_CHANGED: 'event::active_segmentation_changed',
//
// fired when segmentation representation is added
SEGMENTATION_REPRESENTATION_MODIFIED: 'event::segmentation_representation_modified',
Expand Down Expand Up @@ -688,10 +691,28 @@ class SegmentationService extends PubSubService {
// Add a new segmentation
this.addSegmentationToSource(data as cstTypes.SegmentationPublicInput);
}
const { toolGroupService } = this.servicesManager.services;
setSegToolModeForToolGroups(toolGroupService, csToolsEnums.ToolModes.Active);
}

public setActiveSegmentation(viewportId: string, segmentationId: string): void {
const segmentation = this.getSegmentation(segmentationId);
const segments = segmentation.segments;
const { toolGroupService } = this.servicesManager.services;

// Set the tool mode based on the presence of segments
const toolMode = Object.keys(segments).length
? csToolsEnums.ToolModes.Active
: csToolsEnums.ToolModes.Passive;

cstSegmentation.activeSegmentation.setActiveSegmentation(viewportId, segmentationId);

// Set the tool mode for the tool group
setSegToolModeForToolGroups(toolGroupService, toolMode);

this._broadcastEvent(EVENTS.ACTIVE_SEGMENTATION_CHANGED, {
segmentationId,
});
}

/**
Expand Down Expand Up @@ -809,7 +830,7 @@ class SegmentationService extends PubSubService {
if (!segmentIndex) {
// grab the next available segment index based on the object keys,
// so basically get the highest segment index value + 1
segmentIndex = Math.max(...Object.keys(csSegmentation.segments).map(Number)) + 1;
segmentIndex = Math.max(0, ...Object.keys(csSegmentation.segments).map(Number)) + 1;
}

// update the segmentation
Expand Down Expand Up @@ -875,6 +896,15 @@ class SegmentationService extends PubSubService {
*/
public removeSegment(segmentationId: string, segmentIndex: number): void {
cstSegmentation.removeSegment(segmentationId, segmentIndex);
const segmentation = this.getSegmentation(segmentationId);
const segments = segmentation.segments;

// Set the tool to passive mode if there are no segments in the active segmentation.
if (!Object.keys(segments).length) {
const { toolGroupService } = this.servicesManager.services;

setSegToolModeForToolGroups(toolGroupService, csToolsEnums.ToolModes.Passive);
}
}

public setSegmentVisibility(
Expand Down Expand Up @@ -1705,7 +1735,17 @@ class SegmentationService extends PubSubService {
};

private _setActiveSegment(segmentationId: string, segmentIndex: number) {
const segmentation = this.getSegmentation(segmentationId);
const segments = segmentation.segments;

cstSegmentation.segmentIndex.setActiveSegmentIndex(segmentationId, segmentIndex);

// Set the tool to active mode if there is at least one segment in the active segmentation.
if (Object.keys(segments).length) {
const { toolGroupService } = this.servicesManager.services;

setSegToolModeForToolGroups(toolGroupService, csToolsEnums.ToolModes.Active);
}
}

private _getVolumeIdForDisplaySet(displaySet) {
Expand Down
14 changes: 14 additions & 0 deletions extensions/cornerstone/src/utils/SegmentationTools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const segmentationTools = [
'CircularBrush',
'SphereBrush',
'CircularEraser',
'SphereEraser',
'CircleScissor',
'RectangleScissor',
'SphereScissor',
'ThresholdCircularBrush',
'ThresholdSphereBrush',
'ThresholdCircularBrushDynamic',
];

export { segmentationTools };
33 changes: 33 additions & 0 deletions extensions/cornerstone/src/utils/setSegToolModeForToolGroups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Enums } from '@cornerstonejs/tools';
import ToolGroupService from '../services/ToolGroupService';
import { segmentationTools } from './SegmentationTools';

/**
* Sets the mode for segmentation tools in all tool groups managed by the tool group service.
*
* @param toolGroupService - The service managing the tool groups.
* @param mode - The mode to set for the tools (e.g., Active, Enabled, Passive, Disabled).
*/
const setSegToolModeForToolGroups = (toolGroupService: ToolGroupService, mode: Enums.ToolModes) => {
const toolGroupIds = toolGroupService.getToolGroupIds();
toolGroupIds.forEach(toolGroupId => {
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
if (!toolGroup) {
return;
}
const toolName = toolGroup.currentActivePrimaryToolName;
if (!toolName || !toolGroup.hasTool(toolName) || !segmentationTools.includes(toolName)) {
return;
}
let options;

if (mode === Enums.ToolModes.Active) {
options = {
bindings: [{ mouseButton: Enums.MouseBindings.Primary }],
};
}
toolGroup.setToolMode(toolName, mode, options);
});
};

export default setSegToolModeForToolGroups;