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; } }