Skip to content

Commit 51471bd

Browse files
authored
Merge pull request #833 from Kitware/fix-probe
Fix polygon interaction bugs
2 parents 4351186 + 8fd332c commit 51471bd

File tree

8 files changed

+342
-23
lines changed

8 files changed

+342
-23
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: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ import { Tools } from '@/src/store/tools/types';
9292
import { getLPSAxisFromDir } from '@/src/utils/lps';
9393
import { LPSAxisDir } from '@/src/types/lps';
9494
import { usePolygonStore } from '@/src/store/tools/polygons';
95+
import { useRectangleStore } from '@/src/store/tools/rectangles';
9596
import {
9697
useContextMenu,
9798
useCurrentTools,
@@ -235,19 +236,41 @@ export default defineComponent({
235236
236237
// --- //
237238
238-
const { contextMenu, openContextMenu } = useContextMenu();
239+
const { contextMenu, openContextMenu: baseOpenContextMenu } =
240+
useContextMenu();
241+
242+
const rectangleStore = useRectangleStore();
243+
const shouldSuppressInteraction = (id: ToolID) => {
244+
const rectanglePlacing = rectangleStore.tools.some(
245+
(tool) => tool.placing && tool.firstPoint && tool.secondPoint
246+
);
247+
if (rectanglePlacing) return true;
248+
if (placingTool.id.value && id !== placingTool.id.value) {
249+
const placingToolData = activeToolStore.toolByID[placingTool.id.value];
250+
if (placingToolData?.points?.length > 0) return true;
251+
}
252+
return false;
253+
};
254+
255+
const openContextMenu = (id: ToolID, event: any) => {
256+
if (!shouldSuppressInteraction(id)) baseOpenContextMenu(id, event);
257+
};
239258
240259
const currentTools = useCurrentTools(
241260
activeToolStore,
242261
viewAxis,
243-
// only show this view's placing tool
244-
computed(() => {
245-
if (placingTool.id.value) return [placingTool.id.value];
246-
return [];
247-
})
262+
computed(() => (placingTool.id.value ? [placingTool.id.value] : []))
248263
);
249264
250-
const { onHover, overlayInfo } = useHover(currentTools, slice);
265+
const { onHover: baseOnHover, overlayInfo } = useHover(currentTools, slice);
266+
267+
const onHover = (id: ToolID, event: any) => {
268+
if (shouldSuppressInteraction(id)) {
269+
baseOnHover(id, { ...event, hovering: false });
270+
return;
271+
}
272+
baseOnHover(id, event);
273+
};
251274
252275
const mergePossible = computed(
253276
() => activeToolStore.mergeableTools.length >= 1

src/components/tools/polygon/PolygonWidget2D.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,17 @@ export default defineComponent({
101101
onVTKEvent(widget, 'onDraggingEvent', (eventData: any) => {
102102
dragging.value = eventData.dragging;
103103
});
104+
const anotherToolPlacing = computed(() =>
105+
toolStore.tools.some(
106+
(t) => t.placing && t.id !== toolId.value && t.points.length > 0
107+
)
108+
);
104109
const showHandles = computed(() => {
105-
return lastHoverEventData.value?.hovering && !dragging.value;
110+
return (
111+
lastHoverEventData.value?.hovering &&
112+
!dragging.value &&
113+
!anotherToolPlacing.value
114+
);
106115
});
107116
watchEffect(() => {
108117
if (!lastHoverEventData.value) return;

src/components/tools/rectangle/RectangleTool.vue

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { Tools } from '@/src/store/tools/types';
2828
import { getLPSAxisFromDir } from '@/src/utils/lps';
2929
import { LPSAxisDir } from '@/src/types/lps';
3030
import { useRectangleStore } from '@/src/store/tools/rectangles';
31+
import { usePolygonStore } from '@/src/store/tools/polygons';
3132
import {
3233
useCurrentTools,
3334
useContextMenu,
@@ -39,6 +40,7 @@ import AnnotationInfo from '@/src/components/tools/AnnotationInfo.vue';
3940
import { useFrameOfReference } from '@/src/composables/useFrameOfReference';
4041
import { Maybe } from '@/src/types';
4142
import { useSliceInfo } from '@/src/composables/useSliceInfo';
43+
import { ToolID } from '@/src/types/annotation-tool';
4244
import { watchImmediate } from '@vueuse/core';
4345
import RectangleWidget2D from './RectangleWidget2D.vue';
4446
@@ -121,7 +123,8 @@ export default defineComponent({
121123
122124
// --- //
123125
124-
const { contextMenu, openContextMenu } = useContextMenu();
126+
const { contextMenu, openContextMenu: baseOpenContextMenu } =
127+
useContextMenu();
125128
126129
const currentTools = useCurrentTools(
127130
activeToolStore,
@@ -133,7 +136,31 @@ export default defineComponent({
133136
})
134137
);
135138
136-
const { onHover, overlayInfo } = useHover(currentTools, slice);
139+
const { onHover: baseOnHover, overlayInfo } = useHover(currentTools, slice);
140+
141+
// Check if any polygon is actively being placed (has points)
142+
const polygonStore = usePolygonStore();
143+
const isAnyPolygonPlacing = () => {
144+
return polygonStore.tools.some(
145+
(tool) => tool.placing && tool.points.length > 0
146+
);
147+
};
148+
149+
// Suppress hover/context menu when a polygon is actively being placed
150+
const onHover = (id: ToolID, event: any) => {
151+
if (isAnyPolygonPlacing()) {
152+
baseOnHover(id, { ...event, hovering: false });
153+
return;
154+
}
155+
baseOnHover(id, event);
156+
};
157+
158+
const openContextMenu = (id: ToolID, event: any) => {
159+
if (isAnyPolygonPlacing()) {
160+
return;
161+
}
162+
baseOpenContextMenu(id, event);
163+
};
137164
138165
return {
139166
tools: currentTools,

src/vtk/PolygonWidget/behavior.ts

Lines changed: 29 additions & 9 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({
@@ -192,8 +197,6 @@ export default function widgetBehavior(publicAPI: any, model: any) {
192197
if (model.widgetState.getPlacing() && manipulator) {
193198
// Dropping first point?
194199
if (model.widgetState.getHandles().length === 0) {
195-
// update variables used by updateActiveStateHandle
196-
model.activeState = model.widgetState.getMoveHandle();
197200
model._widgetManager.grabFocus(publicAPI);
198201
}
199202
updateActiveStateHandle(event);
@@ -248,8 +251,12 @@ export default function widgetBehavior(publicAPI: any, model: any) {
248251
// So we can rely on getSelections() to be up to date now
249252
overUnselectedHandle = false;
250253

251-
if (model.hasFocus) {
252-
model._widgetManager.disablePicking();
254+
if (anotherWidgetHasFocus()) {
255+
publicAPI.invokeHoverEvent({
256+
...event,
257+
hovering: false,
258+
});
259+
return macro.VOID;
253260
}
254261

255262
publicAPI.invokeHoverEvent({
@@ -336,7 +343,6 @@ export default function widgetBehavior(publicAPI: any, model: any) {
336343
(model.hasFocus && !model.activeState) ||
337344
(model.activeState && !model.activeState.getActive())
338345
) {
339-
// update if mouse hovered over handle/activeState for next onDown
340346
model._widgetManager.enablePicking();
341347
model._interactor.render();
342348
}
@@ -415,13 +421,18 @@ export default function widgetBehavior(publicAPI: any, model: any) {
415421
};
416422

417423
publicAPI.handleRightButtonPress = (eventData: any) => {
424+
// When placing, handle right-click regardless of what widget manager picked
425+
if (model.widgetState.getPlacing()) {
426+
removeLastHandle();
427+
return macro.EVENT_ABORT;
428+
}
429+
418430
if (!model.activeState) {
419431
return macro.VOID;
420432
}
421433

422-
if (model.widgetState.getPlacing()) {
423-
removeLastHandle();
424-
return macro.EVENT_ABORT;
434+
if (anotherWidgetHasFocus()) {
435+
return macro.VOID;
425436
}
426437

427438
const eventWithWidgetAction = {
@@ -451,7 +462,8 @@ export default function widgetBehavior(publicAPI: any, model: any) {
451462

452463
// Called after we are finished/placed.
453464
publicAPI.loseFocus = () => {
454-
if (model.hasFocus) {
465+
const hadFocus = model.hasFocus;
466+
if (hadFocus) {
455467
model._interactor.cancelAnimation(publicAPI);
456468
publicAPI.invokeEndInteractionEvent();
457469
}
@@ -461,6 +473,14 @@ export default function widgetBehavior(publicAPI: any, model: any) {
461473
model.widgetState.getMoveHandle().setOrigin(null);
462474
model.activeState = null;
463475
model.hasFocus = false;
476+
if (hadFocus) {
477+
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());
483+
}
464484
model._widgetManager.enablePicking();
465485
};
466486

src/vtk/RulerWidget/behavior.ts

Lines changed: 18 additions & 0 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,6 +189,14 @@ export default function widgetBehavior(publicAPI: any, model: any) {
184189
return macro.EVENT_ABORT;
185190
}
186191

192+
if (anotherWidgetHasFocus()) {
193+
publicAPI.invokeHoverEvent({
194+
...eventData,
195+
hovering: false,
196+
});
197+
return macro.VOID;
198+
}
199+
187200
publicAPI.invokeHoverEvent({
188201
...eventData,
189202
hovering: !!model.activeState || checkOverFill(),
@@ -220,6 +233,11 @@ export default function widgetBehavior(publicAPI: any, model: any) {
220233
) {
221234
return macro.VOID;
222235
}
236+
237+
if (anotherWidgetHasFocus()) {
238+
return macro.VOID;
239+
}
240+
223241
publicAPI.invokeRightClickEvent(eventData);
224242
return macro.EVENT_ABORT;
225243
};

0 commit comments

Comments
 (0)