Editor/ShaderGraphPlus/Widgets/ControlWidgets/EnumerationEditorControlWidgets.cs
using Editor;
using static ShaderGraphPlus.ShaderTemplate;
namespace ShaderGraphPlus;
internal abstract class CustomEnumControlWidget : ControlWidget
{
protected ShaderGraphPlus _graph;
EnumDescription _enumDesc;
PopupWidget _menu;
public override bool IsControlActive => base.IsControlActive || _menu.IsValid();
public override bool IsControlButton => true;
public override bool IsControlHovered => base.IsControlHovered || _menu.IsValid();
public CustomEnumControlWidget( SerializedProperty property ) : base( property )
{
_graph = property.Parent?.Targets?.FirstOrDefault() as ShaderGraphPlus;
var propertyType = property.PropertyType;
Cursor = CursorShape.Finger;
Layout = Layout.Row();
Layout.Spacing = 2;
_enumDesc = EditorTypeLibrary.GetEnumDescription( propertyType );
}
protected abstract bool IsEntrySupported( EnumDescription.Entry entry );
private bool IsNoneSupported()
{
var enumEntryCount = _enumDesc.Count();
var notSupportedCount = 0;
foreach ( var o in _enumDesc )
{
if ( !IsEntrySupported( o ) )
{
notSupportedCount++;
continue;
}
}
return notSupportedCount == _enumDesc.Count();
}
protected override void PaintControl()
{
if ( _enumDesc is null )
return;
// Auto-correct if current value is not supported
_graph?.ValidateShaderTypeInfo();
var value = SerializedProperty.GetValue<long>( 0 );
var color = IsControlHovered ? Theme.Blue : Theme.TextControl;
var rect = LocalRect.Shrink( 8, 0 );
var e = _enumDesc.GetEntry( value );
if ( !string.IsNullOrEmpty( e.Icon ) )
{
Paint.SetPen( color.WithAlpha( 0.5f ) );
var i = Paint.DrawIcon( rect, e.Icon, 16, TextFlag.LeftCenter );
rect.Left += i.Width + 8;
}
Paint.SetPen( color );
Paint.DrawText( rect, e.Title ?? "Unset", TextFlag.LeftCenter );
Paint.DrawIcon( rect, "Arrow_Drop_Down", 17, TextFlag.RightCenter );
}
protected override void OnMouseClick( MouseEvent e )
{
if ( IsControlDisabled ) return;
if ( e.LeftMouseButton && !_menu.IsValid() && !IsNoneSupported() )
{
OpenMenu();
}
}
protected void ToggleValue( EnumDescription.Entry e )
{
SerializedProperty.SetValue( e.IntegerValue );
}
void OpenMenu()
{
if ( _enumDesc is null )
return;
// Auto-correct if current value is not supported
_graph?.ValidateShaderTypeInfo();
_menu = new PopupWidget( null );
_menu.Layout = Layout.Column();
var menuWidth = ScreenRect.Width;
_menu.MinimumWidth = menuWidth;
_menu.MaximumWidth = menuWidth;
var scroller = _menu.Layout.Add( new ScrollArea( this ), 1 );
scroller.Canvas = new Widget( scroller )
{
Layout = Layout.Column(),
VerticalSizeMode = SizeMode.CanGrow | SizeMode.Expand,
MaximumWidth = menuWidth
};
foreach ( var entry in _enumDesc )
{
if ( !IsEntrySupported( entry ) )
continue;
var b = scroller.Canvas.Layout.Add( new EnumMenuOption( entry, SerializedProperty ) );
b.MouseLeftPress = () =>
{
ToggleValue( entry );
_menu.Update();
_menu.Close();
};
}
_menu.Position = ScreenRect.BottomLeft;
_menu.Visible = true;
_menu.AdjustSize();
_menu.ConstrainToScreen();
_menu.OnPaintOverride = () =>
{
Paint.SetBrushAndPen( Theme.ControlBackground );
Paint.DrawRect( Paint.LocalRect, 0 );
return true;
};
}
}
/// <summary>
/// Custom enum editor for BlendMode that filters options based on template/shading model features
/// </summary>
[CustomEditor( typeof( BlendMode ) )]
internal sealed class BlendModeControlWidget : CustomEnumControlWidget
{
public BlendModeControlWidget( SerializedProperty property ) : base( property )
{
}
protected override bool IsEntrySupported( EnumDescription.Entry entry )
{
if ( _graph is null )
return entry.Browsable;
if ( !entry.Browsable )
return false;
var sti = _graph.ShaderTypeInfo;
return entry.Name switch
{
nameof( BlendMode.Opaque ) => sti.HasSupport( SupportsOpaqueBlend ),
nameof( BlendMode.Masked ) => sti.HasSupport( SupportsMaskedBlend ),
nameof( BlendMode.Translucent ) => sti.HasSupport( SupportsTranslucentBlend ),
_ => true
};
}
}
file class EnumMenuOption : Widget
{
private EnumDescription.Entry _info;
private SerializedProperty _property;
public EnumMenuOption( EnumDescription.Entry e, SerializedProperty p ) : base( null )
{
_info = e;
_property = p;
Layout = Layout.Row();
Layout.Margin = 8;
VerticalSizeMode = SizeMode.CanGrow;
if ( !string.IsNullOrWhiteSpace( e.Icon ) )
{
Layout.Add( new IconButton( e.Icon ) { Background = Color.Transparent, TransparentForMouseEvents = true, IconSize = 18 } );
}
Layout.AddSpacingCell( 8 );
var c = Layout.AddColumn();
var title = c.Add( new Label( e.Title ) );
title.SetStyles( $"font-size: 12px; font-weight: bold; font-family: {Theme.DefaultFont}; color: white;" );
if ( !string.IsNullOrWhiteSpace( e.Description ) )
{
var desc = c.Add( new Label( e.Description.Trim( '\n', '\r', '\t', ' ' ) ) );
desc.WordWrap = true;
desc.MinimumHeight = 1;
desc.VerticalSizeMode = SizeMode.CanGrow;
}
}
bool HasValue()
{
var value = _property.GetValue<long>( 0 );
return value == _info.IntegerValue;
}
protected override void OnPaint()
{
if ( Paint.HasMouseOver || HasValue() )
{
Paint.SetBrushAndPen( Theme.Blue.WithAlpha( HasValue() ? 0.3f : 0.1f ) );
Paint.DrawRect( LocalRect.Shrink( 2 ), 2 );
}
}
}