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]
237 lines
6.0 KiB
C#
237 lines
6.0 KiB
C#
namespace Editor;
|
|
|
|
/// <summary>
|
|
/// This is a callback control widget, which is used to edit classes.
|
|
/// It shows key properties, and an edit button. On clicking the edit button
|
|
/// it'll show a propery sheet popup.
|
|
/// </summary>
|
|
public class GenericControlWidget : ControlObjectWidget
|
|
{
|
|
public override bool SupportsMultiEdit => true;
|
|
|
|
public override bool IsWideMode => _isInlineEditor;
|
|
public override bool IncludeLabel => !_isInlineEditor;
|
|
|
|
bool _isInlineEditor;
|
|
RealTimeSince _visibilityDebounce = 0;
|
|
Widget PlaceholderWidget;
|
|
Dictionary<SerializedProperty, ControlWidget> KeyPropertyWidgets;
|
|
|
|
public GenericControlWidget( SerializedProperty property ) : base( property, true )
|
|
{
|
|
PaintBackground = false;
|
|
|
|
if ( property.TryGetAttribute<InlineEditorAttribute>( out var inlineEditor ) )
|
|
{
|
|
_isInlineEditor = true;
|
|
BuildInlineEditor( inlineEditor );
|
|
return;
|
|
}
|
|
|
|
Layout = Layout.Row();
|
|
Layout.Spacing = 2;
|
|
KeyPropertyWidgets = new();
|
|
|
|
var keys = SerializedObject?.Where( x => x.HasAttribute<KeyPropertyAttribute>() ).ToArray();
|
|
if ( keys is not null && keys.Length > 0 )
|
|
{
|
|
foreach ( var key in keys )
|
|
{
|
|
var widget = Layout.Add( ControlSheetRow.CreateEditor( key ) );
|
|
widget.Visible = key.ShouldShow();
|
|
KeyPropertyWidgets.Add( key, widget );
|
|
}
|
|
|
|
// Only show the full edit button if we have editable properties that aren't showing on the front bar.
|
|
var propertiesThatArentKeys = SerializedObject?.Where( x => x.IsEditable && x.ShouldShow() && !x.IsMethod && !x.HasAttribute<KeyPropertyAttribute>() ).ToArray();
|
|
|
|
if ( propertiesThatArentKeys.Length > 0 )
|
|
{
|
|
var row = Layout.AddColumn();
|
|
var popupButton = new IconButton( "edit_note" );
|
|
popupButton.OnClick = OpenPopup;
|
|
popupButton.ToolTip = $"Edit";
|
|
popupButton.Background = Theme.ControlBackground;
|
|
popupButton.Foreground = Theme.Text;
|
|
popupButton.IconSize = 16;
|
|
|
|
row.Add( popupButton );
|
|
row.AddStretchCell( 1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PlaceholderWidget = new Widget( this );
|
|
PlaceholderWidget.Size = Theme.RowHeight;
|
|
PlaceholderWidget.VerticalSizeMode = SizeMode.CanGrow;
|
|
PlaceholderWidget.HorizontalSizeMode = SizeMode.Flexible;
|
|
PlaceholderWidget.OnPaintOverride = PaintPlaceholder;
|
|
PlaceholderWidget.MouseClick = OpenPopup;
|
|
PlaceholderWidget.Cursor = CursorShape.Finger;
|
|
PlaceholderWidget.ToolTip = $"Edit";
|
|
Layout.Add( PlaceholderWidget, 1 );
|
|
}
|
|
}
|
|
|
|
StickyPopup Popup;
|
|
|
|
public override void OnDestroyed()
|
|
{
|
|
Popup?.Destroy();
|
|
Popup = null;
|
|
|
|
base.OnDestroyed();
|
|
}
|
|
|
|
protected void OpenPopup()
|
|
{
|
|
if ( Popup.IsValid() )
|
|
{
|
|
Popup?.Destroy();
|
|
Popup = null;
|
|
return;
|
|
}
|
|
|
|
var obj = SerializedObject;
|
|
|
|
// if it's nullable, create for the actual value rather than the nullable container
|
|
if ( SerializedProperty.IsNullable )
|
|
{
|
|
// best way to do this?
|
|
obj = SerializedProperty.GetValue<object>().GetSerialized();
|
|
obj.ParentProperty = SerializedProperty;
|
|
}
|
|
|
|
if ( obj is null )
|
|
{
|
|
Log.Error( "Cannot create ControlSheet for a null object" );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Create a popup for the control sheet editor
|
|
//
|
|
{
|
|
var popup = new StickyPopup( null )
|
|
{
|
|
Owner = this,
|
|
MinimumWidth = Width,
|
|
Position = ScreenRect.BottomLeft
|
|
};
|
|
|
|
var editor = EditorUtility.OpenControlSheet( obj, this, false );
|
|
|
|
popup.Layout.Add( editor );
|
|
popup.OnPaintOverride = PaintPopupBackground;
|
|
popup.Visible = true;
|
|
popup.Focus( true );
|
|
|
|
Popup = popup;
|
|
|
|
//
|
|
// Clear any unrelated popups
|
|
//
|
|
Popup.DestroyUnrelatedPopups();
|
|
}
|
|
}
|
|
|
|
bool PaintPopupBackground()
|
|
{
|
|
Paint.ClearPen();
|
|
Paint.SetBrushLinear( 0, Vector2.Down * 256, Theme.SurfaceBackground.Lighten( 0.2f ).WithAlpha( 0.98f ), Theme.SurfaceBackground.WithAlpha( 0.95f ) );
|
|
Paint.DrawRect( Paint.LocalRect );
|
|
|
|
Paint.ClearBrush();
|
|
Paint.SetPen( Color.Black.WithAlpha( 0.33f ), 2, PenStyle.Solid );
|
|
Paint.DrawRect( Paint.LocalRect.Shrink( 0, -10, 1, 1 ), 4 );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PaintPlaceholder()
|
|
{
|
|
var type = SerializedProperty.IsNullable ? SerializedProperty.NullableType : SerializedProperty.PropertyType;
|
|
|
|
var value = SerializedProperty.GetValue<object>();
|
|
|
|
type = value?.GetType() ?? type;
|
|
var displayInfo = DisplayInfo.ForType( type );
|
|
string labelText = displayInfo.Name;
|
|
|
|
// If the type has a custom ToString(), use that instead of the type name.
|
|
if ( type.GetMethod( "ToString" ).DeclaringType != typeof( object ) )
|
|
{
|
|
labelText = value?.ToString() ?? labelText;
|
|
}
|
|
|
|
Theme.DrawDropdown( LocalRect, labelText, displayInfo.Icon ?? "edit_note", Popup.IsValid(), IsControlDisabled );
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The property has [InlineEditor], so we want to unfold this and show it inline.
|
|
/// </summary>
|
|
void BuildInlineEditor( InlineEditorAttribute attribute )
|
|
{
|
|
Layout = Layout.Column();
|
|
|
|
if ( attribute.Label )
|
|
{
|
|
Layout.Add( ControlSheet.CreateLabel( SerializedProperty ) );
|
|
}
|
|
|
|
var cs = new ControlSheet();
|
|
cs.AddObject( SerializedObject );
|
|
cs.Margin = 0;
|
|
|
|
Layout.Add( cs );
|
|
}
|
|
|
|
protected override void OnContextMenu( ContextMenuEvent e )
|
|
{
|
|
if ( !_isInlineEditor ) return;
|
|
|
|
e.Accepted = true;
|
|
|
|
var property = SerializedProperty;
|
|
|
|
var menu = new ContextMenu( this );
|
|
menu.AddOption( $"Copy {property.DisplayName}", "content_copy", () =>
|
|
{
|
|
var str = ToClipboardString();
|
|
EditorUtility.Clipboard.Copy( str );
|
|
} );
|
|
|
|
menu.AddOption( $"Paste as {property.DisplayName}", "content_paste", () =>
|
|
{
|
|
var str = EditorUtility.Clipboard.Paste();
|
|
FromClipboardString( str );
|
|
} );
|
|
|
|
menu.AddOption( "Reset to Default", "restart_alt", () =>
|
|
{
|
|
property.Parent.NoteStartEdit( property );
|
|
property.SetValue( property.GetDefault() );
|
|
property.Parent.NoteFinishEdit( property );
|
|
} );
|
|
|
|
menu.OpenAt( e.ScreenPosition, false );
|
|
}
|
|
|
|
[EditorEvent.Frame]
|
|
public void UpdateVisibility()
|
|
{
|
|
if ( KeyPropertyWidgets is null )
|
|
return;
|
|
if ( _visibilityDebounce < 0.2f )
|
|
return;
|
|
|
|
_visibilityDebounce = Random.Shared.Float( 0, 0.1f );
|
|
|
|
foreach ( var kvp in KeyPropertyWidgets )
|
|
{
|
|
kvp.Value.Visible = kvp.Key.ShouldShow();
|
|
}
|
|
}
|
|
}
|