Code/Demos/BeatPad/PadBlob.cs
using System;
using Goo;
using Sandbox.UI;
using static Sandbox.BeatPadTokens;
namespace Sandbox;
// Pure presenter for one pad. All animated values arrive as props; no state lives here.
// Lit (0=paper, 1=hot) drives fill; PressOffset (0..4px) translates the face and
// collapses the shadow; BounceScale (~1.0) is the release overshoot.
internal static class PadBlob
{
public readonly record struct Props(
int Index,
string Label,
float Lit,
float PressOffset,
float BounceScale,
bool Hovered,
Action<MousePanelEvent> OnDown,
Action<MousePanelEvent> OnUp,
Action<MousePanelEvent> OnEnter,
Action<MousePanelEvent> OnLeave);
public static Container Build(Props p)
{
float off = p.PressOffset;
Color face = Color.Lerp(Paper, Hot, p.Lit);
Color shadowColor = p.Hovered ? Hot : Ink;
return new Container
{
Key = $"pad-{p.Index}",
Width = PadSize,
Height = PadSize,
Position = PositionMode.Relative,
OnMouseDown = p.OnDown,
OnMouseUp = p.OnUp,
OnMouseEnter = p.OnEnter,
OnMouseLeave = p.OnLeave,
Children =
{
new Container
{
Key = "shadow",
Position = PositionMode.Absolute,
Left = PadShadow, Top = PadShadow,
Width = Length.Percent(100), Height = Length.Percent(100),
BackgroundColor = shadowColor,
BorderRadius = PadRadius,
PointerEvents = PointerEvents.None,
},
new Container
{
Key = "face",
Position = PositionMode.Absolute,
Left = 0, Top = 0,
Width = Length.Percent(100), Height = Length.Percent(100),
BackgroundColor = face,
BorderRadius = PadRadius,
BorderColor = Ink,
BorderWidth = OutlineWidth,
JustifyContent = Justify.Center,
AlignItems = Align.Center,
Transform = Goo.PanelTransform.Translate(off, off).Scale(p.BounceScale),
PointerEvents = PointerEvents.None,
Children =
{
new Text(p.Label)
{
FontSize = 11f,
FontColor = Ink,
FontFamily = FontLabel,
TextAlign = TextAlign.Center,
},
},
},
},
};
}
}