/// <summary> /// Global handler for pointer pressed events. /// </summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event args.</param> private static void OnPreviewPointerPressed(object?sender, RoutedEventArgs e) { if (sender is null) { return; } var ev = (PointerPressedEventArgs)e; var visual = (IVisual)sender; if (sender == e.Source && ev.GetCurrentPoint(visual).Properties.IsLeftButtonPressed) { IVisual?element = ev.Pointer?.Captured ?? e.Source as IInputElement; while (element != null) { if (element is IInputElement inputElement && CanFocus(inputElement)) { Instance?.Focus(inputElement, NavigationMethod.Pointer, ev.KeyModifiers); break; } element = element.VisualParent; } } }
public void End() { DragControl = null; DropControl = null; DragStartPoint = default; PointerPressed = false; DoDragDrop = false; TargetPoint = default; TargetDockControl = null; }
public void Start(IControl dragControl, Point point) { DragControl = dragControl; DropControl = null; DragStartPoint = point; PointerPressed = true; DoDragDrop = false; TargetPoint = default; TargetDockControl = null; }
public void Dispose() { if (_visual == null) { return; } UnsubscribeFromParents(); _visual.AttachedToVisualTree -= OnAttachedToVisualTree; _visual.DetachedFromVisualTree -= OnDetachedFromVisualTree; _visual = null; }
public HitTestEnumerator(IVisualNode root, Func <IVisual, bool>?filter, Point point, IVisualNode sceneRoot) { _nodeStack = new PooledStack <Entry>(); _nodeStack.Push(new Entry(root, false, null, true)); _filter = filter; _point = point; _sceneRoot = sceneRoot; _current = null; }
/// <summary> /// Tries to get the first common ancestor of two visuals. /// </summary> /// <param name="visual">The first visual.</param> /// <param name="target">The second visual.</param> /// <returns>The common ancestor, or null if not found.</returns> public static IVisual?FindCommonVisualAncestor(this IVisual visual, IVisual target) { IVisual?v = visual ?? throw new ArgumentNullException(nameof(visual)); if (target is null) { return(null); } IVisual?t = target; void GoUpwards(ref IVisual?node, int count) { for (int i = 0; i < count; ++i) { node = node?.VisualParent; } } // We want to find lowest node first, then make sure that both nodes are at the same height. // By doing that we can sometimes find out that other node is our lowest common ancestor. var firstHeight = CalculateDistanceFromRoot(v); var secondHeight = CalculateDistanceFromRoot(t); if (firstHeight > secondHeight) { GoUpwards(ref v, firstHeight - secondHeight); } else { GoUpwards(ref t, secondHeight - firstHeight); } if (v == t) { return(v); } while (v != null && t != null) { IVisual?firstParent = v.VisualParent; IVisual?secondParent = t.VisualParent; if (firstParent == secondParent) { return(firstParent); } v = v.VisualParent; t = t.VisualParent; } return(null); }
/// <summary> /// Gets the common visual parent of the two control. /// </summary> /// <param name="from">The from control.</param> /// <param name="to">The to control.</param> /// <returns>The common parent.</returns> /// <exception cref="ArgumentException"> /// The two controls do not share a common parent. /// </exception> /// <remarks> /// Any one of the parameters may be null, but not both. /// </remarks> private static IVisual GetVisualParent(IVisual?from, IVisual?to) { var p1 = (from ?? to) !.VisualParent; var p2 = (to ?? from) !.VisualParent; if (p1 != null && p2 != null && p1 != p2) { throw new ArgumentException("Controls for PageSlide must have same parent."); } return(p1 ?? throw new InvalidOperationException("Cannot determine visual parent.")); }
public PointerEventArgs(RoutedEvent routedEvent, IInteractive?source, IPointer pointer, IVisual?rootVisual, Point rootVisualPosition, ulong timestamp, PointerPointProperties properties, KeyModifiers modifiers, Lazy <IReadOnlyList <RawPointerPoint>?>?previousPoints) : this(routedEvent, source, pointer, rootVisual, rootVisualPosition, timestamp, properties, modifiers) { _previousPoints = previousPoints; }
/// <summary> /// Calculates the distance from a visual's ancestor. /// </summary> /// <param name="visual">The visual.</param> /// <param name="ancestor">The ancestor visual.</param> /// <returns> /// The number of steps from the visual to the ancestor or -1 if /// <paramref name="visual"/> is not a descendent of <paramref name="ancestor"/>. /// </returns> public static int CalculateDistanceFromAncestor(this IVisual visual, IVisual?ancestor) { IVisual?v = visual ?? throw new ArgumentNullException(nameof(visual)); var result = 0; while (v != null && v != ancestor) { v = v.VisualParent; result++; } return(v != null ? result : -1); }
public void SetVisual(IVisual?visual) { Dispose(); _visual = visual; if (visual != null) { visual.AttachedToVisualTree += OnAttachedToVisualTree; visual.DetachedFromVisualTree -= OnDetachedFromVisualTree; if (visual.IsAttachedToVisualTree) { SubscribeToParents(); } UpdateMatrix(); } }
/// <summary> /// Tests whether an <see cref="IVisual"/> is an ancestor of another visual. /// </summary> /// <param name="visual">The visual.</param> /// <param name="target">The potential descendant.</param> /// <returns> /// True if <paramref name="visual"/> is an ancestor of <paramref name="target"/>; /// otherwise false. /// </returns> public static bool IsVisualAncestorOf(this IVisual visual, IVisual target) { IVisual?current = target?.VisualParent; while (current != null) { if (current == visual) { return(true); } current = current.VisualParent; } return(false); }
public PointerEventArgs(RoutedEvent routedEvent, IInteractive?source, IPointer pointer, IVisual?rootVisual, Point rootVisualPosition, ulong timestamp, PointerPointProperties properties, KeyModifiers modifiers) : base(routedEvent) { Source = source; _rootVisual = rootVisual; _rootVisualPosition = rootVisualPosition; _properties = properties; Pointer = pointer; Timestamp = timestamp; KeyModifiers = modifiers; }
/// <summary> /// Finds first ancestor of given type. /// </summary> /// <typeparam name="T">Ancestor type.</typeparam> /// <param name="visual">The visual.</param> /// <param name="includeSelf">If given visual should be included in search.</param> /// <returns>First ancestor of given type.</returns> public static T?FindAncestorOfType <T>(this IVisual visual, bool includeSelf = false) where T : class { if (visual is null) { return(null); } IVisual?parent = includeSelf ? visual : visual.VisualParent; while (parent != null) { if (parent is T result) { return(result); } parent = parent.VisualParent; } return(null); }
/// <summary> /// Gets a transform from an ancestor to a descendent. /// </summary> /// <param name="ancestor">The ancestor visual.</param> /// <param name="visual">The visual.</param> /// <returns>The transform.</returns> private static Matrix GetOffsetFrom(IVisual ancestor, IVisual visual) { var result = Matrix.Identity; IVisual?v = visual; while (v != ancestor) { // this should be calculated BEFORE renderTransform if (v.HasMirrorTransform) { var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, v.Bounds.Width, 0); result *= mirrorMatrix; } if (v.RenderTransform?.Value != null) { var origin = v.RenderTransformOrigin.ToPixels(v.Bounds.Size); var offset = Matrix.CreateTranslation(origin); var renderTransform = (-offset) * v.RenderTransform.Value * (offset); result *= renderTransform; } var topLeft = v.Bounds.TopLeft; if (topLeft != default) { result *= Matrix.CreateTranslation(topLeft); } v = v.VisualParent; if (v == null) { throw new ArgumentException("'visual' is not a descendant of 'ancestor'."); } } return(result); }
public bool MoveNext() { while (_nodeStack.Count > 0) { (var wasVisited, var isRoot, IVisualNode node, Rect? clip) = _nodeStack.Pop(); if (wasVisited && isRoot) { break; } var children = node.Children; int childCount = children.Count; if (childCount == 0 || wasVisited) { if ((wasVisited || FilterAndClip(node, ref clip)) && (node.Visual is ICustomHitTest custom ? custom.HitTest(_point) : node.HitTest(_point))) { _current = node.Visual; return(true); } } else if (FilterAndClip(node, ref clip)) { _nodeStack.Push(new Entry(node, true, null)); for (var i = 0; i < childCount; i++) { _nodeStack.Push(new Entry(children[i], false, clip)); } } } return(false); }
public void ProcessRawEvent(RawInputEventArgs e) { if (e.Handled) { return; } var element = FocusedElement ?? e.Root; if (e is RawKeyEventArgs keyInput) { switch (keyInput.Type) { case RawKeyEventType.KeyDown: case RawKeyEventType.KeyUp: var routedEvent = keyInput.Type == RawKeyEventType.KeyDown ? InputElement.KeyDownEvent : InputElement.KeyUpEvent; KeyEventArgs ev = new KeyEventArgs { RoutedEvent = routedEvent, Device = this, Key = keyInput.Key, KeyModifiers = KeyModifiersUtils.ConvertToKey(keyInput.Modifiers), Source = element, }; IVisual?currentHandler = element; while (currentHandler != null && !ev.Handled && keyInput.Type == RawKeyEventType.KeyDown) { var bindings = (currentHandler as IInputElement)?.KeyBindings; if (bindings != null) { KeyBinding[]? bindingsCopy = null; // Create a copy of the KeyBindings list if there's a binding which matches the event. // If we don't do this the foreach loop will throw an InvalidOperationException when the KeyBindings list is changed. // This can happen when a new view is loaded which adds its own KeyBindings to the handler. foreach (var binding in bindings) { if (binding.Gesture?.Matches(ev) == true) { bindingsCopy = bindings.ToArray(); break; } } if (bindingsCopy is object) { foreach (var binding in bindingsCopy) { if (ev.Handled) { break; } binding.TryHandle(ev); } } } currentHandler = currentHandler.VisualParent; } element.RaiseEvent(ev); e.Handled = ev.Handled; break; } } if (e is RawTextInputEventArgs text) { var ev = new TextInputEventArgs() { Device = this, Text = text.Text, Source = element, RoutedEvent = InputElement.TextInputEvent }; element.RaiseEvent(ev); e.Handled = ev.Handled; } }
public void ProcessRawEvent(RawInputEventArgs e) { if (e.Handled) { return; } var element = FocusedElement ?? e.Root; if (e is RawKeyEventArgs keyInput) { switch (keyInput.Type) { case RawKeyEventType.KeyDown: case RawKeyEventType.KeyUp: var routedEvent = keyInput.Type == RawKeyEventType.KeyDown ? InputElement.KeyDownEvent : InputElement.KeyUpEvent; KeyEventArgs ev = new KeyEventArgs { RoutedEvent = routedEvent, Device = this, Key = keyInput.Key, KeyModifiers = KeyModifiersUtils.ConvertToKey(keyInput.Modifiers), Source = element, }; IVisual?currentHandler = element; while (currentHandler != null && !ev.Handled && keyInput.Type == RawKeyEventType.KeyDown) { var bindings = (currentHandler as IInputElement)?.KeyBindings; if (bindings != null) { foreach (var binding in bindings) { if (ev.Handled) { break; } binding.TryHandle(ev); } } currentHandler = currentHandler.VisualParent; } element.RaiseEvent(ev); e.Handled = ev.Handled; break; } } if (e is RawTextInputEventArgs text) { var ev = new TextInputEventArgs() { Device = this, Text = text.Text, Source = element, RoutedEvent = InputElement.TextInputEvent }; element.RaiseEvent(ev); e.Handled = ev.Handled; } }
/// <summary> /// Process pointer event. /// </summary> /// <param name="point">The pointer position.</param> /// <param name="delta">The mouse wheel delta.</param> /// <param name="eventType">The pointer event type.</param> /// <param name="dragAction">The input drag action.</param> /// <param name="activeDockControl">The active dock control.</param> /// <param name="dockControls">The dock controls.</param> public void Process(Point point, Vector delta, EventType eventType, DragAction dragAction, IVisual activeDockControl, IList <IDockControl> dockControls) { if (!(activeDockControl is IInputElement inputActiveDockControl)) { return; } switch (eventType) { case EventType.Pressed: { var dragControl = DockHelpers.GetControl(inputActiveDockControl, point, DockProperties.IsDragAreaProperty); if (dragControl != null) { bool isDragEnabled = dragControl.GetValue(DockProperties.IsDragEnabledProperty); if (isDragEnabled != true) { break; } Debug.WriteLine($"Drag : {point} : {eventType} : {dragControl.Name} : {dragControl.GetType().Name} : {dragControl.DataContext?.GetType().Name}"); _dragControl = dragControl; _dropControl = null; _dragStartPoint = point; _pointerPressed = true; _doDragDrop = false; _targetPoint = default; _targetDockControl = null; break; } } break; case EventType.Released: { if (_doDragDrop == true) { if (_dropControl != null && _targetDockControl != null) { bool isDropEnabled = true; if (_targetDockControl is IControl targetControl) { isDropEnabled = targetControl.GetValue(DockProperties.IsDropEnabledProperty); } if (isDropEnabled == true) { Drop(_targetPoint, dragAction, _targetDockControl); } } else { // TODO: Create window. } } Leave(); _dragControl = null; _dropControl = null; _dragStartPoint = default; _pointerPressed = false; _doDragDrop = false; _targetPoint = default; _targetDockControl = null; } break; case EventType.Moved: { if (_pointerPressed == false) { break; } if (_doDragDrop == false) { Vector diff = _dragStartPoint - point; bool haveMinimumDragDistance = IsMinimumDragDistance(diff); if (haveMinimumDragDistance == true) { if (_dragControl?.DataContext is IDockable targetDockable) { DockHelpers.ShowWindows(targetDockable); } _doDragDrop = true; } } if (_doDragDrop == true) { Point targetPoint = default; IVisual? targetDockControl = null; IControl?dropControl = null; foreach (var dockControl in dockControls) { if (dockControl is IInputElement inputDockControl && inputDockControl != inputActiveDockControl) { var screenPoint = inputActiveDockControl.PointToScreen(point); var dockControlPoint = (dockControl as IVisual)?.PointToClient(screenPoint); if (dockControlPoint == null) { continue; } dropControl = DockHelpers.GetControl(inputDockControl, dockControlPoint.Value, DockProperties.IsDropAreaProperty); if (dropControl != null) { targetPoint = dockControlPoint.Value; targetDockControl = inputDockControl; break; } } } if (dropControl == null) { dropControl = DockHelpers.GetControl(inputActiveDockControl, point, DockProperties.IsDropAreaProperty); if (dropControl != null) { targetPoint = point; targetDockControl = inputActiveDockControl; } } if (dropControl != null && targetDockControl != null) { bool isDropEnabled = true; if (targetDockControl is IControl targetControl) { isDropEnabled = targetControl.GetValue(DockProperties.IsDropEnabledProperty); } Debug.WriteLine($"Drop : {targetPoint} : {eventType} : {dropControl.Name} : {dropControl.GetType().Name} : {dropControl.DataContext?.GetType().Name}"); if (isDropEnabled) { if (_dropControl == dropControl) { _targetPoint = targetPoint; _targetDockControl = targetDockControl; Over(targetPoint, dragAction, targetDockControl); } else { if (_dropControl != null) { Leave(); _dropControl = null; } _dropControl = dropControl; _targetPoint = targetPoint; _targetDockControl = targetDockControl; Enter(targetPoint, dragAction, targetDockControl); } } else { if (_dropControl != null) { Leave(); _dropControl = null; _targetPoint = default; _targetDockControl = null; } } } else { Leave(); _dropControl = null; _targetPoint = default; _targetDockControl = null; } } } break; case EventType.Enter: { } break; case EventType.Leave: { } break; case EventType.CaptureLost: { Leave(); _dragControl = null; _dropControl = null; _dragStartPoint = default; _pointerPressed = false; _doDragDrop = false; _targetPoint = default; _targetDockControl = null; } break; case EventType.WheelChanged: { } break; } }
public Point GetPosition(IVisual?relativeTo) => lastPointerEventArgs.GetPosition(relativeTo);
public int Compare(IVisual?x, IVisual?y) => (x?.ZIndex ?? 0).CompareTo(y?.ZIndex ?? 0);
private Point GetPosition(Point pt, IVisual?relativeTo) { if (_rootVisual == null) { return(default);
public Point GetPosition(IVisual?relativeTo) { if (_rootVisual == null) { return(default);
protected sealed override void OnVisualParentChanged(IVisual?oldParent, IVisual?newParent) { LayoutHelper.InvalidateSelfAndChildrenMeasure(this); base.OnVisualParentChanged(oldParent, newParent); }