nandi/jolt-nativepublic Fork 0
98daca1
Commits
Clone
git clone https://git.rickub.com/nandi/jolt-native.git
git clone ssh://git@rickub.com/nandi/jolt-native.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Revert "Scroll to the row that asked, where it actually is"

This reverts commit 0fb017593acce485b16f9756141b599beb49dc76.
nandi committed 2026-09-11T21:53:09-07:00 Browse files
98daca1 parent: 0fb0175
modified crates/jolt-cosmic/src/lib.rs +24 -160
@@ -36,8 +36,6 @@ use cosmic::iced::futures::{Stream, StreamExt};
3636 use cosmic::iced::widget::container::Style as ContainerStyle;
3737 use cosmic::iced::widget::scrollable::{self as iced_scrollable, AbsoluteOffset, RelativeOffset, Viewport};
3838 use cosmic::iced::widget::text::Wrapping;
39-use cosmic::iced::advanced::widget as advanced;
40-use cosmic::iced::advanced::widget::operation::scrollable as iced_operation;
4139 use cosmic::iced::{Alignment, Background, Border, Color, ContentFit, Font, Length, Padding, Subscription};
4240 use cosmic::widget::{self, Column, Row};
4341 use cosmic::{ApplicationExt, Element};
@@ -265,8 +263,9 @@ struct ScrollAsk {
265263 tick_before: Option<f64>,
266264 /// Not in the tree before this commit: mounted, or mounted again.
267265 fresh: bool,
268- /// The node asking to be shown, if one is.
269- reveal: Option<i32>,
266+ /// Where, as a fraction of the list, a node that has just been asked to be
267+ /// shown sits.
268+ reveal: Option<f32>,
270269 }
271270
272271 /// Every scroll area in `now`, and what changed about each since `before`.
@@ -284,28 +283,23 @@ fn scroll_asks(before: &Tree, now: &Tree) -> Vec<ScrollAsk> {
284283 return;
285284 }
286285 let name = scroll_name(n, id);
287- // The ROW holding whatever asked to be shown. The row and not the
288- // asking node itself, because the row is what carries an id — see
289- // `element` — and the id is how the layout is asked where it is.
290- //
291- // This used to answer with the row's index over the row count, which
292- // is a fraction of the SCROLL RANGE rather than of the content — the
293- // two agree only when the viewport is exactly one row tall — and it
294- // assumed every row the same height besides, in a backlog that puts a
295- // one-line message next to a picture. The landing was out by up to a
296- // viewport, worst in the middle of a list.
297- //
298- // While it is asking, not only on the commit it starts: a row that is
299- // not in the tree yet when the ask arrives would otherwise never be
300- // scrolled to at all, and the ask is over in half a second.
286+ // A row asking to be shown, that was not asking last commit. The
287+ // position is the index of the top-level row holding it: exact for a
288+ // list of rows the same height and close for frq's backlog, and there
289+ // is no layout to ask from here.
290+ let count = n.children.len();
301291 let mut reveal = None;
302- for row in &n.children {
292+ for (index, row) in n.children.iter().enumerate() {
303293 let mut asked = false;
304- walk(now, *row, &mut |_, node| {
305- asked |= node.bool("scroll-here") == Some(true);
294+ walk(now, *row, &mut |nid, node| {
295+ let here = node.bool("scroll-here") == Some(true);
296+ let was = before
297+ .get(nid)
298+ .is_some_and(|old| old.bool("scroll-here") == Some(true));
299+ asked |= here && !was;
306300 });
307301 if asked {
308- reveal = Some(*row);
302+ reveal = Some(index as f32 / (count.saturating_sub(1).max(1)) as f32);
309303 break;
310304 }
311305 }
@@ -325,88 +319,6 @@ fn snap_to_end(name: &str) -> Task<Message> {
325319 iced_scrollable::snap_to(scroll_id(name), RelativeOffset { x: None, y: Some(1.0) })
326320 }
327321
328-/// What a row that can be scrolled to is known by.
329-fn here_id(node: i32) -> widget::Id {
330- widget::Id::new(format!("jolt-here-{node}"))
331-}
332-
333-/// Where `node` sits inside the scroll area called `name`, measured, and then
334-/// the scroll put there.
335-///
336-/// Two steps because the answer is not in the tree. The tree says which row
337-/// asked; only the layout knows how far down the content it ended up, and the
338-/// layout is a thing you can ask questions of exactly once a frame, through an
339-/// `Operation`. So the operation reads the row's bounds and the scroll area's,
340-/// works the offset out, and hands it back as a message that scrolls there.
341-///
342-/// The row is put in the MIDDLE of the viewport rather than against its top
343-/// edge. A line answered three days ago is read with what was said around it,
344-/// and a jump that pins it to the ceiling shows only what came after.
345-fn reveal(name: String, node: i32) -> Task<Message> {
346- let scroll = scroll_id(&name);
347- let target = here_id(node);
348-
349- struct Measure {
350- scroll: widget::Id,
351- target: widget::Id,
352- /// The scroll area: where its viewport starts, how tall it is, and
353- /// how far it is scrolled already.
354- view: Option<(f32, f32, f32)>,
355- /// The row: where it starts and how tall it is.
356- row: Option<(f32, f32)>,
357- }
358-
359- impl advanced::Operation<f32> for Measure {
360- fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn advanced::Operation<f32>)) {
361- operate(self);
362- }
363-
364- fn container(&mut self, id: Option<&widget::Id>, bounds: cosmic::iced::Rectangle) {
365- if id == Some(&self.target) {
366- self.row = Some((bounds.y, bounds.height));
367- }
368- }
369-
370- fn scrollable(
371- &mut self,
372- id: Option<&widget::Id>,
373- bounds: cosmic::iced::Rectangle,
374- _content: cosmic::iced::Rectangle,
375- translation: cosmic::iced::Vector,
376- _state: &mut dyn iced_operation::Scrollable,
377- ) {
378- if id == Some(&self.scroll) {
379- self.view = Some((bounds.y, bounds.height, translation.y));
380- }
381- }
382-
383- fn finish(&self) -> advanced::operation::Outcome<f32> {
384- match (self.view, self.row) {
385- // Both are in window coordinates, so the row's place in the
386- // content is how far it is below the viewport's top edge plus
387- // how far the viewport has already been scrolled.
388- (Some((view_y, view_h, scrolled)), Some((row_y, row_h))) => {
389- let top = row_y - view_y + scrolled;
390- let centred = top - (view_h - row_h).max(0.0) / 2.0;
391- advanced::operation::Outcome::Some(centred.max(0.0))
392- }
393- // The row is not laid out yet — it has only just been mounted,
394- // or it is not in this scroll area at all. Nothing to say, and
395- // the next commit asks again.
396- _ => advanced::operation::Outcome::None,
397- }
398- }
399- }
400-
401- advanced::operate(Measure {
402- scroll,
403- target,
404- view: None,
405- row: None,
406- })
407- .map(move |y| cosmic::Action::App(Message::Revealed(name.clone(), y)))
408-}
409-
410322 // --- the app -----------------------------------------------------------------
411323
412324 struct App {
@@ -431,9 +343,6 @@ enum Message {
431343 Hover(i32),
432344 Unhover(i32),
433345 Scrolled(i32, String, Viewport),
434- /// A scroll area, and how far down its content the row that asked to be
435- /// shown was measured to be.
436- Revealed(String, f32),
437346 PickImage,
438347 Picked(Option<PathBuf>),
439348 }
@@ -495,9 +404,12 @@ impl App {
495404 offset_y: 0.0,
496405 });
497406 let jumped = !ask.fresh && ask.tick.is_some() && ask.tick != ask.tick_before;
498- if let Some(node) = ask.reveal {
407+ if let Some(fraction) = ask.reveal {
499408 memo.at_end = false;
500- tasks.push(reveal(ask.name.clone(), node));
409+ tasks.push(iced_scrollable::snap_to(
410+ scroll_id(&ask.name),
411+ RelativeOffset { x: None, y: Some(fraction) },
412+ ));
501413 } else if jumped || (ask.stick && memo.at_end) {
502414 memo.at_end = true;
503415 tasks.push(snap_to_end(&ask.name));
@@ -607,17 +519,6 @@ impl cosmic::Application for App {
607519 Message::Hover(node) => post(node, "hover", String::new(), 0.0),
608520 Message::Unhover(node) => post(node, "unhover", String::new(), 0.0),
609521 Message::Scrolled(node, name, viewport) => self.scrolled(node, name, viewport),
610- // The measurement came back: put the scroll where it says. The
611- // memo is written too, so a list that is unmounted and comes back
612- // opens where the jump left it rather than where it was before.
613- Message::Revealed(name, y) => {
614- let id = scroll_id(&name);
615- if let Some(memo) = self.scrolls.get_mut(&name) {
616- memo.at_end = false;
617- memo.offset_y = y;
618- }
619- return iced_scrollable::scroll_to(id, AbsoluteOffset { x: None, y: Some(y) });
620- }
621522 // The desktop's own chooser, through the portal, on libcosmic's
622523 // executor: it is a D-Bus round trip, and the window keeps
623524 // painting while it is open.
@@ -1184,23 +1085,6 @@ fn element(t: &Tree, id: i32, enabled: bool, in_row: bool) -> Element<'_, Messag
11841085 .into(),
11851086 };
11861087
1187- // Every row of a scroll area carries an id, so the operation in `reveal`
1188- // can find out where one of them actually is.
1189- //
1190- // Every row, and not only the row that is asking to be shown. iced tells
1191- // two widgets apart by their state's type, and a wrapper with no state of
1192- // its own is indistinguishable from the column it wraps — so a wrapper
1193- // that came and went as a row became the target would have the old tree
1194- // reused for the new shape, and the state under it would be read as
1195- // something it is not. That is not a wrong answer, it is a panic in the
1196- // middle of a layout. Whether a node is a row of a scroll area is a
1197- // question about where it sits, and where it sits does not change under
1198- // it.
1199- let el = match t.get(n.parent) {
1200- Some(parent) if parent.tag == "scroll" => widget::id_container(el, here_id(id)).into(),
1201- _ => el,
1202- };
1203-
12041088 // The containers and the entry size themselves above; anything else asked
12051089 // for a width gets it from a wrapper.
12061090 match (n.tag.as_str(), width_request(n)) {
@@ -1637,7 +1521,7 @@ mod tests {
16371521 }
16381522
16391523 #[test]
1640- fn scroll_here_asks_with_the_row_itself_and_goes_on_asking() {
1524+ fn a_new_scroll_here_asks_for_its_row_and_a_standing_one_does_not() {
16411525 let mut t = Tree::default();
16421526 let root = t.root();
16431527 let list = node(&mut t, root, "scroll");
@@ -1646,33 +1530,13 @@ mod tests {
16461530 let before = t.clone();
16471531 t.set(rows[3], "scroll-here", Prop::Bool(true));
16481532
1649- // The row, not a guess at where it sits: only the layout knows that,
1650- // and `reveal` is what goes and asks it. Here the row and the node
1651- // asking are the same; a message row asks from inside itself, and the
1652- // answer is still the row, since the row is what carries an id.
16531533 let asks = scroll_asks(&before, &t);
16541534 assert_eq!(asks.len(), 1);
16551535 assert!(!asks[0].fresh);
1656- assert_eq!(asks[0].reveal, Some(rows[3]));
1536+ assert_eq!(asks[0].reveal, Some(0.75));
16571537
1658- // And it asks again while the row is still asking. It used to ask only
1659- // on the commit the prop arrived, which meant a row not laid out yet —
1660- // a conversation the client has only just switched to — was never
1661- // scrolled to at all.
16621538 let again = scroll_asks(&t, &t);
1663- assert_eq!(again[0].reveal, Some(rows[3]));
1664-
1665- // Nothing asking, nothing to reveal.
1666- t.set(rows[3], "scroll-here", Prop::Bool(false));
1667- let quiet = scroll_asks(&t, &t);
1668- assert_eq!(quiet[0].reveal, None);
1669-
1670- // And a node asking from deeper inside a row still answers with the
1671- // row: that is the thing the layout can be asked about.
1672- let inner = node(&mut t, rows[1], "vbox");
1673- t.set(inner, "scroll-here", Prop::Bool(true));
1674- let deep = scroll_asks(&t, &t);
1675- assert_eq!(deep[0].reveal, Some(rows[1]));
1539+ assert_eq!(again[0].reveal, None);
16761540 }
16771541
16781542 #[test]
@@ -36,8 +36,6 @@ use cosmic::iced::futures::{Stream, StreamExt};
36 use cosmic::iced::widget::container::Style as ContainerStyle;36 use cosmic::iced::widget::container::Style as ContainerStyle;
37 use cosmic::iced::widget::scrollable::{self as iced_scrollable, AbsoluteOffset, RelativeOffset, Viewport};37 use cosmic::iced::widget::scrollable::{self as iced_scrollable, AbsoluteOffset, RelativeOffset, Viewport};
38 use cosmic::iced::widget::text::Wrapping;38 use cosmic::iced::widget::text::Wrapping;
39-use cosmic::iced::advanced::widget as advanced;
40-use cosmic::iced::advanced::widget::operation::scrollable as iced_operation;
41 use cosmic::iced::{Alignment, Background, Border, Color, ContentFit, Font, Length, Padding, Subscription};39 use cosmic::iced::{Alignment, Background, Border, Color, ContentFit, Font, Length, Padding, Subscription};
42 use cosmic::widget::{self, Column, Row};40 use cosmic::widget::{self, Column, Row};
43 use cosmic::{ApplicationExt, Element};41 use cosmic::{ApplicationExt, Element};
@@ -265,8 +263,9 @@ struct ScrollAsk {
265 tick_before: Option<f64>,263 tick_before: Option<f64>,
266 /// Not in the tree before this commit: mounted, or mounted again.264 /// Not in the tree before this commit: mounted, or mounted again.
267 fresh: bool,265 fresh: bool,
268- /// The node asking to be shown, if one is.266+ /// Where, as a fraction of the list, a node that has just been asked to be
269- reveal: Option<i32>,267+ /// shown sits.
268+ reveal: Option<f32>,
270 }269 }
271 270
272 /// Every scroll area in `now`, and what changed about each since `before`.271 /// Every scroll area in `now`, and what changed about each since `before`.
@@ -284,28 +283,23 @@ fn scroll_asks(before: &Tree, now: &Tree) -> Vec<ScrollAsk> {
284 return;283 return;
285 }284 }
286 let name = scroll_name(n, id);285 let name = scroll_name(n, id);
287- // The ROW holding whatever asked to be shown. The row and not the286+ // A row asking to be shown, that was not asking last commit. The
288- // asking node itself, because the row is what carries an id — see287+ // position is the index of the top-level row holding it: exact for a
289- // `element` — and the id is how the layout is asked where it is.288+ // list of rows the same height and close for frq's backlog, and there
290- //289+ // is no layout to ask from here.
291- // This used to answer with the row's index over the row count, which290+ let count = n.children.len();
292- // is a fraction of the SCROLL RANGE rather than of the content — the
293- // two agree only when the viewport is exactly one row tall — and it
294- // assumed every row the same height besides, in a backlog that puts a
295- // one-line message next to a picture. The landing was out by up to a
296- // viewport, worst in the middle of a list.
297- //
298- // While it is asking, not only on the commit it starts: a row that is
299- // not in the tree yet when the ask arrives would otherwise never be
300- // scrolled to at all, and the ask is over in half a second.
301 let mut reveal = None;291 let mut reveal = None;
302- for row in &n.children {292+ for (index, row) in n.children.iter().enumerate() {
303 let mut asked = false;293 let mut asked = false;
304- walk(now, *row, &mut |_, node| {294+ walk(now, *row, &mut |nid, node| {
305- asked |= node.bool("scroll-here") == Some(true);295+ let here = node.bool("scroll-here") == Some(true);
296+ let was = before
297+ .get(nid)
298+ .is_some_and(|old| old.bool("scroll-here") == Some(true));
299+ asked |= here && !was;
306 });300 });
307 if asked {301 if asked {
308- reveal = Some(*row);302+ reveal = Some(index as f32 / (count.saturating_sub(1).max(1)) as f32);
309 break;303 break;
310 }304 }
311 }305 }
@@ -325,88 +319,6 @@ fn snap_to_end(name: &str) -> Task<Message> {
325 iced_scrollable::snap_to(scroll_id(name), RelativeOffset { x: None, y: Some(1.0) })319 iced_scrollable::snap_to(scroll_id(name), RelativeOffset { x: None, y: Some(1.0) })
326 }320 }
327 321
328-/// What a row that can be scrolled to is known by.
329-fn here_id(node: i32) -> widget::Id {
330- widget::Id::new(format!("jolt-here-{node}"))
331-}
332-
333-/// Where `node` sits inside the scroll area called `name`, measured, and then
334-/// the scroll put there.
335-///
336-/// Two steps because the answer is not in the tree. The tree says which row
337-/// asked; only the layout knows how far down the content it ended up, and the
338-/// layout is a thing you can ask questions of exactly once a frame, through an
339-/// `Operation`. So the operation reads the row's bounds and the scroll area's,
340-/// works the offset out, and hands it back as a message that scrolls there.
341-///
342-/// The row is put in the MIDDLE of the viewport rather than against its top
343-/// edge. A line answered three days ago is read with what was said around it,
344-/// and a jump that pins it to the ceiling shows only what came after.
345-fn reveal(name: String, node: i32) -> Task<Message> {
346- let scroll = scroll_id(&name);
347- let target = here_id(node);
348-
349- struct Measure {
350- scroll: widget::Id,
351- target: widget::Id,
352- /// The scroll area: where its viewport starts, how tall it is, and
353- /// how far it is scrolled already.
354- view: Option<(f32, f32, f32)>,
355- /// The row: where it starts and how tall it is.
356- row: Option<(f32, f32)>,
357- }
358-
359- impl advanced::Operation<f32> for Measure {
360- fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn advanced::Operation<f32>)) {
361- operate(self);
362- }
363-
364- fn container(&mut self, id: Option<&widget::Id>, bounds: cosmic::iced::Rectangle) {
365- if id == Some(&self.target) {
366- self.row = Some((bounds.y, bounds.height));
367- }
368- }
369-
370- fn scrollable(
371- &mut self,
372- id: Option<&widget::Id>,
373- bounds: cosmic::iced::Rectangle,
374- _content: cosmic::iced::Rectangle,
375- translation: cosmic::iced::Vector,
376- _state: &mut dyn iced_operation::Scrollable,
377- ) {
378- if id == Some(&self.scroll) {
379- self.view = Some((bounds.y, bounds.height, translation.y));
380- }
381- }
382-
383- fn finish(&self) -> advanced::operation::Outcome<f32> {
384- match (self.view, self.row) {
385- // Both are in window coordinates, so the row's place in the
386- // content is how far it is below the viewport's top edge plus
387- // how far the viewport has already been scrolled.
388- (Some((view_y, view_h, scrolled)), Some((row_y, row_h))) => {
389- let top = row_y - view_y + scrolled;
390- let centred = top - (view_h - row_h).max(0.0) / 2.0;
391- advanced::operation::Outcome::Some(centred.max(0.0))
392- }
393- // The row is not laid out yet — it has only just been mounted,
394- // or it is not in this scroll area at all. Nothing to say, and
395- // the next commit asks again.
396- _ => advanced::operation::Outcome::None,
397- }
398- }
399- }
400-
401- advanced::operate(Measure {
402- scroll,
403- target,
404- view: None,
405- row: None,
406- })
407- .map(move |y| cosmic::Action::App(Message::Revealed(name.clone(), y)))
408-}
409-
410 // --- the app -----------------------------------------------------------------322 // --- the app -----------------------------------------------------------------
411 323
412 struct App {324 struct App {
@@ -431,9 +343,6 @@ enum Message {
431 Hover(i32),343 Hover(i32),
432 Unhover(i32),344 Unhover(i32),
433 Scrolled(i32, String, Viewport),345 Scrolled(i32, String, Viewport),
434- /// A scroll area, and how far down its content the row that asked to be
435- /// shown was measured to be.
436- Revealed(String, f32),
437 PickImage,346 PickImage,
438 Picked(Option<PathBuf>),347 Picked(Option<PathBuf>),
439 }348 }
@@ -495,9 +404,12 @@ impl App {
495 offset_y: 0.0,404 offset_y: 0.0,
496 });405 });
497 let jumped = !ask.fresh && ask.tick.is_some() && ask.tick != ask.tick_before;406 let jumped = !ask.fresh && ask.tick.is_some() && ask.tick != ask.tick_before;
498- if let Some(node) = ask.reveal {407+ if let Some(fraction) = ask.reveal {
499 memo.at_end = false;408 memo.at_end = false;
500- tasks.push(reveal(ask.name.clone(), node));409+ tasks.push(iced_scrollable::snap_to(
410+ scroll_id(&ask.name),
411+ RelativeOffset { x: None, y: Some(fraction) },
412+ ));
501 } else if jumped || (ask.stick && memo.at_end) {413 } else if jumped || (ask.stick && memo.at_end) {
502 memo.at_end = true;414 memo.at_end = true;
503 tasks.push(snap_to_end(&ask.name));415 tasks.push(snap_to_end(&ask.name));
@@ -607,17 +519,6 @@ impl cosmic::Application for App {
607 Message::Hover(node) => post(node, "hover", String::new(), 0.0),519 Message::Hover(node) => post(node, "hover", String::new(), 0.0),
608 Message::Unhover(node) => post(node, "unhover", String::new(), 0.0),520 Message::Unhover(node) => post(node, "unhover", String::new(), 0.0),
609 Message::Scrolled(node, name, viewport) => self.scrolled(node, name, viewport),521 Message::Scrolled(node, name, viewport) => self.scrolled(node, name, viewport),
610- // The measurement came back: put the scroll where it says. The
611- // memo is written too, so a list that is unmounted and comes back
612- // opens where the jump left it rather than where it was before.
613- Message::Revealed(name, y) => {
614- let id = scroll_id(&name);
615- if let Some(memo) = self.scrolls.get_mut(&name) {
616- memo.at_end = false;
617- memo.offset_y = y;
618- }
619- return iced_scrollable::scroll_to(id, AbsoluteOffset { x: None, y: Some(y) });
620- }
621 // The desktop's own chooser, through the portal, on libcosmic's522 // The desktop's own chooser, through the portal, on libcosmic's
622 // executor: it is a D-Bus round trip, and the window keeps523 // executor: it is a D-Bus round trip, and the window keeps
623 // painting while it is open.524 // painting while it is open.
@@ -1184,23 +1085,6 @@ fn element(t: &Tree, id: i32, enabled: bool, in_row: bool) -> Element<'_, Messag
1184 .into(),1085 .into(),
1185 };1086 };
1186 1087
1187- // Every row of a scroll area carries an id, so the operation in `reveal`
1188- // can find out where one of them actually is.
1189- //
1190- // Every row, and not only the row that is asking to be shown. iced tells
1191- // two widgets apart by their state's type, and a wrapper with no state of
1192- // its own is indistinguishable from the column it wraps — so a wrapper
1193- // that came and went as a row became the target would have the old tree
1194- // reused for the new shape, and the state under it would be read as
1195- // something it is not. That is not a wrong answer, it is a panic in the
1196- // middle of a layout. Whether a node is a row of a scroll area is a
1197- // question about where it sits, and where it sits does not change under
1198- // it.
1199- let el = match t.get(n.parent) {
1200- Some(parent) if parent.tag == "scroll" => widget::id_container(el, here_id(id)).into(),
1201- _ => el,
1202- };
1203-
1204 // The containers and the entry size themselves above; anything else asked1088 // The containers and the entry size themselves above; anything else asked
1205 // for a width gets it from a wrapper.1089 // for a width gets it from a wrapper.
1206 match (n.tag.as_str(), width_request(n)) {1090 match (n.tag.as_str(), width_request(n)) {
@@ -1637,7 +1521,7 @@ mod tests {
1637 }1521 }
1638 1522
1639 #[test]1523 #[test]
1640- fn scroll_here_asks_with_the_row_itself_and_goes_on_asking() {1524+ fn a_new_scroll_here_asks_for_its_row_and_a_standing_one_does_not() {
1641 let mut t = Tree::default();1525 let mut t = Tree::default();
1642 let root = t.root();1526 let root = t.root();
1643 let list = node(&mut t, root, "scroll");1527 let list = node(&mut t, root, "scroll");
@@ -1646,33 +1530,13 @@ mod tests {
1646 let before = t.clone();1530 let before = t.clone();
1647 t.set(rows[3], "scroll-here", Prop::Bool(true));1531 t.set(rows[3], "scroll-here", Prop::Bool(true));
1648 1532
1649- // The row, not a guess at where it sits: only the layout knows that,
1650- // and `reveal` is what goes and asks it. Here the row and the node
1651- // asking are the same; a message row asks from inside itself, and the
1652- // answer is still the row, since the row is what carries an id.
1653 let asks = scroll_asks(&before, &t);1533 let asks = scroll_asks(&before, &t);
1654 assert_eq!(asks.len(), 1);1534 assert_eq!(asks.len(), 1);
1655 assert!(!asks[0].fresh);1535 assert!(!asks[0].fresh);
1656- assert_eq!(asks[0].reveal, Some(rows[3]));1536+ assert_eq!(asks[0].reveal, Some(0.75));
1657 1537
1658- // And it asks again while the row is still asking. It used to ask only
1659- // on the commit the prop arrived, which meant a row not laid out yet —
1660- // a conversation the client has only just switched to — was never
1661- // scrolled to at all.
1662 let again = scroll_asks(&t, &t);1538 let again = scroll_asks(&t, &t);
1663- assert_eq!(again[0].reveal, Some(rows[3]));1539+ assert_eq!(again[0].reveal, None);
1664-
1665- // Nothing asking, nothing to reveal.
1666- t.set(rows[3], "scroll-here", Prop::Bool(false));
1667- let quiet = scroll_asks(&t, &t);
1668- assert_eq!(quiet[0].reveal, None);
1669-
1670- // And a node asking from deeper inside a row still answers with the
1671- // row: that is the thing the layout can be asked about.
1672- let inner = node(&mut t, rows[1], "vbox");
1673- t.set(inner, "scroll-here", Prop::Bool(true));
1674- let deep = scroll_asks(&t, &t);
1675- assert_eq!(deep[0].reveal, Some(rows[1]));
1676 }1540 }
1677 1541
1678 #[test]1542 #[test]