2025-02-28 21:17:55 +01:00
|
|
|
import { Icons, FooterAction } from '@ohif/ui-next';
|
2024-04-02 15:35:30 +02:00
|
|
|
import React, { ReactElement, useState, useCallback } from 'react';
|
2025-02-28 21:17:55 +01:00
|
|
|
import { PresetDialog } from '@ohif/ui-next';
|
2024-04-02 15:35:30 +02:00
|
|
|
import { ViewportPreset, VolumeRenderingPresetsContentProps } from '../../types/ViewportPresets';
|
2025-06-07 19:55:33 +02:00
|
|
|
import { useSystem } from '@ohif/core';
|
2025-12-12 16:46:56 +01:00
|
|
|
import { useTranslation } from 'react-i18next';
|
2024-04-02 15:35:30 +02:00
|
|
|
|
2025-02-28 21:17:55 +01:00
|
|
|
interface Props extends VolumeRenderingPresetsContentProps {
|
|
|
|
|
hide: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-07 19:55:33 +02:00
|
|
|
export function VolumeRenderingPresetsContent({ presets, viewportId, hide }: Props): ReactElement {
|
|
|
|
|
const { commandsManager } = useSystem();
|
2024-04-02 15:35:30 +02:00
|
|
|
const [searchValue, setSearchValue] = useState('');
|
|
|
|
|
const [selectedPreset, setSelectedPreset] = useState<ViewportPreset | null>(null);
|
2025-12-12 16:46:56 +01:00
|
|
|
const { t } = useTranslation('WindowLevelActionMenu');
|
2024-04-02 15:35:30 +02:00
|
|
|
|
2025-02-28 21:17:55 +01:00
|
|
|
const handleSearchChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
|
|
|
|
setSearchValue(event.target.value);
|
|
|
|
|
}, []);
|
2024-04-02 15:35:30 +02:00
|
|
|
|
|
|
|
|
const handleApply = useCallback(
|
|
|
|
|
props => {
|
|
|
|
|
commandsManager.runCommand('setViewportPreset', {
|
|
|
|
|
...props,
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
[commandsManager]
|
|
|
|
|
);
|
|
|
|
|
|
2025-02-28 21:17:55 +01:00
|
|
|
const filteredPresets = searchValue
|
|
|
|
|
? presets.filter(preset => preset.name.toLowerCase().includes(searchValue.toLowerCase()))
|
|
|
|
|
: presets;
|
|
|
|
|
|
2024-04-02 15:35:30 +02:00
|
|
|
const formatLabel = (label: string, maxChars: number) => {
|
|
|
|
|
return label.length > maxChars ? `${label.slice(0, maxChars)}...` : label;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
2025-02-28 21:17:55 +01:00
|
|
|
<PresetDialog className="h-[500px]">
|
|
|
|
|
<PresetDialog.PresetBody>
|
|
|
|
|
<PresetDialog.PresetFilter>
|
|
|
|
|
<PresetDialog.PresetSearch
|
|
|
|
|
value={searchValue}
|
|
|
|
|
onChange={handleSearchChange}
|
2025-12-12 16:46:56 +01:00
|
|
|
placeholder={t('Search all', 'Search all')}
|
2025-02-28 21:17:55 +01:00
|
|
|
/>
|
|
|
|
|
</PresetDialog.PresetFilter>
|
|
|
|
|
<PresetDialog.PresetGrid>
|
|
|
|
|
{filteredPresets.map((preset, index) => (
|
|
|
|
|
<div
|
|
|
|
|
key={index}
|
|
|
|
|
className="flex cursor-pointer flex-col items-start"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setSelectedPreset(preset);
|
|
|
|
|
handleApply({ preset: preset.name, viewportId });
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Icons.ByName
|
|
|
|
|
name={preset.name}
|
|
|
|
|
className={
|
|
|
|
|
selectedPreset?.name === preset.name
|
|
|
|
|
? 'border-highlight h-[75px] w-[95px] max-w-none rounded border-2'
|
2026-02-12 19:12:36 +01:00
|
|
|
: 'hover:border-highlight h-[75px] w-[95px] max-w-none rounded border-2 border-background'
|
2025-02-28 21:17:55 +01:00
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
<label className="text-muted-foreground mt-1 text-left text-xs">
|
|
|
|
|
{formatLabel(preset.name, 11)}
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</PresetDialog.PresetGrid>
|
|
|
|
|
</PresetDialog.PresetBody>
|
|
|
|
|
<FooterAction className="mt-4 flex-shrink-0">
|
|
|
|
|
<FooterAction.Right>
|
2025-12-12 16:46:56 +01:00
|
|
|
<FooterAction.Secondary onClick={hide}>{t('Common:Cancel')}</FooterAction.Secondary>
|
2025-02-28 21:17:55 +01:00
|
|
|
</FooterAction.Right>
|
|
|
|
|
</FooterAction>
|
|
|
|
|
</PresetDialog>
|
2024-04-02 15:35:30 +02:00
|
|
|
);
|
|
|
|
|
}
|