diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index ebecb90abf..20bd983bfb 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -39,7 +39,7 @@ END TEMPLATE--> ### New features -*None yet* +* Control layout properties such as `Margin` can now be set via style sheets. ### Bugfixes @@ -86,6 +86,9 @@ END TEMPLATE--> * You can now specify CVar overrides via environment variable with the `ROBUST_CVAR_*` prefix. For example `ROBUST_CVAR_game__hostname=foobar` would set the appropriate CVar. Double underscores in the environment variable name are replaced with ".". * Added non-generic variant of `GetCVar` to `IConfigurationManager`. * Add type tracking to FieldNotFoundErrorNode for serialization. +* Distance between lines of a `RichTextLabel` can now be modified with `LineHeightScale`. +* UI theme prototypes are now updated when reloaded. +* New `RA0025` analyzer diagnostic warns for manual assignment to `[Dependency]` fields. ### Bugfixes diff --git a/Robust.Client/UserInterface/Control.Layout.Styling.cs b/Robust.Client/UserInterface/Control.Layout.Styling.cs new file mode 100644 index 0000000000..fdc1a4a4c8 --- /dev/null +++ b/Robust.Client/UserInterface/Control.Layout.Styling.cs @@ -0,0 +1,132 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Robust.Client.UserInterface; + +public partial class Control +{ + private LayoutStyleProperties _layoutStyleOverride; + private LayoutStyleProperties _layoutStyleSheet; + + private void UpdateLayoutStyleProperties() + { + var propertiesSet = LayoutStyleProperties.None; + + // Assumed most controls will have little or no style properties, + // so iterating once is less expensive overall then checking 10+ properties. + // C# switch statements are compiled efficiently anyways. + foreach (var (key, value) in _styleProperties) + { + switch (key) + { + case nameof(SizeFlagsStretchRatio): + UpdateField(ref _sizeFlagsStretchRatio, value, LayoutStyleProperties.StretchRatio); + break; + case nameof(MinWidth): + UpdateField(ref _minWidth, value, LayoutStyleProperties.MinWidth); + break; + case nameof(MinHeight): + UpdateField(ref _minHeight, value, LayoutStyleProperties.MinHeight); + break; + case nameof(SetWidth): + UpdateField(ref _setWidth, value, LayoutStyleProperties.SetWidth); + break; + case nameof(SetHeight): + UpdateField(ref _setHeight, value, LayoutStyleProperties.SetHeight); + break; + case nameof(MaxWidth): + UpdateField(ref _maxWidth, value, LayoutStyleProperties.MaxWidth); + break; + case nameof(MaxHeight): + UpdateField(ref _maxHeight, value, LayoutStyleProperties.MaxHeight); + break; + case nameof(HorizontalExpand): + UpdateField(ref _horizontalExpand, value, LayoutStyleProperties.HorizontalExpand); + break; + case nameof(VerticalExpand): + UpdateField(ref _verticalExpand, value, LayoutStyleProperties.VerticalExpand); + break; + case nameof(HorizontalAlignment): + UpdateField(ref _horizontalAlignment, value, LayoutStyleProperties.HorizontalAlignment); + break; + case nameof(VerticalAlignment): + UpdateField(ref _verticalAlignment, value, LayoutStyleProperties.VerticalAlignment); + break; + case nameof(Margin): + UpdateField(ref _margin, value, LayoutStyleProperties.Margin); + break; + } + } + + // Reset cleared properties back to defaults. + var toClear = _layoutStyleSheet & ~propertiesSet; + if (toClear != 0) + { + ClearField(ref _sizeFlagsStretchRatio, DefaultStretchRatio, LayoutStyleProperties.StretchRatio); + ClearField(ref _minWidth, 0, LayoutStyleProperties.MinWidth); + ClearField(ref _minHeight, 0, LayoutStyleProperties.MinHeight); + ClearField(ref _setWidth, DefaultSetSize, LayoutStyleProperties.SetWidth); + ClearField(ref _setHeight, DefaultSetSize, LayoutStyleProperties.SetHeight); + ClearField(ref _maxWidth, DefaultMaxSize, LayoutStyleProperties.MaxWidth); + ClearField(ref _maxHeight, DefaultMaxSize, LayoutStyleProperties.MaxHeight); + ClearField(ref _horizontalExpand, false, LayoutStyleProperties.HorizontalExpand); + ClearField(ref _verticalExpand, false, LayoutStyleProperties.VerticalExpand); + ClearField(ref _horizontalAlignment, DefaultHAlignment, LayoutStyleProperties.HorizontalAlignment); + ClearField(ref _verticalAlignment, DefaultVAlignment, LayoutStyleProperties.VerticalAlignment); + ClearField(ref _margin, default, LayoutStyleProperties.Margin); + } + + _layoutStyleSheet = propertiesSet; + + return; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void UpdateField(ref T field, object value, LayoutStyleProperties flag) + { + if ((_layoutStyleOverride & flag) != 0) + return; + + // TODO: Probably need better error handling... + if (value is not T valueCast) + return; + + field = valueCast; + propertiesSet |= flag; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void ClearField(ref T field, T defaultValue, LayoutStyleProperties flag) + { + if ((toClear & flag) == 0) + return; + + field = defaultValue; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetLayoutStyleProp(LayoutStyleProperties flag) + { + _layoutStyleOverride |= flag; + } + + [Flags] + private enum LayoutStyleProperties : short + { + // @formatter:off + None = 0, + Margin = 1 << 0, + MinWidth = 1 << 1, + MinHeight = 1 << 2, + SetWidth = 1 << 3, + SetHeight = 1 << 4, + MaxWidth = 1 << 5, + MaxHeight = 1 << 6, + StretchRatio = 1 << 7, + HorizontalExpand = 1 << 8, + VerticalExpand = 1 << 9, + HorizontalAlignment = 1 << 10, + VerticalAlignment = 1 << 11, + // @formatter:on + } +} diff --git a/Robust.Client/UserInterface/Control.Layout.cs b/Robust.Client/UserInterface/Control.Layout.cs index 88872de3cd..95904dda04 100644 --- a/Robust.Client/UserInterface/Control.Layout.cs +++ b/Robust.Client/UserInterface/Control.Layout.cs @@ -12,24 +12,30 @@ namespace Robust.Client.UserInterface public partial class Control { + private const float DefaultStretchRatio = 1; + private const float DefaultSetSize = float.NaN; + private const float DefaultMaxSize = float.PositiveInfinity; + private const HAlignment DefaultHAlignment = HAlignment.Stretch; + private const VAlignment DefaultVAlignment = VAlignment.Stretch; + private Vector2 _size; [ViewVariables] internal Vector2? PreviousMeasure; [ViewVariables] internal UIBox2? PreviousArrange; - private float _sizeFlagsStretchRatio = 1; + private float _sizeFlagsStretchRatio = DefaultStretchRatio; private float _minWidth; private float _minHeight; - private float _setWidth = float.NaN; - private float _setHeight = float.NaN; - private float _maxWidth = float.PositiveInfinity; - private float _maxHeight = float.PositiveInfinity; + private float _setWidth = DefaultSetSize; + private float _setHeight = DefaultSetSize; + private float _maxWidth = DefaultMaxSize; + private float _maxHeight = DefaultMaxSize; private bool _horizontalExpand; private bool _verticalExpand; - private HAlignment _horizontalAlignment = HAlignment.Stretch; - private VAlignment _verticalAlignment = VAlignment.Stretch; + private HAlignment _horizontalAlignment = DefaultHAlignment; + private VAlignment _verticalAlignment = DefaultVAlignment; private Thickness _margin; private bool _measuring; private bool _arranging; @@ -53,6 +59,7 @@ namespace Robust.Client.UserInterface set { _margin = value; + SetLayoutStyleProp(LayoutStyleProperties.Margin); InvalidateMeasure(); } } @@ -242,6 +249,7 @@ namespace Robust.Client.UserInterface set { _horizontalAlignment = value; + SetLayoutStyleProp(LayoutStyleProperties.HorizontalAlignment); InvalidateArrange(); } } @@ -258,6 +266,7 @@ namespace Robust.Client.UserInterface set { _verticalAlignment = value; + SetLayoutStyleProp(LayoutStyleProperties.VerticalAlignment); InvalidateArrange(); } } @@ -276,6 +285,7 @@ namespace Robust.Client.UserInterface set { _horizontalExpand = value; + SetLayoutStyleProp(LayoutStyleProperties.HorizontalExpand); Parent?.InvalidateMeasure(); } } @@ -294,6 +304,7 @@ namespace Robust.Client.UserInterface set { _verticalExpand = value; + SetLayoutStyleProp(LayoutStyleProperties.VerticalExpand); Parent?.InvalidateArrange(); } } @@ -318,6 +329,7 @@ namespace Robust.Client.UserInterface _sizeFlagsStretchRatio = value; + SetLayoutStyleProp(LayoutStyleProperties.StretchRatio); Parent?.InvalidateArrange(); } } @@ -394,6 +406,7 @@ namespace Robust.Client.UserInterface set { _minWidth = value; + SetLayoutStyleProp(LayoutStyleProperties.MinWidth); InvalidateMeasure(); } } @@ -408,6 +421,7 @@ namespace Robust.Client.UserInterface set { _minHeight = value; + SetLayoutStyleProp(LayoutStyleProperties.MinHeight); InvalidateMeasure(); } } @@ -422,6 +436,7 @@ namespace Robust.Client.UserInterface set { _setWidth = value; + SetLayoutStyleProp(LayoutStyleProperties.SetWidth); InvalidateMeasure(); } } @@ -436,6 +451,7 @@ namespace Robust.Client.UserInterface set { _setHeight = value; + SetLayoutStyleProp(LayoutStyleProperties.SetHeight); InvalidateMeasure(); } } @@ -450,6 +466,7 @@ namespace Robust.Client.UserInterface set { _maxWidth = value; + SetLayoutStyleProp(LayoutStyleProperties.MaxWidth); InvalidateMeasure(); } } @@ -464,6 +481,7 @@ namespace Robust.Client.UserInterface set { _maxHeight = value; + SetLayoutStyleProp(LayoutStyleProperties.MaxHeight); InvalidateMeasure(); } } diff --git a/Robust.Client/UserInterface/Control.Styling.cs b/Robust.Client/UserInterface/Control.Styling.cs index 4f54cf5644..fbe7a1e700 100644 --- a/Robust.Client/UserInterface/Control.Styling.cs +++ b/Robust.Client/UserInterface/Control.Styling.cs @@ -239,6 +239,7 @@ namespace Robust.Client.UserInterface protected virtual void StylePropertiesChanged() { + UpdateLayoutStyleProperties(); InvalidateMeasure(); }