private void ThrowEnterAndLeaveTouchEvents(UIElement currentElement, UIElement previousElement, TouchEventArgs touchEvent) { var commonElement = FindCommonParent(currentElement, previousElement); // raise leave events to the hierarchy: previousElt -> commonElementParent var previousElementParent = previousElement; while (previousElementParent != commonElement && previousElementParent != null) { if (previousElementParent.IsHierarchyEnabled && previousElementParent.IsTouched) { touchEvent.Handled = false; // reset 'handled' because it corresponds to another event previousElementParent.RaiseTouchLeaveEvent(touchEvent); } previousElementParent = previousElementParent.VisualParent; } // raise enter events to the hierarchy: newElt -> commonElementParent var newElementParent = currentElement; while (newElementParent != commonElement && newElementParent != null) { if (newElementParent.IsHierarchyEnabled && !newElementParent.IsTouched) { touchEvent.Handled = false; // reset 'handled' because it corresponds to another event newElementParent.RaiseTouchEnterEvent(touchEvent); } newElementParent = newElementParent.VisualParent; } }
private void UpdateTouchEvents(UIComponentProcessor.UIComponentState state, GameTime gameTime) { var rootElement = state.UIComponent.RootElement; var intersectionPoint = Vector3.Zero; var lastTouchPosition = new Vector2(float.NegativeInfinity); // analyze pointer event input and trigger UI touch events depending on hit Tests foreach (var pointerEvent in compactedPointerEvents) { // performance optimization: skip all the events that started outside of the UI var lastTouchedElement = state.LastTouchedElement; if (lastTouchedElement == null && pointerEvent.State != PointerState.Down) continue; var time = gameTime.Total; var currentTouchPosition = pointerEvent.Position; var currentTouchedElement = lastTouchedElement; // re-calculate the element under cursor if click position changed. if (lastTouchPosition != currentTouchPosition) currentTouchedElement = GetElementAtScreenPosition(rootElement, pointerEvent.Position, ref intersectionPoint); if (pointerEvent.State == PointerState.Down || pointerEvent.State == PointerState.Up) state.LastIntersectionPoint = intersectionPoint; var touchEvent = new TouchEventArgs { Action = TouchAction.Down, Timestamp = time, ScreenPosition = currentTouchPosition, ScreenTranslation = pointerEvent.DeltaPosition, WorldPosition = intersectionPoint, WorldTranslation = intersectionPoint - state.LastIntersectionPoint }; switch (pointerEvent.State) { case PointerState.Down: touchEvent.Action = TouchAction.Down; if (currentTouchedElement != null) currentTouchedElement.RaiseTouchDownEvent(touchEvent); break; case PointerState.Up: touchEvent.Action = TouchAction.Up; // generate enter/leave events if we passed from an element to another without move events if (currentTouchedElement != lastTouchedElement) ThrowEnterAndLeaveTouchEvents(currentTouchedElement, lastTouchedElement, touchEvent); // trigger the up event if (currentTouchedElement != null) currentTouchedElement.RaiseTouchUpEvent(touchEvent); break; case PointerState.Move: touchEvent.Action = TouchAction.Move; // first notify the move event (even if the touched element changed in between it is still coherent in one of its parents) if (currentTouchedElement != null) currentTouchedElement.RaiseTouchMoveEvent(touchEvent); // then generate enter/leave events if we passed from an element to another if (currentTouchedElement != lastTouchedElement) ThrowEnterAndLeaveTouchEvents(currentTouchedElement, lastTouchedElement, touchEvent); break; case PointerState.Out: case PointerState.Cancel: touchEvent.Action = TouchAction.Move; // generate enter/leave events if we passed from an element to another without move events if (currentTouchedElement != lastTouchedElement) ThrowEnterAndLeaveTouchEvents(currentTouchedElement, lastTouchedElement, touchEvent); // then raise leave event to all the hierarchy of the previously selected element. var element = currentTouchedElement; while (element != null) { if (element.IsTouched) element.RaiseTouchLeaveEvent(touchEvent); element = element.VisualParent; } break; default: throw new ArgumentOutOfRangeException(); } lastTouchPosition = currentTouchPosition; state.LastTouchedElement = currentTouchedElement; state.LastIntersectionPoint = intersectionPoint; } }