// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System.ComponentModel; namespace FlaxEngine.GUI { /// /// The basic GUI label control. /// /// public class Label : ContainerControl { /// /// The text. /// 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); /// /// The font. /// protected FontReference _font; /// /// Gets or sets the text. /// [EditorOrder(10), MultilineText, Tooltip("The label text.")] public LocalizedString Text { get => _text; set { if (_text != value) { _text = value; _textSize = Float2.Zero; PerformLayout(); } } } /// /// Gets or sets the color of the text. /// [EditorDisplay("Text Style"), EditorOrder(2010), Tooltip("The color of the text."), ExpandGroups] public Color TextColor { get; set; } /// /// Gets or sets the color of the text when it is highlighted (mouse is over). /// [EditorDisplay("Text Style"), EditorOrder(2011), 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("Text Style"), EditorOrder(2020), 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("Text Style"), EditorOrder(2021), 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("Text Style"), EditorOrder(2022), Tooltip("The text wrapping within the control bounds.")] public TextWrapping Wrapping { get; set; } = TextWrapping.NoWrap; /// /// Gets or sets the text wrapping within the control bounds. /// [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; /// /// Gets or sets the font. /// [EditorDisplay("Text Style"), EditorOrder(2024)] public FontReference Font { get => _font; set { if (_font != value) { _font = value; if (_autoWidth || _autoHeight || _autoFitText) { _textSize = Float2.Zero; PerformLayout(); } } } } /// /// 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("Text Style"), EditorOrder(2025)] 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(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; } /// /// 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.Foreground; TextColorHighlighted = style.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.Foreground; TextColorHighlighted = style.Foreground; } /// public override void Draw() { base.Draw(); 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(); } /// 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(); } } }