Editor/ShaderGraphPlus/Nodes Test/CustomCodeNodeUI.cs
using Editor;
namespace ShaderGraphPlus.Nodes;
public sealed class CustomCodeNodeUI : NodeUI
{
private CustonFunctionNodeUITest CustomCodeNode => Node as CustonFunctionNodeUITest;
protected override float TitleHeight => 40.0f;
[Flags]
private enum SizeDirection
{
None = 0,
Top = 1 << 0,
Bottom = 1 << 1,
Left = 1 << 2,
Right = 1 << 3
}
private bool _dragging;
private bool _resizing;
private Vector2 _offset;
private Vector2 _minSize => new( 64.0f, 64.0f );
private Vector2 _maxSize => new( 10000.0f, 10000.0f );
private Vector2 _dragSize => new( 16.0f, 16.0f );
private SizeDirection _direction;
private RealTimeSince _lastMouseDown;
private string _lastTitle;
private string _lastDescription;
private bool _didSelectDrag;
public CustomCodeNodeUI( GraphView graph, CustonFunctionNodeUITest customFunctionNode ) : base( graph, customFunctionNode )
{
HoverEvents = true;
Selectable = true;
Movable = true;
}
protected override void OnPaint()
{
var alphaMultiplier = 0.6f;
var comment = CustomCodeNode;
var color = Color.Gray;
var rect = new Rect( 0, Size );
UpdateTooltip();
PrimaryColor = color.Darken( 0.1f ).Desaturate( 0.4f );
if ( Paint.HasSelected )
PrimaryColor = color.Darken( 0.1f ).Desaturate( 0.3f );
else if ( Paint.HasMouseOver )
PrimaryColor = color.Darken( 0.1f ).Desaturate( 0.35f );
Paint.SetPen( PrimaryColor, 0 );
Paint.SetBrush( PrimaryColor.Darken( 0.7f ).WithAlpha( 0.8f * alphaMultiplier ) );
Paint.DrawRect( rect, 5f );
//Paint.ClearPen();
//Paint.SetBrush( PrimaryColor.WithAlpha( 0.05f * alphaMultiplier ) );
//Paint.DrawRect( new Rect( 0f, TitleHeight, rect.Width - 1, rect.Height - TitleHeight ), 2 );
var boarderSize = 8.0f;
var codeViewRect = new Rect( 0f, TitleHeight, rect.Width - 1, rect.Height - TitleHeight ).Shrink( boarderSize );
var codeViewMarginRect = codeViewRect.Shrink( 4 );
Paint.ClearPen();
Paint.SetBrush( Theme.ControlBackground );
Paint.DrawRect( codeViewRect, 5f );
// Highlight stuff
//if ( Paint.HasSelected )
//{
// Paint.SetPen( color.Lighten( 0.1f ).Desaturate( 0.3f ).WithAlpha( 1f * alphaMultiplier ), 2f );
// Paint.ClearBrush();
// Paint.DrawRect( rect.Shrink( 1f ), 4.0f );
//}
//else if ( Paint.HasMouseOver )
//{
// Paint.SetPen( color.Lighten( 0.1f ).Desaturate( 0.3f ).WithAlpha( 0.4f * alphaMultiplier ), 2f );
// Paint.ClearBrush();
// Paint.DrawRect( rect.Shrink( 1f ), 4.0f );
//}
{
rect = new Rect( rect.Position, new Vector2( rect.Width, TitleHeight ) );
//Paint.ClearPen();
//Paint.SetBrush( CustomCodeNode.HeaderColor1 );
//Paint.SetBrushLinear( rect.Left, rect.Right, CustomCodeNode.HeaderColor1, CustomCodeNode.HeaderColor2 );
//Paint.DrawRect( rect, 5f );
//if ( DisplayInfo.Icon != null )
//{
// Paint.SetPen( PrimaryColor.WithAlpha( 0.7f ) );
// Paint.DrawIcon( rect.Shrink( 4f ), DisplayInfo.Icon, 19f, TextFlag.LeftCenter );
// rect.Left += 24f;
//}
// Title
var title = CustomCodeNode.MyName;
Paint.SetDefaultFont( 11f, 500 );
Paint.SetPen( PrimaryColor );
Paint.DrawText( rect.Shrink( 5f, 0f ), title, TextFlag.LeftCenter );
// Description
if ( !string.IsNullOrEmpty( comment.Body ) )
{
rect.Left = 0f;
rect.Top += TitleHeight + 8f;
var trimmedDesc = comment.Body;
Paint.SetPen( Color.White );
Paint.SetFont( "Cascadia Code", 8 );
Paint.DrawText( rect.Shrink( 16f, 0f ), trimmedDesc, TextFlag.WordWrap | TextFlag.DontClip | TextFlag.LeftTop );
}
}
}
protected override void OnMousePressed( GraphicsMouseEvent e )
{
if ( e.LeftMouseButton && !_resizing )
{
UpdateDirection( e.LocalPosition );
if ( _direction != SizeDirection.None )
{
_resizing = true;
e.Accepted = true;
}
}
if ( _resizing )
{
e.Accepted = true;
}
if ( e.LeftMouseButton && !Selected && !_resizing )
{
var nodes = Graph.Items.OfType<NodeUI>();
foreach ( var n in nodes )
{
// Only select this node if it is fully inside our box.
if ( SceneRect.IsInside( n.SceneRect, true ) )
n.Selected = true;
else if ( !e.HasCtrl )
n.Selected = false;
}
_didSelectDrag = true;
e.Accepted = true;
Selected = true;
}
_lastMouseDown = 0f;
_dragging = true;
base.OnMousePressed( e );
}
protected override void OnMouseMove( GraphicsMouseEvent e )
{
if ( _resizing )
{
UpdateResize( e );
e.Accepted = true;
}
if ( _dragging )
{
}
base.OnMouseMove( e );
}
protected override void OnMouseReleased( GraphicsMouseEvent e )
{
var wasResizing = _resizing;
if ( _resizing )
{
e.Accepted = true;
Graph?.PushUndo( "Resize Comment" );
UpdateResize( e );
_resizing = false;
CustomCodeNode.ExpandSize = Size;
CustomCodeNode.Position = Position;
ForceUpdate();
Graph?.PushRedo();
}
if ( e.LeftMouseButton && _didSelectDrag && _lastMouseDown < 0.1f && !e.HasCtrl && !wasResizing )
{
e.Accepted = true;
}
_didSelectDrag = false;
_dragging = false;
base.OnMouseReleased( e );
}
protected override void OnHoverMove( GraphicsHoverEvent e )
{
base.OnHoverMove( e );
UpdateDirection( e.LocalPosition );
}
protected override void OnHoverEnter( GraphicsHoverEvent e )
{
base.OnHoverEnter( e );
UpdateDirection( e.LocalPosition );
}
protected override void OnHoverLeave( GraphicsHoverEvent e )
{
base.OnHoverLeave( e );
_direction = SizeDirection.None;
Cursor = CursorShape.SizeAll;
}
protected override void Layout()
{
Size = CustomCodeNode.ExpandSize.Clamp( _minSize, _maxSize );
}
protected override void OnPositionChanged()
{
if ( _resizing ) return;
base.OnPositionChanged();
}
public void ForceUpdate()
{
PrepareGeometryChange();
Update();
}
private void UpdateDirection( Vector2 position )
{
_direction = SizeDirection.None;
Cursor = CursorShape.SizeAll;
if ( position.x <= _dragSize.x )
{
_direction |= SizeDirection.Left;
_offset.x = position.x;
}
else if ( position.x >= Size.x - _dragSize.x )
{
_direction |= SizeDirection.Right;
_offset.x = position.x - Size.x;
}
if ( position.y <= _dragSize.y )
{
_direction |= SizeDirection.Top;
_offset.y = position.y;
Cursor = _direction.HasFlag( SizeDirection.Left ) ? CursorShape.SizeFDiag :
_direction.HasFlag( SizeDirection.Right ) ? CursorShape.SizeBDiag : CursorShape.SizeV;
}
else if ( position.y >= Size.y - _dragSize.y )
{
_direction |= SizeDirection.Bottom;
_offset.y = position.y - Size.y;
Cursor = _direction.HasFlag( SizeDirection.Left ) ? CursorShape.SizeBDiag :
_direction.HasFlag( SizeDirection.Right ) ? CursorShape.SizeFDiag : CursorShape.SizeV;
}
else if ( _direction.HasFlag( SizeDirection.Left ) || _direction.HasFlag( SizeDirection.Right ) )
{
Cursor = CursorShape.SizeH;
}
else
{
Cursor = CursorShape.SizeAll;
}
}
private Rect ResizeTop( Rect rect, float position )
{
rect.Top = position;
var size = rect.Bottom - rect.Top;
size -= size.Clamp( _minSize.y, _maxSize.y );
rect.Top += size;
return rect;
}
private Rect ResizeLeft( Rect rect, float position )
{
rect.Left = position;
var size = rect.Right - rect.Left;
size -= size.Clamp( _minSize.x, _maxSize.x );
rect.Left += size;
return rect;
}
private Rect ResizeBottom( Rect rect, float position )
{
rect.Bottom = position;
var size = rect.Bottom - rect.Top;
size -= size.Clamp( _minSize.y, _maxSize.y );
rect.Bottom -= size;
return rect;
}
private Rect ResizeRight( Rect rect, float position )
{
rect.Right = position;
var size = rect.Right - rect.Left;
size -= size.Clamp( _minSize.x, _maxSize.x );
rect.Right -= size;
return rect;
}
private void UpdateTooltip()
{
if ( CustomCodeNode.MyName == _lastTitle && CustomCodeNode.Body == _lastDescription ) return;
string name = $"<span style=\"font-size: 16px;font-weight: 900;\">{CustomCodeNode.MyName}</span>";
string description = CustomCodeNode.Body;
ToolTip = $"{name}<br>{description}";
_lastDescription = CustomCodeNode.Body;
_lastTitle = CustomCodeNode.MyName;
}
private void UpdateResize( GraphicsMouseEvent e )
{
if ( !_resizing ) return;
var position = (e.ScenePosition - _offset).SnapToGrid( Graph.GridSize );
var rect = SceneRect;
if ( _direction.HasFlag( SizeDirection.Left ) )
rect = ResizeLeft( rect, position.x );
else if ( _direction.HasFlag( SizeDirection.Right ) )
rect = ResizeRight( rect, position.x );
if ( _direction.HasFlag( SizeDirection.Top ) )
rect = ResizeTop( rect, position.y );
else if ( _direction.HasFlag( SizeDirection.Bottom ) )
rect = ResizeBottom( rect, position.y );
SceneRect = rect;
ForceUpdate();
}
}