Files
sbox-public/game/addons/tools/Code/Scene/GameObjectInspector/ComponentControlWidget.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

153 lines
3.8 KiB
C#

namespace Editor;
[CustomEditor( typeof( Component ) )]
public class ComponentControlWidget : ControlWidget
{
public override bool SupportsMultiEdit => true;
IconButton PickerButton;
public ComponentControlWidget( SerializedProperty property ) : base( property )
{
if ( !property.IsEditable )
ReadOnly = true;
SetSizeMode( SizeMode.Default, SizeMode.Default );
Layout = Layout.Column();
Layout.Spacing = 2;
var inner = Layout.Add( Layout.Row() );
inner.Margin = 2;
inner.AddStretchCell( 1 );
PickerButton = inner.Add( new IconButton( "colorize", () =>
{
PropertyStartEdit();
EyeDropperTool.SetTargetProperty( property );
EyeDropperTool.OnBackToLastTool = () => PropertyFinishEdit();
}, this ) );
PickerButton.FixedWidth = Theme.RowHeight - 4;
PickerButton.FixedHeight = Theme.RowHeight - 4;
PickerButton.Visible = false;
PickerButton.ToolTip = $"Pick {property.DisplayName}";
AcceptDrops = true;
}
protected override void OnContextMenu( ContextMenuEvent e )
{
var m = new ContextMenu( this );
var component = SerializedProperty.GetValue<Component>();
if ( component.IsValid() && component.GameObject.IsValid() )
{
m.AddOption( "Find in Scene", "search", () => EditorUtility.FindInScene( component ) );
m.AddSeparator();
}
if ( !ReadOnly )
{
m.AddOption( "Clear", action: Clear );
}
if ( m.OptionCount > 0 )
{
m.OpenAtCursor( false );
}
e.Accepted = true;
}
protected override void PaintControl()
{
var rect = LocalRect.Shrink( 6, 0 );
var component = SerializedProperty.GetValue<Component>();
var type = EditorTypeLibrary.GetType( SerializedProperty.PropertyType );
Paint.SetDefaultFont();
var icon = type?.Icon;
if ( type.IsInterface ) icon = $"data_object";
if ( SerializedProperty.IsMultipleDifferentValues )
{
Paint.SetPen( Theme.MultipleValues );
Paint.DrawIcon( rect, icon, 14, TextFlag.LeftCenter );
rect.Left += 22;
Paint.DrawText( rect, "Multiple Values", TextFlag.LeftCenter );
}
else if ( !component.IsValid() )
{
Paint.SetPen( Theme.TextControl.WithAlpha( 0.3f ) );
Paint.DrawIcon( rect, icon, 14, TextFlag.LeftCenter );
rect.Left += 22;
Paint.DrawText( rect, $"None ({type?.Name})", TextFlag.LeftCenter );
Cursor = CursorShape.None;
}
else
{
Paint.SetPen( Theme.Green );
Paint.DrawIcon( rect, icon, 14, TextFlag.LeftCenter );
rect.Left += 22;
Paint.DrawText( rect, $"{component.GetType().Name} on ({component.GameObject?.Name ?? "null"})", TextFlag.LeftCenter );
Cursor = CursorShape.Finger;
}
if ( EyeDropperTool.TargetProperty == SerializedProperty )
{
Paint.SetPen( ControlHighlightSecondary.WithAlpha( 0.8f ), 2, PenStyle.Dot );
Paint.SetBrush( ControlHighlightSecondary.WithAlpha( 0.2f ) );
Paint.DrawRect( LocalRect.Shrink( 2 ), Theme.ControlRadius );
}
PickerButton.Visible = IsControlHovered;
}
protected override void OnMouseClick( MouseEvent e )
{
if ( !e.LeftMouseButton )
{
return;
}
e.Accepted = true;
var component = SerializedProperty.GetValue<Component>();
EditorUtility.FindInScene( component );
}
void Clear()
{
PropertyStartEdit();
SerializedProperty.SetValue<Component>( null );
PropertyFinishEdit();
}
private Component GetMatching( DragData data )
{
var type = SerializedProperty.PropertyType;
return data.OfType( type ).Cast<Component>().FirstOrDefault()
?? data.OfType<GameObject>()
.Select( x => x.Components.Get( type, FindMode.EverythingInSelf ) )
.OfType<Component>()
.FirstOrDefault();
}
public override void OnDragHover( DragEvent ev )
{
ev.Action = GetMatching( ev.Data ).IsValid() ? DropAction.Link : DropAction.Ignore;
}
public override void OnDragDrop( DragEvent ev )
{
if ( GetMatching( ev.Data ) is { } value )
{
PropertyStartEdit();
SerializedProperty.SetValue( value );
PropertyFinishEdit();
}
}
}