using Editor.AssetPickers;
using Sandbox.Diagnostics;
namespace Editor;
///
/// File paths stored as strings
///
[CustomEditor( typeof( string ), WithAllAttributes = new[] { typeof( FilePathAttribute ) } )]
public class FilePathStringControlWidget : ControlWidget
{
public override bool IsControlButton => true;
public override bool SupportsMultiEdit => true;
public string Extension { get; set; } = string.Empty;
public FilePathStringControlWidget( SerializedProperty property ) : base( property )
{
property.TryGetAttribute( out var attr );
Assert.NotNull( attr, "FilePathStringControlWidget property has no FilePathAttribute" );
Extension = attr.Extension ?? "";
Cursor = CursorShape.Finger;
MouseTracking = true;
AcceptDrops = true;
IsDraggable = true;
OnValueChanged();
}
protected override void PaintControl()
{
var filePath = SerializedProperty.GetValue( null );
var asset = filePath != null ? AssetSystem.FindByPath( filePath ) : null;
var isEmpty = string.IsNullOrWhiteSpace( filePath );
var rect = new Rect( 0, Size );
var iconRect = rect.Shrink( 2 );
iconRect.Width = iconRect.Height;
rect.Left = iconRect.Right + 10;
Paint.ClearPen();
Paint.SetBrush( Theme.SurfaceBackground.WithAlpha( 0.2f ) );
Paint.DrawRect( iconRect, 2 );
var pickerName = "Any File";
if ( !string.IsNullOrEmpty( Extension ) )
{
var extensions = Extension.Split( ',' );
if ( extensions.Length > 1 )
{
pickerName = $"(*.{extensions[0]} | *." + string.Join( " | *.", extensions.Skip( 1 ) ) + ")";
}
else if ( extensions.Length == 1 )
{
pickerName = $"(*.{extensions[0]})";
}
}
Pixmap icon = null;
var relatedAssetType = AssetType.All.FirstOrDefault( x => x.FileExtension == Extension );
if ( relatedAssetType is not null )
{
icon = relatedAssetType.Icon64;
}
if ( SerializedProperty.IsMultipleDifferentValues )
{
var textRect = rect.Shrink( 0, 3 );
if ( icon != null ) Paint.Draw( iconRect, icon );
Paint.SetDefaultFont();
Paint.SetPen( Theme.MultipleValues );
Paint.DrawText( textRect, $"Multiple Values", TextFlag.LeftCenter );
}
else if ( !isEmpty )
{
if ( asset is not null && !asset.IsDeleted )
{
Paint.Draw( iconRect, asset.GetAssetThumb( true ) );
}
var textRect = rect.Shrink( 0, 3 );
var fileExt = System.IO.Path.GetExtension( filePath );
var fileName = System.IO.Path.GetFileName( filePath );
fileName = fileName.Remove( fileName.IndexOf( fileExt ) ).ToTitleCase().ToLower();
Paint.SetPen( Theme.Text.WithAlpha( 0.9f ) );
Paint.SetHeadingFont( 8, 450 );
var t = Paint.DrawText( textRect, $"{fileName}", TextFlag.LeftTop );
textRect.Left = t.Right + 6;
Paint.SetDefaultFont( 7 );
Theme.DrawFilename( textRect, filePath, TextFlag.LeftCenter, Theme.Text.WithAlpha( 0.5f ) );
}
else
{
var textRect = rect.Shrink( 0, 3 );
if ( icon != null ) Paint.Draw( iconRect, icon );
Paint.SetDefaultFont( italic: true );
Paint.SetPen( Theme.Text.WithAlpha( 0.2f ) );
Paint.DrawText( textRect, pickerName, TextFlag.LeftCenter );
}
}
protected override void OnContextMenu( ContextMenuEvent e )
{
var m = new ContextMenu();
var filePath = SerializedProperty.GetValue( null );
var isEmpty = string.IsNullOrEmpty( filePath );
//m.AddOption( "Open in Editor", "edit", () => asset?.OpenInEditor() ).Enabled = asset != null;
//m.AddOption( "Find in Asset Browser", "search", () => AssetBrowser.OpenTo( asset, true ) ).Enabled = asset is not null;
//m.AddSeparator();
m.AddOption( "Copy", "file_copy", action: Copy ).Enabled = !isEmpty;
m.AddOption( "Paste", "content_paste", action: Paste );
m.AddSeparator();
m.AddOption( "Clear", "backspace", action: Clear ).Enabled = !isEmpty;
m.OpenAtCursor( false );
e.Accepted = true;
}
protected override void OnMouseClick( MouseEvent e )
{
base.OnMouseClick( e );
if ( ReadOnly ) return;
var filePath = SerializedProperty.GetValue( null );
var picker = new GenericPicker( Parent, [], new() );
var query = "";
foreach ( var ext in Extension.Split( ',' ) )
{
if ( string.IsNullOrEmpty( ext ) ) continue;
query += $"t:{ext} ";
}
picker.AssetBrowser.Search.Value = query;
picker.Title = $"Select {SerializedProperty.DisplayName}";
picker.AssetBrowser.OnHighlight += ( entries ) =>
{
PropertyStartEdit();
UpdateFromObject( entries.First() );
PropertyFinishEdit();
};
picker.AssetBrowser.OnFileSelected += ( o ) =>
{
PropertyStartEdit();
UpdateFromObject( o );
PropertyFinishEdit();
};
picker.Show();
picker.SetSelection( filePath );
}
private void UpdateFromObject( object obj )
{
if ( obj is null ) return;
SerializedProperty.Parent.NoteStartEdit( SerializedProperty );
if ( obj is Asset asset )
{
SerializedProperty.SetValue( asset.RelativePath );
}
else if ( obj is string str )
{
var relativePath = System.IO.Path.GetRelativePath( Project.Current.GetAssetsPath(), str );
SerializedProperty.SetValue( relativePath );
}
else if ( obj is AssetEntry assetEntry )
{
var path = System.IO.Path.GetRelativePath( Project.Current.GetAssetsPath(), assetEntry.AbsolutePath );
SerializedProperty.SetValue( path );
}
SerializedProperty.Parent.NoteFinishEdit( SerializedProperty );
}
bool CanAssign( string path )
{
var ext = System.IO.Path.GetExtension( path ).Substring( 1 );
if ( !string.IsNullOrEmpty( Extension ) && !Extension.Split( ',' ).Contains( ext ) )
{
return false;
}
return true;
}
public override void OnDragHover( DragEvent ev )
{
if ( string.IsNullOrEmpty( ev.Data.Text ) )
return;
ev.Action = DropAction.Link;
}
public override void OnDragDrop( DragEvent ev )
{
var path = ev.Data.Text;
if ( string.IsNullOrEmpty( path ) )
return;
if ( !CanAssign( path ) )
return;
PropertyStartEdit();
UpdateFromObject( path );
PropertyFinishEdit();
ev.Action = DropAction.Link;
}
protected override void OnDragStart()
{
var filePath = SerializedProperty.GetValue( null );
var drag = new Drag( this );
drag.Data.Text = filePath;
drag.Execute();
}
void Copy()
{
var filePath = SerializedProperty.GetValue( null );
if ( string.IsNullOrEmpty( filePath ) ) return;
EditorUtility.Clipboard.Copy( filePath );
}
void Paste()
{
var path = EditorUtility.Clipboard.Paste();
if ( !CanAssign( path ) )
return;
UpdateFromObject( path );
}
void Clear()
{
SerializedProperty.Parent.NoteStartEdit( SerializedProperty );
SerializedProperty.SetValue( (string)null );
SerializedProperty.Parent.NoteFinishEdit( SerializedProperty );
}
}