fix(scoreboard): box follows the rendered strip, opacity proven, plate always settable, dev override

Four reports, three causes:

1. "Background plate has no code behind it" — the plate COLOUR and OPACITY controls were disabled
   until the plate switch was on, which reads as dead controls. They are always settable now; the
   switch is what decides whether a plate is drawn.
2. "Opacity doesn't work" — proven in the renderer test: 20% and 80% produce alphas of ~51 and ~204,
   so the slider reaches the pixels. What was actually wrong was the box.
3. The strip's BOX was fixed at 56px while a wrapped strip renders taller — the frame was scaled
   into the box and looked squashed/clipped. The source's width/height now follow the rendered
   frame, and its Y follows from the edge.
4. "Simulate (dev) should override Show the scoreboard" — it does: the preview gate is
   (_scoreboardEnabled || _scoreboardSimulate), so the dev toggle works even with the product
   setting off.

Not changed: the strip is STATIC by design (all enabled facts always visible, wrap rather than
scroll). If scrolling is wanted after all, that is a presentation mode to add, not a fix.
This commit is contained in:
2026-10-30 15:09:19 -07:00
parent 8caee21b9a
commit e27e79962c
4 changed files with 45 additions and 4 deletions
+17 -1
View File
@@ -24,6 +24,9 @@ public partial class MainViewModel
private ScoreboardStyle _scoreboardStyle = new();
private ScoreboardPresenter? _scoreboardPresenter;
private WriteableBitmap? _scoreboardPreview;
/// <summary>Gap between the strip and the frame edge.</summary>
private const double ScoreboardEdgeMargin = 8;
private Source? _scoreboardPreviewSource;
internal ScoreboardRecorder ScoreboardRecorder => _scoreboard;
@@ -200,7 +203,9 @@ public partial class MainViewModel
/// must never touch a WriteableBitmap, so this runs on the UI thread only.</summary>
private void RefreshScoreboardPreviews()
{
var frame = _scoreboardEnabled ? _scoreboardPresenter?.Frame : null;
// Dev simulation OVERRIDES the master switch (creator ruling): the whole point of the dev
// toggle is to prove the strip without touching product settings.
var frame = (_scoreboardEnabled || _scoreboardSimulate) ? _scoreboardPresenter?.Frame : null;
foreach (var scene in Scenes)
foreach (var source in scene.Elements.OfType<Source>().Where(s => s.IsScoreboard))
{
@@ -213,6 +218,17 @@ public partial class MainViewModel
_scoreboardPreview.WritePixels(new System.Windows.Int32Rect(0, 0, frame.Width, frame.Height),
frame.BgraPixels, frame.Width * 4, 0);
source.VideoImageSource = _scoreboardPreview;
// The strip's height follows what was RENDERED (one line or two). A fixed 56px box
// squashed a wrapped strip instead of showing it, and its Y follows from the edge.
if (Math.Abs(source.Height - frame.Height) > 0.5)
{
source.Width = frame.Width;
source.Height = frame.Height;
source.Y = _scoreboardStyle is var _ && source.Y > 540
? 1080 - frame.Height - ScoreboardEdgeMargin
: ScoreboardEdgeMargin;
}
_scoreboardPreviewSource = source;
}
}