| 298 | } |
| 299 | |
| 300 | bool AppSession::seedPlaybackFromSession() { |
| 301 | // The range update AND the display-min for the first-seed snap come from the |
| 302 | // single shared scan in recomputeRange (it can grow on an additional file or |
| 303 | // shrink on a removed/trashed/shorter reload) — no second forEachVisibleRawRange |
| 304 | // pass to keep in lockstep. recomputeRange never touches currentTime; the |
| 305 | // first-seed snap below is the only place that does. |
| 306 | const std::optional<DisplaySeconds> new_min = recomputeRange(); |
| 307 | if (!new_min) { |
| 308 | // No visible data: keep the current range (nothing better to show). The |
| 309 | // first-seed snap re-arms through the CatalogModel::cleared() hook. |
| 310 | return false; |
| 311 | } |
| 312 | |
| 313 | if (!playback_seeded_) { |
| 314 | // First load (or first after the catalog emptied): also snap currentTime to |
| 315 | // the data minimum so the user lands at the start of the data. |
| 316 | playback_engine_->setCurrentTime(*new_min); |
| 317 | playback_seeded_ = true; |
| 318 | } |
| 319 | return true; |
| 320 | } |
| 321 | |
| 322 | bool AppSession::focusPlaybackOnDatasets(const std::vector<DatasetId>& datasets) { |
| 323 | if (datasets.empty()) { |