Say where the grid is on the capture-time axis from the first frame
The sidebar's marker rested greyed at mid-track until the first scroll or scrub. The reasoning was that anchoring it would imply a choice the user had not made -- but that reads the marker as reporting an intention, and it does not. The sidebar's whole claim is to say *when* you are, and that is known from the first frame: the grid is at the top of the library, or wherever it was last left. So a launch opened with the marker halfway down an axis whose visible photographs were all from the wrong end of it. Dimmed rather than absent, which made it look like a reading rather than the absence of one. Seeded in `refresh_timeline` -- the one place that decides what the marker says, and the one that runs on every route which builds the axis -- and only when nothing has claimed it, so a scroll or a scrub still speaks for itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -225,8 +225,12 @@ pub struct LibraryController {
|
||||
/// held until it reaches a doubling. Without it a slow spread would either
|
||||
/// do nothing or, if each update were rounded, leap several levels.
|
||||
pinch_accum: RefCell<f32>,
|
||||
/// The instant the grid is showing. `None` until the user has moved the
|
||||
/// timeline, which is what leaves the marker resting at the middle.
|
||||
/// The instant the grid is showing.
|
||||
///
|
||||
/// `None` only before the first axis has been built: `refresh_timeline`
|
||||
/// seeds it from wherever the view sits, so the marker reports a position
|
||||
/// from the first frame rather than resting greyed at mid-track until the
|
||||
/// user happens to scroll. A scroll or a scrub then sets it directly.
|
||||
current_bucket: RefCell<Option<i64>>,
|
||||
/// What the rating filter bar is narrowed to.
|
||||
///
|
||||
@@ -4182,6 +4186,29 @@ fn start_thumbnail_sweep(window: &AppWindow, ctl: &Rc<LibraryController>) {
|
||||
/// from the data rather than fixing it means the histogram is informative at
|
||||
/// both scales instead of one flat bar or ten thousand slivers.
|
||||
fn refresh_timeline(window: &AppWindow, catalog: &Catalog, ctl: &Rc<LibraryController>) {
|
||||
// Where the grid sits, if nothing has said so yet.
|
||||
//
|
||||
// **The marker used to rest greyed at mid-track until the first scroll or
|
||||
// scrub**, on the reasoning that anchoring it would imply a choice the user
|
||||
// had not made. That reads the marker as reporting an intention, and it does
|
||||
// not: the sidebar's whole claim is to say *when* you are, and the answer is
|
||||
// known from the first frame — the grid is at the top of the library, or at
|
||||
// whatever position was restored into it. A launch that opened with the
|
||||
// marker halfway down an axis whose photographs were all from the wrong end
|
||||
// was simply wrong, and dimmed rather than absent, which made it look like a
|
||||
// reading rather than the absence of one.
|
||||
//
|
||||
// Seeded here rather than at the end of the scan because this is the one
|
||||
// place that decides what the marker says, and it runs on every route that
|
||||
// builds the axis. Only when nothing has claimed it: a scroll or a scrub
|
||||
// sets it directly, and this must never overwrite them.
|
||||
let unanchored = ctl.current_bucket.borrow().is_none();
|
||||
if unanchored {
|
||||
if let Some(when) = capture_time_at(ctl, catalog, ctl.resume_at.get()) {
|
||||
*ctl.current_bucket.borrow_mut() = Some(when);
|
||||
}
|
||||
}
|
||||
|
||||
// Scoped to whatever the grid is showing. A collection's histogram drawn
|
||||
// over the whole library's span said almost nothing: every bar for a
|
||||
// fortnight in Arosa landed in one column of a fifteen-year axis.
|
||||
@@ -4574,9 +4601,10 @@ fn scrub_to(window: &AppWindow, ctl: &Rc<LibraryController>, when: i64) {
|
||||
.unwrap_or(0) as usize
|
||||
};
|
||||
|
||||
// Record where the grid now sits, which anchors the timeline marker. Until
|
||||
// the first scrub this stays `None` and the marker rests at the middle
|
||||
// rather than implying a choice the user has not made.
|
||||
// Record where the grid now sits, which anchors the timeline marker.
|
||||
// `refresh_timeline` seeds this from the view's own position when nothing
|
||||
// has claimed it, so by the time a scrub arrives it is an update rather than
|
||||
// the first word.
|
||||
*ctl.current_bucket.borrow_mut() = Some(when);
|
||||
*ctl.offset.borrow_mut() = position;
|
||||
// Move the viewport as well as the window. Cells are drawn at their
|
||||
|
||||
@@ -93,9 +93,10 @@ export component Timeline inherits Rectangle {
|
||||
/// happened to fall — never under the pointer. Negative means "not
|
||||
/// anchored".
|
||||
in property <float> current-fraction: -1;
|
||||
/// True once the user has taken control. Until then the marker rests at the
|
||||
/// middle rather than pinning to either end, which would imply a selection
|
||||
/// that has not been made.
|
||||
/// Whether the marker has a position to report. False only before the first
|
||||
/// axis has been built — Rust seeds it from wherever the grid sits, so a
|
||||
/// launch draws the marker where the photographs on screen are rather than
|
||||
/// leaving it dimmed at mid-track waiting for a scroll.
|
||||
in property <bool> anchored: false;
|
||||
|
||||
/// Scrub to a fraction along the visible span. Rust turns it into an
|
||||
|
||||
Reference in New Issue
Block a user