UI/SpawnMenu/Spawnlists/SpawnlistsPage.cs
using Sandbox.UI;
namespace Sandbox;
/// <summary>
/// Shared spawnlist support for spawn menu pages.
/// </summary>
public abstract class SpawnlistsPage : BaseSpawnMenu
{
public SpawnlistCollection Collection { get; } = new();
readonly Dictionary<string, SpawnMenuOption> _spawnlistOptions = new();
public SpawnlistsPage()
{
BindCollection();
SpawnlistData.SpawnlistCreated += Collection.Refresh;
Collection.Refresh();
}
void BindCollection()
{
Collection.OnChanged = OnCollectionChanged;
Collection.OnInstalled = OnCollectionInstalled;
}
public override void OnHotloaded()
{
// Constructors do not run again for existing panels during hotload.
BindCollection();
base.OnHotloaded();
}
void OnCollectionChanged()
{
OnParametersSet();
// A removed list must stop refreshing its deleted storage and leave the
// content area on a valid page, whether removed here or from the sidebar.
if ( ActivePanel is SpawnlistView view &&
!Collection.Entries.Any( entry => entry.StorageEntry.Id == view.Entry.Id ) )
{
DeselectOption();
view.Delete( true );
SelectOption( "#spawnmenu.props.all" );
}
}
void OnCollectionInstalled( string name )
{
OnParametersSet();
SelectOption( name );
}
public override void OnDeleted()
{
SpawnlistData.SpawnlistCreated -= Collection.Refresh;
Collection.OnChanged = null;
Collection.OnInstalled = null;
base.OnDeleted();
}
protected void AddSpawnlistOptions()
{
_spawnlistOptions.Clear();
if ( Collection.Entries.Count > 0 || Collection.PendingCount > 0 )
{
AddHeader( "#spawnmenu.section.workshop_spawnlists" );
foreach ( var entry in Collection.Entries )
{
var captured = entry;
_spawnlistOptions[entry.StorageEntry.Id] = AddOption( entry.Icon, entry.Name,
() => new SpawnlistView { Entry = captured.StorageEntry },
entry.IsEditable
? () => OnEditableRightClick( captured )
: () => OnInstalledRightClick( captured ) );
}
AddSkeletons( Collection.PendingCount );
}
AddHeader( "#spawnmenu.section.workshop" );
AddOption( "🎖️", "#spawnmenu.spawnlist.popular", () => new SpawnlistWorkshop { SortOrder = WorkshopSortMode.Popular } );
AddOption( "🐣", "#spawnmenu.spawnlist.newest", () => new SpawnlistWorkshop { SortOrder = WorkshopSortMode.Newest } );
}
protected override void OnMenuFooter( Panel footer )
{
footer.AddChild<SpawnlistFooter>();
}
/// <summary>Refresh after external changes (create, etc.).</summary>
public void RefreshList() => Collection.Refresh();
public void SelectSpawnlist( Storage.Entry entry )
{
if ( !_spawnlistOptions.TryGetValue( entry.Id, out var option ) ) return;
_firstViewed = true;
SwitchOption( option );
}
void OnEditableRightClick( SpawnlistCollection.Entry entry )
{
var menu = new Sandbox.UI.Menu();
if ( entry.StorageEntry.GetMeta( "_workshopId", 0ul ) == 0 )
{
menu.AddOption( "#spawnmenu.spawnlist.rename", "edit", () =>
{
var data = SpawnlistData.Load( entry.StorageEntry );
var popup = new StringQueryPopup
{
Title = "#spawnmenu.spawnlist.rename_title",
Prompt = "#spawnmenu.spawnlist.rename_prompt",
Placeholder = "#spawnmenu.spawnlist.name_placeholder",
ConfirmLabel = "#spawnmenu.spawnlist.rename_button",
InitialValue = data.Name,
OnConfirm = newName =>
{
if ( entry.StorageEntry.GetMeta( "_workshopId", 0ul ) != 0 ) return;
SpawnlistData.Rename( entry.StorageEntry, newName );
Collection.Refresh();
}
};
popup.Parent = FindPopupPanel();
} );
}
menu.AddOption( "#spawnmenu.spawnlist.delete", "delete", () => Collection.Delete( entry.StorageEntry ) );
menu.Open( this, Popup.PositionMode.UnderMouse );
}
void OnInstalledRightClick( SpawnlistCollection.Entry entry )
{
var menu = new Sandbox.UI.Menu();
menu.AddOption( "#spawnmenu.spawnlist.remove", "delete", () => Collection.Uninstall( entry.WorkshopId ) );
menu.Open( this, Popup.PositionMode.UnderMouse );
}
}