mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-04-19 05:48:07 -04:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
322 lines
8.0 KiB
C#
322 lines
8.0 KiB
C#
using System.IO;
|
|
|
|
namespace Editor.AssetPickers;
|
|
|
|
/// <summary>
|
|
/// An asset browser allowing the user to pick a single asset.
|
|
/// Supports limiting display to only certain asset types.
|
|
/// </summary>
|
|
public class GenericPicker : AssetPicker
|
|
{
|
|
/// <summary>
|
|
/// Internal asset browser.
|
|
/// </summary>
|
|
public LocalAssetBrowser AssetBrowser { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Internal cloud browser.
|
|
/// </summary>
|
|
public CloudAssetBrowser CloudBrowser { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// The picked assets.
|
|
/// </summary>
|
|
public List<Asset> Assets { get; protected set; }
|
|
|
|
Button ConfirmButton;
|
|
Button CancelButton;
|
|
|
|
public GenericPicker( Widget parent, List<AssetType> assetTypes, PickerOptions options ) : base( parent, null, options )
|
|
{
|
|
Window.Size = new Vector2( 1280, 720 );
|
|
Window.SetModal( true );
|
|
Window.MinimumSize = 200;
|
|
Window.MaximumSize = 10000;
|
|
Window.Title = $"Select {string.Join( ", ", assetTypes?.Select( x => x.FriendlyName ) ?? new List<string>() )} - Asset Picker";
|
|
Window.StatusBar = new StatusBar( this );
|
|
|
|
Window.StateCookie = "AssetPicker";
|
|
Window.RestoreFromStateCookie();
|
|
|
|
Layout = Layout.Column();
|
|
CreateUI( assetTypes );
|
|
}
|
|
|
|
private DockManager DockManager;
|
|
|
|
void CreateUI( List<AssetType> assetTypes )
|
|
{
|
|
DockManager = new DockManager( this );
|
|
DockManager.DockProperty properties = DockManager.DockProperty.HideCloseButton
|
|
| DockManager.DockProperty.DisallowUserDocking | DockManager.DockProperty.DisableDraggableTab;
|
|
|
|
AssetBrowser = new LocalAssetBrowser( DockManager, assetTypes );
|
|
AssetBrowser.WindowTitle = "Asset Browser";
|
|
AssetBrowser.SetWindowIcon( "folder" );
|
|
|
|
AssetBrowser.OnAssetHighlight += Highlight;
|
|
AssetBrowser.OnAssetsHighlight += Highlight;
|
|
AssetBrowser.OnAssetSelected += ( a ) => Select();
|
|
AssetBrowser.OnHighlight += Highlight;
|
|
AssetBrowser.MultiSelect = Options.EnableMultiselect;
|
|
DockManager.AddDock( null, AssetBrowser, DockArea.Inside, properties );
|
|
|
|
if ( Options.EnableCloud )
|
|
{
|
|
CloudBrowser = new CloudAssetBrowser( DockManager, assetTypes );
|
|
CloudBrowser.WindowTitle = "Cloud Browser";
|
|
CloudBrowser.SetWindowIcon( "cloud_download" );
|
|
|
|
CloudBrowser.OnPackageHighlight = HighlightPackage;
|
|
CloudBrowser.OnPackageSelected = ( a ) => Select();
|
|
CloudBrowser.MultiSelect = Options.EnableMultiselect;
|
|
DockManager.AddDock( null, CloudBrowser, DockArea.Inside, properties );
|
|
}
|
|
|
|
Layout.Add( DockManager, 1 );
|
|
Layout.AddSeparator();
|
|
|
|
var bottom = Layout.AddRow();
|
|
bottom.Spacing = 10;
|
|
bottom.Margin = 10;
|
|
bottom.AddStretchCell();
|
|
|
|
ConfirmButton = bottom.Add( new Button.Primary( "Select" ) );
|
|
ConfirmButton.Enabled = false;
|
|
ConfirmButton.Clicked = Select;
|
|
|
|
CancelButton = bottom.Add( new Button( "Cancel" ) );
|
|
CancelButton.Enabled = true;
|
|
CancelButton.Clicked = Close;
|
|
}
|
|
|
|
public override void SetSelection( Asset asset )
|
|
{
|
|
if ( asset is null )
|
|
{
|
|
DockManager.RaiseDock( AssetBrowser );
|
|
AssetBrowser.NavigateTo( Project.Current.GetAssetsPath() );
|
|
return;
|
|
}
|
|
|
|
Package package = asset?.Package;
|
|
if ( package is not null )
|
|
{
|
|
SetSelection( package );
|
|
}
|
|
else
|
|
{
|
|
DockManager.RaiseDock( AssetBrowser );
|
|
AssetBrowser.FocusOnAsset( asset );
|
|
}
|
|
}
|
|
|
|
public override void SetSelection( Package package )
|
|
{
|
|
if ( package is null )
|
|
return;
|
|
|
|
DockManager.RaiseDock( CloudBrowser );
|
|
CloudBrowser.Search.Value += $" {package.FullIdent}";
|
|
CloudBrowser.FocusOnPackage( package );
|
|
}
|
|
|
|
void Select()
|
|
{
|
|
if ( AssetBrowser.Visible )
|
|
{
|
|
var assets = AssetBrowser.GetSelected<AssetEntry>().Select( x => x.Asset ).ToList();
|
|
|
|
if ( !IsSelectionValid( assets ) )
|
|
return;
|
|
|
|
Submit( assets.ToArray() );
|
|
}
|
|
else
|
|
{
|
|
Package package = CloudBrowser.GetSelected<PackageEntry>().FirstOrDefault().Package;
|
|
if ( package is not null )
|
|
{
|
|
Submit( package );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool IsSelectionValid( List<Asset> assets ) => assets.TrueForAll( IsSelectionValid );
|
|
|
|
bool IsSelectionValid( Asset asset )
|
|
{
|
|
// If no asset types are selected, allow anything to be selected
|
|
if ( AssetBrowser.FilterAssetTypes?.Count == 0 )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ( asset is null )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( !AssetBrowser.FilterAssetTypes?.Contains( asset.AssetType ) ?? false )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool IsSelectionValid( Package package )
|
|
{
|
|
if ( package is null )
|
|
return false;
|
|
|
|
if ( package.TypeName == "map" )
|
|
{
|
|
// special case because these can be vpks, not assets
|
|
return AssetBrowser.FilterAssetTypes.Contains( AssetType.MapFile );
|
|
}
|
|
|
|
var primaryAssetName = package.GetCachedMeta<string>( "PrimaryAsset" );
|
|
string ext = Path.GetExtension( primaryAssetName );
|
|
if ( !AssetBrowser.FilterAssetTypes?.Any( x => ext == $".{x.FileExtension}" ) ?? false )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Highlight( Asset a )
|
|
{
|
|
bool isValid = IsSelectionValid( a );
|
|
if ( isValid )
|
|
{
|
|
Assets = new List<Asset>() { a };
|
|
OnAssetHighlighted?.Invoke( Assets.ToArray() );
|
|
ConfirmButton.Enabled = isValid;
|
|
BindSystem.Flush();
|
|
}
|
|
|
|
EditorUtility.PlayAssetSound( a );
|
|
|
|
ConfirmButton.Enabled = isValid;
|
|
}
|
|
|
|
void Highlight( Asset[] a )
|
|
{
|
|
var assets = new List<Asset>( a );
|
|
bool isValid = IsSelectionValid( assets );
|
|
if ( isValid )
|
|
{
|
|
Assets = assets;
|
|
OnAssetHighlighted?.Invoke( Assets.ToArray() );
|
|
BindSystem.Flush();
|
|
}
|
|
|
|
ConfirmButton.Enabled = isValid;
|
|
}
|
|
|
|
void Highlight( IEnumerable<IAssetListEntry> entries )
|
|
{
|
|
if ( entries.Any( x => x is not AssetEntry or PackageEntry ) )
|
|
{
|
|
// not something we can pick
|
|
ConfirmButton.Enabled = false;
|
|
}
|
|
}
|
|
|
|
async void HighlightPackage( Package package )
|
|
{
|
|
ConfirmButton.Enabled = false;
|
|
|
|
if ( AssetSystem.CanCloudInstall( package ) )
|
|
{
|
|
var a = await AssetSystem.InstallAsync( package.FullIdent );
|
|
|
|
if ( !IsValid ) return;
|
|
|
|
if ( a is not null )
|
|
{
|
|
EditorUtility.PlayAssetSound( a );
|
|
|
|
Assets = new List<Asset>() { a };
|
|
OnAssetHighlighted?.Invoke( Assets.ToArray() );
|
|
}
|
|
}
|
|
|
|
package = await Package.FetchAsync( package.FullIdent, false );
|
|
if ( !IsValid ) return;
|
|
|
|
ConfirmButton.Enabled = IsSelectionValid( package );
|
|
}
|
|
|
|
protected override void OnKeyPress( KeyEvent e )
|
|
{
|
|
base.OnKeyPress( e );
|
|
|
|
if ( e.Key == KeyCode.Escape )
|
|
{
|
|
Close();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called from native to open an asset picker
|
|
/// </summary>
|
|
[Event( "assetsystem.openpicker" )]
|
|
static void OpenAssetPicker( AssetSystem.AssetPickerParameters parameters )
|
|
{
|
|
// TODO: Maybe should pass a parent widget which would be the callback listener?
|
|
AssetPicker picker = null;
|
|
|
|
var options = new PickerOptions()
|
|
{
|
|
EnableCloud = parameters.ShowCloudAssets,
|
|
AdditionalTypes = parameters.FilterAssetTypes
|
|
};
|
|
|
|
if ( parameters.FilterAssetTypes.Select( x => x.ResourceType ).Distinct().Where( x => x != null ).Count() == 1 )
|
|
{
|
|
picker = Create( parameters.ParentWidget, parameters.FilterAssetTypes[0], options );
|
|
}
|
|
else
|
|
{
|
|
picker = new GenericPicker( parameters.ParentWidget, parameters.FilterAssetTypes, options );
|
|
}
|
|
|
|
if ( picker is GenericPicker )
|
|
{
|
|
var gp = picker as GenericPicker;
|
|
|
|
// parameters.ViewMode is 0 for list, 1 for grid, try to preserve icon size from the asset browser cookie
|
|
if ( (parameters.ViewMode == 0 && gp.AssetBrowser.ViewModeType != AssetListViewMode.List) ||
|
|
(parameters.ViewMode == 1 && gp.AssetBrowser.ViewModeType == AssetListViewMode.List) )
|
|
{
|
|
gp.AssetBrowser.ViewModeType = (AssetListViewMode)parameters.ViewMode;
|
|
}
|
|
|
|
}
|
|
|
|
picker.OnAssetPicked = parameters.AssetSelectedCallback;
|
|
|
|
//
|
|
// Native can pass down a title which it also wants to use as a settings key
|
|
//
|
|
if ( !string.IsNullOrEmpty( parameters.Title ) )
|
|
{
|
|
picker.Title = parameters.Title;
|
|
// TODO: Use the title as the AssetBrowser cookie (does it make sense for the window StateCookie too?)
|
|
}
|
|
|
|
picker.Show();
|
|
|
|
//
|
|
// Focus on the initial asset if we have one ( e.g whatever the current asset already is )
|
|
// Do this after the window is shown so it can scroll properly
|
|
//
|
|
picker.SetSelection( parameters.InitialSelectedAsset );
|
|
picker.SetSearchText( parameters.InitialSearchText );
|
|
}
|
|
}
|