mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 14:25:08 +00:00
feat(vegas): keep live games in the ticker by default
display.vegas_scroll.live_in_ticker now defaults to true: through a live game the marquee keeps running and the live scoreboard takes extra turns in it -- its cards updating in place while they scroll -- instead of the ticker giving way to the full-screen scoreboard. The new default would reach nobody on its own: every existing config holds an explicit false copied from the template (there was no control for it), and the template merge only adds missing keys. ConfigManager therefore turns a stored false on once, with a backup, and records live_in_ticker_migrated so a false chosen afterwards stays. The marker is never in the template. A "Keep live games in the ticker" checkbox under Vegas mode sets it. Tests that pin the full-screen takeover now say live_in_ticker=false. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -406,6 +406,15 @@ read any of them:
|
||||
`render_vegas_strip()` and `render_vegas_timeline()` in
|
||||
`src/plugin_system/testing/vegas.py`; the join is now
|
||||
`render_pipeline.join_plugin_rows()`.
|
||||
- **Behaviour change: live games stay in the Vegas ticker by default.**
|
||||
`display.vegas_scroll.live_in_ticker` now defaults to `true`: the marquee
|
||||
keeps running through a live game, which takes extra turns in it, instead
|
||||
of giving way to the full-screen scoreboard. Existing configs all held the
|
||||
old `false`, copied from the template, so the first start turns it on once
|
||||
(`ConfigManager._migrate_live_in_ticker_default`; the previous config is
|
||||
kept as `config.json.backup` and `live_in_ticker_migrated` records that it
|
||||
ran). To keep the full-screen scoreboard, untick the new **Keep live games
|
||||
in the ticker** under Vegas mode; a `false` set after the migration stays.
|
||||
|
||||
### Scrolling
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
"plugin_rotation_order": [],
|
||||
"use_short_date_format": true,
|
||||
"vegas_scroll": {
|
||||
"live_in_ticker": false,
|
||||
"live_in_ticker": true,
|
||||
"live_weight": 3,
|
||||
"favorite_live_weight": 5,
|
||||
"enabled": false,
|
||||
|
||||
@@ -75,17 +75,31 @@ total. See the full list in
|
||||
|
||||
### Live Content in the Ticker
|
||||
|
||||
By default, live content **preempts** Vegas mode: while any plugin reports
|
||||
live priority, the display controller refuses to run the ticker and shows
|
||||
that plugin's full-screen display instead. You get a big readable scoreboard,
|
||||
but the marquee stops entirely for the duration of the game.
|
||||
By default (since 3.8.0) live content **stays in the ticker** and takes
|
||||
**extra turns inside it**, and a scoreboard that supports live cards updates
|
||||
the score on a card already crossing the screen (`live_refresh`, "Update live
|
||||
content while it scrolls").
|
||||
|
||||
Set `live_in_ticker` to keep the ticker running and let live content take
|
||||
**extra turns inside it** instead:
|
||||
To get the old behaviour back -- live content **preempts** Vegas mode: while
|
||||
any plugin reports live priority the ticker stops and that plugin's
|
||||
full-screen display is shown instead -- untick **Keep live games in the
|
||||
ticker** under Vegas mode, or set `live_in_ticker` to `false`:
|
||||
|
||||
```json
|
||||
"vegas_scroll": {
|
||||
"live_in_ticker": false
|
||||
}
|
||||
```
|
||||
|
||||
Until 3.8.0 `false` was the default and every config held it, copied from
|
||||
the template. The first start on 3.8.0 turns it on once (a backup of the
|
||||
config is kept as `config.json.backup`, and `live_in_ticker_migrated` records
|
||||
that it ran); a `false` set after that is left alone.
|
||||
|
||||
The weights below apply while live content is in the ticker:
|
||||
|
||||
```json
|
||||
"vegas_scroll": {
|
||||
"live_in_ticker": true,
|
||||
"live_weight": 3,
|
||||
"favorite_live_weight": 5
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ Read by `src/vegas_mode/config.py` (`VegasScrollConfig.from_config`). See
|
||||
| `max_cycle_duration` | int, `240` |
|
||||
| `frame_based_scrolling` | bool, `true` — does not step or set a frame rate; motion is by elapsed time either way. When `true`, `scroll_speed` passes through a clamp of 0.1–5 px per `scroll_delay` (see next row) |
|
||||
| `scroll_delay` | float, `0.02` — not a frame period. Only used with `frame_based_scrolling`: the applied speed is `clamp(scroll_speed × scroll_delay, 0.1, 5) / scroll_delay` px/s, so at `0.02` speeds under 5 px/s run at 5, and at `0.001` nothing runs slower than 100 px/s |
|
||||
| `live_in_ticker` | bool, `false` — keep scrolling during live games instead of handing the display to a full-screen scoreboard |
|
||||
| `live_in_ticker` | bool, `true` — keep scrolling during live games instead of handing the display to a full-screen scoreboard. `false` was the default before 3.8.0; the first start on 3.8.0 turns a stored `false` on once and sets `live_in_ticker_migrated` |
|
||||
| `live_weight` | int, `3` (1–10) — slots per cycle for a plugin with live content |
|
||||
| `favorite_live_weight` | int, `5` (1–10) — slots per cycle when a plugin reports a favorite team is live |
|
||||
|
||||
|
||||
@@ -336,6 +336,9 @@ to rebuild it twice, 1.7-3.8 ms each on a Pi 4). The `extend` row of
|
||||
work" table), and extensions no longer rebuilding the strip's PIL copy.
|
||||
3. **Live elements:** the plugin API, the records, the worker and in-place
|
||||
patches, with the sports scoreboards and the flight map adopting it.
|
||||
4. **Live games in the ticker by default:** `live_in_ticker` true, so a live
|
||||
game's cards update in the marquee instead of the full-screen scoreboard
|
||||
replacing it; existing configs are switched once (`ConfigManager`).
|
||||
|
||||
`display.vegas_scroll.offscreen_prefetch` (default `true`) restores the
|
||||
deferred path when `false`, and `display.vegas_scroll.live_refresh` (default
|
||||
|
||||
@@ -308,9 +308,9 @@ the core then falls back to its own live-content check — so a plugin whose
|
||||
weight calculation is broken still gets `live_weight` for a game that really
|
||||
is live, rather than being demoted to 1.
|
||||
|
||||
Only consulted when the user has set `vegas_scroll.live_in_ticker`. With the
|
||||
default (`false`) live content preempts Vegas entirely and there is no ticker
|
||||
to be weighted within. See
|
||||
Only consulted while `vegas_scroll.live_in_ticker` is on (the default since
|
||||
3.8.0). With it off live content preempts Vegas entirely and there is no
|
||||
ticker to be weighted within. See
|
||||
[ADVANCED_FEATURES.md](ADVANCED_FEATURES.md#live-content-in-the-ticker).
|
||||
|
||||
### Vegas scroll hooks
|
||||
|
||||
+45
-3
@@ -451,8 +451,10 @@ class ConfigManager:
|
||||
template_config = json.load(f)
|
||||
|
||||
# Check if migration is needed
|
||||
if self._config_needs_migration(self.config, template_config):
|
||||
self.logger.info("Config migration needed - adding new configuration items with defaults")
|
||||
needs_merge = self._config_needs_migration(self.config, template_config)
|
||||
if needs_merge or self._live_in_ticker_needs_migration():
|
||||
if needs_merge:
|
||||
self.logger.info("Config migration needed - adding new configuration items with defaults")
|
||||
|
||||
# Create backup of current config
|
||||
backup_path = f"{self.config_path}.backup"
|
||||
@@ -461,7 +463,9 @@ class ConfigManager:
|
||||
self.logger.info(f"Created backup of current config at {os.path.abspath(backup_path)}")
|
||||
|
||||
# Merge template defaults into current config
|
||||
self._merge_template_defaults(self.config, template_config)
|
||||
if needs_merge:
|
||||
self._merge_template_defaults(self.config, template_config)
|
||||
self._migrate_live_in_ticker_default()
|
||||
|
||||
# save_config_atomic strips the merged secrets back out and
|
||||
# keeps the file's owner and mode.
|
||||
@@ -482,6 +486,44 @@ class ConfigManager:
|
||||
self.logger.error(f"Error during config migration: {e}")
|
||||
# Don't raise - continue with current config
|
||||
|
||||
#: Set in display.vegas_scroll once _migrate_live_in_ticker_default() has
|
||||
#: run. Never in the template: the template merge would add it first, and
|
||||
#: the flip would then never run.
|
||||
LIVE_IN_TICKER_MARKER = 'live_in_ticker_migrated'
|
||||
|
||||
def _vegas_scroll_section(self) -> Optional[Dict[str, Any]]:
|
||||
display = self.config.get('display')
|
||||
vegas = display.get('vegas_scroll') if isinstance(display, dict) else None
|
||||
return vegas if isinstance(vegas, dict) else None
|
||||
|
||||
def _live_in_ticker_needs_migration(self) -> bool:
|
||||
vegas = self._vegas_scroll_section()
|
||||
return vegas is not None and not vegas.get(self.LIVE_IN_TICKER_MARKER)
|
||||
|
||||
def _migrate_live_in_ticker_default(self) -> None:
|
||||
"""Turn on live_in_ticker for a config that only ever had the old default. Once.
|
||||
|
||||
LEDMatrix 3.8.0 makes ``display.vegas_scroll.live_in_ticker`` true:
|
||||
live games stay in the Vegas ticker, their cards updating while they
|
||||
scroll, instead of the ticker giving way to the full-screen
|
||||
scoreboard. Every existing config holds an explicit ``false`` copied
|
||||
from the template -- there was no control for it -- and the template
|
||||
merge only adds missing keys, so the new default would reach nobody.
|
||||
This rewrites that ``false`` once and marks the config, so a
|
||||
``false`` chosen afterwards (the Vegas checkbox, or by hand) stays.
|
||||
"""
|
||||
vegas = self._vegas_scroll_section()
|
||||
if vegas is None or vegas.get(self.LIVE_IN_TICKER_MARKER):
|
||||
return
|
||||
vegas[self.LIVE_IN_TICKER_MARKER] = True
|
||||
if vegas.get('live_in_ticker') is False:
|
||||
vegas['live_in_ticker'] = True
|
||||
self.logger.info(
|
||||
"Vegas mode now keeps live games in the ticker (the new default): "
|
||||
"display.vegas_scroll.live_in_ticker turned on, once. Untick "
|
||||
"\"Keep live games in the ticker\" under Vegas mode for the "
|
||||
"full-screen scoreboard.")
|
||||
|
||||
def _config_needs_migration(self, current_config: Dict[str, Any], template_config: Dict[str, Any]) -> bool:
|
||||
"""Check if config needs migration by comparing with template."""
|
||||
return self._has_new_keys(current_config, template_config)
|
||||
|
||||
@@ -2206,7 +2206,7 @@ class DisplayController:
|
||||
"""Whether live content should stay in the ticker instead of preempting it."""
|
||||
coordinator = self.vegas_coordinator
|
||||
config = getattr(coordinator, 'vegas_config', None)
|
||||
return bool(getattr(config, 'live_in_ticker', False))
|
||||
return bool(getattr(config, 'live_in_ticker', True))
|
||||
|
||||
def _check_live_priority(self, advance=False):
|
||||
"""Return the live-priority mode to display, or None if nothing is live.
|
||||
|
||||
@@ -180,10 +180,13 @@ class VegasModeConfig:
|
||||
|
||||
# --- Live content in the ticker -------------------------------------
|
||||
#
|
||||
# By default a live game preempts Vegas entirely: the display controller
|
||||
# refuses to run the ticker while any plugin reports live priority, and you
|
||||
# get the full-screen scoreboard instead. Set live_in_ticker to keep the
|
||||
# marquee running and let live content take extra turns within it.
|
||||
# By default live content stays in the marquee and takes extra turns
|
||||
# within it, its cards updating while they scroll (live elements, below).
|
||||
# With live_in_ticker false a live game preempts Vegas entirely: the
|
||||
# display controller refuses to run the ticker while any plugin reports
|
||||
# live priority, and you get the full-screen scoreboard instead. (False
|
||||
# was the default until 3.8.0; ConfigManager turns it on once for configs
|
||||
# that still hold the old default.)
|
||||
#
|
||||
# The rotation is otherwise a strict round robin -- every plugin appears
|
||||
# exactly once per cycle -- so with a dozen plugins enabled a live score
|
||||
@@ -193,7 +196,7 @@ class VegasModeConfig:
|
||||
# Weights are per plugin, not per game: a scoreboard showing four live
|
||||
# games still occupies one slot at a time, and rotates its own games within
|
||||
# that slot using its own favorite_live_boost.
|
||||
live_in_ticker: bool = False
|
||||
live_in_ticker: bool = True
|
||||
|
||||
# Slots per cycle for a plugin reporting live content. 1 disables the boost
|
||||
# and restores the plain round robin.
|
||||
|
||||
@@ -134,6 +134,20 @@ class TestJsonPartialSaves:
|
||||
assert resp.status_code == 200, resp.get_json()
|
||||
assert saved['config']['display']['vegas_scroll']['live_refresh'] is True
|
||||
|
||||
def test_live_games_can_be_kept_in_the_ticker_or_not(self, api_v3_client, saved):
|
||||
resp = _post_json(api_v3_client, {'vegas_live_in_ticker': False})
|
||||
assert resp.status_code == 200, resp.get_json()
|
||||
assert saved['config']['display']['vegas_scroll']['live_in_ticker'] is False
|
||||
# An unticked box is absent from a submitted form: that is false too.
|
||||
resp = _post_json(api_v3_client, {'__form_section': 'display',
|
||||
'vegas_scroll_speed': '50',
|
||||
'vegas_live_in_ticker': 'on'})
|
||||
assert saved['config']['display']['vegas_scroll']['live_in_ticker'] is True
|
||||
resp = _post_json(api_v3_client, {'__form_section': 'display',
|
||||
'vegas_scroll_speed': '50'})
|
||||
assert resp.status_code == 200, resp.get_json()
|
||||
assert saved['config']['display']['vegas_scroll']['live_in_ticker'] is False
|
||||
|
||||
def test_double_sided_axis_only_keeps_enabled(self, api_v3_client, saved):
|
||||
resp = _post_json(api_v3_client, {'double_sided_axis': 'horizontal'})
|
||||
assert resp.status_code == 200, resp.get_json()
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
"""live_in_ticker's new default reaches existing installs, once (src/config_manager.py).
|
||||
|
||||
3.8.0 makes display.vegas_scroll.live_in_ticker true. Every existing config
|
||||
holds an explicit false copied from the template, which the template merge
|
||||
never touches (it only adds missing keys), so ConfigManager turns that false
|
||||
on once and marks the config. A false chosen after that -- the new checkbox,
|
||||
or by hand -- must stay false.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
from src.config_manager import ConfigManager # noqa: E402
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
MARKER = ConfigManager.LIVE_IN_TICKER_MARKER
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def files(tmp_path):
|
||||
template = {"display": {"brightness": 90,
|
||||
"vegas_scroll": {"enabled": False, "live_in_ticker": True}}}
|
||||
paths = {name: tmp_path / f"{name}.json" for name in ("config", "secrets", "template")}
|
||||
paths["template"].write_text(json.dumps(template))
|
||||
paths["secrets"].write_text("{}")
|
||||
return paths
|
||||
|
||||
|
||||
def _load(files, config):
|
||||
files["config"].write_text(json.dumps(config))
|
||||
manager = ConfigManager(config_path=str(files["config"]),
|
||||
secrets_path=str(files["secrets"]))
|
||||
manager.template_path = str(files["template"])
|
||||
manager.load_config()
|
||||
return manager, json.loads(files["config"].read_text())
|
||||
|
||||
|
||||
def _vegas(saved):
|
||||
return saved["display"]["vegas_scroll"]
|
||||
|
||||
|
||||
def test_the_old_default_is_turned_on_once_and_marked(files):
|
||||
old = {"display": {"brightness": 90,
|
||||
"vegas_scroll": {"enabled": True, "live_in_ticker": False}}}
|
||||
manager, saved = _load(files, old)
|
||||
assert _vegas(saved)["live_in_ticker"] is True
|
||||
assert _vegas(saved)[MARKER] is True
|
||||
assert _vegas(manager.config)["live_in_ticker"] is True
|
||||
# The config as it was is kept beside it.
|
||||
backup = json.loads(Path(f"{files['config']}.backup").read_text())
|
||||
assert _vegas(backup)["live_in_ticker"] is False
|
||||
|
||||
|
||||
def test_false_chosen_after_the_migration_stays_false(files):
|
||||
chosen = {"display": {"brightness": 90,
|
||||
"vegas_scroll": {"enabled": True, "live_in_ticker": False,
|
||||
MARKER: True}}}
|
||||
_manager, saved = _load(files, chosen)
|
||||
assert _vegas(saved)["live_in_ticker"] is False
|
||||
|
||||
|
||||
def test_a_marked_config_is_not_written_again(files):
|
||||
marked = {"display": {"brightness": 90,
|
||||
"vegas_scroll": {"enabled": True, "live_in_ticker": True,
|
||||
MARKER: True}}}
|
||||
files["config"].write_text(json.dumps(marked))
|
||||
before = files["config"].stat().st_mtime_ns
|
||||
manager = ConfigManager(config_path=str(files["config"]),
|
||||
secrets_path=str(files["secrets"]))
|
||||
manager.template_path = str(files["template"])
|
||||
manager.load_config()
|
||||
assert files["config"].stat().st_mtime_ns == before
|
||||
assert not Path(f"{files['config']}.backup").exists()
|
||||
|
||||
|
||||
def test_a_config_without_vegas_settings_gets_the_new_default(files):
|
||||
_manager, saved = _load(files, {"display": {"brightness": 90}})
|
||||
assert _vegas(saved)["live_in_ticker"] is True
|
||||
assert _vegas(saved)[MARKER] is True
|
||||
|
||||
|
||||
def test_true_already_is_only_marked(files):
|
||||
on = {"display": {"brightness": 90,
|
||||
"vegas_scroll": {"enabled": True, "live_in_ticker": True}}}
|
||||
_manager, saved = _load(files, on)
|
||||
assert _vegas(saved)["live_in_ticker"] is True and _vegas(saved)[MARKER] is True
|
||||
|
||||
|
||||
def test_a_second_load_keeps_a_false_set_in_between(files):
|
||||
old = {"display": {"brightness": 90,
|
||||
"vegas_scroll": {"enabled": True, "live_in_ticker": False}}}
|
||||
_manager, saved = _load(files, old)
|
||||
_vegas(saved)["live_in_ticker"] = False # the checkbox, unticked
|
||||
_manager, saved = _load(files, saved)
|
||||
assert _vegas(saved)["live_in_ticker"] is False
|
||||
|
||||
|
||||
def test_the_shipped_template_has_the_new_default_and_never_the_marker():
|
||||
template = json.loads((REPO / "config" / "config.template.json").read_text(encoding="utf-8"))
|
||||
vegas = template["display"]["vegas_scroll"]
|
||||
assert vegas["live_in_ticker"] is True
|
||||
assert MARKER not in vegas
|
||||
@@ -67,10 +67,13 @@ class TestConfigWhileStopped:
|
||||
|
||||
|
||||
class TestLivePriorityThrottle:
|
||||
"""The full-screen takeover's live scan: live_in_ticker off, no longer the default."""
|
||||
|
||||
def test_scan_runs_at_most_once_per_interval(self, monkeypatch):
|
||||
now = [1000.0]
|
||||
monkeypatch.setattr(coordinator_module.time, 'monotonic', lambda: now[0])
|
||||
c = _coordinator()
|
||||
c.vegas_config.live_in_ticker = False
|
||||
c._live_priority_check = MagicMock(return_value=None)
|
||||
|
||||
for _ in range(10):
|
||||
@@ -84,6 +87,7 @@ class TestLivePriorityThrottle:
|
||||
def test_live_content_still_pauses_vegas(self, monkeypatch):
|
||||
monkeypatch.setattr(coordinator_module.time, 'monotonic', lambda: 1000.0)
|
||||
c = _coordinator()
|
||||
c.vegas_config.live_in_ticker = False
|
||||
c._live_priority_check = MagicMock(return_value='nfl_live')
|
||||
c.pause = MagicMock()
|
||||
assert c.run_frame() is False
|
||||
|
||||
@@ -58,11 +58,16 @@ def test_an_iteration_does_not_poll_every_plugin_for_its_mode(caplog):
|
||||
|
||||
|
||||
def _live_coordinator(live):
|
||||
"""A coordinator running the real run_frame(), with a switchable live check."""
|
||||
"""A coordinator running the real run_frame(), with a switchable live check.
|
||||
|
||||
live_in_ticker off: these pin the full-screen takeover, which is no longer
|
||||
the default.
|
||||
"""
|
||||
coord = _coordinator({})
|
||||
del coord.run_frame # the real one: it is what refuses frames while paused
|
||||
coord.vegas_config = VegasModeConfig.from_config({'display': {'vegas_scroll': {
|
||||
'enabled': True, 'max_cycle_duration': 0, 'continuous_scroll': True}}})
|
||||
'enabled': True, 'max_cycle_duration': 0, 'continuous_scroll': True,
|
||||
'live_in_ticker': False}}})
|
||||
coord.render_pipeline.has_deferred.return_value = False
|
||||
coord.render_pipeline.needs_extension.return_value = False
|
||||
coord.render_pipeline.render_frame.return_value = True
|
||||
|
||||
@@ -5,10 +5,10 @@ live content did not appear in it at all, because the display controller
|
||||
refused to run the ticker while anything was live. With a dozen plugins
|
||||
enabled that left a live score either absent or minutes stale.
|
||||
|
||||
Two things change, both off by default. `live_in_ticker` keeps the marquee
|
||||
running instead of yielding to a full-screen takeover, and the rotation is
|
||||
expanded by Smooth Weighted Round-Robin so a weighted plugin gets several
|
||||
slots per cycle, spaced through it rather than clumped.
|
||||
Two things change. `live_in_ticker` keeps the marquee running instead of
|
||||
yielding to a full-screen takeover (on by default since 3.8.0), and the
|
||||
rotation is expanded by Smooth Weighted Round-Robin so a weighted plugin gets
|
||||
several slots per cycle, spaced through it rather than clumped.
|
||||
|
||||
Weights are per plugin, not per game: a scoreboard showing four live games
|
||||
still occupies one slot at a time and rotates its own games within it.
|
||||
@@ -288,9 +288,9 @@ class TestTheSchedule:
|
||||
|
||||
|
||||
class TestConfigParsing:
|
||||
def test_defaults_preserve_todays_behaviour(self):
|
||||
def test_live_games_stay_in_the_ticker_by_default(self):
|
||||
cfg = VegasModeConfig.from_config({})
|
||||
assert cfg.live_in_ticker is False
|
||||
assert cfg.live_in_ticker is True
|
||||
assert cfg.live_weight == 3 and cfg.favorite_live_weight == 5
|
||||
|
||||
@pytest.mark.parametrize("given,expected", [(0, 1), (-4, 1), (99, 10), (4, 4)])
|
||||
|
||||
@@ -802,7 +802,8 @@ def save_main_config():
|
||||
'vegas_intra_plugin_gap', 'vegas_render_width_pct',
|
||||
'vegas_min_content_separation', 'vegas_min_cut_gap',
|
||||
'vegas_continuous_scroll', 'vegas_extend_threshold_screens',
|
||||
'vegas_smooth_scroll', 'vegas_overflow_mode', 'vegas_live_refresh']
|
||||
'vegas_smooth_scroll', 'vegas_overflow_mode', 'vegas_live_refresh',
|
||||
'vegas_live_in_ticker']
|
||||
|
||||
if any(k in data for k in vegas_fields):
|
||||
if 'display' not in current_config:
|
||||
@@ -823,6 +824,7 @@ def save_main_config():
|
||||
_set_checkbox(vegas_config, 'continuous_scroll', 'vegas_continuous_scroll')
|
||||
_set_checkbox(vegas_config, 'smooth_scroll', 'vegas_smooth_scroll')
|
||||
_set_checkbox(vegas_config, 'live_refresh', 'vegas_live_refresh')
|
||||
_set_checkbox(vegas_config, 'live_in_ticker', 'vegas_live_in_ticker')
|
||||
|
||||
# max_plugin_width_ratio is the one fractional setting, so it is
|
||||
# handled outside the integer loop below.
|
||||
|
||||
@@ -579,6 +579,18 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-4" id="setting-display-vegas_live_in_ticker" data-setting-key="display.vegas_scroll.live_in_ticker">
|
||||
<label class="flex items-center">
|
||||
<input type="checkbox"
|
||||
id="vegas_live_in_ticker"
|
||||
name="vegas_live_in_ticker"
|
||||
{% if main_config.display.get('vegas_scroll', {}).get('live_in_ticker', True) %}checked{% endif %}
|
||||
class="form-checkbox">
|
||||
<span class="ml-2 text-sm text-gray-700">Keep live games in the ticker{{ ui.help_tip('While a game is live, keep the ticker running and give the live scoreboard extra turns in it (Live Weight). Default: on.
|
||||
With this off a live game takes over the whole display with the full-screen scoreboard until it ends, and the ticker stops.', 'Live Games') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div class="form-group" id="setting-display-vegas_extend_threshold_screens" data-setting-key="display.vegas_scroll.extend_threshold_screens">
|
||||
<label for="vegas_extend_threshold_screens" class="block text-sm font-medium text-gray-700">Extend When (screens left){{ ui.help_tip('How much unscrolled content triggers loading the next group, measured in screen widths (1.0–10.0).\nDefault: 2. Higher loads earlier and leaves more slack, at the cost of holding more content in memory. Only applies when Continuous Scroll is on.', 'Extend Threshold') }}</label>
|
||||
|
||||
Reference in New Issue
Block a user