Skip to content

Commit b6026d5

Browse files
committed
fix: polygon nested interaction issues
- Prevent hover handles on existing polygons while placing new one - Allow right-click to remove points when placing inside other annotations - Clear stale activeState on all widgets when placing polygon loses focus - Add hasFocus check to RulerWidget (used by RectangleWidget)
1 parent 9b598f1 commit b6026d5

File tree

5 files changed

+224
-352
lines changed

5 files changed

+224
-352
lines changed

src/components/tools/AnnotationInfo.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import { useElementSize } from '@vueuse/core';
44
import { AnnotationToolStore } from '@/src/store/tools/useAnnotationTool';
55
import { OverlayInfo } from '@/src/composables/annotationTool';
66
7-
// These seem to work ¯\_(ツ)_/¯
87
const TOOLTIP_PADDING_X = 30;
9-
const TOOLTIP_PADDING_Y = 10;
8+
const TOOLTIP_PADDING_Y = 16;
109
1110
const props = defineProps<{
1211
info: OverlayInfo;
@@ -78,6 +77,7 @@ const offset = computed(() => {
7877
background: rgba(255, 255, 255, 0.9) !important;
7978
padding-left: 0;
8079
padding-right: 0;
80+
pointer-events: none;
8181
}
8282
8383
.tooltip-text {

src/components/tools/polygon/PolygonTool.vue

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -239,55 +239,36 @@ export default defineComponent({
239239
const { contextMenu, openContextMenu: baseOpenContextMenu } =
240240
useContextMenu();
241241
242-
// Check if any rectangle is actively being placed
243242
const rectangleStore = useRectangleStore();
244-
const isAnyRectanglePlacing = () => {
245-
return rectangleStore.tools.some(
243+
const shouldSuppressInteraction = (id: ToolID) => {
244+
const rectanglePlacing = rectangleStore.tools.some(
246245
(tool) => tool.placing && tool.firstPoint && tool.secondPoint
247246
);
248-
};
249-
250-
// Suppress context menu for non-placing polygons when actively placing
251-
// or when a rectangle is actively being placed
252-
const openContextMenu = (id: ToolID, event: any) => {
253-
if (isAnyRectanglePlacing()) {
254-
return;
255-
}
247+
if (rectanglePlacing) return true;
256248
if (placingTool.id.value && id !== placingTool.id.value) {
257249
const placingToolData = activeToolStore.toolByID[placingTool.id.value];
258-
if (placingToolData?.points?.length > 0) {
259-
return;
260-
}
250+
if (placingToolData?.points?.length > 0) return true;
261251
}
262-
baseOpenContextMenu(id, event);
252+
return false;
253+
};
254+
255+
const openContextMenu = (id: ToolID, event: any) => {
256+
if (!shouldSuppressInteraction(id)) baseOpenContextMenu(id, event);
263257
};
264258
265259
const currentTools = useCurrentTools(
266260
activeToolStore,
267261
viewAxis,
268-
// only show this view's placing tool
269-
computed(() => {
270-
if (placingTool.id.value) return [placingTool.id.value];
271-
return [];
272-
})
262+
computed(() => (placingTool.id.value ? [placingTool.id.value] : []))
273263
);
274264
275265
const { onHover: baseOnHover, overlayInfo } = useHover(currentTools, slice);
276266
277-
// Suppress hover for non-placing polygons when actively placing (has points)
278-
// or when a rectangle is actively being placed
279267
const onHover = (id: ToolID, event: any) => {
280-
if (isAnyRectanglePlacing()) {
268+
if (shouldSuppressInteraction(id)) {
281269
baseOnHover(id, { ...event, hovering: false });
282270
return;
283271
}
284-
if (placingTool.id.value && id !== placingTool.id.value) {
285-
const placingToolData = activeToolStore.toolByID[placingTool.id.value];
286-
if (placingToolData?.points?.length > 0) {
287-
baseOnHover(id, { ...event, hovering: false });
288-
return;
289-
}
290-
}
291272
baseOnHover(id, event);
292273
};
293274

src/vtk/PolygonWidget/behavior.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ const DOUBLE_CLICK_SLIP_DISTANCE_MAX_SQUARED =
2323
export default function widgetBehavior(publicAPI: any, model: any) {
2424
model.classHierarchy.push('vtkPolygonWidgetBehavior');
2525

26+
const anotherWidgetHasFocus = () =>
27+
model._widgetManager
28+
.getWidgets()
29+
.some((w: any) => w !== publicAPI && w.hasFocus());
30+
2631
const setDragging = (isDragging: boolean) => {
2732
model._dragging = isDragging;
2833
publicAPI.invokeDraggingEvent({
@@ -246,12 +251,7 @@ export default function widgetBehavior(publicAPI: any, model: any) {
246251
// So we can rely on getSelections() to be up to date now
247252
overUnselectedHandle = false;
248253

249-
// Don't emit hover events if another widget has focus (e.g., is placing)
250-
const widgets = model._widgetManager.getWidgets();
251-
const anotherWidgetHasFocus = widgets.some(
252-
(w: any) => w !== publicAPI && w.hasFocus()
253-
);
254-
if (anotherWidgetHasFocus) {
254+
if (anotherWidgetHasFocus()) {
255255
publicAPI.invokeHoverEvent({
256256
...event,
257257
hovering: false,
@@ -431,12 +431,7 @@ export default function widgetBehavior(publicAPI: any, model: any) {
431431
return macro.VOID;
432432
}
433433

434-
// If another widget has focus (e.g., is placing), don't show context menu
435-
const widgets = model._widgetManager.getWidgets();
436-
const anotherWidgetHasFocus = widgets.some(
437-
(w: any) => w !== publicAPI && w.hasFocus()
438-
);
439-
if (anotherWidgetHasFocus) {
434+
if (anotherWidgetHasFocus()) {
440435
return macro.VOID;
441436
}
442437

@@ -480,6 +475,11 @@ export default function widgetBehavior(publicAPI: any, model: any) {
480475
model.hasFocus = false;
481476
if (hadFocus) {
482477
model._widgetManager.releaseFocus();
478+
// Deactivate all widgets so stale activeStates don't persist
479+
// (user may right-click again without moving mouse)
480+
model._widgetManager
481+
.getWidgets()
482+
.forEach((w: any) => w.deactivateAllHandles());
483483
}
484484
model._widgetManager.enablePicking();
485485
};

src/vtk/RulerWidget/behavior.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export function shouldIgnoreEvent(e: any) {
1616
export default function widgetBehavior(publicAPI: any, model: any) {
1717
model.classHierarchy.push('vtkRulerWidgetProp');
1818

19+
const anotherWidgetHasFocus = () =>
20+
model._widgetManager
21+
.getWidgets()
22+
.some((w: any) => w !== publicAPI && w.hasFocus());
23+
1924
model.interactionState = InteractionState.Select;
2025
let draggingState: any = null;
2126

@@ -184,9 +189,7 @@ export default function widgetBehavior(publicAPI: any, model: any) {
184189
return macro.EVENT_ABORT;
185190
}
186191

187-
// Don't emit hover events if another widget has focus (e.g., is placing)
188-
const activeWidget = model._widgetManager.getActiveWidget();
189-
if (activeWidget && activeWidget !== publicAPI) {
192+
if (anotherWidgetHasFocus()) {
190193
publicAPI.invokeHoverEvent({
191194
...eventData,
192195
hovering: false,
@@ -231,9 +234,7 @@ export default function widgetBehavior(publicAPI: any, model: any) {
231234
return macro.VOID;
232235
}
233236

234-
// If another widget has focus (e.g., is placing), don't show context menu
235-
const activeWidget = model._widgetManager.getActiveWidget();
236-
if (activeWidget && activeWidget !== publicAPI) {
237+
if (anotherWidgetHasFocus()) {
237238
return macro.VOID;
238239
}
239240

0 commit comments

Comments
 (0)