diff --git a/dicom-viewer/src/App.tsx b/dicom-viewer/src/App.tsx index af772c3..b013fc2 100644 --- a/dicom-viewer/src/App.tsx +++ b/dicom-viewer/src/App.tsx @@ -397,6 +397,49 @@ function App({ container_id, imageStacks, autoCacheStack, ...props }: AppProps) const [metaModalOpen, setMetaModalOpen] = useState(false); const [metaModalContent, setMetaModalContent] = useState(null); +const handleSelectAnnotation = (viewportIdx: number, uid: string | null) => { + // Use the official selection API for Cornerstone3D Tools + if (window.cornerstone3dTools?.annotation?.selection?.setAnnotationSelected) { + window.cornerstone3dTools.annotation.selection.setAnnotationSelected(uid); + } + + // Optionally, update your own UI state + setSelectedAnnUIDs(prev => { + const next = [...prev]; + next[viewportIdx] = uid; + return next; + }); +}; + +const handleDeleteAnnotation = (viewportIdx: number, uid: string, currentAnnotations: any[]) => { + const allAnnotations = cornerstoneTools.annotation.state.getAllAnnotations() || []; + allAnnotations.forEach(ann => { + if (ann.annotationUID === uid) ann.isSelected = false; + }); + cornerstoneTools.annotation.state.removeAnnotation(uid); + if (cornerstoneTools.annotation.state.triggerAnnotationRender) { + cornerstoneTools.annotation.state.triggerAnnotationRender(); + } else if (renderingEngineRef.current) { + renderingEngineRef.current.render(); + } + // Auto-select another annotation if available + const remaining = currentAnnotations.filter(ann => ann.annotationUID !== uid); + setSelectedAnnUIDs(prev => { + const next = [...prev]; + const newSelected = remaining.length > 0 ? remaining[0].annotationUID : null; + next[viewportIdx] = newSelected; + allAnnotations.forEach(ann => { + ann.isSelected = ann.annotationUID === newSelected; + }); + if (cornerstoneTools.annotation.state.triggerAnnotationRender) { + cornerstoneTools.annotation.state.triggerAnnotationRender(); + } else if (renderingEngineRef.current) { + renderingEngineRef.current.render(); + } + return next; + }); +}; + // Add this function to gather and format metadata: const handleShowMetadata = () => { // Find the first visible viewport with images @@ -472,6 +515,28 @@ function App({ container_id, imageStacks, autoCacheStack, ...props }: AppProps) const [altPressed, setAltPressed] = useState(false); +useEffect(() => { + const mainToolGroup = ToolGroupManager.getToolGroup(MAIN_TOOL_GROUP_ID); + if (!mainToolGroup) return; + + // List all annotation tools you use + [ + 'ArrowAnnotate', + 'NoLabelArrowAnnotate', + 'Length', + 'RectangleROI', + 'EllipticalROI', + 'PlanarFreehandROI', + 'PlanarFreehandContourSegmentation', + // Add more if needed + ].forEach(toolName => { + mainToolGroup.setToolConfiguration(toolName, { + color: '#00e676', // normal color + selectedColor: '#ffeb3b', // yellow for selected + }); + }); +}, [MAIN_TOOL_GROUP_ID]); + useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.altKey) setAltPressed(true); @@ -1452,6 +1517,10 @@ function App({ container_id, imageStacks, autoCacheStack, ...props }: AppProps) const referenceStackObj = availableStacks[referenceStackIdx]; const referenceUID = referenceStackObj?.studyInstanceUID; + const [selectedAnnUIDs, setSelectedAnnUIDs] = useState<(string | null)[]>(() => + Array(MAX_VIEWPORTS).fill(null) + ); + const numVisible = viewportGrid.rows * viewportGrid.cols; const viewports = []; //for (let i = 0; i < MAX_VIEWPORTS; i++) { @@ -1642,101 +1711,185 @@ function App({ container_id, imageStacks, autoCacheStack, ...props }: AppProps) )} // Annotations buttons -{viewportModes[i] === "stack" && (() => { - // Get all annotations for this stack - const imageIds = viewportImageIds[i]; - const allAnnotations = cornerstoneTools.annotation.state.getAllAnnotations() || []; - const stackAnnotations = allAnnotations.filter( - ann => - ann.metadata && - ann.metadata.referencedImageId && - imageIds.includes(ann.metadata.referencedImageId) - ); - if (!stackAnnotations.length) return null; - return ( -
- - -
- ); -})()} + const currentIdx = viewport?.getCurrentImageIdIndex?.() ?? 0; + const currentImageId = imageIds[currentIdx]; + const currentAnnotations = stackAnnotations.filter( + ann => ann.metadata.referencedImageId === currentImageId + ); + + // Use per-viewport selection state + const selectedAnnUID = selectedAnnUIDs[i]; + + + + + + return ( +
+ {/* Prev/Next buttons ... */} + + + {/* List and select/delete individual annotations */} + {currentAnnotations.length > 0 && ( +
+ {currentAnnotations.map(ann => ( +
handleSelectAnnotation(i, ann.annotationUID)} +> + + {selectedAnnUID === ann.annotationUID ? "★ " : ""} + {ann.metadata.toolName || "Annotation"} + + +
+ ))} +
+ )} +
+ ); + })()} // ...existing code... {/* Overlay info (bottom left of viewport) */}