using Godot; using Theriapolis.GodotHost.UI.Widgets; namespace Theriapolis.GodotHost.UI; /// /// M5 kitchen-sink. Renders every primitive from the codex design system /// (single Dark theme — Parchment and Blood dropped from scope per port /// plan §10) so we can eyeball parity against screenshots of the React /// prototype. Launch via: /// godot --path Theriapolis.Godot --codex-test /// public partial class KitchenSink : Control { private Panel _root = null!; private CodexStepper _stepper = null!; public override void _Ready() { AnchorRight = 1f; AnchorBottom = 1f; OffsetRight = 0; OffsetBottom = 0; _root = new Panel { ThemeTypeVariation = "Panel" }; _root.AnchorRight = 1f; _root.AnchorBottom = 1f; AddChild(_root); ApplyTheme(); BuildContent(); } private void ApplyTheme() { _root.Theme = CodexTheme.Build(); // The root Panel's stylebox covers its rect; fill the *outer* // viewport (which Godot draws with its default clear colour) so // screenshots don't show engine grey along any edge. RenderingServer.SetDefaultClearColor(CodexPalette.Dark.BgDeep); } private void BuildContent() { var margin = new MarginContainer(); margin.AddThemeConstantOverride("margin_left", 36); margin.AddThemeConstantOverride("margin_right", 36); margin.AddThemeConstantOverride("margin_top", 28); margin.AddThemeConstantOverride("margin_bottom", 28); margin.AnchorRight = 1f; margin.AnchorBottom = 1f; _root.AddChild(margin); var scroll = new ScrollContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill }; margin.AddChild(scroll); var col = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill, }; col.AddThemeConstantOverride("separation", 24); scroll.AddChild(col); BuildHeader(col); BuildStepperSection(col); BuildButtonsSection(col); BuildInputsSection(col); BuildCardSection(col); BuildPopoverSection(col); } private void BuildHeader(VBoxContainer col) { var h = new HBoxContainer(); col.AddChild(h); var titleCol = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill }; h.AddChild(titleCol); titleCol.AddChild(new Label { Text = "THERIAPOLIS · CODEX OF BECOMING", ThemeTypeVariation = "CodexTitle" }); titleCol.AddChild(new Label { Text = "Kitchen sink — every primitive, three themes", ThemeTypeVariation = "Eyebrow" }); var meta = new Label { Text = "M5 · DESIGN AUDIT", ThemeTypeVariation = "Meta" }; h.AddChild(meta); } private void BuildStepperSection(VBoxContainer col) { var section = MakeSection(col, "STEPPER"); _stepper = new CodexStepper(); _stepper.SizeFlagsHorizontal = SizeFlags.ExpandFill; section.AddChild(_stepper); _stepper.SetSteps( new[] { "Clade", "Species", "Calling", "Subclass", "History", "Abilities", "Skills", "Sign" }, new[] { CodexStepper.StepState.Complete, CodexStepper.StepState.Complete, CodexStepper.StepState.Complete, CodexStepper.StepState.Active, CodexStepper.StepState.Pending, CodexStepper.StepState.Locked, CodexStepper.StepState.Locked, CodexStepper.StepState.Locked, }); _stepper.StepClicked += (int idx) => GD.Print($"[kitchen-sink] Stepper clicked index={idx}"); } private void BuildButtonsSection(VBoxContainer col) { var section = MakeSection(col, "BUTTONS"); var row = new HBoxContainer(); row.AddThemeConstantOverride("separation", 12); section.AddChild(row); row.AddChild(new Button { Text = "Default" }); row.AddChild(new Button { Text = "Primary", ThemeTypeVariation = "PrimaryButton" }); row.AddChild(new Button { Text = "Ghost", ThemeTypeVariation = "GhostButton" }); var disabled = new Button { Text = "Disabled", Disabled = true }; row.AddChild(disabled); } private void BuildInputsSection(VBoxContainer col) { var section = MakeSection(col, "INPUTS"); var row = new HBoxContainer(); row.AddThemeConstantOverride("separation", 12); section.AddChild(row); var le = new LineEdit { PlaceholderText = "Enter your name...", CustomMinimumSize = new Vector2(280, 0), }; row.AddChild(le); row.AddChild(new CheckBox { Text = "Toggle option" }); } private void BuildCardSection(VBoxContainer col) { var section = MakeSection(col, "CARDS"); var grid = new HBoxContainer(); grid.AddThemeConstantOverride("separation", CodexSpacing.Gap); section.AddChild(grid); AddCard(grid, "Canidae", "Predator · medium", "Strong-jawed pack hunters of the inland forest.", selected: false); AddCard(grid, "Felidae", "Predator · medium", "Solitary stalkers, claw-tipped and sharp of ear.", selected: true); AddCard(grid, "Mustelidae", "Predator · small", "Burrowers and threadkillers of the river edges.", selected: false); } private void AddCard(HBoxContainer parent, string name, string meta, string body, bool selected) { var panel = new PanelContainer { ThemeTypeVariation = "Card", CustomMinimumSize = new Vector2(240, 0), }; if (selected && _root.Theme is not null && _root.Theme.HasStylebox("panel_selected", "Card")) { var box = _root.Theme.GetStylebox("panel_selected", "Card"); panel.AddThemeStyleboxOverride("panel", box); } var v = new VBoxContainer(); v.AddThemeConstantOverride("separation", 6); panel.AddChild(v); v.AddChild(new Label { Text = name, ThemeTypeVariation = "CardName" }); v.AddChild(new Label { Text = meta.ToUpperInvariant(), ThemeTypeVariation = "CardMeta" }); v.AddChild(new Label { Text = body, ThemeTypeVariation = "CardBody", AutowrapMode = TextServer.AutowrapMode.WordSmart, CustomMinimumSize = new Vector2(220, 0), }); parent.AddChild(panel); } private void BuildPopoverSection(VBoxContainer col) { var section = MakeSection(col, "TRAIT POPOVERS · HOVER"); var row = new HBoxContainer(); row.AddThemeConstantOverride("separation", 18); section.AddChild(row); row.AddChild(new CodexPopover { TriggerText = "Pack Tactics", Title = "Pack Tactics", Tag = "active", Description = "Once per turn, when an ally is adjacent to your target, gain advantage on the attack.", }); row.AddChild(new CodexPopover { TriggerText = "Glass Bones", Title = "Glass Bones", Description = "Critical hits against you deal an extra 1d6 damage.", Detriment = true, }); row.AddChild(new CodexPopover { TriggerText = "Athletics", Title = "Athletics", Tag = "STR", Description = "Climbs, jumps, swims, and brute physical contests.", }); row.AddChild(new CodexPopover { TriggerText = "+2", Title = "STR modifier", Description = "+1 from Canidae · +1 from Wolf", }); } private static VBoxContainer MakeSection(VBoxContainer col, string title) { var box = new VBoxContainer(); box.AddThemeConstantOverride("separation", 8); col.AddChild(box); box.AddChild(new Label { Text = title, ThemeTypeVariation = "Eyebrow" }); var inner = new VBoxContainer(); inner.AddThemeConstantOverride("separation", 8); box.AddChild(inner); return inner; } }