using Sandbox.UI.Construct;
namespace Sandbox.UI;
public partial class Popup : BasePopup
{
///
/// Which panel triggered this popup. Set by or the constructor.
///
public Panel PopupSource { get; set; }
///
/// Currently selected option in the popup. Used internally for keyboard navigation.
///
public Panel SelectedChild { get; set; }
///
/// Positioning mode for this popup.
///
public PositionMode Position { get; set; }
///
/// Offset away from based on .
///
public float PopupSourceOffset { get; set; }
///
/// If true, will close this popup when the is hidden.
///
public bool CloseWhenParentIsHidden { get; set; } = false;
///
/// Dictates where a is positioned.
///
public enum PositionMode
{
///
/// To the left of the source panel, centered.
///
Left,
///
/// To the left of the source panel, aligned to the bottom.
///
LeftBottom,
///
/// Above the source panel, aligned to the left.
///
AboveLeft,
///
/// Below the source panel, aliging on the left. Do not stretch to size of .
///
BelowLeft,
///
/// Below the source panel, centered horizontally.
///
BelowCenter,
///
/// Below the source panel, stretch to the width of the .
///
BelowStretch,
///
/// Above, centered
///
AboveCenter,
///
/// Position where the mouse cursor is currently
///
UnderMouse
}
public Popup()
{
}
///
public Popup( Panel sourcePanel, PositionMode position, float offset )
{
SetPositioning( sourcePanel, position, offset );
}
///
/// Sets , and .
/// Applies relevant CSS classes.
///
/// Which panel triggered this popup.
/// Desired positioning mode.
/// Offset away from the .
public void SetPositioning( Panel sourcePanel, PositionMode position, float offset )
{
Parent = sourcePanel.FindPopupPanel();
PopupSource = sourcePanel;
Position = position;
PopupSourceOffset = offset;
AddClass( "popup-panel" );
PositionMe( true );
switch ( Position )
{
case PositionMode.Left:
AddClass( "left" );
break;
case PositionMode.LeftBottom:
AddClass( "left-bottom" );
break;
case PositionMode.AboveLeft:
AddClass( "above-left" );
break;
case PositionMode.AboveCenter:
AddClass( "above-center" );
break;
case PositionMode.BelowLeft:
AddClass( "below-left" );
break;
case PositionMode.BelowCenter:
AddClass( "below-center" );
break;
case PositionMode.BelowStretch:
AddClass( "below-stretch" );
break;
}
}
///
/// Header panel that holds and .
///
protected Panel Header;
///
/// Label that dispalys .
///
protected Label TitleLabel;
///
/// Panel that dispalys .
///
protected IconPanel IconPanel;
void CreateHeader()
{
if ( Header.IsValid() ) return;
Header = Add.Panel( "header" );
IconPanel = Header.Add.Icon( null );
TitleLabel = Header.Add.Label( null, "title" );
}
///
/// If set, will add an unselectable header with given text and .
///
public string Title
{
get => TitleLabel?.Text;
set
{
CreateHeader();
TitleLabel.Text = value;
}
}
///
/// If set, will add an unselectable header with given icon and .
///
public string Icon
{
get => IconPanel?.Text;
set
{
CreateHeader();
IconPanel.Text = value;
}
}
///
/// Closes all panels, marks this one as a success and closes it.
///
public void Success()
{
AddClass( "success" );
Popup.CloseAll();
}
///
/// Closes all panels, marks this one as a failure and closes it.
///
public void Failure()
{
AddClass( "failure" );
Popup.CloseAll();
}
///
/// Add an option to this popup with given text and click action.
///
public Panel AddOption( string text, Action action = null )
{
return AddChild( new Button( text, () =>
{
CloseAll();
action?.Invoke();
} ) );
}
///
/// Add an option to this popup with given text, icon and click action.
///
public Panel AddOption( string text, string icon, Action action = null )
{
return AddChild( new Button( text, icon, () => { CloseAll(); action?.Invoke(); } ) );
}
///
/// Move selection in given direction.
///
/// Positive numbers move selection downwards, negative - upwards.
public void MoveSelection( int dir )
{
var currentIndex = GetChildIndex( SelectedChild );
if ( currentIndex >= 0 ) currentIndex += dir;
else if ( currentIndex < 0 ) currentIndex = dir == 1 ? 0 : -1;
SelectedChild?.SetClass( "active", false );
SelectedChild = GetChild( currentIndex, true );
SelectedChild?.SetClass( "active", true );
}
public override void Tick()
{
base.Tick();
if ( CloseWhenParentIsHidden && !PopupSource.IsValid() )
{
Delete();
return;
}
PositionMe( false );
}
public override void OnLayout( ref Rect layoutRect )
{
var padding = 10;
var h = Screen.Height - padding;
var w = Screen.Width - padding;
if ( layoutRect.Bottom > h )
{
layoutRect.Top -= layoutRect.Bottom - h;
layoutRect.Bottom -= layoutRect.Bottom - h;
}
if ( layoutRect.Right > w )
{
layoutRect.Left -= layoutRect.Right - w;
layoutRect.Right -= layoutRect.Right - w;
}
}
void PositionMe( bool isInitial )
{
var rect = PopupSource.Box.Rect * PopupSource.ScaleFromScreen;
var w = Screen.Width * PopupSource.ScaleFromScreen;
var h = Screen.Height * PopupSource.ScaleFromScreen;
Style.MaxHeight = Screen.Height - 50;
switch ( Position )
{
case PositionMode.Left:
{
Style.Left = null;
Style.Right = ((w - rect.Left) + PopupSourceOffset);
Style.Top = rect.Top + rect.Height * 0.5f;
break;
}
case PositionMode.LeftBottom:
{
Style.Left = null;
Style.Right = ((w - rect.Left) + PopupSourceOffset);
Style.Top = null;
Style.Bottom = (h - rect.Bottom);
break;
}
case PositionMode.AboveLeft:
{
Style.Left = rect.Left;
Style.Bottom = (Parent.Box.Rect * Parent.ScaleFromScreen).Height - rect.Top + PopupSourceOffset;
break;
}
case PositionMode.AboveCenter:
{
Style.Left = rect.Left + rect.Width * 0.5f;
Style.Bottom = (Parent.Box.Rect * Parent.ScaleFromScreen).Height - rect.Top + PopupSourceOffset;
break;
}
case PositionMode.BelowLeft:
{
Style.Left = rect.Left;
Style.Top = rect.Bottom + PopupSourceOffset;
break;
}
case PositionMode.BelowCenter:
{
Style.Left = rect.Center.x; // centering is done via styles
Style.Top = rect.Bottom + PopupSourceOffset;
break;
}
case PositionMode.BelowStretch:
{
Style.Left = rect.Left;
Style.Width = rect.Width;
Style.Top = rect.Bottom + PopupSourceOffset;
break;
}
case PositionMode.UnderMouse:
{
if ( isInitial )
{
Style.Left = Mouse.Position.x * PopupSource.ScaleFromScreen;
Style.Top = (Mouse.Position.y + PopupSourceOffset) * PopupSource.ScaleFromScreen;
}
break;
}
}
Style.Dirty();
}
}