mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-02 18:17:09 +02:00
159 lines
5.7 KiB
C#
159 lines
5.7 KiB
C#
using System.Numerics;
|
|
using Robust.Shared.Maths;
|
|
|
|
namespace Robust.Client.UserInterface.Controls
|
|
{
|
|
/// <summary>
|
|
/// Container that tries to put controls at their specified origin,
|
|
/// moving them around if necessary to avoid them going outside of the bounds of the container.
|
|
/// </summary>
|
|
public sealed class PopupContainer : Control
|
|
{
|
|
/// <summary>
|
|
/// The origin that the container tries to place the child at.
|
|
/// </summary>
|
|
public static readonly AttachedProperty PopupOriginProperty = AttachedProperty.Create("PopupOrigin",
|
|
typeof(PopupContainer), typeof(Vector2), changed: PopupOriginChangedCallback);
|
|
|
|
/// <summary>
|
|
/// Alternative position to right-align the popup if <see cref="PopupOriginProperty"/>
|
|
/// would put it off-screen horizontally.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// You know how right click menus with sub menus put the submenu on the left
|
|
/// if it's too close to the right of the screen? Yeah that.
|
|
/// </remarks>
|
|
public static readonly AttachedProperty AltOriginProperty = AttachedProperty.Create("AltOrigin",
|
|
typeof(PopupContainer), typeof(Vector2?), changed: PopupOriginChangedCallback);
|
|
|
|
/// <summary>
|
|
/// Alternative position to bottom-left-align the popup if <see cref="PopupOriginProperty"/>
|
|
/// would put it off-screen vertically.
|
|
/// </summary>
|
|
public static readonly AttachedProperty AltOriginUpProperty = AttachedProperty.Create("AltOriginUp",
|
|
typeof(PopupContainer), typeof(Vector2?), changed: PopupOriginChangedCallback);
|
|
|
|
public PopupContainer()
|
|
{
|
|
RectClipContent = true;
|
|
}
|
|
|
|
public static void SetPopupOrigin(Control control, Vector2 origin)
|
|
{
|
|
control.SetValue(PopupOriginProperty, origin);
|
|
}
|
|
|
|
public static Vector2 GetPopupOrigin(Control control)
|
|
{
|
|
return control.GetValue<Vector2>(PopupOriginProperty);
|
|
}
|
|
|
|
public static Vector2? GetAltOrigin(Control control)
|
|
{
|
|
return control.GetValue<Vector2?>(AltOriginProperty);
|
|
}
|
|
|
|
public static Vector2? GetAltOriginUp(Control control)
|
|
{
|
|
return control.GetValue<Vector2?>(AltOriginUpProperty);
|
|
}
|
|
|
|
public static void SetAltOrigin(Control control, Vector2? origin)
|
|
{
|
|
control.SetValue(AltOriginProperty, origin);
|
|
}
|
|
|
|
public static void SetAltOriginUp(Control control, Vector2? origin)
|
|
{
|
|
control.SetValue(AltOriginUpProperty, origin);
|
|
}
|
|
|
|
private static void PopupOriginChangedCallback(Control owner, AttachedPropertyChangedEventArgs eventArgs)
|
|
{
|
|
if (owner.Parent is PopupContainer container)
|
|
{
|
|
container.InvalidateArrange();
|
|
}
|
|
}
|
|
|
|
protected override Vector2 ArrangeOverride(Vector2 finalSize)
|
|
{
|
|
foreach (var child in Children)
|
|
{
|
|
var size = child.DesiredSize;
|
|
var offset = child.GetValue<Vector2>(PopupOriginProperty);
|
|
var altPos = child.GetValue<Vector2?>(AltOriginProperty);
|
|
var altPosUp = child.GetValue<Vector2?>(AltOriginUpProperty);
|
|
|
|
var box = UIBox2.FromDimensions(offset, size);
|
|
|
|
var isAltPos = false;
|
|
var isAltPosUp = false;
|
|
|
|
// Clamp the right edge.
|
|
if (box.Right > Width)
|
|
{
|
|
// Try to position at alt pos.
|
|
if (altPos != null && altPos.Value.X - size.X > 0)
|
|
{
|
|
// There is horizontal room at the alt pos so there we go.
|
|
isAltPos = true;
|
|
box = UIBox2.FromDimensions(new Vector2(altPos.Value.X - size.X, altPos.Value.Y), size);
|
|
}
|
|
else
|
|
{
|
|
box = box.Translated(new Vector2(-(box.Right - Width), 0));
|
|
}
|
|
}
|
|
|
|
// Clamp the bottom edge.
|
|
if (box.Bottom > Height)
|
|
{
|
|
// Try to position at alt pos.
|
|
if (altPosUp != null && altPosUp.Value.Y - size.Y > 0)
|
|
{
|
|
// There is vertical room at the alt pos so there we go.
|
|
isAltPosUp = true;
|
|
box = UIBox2.FromDimensions(new Vector2(altPosUp.Value.X, altPosUp.Value.Y - size.Y), size);
|
|
}
|
|
else
|
|
{
|
|
box = box.Translated(new Vector2(0, -(box.Bottom - Height)));
|
|
}
|
|
}
|
|
|
|
// Try to clamp the left edge.
|
|
if (box.Left < 0 && !isAltPos)
|
|
{
|
|
box = box.Translated(new Vector2(-offset.X, 0));
|
|
}
|
|
|
|
// Try to clamp the top edge.
|
|
if (box.Top < 0 && !isAltPosUp)
|
|
{
|
|
box = box.Translated(new Vector2(0, -offset.Y));
|
|
}
|
|
|
|
child.Arrange(box);
|
|
}
|
|
|
|
return finalSize;
|
|
}
|
|
|
|
protected override Vector2 MeasureOverride(Vector2 availableSize)
|
|
{
|
|
// Measure to availableSize so that child controls never get too large to fit the whole screen.
|
|
base.MeasureOverride(availableSize);
|
|
|
|
return availableSize;
|
|
}
|
|
|
|
protected override void Resized()
|
|
{
|
|
base.Resized();
|
|
|
|
InvalidateArrange();
|
|
}
|
|
}
|
|
}
|