Editor/ShaderGraphPlus/Widgets/Properties.cs
using Editor;
using System.Runtime.CompilerServices;
namespace ShaderGraphPlus;
public class Properties : Widget
{
private Widget _sheetCanvas;
private ScrollArea _scroller;
private ControlSheet _sheet;
private string _filterText;
private PropertiesHeader _header;
private object _target;
public object Target
{
get => _target;
set
{
if ( value == _target )
return;
_target = value;
Rebuild();
TargetChanged?.Invoke();
}
}
private readonly Layout Editor;
public Action<SerializedProperty> PropertyUpdated { get; set; }
public Action TargetChanged { get; set; }
public Properties( Widget parent ) : base( parent )
{
Name = "Properties";
WindowTitle = "Properties";
SetWindowIcon( "edit" );
MinimumWidth = 400;
Layout = Layout.Column();
Layout.Margin = 0;
var toolbar = new ToolBar( this );
var filter = new LineEdit( toolbar ) { PlaceholderText = "Filter Properties.." };
filter.TextEdited += OnFilterEdited;
toolbar.AddWidget( filter );
Layout.Add( toolbar );
Layout.AddSeparator();
_header = Layout.Add( new PropertiesHeader() );
_sheet = new ControlSheet();
_scroller = new ScrollArea( this );
_scroller.Canvas = new Widget();
_scroller.Canvas.Layout = Layout.Column();
_scroller.Canvas.VerticalSizeMode = SizeMode.CanGrow;
_scroller.Canvas.HorizontalSizeMode = SizeMode.Flexible;
_scroller.Canvas.Layout.Add( _sheet );
_scroller.Canvas.Layout.AddStretchCell();
_sheetCanvas = _scroller.Canvas;
Editor = Layout.AddColumn( 1 );
Editor.Add( _scroller );
Layout.AddStretchCell();
}
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public bool IsTarget<T>( out T targetValue )
{
targetValue = default( T );
if ( Target is T target )
{
targetValue = (T)target;
return true;
}
return false;
}
private void Rebuild()
{
UpdateHeader();
RebuildSheet();
}
private void UpdateHeader()
{
switch ( _target )
{
case ShaderGraphPlus graph:
_header.Text = "Graph Settings";
_header.Icon = "settings";
break;
case CommentNode commentNode:
_header.Text = "Comment";
_header.Icon = commentNode.DisplayInfo.Icon ?? "account_tree";
break;
case BaseNodePlus node:
_header.Text = node.DisplayInfo.Name ?? node.GetType().Name;
_header.Icon = node.DisplayInfo.Icon ?? "account_tree";
break;
case BlackboardParameter parameter:
_header.Text = parameter.DisplayInfo.Name ?? parameter.GetType().Name;
_header.Icon = parameter.DisplayInfo.Icon ?? "account_tree";
break;
case CategoryData category:
_header.Text = "Category";
_header.Icon = "folder";
break;
default:
_header.Text = "Properties";
_header.Icon = "settings";
break;
}
_header.Update();
}
private void RebuildSheet()
{
if ( _scroller is null || _target is null )
return;
var previousCanvas = _scroller.Canvas;
var nextCanvas = new Widget( _scroller )
{
Layout = Layout.Column(),
HorizontalSizeMode = SizeMode.Flexible,
VerticalSizeMode = SizeMode.CanGrow,
TranslucentBackground = true,
NoSystemBackground = true,
Visible = false
};
_sheetCanvas = nextCanvas;
try
{
var so = _target.GetSerialized();
so.OnPropertyChanged += p =>
{
PropertyUpdated?.Invoke( p );
};
_sheet = new ControlSheet();
_sheet.AddObject( so, p => PropertyFilter( p ) );
_sheetCanvas.Layout.Add( _sheet );
_sheetCanvas.Layout.AddStretchCell();
nextCanvas.AdjustSize();
}
catch
{
_sheetCanvas = previousCanvas;
nextCanvas.Destroy();
throw;
}
_scroller.UpdatesEnabled = false;
try
{
nextCanvas.Visible = true;
_scroller.Canvas = nextCanvas;
}
finally
{
_scroller.UpdatesEnabled = true;
_scroller.Update();
}
}
private void OnFilterEdited( string filter )
{
_filterText = filter;
_sheet.Clear( true );
_sheet.AddObject( _target.GetSerialized(), PropertyFilter );
_scroller.Update();
}
bool PropertyFilter( SerializedProperty property )
{
if ( property.HasAttribute<HideAttribute>() ) return false;
if ( string.IsNullOrEmpty( _filterText ) ) return true;
if ( property.Name.ToLower().Contains( _filterText.ToLower() ) ) return true;
if ( property.DisplayName.ToLower().Contains( _filterText.ToLower() ) ) return true;
if ( property.TryGetAsObject( out var obj ) )
{
if ( property.TryGetAttribute<ConditionalVisibilityAttribute>( out var conditional ) )
{
if ( conditional.TestCondition( obj ) ) return false;
}
foreach ( var childProp in obj )
{
if ( childProp.HasAttribute<HideAttribute>() ) continue;
if ( childProp.Name.ToLower().Contains( _filterText.ToLower() ) || childProp.DisplayName.ToLower().Contains( _filterText.ToLower() ) )
{
_sheet.AddRow( childProp );
}
}
}
return false;
}
}
class PropertiesHeader : Widget
{
public string Text { get; set; } = "Properties";
public string Icon { get; set; } = "settings";
public PropertiesHeader() : base( null )
{
FixedHeight = Theme.RowHeight + 2;
}
protected override void OnPaint()
{
var rect = LocalRect;
Paint.Antialiasing = true;
Paint.TextAntialiasing = true;
Paint.ClearPen();
Paint.SetBrush( Theme.SurfaceBackground );
Paint.DrawRect( rect );
var iconColor = Color.Parse( "#8E9199" ) ?? Theme.TextControl;
// Icon
if ( !string.IsNullOrEmpty( Icon ) )
{
var iconRect = new Rect( rect.Left + 4, rect.Top, 22, rect.Height );
Paint.SetPen( iconColor );
Paint.DrawIcon( iconRect, Icon, 16, TextFlag.Center );
}
// Title
var textLeft = string.IsNullOrEmpty( Icon ) ? 4f : 30f;
var textRect = new Rect( textLeft, rect.Top, rect.Width - textLeft, rect.Height );
Paint.SetPen( Theme.Text );
Paint.SetHeadingFont( 11, 440, sizeInPixels: true );
Paint.DrawText( textRect, Text, TextFlag.LeftCenter );
}
}