Browse Source

wip, add button to input observer

Alexander Rose 5 years ago
parent
commit
a68d81e495

+ 2 - 2
src/mol-canvas3d/canvas3d.ts

@@ -90,8 +90,8 @@ const requestAnimationFrame = typeof window !== 'undefined' ? window.requestAnim
 const DefaultRunTask = (task: Task<unknown>) => task.run()
 
 namespace Canvas3D {
-    export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, modifiers: ModifiersKeys }
-    export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, modifiers: ModifiersKeys }
+    export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
+    export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
 
     export function fromCanvas(canvas: HTMLCanvasElement, props: Partial<Canvas3DProps> = {}, runTask = DefaultRunTask) {
         const gl = getGLContext(canvas, {

+ 13 - 10
src/mol-canvas3d/helper/interaction-events.ts

@@ -38,6 +38,7 @@ export class Canvas3dInteractionHelper {
     private inside = false;
 
     private buttons: ButtonsType = ButtonsType.create(0);
+    private button: ButtonsType.Flag = ButtonsType.create(0);
     private modifiers: ModifiersKeys = ModifiersKeys.None;
 
     private identify(isClick: boolean, t: number) {
@@ -50,7 +51,7 @@ export class Canvas3dInteractionHelper {
         if (!this.id) return;
 
         if (isClick) {
-            this.events.click.next({ current: this.getLoci(this.id), buttons: this.buttons, modifiers: this.modifiers });
+            this.events.click.next({ current: this.getLoci(this.id), buttons: this.buttons, button: this.button, modifiers: this.modifiers });
             return;
         }
 
@@ -61,7 +62,7 @@ export class Canvas3dInteractionHelper {
         const loci = this.getLoci(this.id);
         // only broadcast the latest hover
         if (!Representation.Loci.areEqual(this.prevLoci, loci)) {
-            this.events.hover.next({ current: loci, buttons: this.buttons, modifiers: this.modifiers });
+            this.events.hover.next({ current: loci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
             this.prevLoci = loci;
         }
     }
@@ -78,22 +79,24 @@ export class Canvas3dInteractionHelper {
         this.inside = false;
         if (this.prevLoci.loci !== EmptyLoci) {
             this.prevLoci = Representation.Loci.Empty;
-            this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, modifiers: this.modifiers });
+            this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
         }
     }
 
-    move(x: number, y: number, buttons: ButtonsType, modifiers: ModifiersKeys) {
+    move(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
         this.inside = true;
         this.buttons = buttons;
+        this.button = button;
         this.modifiers = modifiers;
         this.cX = x;
         this.cY = y;
     }
 
-    select(x: number, y: number, buttons: ButtonsType, modifiers: ModifiersKeys) {
+    select(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
         this.cX = x;
         this.cY = y;
         this.buttons = buttons;
+        this.button = button;
         this.modifiers = modifiers;
         this.identify(true, 0);
     }
@@ -101,7 +104,7 @@ export class Canvas3dInteractionHelper {
     modify(modifiers: ModifiersKeys) {
         if (this.prevLoci.loci === EmptyLoci || ModifiersKeys.areEqual(modifiers, this.modifiers)) return;
         this.modifiers = modifiers;
-        this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, modifiers: this.modifiers });
+        this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
     }
 
     dispose() {
@@ -109,17 +112,17 @@ export class Canvas3dInteractionHelper {
     }
 
     constructor(private canvasIdentify: Canvas3D['identify'], private getLoci: Canvas3D['getLoci'], input: InputObserver, private maxFps: number = 15) {
-        input.move.subscribe(({x, y, inside, buttons, modifiers }) => {
+        input.move.subscribe(({x, y, inside, buttons, button, modifiers }) => {
             if (!inside) return;
-            this.move(x, y, buttons, modifiers);
+            this.move(x, y, buttons, button, modifiers);
         });
 
         input.leave.subscribe(() => {
             this.leave();
         });
 
-        input.click.subscribe(({x, y, buttons, modifiers }) => {
-            this.select(x, y, buttons, modifiers);
+        input.click.subscribe(({x, y, buttons, button, modifiers }) => {
+            this.select(x, y, buttons, button, modifiers);
         });
 
         input.modifiers.subscribe(modifiers => this.modify(modifiers));

+ 2 - 2
src/mol-plugin/behavior/dynamic/camera.ts

@@ -36,10 +36,10 @@ export const FocusLoci = PluginBehavior.create<FocusLociProps>({
     category: 'interaction',
     ctor: class extends PluginBehavior.Handler<FocusLociProps> {
         register(): void {
-            this.subscribeObservable(this.ctx.behaviors.interaction.click, ({ current, buttons, modifiers }) => {
+            this.subscribeObservable(this.ctx.behaviors.interaction.click, ({ current, button, modifiers }) => {
                 if (!this.ctx.canvas3d) return;
                 const p = this.params;
-                if (Binding.match(this.params.bindings.clickCenterFocus, buttons, modifiers)) {
+                if (Binding.match(this.params.bindings.clickCenterFocus, button, modifiers)) {
                     const loci = Loci.normalize(current.loci, this.ctx.interactivity.props.granularity)
                     if (Loci.isEmpty(loci)) {
                         PluginCommands.Camera.Reset.dispatch(this.ctx, { })

+ 9 - 9
src/mol-plugin/behavior/dynamic/representation.ts

@@ -110,30 +110,30 @@ export const SelectLoci = PluginBehavior.create({
             }
         }
         register() {
-            this.subscribeObservable(this.ctx.behaviors.interaction.click, ({ current, buttons, modifiers }) => {
+            this.subscribeObservable(this.ctx.behaviors.interaction.click, ({ current, button, modifiers }) => {
                 if (!this.ctx.canvas3d) return
 
-                if (Binding.match(this.params.bindings.clickSelect, buttons, modifiers)) {
+                if (Binding.match(this.params.bindings.clickSelect, button, modifiers)) {
                     this.ctx.interactivity.lociSelects.select(current)
                 }
 
-                if (Binding.match(this.params.bindings.clickSelectExtend, buttons, modifiers)) {
-                    this.ctx.interactivity.lociSelects.selectExtend(current)
+                if (Binding.match(this.params.bindings.clickToggleExtend, button, modifiers)) {
+                    this.ctx.interactivity.lociSelects.toggleExtend(current)
                 }
 
-                if (Binding.match(this.params.bindings.clickSelectOnly, buttons, modifiers)) {
+                if (Binding.match(this.params.bindings.clickSelectOnly, button, modifiers)) {
                     this.ctx.interactivity.lociSelects.selectOnly(current)
                 }
 
-                if (Binding.match(this.params.bindings.clickSelectToggle, buttons, modifiers)) {
-                    this.ctx.interactivity.lociSelects.selectToggle(current)
+                if (Binding.match(this.params.bindings.clickToggle, button, modifiers)) {
+                    this.ctx.interactivity.lociSelects.toggle(current)
                 }
 
-                if (Binding.match(this.params.bindings.clickDeselect, buttons, modifiers)) {
+                if (Binding.match(this.params.bindings.clickDeselect, button, modifiers)) {
                     this.ctx.interactivity.lociSelects.deselect(current)
                 }
 
-                if (Binding.match(this.params.bindings.clickDeselectAllOnEmpty, buttons, modifiers)) {
+                if (Binding.match(this.params.bindings.clickDeselectAllOnEmpty, button, modifiers)) {
                     if (Loci.isEmpty(current.loci)) this.ctx.interactivity.lociSelects.deselectAll()
                 }
             });

+ 2 - 2
src/mol-plugin/context.ts

@@ -94,8 +94,8 @@ export class PluginContext {
             isUpdating: this.ev.behavior<boolean>(false)
         },
         interaction: {
-            hover: this.ev.behavior<Interactivity.HoverEvent>({ current: Interactivity.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0 }),
-            click: this.ev.behavior<Interactivity.ClickEvent>({ current: Interactivity.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0 })
+            hover: this.ev.behavior<Interactivity.HoverEvent>({ current: Interactivity.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0, button: 0 }),
+            click: this.ev.behavior<Interactivity.ClickEvent>({ current: Interactivity.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0, button: 0 })
         },
         labels: {
             highlight: this.ev.behavior<{ entries: ReadonlyArray<LociLabelEntry> }>({ entries: [] })

+ 1 - 1
src/mol-plugin/ui/sequence/sequence.tsx

@@ -29,7 +29,7 @@ const MaxSequenceNumberSize = 5
 export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
     private parentDiv = React.createRef<HTMLDivElement>();
     private lastMouseOverSeqIdx = -1;
-    private highlightQueue = new Subject<{ seqIdx: number, buttons: number, modifiers: ModifiersKeys }>();
+    private highlightQueue = new Subject<{ seqIdx: number, buttons: number, button: number, modifiers: ModifiersKeys }>();
 
     private lociHighlightProvider = (loci: Interactivity.Loci, action: MarkerAction) => {
         const changed = this.props.sequenceWrapper.markResidue(loci.loci, action)

+ 2 - 2
src/mol-plugin/util/interactivity.ts

@@ -57,8 +57,8 @@ namespace Interactivity {
     export type Params = typeof Params
     export type Props = PD.Values<Params>
 
-    export interface HoverEvent { current: Loci, buttons: ButtonsType, modifiers: ModifiersKeys }
-    export interface ClickEvent { current: Loci, buttons: ButtonsType, modifiers: ModifiersKeys }
+    export interface HoverEvent { current: Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
+    export interface ClickEvent { current: Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
 
     export type LociMarkProvider = (loci: Loci, action: MarkerAction) => void
 

+ 28 - 10
src/mol-util/input/input-observer.ts

@@ -23,8 +23,15 @@ export function getButtons(event: MouseEvent | Touch) {
             } else if (b > 0) {
                 return 1 << (b - 1)
             }
-        } else if ('button' in event) {
-            const b = (event as any).button  // 'any' to support older browsers
+        }
+    }
+    return 0
+}
+
+export function getButton(event: MouseEvent | Touch) {
+    if (typeof event === 'object') {
+        if ('button' in event) {
+            const b = event.button
             if (b === 1) {
                 return 4
             } else if (b === 2) {
@@ -101,6 +108,7 @@ export namespace ButtonsType {
 
 type BaseInput = {
     buttons: ButtonsType
+    button: ButtonsType.Flag
     modifiers: ModifiersKeys
 }
 
@@ -228,7 +236,8 @@ namespace InputObserver {
 
         let dragging: DraggingState = DraggingState.Stopped
         let disposed = false
-        let buttons = 0 as ButtonsType
+        let buttons = ButtonsType.create(ButtonsType.Flag.None)
+        let button = ButtonsType.Flag.None
         let isInside = false
 
         const events = createEvents()
@@ -358,10 +367,11 @@ namespace InputObserver {
 
         function onTouchStart(ev: TouchEvent) {
             if (ev.touches.length === 1) {
-                buttons = ButtonsType.Flag.Primary
+                buttons = button = ButtonsType.Flag.Primary
                 onPointerDown(ev.touches[0])
             } else if (ev.touches.length === 2) {
                 buttons = ButtonsType.Flag.Secondary & ButtonsType.Flag.Auxilary
+                button = ButtonsType.Flag.Secondary
                 onPointerDown(getCenterTouch(ev))
 
                 const touchDistance = getTouchDistance(ev)
@@ -372,10 +382,11 @@ namespace InputObserver {
                     delta: 0,
                     isStart: true,
                     buttons,
+                    button,
                     modifiers: getModifierKeys()
                 })
             } else if (ev.touches.length === 3) {
-                buttons = ButtonsType.Flag.Forth
+                buttons = button = ButtonsType.Flag.Forth
                 onPointerDown(getCenterTouch(ev))
             }
         }
@@ -385,6 +396,8 @@ namespace InputObserver {
         }
 
         function onTouchMove(ev: TouchEvent) {
+            button = ButtonsType.Flag.None
+
             if (noPinchZoom) {
                 ev.preventDefault();
                 ev.stopPropagation();
@@ -412,6 +425,7 @@ namespace InputObserver {
                         distance: touchDistance,
                         isStart: false,
                         buttons,
+                        button,
                         modifiers: getModifierKeys()
                     })
                 }
@@ -425,6 +439,7 @@ namespace InputObserver {
         function onMouseDown(ev: MouseEvent) {
             updateModifierKeys(ev)
             buttons = getButtons(ev)
+            button = getButton(ev)
             if (noMiddleClickScroll && buttons === ButtonsType.Flag.Auxilary) {
                 ev.preventDefault
             }
@@ -434,11 +449,14 @@ namespace InputObserver {
         function onMouseMove(ev: MouseEvent) {
             updateModifierKeys(ev)
             buttons = getButtons(ev)
+            button = ButtonsType.Flag.None
             onPointerMove(ev)
         }
 
         function onMouseUp(ev: MouseEvent) {
             updateModifierKeys(ev)
+            buttons = getButtons(ev)
+            button = getButton(ev)
             onPointerUp(ev)
             endDrag()
         }
@@ -464,7 +482,7 @@ namespace InputObserver {
                 const { pageX, pageY } = ev
                 const [ x, y ] = pointerEnd
 
-                click.next({ x, y, pageX, pageY, buttons, modifiers: getModifierKeys() })
+                click.next({ x, y, pageX, pageY, buttons, button, modifiers: getModifierKeys() })
             }
         }
 
@@ -473,7 +491,7 @@ namespace InputObserver {
             const { pageX, pageY } = ev
             const [ x, y ] = pointerEnd
             const inside = insideBounds(pointerEnd)
-            move.next({ x, y, pageX, pageY, buttons, modifiers: getModifierKeys(), inside })
+            move.next({ x, y, pageX, pageY, buttons, button, modifiers: getModifierKeys(), inside })
 
             if (dragging === DraggingState.Stopped) return
 
@@ -482,7 +500,7 @@ namespace InputObserver {
 
             const isStart = dragging === DraggingState.Started
             const [ dx, dy ] = pointerDelta
-            drag.next({ x, y, dx, dy, pageX, pageY, buttons, modifiers: getModifierKeys(), isStart })
+            drag.next({ x, y, dx, dy, pageX, pageY, buttons, button, modifiers: getModifierKeys(), isStart })
 
             Vec2.copy(pointerStart, pointerEnd)
             dragging = DraggingState.Moving
@@ -504,10 +522,10 @@ namespace InputObserver {
             const dy = (ev.deltaY || 0) * scale
             const dz = (ev.deltaZ || 0) * scale
 
-            buttons = ButtonsType.Flag.Auxilary
+            buttons = button = ButtonsType.Flag.Auxilary
 
             if (dx || dy || dz) {
-                wheel.next({ dx, dy, dz, buttons, modifiers: getModifierKeys() })
+                wheel.next({ dx, dy, dz, buttons, button, modifiers: getModifierKeys() })
             }
         }