/// <summary> /// Adds an element to the queue. /// </summary> /// <param name="element">The element to add to the queue.</param> public void Enqueue(UIElement element) { Contract.Require(element, nameof(element)); var current = element; var parent = element; while (current != null) { invalidate(current); parent = VisualTreeHelper.GetParent(current) as UIElement; if (parent == null || !bubble) { var entry = new Entry(current.LayoutDepth, current); if (queue.ContainsKey(entry)) return; queue.Add(entry, current); } else { var entry = new Entry(current.LayoutDepth, current); queue.Remove(entry); } if (!bubble) break; current = parent; } }
/// <summary> /// Removes the specified element from the queue. /// </summary> /// <param name="element">The element to remove from the queue.</param> public void Remove(UIElement element) { Contract.Require(element, "element"); var entry = new Entry(element.LayoutDepth, element); queue.Remove(entry); }
/// <summary> /// Gets a value indicating whether the specified element is rendered out-of-band. /// </summary> /// <param name="element">The element to evaluate.</param> /// <returns><c>true</c> if the specified element is rendered out-of-band; otherwise, <c>false</c>.</returns> public Boolean IsRenderedOutOfBand(UIElement element) { Contract.Require(element, "element"); Contract.EnsureNotDisposed(this, Disposed); return element.OutOfBandRenderTarget != null; }
/// <summary> /// Gets a value indicating whether the specified element's texture is ready to be used. /// </summary> /// <param name="element">The element to evaluate.</param> /// <returns><c>true</c> if the specified element's texture is ready; otherwise, <c>false</c>.</returns> public Boolean IsTextureReady(UIElement element) { Contract.Require(element, "element"); Contract.EnsureNotDisposed(this, Disposed); var rtarget = element.OutOfBandRenderTarget; return rtarget != null && rtarget.Value.IsReady; }
/// <summary> /// Deactivates the specified command stream's activated link, if it has one. /// </summary> /// <param name="stream">The command stream to update.</param> /// <param name="element">The element that owns the command stream.</param> /// <returns><see langword="true"/> if the command stream's link was deactivated; otherwise, <see langword="false"/>.</returns> public static Boolean DeactivateTextLink(TextLayoutCommandStream stream, UIElement element) { Contract.Require(element, nameof(element)); if (stream == null || element.View == null) return false; return element.View.Resources.TextRenderer.DeactivateLink(stream); }
/// <summary> /// Gets a value indicating whether the specified element is currently being drawn. /// </summary> /// <param name="element">The element to evaluate.</param> /// <returns><c>true</c> if the specified element is being drawn; otherwise, false.</returns> public static Boolean IsDrawn(UIElement element) { Contract.Require(element, "element"); if (element.Visibility != Visibility.Visible) return false; if (element is Popup || element is Adorner) return true; return (element.RenderSize.Width > 0 && element.RenderSize.Height > 0); }
/// <summary> /// Activates any link at the current cursor position within the specified command stream. /// </summary> /// <param name="stream">The command stream to update.</param> /// <param name="element">The element that owns the command stream.</param> /// <param name="data">The event metadata for the routed event which prompted the link activation.</param> /// <returns><see langword="true"/> if the command stream's link was deactivated; otherwise, <see langword="false"/>.</returns> public static Boolean ActivateTextLink(TextLayoutCommandStream stream, UIElement element, RoutedEventData data) { Contract.Require(element, nameof(element)); if (stream == null || element.View == null || !element.View.Resources.TextRenderer.ActivateLinkAtCursor(stream)) return false; element.Focus(); element.CaptureMouse(); data.Handled = true; return true; }
/// <summary> /// Executes any link at the current cursor position within the specified command stream. /// </summary> /// <param name="stream">The command stream to update.</param> /// <param name="element">The element that owns the command stream.</param> /// <param name="data">The event metadata for the routed event which prompted the link execution.</param> public static Boolean ExecuteTextLink(TextLayoutCommandStream stream, UIElement element, RoutedEventData data) { Contract.Require(element, nameof(element)); if (stream == null || element.View == null) return false; if (stream.ActiveLinkIndex.HasValue) element.ReleaseMouseCapture(); if (!element.View.Resources.TextRenderer.ExecuteActivatedLink(stream)) return false; data.Handled = true; return true; }
/// <summary> /// Updates the position of the cursor within the specified command stream. /// </summary> /// <param name="stream">The command stream to update.</param> /// <param name="element">The element that owns the command stream.</param> /// <param name="position">The position of the input device.</param> public static void UpdateLinkCursor(TextLayoutCommandStream stream, UIElement element, Point2D? position) { Contract.Require(element, nameof(element)); if (stream == null || element.View == null) return; var positionDips = position; var positionPixs = positionDips.HasValue ? (Point2)element.View.Display.DipsToPixels(positionDips.Value) : (Point2?)null; if (positionDips.HasValue && (element.IsMouseOver || element.IsMouseCaptured)) { element.View.Resources .TextRenderer.UpdateCursor(stream, positionPixs); } else { element.View.Resources .TextRenderer.UpdateCursor(stream, null); } }
/// <summary> /// Gets a value indicating whether the renderer is currently drawing the out-of-band render targets for /// the specified element. /// </summary> /// <param name="element">The element to evaluate.</param> /// <returns><see langword="true"/> if the render targets for the specified element are currently being drawn; otherwise, <see langword="false"/>.</returns> public Boolean IsDrawingRenderTargetFor(UIElement element) { Contract.Require(element, nameof(element)); return element == currentElementDrawingRenderTarget; }
/// <summary> /// Resizes the render target to match the specified element. /// </summary> /// <param name="element">The element for which to resize the render target.</param> /// <param name="bounds">The visual bounds of the element in absolute screen coordinates.</param> /// <returns><see langword="true"/> if the element was resized; otherwise, <see langword="false"/>.</returns> public Boolean ResizeForElement(UIElement element, out RectangleD bounds) { Contract.Require(element, nameof(element)); if (element.View == null) { bounds = RectangleD.Empty; return false; } bounds = element.TransformedVisualBounds; var effect = element.Effect; if (effect != null) { effect.ModifyVisualBounds(ref bounds); } var display = element.View.Display; var width = Math.Max(1, (Int32)Math.Ceiling(display.DipsToPixels(bounds.Width))); var height = Math.Max(1, (Int32)Math.Ceiling(display.DipsToPixels(bounds.Height))); if (width == renderTarget.Width && height == renderTarget.Height) return false; if (width < 1 || height < 1) { Resize(1, 1); bounds = RectangleD.Empty; } else { Resize(width, height); } return true; }
/// <summary> /// Initializes a new instance of the <see cref="Entry"/> structure. /// </summary> /// <param name="priority">The entry's priority within the queue.</param> /// <param name="element">The element pending a layout operation.</param> public Entry(Int32 priority, UIElement element) { this.priority = priority; this.element = element; }
/// <summary> /// Gets a value indicating whether the specified element is currently filling space in the layout. /// </summary> /// <param name="element">The element to evaluate.</param> /// <returns><see langword="true"/> if the specified element is filling space; otherwise, <see langword="false"/>.</returns> public static Boolean IsSpaceFilling(UIElement element) { Contract.Require(element, nameof(element)); return element.Visibility != Visibility.Collapsed; }
/// <summary> /// Initializes a new instance of the <see cref="UvmlObject"/> class. /// </summary> /// <param name="xml">The XML element that corresponds to this node.</param> /// <param name="instance">The <see cref="UIElement"/> instance that was created for this object.</param> /// <param name="instanceFlags">The set of <see cref="UIElementInstanceFlags"/> to attach to this object's instance.</param> public UvmlObject(XElement xml, UIElement instance, UIElementInstanceFlags instanceFlags) { this.xml = xml; this.instance = instance; this.instanceFlags = instanceFlags; }
/// <summary> /// Sets the visibility of the specified element. /// </summary> private void SetElementVisibility(UIElement element, Boolean visible) { if (element == null) return; element.Visibility = visible ? Visibility.Visible : Visibility.Collapsed; }
/// <summary> /// Initializes a new instance of the <see cref="ExampleBoxesAdorner"/> class. /// </summary> /// <param name="adornedElement">The element being adorned.</param> public ExampleBoxesAdorner(UIElement adornedElement) : base(adornedElement) { }
/// <summary> /// Gets a value indicating whether the specified element has become disconnected from the view's layout root through the visual tree. /// </summary> /// <param name="element">The element to evaluate.</param> /// <returns><see langword="true"/> if the specified element is visually disconnected; otherwise, <see langword="false"/>.</returns> private static Boolean IsVisuallyDisconnectedFromRoot(UIElement element) { var current = element; while (current != null) { if (current == element.View.LayoutRoot) return false; if (current is PopupRoot) { var popup = current.Parent as Popup; if (popup == null || !popup.IsOpen) return true; current = popup; } else { current = VisualTreeHelper.GetParent(current) as UIElement; } } return true; }
/// <summary> /// Unregisters an element from the out-of-band renderer. /// </summary> /// <param name="element">The element to unregister.</param> public void Unregister(UIElement element) { Contract.Require(element, nameof(element)); Contract.EnsureNotDisposed(this, Disposed); foreach (var registeredElement in registeredElements) { var weakRefTarget = (UIElement)registeredElement.Target; if (weakRefTarget != element) continue; for (UpfPool<OutOfBandRenderTarget>.PooledObject current = element.OutOfBandRenderTarget, next = null; current != null; current = next) { next = current.Value.NextInternal; current.Value.Resize(1, 1); current.Value.NextInternal = null; renderTargetPool.Release(current); } registeredElements.Remove(registeredElement); element.OutOfBandRenderTarget = null; registeredElement.Target = null; WeakReferencePool.Instance.Release(registeredElement); break; } }
/// <summary> /// Registers an element with the out-of-band renderer. /// </summary> /// <param name="element">The element to register.</param> /// <param name="additional">The number of additional render targets to reserve.</param> public void Register(UIElement element, Int32 additional) { Contract.Require(element, nameof(element)); Contract.EnsureRange(additional >= 0, nameof(additional)); Contract.EnsureNotDisposed(this, Disposed); if (IsRenderedOutOfBand(element)) return; InitializePools(); var weakRef = WeakReferencePool.Instance.Retrieve(); weakRef.Target = element; var target = renderTargetPool.Retrieve(element); var targetObject = target.Value; var bounds = default(RectangleD); targetObject.ResizeForElement(element, out bounds); var currentTarget = targetObject; currentTarget.NextInternal = null; for (int i = 0; i < additional; i++) { var additionalTarget = renderTargetPool.Retrieve(element); var additionalTargetObject = additionalTarget.Value; additionalTargetObject.NextInternal = null; additionalTargetObject.Resize(targetObject.Width, targetObject.Height); currentTarget.NextInternal = additionalTarget; currentTarget = additionalTarget.Value; } registeredElements.Add(weakRef); element.OutOfBandRenderTarget = target; }
/// <summary> /// Draws out-of-band elements to their render buffers. /// </summary> /// <param name="time">Time elapsed since the last call to <see cref="UltravioletContext.Draw(UltravioletTime)"/>.</param> public void DrawRenderTargets(UltravioletTime time) { Contract.EnsureNotDisposed(this, Disposed); if (registeredElements.Count == 0) return; var graphics = Ultraviolet.GetGraphics(); var upf = Ultraviolet.GetUI().GetPresentationFoundation(); upf.PerformanceStats.BeginDraw(); try { isDrawingRenderTargets = true; foreach (var registeredElement in registeredElements) { var element = (UIElement)registeredElement.Target; if (element != null && element.OutOfBandRenderTarget != null) { element.OutOfBandRenderTarget.Value.IsReady = false; } if (element.View != null && !element.View.LayoutRoot.IsLoaded) viewsNeedingLoading.Add(element.View); } foreach (var view in viewsNeedingLoading) { view.EnsureIsLoaded(); } viewsNeedingLoading.Clear(); registeredElements.Sort(uiElementComparer); foreach (var registeredElement in registeredElements) { var element = (UIElement)registeredElement.Target; if (element == null) { deadReferences.Add(registeredElement); continue; } if (element.View == null) continue; var bounds = default(RectangleD); var effect = element.Effect; var rtarget = element.OutOfBandRenderTarget.Value; if (rtarget.ResizeForElement(element, out bounds)) { for (var current = rtarget.Next; current != null; current = current.Next) current.Resize(rtarget.Width, rtarget.Height); } graphics.SetRenderTarget(rtarget.RenderTarget); graphics.Clear(Color.Transparent); var popup = element as Popup; if (popup != null) { if (!popup.IsOpen) continue; element = popup.Root; } if (!element.TransformedVisualBounds.IsEmpty && !IsVisuallyDisconnectedFromRoot(element)) { drawingContext.Reset(element.View.Display); var visualParent = VisualTreeHelper.GetParent(element) as UIElement; var visualTransformOfParent = (visualParent == null) ? popup.PopupTransformToView : visualParent.GetVisualTransformMatrix(); var visualTransformOfElement = element.GetVisualTransformMatrix(ref visualTransformOfParent); rtarget.VisualTransform = visualTransformOfElement; rtarget.VisualBounds = bounds; currentElementDrawingRenderTarget = element; element.DrawToRenderTarget(time, drawingContext, rtarget.RenderTarget, (popup != null) ? popup.PopupTransformToViewInDevicePixels : visualTransformOfParent); if (rtarget.Next != null) { if (effect != null) { effect.DrawRenderTargets(drawingContext, element, rtarget); } } currentElementDrawingRenderTarget = null; rtarget.IsReady = true; } } foreach (var deadReference in deadReferences) registeredElements.Remove(deadReference); } finally { isDrawingRenderTargets = false; currentElementDrawingRenderTarget = null; } deadReferences.Clear(); graphics.SetRenderTarget(null); graphics.Clear(Color.Transparent); upf.PerformanceStats.EndDraw(); }
/// <summary> /// Gets the render target that represents the specified element. /// </summary> /// <param name="element">The element for which to retrieve a render target.</param> /// <returns>The render target associated with the specified out-of-band element, or <c>null if the element is /// not registered for out-of-band rendering.</c></returns> public OutOfBandRenderTarget GetElementRenderTarget(UIElement element) { Contract.Require(element, nameof(element)); Contract.EnsureNotDisposed(this, Disposed); var pooledObject = element.OutOfBandRenderTarget; return (pooledObject == null) ? null : pooledObject.Value; }