Code/Internal/StatefulDrawPanel.cs
using System;
using Sandbox;
using Sandbox.Rendering;
using Sandbox.UI;
namespace Goo.Internal;
internal sealed class StatefulDrawPanel : Panel, IPanelDraw, IStatefulHost, IStatefulEventHost
{
StateController? _state;
internal Action<MousePanelEvent>? _onClick;
internal Action<MousePanelEvent>? _onMouseEnter;
internal Action<MousePanelEvent>? _onMouseLeave;
internal Action<MousePanelEvent>? _onMouseDown;
internal Action<MousePanelEvent>? _onMouseUp;
internal Action<MousePanelEvent>? _onMouseMove;
internal bool _userSetPointerEvents;
internal Action? _requestRebuild;
public Action? RequestRebuild { set => _requestRebuild = value; }
internal Action<DragEvent>? _onDragStart;
internal Action<DragEvent>? _onDrag;
internal Action<DragEvent>? _onDragEnd;
internal Action<PanelEvent>? _onDragEnter;
internal Action<PanelEvent>? _onDragLeave;
internal Action<PanelEvent>? _onDrop;
bool _wantsDrag;
// User custom-draw state.
internal DrawState _drawState = DrawState.Empty;
public void ApplyStateVariants(
Color? baseBg, Color? baseFg,
Color? hoverBg, Color? activeBg, Color? focusBg,
Color? hoverFg, Color? activeFg, Color? focusFg,
int? transitionMs)
{
_state ??= new StateController(this);
_state.ApplyVariants(
baseBg, baseFg,
hoverBg, activeBg, focusBg,
hoverFg, activeFg, focusFg,
transitionMs);
}
public void ApplyEvents(in BlobEvents events)
{
_onClick = events.OnClick;
_onMouseEnter = events.OnMouseEnter;
_onMouseLeave = events.OnMouseLeave;
_onMouseDown = events.OnMouseDown;
_onMouseUp = events.OnMouseUp;
_onMouseMove = events.OnMouseMove;
_onDragStart = events.OnDragStart;
_onDrag = events.OnDrag;
_onDragEnd = events.OnDragEnd;
_onDragEnter = events.OnDragEnter;
_onDragLeave = events.OnDragLeave;
_onDrop = events.OnDrop;
_wantsDrag = events.WantsDrag;
}
public bool HasEventHandlers =>
_onClick != null || _onMouseEnter != null || _onMouseLeave != null ||
_onMouseDown != null || _onMouseUp != null || _onMouseMove != null ||
_onDragStart != null || _onDrag != null || _onDragEnd != null ||
_onDragEnter != null || _onDragLeave != null || _onDrop != null;
public bool UserSetPointerEvents
{
get => _userSetPointerEvents;
set => _userSetPointerEvents = value;
}
// IPanelDraw paint pass for the user Material recipe and Draw callback. BackgroundColor goes through the engine's batched background path instead.
public void Draw(CommandList cl)
{
var rect = Box.Rect;
if (_drawState.Material is Material userMat)
{
if (!_drawState.Uniforms.IsDefaultOrEmpty)
foreach (var u in _drawState.Uniforms)
ApplyUniform(cl, u);
cl.DrawQuad(rect, userMat, Color.White);
}
_drawState.Draw?.Invoke(cl, rect);
}
static void ApplyUniform(CommandList cl, in UniformValue u)
{
switch (u.Kind)
{
case UniformKind.Color: cl.Attributes.Set(u.Name, u.ColorValue); break;
case UniformKind.Float: cl.Attributes.Set(u.Name, u.FloatValue); break;
case UniformKind.Int: cl.Attributes.Set(u.Name, u.IntValue); break;
case UniformKind.Bool: cl.Attributes.Set(u.Name, u.BoolValue ? 1 : 0); break;
case UniformKind.Vec2: cl.Attributes.Set(u.Name, new Vector2(u.VecValue.x, u.VecValue.y)); break;
case UniformKind.Vec3: cl.Attributes.Set(u.Name, new Vector3(u.VecValue.x, u.VecValue.y, u.VecValue.z)); break;
case UniformKind.Vec4: cl.Attributes.Set(u.Name, u.VecValue); break;
case UniformKind.Texture: if (u.TextureValue is not null) cl.Attributes.Set(u.Name, u.TextureValue); break;
}
}
protected override void OnClick(MousePanelEvent e)
{
base.OnClick(e);
EventDispatch.Fire(_onClick, e, _requestRebuild);
}
protected override void OnRightClick(MousePanelEvent e)
{
base.OnRightClick(e);
EventDispatch.Fire(_onClick, e, _requestRebuild);
}
protected override void OnMiddleClick(MousePanelEvent e)
{
base.OnMiddleClick(e);
EventDispatch.Fire(_onClick, e, _requestRebuild);
}
protected override void OnMouseOver(MousePanelEvent e)
{
base.OnMouseOver(e);
EventDispatch.Fire(_onMouseEnter, e, _requestRebuild);
}
protected override void OnMouseOut(MousePanelEvent e)
{
base.OnMouseOut(e);
EventDispatch.Fire(_onMouseLeave, e, _requestRebuild);
}
protected override void OnMouseDown(MousePanelEvent e)
{
base.OnMouseDown(e);
EventDispatch.Fire(_onMouseDown, e, _requestRebuild);
}
protected override void OnMouseUp(MousePanelEvent e)
{
base.OnMouseUp(e);
EventDispatch.Fire(_onMouseUp, e, _requestRebuild);
}
protected override void OnMouseMove(MousePanelEvent e)
{
base.OnMouseMove(e);
EventDispatch.Fire(_onMouseMove, e, _requestRebuild);
}
public override bool WantsDrag => _wantsDrag;
protected override void OnDragStart( DragEvent e ) => _onDragStart?.Invoke( e );
protected override void OnDrag( DragEvent e ) => _onDrag?.Invoke( e );
protected override void OnDragEnd( DragEvent e ) => _onDragEnd?.Invoke( e );
protected override void OnDragEnter( PanelEvent e )
{
base.OnDragEnter( e );
_onDragEnter?.Invoke( e );
}
protected override void OnDragLeave( PanelEvent e )
{
base.OnDragLeave( e );
_onDragLeave?.Invoke( e );
}
protected override void OnDrop( PanelEvent e )
{
base.OnDrop( e );
_onDrop?.Invoke( e );
}
}