feat(scoreboard): a master on/off switch that also stops the polling

Creator: "even if it's not visible, we want to avoid polling."

ScoreboardEnabled is the layer's master switch in the properties panel. Off means two things:
- the strip frame is null in every scene (per-scene eye toggles stay independent), and
- the cadence policy returns None at every phase — a scoreboard nobody can see must not spend quota.

The switch is persisted (Scoreboard.Enabled), because one that resets would quietly resume polling.

The polling gate is ScoreboardPollsEnabled: master switch AND at least one scene with a visible
scoreboard — so hiding it in all five scenes also stops the polls.

Guards: ScoreboardCadenceTests adds the switch off across live/test/recording; ScoreboardProperties
pins the checkbox and the VM surface.
This commit is contained in:
2026-10-30 14:54:05 -07:00
parent 85a4a8a7d3
commit 38c2ad6555
7 changed files with 48 additions and 2 deletions
+23 -1
View File
@@ -28,6 +28,28 @@ public partial class MainViewModel
internal ScoreboardRecorder ScoreboardRecorder => _scoreboard;
private bool _scoreboardEnabled = true;
/// <summary>The scoreboard's master switch. Off hides the strip in EVERY scene (the per-scene
/// eye stays independent) and — the point of the switch — stops all polling: a scoreboard nobody
/// can see must not spend quota.</summary>
public bool ScoreboardEnabled
{
get => _scoreboardEnabled;
set
{
if (!SetProperty(ref _scoreboardEnabled, value)) return;
_layoutStore.SaveScoreboardEnabled(value);
RefreshScoreboardPreviews();
OnPropertyChanged(nameof(ScoreboardPollsEnabled));
}
}
/// <summary>What the cadence policy asks: the master switch AND at least one scene showing it.</summary>
internal bool ScoreboardPollsEnabled =>
_scoreboardEnabled && Scenes.Any(scene =>
scene.Elements.OfType<Source>().Any(s => s.IsScoreboard && s.IsVisible && s.IsEnabled));
internal ScoreboardTiles ScoreboardTilesState => _scoreboardTiles;
/// <summary>Composited strip frame for the output path (cached by the presenter).</summary>
@@ -146,7 +168,7 @@ public partial class MainViewModel
/// must never touch a WriteableBitmap, so this runs on the UI thread only.</summary>
private void RefreshScoreboardPreviews()
{
var frame = _scoreboardPresenter?.Frame;
var frame = _scoreboardEnabled ? _scoreboardPresenter?.Frame : null;
foreach (var scene in Scenes)
foreach (var source in scene.Elements.OfType<Source>().Where(s => s.IsScoreboard))
{