UI/Window/Window.cs
using Sandbox.UI;
namespace HC3.UI;
public abstract class Window : Panel
{
/// <summary>
/// Window title, shown in titlebar
/// </summary>
public virtual string Title { get; set; } = "New Window";
/// <summary>
/// Unique key for this window. If a new window is opened with the same key, we'll focus this one instead.
/// </summary>
public virtual object Key { get; }
/// <summary>
/// Window icon, shown in titlebar
/// </summary>
public virtual string Icon { get; } = null;
/// <summary>
/// Can this window be shrunk?
/// </summary>
public virtual bool CanShrink { get; } = true;
/// <summary>
/// Normalised position of this window
/// </summary>
public Vector2 Position;
/// <summary>
/// Position of this window within Screen bounds
/// </summary>
public Vector2 ScreenPosition
{
get => (Position * Screen.Size);//.Clamp( Vector2.Zero, Screen.Size );
set
{
var p = value / Screen.Size;
if ( p.AlmostEqual( Position ) ) return;
Position = p;
}
}
public enum ScreenAlignment
{
TopLeft,
TopCenter,
TopRight,
CenterLeft,
Center,
CenterRight,
BottomLeft,
BottomCenter,
BottomRight
}
public ScreenAlignment Alignment { get; private set; } = ScreenAlignment.TopLeft;
bool _alignmentDirty = false;
private List<Window> _subwindows = new List<Window>();
public Window()
{
Key = this;
}
/// <summary>
/// Whether this window should persist when another of the same type opens
/// </summary>
public bool Pinned { get; set; } = false;
/// <summary>
/// Whether this window is pinnable at all
/// </summary>
public virtual bool IsPinnable => false;
public void SetTitle( string title )
{
Title = title;
}
public void ConstrainToScreen()
{
ScreenPosition = ScreenPosition.Clamp( Vector2.Zero, Screen.Size - Box.Rect.Size );
}
public void Realign()
{
var boxSize = Box.Rect.Size;
var offset = Vector2.Zero;
switch ( Alignment )
{
case ScreenAlignment.TopLeft:
offset = Vector2.Zero;
break;
case ScreenAlignment.TopCenter:
offset = new Vector2( -boxSize.x / 2, 0 );
break;
case ScreenAlignment.TopRight:
offset = new Vector2( -boxSize.x, 0 );
break;
case ScreenAlignment.CenterLeft:
offset = new Vector2( 0, -boxSize.y / 2 );
break;
case ScreenAlignment.Center:
offset = -boxSize / 2;
break;
case ScreenAlignment.CenterRight:
offset = new Vector2( -boxSize.x, -boxSize.y / 2 );
break;
case ScreenAlignment.BottomLeft:
offset = new Vector2( 0, -boxSize.y );
break;
case ScreenAlignment.BottomCenter:
offset = new Vector2( -boxSize.x / 2, -boxSize.y );
break;
case ScreenAlignment.BottomRight:
offset = -boxSize;
break;
}
ScreenPosition = ScreenPosition + offset;
ConstrainToScreen();
}
public void SetPosition( Vector2 screenPosition, ScreenAlignment alignment )
{
ScreenPosition = screenPosition;
Alignment = alignment;
_alignmentDirty = true;
}
public void SetPosition( ScreenAlignment alignment )
{
Alignment = alignment;
_alignmentDirty = true;
ScreenPosition = Alignment switch
{
ScreenAlignment.BottomCenter => new Vector2( Screen.Size.x / 2, Screen.Size.y - 425f ),
_ => Screen.Size / 2,
};
}
public override void OnLayout( ref Rect layoutRect )
{
base.OnLayout( ref layoutRect );
if ( _alignmentDirty )
{
// bs: can't do this on creation as we've not sized it
Realign();
_alignmentDirty = false;
}
}
/// <summary>
/// Opens the window as a subwindow of this one, so it'll get closed when we do.
/// </summary>
public void OpenSubwindow( Window window )
{
_subwindows.Add( window );
WindowManager.Instance.Open( window );
}
public override void OnDeleted()
{
base.OnDeleted();
foreach ( Window window in _subwindows )
{
WindowManager.Instance.Close( window );
}
}
/// <summary>
/// Close this window
/// </summary>
public void Close()
{
WindowManager.Instance.Close( this );
}
/// <summary>
/// Called when this window is closed
/// </summary>
public virtual void OnClose()
{
OnDeactivated();
}
/// <summary>
/// Called when this window is activated
/// </summary>
public virtual void OnActivated()
{
if ( Key is IInspectable inspectable )
{
SelectionSystem.Instance.OnSelected( inspectable );
}
}
/// <summary>
/// Called when this window is deactivated
/// </summary>
public virtual void OnDeactivated()
{
if ( Key is IInspectable inspectable )
{
SelectionSystem.Instance.OnSelected( null );
}
}
}