A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

468 lines
16 KiB

// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Reactive.Linq;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
using Avalonia.Metadata;
namespace Avalonia.Controls
{
/// <summary>
/// A control that displays a block of text.
/// </summary>
public class TextBlock : Control
{
/// <summary>
/// Defines the <see cref="Background"/> property.
/// </summary>
public static readonly StyledProperty<IBrush> BackgroundProperty =
Border.BackgroundProperty.AddOwner<TextBlock>();
/// <summary>
/// Defines the <see cref="Padding"/> property.
/// </summary>
public static readonly StyledProperty<Thickness> PaddingProperty =
Decorator.PaddingProperty.AddOwner<TextBlock>();
// TODO: Define these attached properties elsewhere (e.g. on a Text class) and AddOwner
// them into TextBlock.
/// <summary>
/// Defines the <see cref="FontFamily"/> property.
/// </summary>
public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, FontFamily>(
nameof(FontFamily),
defaultValue: FontFamily.Default,
inherits: true);
/// <summary>
/// Defines the <see cref="FontSize"/> property.
/// </summary>
public static readonly AttachedProperty<double> FontSizeProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, double>(
nameof(FontSize),
defaultValue: 12,
inherits: true);
/// <summary>
/// Defines the <see cref="FontStyle"/> property.
/// </summary>
public static readonly AttachedProperty<FontStyle> FontStyleProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, FontStyle>(
nameof(FontStyle),
inherits: true);
/// <summary>
/// Defines the <see cref="FontWeight"/> property.
/// </summary>
public static readonly AttachedProperty<FontWeight> FontWeightProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, FontWeight>(
nameof(FontWeight),
inherits: true,
defaultValue: FontWeight.Normal);
/// <summary>
/// Defines the <see cref="Foreground"/> property.
/// </summary>
public static readonly AttachedProperty<IBrush> ForegroundProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, IBrush>(
nameof(Foreground),
Brushes.Black,
inherits: true);
/// <summary>
/// Defines the <see cref="Text"/> property.
/// </summary>
public static readonly DirectProperty<TextBlock, string> TextProperty =
AvaloniaProperty.RegisterDirect<TextBlock, string>(
nameof(Text),
o => o.Text,
(o, v) => o.Text = v);
/// <summary>
/// Defines the <see cref="TextAlignment"/> property.
/// </summary>
public static readonly StyledProperty<TextAlignment> TextAlignmentProperty =
AvaloniaProperty.Register<TextBlock, TextAlignment>(nameof(TextAlignment));
/// <summary>
/// Defines the <see cref="TextWrapping"/> property.
/// </summary>
public static readonly StyledProperty<TextWrapping> TextWrappingProperty =
AvaloniaProperty.Register<TextBlock, TextWrapping>(nameof(TextWrapping));
/// <summary>
/// Defines the <see cref="TextTrimming"/> property.
/// </summary>
public static readonly StyledProperty<TextTrimming> TextTrimmingProperty =
AvaloniaProperty.Register<TextBlock, TextTrimming>(nameof(TextTrimming));
/// <summary>
/// Defines the <see cref="TextDecorations"/> property.
/// </summary>
public static readonly StyledProperty<TextDecorationCollection> TextDecorationsProperty =
AvaloniaProperty.Register<TextBlock, TextDecorationCollection>(nameof(TextDecorations));
private string _text;
private TextLayout _textLayout;
private Size _constraint;
/// <summary>
/// Initializes static members of the <see cref="TextBlock"/> class.
/// </summary>
static TextBlock()
{
ClipToBoundsProperty.OverrideDefaultValue<TextBlock>(true);
AffectsRender<TextBlock>(
BackgroundProperty, ForegroundProperty, FontSizeProperty,
FontWeightProperty, FontStyleProperty, TextWrappingProperty,
TextTrimmingProperty, TextAlignmentProperty, FontFamilyProperty,
TextDecorationsProperty, TextProperty, PaddingProperty);
AffectsMeasure<TextBlock>(
FontSizeProperty, FontWeightProperty, FontStyleProperty,
FontFamilyProperty, TextTrimmingProperty, TextProperty,
PaddingProperty);
Observable.Merge(
TextProperty.Changed,
ForegroundProperty.Changed,
TextAlignmentProperty.Changed,
TextWrappingProperty.Changed,
TextTrimmingProperty.Changed,
FontSizeProperty.Changed,
FontStyleProperty.Changed,
FontWeightProperty.Changed,
FontFamilyProperty.Changed,
TextDecorationsProperty.Changed,
PaddingProperty.Changed
).AddClassHandler<TextBlock>((x, _) => x.InvalidateTextLayout());
}
/// <summary>
/// Initializes a new instance of the <see cref="TextBlock"/> class.
/// </summary>
public TextBlock()
{
_text = string.Empty;
}
/// <summary>
/// Gets the <see cref="TextLayout"/> used to render the text.
/// </summary>
public TextLayout TextLayout
{
get
{
return _textLayout ?? (_textLayout = CreateTextLayout(_constraint, Text));
}
}
/// <summary>
/// Gets or sets the padding to place around the <see cref="Text"/>.
/// </summary>
public Thickness Padding
{
get { return GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}
/// <summary>
/// Gets or sets a brush used to paint the control's background.
/// </summary>
public IBrush Background
{
get { return GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
/// <summary>
/// Gets or sets the text.
/// </summary>
[Content]
public string Text
{
get { return _text; }
set { SetAndRaise(TextProperty, ref _text, value); }
}
/// <summary>
/// Gets or sets the font family.
/// </summary>
public FontFamily FontFamily
{
get { return GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); }
}
/// <summary>
/// Gets or sets the font size.
/// </summary>
public double FontSize
{
get { return GetValue(FontSizeProperty); }
set { SetValue(FontSizeProperty, value); }
}
/// <summary>
/// Gets or sets the font style.
/// </summary>
public FontStyle FontStyle
{
get { return GetValue(FontStyleProperty); }
set { SetValue(FontStyleProperty, value); }
}
/// <summary>
/// Gets or sets the font weight.
/// </summary>
public FontWeight FontWeight
{
get { return GetValue(FontWeightProperty); }
set { SetValue(FontWeightProperty, value); }
}
/// <summary>
/// Gets or sets a brush used to paint the text.
/// </summary>
public IBrush Foreground
{
get { return GetValue(ForegroundProperty); }
set { SetValue(ForegroundProperty, value); }
}
/// <summary>
/// Gets or sets the control's text wrapping mode.
/// </summary>
public TextWrapping TextWrapping
{
get { return GetValue(TextWrappingProperty); }
set { SetValue(TextWrappingProperty, value); }
}
/// <summary>
/// Gets or sets the control's text trimming mode.
/// </summary>
public TextTrimming TextTrimming
{
get { return GetValue(TextTrimmingProperty); }
set { SetValue(TextTrimmingProperty, value); }
}
/// <summary>
/// Gets or sets the text alignment.
/// </summary>
public TextAlignment TextAlignment
{
get { return GetValue(TextAlignmentProperty); }
set { SetValue(TextAlignmentProperty, value); }
}
/// <summary>
/// Gets or sets the text decorations.
/// </summary>
public TextDecorationCollection TextDecorations
{
get => GetValue(TextDecorationsProperty);
set => SetValue(TextDecorationsProperty, value);
}
/// <summary>
/// Gets the value of the attached <see cref="FontFamilyProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font family.</returns>
public static FontFamily GetFontFamily(Control control)
{
return control.GetValue(FontFamilyProperty);
}
/// <summary>
/// Gets the value of the attached <see cref="FontSizeProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font family.</returns>
public static double GetFontSize(Control control)
{
return control.GetValue(FontSizeProperty);
}
/// <summary>
/// Gets the value of the attached <see cref="FontStyleProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font family.</returns>
public static FontStyle GetFontStyle(Control control)
{
return control.GetValue(FontStyleProperty);
}
/// <summary>
/// Gets the value of the attached <see cref="FontWeightProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font family.</returns>
public static FontWeight GetFontWeight(Control control)
{
return control.GetValue(FontWeightProperty);
}
/// <summary>
/// Gets the value of the attached <see cref="ForegroundProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The foreground.</returns>
public static IBrush GetForeground(Control control)
{
return control.GetValue(ForegroundProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FontFamilyProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
/// <returns>The font family.</returns>
public static void SetFontFamily(Control control, FontFamily value)
{
control.SetValue(FontFamilyProperty, value);
}
/// <summary>
/// Sets the value of the attached <see cref="FontSizeProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
/// <returns>The font family.</returns>
public static void SetFontSize(Control control, double value)
{
control.SetValue(FontSizeProperty, value);
}
/// <summary>
/// Sets the value of the attached <see cref="FontStyleProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
/// <returns>The font family.</returns>
public static void SetFontStyle(Control control, FontStyle value)
{
control.SetValue(FontStyleProperty, value);
}
/// <summary>
/// Sets the value of the attached <see cref="FontWeightProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
/// <returns>The font family.</returns>
public static void SetFontWeight(Control control, FontWeight value)
{
control.SetValue(FontWeightProperty, value);
}
/// <summary>
/// Sets the value of the attached <see cref="ForegroundProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
/// <returns>The font family.</returns>
public static void SetForeground(Control control, IBrush value)
{
control.SetValue(ForegroundProperty, value);
}
/// <summary>
/// Renders the <see cref="TextBlock"/> to a drawing context.
/// </summary>
/// <param name="context">The drawing context.</param>
public override void Render(DrawingContext context)
{
var background = Background;
if (background != null)
{
context.FillRectangle(background, new Rect(Bounds.Size));
}
var padding = Padding;
TextLayout?.Draw(context.PlatformImpl, new Point(padding.Left, padding.Top));
}
/// <summary>
/// Creates the <see cref="TextLayout"/> used to render the text.
/// </summary>
/// <param name="constraint">The constraint of the text.</param>
/// <param name="text">The text to format.</param>
/// <returns>A <see cref="TextLayout"/> object.</returns>
protected virtual TextLayout CreateTextLayout(Size constraint, string text)
{
if (constraint == Size.Empty)
{
return null;
}
return new TextLayout(
text ?? string.Empty,
FontManager.Current?.GetOrAddTypeface(FontFamily, FontWeight, FontStyle),
FontSize,
Foreground,
TextAlignment,
TextWrapping,
TextTrimming,
TextDecorations,
constraint.Width,
constraint.Height);
}
/// <summary>
/// Invalidates <see cref="TextLayout"/>.
/// </summary>
protected void InvalidateTextLayout()
{
_textLayout = null;
}
/// <summary>
/// Measures the control.
/// </summary>
/// <param name="availableSize">The available size for the control.</param>
/// <returns>The desired size.</returns>
protected override Size MeasureOverride(Size availableSize)
{
if (string.IsNullOrEmpty(Text))
{
return new Size();
}
var padding = Padding;
availableSize = availableSize.Deflate(padding);
if (_constraint != availableSize)
{
InvalidateTextLayout();
}
_constraint = availableSize;
var measuredSize = TextLayout?.Bounds.Size ?? Size.Empty;
return measuredSize.Inflate(padding);
}
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
InvalidateTextLayout();
InvalidateMeasure();
}
}
}