using System; using System.Collections.Generic; using Robust.Client.Graphics; using Robust.Client.Graphics.Drawing; using Robust.Shared.Animations; using Robust.Shared.Maths; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; namespace Robust.Client.UserInterface.Controls { /// /// A label is a GUI control that displays simple text. /// public class Label : Control { public const string StylePropertyFontColor = "font-color"; public const string StylePropertyFont = "font"; private int _cachedTextHeight; private readonly List _cachedTextWidths = new List(); private bool _textDimensionCacheValid; private string _text; private bool _clipText; public Label() { MouseFilter = MouseFilterMode.Ignore; SizeFlagsVertical = SizeFlags.ShrinkCenter; } /// /// The text to display. /// [ViewVariables] public string Text { get => _text; set { _text = value; _textDimensionCacheValid = false; MinimumSizeChanged(); } } [ViewVariables] public bool ClipText { get => _clipText; set { _clipText = value; RectClipContent = value; MinimumSizeChanged(); } } [ViewVariables] public AlignMode Align { get; set; } [ViewVariables] public VAlignMode VAlign { get; set; } public Font FontOverride { get; set; } private Font ActualFont { get { if (FontOverride != null) { return FontOverride; } if (TryGetStyleProperty(StylePropertyFont, out var font)) { return font; } return UserInterfaceManager.ThemeDefaults.LabelFont; } } public Color? FontColorShadowOverride { get; set; } private Color ActualFontColor { get { if (FontColorOverride.HasValue) { return FontColorOverride.Value; } if (TryGetStyleProperty(StylePropertyFontColor, out var color)) { return color; } return Color.White; } } [ViewVariables(VVAccess.ReadWrite)] [Animatable] public Color? FontColorOverride { get; set; } public int? ShadowOffsetXOverride { get; set; } public int? ShadowOffsetYOverride { get; set; } protected internal override void Draw(DrawingHandleScreen handle) { if (_text == null) { return; } if (!_textDimensionCacheValid) { _calculateTextDimension(); DebugTools.Assert(_textDimensionCacheValid); } int vOffset; switch (VAlign) { case VAlignMode.Top: vOffset = 0; break; case VAlignMode.Fill: case VAlignMode.Center: vOffset = (PixelSize.Y - _cachedTextHeight) / 2; break; case VAlignMode.Bottom: vOffset = PixelSize.Y - _cachedTextHeight; break; default: throw new ArgumentOutOfRangeException(); } var newlines = 0; var font = ActualFont; var actualFontColor = ActualFontColor; Vector2 CalcBaseline() { DebugTools.Assert(_textDimensionCacheValid); int hOffset; switch (Align) { case AlignMode.Left: hOffset = 0; break; case AlignMode.Center: case AlignMode.Fill: hOffset = (PixelSize.X - _cachedTextWidths[newlines]) / 2; break; case AlignMode.Right: hOffset = PixelSize.X - _cachedTextWidths[newlines]; break; default: throw new ArgumentOutOfRangeException(); } return (hOffset, font.GetAscent(UIScale) + font.GetLineHeight(UIScale) * newlines + vOffset); } var baseLine = CalcBaseline(); foreach (var chr in _text) { if (chr == '\n') { newlines += 1; baseLine = CalcBaseline(); } var advance = font.DrawChar(handle, chr, baseLine, UIScale, actualFontColor); baseLine += (advance, 0); } } public enum AlignMode { Left = 0, Center = 1, Right = 2, Fill = 3 } public enum VAlignMode { Top = 0, Center = 1, Bottom = 2, Fill = 3 } protected override Vector2 CalculateMinimumSize() { if (!_textDimensionCacheValid) { _calculateTextDimension(); DebugTools.Assert(_textDimensionCacheValid); } if (ClipText) { return (0, _cachedTextHeight / UIScale); } var totalWidth = 0; foreach (var width in _cachedTextWidths) { totalWidth = Math.Max(totalWidth, width); } return (totalWidth / UIScale, _cachedTextHeight / UIScale); } protected internal override void UIScaleChanged() { _textDimensionCacheValid = false; base.UIScaleChanged(); } private void _calculateTextDimension() { _cachedTextWidths.Clear(); _cachedTextWidths.Add(0); if (_text == null) { _cachedTextHeight = 0; _textDimensionCacheValid = true; return; } var font = ActualFont; var height = font.GetHeight(UIScale); foreach (var chr in _text) { if (chr == '\n') { _cachedTextWidths.Add(0); height += font.GetLineHeight(UIScale); } else { var metrics = font.GetCharMetrics(chr, UIScale); if (!metrics.HasValue) { continue; } _cachedTextWidths[_cachedTextWidths.Count-1] += metrics.Value.Advance; } } _cachedTextHeight = height; _textDimensionCacheValid = true; } protected override void StylePropertiesChanged() { _textDimensionCacheValid = false; base.StylePropertiesChanged(); } } }