| File: Microsoft\Windows\Controls\KeyTipAdorner.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\System.Windows.Controls.Ribbon\System.Windows.Controls.Ribbon.csproj (System.Windows.Controls.Ribbon) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Windows.Documents; using System.Windows.Media; #if RIBBON_IN_FRAMEWORK using System.Windows.Controls.Ribbon; #else using Microsoft.Windows.Controls.Ribbon; #endif using MS.Internal; #if RIBBON_IN_FRAMEWORK namespace System.Windows.Controls #else namespace Microsoft.Windows.Controls #endif { /// <summary> /// The adorner control which is used to render KeyTip /// </summary> internal class KeyTipAdorner : Adorner { #region Constructor public KeyTipAdorner(UIElement adornedElement, UIElement placementTarget, KeyTipHorizontalPlacement horizontalPlacement, KeyTipVerticalPlacement verticalPlacement, double horizontalOffset, double verticalOffset, RibbonGroup ownerRibbonGroup) : base(adornedElement) { PlacementTarget = (placementTarget ?? adornedElement); HorizontalPlacement = horizontalPlacement; VerticalPlacement = verticalPlacement; HorizontalOffset = horizontalOffset; VerticalOffset = verticalOffset; OwnerRibbonGroup = ownerRibbonGroup; } #endregion #region Basic Adorner protected override Visual GetVisualChild(int index) { if (index != 0 || _keyTipControl == null) { throw new ArgumentOutOfRangeException(nameof(index)); } return _keyTipControl; } protected override int VisualChildrenCount { get { return (_keyTipControl == null ? 0 : 1); } } protected override Size MeasureOverride(Size constraint) { if (_keyTipControl != null) { Size childConstraint = new Size(Double.PositiveInfinity, Double.PositiveInfinity); _keyTipControl.Measure(childConstraint); } return new Size(0, 0); } protected override Size ArrangeOverride(Size finalSize) { _keyTipControl?.Arrange(new Rect(_keyTipControl.DesiredSize)); return finalSize; } #endregion #region KeyTipControl Management /// <summary> /// Links the given KeyTipControl as the visual child of self. /// In the process sets various properties of the control. /// </summary> public void LinkKeyTipControl(DependencyObject keyTipElement, KeyTipControl keyTipControl) { Debug.Assert(_keyTipControl == null && keyTipControl.KeyTipAdorner == null); _keyTipControl = keyTipControl; _keyTipControl.KeyTipAdorner = this; _keyTipControl.Text = KeyTipService.GetKeyTip(keyTipElement).ToUpper(KeyTipService.GetCultureForElement(keyTipElement)); _keyTipControl.IsEnabled = (bool)keyTipElement.GetValue(UIElement.IsEnabledProperty); Style keyTipStyle = KeyTipService.GetKeyTipStyle(keyTipElement); _keyTipControl.Style = keyTipStyle; _keyTipControl.RenderTransform = _keyTipTransform; bool clearCustomProperties = true; if (keyTipStyle == null) { Ribbon.Ribbon ribbon = RibbonControlService.GetRibbon(PlacementTarget); if (ribbon != null) { // Use Ribbon properties if the owner element belongs to a Ribbon. keyTipStyle = KeyTipService.GetKeyTipStyle(ribbon); if (keyTipStyle != null) { _keyTipControl.Style = keyTipStyle; } else { clearCustomProperties = false; _keyTipControl.Background = ribbon.Background; _keyTipControl.BorderBrush = ribbon.BorderBrush; _keyTipControl.Foreground = ribbon.Foreground; } } } if (clearCustomProperties) { _keyTipControl.ClearValue(Control.BackgroundProperty); _keyTipControl.ClearValue(Control.BorderBrushProperty); _keyTipControl.ClearValue(Control.ForegroundProperty); } AddVisualChild(_keyTipControl); EnsureTransform(); } /// <summary> /// Unlinks the earlier linked KeyTipControl from visual tree. /// </summary> public void UnlinkKeyTipControl() { if (_keyTipControl != null) { _keyTipControl.KeyTipAdorner = null; RemoveVisualChild(_keyTipControl); _keyTipControl = null; } } public KeyTipControl KeyTipControl { get { return _keyTipControl; } } #endregion #region KeyTip Placement private KeyTipHorizontalPlacement HorizontalPlacement { get; set; } private KeyTipVerticalPlacement VerticalPlacement { get; set; } private double HorizontalOffset { get; set; } private double VerticalOffset { get; set; } private UIElement PlacementTarget { get; set; } private RibbonGroup OwnerRibbonGroup { get; set; } /// <summary> /// Invalidate X/Y properties of keytip transform /// when size of KeyTipControl changes accordingly. /// </summary> /// <param name="e"></param> internal void OnKeyTipControlSizeChanged(SizeChangedEventArgs e) { if (e.WidthChanged) { EnsureTransformX(); } if (e.HeightChanged) { EnsureTransformY(); } } private void EnsureTransform() { EnsureTransformX(); EnsureTransformY(); } /// <summary> /// Updates X of keytip transform. /// </summary> private void EnsureTransformX() { UIElement placementTarget = PlacementTarget; if (placementTarget != null) { int horizontalPlacementValue = (int)HorizontalPlacement; double horizontalPosition = 0; if (horizontalPlacementValue >= 0 && horizontalPlacementValue < 9) { switch (horizontalPlacementValue % 3) { case 1: // compensate horizontal position for center of target horizontalPosition += (placementTarget.RenderSize.Width / 2); break; case 2: // compensate horizontal position for right of target horizontalPosition += placementTarget.RenderSize.Width; break; } if (_keyTipControl != null) { if (horizontalPlacementValue >= 6) { // compensate horizontal position for right of keytip horizontalPosition -= _keyTipControl.ActualWidth; } else if (horizontalPlacementValue >= 3) { // compensate horizontal position for center of keytip horizontalPosition -= (_keyTipControl.ActualWidth / 2); } } } horizontalPosition += HorizontalOffset; _keyTipTransform.X = horizontalPosition; } else { _keyTipTransform.X = 0; } } /// <summary> /// Updates Y of keytip transform. /// </summary> private void EnsureTransformY() { UIElement placementTarget = PlacementTarget; if (placementTarget == null) { placementTarget = AdornedElement; } if (placementTarget != null) { int verticalPlacementValue = (int)VerticalPlacement; double verticalPosition = 0; if (verticalPlacementValue >= 0 && verticalPlacementValue < 9) { switch (verticalPlacementValue % 3) { case 1: // compensate vertical position for center of target verticalPosition += (placementTarget.RenderSize.Height / 2); break; case 2: // compensate vertical position for bottom of target verticalPosition += placementTarget.RenderSize.Height; break; } if (_keyTipControl != null) { if (verticalPlacementValue >= 6) { // compensate vertical position for bottom of keytip verticalPosition -= _keyTipControl.ActualHeight; } else if (verticalPlacementValue >= 3) { // compensate vertical position for center of keytip verticalPosition -= (_keyTipControl.ActualHeight / 2); } } } verticalPosition += VerticalOffset; verticalPosition = NudgeToRibbonGroupAxis(placementTarget, verticalPosition); _keyTipTransform.Y = verticalPosition; } else { _keyTipTransform.Y = 0; } } /// <summary> /// Helper method to nudge the vertical postion of keytip, /// to RibbonGroup's top/bottom axis if applicable. /// </summary> private double NudgeToRibbonGroupAxis(UIElement placementTarget, double verticalPosition) { if (OwnerRibbonGroup != null) { ItemsPresenter itemsPresenter = OwnerRibbonGroup.ItemsPresenter; if (itemsPresenter != null) { GeneralTransform transform = placementTarget.TransformToAncestor(itemsPresenter); Point targetOrigin = transform.Transform(new Point()); double keyTipTopY = verticalPosition + targetOrigin.Y; double keyTipCenterY = keyTipTopY; double keyTipBottomY = keyTipTopY; if (_keyTipControl != null) { keyTipBottomY += _keyTipControl.ActualHeight; keyTipCenterY += _keyTipControl.ActualHeight / 2; } if (DoubleUtil.LessThan(Math.Abs(keyTipTopY), RibbonGroupKeyTipAxisNudgeSpace)) { // Nudge to top axis verticalPosition -= (keyTipCenterY - RibbonGroupKeyTipAxisOffset); } else if (DoubleUtil.LessThan(Math.Abs(itemsPresenter.ActualHeight - keyTipBottomY), RibbonGroupKeyTipAxisNudgeSpace)) { // Nudge to bottom axis double centerOffsetFromGroupBottom = keyTipCenterY - itemsPresenter.ActualHeight; verticalPosition -= (centerOffsetFromGroupBottom + RibbonGroupKeyTipAxisOffset); } } } return verticalPosition; } /// <summary> /// Helper method to nudge the keytip into the /// boundary of the adorner layer. /// </summary> internal void NudgeIntoAdornerLayerBoundary(AdornerLayer adornerLayer) { if (_keyTipControl != null && _keyTipControl.IsLoaded) { Point adornerOrigin = this.TranslatePoint(new Point(), adornerLayer); Rect adornerLayerRect = new Rect(0, 0, adornerLayer.ActualWidth, adornerLayer.ActualHeight); Rect keyTipControlRect = new Rect(adornerOrigin.X + _keyTipTransform.X, adornerOrigin.Y + _keyTipTransform.Y, _keyTipControl.ActualWidth, _keyTipControl.ActualHeight); if (adornerLayerRect.IntersectsWith(keyTipControlRect) && !adornerLayerRect.Contains(keyTipControlRect)) { double deltaX = 0; double deltaY = 0; // Nudge the keytip control horizontally if its left or right // edge falls outside the adornerlayer. if (DoubleUtil.LessThan(keyTipControlRect.Left, adornerLayerRect.Left)) { deltaX = adornerLayerRect.Left - keyTipControlRect.Left; } else if (DoubleUtil.GreaterThan(keyTipControlRect.Right, adornerLayerRect.Right)) { deltaX = adornerLayerRect.Right - keyTipControlRect.Right; } // Nudge the keytip control vertically if its top or bottom // edge falls outside the adornerlayer. if (DoubleUtil.LessThan(keyTipControlRect.Top, adornerLayerRect.Top)) { deltaY = adornerLayerRect.Top - keyTipControlRect.Top; } else if (DoubleUtil.GreaterThan(keyTipControlRect.Bottom, adornerLayerRect.Bottom)) { deltaY = adornerLayerRect.Bottom - keyTipControlRect.Bottom; } _keyTipTransform.X += deltaX; _keyTipTransform.Y += deltaY; } } } #endregion #region Private Data private KeyTipControl _keyTipControl; private TranslateTransform _keyTipTransform = new TranslateTransform(0, 0); private const double RibbonGroupKeyTipAxisNudgeSpace = 15; private const double RibbonGroupKeyTipAxisOffset = 5; #endregion } }