// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System.ComponentModel;
namespace FlaxEngine.GUI
{
///
/// The basic GUI label control.
///
///
public class Label : ContainerControl
{
private string _text;
private bool _autoWidth;
private bool _autoHeight;
private bool _autoFitText;
private Vector2 _textSize;
private Vector2 _autoFitTextRange = new Vector2(0.1f, 100.0f);
///
/// The font.
///
protected FontReference _font;
///
/// Gets or sets the text.
///
[EditorOrder(10), MultilineText, Tooltip("The label text.")]
public string Text
{
get => _text;
set
{
if (_text != value)
{
_text = value;
_textSize = Vector2.Zero;
PerformLayout();
}
}
}
///
/// Gets or sets the color of the text.
///
[EditorDisplay("Style"), EditorOrder(2000), Tooltip("The color of the text.")]
public Color TextColor { get; set; }
///
/// Gets or sets the color of the text when it is highlighted (mouse is over).
///
[EditorDisplay("Style"), EditorOrder(2000), Tooltip("The color of the text when it is highlighted (mouse is over).")]
public Color TextColorHighlighted { get; set; }
///
/// Gets or sets the horizontal text alignment within the control bounds.
///
[EditorDisplay("Style"), EditorOrder(2010), Tooltip("The horizontal text alignment within the control bounds.")]
public TextAlignment HorizontalAlignment { get; set; } = TextAlignment.Center;
///
/// Gets or sets the vertical text alignment within the control bounds.
///
[EditorDisplay("Style"), EditorOrder(2020), Tooltip("The vertical text alignment within the control bounds.")]
public TextAlignment VerticalAlignment { get; set; } = TextAlignment.Center;
///
/// Gets or sets the text wrapping within the control bounds.
///
[EditorDisplay("Style"), EditorOrder(2030), Tooltip("The text wrapping within the control bounds.")]
public TextWrapping Wrapping { get; set; } = TextWrapping.NoWrap;
///
/// Gets or sets the font.
///
[EditorDisplay("Style"), EditorOrder(2000)]
public FontReference Font
{
get => _font;
set => _font = value;
}
///
/// 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.
///
[EditorDisplay("Style"), EditorOrder(2000)]
public MaterialBase Material { get; set; }
///
/// Gets or sets the margin for the text within the control bounds.
///
[EditorOrder(70), Tooltip("The margin for the text within the control bounds.")]
public Margin Margin { get; set; }
///
/// Gets or sets a value indicating whether clip text during rendering.
///
[EditorOrder(80), DefaultValue(false), Tooltip("If checked, text will be clipped during rendering.")]
public bool ClipText { get; set; }
///
/// Gets or sets a value indicating whether set automatic width based on text contents.
///
[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();
}
}
}
///
/// Gets or sets a value indicating whether set automatic height based on text contents.
///
[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();
}
}
}
///
/// Gets or sets a value indicating whether scale text to fit the label control bounds. Disables using text alignment, automatic width and height.
///
[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();
}
}
}
///
/// Gets or sets the text scale range (min and max) for automatic fit text option. Can be used to constraint the text scale adjustment.
///
[VisibleIf(nameof(AutoFitText))]
[EditorOrder(110), DefaultValue(typeof(Vector2), "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 Vector2 AutoFitTextRange
{
get => _autoFitTextRange;
set => _autoFitTextRange = value;
}
///
/// Initializes a new instance of the class.
///
public Label()
: base(0, 0, 100, 20)
{
AutoFocus = false;
var style = Style.Current;
Font = new FontReference(style.FontMedium);
TextColor = Style.Current.Foreground;
TextColorHighlighted = Style.Current.Foreground;
}
///
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.Current.Foreground;
TextColorHighlighted = Style.Current.Foreground;
}
///
public override void Draw()
{
base.Draw();
var rect = new Rectangle(new Vector2(Margin.Left, Margin.Top), Size - Margin.Size);
if (ClipText)
Render2D.PushClip(new Rectangle(Vector2.Zero, Size));
var color = IsMouseOver ? TextColorHighlighted : TextColor;
if (!EnabledInHierarchy)
color *= 0.6f;
var scale = 1.0f;
var hAlignment = _autoWidth ? TextAlignment.Near : HorizontalAlignment;
var wAlignment = _autoHeight ? TextAlignment.Near : VerticalAlignment;
if (_autoFitText)
{
hAlignment = TextAlignment.Center;
wAlignment = TextAlignment.Center;
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,
1.0f,
scale
);
if (ClipText)
Render2D.PopClip();
}
///
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);
// 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();
}
}
}