From 52cc9e6ce3bcd2e016b52c2a514978be71df0439 Mon Sep 17 00:00:00 2001
From: Alexander Rose <alex.rose@rcsb.org>
Date: Wed, 15 May 2019 20:51:02 -0700
Subject: [PATCH] added unbound InputObserver

---
 src/mol-canvas3d/canvas3d.ts         |   4 +-
 src/mol-util/input/input-observer.ts | 114 +++++++++++++++------------
 2 files changed, 64 insertions(+), 54 deletions(-)

diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts
index 1caea985d..a4a5648a9 100644
--- a/src/mol-canvas3d/canvas3d.ts
+++ b/src/mol-canvas3d/canvas3d.ts
@@ -101,8 +101,8 @@ namespace Canvas3D {
             preserveDrawingBuffer: true
         })
         if (gl === null) throw new Error('Could not create a WebGL rendering context')
-        const input = InputObserver.create(canvas)
-        return Canvas3D.create(gl, input)
+        const input = InputObserver.fromElement(canvas)
+        return Canvas3D.create(gl, input, props)
     }
 
     export function create(gl: GLRenderingContext, input: InputObserver, props: Partial<Canvas3DProps> = {}): Canvas3D {
diff --git a/src/mol-util/input/input-observer.ts b/src/mol-util/input/input-observer.ts
index 8b08cb2fb..d9b521298 100644
--- a/src/mol-util/input/input-observer.ts
+++ b/src/mol-util/input/input-observer.ts
@@ -8,7 +8,7 @@ import { Subject, Observable } from 'rxjs';
 
 import { Vec2 } from 'mol-math/linear-algebra';
 
-import { BitFlags } from 'mol-util';
+import { BitFlags, noop } from 'mol-util';
 
 function getButtons(event: MouseEvent | Touch) {
     if (typeof event === 'object') {
@@ -144,23 +144,50 @@ interface InputObserver {
     noScroll: boolean
     noContextMenu: boolean
 
-    drag: Observable<DragInput>,
+    readonly drag: Observable<DragInput>,
     // Equivalent to mouseUp and touchEnd
-    interactionEnd: Observable<undefined>,
-    wheel: Observable<WheelInput>,
-    pinch: Observable<PinchInput>,
-    click: Observable<ClickInput>,
-    move: Observable<MoveInput>,
-    leave: Observable<undefined>,
-    enter: Observable<undefined>,
-    resize: Observable<ResizeInput>,
-    modifiers: Observable<ModifiersKeys>
+    readonly interactionEnd: Observable<undefined>,
+    readonly wheel: Observable<WheelInput>,
+    readonly pinch: Observable<PinchInput>,
+    readonly click: Observable<ClickInput>,
+    readonly move: Observable<MoveInput>,
+    readonly leave: Observable<undefined>,
+    readonly enter: Observable<undefined>,
+    readonly resize: Observable<ResizeInput>,
+    readonly modifiers: Observable<ModifiersKeys>
 
     dispose: () => void
 }
 
+function createEvents() {
+    return {
+        drag: new Subject<DragInput>(),
+        interactionEnd: new Subject<undefined>(),
+        click: new Subject<ClickInput>(),
+        move: new Subject<MoveInput>(),
+        wheel: new Subject<WheelInput>(),
+        pinch: new Subject<PinchInput>(),
+        resize: new Subject<ResizeInput>(),
+        leave: new Subject<undefined>(),
+        enter: new Subject<undefined>(),
+        modifiers: new Subject<ModifiersKeys>(),
+    }
+}
+
 namespace InputObserver {
-    export function create (element: Element, props: InputObserverProps = {}): InputObserver {
+    export function create(props: InputObserverProps = {}): InputObserver {
+        const { noScroll, noContextMenu } = { ...DefaultInputObserverProps, ...props }
+        return {
+            noScroll,
+            noContextMenu,
+
+            ...createEvents(),
+
+            dispose: noop
+        }
+    }
+
+    export function fromElement(element: Element, props: InputObserverProps = {}): InputObserver {
         let { noScroll, noContextMenu, noPinchZoom } = { ...DefaultInputObserverProps, ...props }
 
         let lastTouchDistance = 0
@@ -169,15 +196,15 @@ namespace InputObserver {
         const pointerEnd = Vec2.zero()
         const pointerDelta = Vec2.zero()
         const rectSize = Vec2.zero()
-        const modifiers: ModifiersKeys = {
+        const modifierKeys: ModifiersKeys = {
             shift: false,
             alt: false,
             control: false,
             meta: false
         }
 
-        function getModifiers(): ModifiersKeys {
-            return { ...modifiers };
+        function getModifierKeys(): ModifiersKeys {
+            return { ...modifierKeys };
         }
 
         let dragging: DraggingState = DraggingState.Stopped
@@ -185,16 +212,8 @@ namespace InputObserver {
         let buttons = 0 as ButtonsType
         let isInside = false
 
-        const drag = new Subject<DragInput>()
-        const interactionEnd = new Subject<undefined>();
-        const click = new Subject<ClickInput>()
-        const move = new Subject<MoveInput>()
-        const wheel = new Subject<WheelInput>()
-        const pinch = new Subject<PinchInput>()
-        const resize = new Subject<ResizeInput>()
-        const leave = new Subject<undefined>()
-        const enter = new Subject<undefined>()
-        const modifiersEvent = new Subject<ModifiersKeys>()
+        const events = createEvents()
+        const { drag, interactionEnd, wheel, pinch, click, move, leave, enter, resize, modifiers } = events
 
         attach()
 
@@ -204,22 +223,13 @@ namespace InputObserver {
             get noContextMenu () { return noContextMenu },
             set noContextMenu (value: boolean) { noContextMenu = value },
 
-            drag,
-            interactionEnd,
-            wheel,
-            pinch,
-            click,
-            move,
-            leave,
-            enter,
-            resize,
-            modifiers: modifiersEvent,
+            ...events,
 
             dispose
         }
 
         function attach () {
-            element.addEventListener( 'contextmenu', onContextMenu, false )
+            element.addEventListener('contextmenu', onContextMenu, false )
 
             element.addEventListener('wheel', onMouseWheel as any, false)
             element.addEventListener('mousedown', onMouseDown as any, false)
@@ -274,31 +284,31 @@ namespace InputObserver {
         }
 
         function handleBlur () {
-            if (buttons || modifiers.shift || modifiers.alt || modifiers.meta || modifiers.control) {
+            if (buttons || modifierKeys.shift || modifierKeys.alt || modifierKeys.meta || modifierKeys.control) {
                 buttons = 0 as ButtonsType
-                modifiers.shift = modifiers.alt = modifiers.control = modifiers.meta = false
+                modifierKeys.shift = modifierKeys.alt = modifierKeys.control = modifierKeys.meta = false
             }
         }
 
         function handleKeyDown (event: KeyboardEvent) {
             let changed = false;
-            if (!modifiers.alt && event.altKey) { changed = true; modifiers.alt = true; }
-            if (!modifiers.shift && event.shiftKey) { changed = true; modifiers.shift = true; }
-            if (!modifiers.control && event.ctrlKey) { changed = true; modifiers.control = true; }
-            if (!modifiers.meta && event.metaKey) { changed = true; modifiers.meta = true; }
+            if (!modifierKeys.alt && event.altKey) { changed = true; modifierKeys.alt = true; }
+            if (!modifierKeys.shift && event.shiftKey) { changed = true; modifierKeys.shift = true; }
+            if (!modifierKeys.control && event.ctrlKey) { changed = true; modifierKeys.control = true; }
+            if (!modifierKeys.meta && event.metaKey) { changed = true; modifierKeys.meta = true; }
 
-            if (changed && isInside) modifiersEvent.next(getModifiers());
+            if (changed && isInside) modifiers.next(getModifierKeys());
         }
 
         function handleKeyUp (event: KeyboardEvent) {
             let changed = false;
 
-            if (modifiers.alt && !event.altKey) { changed = true; modifiers.alt = false; }
-            if (modifiers.shift && !event.shiftKey) { changed = true; modifiers.shift = false; }
-            if (modifiers.control && !event.ctrlKey) { changed = true; modifiers.control = false; }
-            if (modifiers.meta && !event.metaKey) { changed = true; modifiers.meta = false; }
+            if (modifierKeys.alt && !event.altKey) { changed = true; modifierKeys.alt = false; }
+            if (modifierKeys.shift && !event.shiftKey) { changed = true; modifierKeys.shift = false; }
+            if (modifierKeys.control && !event.ctrlKey) { changed = true; modifierKeys.control = false; }
+            if (modifierKeys.meta && !event.metaKey) { changed = true; modifierKeys.meta = false; }
 
-            if (changed && isInside) modifiersEvent.next(getModifiers());
+            if (changed && isInside) modifiers.next(getModifierKeys());
         }
 
         function getCenterTouch (ev: TouchEvent): PointerEvent {
@@ -403,7 +413,7 @@ namespace InputObserver {
                 const { pageX, pageY } = ev
                 const [ x, y ] = pointerEnd
 
-                click.next({ x, y, pageX, pageY, buttons, modifiers: getModifiers() })
+                click.next({ x, y, pageX, pageY, buttons, modifiers: getModifierKeys() })
             }
         }
 
@@ -412,7 +422,7 @@ namespace InputObserver {
             const { pageX, pageY } = ev
             const [ x, y ] = pointerEnd
             const inside = insideBounds(pointerEnd)
-            move.next({ x, y, pageX, pageY, buttons, modifiers: getModifiers(), inside })
+            move.next({ x, y, pageX, pageY, buttons, modifiers: getModifierKeys(), inside })
 
             if (dragging === DraggingState.Stopped) return
 
@@ -420,7 +430,7 @@ namespace InputObserver {
 
             const isStart = dragging === DraggingState.Started
             const [ dx, dy ] = pointerDelta
-            drag.next({ x, y, dx, dy, pageX, pageY, buttons, modifiers: getModifiers(), isStart })
+            drag.next({ x, y, dx, dy, pageX, pageY, buttons, modifiers: getModifierKeys(), isStart })
 
             Vec2.copy(pointerStart, pointerEnd)
             dragging = DraggingState.Moving
@@ -443,7 +453,7 @@ namespace InputObserver {
             const dz = (ev.deltaZ || 0) * scale
 
             if (dx || dy || dz) {
-                wheel.next({ dx, dy, dz, buttons, modifiers: getModifiers() })
+                wheel.next({ dx, dy, dz, buttons, modifiers: getModifierKeys() })
             }
         }
 
-- 
GitLab