fix(toolbox): Preserve user-specified tool state and streamline command execution (#4063)
This commit is contained in:
1 parent
4784638717
commit
f1a736d193
34 files changed
+332
-181
No files matched your search
@@ -485,7 +485,10 @@ function _subscribeToJumpToMeasurementEvents(
|
||||
cornerstoneViewportService.getViewportIdToJump(
|
||||
jumpId,
|
||||
measurement.displaySetInstanceUID,
|
||||
{ referencedImageId: measurement.referencedImageId }
|
||||
{
|
||||
referencedImageId:
|
||||
measurement.referencedImageId || measurement.metadata?.referencedImageId,
|
||||
}
|
||||
);
|
||||
}
|
||||
if (cacheJumpToMeasurementEvent.cornerstoneViewport !== viewportId) {
|
||||
@@ -594,6 +597,9 @@ function _jumpToMeasurement(
|
||||
i => i.SOPInstanceUID === SOPInstanceUID
|
||||
);
|
||||
|
||||
// the index is reversed in the volume viewport
|
||||
// imageIdIndex = referencedDisplaySet.images.length - 1 - imageIdIndex;
|
||||
|
||||
const { viewPlaneNormal: viewportViewPlane } = viewport.getCamera();
|
||||
|
||||
// should compare abs for both planes since the direction can be flipped
|
||||
|
||||
@@ -23,7 +23,7 @@ function CornerstoneImageScrollbar({
|
||||
|
||||
if (isCineEnabled) {
|
||||
// on image scrollbar change, stop the CINE if it is playing
|
||||
cineService.stopClip(element);
|
||||
cineService.stopClip(element, { viewportId });
|
||||
cineService.setCine({ id: viewportId, isPlaying: false });
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ function WrappedCinePlayer({ enabledVPElement, viewportId, servicesManager }) {
|
||||
}
|
||||
cineService.setCine({ id: viewportId, isPlaying, frameRate });
|
||||
setNewStackFrameRate(frameRate);
|
||||
}, [displaySetService, viewportId, viewportGridService, cines, isCineEnabled]);
|
||||
}, [displaySetService, viewportId, viewportGridService, cines, isCineEnabled, enabledVPElement]);
|
||||
|
||||
useEffect(() => {
|
||||
isMountedRef.current = true;
|
||||
@@ -78,6 +78,14 @@ function WrappedCinePlayer({ enabledVPElement, viewportId, servicesManager }) {
|
||||
};
|
||||
}, [isCineEnabled, newDisplaySetHandler]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isCineEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
cineHandler();
|
||||
}, [isCineEnabled, cineHandler, enabledVPElement]);
|
||||
|
||||
/**
|
||||
* Use effect for handling new display set
|
||||
*/
|
||||
@@ -112,7 +120,7 @@ function WrappedCinePlayer({ enabledVPElement, viewportId, servicesManager }) {
|
||||
cineHandler();
|
||||
|
||||
return () => {
|
||||
cineService.stopClip(enabledVPElement);
|
||||
cineService.stopClip(enabledVPElement, { viewportId });
|
||||
};
|
||||
}, [cines, viewportId, cineService, enabledVPElement, cineHandler]);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ const getToggledClassName = (isToggled: boolean) => {
|
||||
export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
const {
|
||||
toolGroupService,
|
||||
toolbarService,
|
||||
syncGroupService,
|
||||
cornerstoneViewportService,
|
||||
hangingProtocolService,
|
||||
@@ -21,16 +22,16 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
// enabled or not
|
||||
{
|
||||
name: 'evaluate.cornerstoneTool',
|
||||
evaluate: ({ viewportId, button, disabledText }) => {
|
||||
evaluate: ({ viewportId, button, toolNames, disabledText }) => {
|
||||
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
|
||||
|
||||
if (!toolGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toolName = getToolNameForButton(button);
|
||||
const toolName = toolbarService.getToolNameForButton(button);
|
||||
|
||||
if (!toolGroup || !toolGroup.hasTool(toolName)) {
|
||||
if (!toolGroup || (!toolGroup.hasTool(toolName) && !toolNames)) {
|
||||
return {
|
||||
disabled: true,
|
||||
className: '!text-common-bright ohif-disabled',
|
||||
@@ -38,7 +39,9 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
};
|
||||
}
|
||||
|
||||
const isPrimaryActive = toolGroup.getActivePrimaryMouseButtonTool() === toolName;
|
||||
const isPrimaryActive = toolNames
|
||||
? toolNames.includes(toolGroup.getActivePrimaryMouseButtonTool())
|
||||
: toolGroup.getActivePrimaryMouseButtonTool() === toolName;
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
@@ -71,7 +74,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
// check if the active toolName is part of the items then we need
|
||||
// to move it to the primary button
|
||||
const activeToolIndex = items.findIndex(item => {
|
||||
const toolName = getToolNameForButton(item);
|
||||
const toolName = toolbarService.getToolNameForButton(item);
|
||||
return toolName === activeToolName;
|
||||
});
|
||||
|
||||
@@ -114,6 +117,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
_evaluateToggle({
|
||||
viewportId,
|
||||
button,
|
||||
toolbarService,
|
||||
disabledText,
|
||||
offModes: [Enums.ToolModes.Disabled],
|
||||
toolGroupService,
|
||||
@@ -125,6 +129,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
_evaluateToggle({
|
||||
viewportId,
|
||||
button,
|
||||
toolbarService,
|
||||
disabledText,
|
||||
offModes: [Enums.ToolModes.Disabled, Enums.ToolModes.Passive],
|
||||
toolGroupService,
|
||||
@@ -267,13 +272,20 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
];
|
||||
}
|
||||
|
||||
function _evaluateToggle({ viewportId, button, disabledText, offModes, toolGroupService }) {
|
||||
function _evaluateToggle({
|
||||
viewportId,
|
||||
toolbarService,
|
||||
button,
|
||||
disabledText,
|
||||
offModes,
|
||||
toolGroupService,
|
||||
}) {
|
||||
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
|
||||
|
||||
if (!toolGroup) {
|
||||
return;
|
||||
}
|
||||
const toolName = getToolNameForButton(button);
|
||||
const toolName = toolbarService.getToolNameForButton(button);
|
||||
|
||||
if (!toolGroup.hasTool(toolName)) {
|
||||
return {
|
||||
@@ -289,19 +301,3 @@ function _evaluateToggle({ viewportId, button, disabledText, offModes, toolGroup
|
||||
className: getToggledClassName(!isOff),
|
||||
};
|
||||
}
|
||||
|
||||
// Todo: this is duplicate, we should move it to a shared location
|
||||
function getToolNameForButton(button) {
|
||||
const { props } = button;
|
||||
|
||||
const commands = props?.commands || button.commands;
|
||||
const commandsArray = Array.isArray(commands) ? commands : [commands];
|
||||
const firstCommand = commandsArray[0];
|
||||
|
||||
if (firstCommand?.commandOptions) {
|
||||
return firstCommand.commandOptions.toolName ?? props?.id ?? button.id;
|
||||
}
|
||||
|
||||
// use id as a fallback for toolName
|
||||
return props?.id ?? button.id;
|
||||
}
|
||||
@@ -532,6 +532,11 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
cameraProps: unknown
|
||||
): string {
|
||||
const viewportInfo = this.getViewportInfo(activeViewportId);
|
||||
|
||||
if (viewportInfo.getViewportType() === csEnums.ViewportType.VOLUME_3D) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { referencedImageId } = cameraProps;
|
||||
if (viewportInfo?.contains(displaySetInstanceUID, referencedImageId)) {
|
||||
return activeViewportId;
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { Types, Enums } from '@cornerstonejs/core';
|
||||
import {
|
||||
Types,
|
||||
Enums,
|
||||
getEnabledElementByViewportId,
|
||||
VolumeViewport,
|
||||
utilities,
|
||||
} from '@cornerstonejs/core';
|
||||
import { Types as CoreTypes } from '@ohif/core';
|
||||
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
|
||||
import getCornerstoneBlendMode from '../../utils/getCornerstoneBlendMode';
|
||||
@@ -89,13 +95,30 @@ const DEFAULT_TOOLGROUP_ID = 'default';
|
||||
|
||||
// Return true if the data contains the given display set UID OR the imageId
|
||||
// if it is a composite object.
|
||||
const dataContains = (data, displaySetUID: string, imageId?: string): boolean => {
|
||||
if (data.displaySetInstanceUID === displaySetUID) {
|
||||
return true;
|
||||
}
|
||||
const dataContains = ({ data, displaySetUID, imageId, viewport }): boolean => {
|
||||
if (imageId && data.isCompositeStack && data.imageIds) {
|
||||
return !!data.imageIds.find(dataId => dataId === imageId);
|
||||
}
|
||||
|
||||
if (imageId && (data.volumeId || viewport instanceof VolumeViewport)) {
|
||||
const isAcquisition = !!viewport.getCurrentImageId();
|
||||
|
||||
if (!isAcquisition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const imageURI = utilities.imageIdToURI(imageId);
|
||||
const hasImageId = viewport.hasImageURI(imageURI);
|
||||
|
||||
if (hasImageId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.displaySetInstanceUID === displaySetUID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -122,10 +145,20 @@ class ViewportInfo {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { viewport } = getEnabledElementByViewportId(this.viewportId) || {};
|
||||
|
||||
if (this.viewportData.data.length) {
|
||||
return !!this.viewportData.data.find(data => dataContains(data, displaySetUID, imageId));
|
||||
return !!this.viewportData.data.find(data =>
|
||||
dataContains({ data, displaySetUID, imageId, viewport })
|
||||
);
|
||||
}
|
||||
return dataContains(this.viewportData.data, displaySetUID, imageId);
|
||||
|
||||
return dataContains({
|
||||
data: this.viewportData.data,
|
||||
displaySetUID,
|
||||
imageId,
|
||||
viewport,
|
||||
});
|
||||
}
|
||||
|
||||
public destroy = (): void => {
|
||||
|
||||
@@ -114,6 +114,7 @@ function getMappedAnnotations(annotation, DisplaySetService) {
|
||||
unit: modalityUnit,
|
||||
mean,
|
||||
stdDev,
|
||||
metadata,
|
||||
max,
|
||||
area,
|
||||
areaUnit,
|
||||
|
||||
Reference in new issue
Block a user