Skip to content

Commit

Permalink
feat(segmentation): Enhance dropdown menu functionality in Segmentati…
Browse files Browse the repository at this point in the history
…onTable (#4553)
  • Loading branch information
sedghi authored Nov 28, 2024
1 parent 144ec79 commit 397fd85
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 167 deletions.
81 changes: 78 additions & 3 deletions extensions/cornerstone/src/panels/PanelSegmentation.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import React from 'react';
import { SegmentationTable } from '@ohif/ui-next';
import {
DropdownMenuLabel,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuPortal,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
Icons,
SegmentationTable,
DropdownMenuSubTrigger,
} from '@ohif/ui-next';
import { useActiveViewportSegmentationRepresentations } from '../hooks/useActiveViewportSegmentationRepresentations';
import { metaData } from '@cornerstonejs/core';

Expand Down Expand Up @@ -147,6 +158,66 @@ export default function PanelSegmentation({
}
);

const CustomDropdownMenuContent = customizationService.getCustomComponent(
'PanelSegmentation.CustomDropdownMenuContent',
({
activeSegmentation,
onSegmentationAdd,
onSegmentationRemoveFromViewport,
onSegmentationEdit,
onSegmentationDelete,
allowExport,
storeSegmentation,
onSegmentationDownload,
onSegmentationDownloadRTSS,
t,
}) => (
<DropdownMenuContent align="start">
<DropdownMenuItem onClick={() => onSegmentationAdd(activeSegmentation.id)}>
<Icons.Add className="text-foreground" />
<span className="pl-2">{t('Create New Segmentation')}</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>{t('Manage Current Segmentation')}</DropdownMenuLabel>
<DropdownMenuItem onClick={() => onSegmentationRemoveFromViewport(activeSegmentation.id)}>
<Icons.Series className="text-foreground" />
<span className="pl-2">{t('Remove from Viewport')}</span>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onSegmentationEdit(activeSegmentation.id)}>
<Icons.Rename className="text-foreground" />
<span className="pl-2">{t('Rename')}</span>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger
disabled={!allowExport}
className="pl-1"
>
<Icons.Export className="text-foreground" />
<span className="pl-2">{t('Export & Download')}</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem onClick={() => storeSegmentation(activeSegmentation.id)}>
{t('Export DICOM SEG')}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onSegmentationDownload(activeSegmentation.id)}>
{t('Download DICOM SEG')}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onSegmentationDownloadRTSS(activeSegmentation.id)}>
{t('Download DICOM RTSTRUCT')}
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => onSegmentationDelete(activeSegmentation.id)}>
<Icons.Delete className="text-red-600" />
<span className="pl-2 text-red-600">{t('Delete')}</span>
</DropdownMenuItem>
</DropdownMenuContent>
)
);

const exportOptions = segmentationsWithRepresentations.map(({ segmentation }) => {
const { representationData, segmentationId } = segmentation;
const { Labelmap } = representationData;
Expand Down Expand Up @@ -219,13 +290,17 @@ export default function PanelSegmentation({

{SegmentationTableMode === 'collapsed' ? (
<SegmentationTable.Collapsed>
<SegmentationTable.SelectorHeader />
<SegmentationTable.SelectorHeader>
<CustomDropdownMenuContent />
</SegmentationTable.SelectorHeader>
<SegmentationTable.AddSegmentRow />
<SegmentationTable.Segments />
</SegmentationTable.Collapsed>
) : (
<SegmentationTable.Expanded>
<SegmentationTable.Header />
<SegmentationTable.Header>
<CustomDropdownMenuContent />
</SegmentationTable.Header>
{/* <SegmentationTable.AddSegmentRow /> */}
<SegmentationTable.Segments />
</SegmentationTable.Expanded>
Expand Down
8 changes: 8 additions & 0 deletions extensions/default/src/commandsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ const commandsModule = ({
* @param options.stageId - the stageId to apply
* @param options.stageIndex - the index of the stage to go to.
* @param options.reset - flag to indicate if the HP should be reset to its original and not restored to a previous state
*
* commandsManager.run('setHangingProtocol', {
* activeStudyUID: '1.2.3',
* protocolId: 'myProtocol',
* stageId: 'myStage',
* stageIndex: 0,
* reset: false,
* });
*/
setHangingProtocol: ({
activeStudyUID = '',
Expand Down
38 changes: 38 additions & 0 deletions modes/longitudinal/src/customizations.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import React from 'react';
import {
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuPortal,
DropdownMenuLabel,
Icons,
} from '@ohif/ui-next';

export const performCustomizations = customizationService => {
// Set the custom SegmentationTable
customizationService.addModeCustomizations([
Expand All @@ -22,5 +35,30 @@ export const performCustomizations = customizationService => {
// { value: 'Toe', label: 'Toe' },
// ],
// },
/**
* Custom Dropdown Menu Item
*/
// {
// id: 'PanelSegmentation.CustomDropdownMenuContent',
// content: ({
// activeSegmentation,
// onSegmentationAdd,
// onSegmentationRemoveFromViewport,
// onSegmentationEdit,
// onSegmentationDelete,
// allowExport,
// storeSegmentation,
// onSegmentationDownload,
// onSegmentationDownloadRTSS,
// t,
// }) => (
// <DropdownMenuContent align="start">
// <DropdownMenuItem onClick={() => onSegmentationDelete(activeSegmentation.id)}>
// <Icons.Delete className="text-red-600" />
// <span className="pl-2 text-red-600">{t('My Custom Dropdown Menu Item')}</span>
// </DropdownMenuItem>
// </DropdownMenuContent>
// ),
// },
]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ export const SegmentationExpanded: React.FC<{ children?: React.ReactNode }> = ({
representation: segmentationInfo.representation,
})
) : (
<SegmentationHeader
segmentation={segmentationInfo.segmentation}
representation={segmentationInfo.representation}
/>
<SegmentationHeader segmentation={segmentationInfo.segmentation} />
)}
</PanelSection.Header>
<PanelSection.Content>
Expand All @@ -38,7 +35,6 @@ export const SegmentationExpanded: React.FC<{ children?: React.ReactNode }> = ({
React.isValidElement(child)
? React.cloneElement(child, {
segmentation: segmentationInfo.segmentation,
representation: segmentationInfo.representation,
})
: child
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,31 @@
import React from 'react';
import { Button } from '../Button';
import { Icons } from '../Icons/Icons';
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
DropdownMenuPortal,
} from '../DropdownMenu';
import { DropdownMenu, DropdownMenuTrigger } from '../DropdownMenu';
import { Tooltip, TooltipTrigger, TooltipContent } from '../Tooltip/Tooltip';
import { useSegmentationTableContext } from './SegmentationTableContext';
import { useTranslation } from 'react-i18next';

export const SegmentationHeader: React.FC<{
children?: React.ReactNode;
segmentation?: any;
}> = ({ segmentation }) => {
}> = ({ children, segmentation }) => {
const { t } = useTranslation('SegmentationTable');
const {
onSegmentAdd,
onSegmentationRemoveFromViewport,
onSegmentationEdit,
onSegmentationDelete,
onSegmentationDownload,
onSegmentationDownloadRTSS,
storeSegmentation,
} = useSegmentationTableContext('SegmentationHeader');
const { ...contextProps } = useSegmentationTableContext('SegmentationHeader');

if (!segmentation) {
return null;
}

const childrenWithProps = React.Children.map(children, child =>
React.isValidElement(child)
? React.cloneElement(child, {
t,
...contextProps,
})
: child
);

return (
<div className="text-foreground flex h-8 w-full items-center justify-between">
<div className="flex items-center space-x-1">
Expand All @@ -48,79 +40,7 @@ export const SegmentationHeader: React.FC<{
<Icons.More />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem
onClick={e => {
e.stopPropagation();
onSegmentAdd(segmentation.segmentationId);
}}
>
<Icons.Add className="text-foreground" />
<span className="pl-2">{t('Add Segment')}</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={e => {
e.stopPropagation();
onSegmentationRemoveFromViewport(segmentation.segmentationId);
}}
>
<Icons.Series className="text-foreground" />
<span className="pl-2">{t('Remove from Viewport')}</span>
</DropdownMenuItem>
<DropdownMenuItem
onClick={e => {
e.stopPropagation();
onSegmentationEdit(segmentation.segmentationId);
}}
>
<Icons.Rename className="text-foreground" />
<span className="pl-2">{t('Rename')}</span>
</DropdownMenuItem>
<DropdownMenuItem onClick={e => e.stopPropagation()}>
<Icons.Hide className="text-foreground" />
<span className="pl-2">{t('Hide or Show all Segments')}</span>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger onClick={e => e.stopPropagation()}>
<Icons.Export className="text-foreground" />
<span className="pl-2">{t('Export & Download')}</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem
onClick={e => {
e.stopPropagation();
storeSegmentation(segmentation.segmentationId);
}}
>
{t('Export DICOM SEG')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={e => {
e.stopPropagation();
onSegmentationDownload(segmentation.segmentationId);
}}
>
{t('Download DICOM SEG')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={e => {
e.stopPropagation();
onSegmentationDownloadRTSS(segmentation.segmentationId);
}}
>
{t('Download DICOM RTSTRUCT')}
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => onSegmentationDelete(segmentation.segmentationId)}>
<Icons.Delete className="text-red-600" />
<span className="pl-2 text-red-600">{t('Delete')}</span>
</DropdownMenuItem>
</DropdownMenuContent>
{childrenWithProps}
</DropdownMenu>
<div className="pl-1.5">{segmentation.label}</div>
</div>
Expand Down
Loading

0 comments on commit 397fd85

Please sign in to comment.