Files
sbox-public/game/addons/tools/Code/Widgets/ControlWidgets/TextureImageControlWidget.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

238 lines
6.6 KiB
C#

namespace Editor;
/// <summary>
/// Resources stored as strings
/// </summary>
[CustomEditor( typeof( string ), WithAllAttributes = [typeof( TextureImagePathAttribute )] )]
public class TextureImageControlWidget : ControlWidget
{
public override bool IsControlButton => true;
public override bool SupportsMultiEdit => true;
public string WarningText { get; set; }
public TextureImageControlWidget( SerializedProperty property ) : base( property )
{
Cursor = CursorShape.Finger;
MouseTracking = true;
AcceptDrops = true;
IsDraggable = true;
OnValueChanged();
}
protected override void PaintControl()
{
var resource = SerializedProperty.GetValue<string>( null );
var asset = resource != null ? AssetSystem.FindByPath( resource ) : null;
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 = "Texture Image";
if ( !string.IsNullOrEmpty( WarningText ) )
{
Rect warningRect = iconRect;
warningRect.Left = rect.Left + 16;
Paint.SetPen( Theme.Yellow );
Paint.DrawIcon( warningRect, "warning", Math.Max( 16, warningRect.Height / 2 ) );
rect.Left += 16;
}
Pixmap icon = AssetType.ImageFile.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 ( asset is not null && !asset.IsDeleted )
{
Paint.Draw( iconRect, asset.GetAssetThumb( true ) );
var textRect = rect.Shrink( 0, 3 );
Paint.SetPen( Theme.Text.WithAlpha( 0.9f ) );
Paint.SetHeadingFont( 8, 450 );
var t = Paint.DrawText( textRect, $"{asset.Name}", TextFlag.LeftTop );
textRect.Left = t.Right + 6;
Paint.SetDefaultFont( 7 );
Theme.DrawFilename( textRect, asset.RelativePath, TextFlag.LeftCenter, Theme.Text.WithAlpha( 0.5f ) );
}
else if ( !string.IsNullOrWhiteSpace( resource ) )
{
var textRect = rect.Shrink( 0, 3 );
bool isPackage = !resource.Contains( ".vmap" ) && Package.TryParseIdent( resource, out _ );
if ( !isPackage )
{
Paint.SetBrush( Theme.Red.Darken( 0.8f ) );
Paint.DrawRect( iconRect, 2 );
Paint.SetPen( Theme.Red );
Paint.DrawIcon( iconRect, "error", Math.Max( 16, iconRect.Height / 2 ) );
}
else if ( icon != null ) Paint.Draw( iconRect, icon );
Paint.SetPen( Theme.Text.WithAlpha( 0.9f ) );
Paint.SetHeadingFont( 8, 450 );
var t = Paint.DrawText( textRect, isPackage ? (Package.TryGetCached( resource, out Package package ) ? $"{package.Title} ☁️" : $"Cloud {pickerName}") : $"Missing {pickerName}", TextFlag.LeftTop );
textRect.Left = t.Right + 6;
Paint.SetDefaultFont( 7 );
Theme.DrawFilename( textRect, resource, 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 resource = SerializedProperty.GetValue<string>( null );
var asset = (resource != null) ? AssetSystem.FindByPath( resource ) : null;
m.AddOption( "Open in Editor", "edit", () => asset?.OpenInEditor() ).Enabled = asset != null && !asset.IsProcedural;
m.AddOption( "Find in Asset Browser", "search", () => LocalAssetBrowser.OpenTo( asset, true ) ).Enabled = asset is not null;
m.AddSeparator();
m.AddOption( "Copy", "file_copy", action: Copy ).Enabled = asset != null;
m.AddOption( "Paste", "content_paste", action: Paste );
m.AddSeparator();
m.AddOption( "Clear", "backspace", action: Clear ).Enabled = resource != null;
m.OpenAtCursor( false );
e.Accepted = true;
}
protected override void OnMouseClick( MouseEvent e )
{
base.OnMouseClick( e );
if ( ReadOnly ) return;
OpenPicker();
}
public void OpenPicker()
{
var resource = SerializedProperty.GetValue<string>( null );
var asset = resource != null ? AssetSystem.FindByPath( resource ) : null;
var options = new AssetPicker.PickerOptions
{
AdditionalTypes = [AssetType.Texture, AssetType.ImageFile]
};
var picker = AssetPicker.Create( this, AssetType.Texture, options );
picker.SetSelection( resource );
picker.Title = $"Select Image File";
picker.OnAssetHighlighted = ( o ) => UpdateFromAsset( o.FirstOrDefault() );
picker.OnAssetPicked = ( o ) => UpdateFromAsset( o.FirstOrDefault() );
picker.Show();
picker.SetSelection( asset );
}
private void UpdateFromAsset( Asset asset )
{
if ( asset is null ) return;
SerializedProperty.Parent.NoteStartEdit( SerializedProperty );
SerializedProperty.SetValue( asset.RelativePath );
SerializedProperty.Parent.NoteFinishEdit( SerializedProperty );
}
public override void OnDragHover( DragEvent ev )
{
if ( !ev.Data.HasFileOrFolder )
return;
var asset = AssetSystem.FindByPath( ev.Data.FileOrFolder );
if ( asset == null )
return;
if ( asset.AssetType != AssetType.ImageFile && asset.AssetType != AssetType.Texture )
return;
ev.Action = DropAction.Link;
}
public override void OnDragDrop( DragEvent ev )
{
if ( !ev.Data.HasFileOrFolder )
return;
var asset = AssetSystem.FindByPath( ev.Data.FileOrFolder );
if ( asset == null )
return;
if ( asset.AssetType != AssetType.ImageFile && asset.AssetType != AssetType.Texture )
return;
UpdateFromAsset( asset );
ev.Action = DropAction.Link;
}
protected override void OnDragStart()
{
var resource = SerializedProperty.GetValue<string>( null );
var asset = resource != null ? AssetSystem.FindByPath( resource ) : null;
if ( asset == null )
return;
var drag = new Drag( this );
drag.Data.Url = new Uri( $"file://{asset.AbsolutePath}" );
drag.Execute();
}
void Copy()
{
var resource = SerializedProperty.GetValue<string>( null );
if ( resource == null ) return;
var asset = AssetSystem.FindByPath( resource );
if ( asset != null )
resource = asset.RelativePath;
EditorUtility.Clipboard.Copy( resource );
}
void Paste()
{
var path = EditorUtility.Clipboard.Paste();
var asset = AssetSystem.FindByPath( path );
UpdateFromAsset( asset );
}
void Clear()
{
SerializedProperty.Parent.NoteStartEdit( SerializedProperty );
SerializedProperty.SetValue( (Resource)null );
SerializedProperty.Parent.NoteFinishEdit( SerializedProperty );
}
}