Przeglądaj źródła

Observable and Canvas2D bug fixing

Observable's eventState is now a object member of an observable instance to avoid runtime alloc and allow reentrancy among observables' observers

Canvas2D: setting the eventState's skipNextObservers will also prevent the 3D Engines' handlers to be executed.
nockawa 9 lat temu
rodzic
commit
8f37100e3e
2 zmienionych plików z 30 dodań i 16 usunięć
  1. 17 8
      src/Canvas2d/babylon.canvas2d.ts
  2. 13 8
      src/Tools/babylon.observable.ts

+ 17 - 8
src/Canvas2d/babylon.canvas2d.ts

@@ -426,15 +426,18 @@
 
             // Analyze the pointer event type and fire proper events on the primitive
 
+            let skip = false;
             if (eventData.type === PointerEventTypes.POINTERWHEEL) {
-                this._bubbleNotifyPrimPointerObserver(targetPrim, PrimitivePointerInfo.PointerMouseWheel, <MouseWheelEvent>eventData.event);
+                skip = !this._bubbleNotifyPrimPointerObserver(targetPrim, PrimitivePointerInfo.PointerMouseWheel, eventData);
             } else if (eventData.type === PointerEventTypes.POINTERMOVE) {
-                this._bubbleNotifyPrimPointerObserver(targetPrim, PrimitivePointerInfo.PointerMove, <PointerEvent>eventData.event);
+                skip = !this._bubbleNotifyPrimPointerObserver(targetPrim, PrimitivePointerInfo.PointerMove, eventData);
             } else if (eventData.type === PointerEventTypes.POINTERDOWN) {
-                this._bubbleNotifyPrimPointerObserver(targetPrim, PrimitivePointerInfo.PointerDown, <PointerEvent>eventData.event);
+                skip = !this._bubbleNotifyPrimPointerObserver(targetPrim, PrimitivePointerInfo.PointerDown, eventData);
             } else if (eventData.type === PointerEventTypes.POINTERUP) {
-                this._bubbleNotifyPrimPointerObserver(targetPrim, PrimitivePointerInfo.PointerUp, <PointerEvent>eventData.event);
+                skip = !this._bubbleNotifyPrimPointerObserver(targetPrim, PrimitivePointerInfo.PointerUp, eventData);
             }
+
+            eventState.skipNextObservers = skip;
         }
 
         private _updatePointerInfo(eventData: PointerInfoBase, localPosition: Vector2) {
@@ -580,8 +583,9 @@
             console.log(debug);
         }
 
-        private _bubbleNotifyPrimPointerObserver(prim: Prim2DBase, mask: number, eventData: any) {
+        private _bubbleNotifyPrimPointerObserver(prim: Prim2DBase, mask: number, eventData: PointerInfoBase): boolean {
             let ppi = this._primPointerInfo;
+            let event = eventData ? eventData.event : null;
 
             // In case of PointerOver/Out we will first notify the parent with PointerEnter/Leave
             if ((mask & (PrimitivePointerInfo.PointerOver | PrimitivePointerInfo.PointerOut)) !== 0) {
@@ -597,14 +601,18 @@
 
                     // Exec the observers
                     this._debugExecObserver(cur, mask);
-                    cur._pointerEventObservable.notifyObservers(ppi, mask);
-                    this._triggerActionManager(cur, ppi, mask, eventData);
+                    if (!cur._pointerEventObservable.notifyObservers(ppi, mask) && eventData instanceof PointerInfoPre) {
+                        eventData.skipOnPointerObservable = true;
+                        return false;
+                    }
+
+                    this._triggerActionManager(cur, ppi, mask, event);
 
                     // Bubble canceled? If we're not executing PointerOver or PointerOut, quit immediately
                     // If it's PointerOver/Out we have to trigger PointerEnter/Leave no matter what
                     if (ppi.cancelBubble) {
                         if ((mask & (PrimitivePointerInfo.PointerOver | PrimitivePointerInfo.PointerOut)) === 0) {
-                            return;
+                            return false;
                         }
 
                         // We're dealing with PointerOver/Out, let's keep looping to fire PointerEnter/Leave, but not Over/Out anymore
@@ -632,6 +640,7 @@
                 // Loop to the parent
                 cur = cur.parent;
             }
+            return true;
         }
 
         private _triggerActionManager(prim: Prim2DBase, ppi: PrimitivePointerInfo, mask: number, eventData) {

+ 13 - 8
src/Tools/babylon.observable.ts

@@ -45,10 +45,14 @@
      * A given observer can register itself with only Move and Stop (mask = 0x03), then it will only be notified when one of these two occurs and will never be for Turn Left/Right.
      */
     export class Observable<T> {
-        private static _pooledEventState: EventState = null;
-
         _observers = new Array<Observer<T>>();
 
+        private _eventState: EventState;
+
+        constructor() {
+            this._eventState = new EventState(0);
+        }
+
         /**
          * Create a new Observer with the specified callback
          * @param callback the callback that will be executed for that Observer
@@ -106,23 +110,24 @@
 
         /**
          * Notify all Observers by calling their respective callback with the given data
+         * Will return true if all observers were executed, false if an observer set skipNextObservers to true, then prevent the subsequent ones to execute
          * @param eventData
          * @param mask
          */
-        public notifyObservers(eventData: T, mask: number = -1): void {
-            var state = Observable._pooledEventState ? Observable._pooledEventState.initalize(mask) : new EventState(mask);
-            Observable._pooledEventState = null;
+        public notifyObservers(eventData: T, mask: number = -1): boolean {
+            let state = this._eventState;
+            state.mask = mask;
+            state.skipNextObservers = false;
 
             for (var obs of this._observers) {
                 if (obs.mask & mask) {
                     obs.callback(eventData, state);
                 }
                 if (state.skipNextObservers) {
-                    break;
+                    return false;
                 }
             }
-
-            Observable._pooledEventState = state;
+            return true;
         }
 
         /**