Refactor UI system. (#843)

* Refactor UI system.

Deferred updating is used for styling & layout. This fixes the awful time complexity of containers.
Removed SetDefaults and Initialize. They were a bad idea alright.

* Fix build on .NET Framework.
This commit is contained in:
Pieter-Jan Briers
2019-08-14 22:03:51 +02:00
committed by GitHub
parent cdac0d5757
commit cb5f2ffae1
57 changed files with 1256 additions and 1515 deletions

View File

@@ -427,7 +427,7 @@ namespace Robust.Client.Console.Commands
public bool Execute(IDebugConsole console, params string[] args)
{
var window = new SS14Window("UITest");
var window = new SS14Window();
var tabContainer = new TabContainer();
window.Contents.AddChild(tabContainer);
var scroll = new ScrollContainer();

View File

@@ -1,6 +1,5 @@
using System;
using JetBrains.Annotations;
using Robust.Client.Utility;
using Robust.Shared.Maths;
namespace Robust.Client.Graphics.Drawing
@@ -128,11 +127,6 @@ namespace Robust.Client.Graphics.Drawing
var right = baseBox.Right - GetContentMargin(Margin.Right);
var bottom = baseBox.Bottom - GetContentMargin(Margin.Bottom);
if (left > right || top > bottom)
{
throw new ArgumentException("Box is too small!", nameof(baseBox));
}
return new UIBox2(left, top, right, bottom);
}

View File

@@ -99,6 +99,9 @@ namespace Robust.Client.Interfaces.UserInterface
void RemoveModal(Control modal);
void Render(IRenderHandle renderHandle);
void QueueStyleUpdate(Control control);
void QueueLayoutUpdate(Control control);
}
}

View File

@@ -0,0 +1,972 @@
using System;
using JetBrains.Annotations;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Robust.Client.UserInterface
{
public partial class Control
{
private float _anchorBottom;
private float _anchorLeft;
private float _anchorRight;
private float _anchorTop;
private float _marginRight;
private float _marginLeft;
private float _marginTop;
private float _marginBottom;
private Vector2 _position;
private Vector2 _sizeByMargins;
private Vector2 _size;
private float _sizeFlagsStretchRatio = 1;
private Vector2? _calculatedMinimumSize;
private Vector2 _customMinimumSize;
private GrowDirection _growHorizontal;
private GrowDirection _growVertical;
public event Action<Control> OnMinimumSizeChanged;
private SizeFlags _sizeFlagsHorizontal = SizeFlags.Fill;
private SizeFlags _sizeFlagsVertical = SizeFlags.Fill;
private bool _layoutDirty;
/// <summary>
/// The value of an anchor that is exactly on the begin of the parent control.
/// </summary>
public const float AnchorBegin = 0;
/// <summary>
/// The value of an anchor that is exactly on the end of the parent control.
/// </summary>
public const float AnchorEnd = 1;
/// <summary>
/// Specifies the anchor of the bottom edge of the control.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float AnchorBottom
{
get => _anchorBottom;
set
{
_anchorBottom = value;
DoLayoutUpdate();
}
}
/// <summary>
/// Specifies the anchor of the left edge of the control.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float AnchorLeft
{
get => _anchorLeft;
set
{
_anchorLeft = value;
DoLayoutUpdate();
}
}
/// <summary>
/// Specifies the anchor of the right edge of the control.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float AnchorRight
{
get => _anchorRight;
set
{
_anchorRight = value;
DoLayoutUpdate();
}
}
/// <summary>
/// Specifies the anchor of the top edge of the control.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float AnchorTop
{
get => _anchorTop;
set
{
_anchorTop = value;
DoLayoutUpdate();
}
}
/// <summary>
/// Specifies the margin of the right edge of the control.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float MarginRight
{
get => _marginRight;
set
{
_marginRight = value;
DoLayoutUpdate();
}
}
/// <summary>
/// Specifies the margin of the left edge of the control.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float MarginLeft
{
get => _marginLeft;
set
{
_marginLeft = value;
DoLayoutUpdate();
}
}
/// <summary>
/// Specifies the margin of the top edge of the control.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float MarginTop
{
get => _marginTop;
set
{
_marginTop = value;
DoLayoutUpdate();
}
}
/// <summary>
/// Specifies the margin of the bottom edge of the control.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float MarginBottom
{
get => _marginBottom;
set
{
_marginBottom = value;
DoLayoutUpdate();
}
}
/// <summary>
/// Called when the <see cref="UIScale"/> for this control changes.
/// </summary>
protected internal virtual void UIScaleChanged()
{
MinimumSizeChanged();
}
/// <summary>
/// The amount of "real" pixels a virtual pixel takes up.
/// The higher the number, the bigger the interface.
/// </summary>
[ViewVariables]
protected float UIScale => UserInterfaceManager.UIScale;
/// <summary>
/// The size of this control, in virtual pixels.
/// </summary>
/// <seealso cref="PixelSize"/>
/// <seealso cref="Width"/>
/// <seealso cref="Height"/>
[ViewVariables(VVAccess.ReadWrite)]
public Vector2 Size
{
get => _size;
set
{
var (diffX, diffY) = value - _sizeByMargins;
_marginRight += diffX;
_marginBottom += diffY;
DoLayoutUpdate();
}
}
/// <summary>
/// The size of this control, in physical pixels.
/// </summary>
[ViewVariables]
public Vector2i PixelSize => (Vector2i) (_size * UserInterfaceManager.UIScale);
/// <summary>
/// A <see cref="UIBox2"/> with the top left at 0,0 and the size equal to <see cref="Size"/>.
/// </summary>
/// <seealso cref="PixelSizeBox"/>
public UIBox2 SizeBox => new UIBox2(Vector2.Zero, Size);
/// <summary>
/// A <see cref="UIBox2i"/> with the top left at 0,0 and the size equal to <see cref="PixelSize"/>.
/// </summary>
/// <seealso cref="SizeBox"/>
public UIBox2i PixelSizeBox => new UIBox2i(Vector2i.Zero, PixelSize);
/// <summary>
/// The width of the control, in virtual pixels.
/// </summary>
/// <seealso cref="PixelWidth"/>
public float Width => Size.X;
/// <summary>
/// The height of the control, in virtual pixels.
/// </summary>
/// <seealso cref="PixelHeight"/>
public float Height => Size.Y;
/// <summary>
/// The width of the control, in physical pixels.
/// </summary>
/// <seealso cref="Width"/>
public int PixelWidth => PixelSize.X;
/// <summary>
/// The height of the control, in physical pixels.
/// </summary>
/// <seealso cref="Height"/>
public int PixelHeight => PixelSize.Y;
/// <summary>
/// The position of the top left corner of the control, in virtual pixels.
/// This is relative to the position of the parent.
/// </summary>
/// <seealso cref="PixelPosition"/>
/// <seealso cref="GlobalPosition"/>
[ViewVariables(VVAccess.ReadWrite)]
public Vector2 Position
{
get => _position;
set
{
var (diffX, diffY) = value - _position;
_marginTop += diffY;
_marginBottom += diffY;
_marginLeft += diffX;
_marginRight += diffX;
DoLayoutUpdate();
}
}
/// <summary>
/// The position of the top left corner of the control, in physical pixels.
/// </summary>
/// <seealso cref="Position"/>
[ViewVariables]
public Vector2i PixelPosition => (Vector2i) (_position * UserInterfaceManager.UIScale);
/// <summary>
/// The position of the top left corner of the control, in virtual pixels.
/// This is not relative to the parent.
/// </summary>
/// <seealso cref="GlobalPosition"/>
/// <seealso cref="Position"/>
[ViewVariables]
public Vector2 GlobalPosition
{
get
{
var offset = Position;
var parent = Parent;
while (parent != null)
{
offset += parent.Position;
parent = parent.Parent;
}
return offset;
}
}
/// <summary>
/// The position of the top left corner of the control, in physical pixels.
/// This is not relative to the parent.
/// </summary>
/// <seealso cref="GlobalPosition"/>
[ViewVariables]
public Vector2i GlobalPixelPosition
{
get
{
var offset = PixelPosition;
var parent = Parent;
while (parent != null)
{
offset += parent.PixelPosition;
parent = parent.Parent;
}
return offset;
}
}
/// <summary>
/// Represents the "rectangle" of the control relative to the parent, in virtual pixels.
/// </summary>
/// <seealso cref="PixelRect"/>
public UIBox2 Rect => UIBox2.FromDimensions(_position, _size);
/// <summary>
/// Represents the "rectangle" of the control relative to the parent, in physical pixels.
/// </summary>
/// <seealso cref="Rect"/>
public UIBox2i PixelRect => UIBox2i.FromDimensions(PixelPosition, PixelSize);
/// <summary>
/// Determines how the control will move on the horizontal axis to ensure it is at its minimum size.
/// See <see cref="GrowDirection"/> for more information.
/// </summary>
[ViewVariables]
public GrowDirection GrowHorizontal
{
get => _growHorizontal;
set
{
_growHorizontal = value;
UpdateLayout();
}
}
/// <summary>
/// Determines how the control will move on the vertical axis to ensure it is at its minimum size.
/// See <see cref="GrowDirection"/> for more information.
/// </summary>
[ViewVariables]
public GrowDirection GrowVertical
{
get => _growVertical;
set
{
_growVertical = value;
UpdateLayout();
}
}
/// <summary>
/// Horizontal size flags for container layout.
/// </summary>
[ViewVariables]
public SizeFlags SizeFlagsHorizontal
{
get => _sizeFlagsHorizontal;
set
{
_sizeFlagsHorizontal = value;
if (Parent is Container container)
{
container.QueueSortChildren();
}
}
}
/// <summary>
/// Vertical size flags for container layout.
/// </summary>
[ViewVariables]
public SizeFlags SizeFlagsVertical
{
get => _sizeFlagsVertical;
set
{
_sizeFlagsVertical = value;
if (Parent is Container container)
{
container.QueueSortChildren();
}
}
}
/// <summary>
/// Stretch ratio used to give shared of the available space in case multiple siblings are set to expand
/// in a container
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the value is less than or equal to 0.
/// </exception>
[ViewVariables]
public float SizeFlagsStretchRatio
{
get => _sizeFlagsStretchRatio;
set
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException(nameof(value), value, "Value must be greater than zero.");
}
_sizeFlagsStretchRatio = value;
if (Parent is Container container)
{
container.QueueSortChildren();
}
}
}
/// <summary>
/// A combination of <see cref="CustomMinimumSize" /> and <see cref="CalculateMinimumSize" />,
/// Whichever is greater.
/// Use this for whenever you need the *actual* minimum size of something.
/// </summary>
/// <remarks>
/// This is in virtual pixels.
/// </remarks>
/// <seealso cref="CombinedPixelMinimumSize"/>
[ViewVariables]
public Vector2 CombinedMinimumSize
{
get
{
if (!_calculatedMinimumSize.HasValue)
{
_updateMinimumSize();
DebugTools.Assert(_calculatedMinimumSize.HasValue);
}
return Vector2.ComponentMax(CustomMinimumSize, _calculatedMinimumSize.Value);
}
}
/// <summary>
/// The <see cref="CombinedMinimumSize"/>, in physical pixels.
/// </summary>
public Vector2i CombinedPixelMinimumSize => (Vector2i) (CombinedMinimumSize * UIScale);
/// <summary>
/// A custom minimum size. If the control-calculated size is is smaller than this, this is used instead.
/// </summary>
/// <seealso cref="CalculateMinimumSize" />
/// <seealso cref="CombinedMinimumSize" />
[ViewVariables]
public Vector2 CustomMinimumSize
{
get => _customMinimumSize;
set
{
_customMinimumSize = Vector2.ComponentMax(Vector2.Zero, value);
MinimumSizeChanged();
}
}
private void _updateMinimumSize()
{
_calculatedMinimumSize = Vector2.ComponentMax(Vector2.Zero, CalculateMinimumSize());
}
/// <summary>
/// Override this to calculate a minimum size for this control.
/// Do NOT call this directly to get the minimum size for layout purposes!
/// Use <see cref="CombinedMinimumSize" /> for the ACTUAL minimum size.
/// </summary>
protected virtual Vector2 CalculateMinimumSize()
{
return Vector2.Zero;
}
/// <summary>
/// Tells the GUI system that the minimum size of this control may have changed,
/// so that say containers will re-sort it if necessary.
/// </summary>
public void MinimumSizeChanged()
{
_calculatedMinimumSize = null;
OnMinimumSizeChanged?.Invoke(this);
}
/// <summary>
/// Sets an anchor AND a margin preset. This is most likely the method you want.
/// </summary>
public void SetAnchorAndMarginPreset(LayoutPreset preset, LayoutPresetMode mode = LayoutPresetMode.MinSize,
int margin = 0)
{
SetAnchorPreset(preset);
SetMarginsPreset(preset, mode, margin);
}
/// <summary>
/// Changes all the anchors of a node at once to common presets.
/// The result is that the anchors are laid out to be suitable for a preset.
/// </summary>
/// <param name="preset">
/// The preset to apply to the anchors.
/// </param>
/// <param name="keepMargin">
/// If this is true, the control margin values themselves will not be changed,
/// and the control position and size will change according to the new anchor parameters.
/// If false, the control margins will adjust so that the control position and size remains the same relative to its parent.
/// </param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if <paramref name="preset" /> isn't a valid preset value.
/// </exception>
public void SetAnchorPreset(LayoutPreset preset, bool keepMargin = false)
{
// TODO: Implement keepMargin.
// Left Anchor.
switch (preset)
{
case LayoutPreset.TopLeft:
case LayoutPreset.BottomLeft:
case LayoutPreset.CenterLeft:
case LayoutPreset.LeftWide:
case LayoutPreset.HorizontalCenterWide:
case LayoutPreset.Wide:
case LayoutPreset.TopWide:
case LayoutPreset.BottomWide:
AnchorLeft = 0;
break;
case LayoutPreset.CenterTop:
case LayoutPreset.CenterBottom:
case LayoutPreset.Center:
case LayoutPreset.VerticalCenterWide:
AnchorLeft = 0.5f;
break;
case LayoutPreset.TopRight:
case LayoutPreset.BottomRight:
case LayoutPreset.CenterRight:
case LayoutPreset.RightWide:
AnchorLeft = 1;
break;
default:
throw new ArgumentOutOfRangeException(nameof(preset), preset, null);
}
// Top Anchor.
switch (preset)
{
case LayoutPreset.TopLeft:
case LayoutPreset.TopRight:
case LayoutPreset.LeftWide:
case LayoutPreset.TopWide:
case LayoutPreset.Wide:
case LayoutPreset.RightWide:
case LayoutPreset.CenterTop:
case LayoutPreset.VerticalCenterWide:
AnchorTop = 0;
break;
case LayoutPreset.CenterLeft:
case LayoutPreset.CenterRight:
case LayoutPreset.HorizontalCenterWide:
case LayoutPreset.Center:
AnchorTop = 0.5f;
break;
case LayoutPreset.CenterBottom:
case LayoutPreset.BottomLeft:
case LayoutPreset.BottomRight:
case LayoutPreset.BottomWide:
AnchorTop = 1;
break;
default:
throw new ArgumentOutOfRangeException(nameof(preset), preset, null);
}
// Right Anchor.
switch (preset)
{
case LayoutPreset.TopLeft:
case LayoutPreset.CenterLeft:
case LayoutPreset.BottomLeft:
case LayoutPreset.LeftWide:
AnchorRight = 0;
break;
case LayoutPreset.CenterTop:
case LayoutPreset.CenterBottom:
case LayoutPreset.Center:
case LayoutPreset.VerticalCenterWide:
AnchorRight = 0.5f;
break;
case LayoutPreset.CenterRight:
case LayoutPreset.TopRight:
case LayoutPreset.Wide:
case LayoutPreset.HorizontalCenterWide:
case LayoutPreset.TopWide:
case LayoutPreset.BottomWide:
case LayoutPreset.RightWide:
case LayoutPreset.BottomRight:
AnchorRight = 1;
break;
default:
throw new ArgumentOutOfRangeException(nameof(preset), preset, null);
}
// Bottom Anchor.
switch (preset)
{
case LayoutPreset.TopWide:
case LayoutPreset.TopLeft:
case LayoutPreset.TopRight:
case LayoutPreset.CenterTop:
AnchorBottom = 0;
break;
case LayoutPreset.CenterLeft:
case LayoutPreset.CenterRight:
case LayoutPreset.Center:
case LayoutPreset.HorizontalCenterWide:
AnchorBottom = 0.5f;
break;
case LayoutPreset.CenterBottom:
case LayoutPreset.BottomLeft:
case LayoutPreset.BottomRight:
case LayoutPreset.LeftWide:
case LayoutPreset.Wide:
case LayoutPreset.RightWide:
case LayoutPreset.VerticalCenterWide:
case LayoutPreset.BottomWide:
AnchorBottom = 1;
break;
default:
throw new ArgumentOutOfRangeException(nameof(preset), preset, null);
}
}
/// <summary>
/// Changes all the margins of a control at once to common presets.
/// The result is that the control is laid out as specified by the preset.
/// </summary>
/// <param name="preset"></param>
/// <param name="resizeMode"></param>
/// <param name="margin">Some extra margin to add depending on the preset chosen.</param>
public void SetMarginsPreset(LayoutPreset preset, LayoutPresetMode resizeMode = LayoutPresetMode.MinSize,
int margin = 0)
{
var newSize = Size;
var minSize = CombinedMinimumSize;
if ((resizeMode & LayoutPresetMode.KeepWidth) == 0)
{
newSize = new Vector2(minSize.X, newSize.Y);
}
if ((resizeMode & LayoutPresetMode.KeepHeight) == 0)
{
newSize = new Vector2(newSize.X, minSize.Y);
}
var parentSize = Parent?.Size ?? Vector2.Zero;
// Left Margin.
switch (preset)
{
case LayoutPreset.TopLeft:
case LayoutPreset.BottomLeft:
case LayoutPreset.CenterLeft:
case LayoutPreset.LeftWide:
case LayoutPreset.HorizontalCenterWide:
case LayoutPreset.Wide:
case LayoutPreset.TopWide:
case LayoutPreset.BottomWide:
// The AnchorLeft bit is to reverse the effect of anchors,
// So that the preset result is the same no matter what margins are set.
_marginLeft = parentSize.X * (0 - AnchorLeft) + margin;
break;
case LayoutPreset.CenterTop:
case LayoutPreset.CenterBottom:
case LayoutPreset.Center:
case LayoutPreset.VerticalCenterWide:
_marginLeft = parentSize.X * (0.5f - AnchorLeft) - newSize.X / 2;
break;
case LayoutPreset.TopRight:
case LayoutPreset.BottomRight:
case LayoutPreset.CenterRight:
case LayoutPreset.RightWide:
_marginLeft = parentSize.X * (1 - AnchorLeft) - newSize.X - margin;
break;
default:
throw new ArgumentOutOfRangeException(nameof(preset), preset, null);
}
// Top Anchor.
switch (preset)
{
case LayoutPreset.TopLeft:
case LayoutPreset.TopRight:
case LayoutPreset.LeftWide:
case LayoutPreset.TopWide:
case LayoutPreset.Wide:
case LayoutPreset.RightWide:
case LayoutPreset.CenterTop:
case LayoutPreset.VerticalCenterWide:
_marginTop = parentSize.Y * (0 - AnchorTop) + margin;
break;
case LayoutPreset.CenterLeft:
case LayoutPreset.CenterRight:
case LayoutPreset.HorizontalCenterWide:
case LayoutPreset.Center:
_marginTop = parentSize.Y * (0.5f - AnchorTop) - newSize.Y / 2;
break;
case LayoutPreset.CenterBottom:
case LayoutPreset.BottomLeft:
case LayoutPreset.BottomRight:
case LayoutPreset.BottomWide:
_marginTop = parentSize.Y * (1 - AnchorTop) - newSize.Y - margin;
break;
default:
throw new ArgumentOutOfRangeException(nameof(preset), preset, null);
}
// Right Anchor.
switch (preset)
{
case LayoutPreset.TopLeft:
case LayoutPreset.CenterLeft:
case LayoutPreset.BottomLeft:
case LayoutPreset.LeftWide:
_marginRight = parentSize.X * (0 - AnchorRight) + newSize.X + margin;
break;
case LayoutPreset.CenterTop:
case LayoutPreset.CenterBottom:
case LayoutPreset.Center:
case LayoutPreset.VerticalCenterWide:
_marginRight = parentSize.X * (0.5f - AnchorRight) + newSize.X;
break;
case LayoutPreset.CenterRight:
case LayoutPreset.TopRight:
case LayoutPreset.Wide:
case LayoutPreset.HorizontalCenterWide:
case LayoutPreset.TopWide:
case LayoutPreset.BottomWide:
case LayoutPreset.RightWide:
case LayoutPreset.BottomRight:
_marginRight = parentSize.X * (1 - AnchorRight) - margin;
break;
default:
throw new ArgumentOutOfRangeException(nameof(preset), preset, null);
}
// Bottom Anchor.
switch (preset)
{
case LayoutPreset.TopWide:
case LayoutPreset.TopLeft:
case LayoutPreset.TopRight:
case LayoutPreset.CenterTop:
_marginBottom = parentSize.Y * (0 - AnchorBottom) + newSize.Y + margin;
break;
case LayoutPreset.CenterLeft:
case LayoutPreset.CenterRight:
case LayoutPreset.Center:
case LayoutPreset.HorizontalCenterWide:
_marginBottom = parentSize.Y * (0.5f - AnchorBottom) + newSize.Y;
break;
case LayoutPreset.CenterBottom:
case LayoutPreset.BottomLeft:
case LayoutPreset.BottomRight:
case LayoutPreset.LeftWide:
case LayoutPreset.Wide:
case LayoutPreset.RightWide:
case LayoutPreset.VerticalCenterWide:
case LayoutPreset.BottomWide:
_marginBottom = parentSize.Y * (1 - AnchorBottom) - margin;
break;
default:
throw new ArgumentOutOfRangeException(nameof(preset), preset, null);
}
UpdateLayout();
}
public void ForceRunLayoutUpdate()
{
DoLayoutUpdate();
// I already apologize, Sonar.
// This is terrible.
if (this is Container container)
{
container.SortChildren();
}
foreach (var child in Children)
{
child.ForceRunLayoutUpdate();
}
}
public enum LayoutPreset : byte
{
TopLeft = 0,
TopRight = 1,
BottomLeft = 2,
BottomRight = 3,
CenterLeft = 4,
CenterTop = 5,
CenterRight = 6,
CenterBottom = 7,
Center = 8,
LeftWide = 9,
TopWide = 10,
RightWide = 11,
BottomWide = 12,
VerticalCenterWide = 13,
HorizontalCenterWide = 14,
Wide = 15,
}
/// <seealso cref="Control.SetMarginsPreset" />
[Flags]
[PublicAPI]
public enum LayoutPresetMode : byte
{
/// <summary>
/// Reset control size to minimum size.
/// </summary>
MinSize = 0,
/// <summary>
/// Reset height to minimum but keep width the same.
/// </summary>
KeepWidth = 1,
/// <summary>
/// Reset width to minimum but keep height the same.
/// </summary>
KeepHeight = 2,
/// <summary>
/// Do not modify control size at all.
/// </summary>
KeepSize = KeepWidth | KeepHeight,
}
/// <summary>
/// Controls how a control changes size when inside a container.
/// </summary>
[Flags]
[PublicAPI]
public enum SizeFlags : byte
{
/// <summary>
/// Shrink to the begin of the specified axis.
/// </summary>
None = 0,
/// <summary>
/// Fill as much space as possible in a container, without pushing others.
/// </summary>
Fill = 1,
/// <summary>
/// Fill as much space as possible in a container, pushing other nodes.
/// The ratio of pushing if there's multiple set to expand is dependant on <see cref="SizeFlagsStretchRatio" />
/// </summary>
Expand = 2,
/// <summary>
/// Combination of <see cref="Fill" /> and <see cref="Expand" />.
/// </summary>
FillExpand = 3,
/// <summary>
/// Shrink inside a container, aligning to the center.
/// </summary>
ShrinkCenter = 4,
/// <summary>
/// Shrink inside a container, aligning to the end.
/// </summary>
ShrinkEnd = 8,
}
/// <summary>
/// Controls how the control should move when its wanted size (controlled by anchors/margins) is smaller
/// than its minimum size.
/// </summary>
public enum GrowDirection : byte
{
/// <summary>
/// The control will expand to the bottom right to reach its minimum size.
/// </summary>
End = 0,
/// <summary>
/// The control will expand to the top left to reach its minimum size.
/// </summary>
Begin,
/// <summary>
/// The control will expand on all axes equally to reach its minimum size.
/// </summary>
Both
}
private protected void UpdateLayout()
{
if (_layoutDirty)
{
// Already queued for a layout update, don't bother.
return;
}
_layoutDirty = true;
UserInterfaceManagerInternal.QueueLayoutUpdate(this);
}
internal void DoLayoutUpdate()
{
_layoutDirty = false;
var (pSizeX, pSizeY) = Parent?._size ?? Vector2.Zero;
// Calculate where the control "wants" to be by its anchors/margins.
var top = _anchorTop * pSizeY + _marginTop;
var left = _anchorLeft * pSizeX + _marginLeft;
var right = _anchorRight * pSizeX + _marginRight;
var bottom = _anchorBottom * pSizeY + _marginBottom;
// The position we want.
var (wPosX, wPosY) = (left, top);
// The size we want.
var (wSizeX, wSizeY) = (right - left, bottom - top);
var (minSizeX, minSizeY) = CombinedMinimumSize;
_handleLayoutOverflow(GrowHorizontal, minSizeX, wPosX, wSizeX, out var posX, out var sizeX);
_handleLayoutOverflow(GrowVertical, minSizeY, wPosY, wSizeY, out var posY, out var sizeY);
var oldSize = _size;
_position = (posX, posY);
_size = (sizeX, sizeY);
_sizeByMargins = (wSizeX, wSizeY);
// If size is different then child controls may need to be laid out differently.
if (_size != oldSize)
{
Resized();
foreach (var child in _orderedChildren)
{
child.UpdateLayout();
}
}
}
private static void _handleLayoutOverflow(GrowDirection direction, float minSize, float wPos, float wSize,
out float pos,
out float size)
{
var overflow = minSize - wSize;
if (overflow <= 0)
{
pos = wPos;
size = wSize;
return;
}
switch (direction)
{
case GrowDirection.End:
pos = wPos;
break;
case GrowDirection.Begin:
pos = wPos - overflow;
break;
case GrowDirection.Both:
pos = wPos - overflow / 2;
break;
default:
throw new ArgumentOutOfRangeException();
}
size = minSize;
}
}
}

View File

@@ -72,6 +72,20 @@ namespace Robust.Client.UserInterface
private void Restyle()
{
if (_stylingDirty)
{
// Already queued for a style update, don't bother.
return;
}
_stylingDirty = true;
UserInterfaceManagerInternal.QueueStyleUpdate(this);
}
internal void DoStyleUpdate()
{
_stylingDirty = false;
_styleProperties.Clear();
// TODO: probably gonna need support for multiple stylesheets.
@@ -144,6 +158,16 @@ namespace Robust.Client.UserInterface
MinimumSizeChanged();
}
public void ForceRunStyleUpdate()
{
DoStyleUpdate();
foreach (var child in Children)
{
child.ForceRunStyleUpdate();
}
}
public bool TryGetStyleProperty<T>(string param, out T value)
{
if (_styleProperties.TryGetValue(param, out var val))

File diff suppressed because it is too large Load Diff

View File

@@ -16,14 +16,6 @@ namespace Robust.Client.UserInterface.Controls
private bool _disabled;
private bool _pressed;
protected BaseButton()
{
}
protected BaseButton(string name) : base(name)
{
}
/// <summary>
/// Controls mode of operation in relation to press/release events.
/// </summary>
@@ -233,7 +225,7 @@ namespace Robust.Client.UserInterface.Controls
Normal = 0,
Pressed = 1,
Hover = 2,
Disabled = 3,
Disabled = 3
}
public class ButtonEventArgs : EventArgs
@@ -279,7 +271,7 @@ namespace Robust.Client.UserInterface.Controls
/// <see cref="BaseButton.OnPressed"/> fires when the mouse button causing them is released.
/// This is the default and most intuitive method.
/// </summary>
Release = 1,
Release = 1
}
}
}

View File

@@ -17,10 +17,7 @@ namespace Robust.Client.UserInterface.Controls
protected BoxContainer()
{
}
protected BoxContainer(string name) : base(name)
{
MouseFilter = MouseFilterMode.Pass;
}
/// <summary>
@@ -213,13 +210,6 @@ namespace Robust.Client.UserInterface.Controls
return new Vector2(minWidth, minHeight);
}
protected override void SetDefaults()
{
base.SetDefaults();
MouseFilter = MouseFilterMode.Pass;
}
public enum AlignMode
{
/// <summary>
@@ -235,7 +225,7 @@ namespace Robust.Client.UserInterface.Controls
/// <summary>
/// Controls are laid out from the end of the box container.
/// </summary>
End = 2,
End = 2
}
}
}

View File

@@ -21,10 +21,7 @@ namespace Robust.Client.UserInterface.Controls
public Button()
{
}
public Button(string name) : base(name)
{
DrawModeChanged();
}
/// <summary>
@@ -115,7 +112,7 @@ namespace Robust.Client.UserInterface.Controls
/// <summary>
/// Text is aligned to the right of the button.
/// </summary>
Right = 2,
Right = 2
}
protected internal override void Draw(DrawingHandleScreen handle)
@@ -200,13 +197,6 @@ namespace Robust.Client.UserInterface.Controls
return (width / UIScale, fontHeight) + style.MinimumSize / UIScale;
}
protected override void Initialize()
{
base.Initialize();
DrawModeChanged();
}
protected override void DrawModeChanged()
{
switch (DrawMode)

View File

@@ -14,10 +14,7 @@ namespace Robust.Client.UserInterface.Controls
public CheckBox()
{
}
public CheckBox(string name) : base(name)
{
ToggleMode = true;
}
protected internal override void Draw(DrawingHandleScreen handle)
@@ -68,12 +65,5 @@ namespace Robust.Client.UserInterface.Controls
return 0;
}
protected override void SetDefaults()
{
base.SetDefaults();
ToggleMode = true;
}
}
}

View File

@@ -2,8 +2,5 @@ namespace Robust.Client.UserInterface.Controls
{
public class CheckButton : Button
{
public CheckButton()
{
}
}
}

View File

@@ -8,12 +8,9 @@ namespace Robust.Client.UserInterface.Controls
/// </summary>
public abstract class Container : Control
{
protected Container() : base()
{
}
protected Container(string name) : base(name)
protected internal void QueueSortChildren()
{
UpdateLayout();
}
/// <summary>
@@ -31,7 +28,7 @@ namespace Robust.Client.UserInterface.Controls
newChild.OnMinimumSizeChanged += _childChanged;
newChild.OnVisibilityChanged += _childChanged;
MinimumSizeChanged();
SortChildren();
QueueSortChildren();
}
protected override void ChildRemoved(Control child)
@@ -41,7 +38,7 @@ namespace Robust.Client.UserInterface.Controls
child.OnMinimumSizeChanged -= _childChanged;
child.OnVisibilityChanged -= _childChanged;
MinimumSizeChanged();
SortChildren();
QueueSortChildren();
}
protected void FitChildInPixelBox(Control child, UIBox2i pixelBox)
@@ -98,14 +95,14 @@ namespace Robust.Client.UserInterface.Controls
private void _childChanged(Control child)
{
MinimumSizeChanged();
SortChildren();
QueueSortChildren();
}
protected override void Resized()
{
base.Resized();
SortChildren();
QueueSortChildren();
}
}
}

View File

@@ -11,14 +11,6 @@ namespace Robust.Client.UserInterface.Controls
{
private int _columns = 1;
public GridContainer()
{
}
public GridContainer(string name) : base(name)
{
}
/// <summary>
/// The amount of columns to organize the children into.
/// </summary>
@@ -37,7 +29,7 @@ namespace Robust.Client.UserInterface.Controls
_columns = value;
MinimumSizeChanged();
SortChildren();
QueueSortChildren();
}
}

View File

@@ -5,14 +5,6 @@
/// </summary>
public class HBoxContainer : BoxContainer
{
public HBoxContainer() : base()
{
}
public HBoxContainer(string name) : base(name)
{
}
private protected override bool Vertical => false;
}
}

View File

@@ -4,6 +4,7 @@ namespace Robust.Client.UserInterface.Controls
{
public HScrollBar() : base(OrientationMode.Horizontal)
{
GrowVertical = GrowDirection.Begin;
}
}
}

View File

@@ -31,16 +31,13 @@ namespace Robust.Client.UserInterface.Controls
public ItemListSelectMode SelectMode { get; set; } = ItemListSelectMode.Single;
public ItemList()
{
}
public ItemList(string name) : base(name)
{
}
protected override void SetDefaults()
{
RectClipContent = true;
_scrollBar = new VScrollBar {Name = "_v_scroll"};
AddChild(_scrollBar);
_scrollBar.SetAnchorAndMarginPreset(LayoutPreset.RightWide);
_scrollBar.OnValueChanged += _ => _isAtBottom = _scrollBar.IsAtEnd;
}
private void RecalculateContentHeight()
@@ -431,16 +428,6 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override void Initialize()
{
base.Initialize();
_scrollBar = new VScrollBar {Name = "_v_scroll"};
AddChild(_scrollBar);
_scrollBar.SetAnchorAndMarginPreset(LayoutPreset.RightWide);
_scrollBar.OnValueChanged += _ => _isAtBottom = _scrollBar.IsAtEnd;
}
[Pure]
private int _getScrollSpeed()
{
@@ -479,17 +466,17 @@ namespace Robust.Client.UserInterface.Controls
public sealed class Item
{
public string Text = null;
public string TooltipText = null;
public Texture Icon = null;
public UIBox2 IconRegion = new UIBox2();
public string Text;
public string TooltipText;
public Texture Icon;
public UIBox2 IconRegion;
public Color IconModulate = Color.White;
public bool Selected = false;
public bool Selected;
public bool Selectable = true;
public bool TooltipEnabled = true;
public bool Disabled = false;
public bool Disabled;
public UIBox2? Region = null;
public UIBox2? Region;
public Vector2 IconSize
{
@@ -558,7 +545,7 @@ namespace Robust.Client.UserInterface.Controls
{
None,
Single,
Multiple,
Multiple
}
}
}

View File

@@ -20,12 +20,10 @@ namespace Robust.Client.UserInterface.Controls
private string _text;
private bool _clipText;
public Label(string name) : base(name)
{
}
public Label()
{
MouseFilter = MouseFilterMode.Ignore;
SizeFlagsVertical = SizeFlags.ShrinkCenter;
}
/// <summary>
@@ -184,7 +182,7 @@ namespace Robust.Client.UserInterface.Controls
Left = 0,
Center = 1,
Right = 2,
Fill = 3,
Fill = 3
}
public enum VAlignMode
@@ -192,7 +190,7 @@ namespace Robust.Client.UserInterface.Controls
Top = 0,
Center = 1,
Bottom = 2,
Fill = 3,
Fill = 3
}
protected override Vector2 CalculateMinimumSize()
@@ -263,11 +261,5 @@ namespace Robust.Client.UserInterface.Controls
base.StylePropertiesChanged();
}
protected override void SetDefaults()
{
base.SetDefaults();
MouseFilter = MouseFilterMode.Ignore;
SizeFlagsVertical = SizeFlags.ShrinkCenter;
}
}
}

View File

@@ -32,10 +32,9 @@ namespace Robust.Client.UserInterface.Controls
public LineEdit()
{
}
public LineEdit(string name) : base(name)
{
MouseFilter = MouseFilterMode.Stop;
CanKeyboardFocus = true;
KeyboardFocusOnClick = true;
}
public AlignMode TextAlign { get; set; }
@@ -365,15 +364,6 @@ namespace Robust.Client.UserInterface.Controls
_cursorBlinkTimer = BlinkTime;
}
protected override void SetDefaults()
{
base.SetDefaults();
MouseFilter = MouseFilterMode.Stop;
CanKeyboardFocus = true;
KeyboardFocusOnClick = true;
}
[Pure]
private Font _getFont()
{
@@ -416,7 +406,7 @@ namespace Robust.Client.UserInterface.Controls
{
Left = 0,
Center = 1,
Right = 2,
Right = 2
}
public class LineEditEventArgs : EventArgs

View File

@@ -4,14 +4,6 @@ namespace Robust.Client.UserInterface.Controls
{
public class MarginContainer : Container
{
public MarginContainer()
{
}
public MarginContainer(string name) : base(name)
{
}
public int? MarginBottomOverride { get; set; }
public int? MarginTopOverride { get; set; }
public int? MarginRightOverride { get; set; }

View File

@@ -102,7 +102,7 @@ namespace Robust.Client.UserInterface.Controls
Text = menuButton.Text,
ClipText = true,
Disabled = menuButton.Disabled,
TextAlign = Button.AlignMode.Left,
TextAlign = Button.AlignMode.Left
};
pushButton.OnPressed += _ => menuButton.OnPressed?.Invoke();
container.AddChild(pushButton);

View File

@@ -177,16 +177,6 @@ namespace Robust.Client.UserInterface.Controls
public OptionButton()
{
}
public OptionButton(string name) : base(name)
{
}
protected override void Initialize()
{
base.Initialize();
OnPressed += _onPressed;
_popup = new Popup();
UserInterfaceManager.ModalRoot.AddChild(_popup);

View File

@@ -3,10 +3,8 @@ using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Input;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using PureAttribute = System.Diagnostics.Contracts.PureAttribute;
namespace Robust.Client.UserInterface.Controls
{
@@ -27,6 +25,16 @@ namespace Robust.Client.UserInterface.Controls
public bool ScrollFollowing { get; set; } = true;
public OutputPanel()
{
RectClipContent = true;
_scrollBar = new VScrollBar {Name = "_v_scroll"};
AddChild(_scrollBar);
_scrollBar.SetAnchorAndMarginPreset(LayoutPreset.RightWide);
_scrollBar.OnValueChanged += _ => _isAtBottom = _scrollBar.IsAtEnd;
}
public StyleBox StyleBoxOverride
{
get => _styleBoxOverride;
@@ -92,16 +100,6 @@ namespace Robust.Client.UserInterface.Controls
_isAtBottom = true;
}
protected override void Initialize()
{
base.Initialize();
_scrollBar = new VScrollBar {Name = "_v_scroll"};
AddChild(_scrollBar);
_scrollBar.SetAnchorAndMarginPreset(LayoutPreset.RightWide);
_scrollBar.OnValueChanged += _ => _isAtBottom = _scrollBar.IsAtEnd;
}
protected internal override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
@@ -150,13 +148,6 @@ namespace Robust.Client.UserInterface.Controls
_isAtBottom = _scrollBar.IsAtEnd;
}
protected override void SetDefaults()
{
base.SetDefaults();
RectClipContent = true;
}
protected override void Resized()
{
base.Resized();
@@ -192,7 +183,7 @@ namespace Robust.Client.UserInterface.Controls
}
}
[Pure]
[System.Diagnostics.Contracts.Pure]
private Font _getFont()
{
if (TryGetStyleProperty("font", out Font font))
@@ -203,7 +194,7 @@ namespace Robust.Client.UserInterface.Controls
return UserInterfaceManager.ThemeDefaults.DefaultFont;
}
[Pure]
[System.Diagnostics.Contracts.Pure]
[CanBeNull]
private StyleBox _getStyleBox()
{
@@ -216,14 +207,14 @@ namespace Robust.Client.UserInterface.Controls
return box;
}
[Pure]
[System.Diagnostics.Contracts.Pure]
private int _getScrollSpeed()
{
var font = _getFont();
return font.GetLineHeight(UIScale) * 2;
}
[Pure]
[System.Diagnostics.Contracts.Pure]
private UIBox2 _getContentBox()
{
var style = _getStyleBox();

View File

@@ -7,14 +7,6 @@ namespace Robust.Client.UserInterface.Controls
{
public const string StylePropertyPanel = "panel";
public Panel(string name) : base(name)
{
}
public Panel()
{
}
private StyleBox _panelOverride;
public StyleBox PanelOverride

View File

@@ -8,15 +8,6 @@ namespace Robust.Client.UserInterface.Controls
{
public const string StylePropertyPanel = "panel";
public PanelContainer()
{
}
public PanelContainer(string name) : base(name)
{
}
private StyleBox _panelOverride;
public StyleBox PanelOverride

View File

@@ -7,10 +7,7 @@ namespace Robust.Client.UserInterface.Controls
{
public Popup()
{
}
public Popup(string name) : base(name)
{
Visible = false;
}
public event Action OnPopupHide;
@@ -39,12 +36,5 @@ namespace Robust.Client.UserInterface.Controls
Visible = false;
OnPopupHide?.Invoke();
}
protected override void SetDefaults()
{
base.SetDefaults();
Visible = false;
}
}
}

View File

@@ -12,14 +12,6 @@ namespace Robust.Client.UserInterface.Controls
private StyleBox _backgroundStyleBoxOverride;
private StyleBox _foregroundStyleBoxOverride;
public ProgressBar()
{
}
public ProgressBar(string name) : base(name)
{
}
public StyleBox BackgroundStyleBoxOverride
{
get => _backgroundStyleBoxOverride;

View File

@@ -12,14 +12,6 @@ namespace Robust.Client.UserInterface.Controls
private float _value;
private float _page;
public Range()
{
}
public Range(string name) : base(name)
{
}
public event Action<Range> OnValueChanged;
public float GetAsRatio()

View File

@@ -14,14 +14,6 @@ namespace Robust.Client.UserInterface.Controls
public float? MaxWidth { get; set; }
public RichTextLabel()
{
}
public RichTextLabel(string name) : base(name)
{
}
public void SetMessage(FormattedMessage message)
{
_message = message;

View File

@@ -19,6 +19,8 @@ namespace Robust.Client.UserInterface.Controls
protected ScrollBar(OrientationMode orientation)
{
_orientation = orientation;
MouseFilter = MouseFilterMode.Pass;
}
public bool IsAtEnd
@@ -43,13 +45,6 @@ namespace Robust.Client.UserInterface.Controls
styleBox?.Draw(handle, _getGrabberBox());
}
protected override void SetDefaults()
{
base.SetDefaults();
MouseFilter = MouseFilterMode.Pass;
}
protected internal override void MouseExited()
{
base.MouseExited();
@@ -128,10 +123,8 @@ namespace Robust.Client.UserInterface.Controls
{
return new UIBox2(grabberOffset, 0, grabberEnd, PixelHeight);
}
else
{
return new UIBox2(0, grabberOffset, PixelWidth, grabberEnd);
}
return new UIBox2(0, grabberOffset, PixelWidth, grabberEnd);
}
[System.Diagnostics.Contracts.Pure]
@@ -153,10 +146,8 @@ namespace Robust.Client.UserInterface.Controls
{
return PixelWidth;
}
else
{
return PixelHeight;
}
return PixelHeight;
}
private void _updatePseudoClass()
@@ -183,7 +174,7 @@ namespace Robust.Client.UserInterface.Controls
protected enum OrientationMode
{
Horizontal,
Vertical,
Vertical
}
}
}

View File

@@ -12,17 +12,24 @@ namespace Robust.Client.UserInterface.Controls
private bool _vScrollVisible;
private bool _hScrollVisible;
private VScrollBar _vScrollBar;
private HScrollBar _hScrollBar;
private readonly VScrollBar _vScrollBar;
private readonly HScrollBar _hScrollBar;
private bool _suppressScrollValueChanged;
public ScrollContainer()
{
}
RectClipContent = true;
public ScrollContainer(string name) : base(name)
{
Action<Range> ev = _scrollValueChanged;
_hScrollBar = new HScrollBar {Visible = false};
_vScrollBar = new VScrollBar {Visible = false};
AddChild(_hScrollBar);
AddChild(_vScrollBar);
_hScrollBar.SetAnchorAndMarginPreset(LayoutPreset.BottomWide);
_vScrollBar.SetAnchorAndMarginPreset(LayoutPreset.RightWide);
_hScrollBar.OnValueChanged += ev;
_vScrollBar.OnValueChanged += ev;
}
public bool VScrollEnabled
@@ -45,21 +52,6 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override void Initialize()
{
base.Initialize();
Action<Range> ev = _scrollValueChanged;
_hScrollBar = new HScrollBar {Visible = false};
_vScrollBar = new VScrollBar {Visible = false};
AddChild(_hScrollBar);
AddChild(_vScrollBar);
_hScrollBar.SetAnchorAndMarginPreset(LayoutPreset.BottomWide);
_vScrollBar.SetAnchorAndMarginPreset(LayoutPreset.RightWide);
_hScrollBar.OnValueChanged += ev;
_vScrollBar.OnValueChanged += ev;
}
protected internal override void SortChildren()
{
if (_vScrollBar?.Parent == null || _hScrollBar?.Parent == null)
@@ -169,13 +161,6 @@ namespace Robust.Client.UserInterface.Controls
return new Vector2(totalX, totalY);
}
protected override void SetDefaults()
{
base.SetDefaults();
RectClipContent = true;
}
protected internal override void MouseWheel(GUIMouseWheelEventArgs args)
{
base.MouseWheel(args);
@@ -228,7 +213,7 @@ namespace Robust.Client.UserInterface.Controls
return;
}
SortChildren();
QueueSortChildren();
}
}
}

View File

@@ -22,16 +22,6 @@ namespace Robust.Client.UserInterface.Controls
public SpriteView()
{
}
public SpriteView(string name) : base(name)
{
}
protected override void Initialize()
{
base.Initialize();
RectClipContent = true;
}

View File

@@ -20,14 +20,6 @@ namespace Robust.Client.UserInterface.Controls
private bool _tabsVisible = true;
private readonly List<TabData> _tabData = new List<TabData>();
public TabContainer()
{
}
public TabContainer(string name) : base(name)
{
}
public int CurrentTab
{
get => _currentTab;

View File

@@ -16,10 +16,7 @@ namespace Robust.Client.UserInterface.Controls
public TextureButton()
{
}
public TextureButton(string name) : base(name)
{
DrawModeChanged();
}
public Texture TextureNormal { get; set; }
@@ -35,13 +32,6 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override void Initialize()
{
base.Initialize();
DrawModeChanged();
}
protected override void DrawModeChanged()
{
switch (DrawMode)

View File

@@ -14,14 +14,6 @@ namespace Robust.Client.UserInterface.Controls
private Texture _texture;
private Vector2 _textureScale = Vector2.One;
public TextureRect()
{
}
public TextureRect(string name) : base(name)
{
}
/// <summary>
/// The texture to draw.
/// </summary>

View File

@@ -26,17 +26,14 @@ namespace Robust.Client.UserInterface.Controls
public event Action OnItemSelected;
#region Construction
public Tree(string name) : base(name)
{
}
public Tree()
{
}
RectClipContent = true;
#endregion Construction
_scrollBar = new VScrollBar {Name = "_v_scroll"};
AddChild(_scrollBar);
_scrollBar.SetAnchorAndMarginPreset(LayoutPreset.RightWide);
}
public void Clear()
{
@@ -83,22 +80,6 @@ namespace Robust.Client.UserInterface.Controls
return item;
}
protected override void SetDefaults()
{
base.SetDefaults();
RectClipContent = true;
}
protected override void Initialize()
{
base.Initialize();
_scrollBar = new VScrollBar {Name = "_v_scroll"};
AddChild(_scrollBar);
_scrollBar.SetAnchorAndMarginPreset(LayoutPreset.RightWide);
}
protected internal override void MouseDown(GUIMouseButtonEventArgs args)
{
base.MouseDown(args);
@@ -253,10 +234,8 @@ namespace Robust.Client.UserInterface.Controls
return sum;
}
else
{
return _getItemHeight(_root, font);
}
return _getItemHeight(_root, font);
}
private float _getItemHeight(Item item, Font font)

View File

@@ -5,14 +5,6 @@
/// </summary>
public class VBoxContainer : BoxContainer
{
public VBoxContainer()
{
}
public VBoxContainer(string name) : base(name)
{
}
private protected override bool Vertical => true;
}
}

View File

@@ -4,6 +4,7 @@
{
public VScrollBar() : base(OrientationMode.Vertical)
{
GrowHorizontal = GrowDirection.Begin;
}
}
}

View File

@@ -3,7 +3,5 @@ namespace Robust.Client.UserInterface.Controls
public class VSplitContainer : SplitContainer
{
private protected sealed override bool Vertical => true;
public VSplitContainer() {}
}
}

View File

@@ -1,12 +1,9 @@
using System.Text;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Input;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.ResourceManagement;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.State;
@@ -15,7 +12,6 @@ using Robust.Client.State.States;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Robust.Client.UserInterface.CustomControls
{
@@ -28,7 +24,7 @@ namespace Robust.Client.UserInterface.CustomControls
private readonly IClyde _displayManager;
private readonly IMapManager _mapManager;
private Label contents;
private readonly Label contents;
//TODO: Think about a factory for this
public DebugCoordsPanel(IPlayerManager playerMan,
@@ -45,18 +41,6 @@ namespace Robust.Client.UserInterface.CustomControls
_displayManager = displayMan;
_mapManager = mapMan;
PerformLayout();
}
protected override void Initialize()
{
base.Initialize();
contents = new Label();
}
private void PerformLayout()
{
SizeFlagsHorizontal = SizeFlags.None;
contents = new Label

View File

@@ -1,7 +1,6 @@
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.State;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
@@ -49,12 +48,6 @@ namespace Robust.Client.UserInterface.CustomControls
_netManager = netManager;
_mapManager = mapManager;
PerformLayout();
}
protected override void Initialize()
{
base.Initialize();
MouseFilter = MouseFilterMode.Ignore;
Visible = false;
@@ -62,10 +55,7 @@ namespace Robust.Client.UserInterface.CustomControls
MarginLeft = 2;
MarginTop = 2;
}
private void PerformLayout()
{
_fpsCounter = new FpsCounter(_gameTiming);
AddChild(_fpsCounter);

View File

@@ -35,17 +35,8 @@ namespace Robust.Client.UserInterface.CustomControls
NetManager = netMan;
GameTiming = gameTiming;
PerformLayout();
}
protected override void Initialize()
{
base.Initialize();
contents = new Label();
}
private void PerformLayout()
{
SizeFlagsHorizontal = SizeFlags.None;
contents = new Label

View File

@@ -19,18 +19,6 @@ namespace Robust.Client.UserInterface.CustomControls
{
_gameTiming = gameTiming;
PerformLayout();
}
protected override void Initialize()
{
base.Initialize();
_contents = new Label();
}
private void PerformLayout()
{
_contents = new Label
{
FontColorShadowOverride = Color.Black,

View File

@@ -55,13 +55,9 @@ namespace Robust.Client.UserInterface.CustomControls
this.placementManager = placementManager;
this.prototypeManager = prototypeManager;
this.resourceCache = resourceCache;
_loc = loc;
PerformLayout();
}
private void PerformLayout()
{
Size = new Vector2(250.0f, 300.0f);
Title = _loc.GetString("Entity Spawn Panel");
@@ -133,7 +129,7 @@ namespace Robust.Client.UserInterface.CustomControls
BuildEntityList();
placementManager.PlacementCanceled += OnPlacementCanceled;
this.placementManager.PlacementCanceled += OnPlacementCanceled;
}
protected override void Dispose(bool disposing)
@@ -282,11 +278,9 @@ namespace Robust.Client.UserInterface.CustomControls
public Label EntityLabel { get; private set; }
public TextureRect EntityTextureRect { get; private set; }
protected override void Initialize()
public EntitySpawnButton()
{
base.Initialize();
ActualButton = new Button("Button")
ActualButton = new Button
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsVertical = SizeFlags.FillExpand,
@@ -294,17 +288,17 @@ namespace Robust.Client.UserInterface.CustomControls
};
AddChild(ActualButton);
var hBoxContainer = new HBoxContainer("HBoxContainer")
var hBoxContainer = new HBoxContainer
{
MouseFilter = MouseFilterMode.Ignore,
};
var textureWrap = new Control("TextureWrap")
var textureWrap = new Control
{
CustomMinimumSize = new Vector2(32.0f, 32.0f),
MouseFilter = MouseFilterMode.Ignore,
RectClipContent = true
};
EntityTextureRect = new TextureRect("TextureRect")
EntityTextureRect = new TextureRect
{
AnchorRight = 1.0f,
AnchorBottom = 1.0f,
@@ -314,7 +308,7 @@ namespace Robust.Client.UserInterface.CustomControls
};
textureWrap.AddChild(EntityTextureRect);
EntityLabel = new Label("Label")
EntityLabel = new Label
{
SizeFlagsVertical = SizeFlags.ShrinkCenter,
Text = "Backpack"

View File

@@ -12,11 +12,6 @@ namespace Robust.Client.UserInterface.CustomControls
public FpsCounter(IGameTiming gameTiming)
{
_gameTiming = gameTiming;
}
protected override void Initialize()
{
base.Initialize();
FontColorShadowOverride = Color.Black;
ShadowOffsetXOverride = 1;

View File

@@ -39,11 +39,6 @@ namespace Robust.Client.UserInterface.CustomControls
public FrameGraph(IGameTiming gameTiming)
{
_gameTiming = gameTiming;
}
protected override void Initialize()
{
base.Initialize();
SizeFlagsHorizontal = SizeFlags.None;
}

View File

@@ -7,10 +7,10 @@ namespace Robust.Client.UserInterface.CustomControls
{
public sealed class OptionsMenu : SS14Window
{
private Button ApplyButton;
private CheckBox VSyncCheckBox;
private CheckBox FullscreenCheckBox;
private CheckBox HighResLightsCheckBox;
private readonly Button ApplyButton;
private readonly CheckBox VSyncCheckBox;
private readonly CheckBox FullscreenCheckBox;
private readonly CheckBox HighResLightsCheckBox;
private readonly IConfigurationManager configManager;
protected override Vector2? CustomSize => (180, 160);
@@ -19,18 +19,8 @@ namespace Robust.Client.UserInterface.CustomControls
{
configManager = configMan;
PerformLayout();
}
protected override void Initialize()
{
base.Initialize();
Title = "Options";
}
private void PerformLayout()
{
var vBox = new VBoxContainer();
Contents.AddChild(vBox);
vBox.SetAnchorAndMarginPreset(LayoutPreset.Wide);

View File

@@ -17,8 +17,70 @@ namespace Robust.Client.UserInterface.CustomControls
protected virtual Vector2? CustomSize => null;
public SS14Window() {}
public SS14Window(string name) : base(name) {}
public SS14Window()
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = new Color(37, 37, 42)
};
// Setup header. Includes the title label and close button.
var header = new Panel
{
AnchorRight = 1.0f, MarginBottom = 25.0f,
MouseFilter = MouseFilterMode.Ignore,
StyleClasses = {StyleClassWindowHeader}
};
header.AddStyleClass(StyleClassWindowHeader);
TitleLabel = new Label
{
ClipText = true,
AnchorRight = 1.0f,
AnchorBottom = 1.0f,
MarginRight = -25.0f,
MarginLeft = 5,
Text = "Exemplary Window Title Here",
VAlign = Label.VAlignMode.Center,
StyleClasses = {StyleClassWindowTitle}
};
CloseButton = new TextureButton
{
AnchorLeft = 1.0f, AnchorRight = 1.0f, AnchorBottom = 1.0f, MarginLeft = -25.0f,
StyleClasses = {StyleClassWindowCloseButton}
};
CloseButton.OnPressed += CloseButtonPressed;
header.AddChild(TitleLabel);
header.AddChild(CloseButton);
// Setup content area.
Contents = new MarginContainer
{
AnchorRight = 1.0f,
AnchorBottom = 1.0f,
MarginTop = 30.0f,
MarginBottomOverride = 10,
MarginLeftOverride = 10,
MarginRightOverride = 10,
MarginTopOverride = 10,
RectClipContent = true,
MouseFilter = MouseFilterMode.Ignore
};
Contents.OnMinimumSizeChanged += _ => MinimumSizeChanged();
AddChild(header);
AddChild(Contents);
AddStyleClass(StyleClassWindowPanel);
MarginLeft = 100.0f;
MarginTop = 38.0f;
MarginRight = 878.0f;
MarginBottom = 519.0f;
if (CustomSize != null)
{
Size = CustomSize.Value;
}
}
[Flags]
enum DragMode
@@ -68,73 +130,6 @@ namespace Robust.Client.UserInterface.CustomControls
// Drag resizing and moving code is mostly taken from Godot's WindowDialog.
protected override void Initialize()
{
base.Initialize();
// Set panel background color
PanelOverride = new StyleBoxFlat
{
BackgroundColor = new Color(37, 37, 42)
};
// Setup header. Includes the title label and close button.
var header = new Panel("Header")
{
AnchorRight = 1.0f, MarginBottom = 25.0f,
MouseFilter = MouseFilterMode.Ignore,
StyleClasses = { StyleClassWindowHeader }
};
header.AddStyleClass(StyleClassWindowHeader);
TitleLabel = new Label("Header Text")
{
ClipText = true,
AnchorRight = 1.0f,
AnchorBottom = 1.0f,
MarginRight = -25.0f,
MarginLeft = 5,
Text = "Exemplary Window Title Here",
VAlign = Label.VAlignMode.Center,
StyleClasses = { StyleClassWindowTitle }
};
CloseButton = new TextureButton("CloseButton")
{
AnchorLeft = 1.0f, AnchorRight = 1.0f, AnchorBottom = 1.0f, MarginLeft = -25.0f,
StyleClasses = { StyleClassWindowCloseButton }
};
CloseButton.OnPressed += CloseButtonPressed;
header.AddChild(TitleLabel);
header.AddChild(CloseButton);
// Setup content area.
Contents = new MarginContainer("Contents")
{
AnchorRight = 1.0f,
AnchorBottom = 1.0f,
MarginTop = 30.0f,
MarginBottomOverride = 10,
MarginLeftOverride = 10,
MarginRightOverride = 10,
MarginTopOverride = 10,
RectClipContent = true,
MouseFilter = MouseFilterMode.Ignore
};
Contents.OnMinimumSizeChanged += _ => MinimumSizeChanged();
AddChild(header);
AddChild(Contents);
AddStyleClass(StyleClassWindowPanel);
MarginLeft = 100.0f;
MarginTop = 38.0f;
MarginRight = 878.0f;
MarginBottom = 519.0f;
if (CustomSize != null)
{
Size = CustomSize.Value;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);

View File

@@ -12,15 +12,11 @@ namespace Robust.Client.UserInterface.CustomControls
set => _label.Text = value;
}
protected override void Initialize()
{
base.Initialize();
AddChild(_label = new Label());
}
public Tooltip()
{
MouseFilter = MouseFilterMode.Ignore;
AddChild(_label = new Label());
}
}
}

View File

@@ -5,7 +5,6 @@ using Robust.Client.Input;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.State;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
@@ -34,7 +33,6 @@ namespace Robust.Client.UserInterface
[Dependency] private readonly IGameTiming _gameTiming;
[Dependency] private readonly IPlayerManager _playerManager;
[Dependency] private readonly IEyeManager _eyeManager;
[Dependency] private readonly IResourceCache _resourceCache;
[Dependency] private readonly IStateManager _stateManager;
[Dependency] private readonly IClientNetManager _netManager;
[Dependency] private readonly IMapManager _mapManager;
@@ -66,6 +64,9 @@ namespace Robust.Client.UserInterface
private Tooltip _tooltip;
private const float TooltipDelay = 1;
private readonly Queue<Control> _styleUpdateQueue = new Queue<Control>();
private readonly Queue<Control> _layoutUpdateQueue = new Queue<Control>();
public void Initialize()
{
UIScale = _configurationManager.GetCVar<float>("display.uiScale");
@@ -91,8 +92,9 @@ namespace Robust.Client.UserInterface
private void _initializeCommon()
{
RootControl = new Control("UIRoot")
RootControl = new Control
{
Name = "UIRoot",
MouseFilter = Control.MouseFilterMode.Ignore,
IsInsideTree = true
};
@@ -100,22 +102,25 @@ namespace Robust.Client.UserInterface
RootControl.Size = _displayManager.ScreenSize / UIScale;
_displayManager.OnWindowResized += args => _updateRootSize();
StateRoot = new Control("StateRoot")
StateRoot = new Control
{
Name = "StateRoot",
MouseFilter = Control.MouseFilterMode.Ignore
};
StateRoot.SetAnchorPreset(Control.LayoutPreset.Wide);
RootControl.AddChild(StateRoot);
WindowRoot = new Control("WindowRoot")
WindowRoot = new Control
{
Name = "WindowRoot",
MouseFilter = Control.MouseFilterMode.Ignore
};
WindowRoot.SetAnchorPreset(Control.LayoutPreset.Wide);
RootControl.AddChild(WindowRoot);
ModalRoot = new Control("ModalRoot")
ModalRoot = new Control
{
Name = "ModalRoot",
MouseFilter = Control.MouseFilterMode.Ignore,
};
ModalRoot.SetAnchorPreset(Control.LayoutPreset.Wide);
@@ -147,6 +152,24 @@ namespace Robust.Client.UserInterface
{
RootControl.DoFrameUpdate(args);
// Process queued style & layout updates.
while (_styleUpdateQueue.Count != 0)
{
var control = _styleUpdateQueue.Dequeue();
control.DoStyleUpdate();
}
while (_layoutUpdateQueue.Count != 0)
{
var control = _layoutUpdateQueue.Dequeue();
control.DoLayoutUpdate();
if (control is Container container)
{
container.SortChildren();
}
}
_tooltipTimer -= args.DeltaSeconds;
if (_tooltipTimer <= 0)
{
@@ -422,6 +445,16 @@ namespace Robust.Client.UserInterface
_render(renderHandle, RootControl, Vector2i.Zero, Color.White, null);
}
public void QueueStyleUpdate(Control control)
{
_styleUpdateQueue.Enqueue(control);
}
public void QueueLayoutUpdate(Control control)
{
_layoutUpdateQueue.Enqueue(control);
}
private static void _render(IRenderHandle renderHandle, Control control, Vector2i position, Color modulate,
UIBox2i? scissorBox)
{

View File

@@ -9,7 +9,7 @@ namespace Robust.Client.ViewVariables.Editors
{
protected override Control MakeUI(object value)
{
var hBox = new HBoxContainer("ViewVariablesPropertyEditorAngle")
var hBox = new HBoxContainer
{
CustomMinimumSize = new Vector2(200, 0)
};

View File

@@ -189,7 +189,7 @@ namespace Robust.Client.ViewVariables
instance = new ViewVariablesInstanceObject(this, _resourceCache);
}
var window = new SS14Window("VV") {Title = "View Variables"};
var window = new SS14Window {Title = "View Variables"};
instance.Initialize(window, obj);
window.OnClose += () => _closeInstance(instance, false);
_windows.Add(instance, window);
@@ -198,7 +198,7 @@ namespace Robust.Client.ViewVariables
public async void OpenVV(ViewVariablesObjectSelector selector)
{
var window = new SS14Window("VV") {Title = "View Variables"};
var window = new SS14Window {Title = "View Variables"};
var loadingLabel = new Label {Text = "Retrieving remote object data from server..."};
window.Contents.AddChild(loadingLabel);

View File

@@ -43,6 +43,9 @@ namespace Robust.UnitTesting.Client.UserInterface
var control = new Control {Size = new Vector2(100, 100)};
var child = new Control {AnchorRight = 1, AnchorBottom = 1};
control.AddChild(child);
control.ForceRunLayoutUpdate();
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
@@ -87,6 +90,8 @@ namespace Robust.UnitTesting.Client.UserInterface
};
control.AddChild(child);
control.ForceRunLayoutUpdate();
Assert.That(child.Position, Is.EqualTo(new Vector2(10, 10)));
Assert.That(child.Size, Is.EqualTo(new Vector2(80, 80)));
}
@@ -98,6 +103,7 @@ namespace Robust.UnitTesting.Client.UserInterface
var child = new Control();
control.AddChild(child);
control.ForceRunLayoutUpdate();
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
Assert.That(child.Size, Is.EqualTo(Vector2.Zero));
@@ -129,6 +135,7 @@ namespace Robust.UnitTesting.Client.UserInterface
var control = new Control {Size = new Vector2(100, 100)};
var child = new Control {CustomMinimumSize = new Vector2(30, 30)};
control.AddChild(child);
control.ForceRunLayoutUpdate();
Assert.That(child.Size, Is.EqualTo(new Vector2(30, 30)));
@@ -198,6 +205,7 @@ namespace Robust.UnitTesting.Client.UserInterface
var parent = new Control {Size = (50, 50)};
var child = new Control();
parent.AddChild(child);
parent.ForceRunLayoutUpdate();
// Child should be at 0,0.
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
@@ -205,6 +213,7 @@ namespace Robust.UnitTesting.Client.UserInterface
// Making the child have a bigger minimum size should grow it to the bottom left.
// i.e. size should change, position should not.
child.CustomMinimumSize = (100, 100);
parent.ForceRunLayoutUpdate();
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
@@ -217,6 +226,7 @@ namespace Robust.UnitTesting.Client.UserInterface
var parent = new Control {Size = (50, 50)};
var child = new Control {GrowHorizontal = Control.GrowDirection.Begin};
parent.AddChild(child);
parent.ForceRunLayoutUpdate();
// Child should be at 0,0.
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
@@ -224,6 +234,7 @@ namespace Robust.UnitTesting.Client.UserInterface
// Making the child have a bigger minimum size should grow it to the bottom right.
// i.e. size should change, position should not.
child.CustomMinimumSize = (100, 100);
parent.ForceRunLayoutUpdate();
Assert.That(child.Position, Is.EqualTo(new Vector2(-100, 0)));
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
@@ -236,11 +247,13 @@ namespace Robust.UnitTesting.Client.UserInterface
var parent = new Control {Size = (50, 50)};
var child = new Control {GrowHorizontal = Control.GrowDirection.Both};
parent.AddChild(child);
parent.ForceRunLayoutUpdate();
// Child should be at 0,0.
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
child.CustomMinimumSize = (100, 100);
parent.ForceRunLayoutUpdate();
Assert.That(child.Position, Is.EqualTo(new Vector2(-50, 0)));
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
@@ -253,16 +266,19 @@ namespace Robust.UnitTesting.Client.UserInterface
var parent = new Control {Size = (50, 50)};
var child = new Control();
parent.AddChild(child);
parent.ForceRunLayoutUpdate();
// Child should be at 0,0.
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
child.CustomMinimumSize = (100, 100);
parent.ForceRunLayoutUpdate();
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
child.GrowHorizontal = Control.GrowDirection.Begin;
parent.ForceRunLayoutUpdate();
Assert.That(child.Position, Is.EqualTo(new Vector2(-100, 0)));
}

View File

@@ -1,14 +1,8 @@
using NUnit.Framework;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.Interfaces.Resources;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
using Robust.Shared.Maths;
namespace Robust.UnitTesting.Client.UserInterface.Controls
{
[TestFixture]
@@ -21,12 +15,14 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
public void TestLayoutBasic()
{
var boxContainer = new VBoxContainer {CustomMinimumSize = (50, 60)};
var control1 = new Control("1") {CustomMinimumSize = (20, 20)};
var control2 = new Control("2") {CustomMinimumSize = (30, 30)};
var control1 = new Control {CustomMinimumSize = (20, 20)};
var control2 = new Control {CustomMinimumSize = (30, 30)};
boxContainer.AddChild(control1);
boxContainer.AddChild(control2);
boxContainer.ForceRunLayoutUpdate();
Assert.That(control1.Position, Is.EqualTo(Vector2.Zero));
Assert.That(control1.Size, Is.EqualTo(new Vector2(50, 20)));
// Keep the separation in mind!
@@ -39,15 +35,17 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
public void TestLayoutExpand()
{
var boxContainer = new VBoxContainer {CustomMinimumSize = (50, 60)};
var control1 = new Control("1")
var control1 = new Control
{
SizeFlagsVertical = Control.SizeFlags.FillExpand
};
var control2 = new Control("2") {CustomMinimumSize = (30, 30)};
var control2 = new Control {CustomMinimumSize = (30, 30)};
boxContainer.AddChild(control1);
boxContainer.AddChild(control2);
boxContainer.ForceRunLayoutUpdate();
Assert.That(control1.Position, Is.EqualTo(Vector2.Zero));
Assert.That(control1.Size, Is.EqualTo(new Vector2(50, 29)));
// Keep the separation in mind!
@@ -60,11 +58,11 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
public void TestCalcMinSize()
{
var boxContainer = new VBoxContainer();
var control1 = new Control("1")
var control1 = new Control
{
CustomMinimumSize = (50, 30)
};
var control2 = new Control("2") {CustomMinimumSize = (30, 50)};
var control2 = new Control {CustomMinimumSize = (30, 50)};
boxContainer.AddChild(control1);
boxContainer.AddChild(control2);
@@ -76,20 +74,22 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
public void TestTwoExpand()
{
var boxContainer = new VBoxContainer {CustomMinimumSize = (30, 82)};
var control1 = new Control("1")
var control1 = new Control
{
SizeFlagsVertical = Control.SizeFlags.FillExpand
};
var control2 = new Control("2")
var control2 = new Control
{
SizeFlagsVertical = Control.SizeFlags.FillExpand
};
var control3 = new Control("3") {CustomMinimumSize = (0, 50)};
var control3 = new Control {CustomMinimumSize = (0, 50)};
boxContainer.AddChild(control1);
boxContainer.AddChild(control3);
boxContainer.AddChild(control2);
boxContainer.ForceRunLayoutUpdate();
Assert.That(control1.Position, Is.EqualTo(Vector2.Zero));
Assert.That(control1.Size, Is.EqualTo(new Vector2(30, 15)));
Assert.That(control3.Position, Is.EqualTo(new Vector2(0, 16)));

View File

@@ -23,6 +23,9 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
var child = new Control {CustomMinimumSize = (50, 50)};
container.AddChild(child);
container.ForceRunLayoutUpdate();
Assert.That(container.CombinedMinimumSize, Is.EqualTo(new Vector2(50, 50)));
Assert.That(child.Position, Is.EqualTo(new Vector2(25, 25)));
Assert.That(child.Size, Is.EqualTo(new Vector2(50, 50)));

View File

@@ -32,6 +32,8 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
grid.AddChild(child4);
grid.AddChild(child5);
grid.ForceRunLayoutUpdate();
Assert.That(grid.CombinedMinimumSize, Is.EqualTo(new Vector2(104, 158)));
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
@@ -57,6 +59,8 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
grid.AddChild(child4);
grid.AddChild(child5);
grid.ForceRunLayoutUpdate();
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
Assert.That(child1.Size, Is.EqualTo(new Vector2(146, 50)));
Assert.That(child2.Position, Is.EqualTo(new Vector2(150, 0)));

View File

@@ -71,11 +71,16 @@ namespace Robust.UnitTesting.Client.UserInterface
uiMgr.Stylesheet = sheet;
var control = new Label();
uiMgr.StateRoot.AddChild(control);
control.ForceRunStyleUpdate();
control.TryGetStyleProperty("foo", out string value);
Assert.That(value, Is.EqualTo("bar"));
control.StyleIdentifier = "baz";
control.ForceRunStyleUpdate();
control.TryGetStyleProperty("foo", out value);
Assert.That(value, Is.EqualTo("honk"));
}

View File

@@ -137,8 +137,8 @@ namespace Robust.UnitTesting.Client.UserInterface
public void TestGrabKeyboardFocus()
{
Assert.That(_userInterfaceManager.KeyboardFocused, Is.Null);
var control1 = new Control("Control1") {CanKeyboardFocus = true};
var control2 = new Control("Control2") {CanKeyboardFocus = true};
var control1 = new Control {CanKeyboardFocus = true};
var control2 = new Control {CanKeyboardFocus = true};
control1.GrabKeyboardFocus();
Assert.That(_userInterfaceManager.KeyboardFocused, Is.EqualTo(control1));
@@ -155,8 +155,8 @@ namespace Robust.UnitTesting.Client.UserInterface
public void TestGrabKeyboardFocusSteal()
{
Assert.That(_userInterfaceManager.KeyboardFocused, Is.Null);
var control1 = new Control("Control1") {CanKeyboardFocus = true};
var control2 = new Control("Control2") {CanKeyboardFocus = true};
var control1 = new Control {CanKeyboardFocus = true};
var control2 = new Control {CanKeyboardFocus = true};
control1.GrabKeyboardFocus();
control2.GrabKeyboardFocus();
@@ -172,8 +172,8 @@ namespace Robust.UnitTesting.Client.UserInterface
public void TestGrabKeyboardFocusOtherRelease()
{
Assert.That(_userInterfaceManager.KeyboardFocused, Is.Null);
var control1 = new Control("Control1") {CanKeyboardFocus = true};
var control2 = new Control("Control2") {CanKeyboardFocus = true};
var control1 = new Control {CanKeyboardFocus = true};
var control2 = new Control {CanKeyboardFocus = true};
control1.GrabKeyboardFocus();
control2.ReleaseKeyboardFocus();
@@ -212,6 +212,8 @@ namespace Robust.UnitTesting.Client.UserInterface
_userInterfaceManager.RootControl.AddChild(control);
_userInterfaceManager.RootControl.ForceRunLayoutUpdate();
var mouseEvent = new MouseButtonEventArgs(Mouse.Button.Left, false, Mouse.ButtonMask.None,
new Vector2(30, 30), false, false, false, false);