Files
RobustToolbox/SS14.Client/UserInterface/Controls/Button.cs
2019-03-05 09:35:18 +01:00

331 lines
9.1 KiB
C#

using System;
using SS14.Client.Graphics;
using SS14.Client.Graphics.Drawing;
using SS14.Client.Utility;
using SS14.Shared.Maths;
namespace SS14.Client.UserInterface.Controls
{
[ControlWrap(typeof(Godot.Button))]
public class Button : BaseButton
{
public const string StylePropertyStyleBox = "stylebox";
public const string StylePseudoClassNormal = "normal";
public const string StylePseudoClassHover = "hover";
public const string StylePseudoClassDisabled = "disabled";
public const string StylePseudoClassPressed = "pressed";
private int? _textWidthCache;
public Button()
{
}
public Button(string name) : base(name)
{
}
internal Button(Godot.Button button) : base(button)
{
}
private protected override Godot.Control SpawnSceneControl()
{
return new Godot.Button();
}
private AlignMode _textAlign;
public AlignMode TextAlign
{
get => GameController.OnGodot ? (AlignMode)SceneControl.Get("align") : _textAlign;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("align", (Godot.Button.TextAlign) value);
}
else
{
_textAlign = value;
}
}
}
private bool _clipText;
public bool ClipText
{
get => GameController.OnGodot ? (bool)SceneControl.Get("clip_text") : _clipText;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("clip_text", value);
}
else
{
_clipText = value;
}
}
}
private string _text;
public string Text
{
get => GameController.OnGodot ? (string)SceneControl.Get("text") : _text;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("text", value);
}
else
{
_text = value;
_textWidthCache = null;
MinimumSizeChanged();
}
}
}
private StyleBox ActualStyleBox
{
get
{
if (TryGetStyleProperty(StylePropertyStyleBox, out StyleBox box))
{
return box;
}
return UserInterfaceManager.ThemeDefaults.ButtonStyle;
}
}
public Font ActualFont
{
get
{
if (TryGetStyleProperty("font", out Font font))
{
return font;
}
return UserInterfaceManager.ThemeDefaults.DefaultFont;
}
}
public Color ActualFontColor
{
get
{
if (TryGetStyleProperty("font-color", out Color fontColor))
{
return fontColor;
}
return _fontColorOverride ?? Color.White;
}
}
private Color? _fontColorOverride;
public Color? FontColorOverride
{
get => _fontColorOverride ?? GetColorOverride("font_color");
set => SetColorOverride("font_color", _fontColorOverride = value);
}
private Color? _fontColorDisabledOverride;
public Color? FontColorDisabledOverride
{
get => _fontColorDisabledOverride ?? GetColorOverride("font_color_disabled");
set => SetColorOverride("font_color_disabled", _fontColorDisabledOverride = value);
}
private Color? _fontColorHoverOverride;
public Color? FontColorHoverOverride
{
get => _fontColorHoverOverride ?? GetColorOverride("font_color_hover");
set => SetColorOverride("font_color_hover", _fontColorHoverOverride = value);
}
private Color? _fontColorPressedOverride;
public Color? FontColorPressedOverride
{
get => _fontColorPressedOverride ?? GetColorOverride("font_color_pressed");
set => SetColorOverride("font_color_pressed", _fontColorPressedOverride = value);
}
public enum AlignMode
{
Left = 0,
Center = 1,
Right = 2,
}
protected internal override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (GameController.OnGodot)
{
return;
}
var uiTheme = UserInterfaceManager.ThemeDefaults;
var style = ActualStyleBox;
var font = ActualFont;
var drawBox = SizeBox;
style.Draw(handle, drawBox);
if (_text == null)
{
return;
}
var width = _ensureWidthCache();
var contentBox = style.GetContentBox(drawBox);
int drawOffset;
switch (TextAlign)
{
case AlignMode.Left:
drawOffset = 0;
break;
case AlignMode.Center:
drawOffset = (int)(contentBox.Width - width) / 2;
break;
case AlignMode.Right:
drawOffset = (int)(contentBox.Width - width);
break;
default:
throw new ArgumentOutOfRangeException();
}
var color = ActualFontColor;
var offsetY = (int) (contentBox.Height - font.Height) / 2;
var baseLine = new Vector2i(drawOffset, offsetY+font.Ascent) + contentBox.TopLeft;
foreach (var chr in _text)
{
if (!font.TryGetCharMetrics(chr, out var metrics))
{
continue;
}
if (!(ClipText && (baseLine.X < contentBox.Left || baseLine.X + metrics.Advance > contentBox.Right)))
{
font.DrawChar(handle, chr, baseLine, color);
}
baseLine += (metrics.Advance, 0);
}
}
protected override Vector2 CalculateMinimumSize()
{
if (GameController.OnGodot)
{
return base.CalculateMinimumSize();
}
var uiTheme = UserInterfaceManager.ThemeDefaults;
var style = ActualStyleBox;
var font = ActualFont;
var fontHeight = font.Height;
if (ClipText)
{
return (0, fontHeight) + style.MinimumSize;
}
var width = _ensureWidthCache();
return new Vector2(width, fontHeight) + style.MinimumSize;
}
protected override void Initialize()
{
base.Initialize();
DrawModeChanged();
}
protected override void DrawModeChanged()
{
switch (DrawMode)
{
case DrawModeEnum.Normal:
StylePseudoClass = StylePseudoClassNormal;
break;
case DrawModeEnum.Pressed:
StylePseudoClass = StylePseudoClassPressed;
break;
case DrawModeEnum.Hover:
StylePseudoClass = StylePseudoClassHover;
break;
case DrawModeEnum.Disabled:
StylePseudoClass = StylePseudoClassDisabled;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private int _ensureWidthCache()
{
if (_textWidthCache.HasValue)
{
return _textWidthCache.Value;
}
if (_text == null)
{
_textWidthCache = 0;
return 0;
}
var uiTheme = UserInterfaceManager.ThemeDefaults;
var font = ActualFont;
var textWidth = 0;
foreach (var chr in _text)
{
var metrics = font.GetCharMetrics(chr);
if (metrics == null)
{
continue;
}
textWidth += metrics.Value.Advance;
}
_textWidthCache = textWidth;
return textWidth;
}
protected override void StylePropertiesChanged()
{
_textWidthCache = null;
base.StylePropertiesChanged();
}
private protected override void SetGodotProperty(string property, object value, GodotAssetScene context)
{
base.SetGodotProperty(property, value, context);
if (property == "text")
{
Text = (string) value;
}
if (property == "align")
{
TextAlign = (AlignMode) (long) value;
}
}
}
}