mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-03 02:27:08 +02:00
493 lines
16 KiB
C#
493 lines
16 KiB
C#
using System;
|
|
using JetBrains.Annotations;
|
|
using Robust.Client.Utility;
|
|
using Robust.Shared.Maths;
|
|
|
|
namespace Robust.Client.Graphics.Drawing
|
|
{
|
|
/// <summary>
|
|
/// Equivalent to Godot's <c>StyleBox</c> class,
|
|
/// this is for drawing pretty fancy boxes using minimal code.
|
|
/// </summary>
|
|
[PublicAPI]
|
|
public abstract class StyleBox
|
|
{
|
|
public Vector2 MinimumSize =>
|
|
new Vector2(GetContentMargin(Margin.Left) + GetContentMargin(Margin.Right),
|
|
GetContentMargin(Margin.Top) + GetContentMargin(Margin.Bottom));
|
|
|
|
private float? _contentMarginTop;
|
|
private float? _contentMarginLeft;
|
|
private float? _contentMarginBottom;
|
|
private float? _contentMarginRight;
|
|
|
|
public float? ContentMarginLeftOverride
|
|
{
|
|
get => _contentMarginLeft;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), value, "Value cannot be less than zero.");
|
|
}
|
|
|
|
_contentMarginLeft = value;
|
|
}
|
|
}
|
|
|
|
public float? ContentMarginTopOverride
|
|
{
|
|
get => _contentMarginTop;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), value, "Value cannot be less than zero.");
|
|
}
|
|
|
|
_contentMarginTop = value;
|
|
}
|
|
}
|
|
|
|
public float? ContentMarginRightOverride
|
|
{
|
|
get => _contentMarginRight;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), value, "Value cannot be less than zero.");
|
|
}
|
|
|
|
_contentMarginRight = value;
|
|
}
|
|
}
|
|
|
|
public float? ContentMarginBottomOverride
|
|
{
|
|
get => _contentMarginBottom;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), value, "Value cannot be less than zero.");
|
|
}
|
|
|
|
_contentMarginBottom = value;
|
|
}
|
|
}
|
|
|
|
public void Draw(DrawingHandleScreen handle, UIBox2 box)
|
|
{
|
|
DoDraw(handle, box);
|
|
}
|
|
|
|
public float GetContentMargin(Margin margin)
|
|
{
|
|
float? marginData;
|
|
switch (margin)
|
|
{
|
|
case Margin.Top:
|
|
marginData = ContentMarginTopOverride;
|
|
break;
|
|
case Margin.Bottom:
|
|
marginData = ContentMarginBottomOverride;
|
|
break;
|
|
case Margin.Right:
|
|
marginData = ContentMarginRightOverride;
|
|
break;
|
|
case Margin.Left:
|
|
marginData = ContentMarginLeftOverride;
|
|
break;
|
|
default:
|
|
throw new ArgumentException("Margin must be a single margin flag.", nameof(margin));
|
|
}
|
|
|
|
return marginData ?? GetDefaultContentMargin(margin);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the offsets of the content region of this box,
|
|
/// if this box is drawn from the given position.
|
|
/// </summary>
|
|
public Vector2 GetContentOffset(Vector2 basePosition)
|
|
{
|
|
return basePosition + (GetContentMargin(Margin.Left), GetContentMargin(Margin.Top));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the box considered the "contents" of this style box, when drawn at a specific size.
|
|
/// </summary>
|
|
/// <exception cref="ArgumentException">
|
|
/// <paramref name="baseBox"/> is too small and the resultant box would have negative dimensions.
|
|
/// </exception>
|
|
public UIBox2 GetContentBox(UIBox2 baseBox)
|
|
{
|
|
var left = baseBox.Left + GetContentMargin(Margin.Left);
|
|
var top = baseBox.Top + GetContentMargin(Margin.Top);
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the draw box, positioned at <paramref name="position"/>,
|
|
/// that envelops a box with the given dimensions perfectly given this box's content margins.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// It's basically a reverse <see cref="GetContentBox"/>.
|
|
/// </remarks>
|
|
/// <param name="position">The position at which the new box should be drawn.</param>
|
|
/// <param name="dimensions">The dimensions of the content box inside this new box.</param>
|
|
/// <returns>
|
|
/// A box that, when ran through <see cref="GetContentBox"/>,
|
|
/// has a content box of size <paramref name="dimensions"/>
|
|
/// </returns>
|
|
public UIBox2 GetEnvelopBox(Vector2 position, Vector2 dimensions)
|
|
{
|
|
return UIBox2.FromDimensions(position, dimensions + MinimumSize);
|
|
}
|
|
|
|
public void SetContentMarginOverride(Margin margin, float value)
|
|
{
|
|
if ((margin & Margin.Left) != 0)
|
|
{
|
|
ContentMarginLeftOverride = value;
|
|
}
|
|
|
|
if ((margin & Margin.Top) != 0)
|
|
{
|
|
ContentMarginTopOverride = value;
|
|
}
|
|
|
|
if ((margin & Margin.Right) != 0)
|
|
{
|
|
ContentMarginRightOverride = value;
|
|
}
|
|
|
|
if ((margin & Margin.Bottom) != 0)
|
|
{
|
|
ContentMarginBottomOverride = value;
|
|
}
|
|
}
|
|
|
|
protected abstract void DoDraw(DrawingHandleScreen handle, UIBox2 box);
|
|
|
|
protected virtual float GetDefaultContentMargin(Margin margin)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
[Flags]
|
|
public enum Margin
|
|
{
|
|
None = 0,
|
|
Top = 1,
|
|
Bottom = 2,
|
|
Right = 4,
|
|
Left = 8,
|
|
All = Top | Bottom | Right | Left,
|
|
Vertical = Top | Bottom,
|
|
Horizontal = Left | Right,
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Style box based on a 9-patch texture.
|
|
/// </summary>
|
|
public class StyleBoxTexture : StyleBox
|
|
{
|
|
public StyleBoxTexture()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clones a stylebox so it can be separately modified.
|
|
/// </summary>
|
|
public StyleBoxTexture(StyleBoxTexture copy)
|
|
{
|
|
PatchMarginTop = copy.PatchMarginTop;
|
|
PatchMarginLeft = copy.PatchMarginLeft;
|
|
PatchMarginBottom = copy.PatchMarginBottom;
|
|
PatchMarginRight = copy.PatchMarginRight;
|
|
Texture = copy.Texture;
|
|
Modulate = copy.Modulate;
|
|
}
|
|
|
|
public float ExpandMarginLeft { get; set; }
|
|
|
|
public float ExpandMarginTop { get; set; }
|
|
|
|
public float ExpandMarginBottom { get; set; }
|
|
|
|
public float ExpandMarginRight { get; set; }
|
|
|
|
private float _patchMarginLeft;
|
|
|
|
public float PatchMarginLeft
|
|
{
|
|
get => _patchMarginLeft;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), value, "Value cannot be less than zero.");
|
|
}
|
|
|
|
_patchMarginLeft = value;
|
|
}
|
|
}
|
|
|
|
private float _patchMarginRight;
|
|
|
|
public float PatchMarginRight
|
|
{
|
|
get => _patchMarginRight;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), value, "Value cannot be less than zero.");
|
|
}
|
|
|
|
_patchMarginRight = value;
|
|
}
|
|
}
|
|
|
|
private float _patchMarginTop;
|
|
|
|
public float PatchMarginTop
|
|
{
|
|
get => _patchMarginTop;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), value, "Value cannot be less than zero.");
|
|
}
|
|
|
|
_patchMarginTop = value;
|
|
}
|
|
}
|
|
|
|
private float _patchMarginBottom;
|
|
|
|
public float PatchMarginBottom
|
|
{
|
|
get => _patchMarginBottom;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), value, "Value cannot be less than zero.");
|
|
}
|
|
|
|
_patchMarginBottom = value;
|
|
}
|
|
}
|
|
|
|
public Color Modulate { get; set; } = Color.White;
|
|
|
|
public Texture Texture { get; set; }
|
|
|
|
[Obsolete("Use SetPatchMargin")]
|
|
public void SetMargin(Margin margin, float value)
|
|
{
|
|
SetPatchMargin(margin, value);
|
|
}
|
|
|
|
public void SetPatchMargin(Margin margin, float value)
|
|
{
|
|
if ((margin & Margin.Top) != 0)
|
|
{
|
|
PatchMarginTop = value;
|
|
}
|
|
|
|
if ((margin & Margin.Bottom) != 0)
|
|
{
|
|
PatchMarginBottom = value;
|
|
}
|
|
|
|
if ((margin & Margin.Right) != 0)
|
|
{
|
|
PatchMarginRight = value;
|
|
}
|
|
|
|
if ((margin & Margin.Left) != 0)
|
|
{
|
|
PatchMarginLeft = value;
|
|
}
|
|
}
|
|
|
|
public void SetExpandMargin(Margin margin, float value)
|
|
{
|
|
if ((margin & Margin.Top) != 0)
|
|
{
|
|
ExpandMarginTop = value;
|
|
}
|
|
|
|
if ((margin & Margin.Bottom) != 0)
|
|
{
|
|
ExpandMarginBottom = value;
|
|
}
|
|
|
|
if ((margin & Margin.Right) != 0)
|
|
{
|
|
ExpandMarginRight = value;
|
|
}
|
|
|
|
if ((margin & Margin.Left) != 0)
|
|
{
|
|
ExpandMarginLeft = value;
|
|
}
|
|
}
|
|
|
|
protected override void DoDraw(DrawingHandleScreen handle, UIBox2 box)
|
|
{
|
|
box = new UIBox2(
|
|
box.Left - ExpandMarginLeft,
|
|
box.Top - ExpandMarginTop,
|
|
box.Right + ExpandMarginRight,
|
|
box.Bottom + ExpandMarginBottom);
|
|
|
|
if (PatchMarginLeft > 0)
|
|
{
|
|
if (PatchMarginTop > 0)
|
|
{
|
|
// Draw top left
|
|
var topLeftBox = new UIBox2(0, 0, PatchMarginLeft, PatchMarginTop)
|
|
.Translated(box.TopLeft);
|
|
handle.DrawTextureRectRegion(Texture, topLeftBox,
|
|
new UIBox2(0, 0, PatchMarginLeft, PatchMarginTop), Modulate);
|
|
}
|
|
|
|
{
|
|
// Draw left
|
|
var leftBox =
|
|
new UIBox2(0, PatchMarginTop, PatchMarginLeft, box.Height - PatchMarginBottom)
|
|
.Translated(box.TopLeft);
|
|
handle.DrawTextureRectRegion(Texture, leftBox,
|
|
new UIBox2(0, PatchMarginTop, PatchMarginLeft, Texture.Height - PatchMarginBottom), Modulate);
|
|
}
|
|
|
|
if (PatchMarginBottom > 0)
|
|
{
|
|
// Draw bottom left
|
|
var bottomLeftBox =
|
|
new UIBox2(0, box.Height - PatchMarginBottom, PatchMarginLeft, box.Height)
|
|
.Translated(box.TopLeft);
|
|
handle.DrawTextureRectRegion(Texture, bottomLeftBox,
|
|
new UIBox2(0, Texture.Height - PatchMarginBottom, PatchMarginLeft, Texture.Height), Modulate);
|
|
}
|
|
}
|
|
|
|
if (PatchMarginRight > 0)
|
|
{
|
|
if (PatchMarginTop > 0)
|
|
{
|
|
// Draw top right
|
|
var topRightBox = new UIBox2(box.Width - PatchMarginRight, 0, box.Width, PatchMarginTop)
|
|
.Translated(box.TopLeft);
|
|
handle.DrawTextureRectRegion(Texture, topRightBox,
|
|
new UIBox2(Texture.Width - PatchMarginRight, 0, Texture.Width, PatchMarginTop), Modulate);
|
|
}
|
|
|
|
{
|
|
// Draw right
|
|
var rightBox =
|
|
new UIBox2(box.Width - PatchMarginRight, PatchMarginTop, box.Width,
|
|
box.Height - PatchMarginBottom)
|
|
.Translated(box.TopLeft);
|
|
handle.DrawTextureRectRegion(Texture, rightBox,
|
|
new UIBox2(Texture.Width - PatchMarginRight, PatchMarginTop, Texture.Width,
|
|
Texture.Height - PatchMarginBottom), Modulate);
|
|
}
|
|
|
|
if (PatchMarginBottom > 0)
|
|
{
|
|
// Draw bottom right
|
|
var bottomRightBox =
|
|
new UIBox2(box.Width - PatchMarginRight, box.Height - PatchMarginBottom, box.Width, box.Height)
|
|
.Translated(box.TopLeft);
|
|
handle.DrawTextureRectRegion(Texture, bottomRightBox,
|
|
new UIBox2(Texture.Width - PatchMarginRight, Texture.Height - PatchMarginBottom, Texture.Width,
|
|
Texture.Height), Modulate);
|
|
}
|
|
}
|
|
|
|
if (PatchMarginTop > 0)
|
|
{
|
|
// Draw top
|
|
var topBox =
|
|
new UIBox2(PatchMarginLeft, 0, box.Width - PatchMarginRight, PatchMarginTop)
|
|
.Translated(box.TopLeft);
|
|
handle.DrawTextureRectRegion(Texture, topBox,
|
|
new UIBox2(PatchMarginLeft, 0, Texture.Width - PatchMarginRight, PatchMarginTop), Modulate);
|
|
}
|
|
|
|
if (PatchMarginBottom > 0)
|
|
{
|
|
// Draw bottom
|
|
var bottomBox =
|
|
new UIBox2(PatchMarginLeft, box.Height - PatchMarginBottom, box.Width - PatchMarginRight,
|
|
box.Height)
|
|
.Translated(box.TopLeft);
|
|
handle.DrawTextureRectRegion(Texture, bottomBox,
|
|
new UIBox2(PatchMarginLeft, Texture.Height - PatchMarginBottom, Texture.Width - PatchMarginRight,
|
|
Texture.Height), Modulate);
|
|
}
|
|
|
|
// Draw center
|
|
{
|
|
var centerBox = new UIBox2(PatchMarginLeft, PatchMarginTop, box.Width - PatchMarginRight,
|
|
box.Height - PatchMarginBottom).Translated(box.TopLeft);
|
|
|
|
handle.DrawTextureRectRegion(Texture, centerBox,
|
|
new UIBox2(PatchMarginLeft, PatchMarginTop, Texture.Width - PatchMarginRight,
|
|
Texture.Height - PatchMarginBottom), Modulate);
|
|
}
|
|
}
|
|
|
|
protected override float GetDefaultContentMargin(Margin margin)
|
|
{
|
|
switch (margin)
|
|
{
|
|
case Margin.Top:
|
|
return PatchMarginTop;
|
|
case Margin.Bottom:
|
|
return PatchMarginBottom;
|
|
case Margin.Right:
|
|
return PatchMarginRight;
|
|
case Margin.Left:
|
|
return PatchMarginLeft;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(margin), margin, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class StyleBoxFlat : StyleBox
|
|
{
|
|
public Color BackgroundColor { get; set; }
|
|
|
|
protected override void DoDraw(DrawingHandleScreen handle, UIBox2 box)
|
|
{
|
|
handle.DrawRect(box, BackgroundColor);
|
|
}
|
|
}
|
|
|
|
public class StyleBoxEmpty : StyleBox
|
|
{
|
|
protected override void DoDraw(DrawingHandleScreen handle, UIBox2 box)
|
|
{
|
|
// It's empty what more do you want?
|
|
}
|
|
}
|
|
}
|