// ----------------------------------------------------------------------- // // Copyright 2015 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Controls.Primitives { using System; using Perspex.Input; using Perspex.Media; using Perspex.Rendering; /// /// A text block that displays a character prefixed with an underscore as an access key. /// public class AccessText : TextBlock { /// /// Defines the attached property. /// public static readonly PerspexProperty ShowAccessKeyProperty = PerspexProperty.RegisterAttached("ShowAccessKey", inherits: true); /// /// The access key handler for the current window. /// private IAccessKeyHandler accessKeys; /// /// Initializes static members of the class. /// static AccessText() { AffectsRender(ShowAccessKeyProperty); } /// /// Initializes a new instance of the class. /// public AccessText() { this.GetObservable(TextProperty).Subscribe(this.TextChanged); } /// /// Gets the access key. /// public char AccessKey { get; private set; } /// /// Gets or sets a value indicating whether the access key should be underlined. /// public bool ShowAccessKey { get { return this.GetValue(ShowAccessKeyProperty); } set { this.SetValue(ShowAccessKeyProperty, value); } } /// /// Renders the to a drawing context. /// /// The drawing context. public override void Render(IDrawingContext context) { base.Render(context); int underscore = this.Text?.IndexOf('_') ?? -1; if (underscore != -1 && this.ShowAccessKey) { var rect = this.FormattedText.HitTestTextPosition(underscore); var offset = new Vector(0, -0.5); context.DrawLine( new Pen(this.Foreground, 1), rect.BottomLeft + offset, rect.BottomRight + offset); } } /// /// Creates the used to render the text. /// /// The constraint of the text. /// A object. protected override FormattedText CreateFormattedText(Size constraint) { var result = new FormattedText( this.StripAccessKey(this.Text), this.FontFamily, this.FontSize, this.FontStyle, this.TextAlignment, this.FontWeight); result.Constraint = constraint; return result; } /// /// Measures the control. /// /// The available size for the control. /// The desired size. protected override Size MeasureOverride(Size availableSize) { var result = base.MeasureOverride(availableSize); return result.WithHeight(result.Height + 1); } /// /// Called when the control is attached to a visual tree. /// /// The root of the visual tree. protected override void OnAttachedToVisualTree(IRenderRoot root) { base.OnAttachedToVisualTree(root); this.accessKeys = (root as IInputRoot)?.AccessKeyHandler; if (this.accessKeys != null && this.AccessKey != 0) { this.accessKeys.Register(this.AccessKey, this); } } /// /// Called when the control is detached from a visual tree. /// /// The root of the visual tree. protected override void OnDetachedFromVisualTree(IRenderRoot root) { base.OnDetachedFromVisualTree(root); if (this.accessKeys != null && this.AccessKey != 0) { this.accessKeys.Unregister(this); this.accessKeys = null; } } /// /// Returns a string with the first underscore stripped. /// /// The text. /// The text with the first underscore stripped. private string StripAccessKey(string text) { var position = text.IndexOf('_'); if (position == -1) { return text; } else { return text.Substring(0, position) + text.Substring(position + 1); } } /// /// Called when the property changes. /// /// The new text. private void TextChanged(string text) { var key = (char)0; if (text != null) { int underscore = text.IndexOf('_'); if (underscore != -1 && underscore < text.Length - 1) { key = text[underscore + 1]; } } this.AccessKey = key; if (this.accessKeys != null && this.AccessKey != 0) { this.accessKeys.Register(this.AccessKey, this); } } } }