From 2c9b0345c4acc67770932d5147620362fce3a09d Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 15 Sep 2025 12:42:55 +0100 Subject: [PATCH] Implement code changes to enhance functionality and improve performance --- dicom-viewer/src/App.tsx | 1369 +++++++++++++++++++------------------- 1 file changed, 671 insertions(+), 698 deletions(-) diff --git a/dicom-viewer/src/App.tsx b/dicom-viewer/src/App.tsx index 7cb38a7..210582f 100644 --- a/dicom-viewer/src/App.tsx +++ b/dicom-viewer/src/App.tsx @@ -2790,50 +2790,46 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer > {/* Custom Stack Dropdown */}
+ {/* Stack selector trigger button */} + + {/* Dropdown */} {openDropdownIdx === i && (
{ - if (el) el.focus(); - }} + ref={el => { if (el) el.focus(); }} tabIndex={0} style={{ position: "absolute", @@ -2852,31 +2848,13 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer }} role="listbox" onMouseDown={e => e.stopPropagation()} - onWheel={e => { - // Trap scroll inside the dropdown - const target = e.currentTarget as HTMLDivElement; - const { scrollTop, scrollHeight, clientHeight } = target; - const atTop = scrollTop === 0; - const atBottom = scrollTop + clientHeight >= scrollHeight - 1; - if ( - (e.deltaY < 0 && atTop) || - (e.deltaY > 0 && atBottom) - ) { - // Let the event bubble to parent (viewport) - return; - } - // Otherwise, prevent scrolling the viewport - e.stopPropagation(); - e.preventDefault(); - // Manually scroll the menu - target.scrollTop += e.deltaY; - }} onBlur={e => { - const related = e.relatedTarget as Node; - const parent = e.currentTarget.parentElement; - if (!parent?.contains(related)) { - setTimeout(() => setOpenDropdownIdx(null), 100); - } + // close when focus leaves + setTimeout(() => { + if (!(e.currentTarget as HTMLElement).contains(document.activeElement)) { + setOpenDropdownIdx(null); + } + }, 0); }} > {availableStacks.map((stackObj, idx) => { @@ -2911,14 +2889,9 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer console.warn(`Attempted to select invalid stack at index ${idx}`, stackObj); return; } - // Select the stack for this viewport - // Use the shared handler so selection behavior is consistent - handleLoadStack(i, idx).catch((err) => { - console.error("Failed to load stack:", err); - }); - - // Close the dropdown - setOpenDropdownIdx(null); + // Use existing handler to load the stack into this viewport + handleLoadStack(i, idx).catch(err => console.error("Failed to load stack:", err)); + setOpenDropdownIdx(null); }} >
{label}
@@ -2928,718 +2901,718 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer })}
)} +
- - ) - } + ) + } ); -} + } -return ( - // App root -
- {/* Loading overlay */} - {loadingState && ( -
- {loadingState === "annotations" - ? "Loading Annotations..." - : "Loading Viewer State..."} -
- )} - -
- {/* Side menu toggle button */} - - - {/* Side menu drawer */} - {sideMenuOpen && ( + return ( + // App root +
+ {/* Loading overlay */} + {loadingState && (
-
-
- Menu - -
- - -
- setOrderBySliceLocation(e.target.checked)} - style={{ accentColor: "#666" }} - /> - -
- - - - - - - {/* Add more menu items here if needed */} - -
+ {loadingState === "annotations" + ? "Loading Annotations..." + : "Loading Viewer State..."}
)} -
- {/* Viewport grid menu at top center */} + +
+ {/* Side menu toggle button */} + + + {/* Side menu drawer */} + {sideMenuOpen && ( +
+
+
+ Menu + +
+ + +
+ setOrderBySliceLocation(e.target.checked)} + style={{ accentColor: "#666" }} + /> + +
+ + + + + + + {/* Add more menu items here if needed */} + +
+
+ )} +
+ {/* Viewport grid menu at top center */} -
- {/* Transparent hit area to catch hover/focus */}
setGridBtnActive(true)} - onFocus={() => setGridBtnActive(true)} - tabIndex={-1} - /> - {/* --- Fullscreen button next to grid button --- */} - - - {viewportMenuOpen && ( + {/* Transparent hit area to catch hover/focus */}
setGridBtnActive(true)} + onFocus={() => setGridBtnActive(true)} + tabIndex={-1} + /> + {/* --- Fullscreen button next to grid button --- */} + - ))} -
- )} -
- - - {/* Viewport grid (inside main div) */} -
- {viewports} - - -
- - - {/* Settings button at top right */} - - - {/* Settings Modal (viewport-local, not fixed to page) */} - { - settingsOpen && ( -
+ + {viewportMenuOpen && (
e.stopPropagation()} > -
- Settings -
- {/* Settings content: Tool dropdowns */} -
-
Mouse Button Tool Bindings
- {MOUSE_BUTTONS.map((btn) => ( -
- - setMouseToolBindings(prev => ({ ...prev, [btn.value]: e.target.value }))} + style={{ + background: "#333", + color: "#fff", + border: "1px solid #444", + borderRadius: "4px", + padding: "4px 8px", + fontSize: "14px", + }} + > + {TOOL_OPTIONS.map(opt => ( + + ))} + +
+ ))} + + {/* Expandable advanced mouse bindings */} +
+ + {showAdvancedMouseBindings && ( +
+ {ALL_MOUSE_BINDINGS.slice(3).map((btn) => ( +
+ + +
+ ))} +
+ )}
- ))} - - {/* Expandable advanced mouse bindings */} -
- - {showAdvancedMouseBindings && ( -
- {ALL_MOUSE_BINDINGS.slice(3).map((btn) => ( -
- - -
- ))} + {/* Ctrl + Mouse Button Tool Bindings */} +
Ctrl + Mouse Button Tool Bindings
+ {MOUSE_BUTTONS.map((btn) => ( +
+ +
- )} -
- {/* Ctrl + Mouse Button Tool Bindings */} -
Ctrl + Mouse Button Tool Bindings
- {MOUSE_BUTTONS.map((btn) => ( -
- - + {showAdvancedCtrlMouseBindings ? "Hide" : "Show"} Advanced Ctrl + Mouse Bindings + + {showAdvancedCtrlMouseBindings && ( +
+ {ALL_MOUSE_BINDINGS.slice(3).map((btn) => ( +
+ + +
+ ))} +
+ )}
- ))} - - {/* Separate button for advanced Ctrl+Mouse bindings */} -
- - {showAdvancedCtrlMouseBindings && ( -
- {ALL_MOUSE_BINDINGS.slice(3).map((btn) => ( -
- - -
- ))} -
- )}
+
-
-
- ) - } - { - metaModalOpen && ( -
setMetaModalOpen(false)} - > + ) + } + { + metaModalOpen && (
e.stopPropagation()} + onClick={() => setMetaModalOpen(false)} > -
- DICOM Metadata -
- {metaModalContent} - +
+ DICOM Metadata +
+ {metaModalContent} + +
-
- ) - } - {/* ...rest of your UI... */} + ) + } + {/* ...rest of your UI... */} -
-) +
+ ) }