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:
@@ -502,9 +502,8 @@
|
||||
IsChecked="{Binding ScoreboardBackgroundEnabled, Mode=TwoWay}"/>
|
||||
<ComboBox Style="{StaticResource YtComboBox}" Height="24" FontSize="11" Margin="10,0,0,6"
|
||||
ItemsSource="{Binding ScoreboardColorOptions}" DisplayMemberPath="Name"
|
||||
SelectedValuePath="Hex" SelectedValue="{Binding ScoreboardBackgroundColor, Mode=TwoWay}"
|
||||
IsEnabled="{Binding ScoreboardBackgroundEnabled}"/>
|
||||
<DockPanel Margin="10,0,0,6" IsEnabled="{Binding ScoreboardBackgroundEnabled}">
|
||||
SelectedValuePath="Hex" SelectedValue="{Binding ScoreboardBackgroundColor, Mode=TwoWay}"/>
|
||||
<DockPanel Margin="10,0,0,6">
|
||||
<TextBlock DockPanel.Dock="Left" Text="Opacity" Foreground="{StaticResource Brush.OnSurfaceVariant}"
|
||||
FontSize="11" Width="60" VerticalAlignment="Center"/>
|
||||
<TextBlock DockPanel.Dock="Right" Width="42" TextAlignment="Right" FontSize="11"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,27 @@ public class ScoreboardRendererTests
|
||||
var red = ScoreboardRenderer.Render(Tiles, new ScoreboardStyle("#FF0000", false, "#000000", 0.5));
|
||||
Assert.True(Count(red!, (r, g, b, a) => r > 180 && g < 80 && b < 80 && a > 200) > 20);
|
||||
|
||||
// The PLATE TOGGLE itself: same text, plate off vs on, different pixels. This is the
|
||||
// check that answers "the checkbox has no code behind it".
|
||||
var off = ScoreboardRenderer.Render(Tiles, new ScoreboardStyle("#FFFFFF", false, "#0000FF", 0.5));
|
||||
var on = ScoreboardRenderer.Render(Tiles, new ScoreboardStyle("#FFFFFF", true, "#0000FF", 0.5));
|
||||
Assert.True(Count(on!, (r, g, b, a) => b > 150 && r < 60 && g < 60 && a > 100)
|
||||
> Count(off!, (r, g, b, a) => b > 150 && r < 60 && g < 60 && a > 100) + 500,
|
||||
"turning the plate on must add plate pixels");
|
||||
|
||||
// Opacity: 20% and 80% must produce visibly different plate transparency.
|
||||
var faint = ScoreboardRenderer.Render(Tiles, new ScoreboardStyle("#FFFFFF", true, "#0000FF", 0.2));
|
||||
var solid = ScoreboardRenderer.Render(Tiles, new ScoreboardStyle("#FFFFFF", true, "#0000FF", 0.8));
|
||||
int AlphaOf(VideoFrame f)
|
||||
{
|
||||
for (var i = 3; i < f.BgraPixels.Length; i += 4)
|
||||
if (f.BgraPixels[i] is > 10 and < 245) return f.BgraPixels[i];
|
||||
return 0;
|
||||
}
|
||||
Assert.InRange(AlphaOf(faint!), 35, 70); // ~20% of 255
|
||||
Assert.InRange(AlphaOf(solid!), 190, 220); // ~80% of 255
|
||||
Assert.True(AlphaOf(solid!) > AlphaOf(faint!) + 100, "the opacity slider must move the alpha");
|
||||
|
||||
// Nothing enabled: no frame at all (the layer draws nothing).
|
||||
Assert.Null(ScoreboardRenderer.Render(Array.Empty<string>(), new ScoreboardStyle()));
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ public class ScoreboardSimulationTests
|
||||
recorder.StartSession();
|
||||
Assert.Equal(0, recorder.State.NewMembers);
|
||||
|
||||
// Simulate OVERRIDES the master "show" switch: the dev toggle must work even when the
|
||||
// product setting is off.
|
||||
var vmSource = SourceAssert.Text("ViewModels", "MainViewModel.Scoreboard.cs");
|
||||
Assert.Contains("_scoreboardEnabled || _scoreboardSimulate", vmSource);
|
||||
|
||||
// The control exists and is gated on the build, not on a runtime flag.
|
||||
var panel = SourceAssert.Text("Controls", "LeftPanel.xaml");
|
||||
Assert.Contains("ScoreboardSimulate", panel);
|
||||
|
||||
Reference in New Issue
Block a user