feat(app): Decouple colorbar UI from service and enable action menu programatic control (#5018)

This commit is contained in:
Alireza authored and GitHub committed 2025-05-08 12:51:30 -04:00
1 parent f14d9ebdd7
commit 1445e12124
41 files changed
+1872 -659

No files matched your search

@@ -0,0 +1,138 @@
import React, { ReactNode } from 'react';
import { useSystem } from '@ohif/core';
import {
Button,
cn,
Icons,
Popover,
PopoverContent,
PopoverTrigger,
useViewportGrid,
useViewportActionCorners,
AllInOneMenu,
} from '@ohif/ui-next';
import { WindowLevelActionMenu } from './WindowLevelActionMenu';
import { MENU_IDS } from '../menus/menu-ids';
export function WindowLevelActionMenuWrapper({
viewportId,
element,
location,
displaySets,
}: withAppTypes<{
viewportId: string;
element: HTMLElement;
location: string;
displaySets: Array<AppTypes.DisplaySet>;
}>): ReactNode {
const [viewportGrid] = useViewportGrid();
const [actionCornerState, viewportActionCornersAPI] = useViewportActionCorners();
const isActiveViewport = viewportId === viewportGrid.activeViewportId;
const { servicesManager } = useSystem();
const { customizationService } = servicesManager.services;
const presets = customizationService.getCustomization('cornerstone.windowLevelPresets');
const colorbarProperties = customizationService.getCustomization('cornerstone.colorbar');
const { volumeRenderingPresets, volumeRenderingQualityRange } =
customizationService.getCustomization('cornerstone.3dVolumeRendering');
const isMenuOpen =
actionCornerState.viewports[viewportId]?.[location]?.find(
item => item.id === MENU_IDS.WINDOW_LEVEL_MENU
)?.isOpen ?? false;
const handleOpenChange = (openState: boolean) => {
if (openState) {
viewportActionCornersAPI.openItem?.(viewportId, MENU_IDS.WINDOW_LEVEL_MENU);
} else {
viewportActionCornersAPI.closeItem?.(viewportId, MENU_IDS.WINDOW_LEVEL_MENU);
}
};
const { align, side, horizontalDirection, verticalDirection } = getMenuDirections(
location,
viewportActionCornersAPI
);
const displaySetPresets = displaySets
.filter(displaySet => presets[displaySet.Modality])
.map(displaySet => {
return { [displaySet.Modality]: presets[displaySet.Modality] };
});
const modalities = displaySets.map(displaySet => displaySet.supportsWindowLevel);
if (modalities.length === 0) {
return null;
}
return (
<Popover
open={isMenuOpen}
onOpenChange={handleOpenChange}
>
<PopoverTrigger
asChild
className="flex items-center justify-center"
>
<Button
variant="ghost"
size="icon"
className={cn(
isActiveViewport ? 'visible' : 'invisible group-hover/pane:visible',
'text-highlight'
)}
>
<Icons.ByName name="viewport-window-level" />
</Button>
</PopoverTrigger>
<PopoverContent
className="border-none bg-transparent p-0 shadow-none"
side={side}
align={align}
alignOffset={0}
sideOffset={5}
>
<WindowLevelActionMenu
viewportId={viewportId}
element={element}
presets={displaySetPresets}
horizontalDirection={horizontalDirection}
verticalDirection={verticalDirection}
colorbarProperties={colorbarProperties}
displaySets={displaySets}
volumeRenderingPresets={volumeRenderingPresets}
volumeRenderingQualityRange={volumeRenderingQualityRange}
/>
</PopoverContent>
</Popover>
);
}
const getMenuDirections = (location, viewportActionCornersAPI) => {
let align = 'center';
let side = 'bottom';
if (location !== undefined) {
const positioning = viewportActionCornersAPI.getAlignAndSide(location);
align = positioning.align;
side = positioning.side;
}
let horizontalDirection;
let verticalDirection;
if (side === 'bottom') {
verticalDirection = AllInOneMenu.VerticalDirection.TopToBottom;
} else {
verticalDirection = AllInOneMenu.VerticalDirection.BottomToTop;
}
if (align === 'start') {
horizontalDirection = AllInOneMenu.HorizontalDirection.LeftToRight;
} else {
horizontalDirection = AllInOneMenu.HorizontalDirection.RightToLeft;
}
return { align, side, horizontalDirection, verticalDirection };
};