// Copyright (c) The Perspex Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; using System.Reactive; using System.Reactive.Linq; using Perspex.Media; namespace Perspex.Controls { /// /// A control that displays a block of text. /// public class TextBlock : Control { /// /// Defines the property. /// public static readonly PerspexProperty BackgroundProperty = Border.BackgroundProperty.AddOwner(); /// /// Defines the property. /// public static readonly PerspexProperty FontFamilyProperty = PerspexProperty.RegisterAttached( nameof(FontFamily), inherits: true); /// /// Defines the property. /// public static readonly PerspexProperty FontSizeProperty = PerspexProperty.RegisterAttached( nameof(FontSize), inherits: true); /// /// Defines the property. /// public static readonly PerspexProperty FontStyleProperty = PerspexProperty.RegisterAttached( nameof(FontStyle), inherits: true); /// /// Defines the property. /// public static readonly PerspexProperty FontWeightProperty = PerspexProperty.RegisterAttached( nameof(FontWeight), inherits: true, defaultValue: FontWeight.Normal); /// /// Defines the property. /// public static readonly PerspexProperty ForegroundProperty = PerspexProperty.RegisterAttached( nameof(Foreground), new SolidColorBrush(0xff000000), inherits: true); /// /// Defines the property. /// public static readonly PerspexProperty TextProperty = PerspexProperty.Register(nameof(Text), defaultBindingMode: BindingMode.TwoWay); /// /// Defines the property. /// public static readonly PerspexProperty TextAlignmentProperty = PerspexProperty.Register(nameof(TextAlignment)); /// /// Defines the property. /// public static readonly PerspexProperty TextWrappingProperty = PerspexProperty.Register(nameof(TextWrapping)); /// /// The formatted text used for rendering. /// private FormattedText _formattedText; /// /// Stores the last constraint passed to MeasureOverride. /// private Size _constraint; /// /// Initializes static members of the class. /// static TextBlock() { AffectsRender(ForegroundProperty); } /// /// Initializes a new instance of the class. /// public TextBlock() { Observable.Merge( GetObservable(TextProperty).Select(_ => Unit.Default), GetObservable(TextAlignmentProperty).Select(_ => Unit.Default), GetObservable(FontSizeProperty).Select(_ => Unit.Default), GetObservable(FontStyleProperty).Select(_ => Unit.Default)) .Subscribe(_ => { InvalidateFormattedText(); }); } /// /// Gets or sets a brush used to paint the control's background. /// public Brush Background { get { return GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } /// /// Gets or sets the text. /// public string Text { get { return GetValue(TextProperty); } set { SetValue(TextProperty, value); } } /// /// Gets or sets the font family. /// public string FontFamily { get { return GetValue(FontFamilyProperty); } set { SetValue(FontFamilyProperty, value); } } /// /// Gets or sets the font size. /// public double FontSize { get { return GetValue(FontSizeProperty); } set { SetValue(FontSizeProperty, value); } } /// /// Gets or sets the font style. /// public FontStyle FontStyle { get { return GetValue(FontStyleProperty); } set { SetValue(FontStyleProperty, value); } } /// /// Gets or sets the font weight. /// public FontWeight FontWeight { get { return GetValue(FontWeightProperty); } set { SetValue(FontWeightProperty, value); } } /// /// Gets or sets a brush used to paint the text. /// public Brush Foreground { get { return GetValue(ForegroundProperty); } set { SetValue(ForegroundProperty, value); } } /// /// Gets the used to render the text. /// public FormattedText FormattedText { get { if (_formattedText == null) { _formattedText = CreateFormattedText(_constraint); } return _formattedText; } } /// /// Gets or sets the control's text wrapping mode. /// public TextWrapping TextWrapping { get { return GetValue(TextWrappingProperty); } set { SetValue(TextWrappingProperty, value); } } /// /// Gets or sets the text alignment. /// public TextAlignment TextAlignment { get { return GetValue(TextAlignmentProperty); } set { SetValue(TextAlignmentProperty, value); } } /// /// Gets the value of the attached on a control. /// /// The control. /// The font family. public static string GetFontFamily(Control control) { return control.GetValue(FontFamilyProperty); } /// /// Gets the value of the attached on a control. /// /// The control. /// The font family. public static double GetFontSize(Control control) { return control.GetValue(FontSizeProperty); } /// /// Gets the value of the attached on a control. /// /// The control. /// The font family. public static FontStyle GetFontStyle(Control control) { return control.GetValue(FontStyleProperty); } /// /// Gets the value of the attached on a control. /// /// The control. /// The font family. public static FontWeight GetFontWeight(Control control) { return control.GetValue(FontWeightProperty); } /// /// Sets the value of the attached on a control. /// /// The control. /// The property value to set. /// The font family. public static void SetFontFamily(Control control, string value) { control.SetValue(FontFamilyProperty, value); } /// /// Sets the value of the attached on a control. /// /// The control. /// The property value to set. /// The font family. public static void SetFontSize(Control control, double value) { control.SetValue(FontSizeProperty, value); } /// /// Sets the value of the attached on a control. /// /// The control. /// The property value to set. /// The font family. public static void SetFontStyle(Control control, FontStyle value) { control.SetValue(FontStyleProperty, value); } /// /// Sets the value of the attached on a control. /// /// The control. /// The property value to set. /// The font family. public static void SetFontWeight(Control control, FontWeight value) { control.SetValue(FontWeightProperty, value); } /// /// Renders the to a drawing context. /// /// The drawing context. public override void Render(DrawingContext context) { Brush background = Background; if (background != null) { context.FillRectangle(background, new Rect(Bounds.Size)); } FormattedText.Constraint = Bounds.Size; context.DrawText(Foreground, new Point(), FormattedText); } /// /// Creates the used to render the text. /// /// The constraint of the text. /// A object. protected virtual FormattedText CreateFormattedText(Size constraint) { var result = new FormattedText( Text ?? string.Empty, FontFamily ?? "Arial", FontSize > 0 ? FontSize : 12, FontStyle, TextAlignment, FontWeight); result.Constraint = constraint; return result; } /// /// Invalidates . /// protected void InvalidateFormattedText() { if (_formattedText != null) { _constraint = _formattedText.Constraint; _formattedText.Dispose(); _formattedText = null; } InvalidateMeasure(); } /// /// Measures the control. /// /// The available size for the control. /// The desired size. protected override Size MeasureOverride(Size availableSize) { if (!string.IsNullOrEmpty(Text)) { if (TextWrapping == TextWrapping.Wrap) { FormattedText.Constraint = new Size(availableSize.Width, double.PositiveInfinity); } else { FormattedText.Constraint = Size.Infinity; } return FormattedText.Measure(); } return new Size(); } } }