private void UpdateMouseOver(UIComponentProcessor.UIComponentState state) { if (input == null || !input.HasMouse) { return; } var intersectionPoint = Vector3.Zero; var mousePosition = input.MousePosition; var rootElement = state.UIComponent.RootElement; var lastOveredElement = state.LastOveredElement; var overredElement = lastOveredElement; // determine currently overred element. if (mousePosition != lastMousePosition) { overredElement = GetElementAtScreenPosition(rootElement, mousePosition, ref intersectionPoint); } // find the common parent between current and last overred elements var commonElement = FindCommonParent(overredElement, lastOveredElement); // disable mouse over state to previously overred hierarchy var parent = lastOveredElement; while (parent != commonElement && parent != null) { parent.MouseOverState = MouseOverState.MouseOverNone; parent = parent.VisualParent; } // enable mouse over state to currently overred hierarchy if (overredElement != null) { // the element itself overredElement.MouseOverState = MouseOverState.MouseOverElement; // its hierarchy parent = overredElement.VisualParent; while (parent != null) { if (parent.IsHierarchyEnabled) { parent.MouseOverState = MouseOverState.MouseOverChild; } parent = parent.VisualParent; } } // update cached values state.LastOveredElement = overredElement; lastMousePosition = mousePosition; }
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; } }