using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Theriapolis.Game.CodexUI.Core; namespace Theriapolis.Game.CodexUI.Widgets; /// /// Single-child container that paints a parchment fill and a 1-px ink rule /// border. The review-step summary blocks and the aside container both use /// this; for borderless wrappers (e.g. the page's main column) just nest in /// a instead. /// public sealed class CodexPanel : CodexWidget { public CodexWidget? Child { get; set; } public Color BackgroundColor { get; set; } = CodexColors.Bg2; public Color BorderColor { get; set; } = CodexColors.Rule; public bool Bordered { get; set; } = true; public Thickness Inset { get; set; } = new(18, 18, 20, 18); private readonly CodexAtlas _atlas; public CodexPanel(CodexAtlas atlas, CodexWidget? child = null) { _atlas = atlas; Child = child; if (child is not null) child.Parent = this; } protected override Point MeasureCore(Point available) { if (Child is null) return new Point(Inset.HorizontalSum(), Inset.VerticalSum()); var inner = new Point(available.X - Inset.HorizontalSum(), available.Y - Inset.VerticalSum()); var s = Child.Measure(inner); return new Point(s.X + Inset.HorizontalSum(), s.Y + Inset.VerticalSum()); } protected override void ArrangeCore(Rectangle bounds) { Child?.Arrange(new Rectangle( bounds.X + Inset.Left, bounds.Y + Inset.Top, bounds.Width - Inset.HorizontalSum(), bounds.Height - Inset.VerticalSum())); } public override void Update(GameTime gt, CodexInput input) => Child?.Update(gt, input); public override void Draw(SpriteBatch sb, GameTime gt) { sb.Draw(_atlas.Pixel, Bounds, BackgroundColor); if (Bordered) { sb.Draw(_atlas.Pixel, new Rectangle(Bounds.X, Bounds.Y, Bounds.Width, 1), BorderColor); sb.Draw(_atlas.Pixel, new Rectangle(Bounds.X, Bounds.Bottom - 1, Bounds.Width, 1), BorderColor); sb.Draw(_atlas.Pixel, new Rectangle(Bounds.X, Bounds.Y, 1, Bounds.Height), BorderColor); sb.Draw(_atlas.Pixel, new Rectangle(Bounds.Right - 1, Bounds.Y, 1, Bounds.Height), BorderColor); } Child?.Draw(sb, gt); } }