feat(app): Decouple colorbar UI from service and enable action menu programatic control (#5018)
This commit is contained in:
1 parent
f14d9ebdd7
commit
1445e12124
41 files changed
+1872
-659
No files matched your search
@@ -1,15 +1,14 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
|
||||
import { Switch } from '@ohif/ui-next';
|
||||
import { StackViewport } from '@cornerstonejs/core';
|
||||
import { ColorbarProps } from '../../types/Colorbar';
|
||||
import { ColorbarProps, ColorbarOptions } from '../../types/Colorbar';
|
||||
import { utilities } from '@cornerstonejs/core';
|
||||
import { useSystem } from '@ohif/core';
|
||||
|
||||
export function setViewportColorbar(
|
||||
viewportId,
|
||||
commandsManager,
|
||||
viewportId: string,
|
||||
commandsManager: any,
|
||||
servicesManager: AppTypes.ServicesManager,
|
||||
colorbarOptions
|
||||
colorbarOptions: Partial<ColorbarOptions>
|
||||
) {
|
||||
const { cornerstoneViewportService, viewportGridService } = servicesManager.services;
|
||||
const displaySetInstanceUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
|
||||
+9
-16
@@ -1,7 +1,6 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import classNames from 'classnames';
|
||||
import { AllInOneMenu } from '@ohif/ui-next';
|
||||
import { AllInOneMenu, cn } from '@ohif/ui-next';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import { Colormap } from './Colormap';
|
||||
import { Colorbar } from './Colorbar';
|
||||
@@ -25,6 +24,7 @@ export type WindowLevelActionMenuProps = {
|
||||
displaySets: Array<any>;
|
||||
volumeRenderingPresets: Array<ViewportPreset>;
|
||||
volumeRenderingQualityRange: VolumeRenderingQualityRange;
|
||||
location: string;
|
||||
};
|
||||
|
||||
export function WindowLevelActionMenu({
|
||||
@@ -111,20 +111,13 @@ export function WindowLevelActionMenu({
|
||||
]);
|
||||
|
||||
return (
|
||||
<AllInOneMenu.IconMenu
|
||||
icon="viewport-window-level"
|
||||
verticalDirection={verticalDirection}
|
||||
horizontalDirection={horizontalDirection}
|
||||
iconClassName={classNames(
|
||||
activeViewportId === viewportId ? 'visible' : 'invisible group-hover/pane:visible',
|
||||
'flex shrink-0 cursor-pointer rounded active:text-foreground text-highlight',
|
||||
isLight ? ' hover:bg-primary/30' : 'hover:bg-primary/30'
|
||||
)}
|
||||
menuStyle={{ maxHeight: vpHeight - 32, minWidth: 218 }}
|
||||
onVisibilityChange={() => {
|
||||
setVpHeight(element.clientHeight);
|
||||
}}
|
||||
<AllInOneMenu.Menu
|
||||
menuKey={menuKey}
|
||||
key={menuKey}
|
||||
// the visibility is handled by the parent component
|
||||
isVisible={true}
|
||||
horizontalDirection={horizontalDirection}
|
||||
verticalDirection={verticalDirection}
|
||||
>
|
||||
<AllInOneMenu.ItemPanel>
|
||||
{!is3DVolume && (
|
||||
@@ -180,6 +173,6 @@ export function WindowLevelActionMenu({
|
||||
</AllInOneMenu.SubMenu>
|
||||
)}
|
||||
</AllInOneMenu.ItemPanel>
|
||||
</AllInOneMenu.IconMenu>
|
||||
</AllInOneMenu.Menu>
|
||||
);
|
||||
}
|
||||
+138
@@ -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 };
|
||||
};
|
||||
+11
-51
@@ -1,53 +1,13 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import { WindowLevelActionMenuProps } from './WindowLevelActionMenu';
|
||||
import { useSystem } from '@ohif/core';
|
||||
import { WindowLevelActionMenu as WindowLevelActionMenuComponent } from './WindowLevelActionMenu';
|
||||
import React from 'react';
|
||||
import { WindowLevelActionMenuWrapper } from './WindowLevelActionMenuWrapper';
|
||||
|
||||
function WindowLevelActionMenu({
|
||||
viewportId,
|
||||
element,
|
||||
displaySets,
|
||||
verticalDirection,
|
||||
horizontalDirection,
|
||||
}: withAppTypes<{
|
||||
viewportId: string;
|
||||
element: HTMLElement;
|
||||
displaySets: AppTypes.DisplaySet[];
|
||||
}>): ReactNode {
|
||||
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 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 (
|
||||
<WindowLevelActionMenuComponent
|
||||
viewportId={viewportId}
|
||||
element={element}
|
||||
presets={displaySetPresets}
|
||||
verticalDirection={verticalDirection}
|
||||
horizontalDirection={horizontalDirection}
|
||||
colorbarProperties={colorbarProperties}
|
||||
displaySets={displaySets}
|
||||
volumeRenderingPresets={volumeRenderingPresets}
|
||||
volumeRenderingQualityRange={volumeRenderingQualityRange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function getWindowLevelActionMenu(props: WindowLevelActionMenuProps) {
|
||||
return <WindowLevelActionMenu {...props} />;
|
||||
export function getWindowLevelActionMenu(
|
||||
props: withAppTypes<{
|
||||
viewportId: string;
|
||||
element: HTMLElement;
|
||||
location: string;
|
||||
displaySets: Array<any>;
|
||||
}>
|
||||
) {
|
||||
return <WindowLevelActionMenuWrapper {...props} />;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export * from './Colorbar';
|
||||
export * from './Colormap';
|
||||
export * from './WindowLevel';
|
||||
export * from './WindowLevelActionMenu';
|
||||
export * from './WindowLevelActionMenuWrapper';
|
||||
export * from './VolumeRenderingOptions';
|
||||
export * from './VolumeRenderingPresets';
|
||||
export * from './VolumeRenderingQuality';
|
||||
export * from './VolumeLighting';
|
||||
export * from './VolumeShade';
|
||||
export * from './VolumeShift';
|
||||
Reference in new issue
Block a user