Files
FlaxEngine/Source/Engine/UI/GUI/Common/Label.cs
2024-02-18 19:48:43 +01:00

277 lines
9.9 KiB
C#

// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System.ComponentModel;
namespace FlaxEngine.GUI
{
/// <summary>
/// The basic GUI label control.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
public class Label : ContainerControl
{
/// <summary>
/// The text.
/// </summary>
protected LocalizedString _text = new LocalizedString();
private bool _autoWidth;
private bool _autoHeight;
private bool _autoFitText;
private Float2 _textSize;
private Float2 _autoFitTextRange = new Float2(0.1f, 100.0f);
/// <summary>
/// The font.
/// </summary>
protected FontReference _font;
/// <summary>
/// Gets or sets the text.
/// </summary>
[EditorOrder(10), MultilineText, Tooltip("The label text.")]
public LocalizedString Text
{
get => _text;
set
{
if (_text != value)
{
_text = value;
_textSize = Float2.Zero;
PerformLayout();
}
}
}
/// <summary>
/// Gets or sets the color of the text.
/// </summary>
[EditorDisplay("Text Style"), EditorOrder(2010), Tooltip("The color of the text."), ExpandGroups]
public Color TextColor { get; set; }
/// <summary>
/// Gets or sets the color of the text when it is highlighted (mouse is over).
/// </summary>
[EditorDisplay("Text Style"), EditorOrder(2011), Tooltip("The color of the text when it is highlighted (mouse is over).")]
public Color TextColorHighlighted { get; set; }
/// <summary>
/// Gets or sets the horizontal text alignment within the control bounds.
/// </summary>
[EditorDisplay("Text Style"), EditorOrder(2020), Tooltip("The horizontal text alignment within the control bounds.")]
public TextAlignment HorizontalAlignment { get; set; } = TextAlignment.Center;
/// <summary>
/// Gets or sets the vertical text alignment within the control bounds.
/// </summary>
[EditorDisplay("Text Style"), EditorOrder(2021), Tooltip("The vertical text alignment within the control bounds.")]
public TextAlignment VerticalAlignment { get; set; } = TextAlignment.Center;
/// <summary>
/// Gets or sets the text wrapping within the control bounds.
/// </summary>
[EditorDisplay("Text Style"), EditorOrder(2022), Tooltip("The text wrapping within the control bounds.")]
public TextWrapping Wrapping { get; set; } = TextWrapping.NoWrap;
/// <summary>
/// Gets or sets the text wrapping within the control bounds.
/// </summary>
[EditorDisplay("Text Style"), EditorOrder(2023), Tooltip("The gap between lines when wrapping and more than a single line is displayed."), Limit(0f)]
public float BaseLinesGapScale { get; set; } = 1.0f;
/// <summary>
/// Gets or sets the font.
/// </summary>
[EditorDisplay("Text Style"), EditorOrder(2024)]
public FontReference Font
{
get => _font;
set
{
if (_font != value)
{
_font = value;
if (_autoWidth || _autoHeight || _autoFitText)
{
_textSize = Float2.Zero;
PerformLayout();
}
}
}
}
/// <summary>
/// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.
/// </summary>
[EditorDisplay("Text Style"), EditorOrder(2025)]
public MaterialBase Material { get; set; }
/// <summary>
/// Gets or sets the margin for the text within the control bounds.
/// </summary>
[EditorOrder(70), Tooltip("The margin for the text within the control bounds.")]
public Margin Margin { get; set; }
/// <summary>
/// Gets or sets a value indicating whether clip text during rendering.
/// </summary>
[EditorOrder(80), DefaultValue(false), Tooltip("If checked, text will be clipped during rendering.")]
public bool ClipText { get; set; }
/// <summary>
/// Gets or sets a value indicating whether set automatic width based on text contents.
/// </summary>
[EditorOrder(85), DefaultValue(false), Tooltip("If checked, the control width will be based on text contents.")]
public bool AutoWidth
{
get => _autoWidth;
set
{
if (_autoWidth != value)
{
_autoWidth = value;
PerformLayout();
}
}
}
/// <summary>
/// Gets or sets a value indicating whether set automatic height based on text contents.
/// </summary>
[EditorOrder(90), DefaultValue(false), Tooltip("If checked, the control height will be based on text contents.")]
public bool AutoHeight
{
get => _autoHeight;
set
{
if (_autoHeight != value)
{
_autoHeight = value;
PerformLayout();
}
}
}
/// <summary>
/// Gets or sets a value indicating whether scale text to fit the label control bounds. Disables using text alignment, automatic width and height.
/// </summary>
[EditorOrder(100), DefaultValue(false), Tooltip("If checked, enables scaling text to fit the label control bounds. Disables using text alignment, automatic width and height.")]
public bool AutoFitText
{
get => _autoFitText;
set
{
if (_autoFitText != value)
{
_autoFitText = value;
PerformLayout();
}
}
}
/// <summary>
/// Gets or sets the text scale range (min and max) for automatic fit text option. Can be used to constraint the text scale adjustment.
/// </summary>
[VisibleIf(nameof(AutoFitText))]
[EditorOrder(110), DefaultValue(typeof(Float2), "0.1, 100"), Tooltip("The text scale range (min and max) for automatic fit text option. Can be used to constraint the text scale adjustment.")]
public Float2 AutoFitTextRange
{
get => _autoFitTextRange;
set => _autoFitTextRange = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="Label"/> class.
/// </summary>
public Label()
: base(0, 0, 100, 20)
{
AutoFocus = false;
var style = Style.Current;
Font = new FontReference(style.FontMedium);
TextColor = style.Foreground;
TextColorHighlighted = style.Foreground;
}
/// <inheritdoc />
public Label(float x, float y, float width, float height)
: base(x, y, width, height)
{
AutoFocus = false;
var style = Style.Current;
Font = new FontReference(style.FontMedium);
TextColor = style.Foreground;
TextColorHighlighted = style.Foreground;
}
/// <inheritdoc />
public override void DrawSelf()
{
base.DrawSelf();
var rect = new Rectangle(new Float2(Margin.Left, Margin.Top), Size - Margin.Size);
if (ClipText)
Render2D.PushClip(new Rectangle(Float2.Zero, Size));
var color = IsMouseOver || IsNavFocused ? TextColorHighlighted : TextColor;
if (!EnabledInHierarchy)
color *= 0.6f;
var scale = 1.0f;
var hAlignment = HorizontalAlignment;
var wAlignment = VerticalAlignment;
if (_autoFitText)
{
if (!_textSize.IsZero)
{
scale = (rect.Size / _textSize).MinValue;
scale = Mathf.Clamp(scale, _autoFitTextRange.X, _autoFitTextRange.Y);
}
}
Render2D.DrawText(_font.GetFont(), Material, _text, rect, color, hAlignment, wAlignment, Wrapping, BaseLinesGapScale, scale);
if (ClipText)
Render2D.PopClip();
}
/// <inheritdoc />
protected override void PerformLayoutBeforeChildren()
{
if (_autoWidth || _autoHeight || _autoFitText)
{
var font = _font.GetFont();
if (font)
{
// Calculate text size
var layout = TextLayoutOptions.Default;
layout.TextWrapping = Wrapping;
if (_autoHeight && !_autoWidth)
layout.Bounds.Size.X = Width - Margin.Width;
else if (_autoWidth && !_autoHeight)
layout.Bounds.Size.Y = Height - Margin.Height;
_textSize = font.MeasureText(_text, ref layout);
_textSize.Y *= BaseLinesGapScale;
// Check if size is controlled via text
if (_autoWidth || _autoHeight)
{
var size = Size;
if (_autoWidth)
size.X = _textSize.X + Margin.Width;
if (_autoHeight)
size.Y = _textSize.Y + Margin.Height;
Size = size;
}
}
}
base.PerformLayoutBeforeChildren();
}
}
}