feat(multimonitor): Add simple multi-monitor support to open another study(#4178)

This commit is contained in:
Bill Wallace authored and GitHub committed 2025-01-13 10:49:08 -05:00
1 parent a4a6de07f4
commit 07c628e689
49 files changed
+1476 -367

No files matched your search

+72 -8
View File
@@ -1,4 +1,4 @@
import { Types } from '@ohif/core';
import { Types, DicomMetadataStore } from '@ohif/core';
import { ContextMenuController, defaultContextMenu } from './CustomizableContextMenu';
import DicomTagBrowser from './DicomTagBrowser/DicomTagBrowser';
@@ -16,6 +16,7 @@ import { useHangingProtocolStageIndexStore } from './stores/useHangingProtocolSt
import { useToggleHangingProtocolStore } from './stores/useToggleHangingProtocolStore';
import { useViewportsByPositionStore } from './stores/useViewportsByPositionStore';
import { useToggleOneUpViewportGridStore } from './stores/useToggleOneUpViewportGridStore';
import requestDisplaySetCreationForStudy from './Panels/requestDisplaySetCreationForStudy';
export type HangingProtocolParams = {
protocolId?: string;
@@ -33,6 +34,7 @@ export type UpdateViewportDisplaySetParams = {
const commandsModule = ({
servicesManager,
commandsManager,
extensionManager,
}: Types.Extensions.ExtensionParams): Types.Extensions.CommandsModule => {
const {
customizationService,
@@ -41,12 +43,56 @@ const commandsModule = ({
uiNotificationService,
viewportGridService,
displaySetService,
multiMonitorService,
} = servicesManager.services;
// Define a context menu controller for use with any context menus
const contextMenuController = new ContextMenuController(servicesManager, commandsManager);
const actions = {
/**
* Runs a command in multi-monitor mode. No-op if not multi-monitor.
*/
multimonitor: async options => {
const { screenDelta, StudyInstanceUID, commands, hashParams } = options;
if (multiMonitorService.numberOfScreens < 2) {
return options.fallback?.(options);
}
const newWindow = await multiMonitorService.launchWindow(
StudyInstanceUID,
screenDelta,
hashParams
);
// Only run commands if we successfully got a window with a commands manager
if (newWindow && commands) {
// Todo: fix this properly, but it takes time for the new window to load
// and then the commandsManager is available for it
setTimeout(() => {
multiMonitorService.run(screenDelta, commands, options);
}, 1000);
}
},
/**
* Ensures that the specified study is available for display
* Then, if commands is specified, runs the given commands list/instance
*/
loadStudy: async options => {
const { StudyInstanceUID } = options;
const displaySets = displaySetService.getActiveDisplaySets();
const isActive = displaySets.find(ds => ds.StudyInstanceUID === StudyInstanceUID);
if (isActive) {
return;
}
const [dataSource] = extensionManager.getActiveDataSource();
await requestDisplaySetCreationForStudy(dataSource, displaySetService, StudyInstanceUID);
const study = DicomMetadataStore.getStudy(StudyInstanceUID);
hangingProtocolService.addStudy(study);
},
/**
* Show the context menu.
* @param options.menuId defines the menu name to lookup, from customizationService
@@ -135,11 +181,13 @@ const commandsModule = ({
*/
setHangingProtocol: ({
activeStudyUID = '',
StudyInstanceUID = '',
protocolId,
stageId,
stageIndex,
reset = false,
}: HangingProtocolParams): boolean => {
const toUseStudyInstanceUID = activeStudyUID || StudyInstanceUID;
try {
// Stores in the state the display set selector id to displaySetUID mapping
// Pass in viewportId for the active viewport. This item will get set as
@@ -158,7 +206,7 @@ const commandsModule = ({
}
} else if (stageIndex === undefined && stageId === undefined) {
// Re-set the same stage as was previously used
const hangingId = `${activeStudyUID || hpInfo.activeStudyUID}:${protocolId}`;
const hangingId = `${toUseStudyInstanceUID || hpInfo.activeStudyUID}:${protocolId}`;
stageIndex = hangingProtocolStageIndexMap[hangingId]?.stageIndex;
}
@@ -169,11 +217,9 @@ const commandsModule = ({
stageIndex,
});
if (activeStudyUID) {
hangingProtocolService.setActiveStudyUID(activeStudyUID);
}
const activeStudyChanged = hangingProtocolService.setActiveStudyUID(toUseStudyInstanceUID);
const storedHanging = `${hangingProtocolService.getState().activeStudyUID}:${protocolId}:${
const storedHanging = `${toUseStudyInstanceUID || hangingProtocolService.getState().activeStudyUID}:${protocolId}:${
useStageIdx || 0
}`;
@@ -181,9 +227,25 @@ const commandsModule = ({
const restoreProtocol = !reset && viewportGridState[storedHanging];
if (
reset ||
(activeStudyChanged &&
!viewportGridState[storedHanging] &&
stageIndex === undefined &&
stageId === undefined)
) {
// Run the hanging protocol fresh, re-using the existing study data
// This is done on reset or when the study changes and we haven't yet
// applied it, and don't specify exact stage to use.
const displaySets = displaySetService.getActiveDisplaySets();
const activeStudy = {
StudyInstanceUID: toUseStudyInstanceUID,
displaySets,
};
hangingProtocolService.run(activeStudy, protocolId);
} else if (
protocolId === hpInfo.protocolId &&
useStageIdx === hpInfo.stageIndex &&
!activeStudyUID
!toUseStudyInstanceUID
) {
// Clear the HP setting to reset them
hangingProtocolService.setProtocol(protocolId, {
@@ -204,7 +266,7 @@ const commandsModule = ({
// Do this after successfully applying the update
const { setDisplaySetSelector } = useDisplaySetSelectorStore.getState();
setDisplaySetSelector(
`${activeStudyUID || hpInfo.activeStudyUID}:activeDisplaySet:0`,
`${toUseStudyInstanceUID || hpInfo.activeStudyUID}:activeDisplaySet:0`,
null
);
return true;
@@ -562,6 +624,8 @@ const commandsModule = ({
};
const definitions = {
multimonitor: actions.multimonitor,
loadStudy: actions.loadStudy,
showContextMenu: actions.showContextMenu,
closeContextMenu: actions.closeContextMenu,
clearMeasurements: actions.clearMeasurements,