mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
New GridContainer capabilities and customizable tooltips (#1395)
* #272 avoid mouse overlapping tooltip when near edges, change tooltip colors to match mockups * #272 WIP customizable tooltips, old approach currently working still * #272 WIP customizable tooltips, old approach currently working still * #272 ensure tooltips go away when disposing control * #272 implement row-oriented GridContainer * #272 generalize GridContainer to support rows or cols * #272 improve readability in new GridContainer logic * #272 GridContainer can expand in opposite direction * #272 GridContainer can expand in opposite direction * #272 GridContainer can expand in opposite direction, fix test * #272 add GridContainer capability to limit by size rather than count * #272 add some clarifications about ui scale and vp / rp * #272 don't spam showtooltip event, calculate tooltip positioning using combined minimum size
This commit is contained in:
@@ -34,7 +34,7 @@ namespace Robust.Client.Interfaces.UserInterface
|
||||
Control? CurrentlyHovered { get; }
|
||||
|
||||
float UIScale { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default UIScale that we will use if <see cref="CVars.DisplayUIScale"/> gets set to 0.
|
||||
/// Based on the OS-assigned window scale factor.
|
||||
@@ -134,6 +134,10 @@ namespace Robust.Client.Interfaces.UserInterface
|
||||
void QueueStyleUpdate(Control control);
|
||||
void QueueLayoutUpdate(Control control);
|
||||
void CursorChanged(Control control);
|
||||
/// <summary>
|
||||
/// Hides the tooltip for the indicated control, if tooltip for that control is currently showing.
|
||||
/// </summary>
|
||||
void HideTooltipFor(Control control);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ namespace Robust.Client.UserInterface
|
||||
/// <summary>
|
||||
/// The amount of "real" pixels a virtual pixel takes up.
|
||||
/// The higher the number, the bigger the interface.
|
||||
/// I.e. UIScale units are real pixels (rp) / virtual pixels (vp),
|
||||
/// real pixels varies depending on interface, virtual pixels doesn't.
|
||||
/// And vp * UIScale = rp, and rp / UIScale = vp
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
protected float UIScale => UserInterfaceManager.UIScale;
|
||||
|
||||
@@ -192,13 +192,42 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The tooltip that is shown when the mouse is hovered over this control for a bit.
|
||||
/// Simple text tooltip that is shown when the mouse is hovered over this control for a bit.
|
||||
/// See <see cref="OnShowTooltip"/> for a more customizable alternative.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If empty or null, no tooltip is shown in the first place.
|
||||
/// If empty or null, no tooltip is shown in the first place (but OnShowTooltip and OnHideTooltip
|
||||
/// events are still fired).
|
||||
/// </remarks>
|
||||
public string? ToolTip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the mouse is hovered over this control for a bit and a tooltip
|
||||
/// should be shown. Can be used as an alternative to ToolTip to perform custom tooltip
|
||||
/// logic such as showing a more complex tooltip control.
|
||||
///
|
||||
/// Any custom tooltip controls should typically be added
|
||||
/// as a child of UserInterfaceManager.PopupRoot
|
||||
/// Handlers can use <see cref="Tooltips.PositionTooltip(Control)"/> to assist with positioning
|
||||
/// custom tooltip controls.
|
||||
/// </summary>
|
||||
public event EventHandler? OnShowTooltip;
|
||||
|
||||
internal void PerformShowTooltip()
|
||||
{
|
||||
OnShowTooltip?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when this control is showing a tooltip which should now be hidden.
|
||||
/// </summary>
|
||||
public event EventHandler? OnHideTooltip;
|
||||
|
||||
internal void PerformHideTooltip()
|
||||
{
|
||||
OnHideTooltip?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The mode that controls how mouse filtering works. See the enum for how it functions.
|
||||
/// </summary>
|
||||
@@ -373,6 +402,8 @@ namespace Robust.Client.UserInterface
|
||||
return;
|
||||
}
|
||||
|
||||
UserInterfaceManagerInternal.HideTooltipFor(this);
|
||||
|
||||
DisposeAllChildren();
|
||||
Parent?.RemoveChild(this);
|
||||
|
||||
|
||||
@@ -1,59 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A container that lays out its children in a grid.
|
||||
/// A container that lays out its children in a grid. Can define specific count of
|
||||
/// rows or specific count of columns (not both), and will grow to fill in additional rows/columns within
|
||||
/// that limit. Alternatively, can define a maximum width or height, and grid will
|
||||
/// lay out elements (aligned in a grid pattern, not floated) within the defined limit.
|
||||
/// </summary>
|
||||
public class GridContainer : Container
|
||||
{
|
||||
private int _columns = 1;
|
||||
// limit - depending on mode, this is either rows or columns
|
||||
private int _limitedDimensionCount = 1;
|
||||
// virtual pixels
|
||||
private float _limitSize;
|
||||
private LimitType _limitType = LimitType.Count;
|
||||
private Dimension _limitDimension = Dimension.Column;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The amount of columns to organize the children into.
|
||||
/// Indicates whether row or column count has been specified, and thus
|
||||
/// how items will fill them out as they are added.
|
||||
/// This is set depending on whether you have specified Columns or Rows.
|
||||
/// </summary>
|
||||
public Dimension LimitedDimension => _limitDimension;
|
||||
/// <summary>
|
||||
/// Opposite dimension of LimitedDimension
|
||||
/// </summary>
|
||||
public Dimension UnlimitedDimension => _limitDimension == Dimension.Column ? Dimension.Row : Dimension.Column;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether we are limiting based on an explicit number of rows or columns, or limiting
|
||||
/// based on a defined max width or height.
|
||||
/// </summary>
|
||||
public LimitType LimitType => _limitType;
|
||||
|
||||
/// <summary>
|
||||
/// The "normal" direction of expansion when the defined row or column limit is met
|
||||
/// is right (for row-limited) and down (for column-limited),
|
||||
/// this inverts that so the container expands in the opposite direction as elements are added.
|
||||
/// </summary>
|
||||
public bool ExpandBackwards
|
||||
{
|
||||
get => _expandBackwards;
|
||||
set
|
||||
{
|
||||
_expandBackwards = value;
|
||||
UpdateLayout();
|
||||
}
|
||||
}
|
||||
private bool _expandBackwards;
|
||||
|
||||
/// <summary>
|
||||
/// The number of columns to organize the children into. Setting this puts this grid
|
||||
/// into LimitMode.LimitColumns and LimitType.Count - items will be added to fill up the entire row, up to the defined
|
||||
/// limit of columns, and then create a second row.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown if the value assigned is less than or equal to 0.
|
||||
/// </exception>
|
||||
/// <returns>specified limit if LimitMode.LimitColums, otherwise the number
|
||||
/// of columns being used for the current amount of children.</returns>
|
||||
public int Columns
|
||||
{
|
||||
get => _columns;
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, "Value must be greater than zero.");
|
||||
}
|
||||
|
||||
_columns = value;
|
||||
MinimumSizeChanged();
|
||||
UpdateLayout();
|
||||
}
|
||||
get => GetCount(Dimension.Column);
|
||||
set => SetCount(Dimension.Column, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The amount of rows being used for the current amount of children.
|
||||
/// The number of rows to organize the children into. Setting this puts this grid
|
||||
/// into LimitMode.LimitRows and LimitType.Count - items will be added to fill up the entire column, up to the defined
|
||||
/// limit of rows, and then create a second column.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown if the value assigned is less than or equal to 0.
|
||||
/// </exception>
|
||||
/// <returns>specified limit if LimitMode.LimitRows, otherwise the number
|
||||
/// of rows being used for the current number of children.</returns>
|
||||
public int Rows
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ChildCount == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
var div = ChildCount / Columns;
|
||||
if (ChildCount % Columns != 0)
|
||||
{
|
||||
div += 1;
|
||||
}
|
||||
|
||||
return div;
|
||||
}
|
||||
get => GetCount(Dimension.Row);
|
||||
set => SetCount(Dimension.Row, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// The max width (in virtual pixels) the grid of elements can have. This dynamically determines
|
||||
/// the number of columns based on the size of the elements. Setting this puts this grid
|
||||
/// into LimitMode.LimitColumns and LimitType.Size. Items will be added to fill up the entire row, up to the defined
|
||||
/// width, and then create a second row.
|
||||
///
|
||||
/// In the presence of unevenly-sized children,
|
||||
/// rows will still have the same amount elements - the items are laid out in a grid pattern such
|
||||
/// that they are all aligned, the height and width of each "cell" being determined by
|
||||
/// the greatest min height and min width among the elements. In the presence of expanding elements,
|
||||
/// their pre-expanded size will be used to determine the cell layout, then the elements expand within
|
||||
/// the defined Control.Size
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown if the value assigned is less than or equal to 0.
|
||||
/// </exception>
|
||||
public float MaxWidth
|
||||
{
|
||||
set => SetMaxSize(Dimension.Column, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// The max height (in virtual pixels) the grid of elements can have. This dynamically determines
|
||||
/// the number of rows based on the size of the elements. Setting this puts this grid
|
||||
/// into LimitMode.LimitRows and LimitType.Size - items will be added to fill up the entire column, up to the defined
|
||||
/// height, and then create a second column.
|
||||
///
|
||||
/// In the presence of unevenly-sized children,
|
||||
/// columns will still have the same amount elements - the items are laid out in a grid pattern such
|
||||
/// that they are all aligned, the height and width of each "cell" being determined by
|
||||
/// the greatest min height and min width among the elements. In the presence of expanding elements,
|
||||
/// their pre-expanded size will be used to determine the layout, then the elements expand within
|
||||
/// the defined Control.Size
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown if the value assigned is less than or equal to 0.
|
||||
/// </exception>
|
||||
public float MaxHeight
|
||||
{
|
||||
set => SetMaxSize(Dimension.Row, value);
|
||||
}
|
||||
|
||||
|
||||
private int? _vSeparationOverride;
|
||||
|
||||
@@ -75,15 +148,146 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
private Vector2i Separations => (_hSeparationOverride ?? 4, _vSeparationOverride ?? 4);
|
||||
|
||||
private float GetLimitPixelSize()
|
||||
{
|
||||
return _limitSize * UIScale;
|
||||
}
|
||||
|
||||
private int GetCount(Dimension forDimension)
|
||||
{
|
||||
if (_limitType == LimitType.Count)
|
||||
{
|
||||
if (forDimension == _limitDimension) return _limitedDimensionCount;
|
||||
if (ChildCount == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
var divisor = (_limitDimension == Dimension.Column ? Columns : Rows);
|
||||
var div = ChildCount / divisor;
|
||||
if (ChildCount % divisor != 0)
|
||||
{
|
||||
div += 1;
|
||||
}
|
||||
|
||||
return div;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (forDimension == _limitDimension) return CalculateLimitedCount();
|
||||
if (ChildCount == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
var divisor = CalculateLimitedCount();;
|
||||
var div = ChildCount / divisor;
|
||||
if (ChildCount % divisor != 0)
|
||||
{
|
||||
div += 1;
|
||||
}
|
||||
|
||||
return div;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCount(Dimension forDimension, int value)
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, "Value must be greater than zero.");
|
||||
}
|
||||
|
||||
_limitDimension = forDimension;
|
||||
_limitType = LimitType.Count;
|
||||
|
||||
_limitedDimensionCount = value;
|
||||
MinimumSizeChanged();
|
||||
UpdateLayout();
|
||||
}
|
||||
|
||||
private void SetMaxSize(Dimension forDimension, float value)
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, "Value must be greater than zero.");
|
||||
}
|
||||
|
||||
_limitDimension = forDimension;
|
||||
_limitType = LimitType.Size;
|
||||
|
||||
_limitSize = value;
|
||||
MinimumSizeChanged();
|
||||
UpdateLayout();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If columns (or width) are being limited, calculates how many columns
|
||||
/// there should be.
|
||||
/// </summary>
|
||||
private int CalculateLimitedCount()
|
||||
{
|
||||
if (_limitType == LimitType.Count) return _limitedDimensionCount;
|
||||
|
||||
// to make it easier to read and visualize, we're just going to use the terms "x" and "y", width, and height,
|
||||
// rows and cols,
|
||||
// but at the start of the method here we'll set those to what they actually are based
|
||||
// on the limited dimension, which might involve swapping them.
|
||||
// For the below convention, we pretend that columns (or width) have a limit defined, thus
|
||||
// the amount of rows is not limited (unlimited).
|
||||
|
||||
// we convert all elements to "cells" of the same size so they will align,
|
||||
// also converting to our pretend scenario of limited columns/width
|
||||
var (cellWidthActual, cellHeightActual) = CellSize();
|
||||
var (wSepActual, hSepActual) = (Vector2i) (Separations * UIScale);
|
||||
var cellWidth = _limitDimension == Dimension.Column ? cellWidthActual : cellHeightActual;
|
||||
var wSep = _limitDimension == Dimension.Column ? wSepActual : hSepActual;
|
||||
|
||||
// calculate how many cells will fit into a given column without going over, accounting
|
||||
// for additional wSep between each cell only if there's more than one
|
||||
if (ChildCount == 0) return 1;
|
||||
|
||||
if ((2 * cellWidth + wSep) > GetLimitPixelSize())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return Math.Min(ChildCount, (int) ((GetLimitPixelSize() + wSep) / (cellWidth + wSep)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the size of a "cell" in physical pixels, for use in LimitType.Size mode. This
|
||||
/// is based on the maximum minheight / minwidth of each element.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Vector2i CellSize()
|
||||
{
|
||||
int maxMinWidth = -1;
|
||||
int maxMinHeight = -1;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
var (minSizeX, minSizeY) = child.CombinedPixelMinimumSize;
|
||||
maxMinWidth = Math.Max(maxMinWidth, minSizeX);
|
||||
maxMinHeight = Math.Max(maxMinHeight, minSizeY);
|
||||
}
|
||||
|
||||
return new Vector2i(maxMinWidth, maxMinHeight);
|
||||
}
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
var (wSep, hSep) = (Vector2i) (Separations * UIScale);
|
||||
var rows = Rows;
|
||||
// to make it easier to read and visualize, we're just going to use the terms "x" and "y", width, and height,
|
||||
// rows and cols,
|
||||
// but at the start of the method here we'll set those to what they actually are based
|
||||
// on the limited dimension, which might involve swapping them.
|
||||
// For the below convention, we pretend that columns have a limit defined, thus
|
||||
// the amount of rows is not limited (unlimited).
|
||||
|
||||
// Minimum width of the columns.
|
||||
Span<int> columnSizes = stackalloc int[_columns];
|
||||
// Minimum height of the rows.
|
||||
Span<int> rowSizes = stackalloc int[rows];
|
||||
var rows = GetCount(UnlimitedDimension);
|
||||
var cols = GetCount(LimitedDimension);
|
||||
var cellSize = CellSize();
|
||||
|
||||
Span<int> minColWidth = stackalloc int[cols];
|
||||
Span<int> minRowHeight = stackalloc int[rows];
|
||||
|
||||
var index = 0;
|
||||
foreach (var child in Children)
|
||||
@@ -94,34 +298,45 @@ namespace Robust.Client.UserInterface.Controls
|
||||
continue;
|
||||
}
|
||||
|
||||
var row = index / _columns;
|
||||
var column = index % _columns;
|
||||
var column = index % cols;
|
||||
var row = index / cols;
|
||||
|
||||
var (minSizeX, minSizeY) = child.CombinedPixelMinimumSize;
|
||||
columnSizes[column] = Math.Max(minSizeX, columnSizes[column]);
|
||||
rowSizes[row] = Math.Max(minSizeY, rowSizes[row]);
|
||||
// also converting here to our "pretend" scenario where columns have a limit defined.
|
||||
// note if we are limiting by size rather than count, the size of each child is constant (cell size)
|
||||
var (minSizeXActual, minSizeYActual) = _limitType == LimitType.Count ? child.CombinedPixelMinimumSize : cellSize;
|
||||
var minSizeX = _limitDimension == Dimension.Column ? minSizeXActual : minSizeYActual;
|
||||
var minSizeY = _limitDimension == Dimension.Column ? minSizeYActual : minSizeXActual;
|
||||
minColWidth[column] = Math.Max(minSizeX, minColWidth[column]);
|
||||
minRowHeight[row] = Math.Max(minSizeY, minRowHeight[row]);
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
var minWidth = AccumSizes(columnSizes, wSep);
|
||||
var minHeight = AccumSizes(rowSizes, hSep);
|
||||
// converting here to our "pretend" scenario where columns have a limit defined
|
||||
var (wSepActual, hSepActual) = (Vector2i) (Separations * UIScale);
|
||||
var wSep = _limitDimension == Dimension.Column ? wSepActual : hSepActual;
|
||||
var hSep = _limitDimension == Dimension.Column ? hSepActual : wSepActual;
|
||||
var minWidth = AccumSizes(minColWidth, wSep);
|
||||
var minHeight = AccumSizes(minRowHeight, hSep);
|
||||
|
||||
return new Vector2(minWidth, minHeight) / UIScale;
|
||||
// converting back from our pretend scenario where columns are limited
|
||||
return new Vector2(
|
||||
_limitDimension == Dimension.Column ? minWidth : minHeight,
|
||||
_limitDimension == Dimension.Column ? minHeight : minWidth) / UIScale;
|
||||
}
|
||||
|
||||
private static int AccumSizes(Span<int> sizes, int separator)
|
||||
{
|
||||
var totalSize = 0;
|
||||
var firstColumn = true;
|
||||
var first = true;
|
||||
|
||||
foreach (var size in sizes)
|
||||
{
|
||||
totalSize += size;
|
||||
|
||||
if (firstColumn)
|
||||
if (first)
|
||||
{
|
||||
firstColumn = false;
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -134,15 +349,24 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
protected override void LayoutUpdateOverride()
|
||||
{
|
||||
var rows = Rows;
|
||||
// to make it easier to read and visualize, we're just going to use the terms "x" and "y", width, and height,
|
||||
// rows and cols,
|
||||
// but at the start of the method here we'll set those to what they actually are based
|
||||
// on the limited dimension, which might involve swapping them.
|
||||
// For the below convention, we pretend that columns have a limit defined, thus
|
||||
// the amount of rows is not limited (unlimited).
|
||||
|
||||
// Minimum width of the columns.
|
||||
Span<int> columnSizes = stackalloc int[_columns];
|
||||
// Minimum height of the rows.
|
||||
Span<int> rowSizes = stackalloc int[rows];
|
||||
// Columns that are set to expand horizontally.
|
||||
Span<bool> columnExpand = stackalloc bool[_columns];
|
||||
// Columns that are set to expand vertically.
|
||||
var rows = GetCount(UnlimitedDimension);
|
||||
var cols = GetCount(LimitedDimension);
|
||||
var cellSize = CellSize();
|
||||
|
||||
Span<int> minColWidth = stackalloc int[cols];
|
||||
// Minimum lateral size of the unlimited dimension
|
||||
// (i.e. width of columns, height of rows).
|
||||
Span<int> minRowHeight = stackalloc int[rows];
|
||||
// columns that are set to expand vertically
|
||||
Span<bool> colExpand = stackalloc bool[cols];
|
||||
// rows that are set to expand horizontally
|
||||
Span<bool> rowExpand = stackalloc bool[rows];
|
||||
|
||||
// Get minSize and size flag expand of each column and row.
|
||||
@@ -155,20 +379,29 @@ namespace Robust.Client.UserInterface.Controls
|
||||
continue;
|
||||
}
|
||||
|
||||
var row = index / _columns;
|
||||
var column = index % _columns;
|
||||
var column = index % cols;
|
||||
var row = index / cols;
|
||||
|
||||
var (minSizeX, minSizeY) = child.CombinedPixelMinimumSize;
|
||||
columnSizes[column] = Math.Max(minSizeX, columnSizes[column]);
|
||||
rowSizes[row] = Math.Max(minSizeY, rowSizes[row]);
|
||||
columnExpand[column] = columnExpand[column] || (child.SizeFlagsHorizontal & SizeFlags.Expand) != 0;
|
||||
rowExpand[row] = rowExpand[row] || (child.SizeFlagsVertical & SizeFlags.Expand) != 0;
|
||||
// converting here to our "pretend" scenario where columns have a limit defined
|
||||
// note if we are limiting by size rather than count, the size of each child is constant (cell size)
|
||||
var (minSizeXActual, minSizeYActual) = _limitType == LimitType.Count ? child.CombinedPixelMinimumSize : cellSize;
|
||||
var minSizeX = _limitDimension == Dimension.Column ? minSizeXActual : minSizeYActual;
|
||||
var minSizeY = _limitDimension == Dimension.Column ? minSizeYActual : minSizeXActual;
|
||||
minColWidth[column] = Math.Max(minSizeX, minColWidth[column]);
|
||||
minRowHeight[row] = Math.Max(minSizeY, minRowHeight[row]);
|
||||
var colSizeFlag = _limitDimension == Dimension.Column
|
||||
? child.SizeFlagsHorizontal
|
||||
: child.SizeFlagsVertical;
|
||||
var rowSizeFlag = UnlimitedDimension == Dimension.Column
|
||||
? child.SizeFlagsHorizontal
|
||||
: child.SizeFlagsVertical;
|
||||
colExpand[column] = colExpand[column] || (colSizeFlag & SizeFlags.Expand) != 0;
|
||||
rowExpand[row] = rowExpand[row] || (rowSizeFlag & SizeFlags.Expand) != 0;
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
// Basically now we just apply BoxContainer logic on rows and columns.
|
||||
var (vSep, hSep) = (Vector2i) (Separations * UIScale);
|
||||
var stretchMinX = 0;
|
||||
var stretchMinY = 0;
|
||||
// We do not use stretch ratios because Godot doesn't,
|
||||
@@ -179,11 +412,11 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var stretchCountX = 0;
|
||||
var stretchCountY = 0;
|
||||
|
||||
for (var i = 0; i < columnSizes.Length; i++)
|
||||
for (var i = 0; i < minColWidth.Length; i++)
|
||||
{
|
||||
if (!columnExpand[i])
|
||||
if (!colExpand[i])
|
||||
{
|
||||
stretchMinX += columnSizes[i];
|
||||
stretchMinX += minColWidth[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -191,11 +424,11 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < rowSizes.Length; i++)
|
||||
for (var i = 0; i < minRowHeight.Length; i++)
|
||||
{
|
||||
if (!rowExpand[i])
|
||||
{
|
||||
stretchMinY += rowSizes[i];
|
||||
stretchMinY += minRowHeight[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -203,35 +436,74 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
}
|
||||
|
||||
var stretchMaxX = Width - hSep * (_columns - 1);
|
||||
var stretchMaxY = Height - vSep * (rows - 1);
|
||||
// converting here to our "pretend" scenario where columns have a limit defined
|
||||
var (vSepActual, hSepActual) = (Vector2i) (Separations * UIScale);
|
||||
var hSep = _limitDimension == Dimension.Column ? hSepActual : vSepActual;
|
||||
var vSep = _limitDimension == Dimension.Column ? vSepActual : hSepActual;
|
||||
var width = _limitDimension == Dimension.Column ? Width : Height;
|
||||
var height = _limitDimension == Dimension.Column ? Height : Width;
|
||||
|
||||
var stretchMaxX = width - hSep * (cols - 1);
|
||||
var stretchMaxY = height - vSep * (rows - 1);
|
||||
|
||||
var stretchAvailX = Math.Max(0, stretchMaxX - stretchMinX);
|
||||
var stretchAvailY = Math.Max(0, stretchMaxY - stretchMinY);
|
||||
|
||||
for (var i = 0; i < columnSizes.Length; i++)
|
||||
for (var i = 0; i < minColWidth.Length; i++)
|
||||
{
|
||||
if (!columnExpand[i])
|
||||
if (!colExpand[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
columnSizes[i] = (int) (stretchAvailX / stretchCountX);
|
||||
minColWidth[i] = (int) (stretchAvailX / stretchCountX);
|
||||
}
|
||||
|
||||
for (var i = 0; i < rowSizes.Length; i++)
|
||||
for (var i = 0; i < minRowHeight.Length; i++)
|
||||
{
|
||||
if (!rowExpand[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rowSizes[i] = (int) (stretchAvailY / stretchCountY);
|
||||
minRowHeight[i] = (int) (stretchAvailY / stretchCountY);
|
||||
}
|
||||
|
||||
// Actually lay them out.
|
||||
var vOffset = 0;
|
||||
// if inverted, (in our pretend "columns are limited" scenario) we must calculate the final
|
||||
// height (as height will vary depending on number of elements), and then
|
||||
// go backwards, starting from the bottom and filling elements in upwards
|
||||
var finalVOffset = 0;
|
||||
if (ExpandBackwards)
|
||||
{
|
||||
// we have to iterate through the elements first to determine the height each
|
||||
// row will end up having, as they can vary
|
||||
index = 0;
|
||||
for (var i = 0; i < ChildCount; i++, index++)
|
||||
{
|
||||
var child = GetChild(i);
|
||||
if (!child.Visible)
|
||||
{
|
||||
index--;
|
||||
continue;
|
||||
}
|
||||
|
||||
var column = index % cols;
|
||||
var row = index / cols;
|
||||
|
||||
if (column == 0)
|
||||
{
|
||||
// Just started a new row/col.
|
||||
if (row != 0)
|
||||
{
|
||||
finalVOffset += vSep + minRowHeight[row - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var hOffset = 0;
|
||||
var vOffset = ExpandBackwards ? finalVOffset : 0;
|
||||
index = 0;
|
||||
for (var i = 0; i < ChildCount; i++, index++)
|
||||
{
|
||||
@@ -242,24 +514,59 @@ namespace Robust.Client.UserInterface.Controls
|
||||
continue;
|
||||
}
|
||||
|
||||
var row = index / _columns;
|
||||
var column = index % _columns;
|
||||
var column = index % cols;
|
||||
var row = index / cols;
|
||||
|
||||
if (column == 0)
|
||||
{
|
||||
// Just started a new row.
|
||||
// Just started a new row
|
||||
hOffset = 0;
|
||||
if (row != 0)
|
||||
{
|
||||
vOffset += vSep + rowSizes[row - 1];
|
||||
if (ExpandBackwards)
|
||||
{
|
||||
// every time we start a new row we actually decrease the voffset, we are filling
|
||||
// in the up direction
|
||||
vOffset -= vSep + minRowHeight[row - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
vOffset += vSep + minRowHeight[row - 1];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var box = UIBox2i.FromDimensions(hOffset, vOffset, columnSizes[column], rowSizes[row]);
|
||||
// converting back from our "pretend" scenario
|
||||
var left = _limitDimension == Dimension.Column ? hOffset : vOffset;
|
||||
var top = _limitDimension == Dimension.Column ? vOffset : hOffset;
|
||||
var boxWidth = _limitDimension == Dimension.Column ? minColWidth[column] : minRowHeight[row];
|
||||
var boxHeight = _limitDimension == Dimension.Column ? minRowHeight[row] : minColWidth[column];
|
||||
|
||||
var box = UIBox2i.FromDimensions(left, top, boxWidth, boxHeight);
|
||||
FitChildInPixelBox(child, box);
|
||||
|
||||
hOffset += columnSizes[column] + hSep;
|
||||
hOffset += minColWidth[column] + hSep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Dimension
|
||||
{
|
||||
Column,
|
||||
Row
|
||||
}
|
||||
|
||||
public enum LimitType
|
||||
{
|
||||
/// <summary>
|
||||
/// Defined number of rows or columns
|
||||
/// </summary>
|
||||
Count,
|
||||
/// <summary>
|
||||
/// Defined max width or height, inside of which the number of rows or columns
|
||||
/// will be fit.
|
||||
/// </summary>
|
||||
Size
|
||||
}
|
||||
}
|
||||
|
||||
56
Robust.Client/UserInterface/Tooltips.cs
Normal file
56
Robust.Client/UserInterface/Tooltips.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.UserInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// Utilities for working with tooltips.
|
||||
/// </summary>
|
||||
public static class Tooltips
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Positions the provided control as a tooltip within the bounds of its parent UserInterfaceManager screen
|
||||
/// under the current mouse position. Sizing Based on its current combined minimum size.
|
||||
/// Defaults to the top left corner
|
||||
/// of the control being placed at the mouse position but
|
||||
/// adjusting to a different corner if the control would go beyond the edge of the bounds.
|
||||
/// </summary>
|
||||
/// <param name="tooltip">control to position (current size will be used to determine bounds)</param>
|
||||
public static void PositionTooltip(Control tooltip)
|
||||
{
|
||||
PositionTooltip(tooltip.UserInterfaceManager.RootControl.Size,
|
||||
tooltip.UserInterfaceManager.MousePositionScaled,
|
||||
tooltip);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Positions the provided control as a tooltip within the provided screenBounds based on its current
|
||||
/// combined minimum size.
|
||||
/// Defaults to the top left corner
|
||||
/// of the control being placed at the indicated position but
|
||||
/// adjusting to a different corner if the control would go beyond the edge of the bounds.
|
||||
/// </summary>
|
||||
/// <param name="screenBounds">max x and y screen coordinates for the tooltip to occupy, tooltip
|
||||
/// will be shifted to avoid exceeding these bounds.</param>
|
||||
/// <param name="screenPosition">position to place the tooltip at, in screen coordinates</param>
|
||||
/// <param name="tooltip">control to position (current size will be used to determine bounds)</param>
|
||||
public static void PositionTooltip(Vector2 screenBounds, Vector2 screenPosition, Control tooltip)
|
||||
{
|
||||
LayoutContainer.SetPosition(tooltip, screenPosition);
|
||||
|
||||
var combinedMinSize = tooltip.CombinedMinimumSize;
|
||||
var (right, bottom) = tooltip.Position + combinedMinSize;
|
||||
|
||||
if (right > screenBounds.X)
|
||||
{
|
||||
LayoutContainer.SetPosition(tooltip, (screenPosition.X - combinedMinSize.X, tooltip.Position.Y));
|
||||
}
|
||||
|
||||
if (bottom > screenBounds.Y)
|
||||
{
|
||||
LayoutContainer.SetPosition(tooltip, (tooltip.Position.X, screenPosition.Y - combinedMinSize.Y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,7 @@ namespace Robust.Client.UserInterface
|
||||
private bool _rendering = true;
|
||||
private float _tooltipTimer;
|
||||
private Tooltip _tooltip = default!;
|
||||
private bool showingTooltip;
|
||||
private const float TooltipDelay = 1;
|
||||
|
||||
private readonly Queue<Control> _styleUpdateQueue = new Queue<Control>();
|
||||
@@ -692,8 +693,20 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
private void _clearTooltip()
|
||||
{
|
||||
if (!showingTooltip) return;
|
||||
_tooltip.Visible = false;
|
||||
CurrentlyHovered?.PerformHideTooltip();
|
||||
_resetTooltipTimer();
|
||||
showingTooltip = false;
|
||||
}
|
||||
|
||||
|
||||
public void HideTooltipFor(Control control)
|
||||
{
|
||||
if (CurrentlyHovered == control)
|
||||
{
|
||||
_clearTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
private void _resetTooltipTimer()
|
||||
@@ -703,27 +716,23 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
private void _showTooltip()
|
||||
{
|
||||
if (showingTooltip) return;
|
||||
showingTooltip = true;
|
||||
var hovered = CurrentlyHovered;
|
||||
if (hovered == null || string.IsNullOrWhiteSpace(hovered.ToolTip))
|
||||
if (hovered == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tooltip.Visible = true;
|
||||
_tooltip.Text = hovered.ToolTip;
|
||||
LayoutContainer.SetPosition(_tooltip, MousePositionScaled);
|
||||
|
||||
var (right, bottom) = _tooltip.Position + _tooltip.Size;
|
||||
|
||||
if (right > RootControl.Size.X)
|
||||
// show simple tooltip if there is one
|
||||
if (!String.IsNullOrWhiteSpace(hovered.ToolTip))
|
||||
{
|
||||
LayoutContainer.SetPosition(_tooltip, (RootControl.Size.X - _tooltip.Size.X, _tooltip.Position.Y));
|
||||
_tooltip.Visible = true;
|
||||
_tooltip.Text = hovered.ToolTip;
|
||||
Tooltips.PositionTooltip(_tooltip);
|
||||
}
|
||||
|
||||
if (bottom > RootControl.Size.Y)
|
||||
{
|
||||
LayoutContainer.SetPosition(_tooltip, (_tooltip.Position.X, RootControl.Size.Y - _tooltip.Size.Y));
|
||||
}
|
||||
hovered.PerformShowTooltip();
|
||||
}
|
||||
|
||||
private void _uiScaleChanged(float newValue)
|
||||
|
||||
@@ -16,10 +16,11 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[Test]
|
||||
public void TestBasic()
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBasic(bool limitByCount)
|
||||
{
|
||||
var grid = new GridContainer {Columns = 2};
|
||||
var grid = limitByCount ? new GridContainer {Columns = 2} : new GridContainer { MaxWidth = 125};
|
||||
var child1 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child2 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child3 = new Control {CustomMinimumSize = (50, 50)};
|
||||
@@ -43,10 +44,160 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(0, 108)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExpand()
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBasicRows(bool limitByCount)
|
||||
{
|
||||
var grid = new GridContainer {Columns = 2, Size = (200, 200)};
|
||||
var grid = limitByCount ? new GridContainer {Rows = 2}
|
||||
: new GridContainer {MaxHeight = 125};
|
||||
var child1 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child2 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child3 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child4 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child5 = new Control {CustomMinimumSize = (50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.ForceRunLayoutUpdate();
|
||||
|
||||
Assert.That(grid.CombinedMinimumSize, Is.EqualTo(new Vector2(158, 104)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(108, 0)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnevenLimitSize()
|
||||
{
|
||||
// when uneven sizes are used and limiting by size, they should all be treated as equal size cells based on the
|
||||
// max minwidth / minheight among them.
|
||||
// Note that when limiting by count, the behavior is different - rows and columns are individually
|
||||
// expanded based on the max size of their elements
|
||||
var grid = new GridContainer { MaxWidth = 125};
|
||||
var child1 = new Control {CustomMinimumSize = (12, 24)};
|
||||
var child2 = new Control {CustomMinimumSize = (30, 50)};
|
||||
var child3 = new Control {CustomMinimumSize = (40, 20)};
|
||||
var child4 = new Control {CustomMinimumSize = (20, 12)};
|
||||
var child5 = new Control {CustomMinimumSize = (50, 10)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
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));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(0, 108)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnevenLimitSizeRows()
|
||||
{
|
||||
var grid = new GridContainer {MaxHeight = 125};
|
||||
var child1 = new Control {CustomMinimumSize = (12, 2)};
|
||||
var child2 = new Control {CustomMinimumSize = (5, 23)};
|
||||
var child3 = new Control {CustomMinimumSize = (42, 4)};
|
||||
var child4 = new Control {CustomMinimumSize = (2, 50)};
|
||||
var child5 = new Control {CustomMinimumSize = (50, 34)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.ForceRunLayoutUpdate();
|
||||
|
||||
Assert.That(grid.CombinedMinimumSize, Is.EqualTo(new Vector2(158, 104)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(108, 0)));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBasicBackwards(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount ? new GridContainer {Columns = 2, ExpandBackwards = true}
|
||||
: new GridContainer { MaxWidth = 125, ExpandBackwards = true};
|
||||
var child1 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child2 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child3 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child4 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child5 = new Control {CustomMinimumSize = (50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.ForceRunLayoutUpdate();
|
||||
|
||||
Assert.That(grid.CombinedMinimumSize, Is.EqualTo(new Vector2(104, 158)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(new Vector2(0, 108)));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(54, 108)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(Vector2.Zero));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBasicRowsBackwards(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount ? new GridContainer {Rows = 2, ExpandBackwards = true}
|
||||
: new GridContainer {MaxHeight = 125, ExpandBackwards = true};
|
||||
var child1 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child2 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child3 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child4 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child5 = new Control {CustomMinimumSize = (50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.ForceRunLayoutUpdate();
|
||||
|
||||
Assert.That(grid.CombinedMinimumSize, Is.EqualTo(new Vector2(158, 104)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(new Vector2(108, 0)));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(108, 54)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(Vector2.Zero));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestExpand(bool limitByCount)
|
||||
{
|
||||
// in the presence of a MaxWidth with expanding elements, the
|
||||
// pre-expanded size should be used to determine the size of each "cell", and then expansion
|
||||
// happens within the defined control size
|
||||
var grid = limitByCount ? new GridContainer {Columns = 2, Size = (200, 200)}
|
||||
: new GridContainer {MaxWidth = 125, Size = (200, 200)} ;
|
||||
var child1 = new Control {CustomMinimumSize = (50, 50), SizeFlagsHorizontal = Control.SizeFlags.FillExpand};
|
||||
var child2 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child3 = new Control {CustomMinimumSize = (50, 50)};
|
||||
@@ -73,10 +224,44 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
Assert.That(child5.Size, Is.EqualTo(new Vector2(146, 50)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRowCount()
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestExpandRows(bool limitByCount)
|
||||
{
|
||||
var grid = new GridContainer {Columns = 2};
|
||||
var grid = limitByCount ? new GridContainer {Rows = 2, Size = (200, 200)}
|
||||
: new GridContainer {MaxHeight = 125, Size = (200, 200)};
|
||||
var child1 = new Control {CustomMinimumSize = (50, 50), SizeFlagsVertical = Control.SizeFlags.FillExpand};
|
||||
var child2 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child3 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child4 = new Control {CustomMinimumSize = (50, 50), SizeFlagsHorizontal = Control.SizeFlags.FillExpand};
|
||||
var child5 = new Control {CustomMinimumSize = (50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.ForceRunLayoutUpdate();
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child1.Size, Is.EqualTo(new Vector2(50, 146)));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(0, 150)));
|
||||
Assert.That(child2.Size, Is.EqualTo(new Vector2(50, 50)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child3.Size, Is.EqualTo(new Vector2(92, 146)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 150)));
|
||||
Assert.That(child4.Size, Is.EqualTo(new Vector2(92, 50)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(150, 0)));
|
||||
Assert.That(child5.Size, Is.EqualTo(new Vector2(50, 146)));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestRowCount(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount ? new GridContainer {Columns = 2}
|
||||
: new GridContainer {MaxWidth = 125};
|
||||
var child1 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child2 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child3 = new Control {CustomMinimumSize = (50, 50)};
|
||||
@@ -99,5 +284,34 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
|
||||
Assert.That(grid.Rows, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestColumnCountRows(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount ? new GridContainer {Rows = 2}
|
||||
: new GridContainer{MaxHeight = 125};
|
||||
var child1 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child2 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child3 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child4 = new Control {CustomMinimumSize = (50, 50)};
|
||||
var child5 = new Control {CustomMinimumSize = (50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
Assert.That(grid.Columns, Is.EqualTo(3));
|
||||
|
||||
grid.RemoveChild(child5);
|
||||
|
||||
Assert.That(grid.Columns, Is.EqualTo(2));
|
||||
|
||||
grid.DisposeAllChildren();
|
||||
|
||||
Assert.That(grid.Columns, Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user