using System.Windows; namespace ytLive.Models; /// /// The vertical (9:16) tier's camera rules — TASK 57, the "vv" feature. /// /// The vertical tier is a centred band crop of the SAME 1920×1080 master the /// 16:9 tiers use, so a camera placed for 16:9 lands outside the cropped /// window and vanishes from the vertical output. The vertical tier therefore /// keeps its OWN placement per scene: a small tile inside the band, snapped to /// one of six spots — the band splits into a top and a bottom half, each with /// a left, a centre and a right slot. /// /// Geometry only: the preview and the compositor both read the element's own /// X/Y/W/H + ClipShape, so the placement is resolved by swapping those values /// when the tier changes. No render-path change. /// public static class VerticalCameraLayout { /// The vertical tier's camera tile over the master frame — /// 270×152 master px = 480×270 in the 1080×1920 output. public const double TileWidth = 270; public const double TileHeight = 152; /// How far the tile keeps from the band's outer edge — the app's /// own placement margin (32 master px) used by the default webcam spot. public const double Inset = 32; /// True for the portrait tier (the vertical 1080×1920 one). public static bool IsVerticalTier(QualityOption quality) => quality.Height > quality.Width; /// The half of the band a tile lives in — top or bottom. public static Rect AreaFor(Rect band, bool bottom) => new(band.Left, bottom ? band.Top + band.Height / 2 : band.Top, band.Width, band.Height / 2); /// The largest a camera may be inside the band: one whole area. public static (double Width, double Height) MaxSizeFor(Rect band) => (band.Width, band.Height / 2); /// /// The spot a tile snaps to: the area (top/bottom) and the column /// (left/centre/right) its centre falls in, then the tile's top-left for /// that spot — inset from the band's outer edge, and never outside the band /// (a tile wider than the inset eats it). /// public static (double X, double Y) SpotFor(Rect band, double width, double height, double centreX, double centreY) { var bottom = centreY >= band.Top + band.Height / 2; var area = AreaFor(band, bottom); var third = area.Width / 3; double x; if (centreX < area.Left + third) x = area.Left + Inset; else if (centreX < area.Left + 2 * third) x = area.Left + (area.Width - width) / 2; else x = area.Right - Inset - width; var y = bottom ? area.Bottom - Inset - height : area.Top + Inset; x = Math.Clamp(x, band.Left, Math.Max(band.Left, band.Right - width)); y = Math.Clamp(y, band.Top, Math.Max(band.Top, band.Bottom - height)); return (x, y); } /// The default tile spot: the bottom-right corner of the band — /// the same corner the 16:9 default webcam placement uses. public static (double X, double Y) DefaultSpot(Rect band, double width, double height) => SpotFor(band, width, height, band.Right, band.Bottom); }