diff --git a/frontend/javascripts/libs/input.ts b/frontend/javascripts/libs/input.ts index 19e952ffe9..bc41b4b001 100644 --- a/frontend/javascripts/libs/input.ts +++ b/frontend/javascripts/libs/input.ts @@ -331,7 +331,7 @@ export class InputKeyboard { } // The mouse module. -// Events: over, out, leftClick, rightClick, leftDownMove +// Events: over, out, {left,right}Click, {left,right}DownMove, {left,right}DoubleClick class InputMouseButton { mouse: InputMouse; name: MouseButtonString; @@ -384,6 +384,24 @@ class InputMouseButton { } } + handleDoubleClick(event: MouseEvent, triggeredByTouch: boolean): void { + // event.which is 0 on touch devices as there are no mouse buttons, interpret that as the left mouse button + // Safari doesn't support evt.buttons, but only evt.which is non-standardized + const eventWhich = event.which !== 0 ? event.which : 1; + + if (eventWhich === this.which) { + if (this.moveDelta <= MOUSE_MOVE_DELTA_THRESHOLD) { + this.mouse.emitter.emit( + `${this.name}DoubleClick`, + this.mouse.lastPosition, + this.id, + event, + triggeredByTouch, + ); + } + } + } + handleMouseMove(event: MouseEvent, delta: Point2): void { if (this.down) { this.moveDelta += Math.abs(delta.x) + Math.abs(delta.y); @@ -437,6 +455,7 @@ export class InputMouse { document.addEventListener("mousemove", this.mouseMove); document.addEventListener("mouseup", this.mouseUp); document.addEventListener("touchend", this.touchEnd); + document.addEventListener("dblclick", this.doubleClick); this.delegatedEvents = { ...Utils.addEventListenerWithDelegation( @@ -489,6 +508,7 @@ export class InputMouse { document.removeEventListener("mousemove", this.mouseMove); document.removeEventListener("mouseup", this.mouseUp); document.removeEventListener("touchend", this.touchEnd); + document.removeEventListener("dblclick", this.doubleClick); for (const [eventName, eventHandler] of Object.entries(this.delegatedEvents)) { document.removeEventListener(eventName, eventHandler); @@ -542,6 +562,12 @@ export class InputMouse { } }; + doubleClick = (event: MouseEvent): void => { + if (this.isHit(event)) { + this.leftMouseButton.handleDoubleClick(event, false); + } + }; + touchEnd = (): void => { // The order of events during a click on a touch enabled device is: // touch events -> mouse events -> click diff --git a/frontend/javascripts/oxalis/controller/combinations/tool_controls.ts b/frontend/javascripts/oxalis/controller/combinations/tool_controls.ts index 811f6c40f4..dc9c461de4 100644 --- a/frontend/javascripts/oxalis/controller/combinations/tool_controls.ts +++ b/frontend/javascripts/oxalis/controller/combinations/tool_controls.ts @@ -137,6 +137,20 @@ export class MoveTool { } handleClickSegment(pos); }, + leftDoubleClick: (pos: Point2, _plane: OrthoView, _event: MouseEvent, _isTouch: boolean) => { + const { uiInformation } = Store.getState(); + const isMoveToolActive = uiInformation.activeTool === AnnotationToolEnum.MOVE; + + if (isMoveToolActive) { + // We want to select the clicked segment ID only in the MOVE tool. This method is + // implemented within the Move tool, but other tool controls will fall back to this one + // if they didn't define the double click hook. However, for most other tools, this behavior + // would be suboptimal, because when doing a double click, the first click will also be registered + // as a simple left click. For example, doing a double click with the brush tool would brush something + // and then immediately select the id again which is weird. + VolumeHandlers.handlePickCell(pos); + } + }, middleClick: (pos: Point2, _plane: OrthoView, event: MouseEvent) => { if (event.shiftKey) { handleAgglomerateSkeletonAtClick(pos);