nav-scrollabe: detect size to determine if needs scrolling, msg when ready

[?]
Jun 28, 2025, 9:47 AM
WIFVLV376GIMVTGVXBFWIPU7FR5O3SGIQ343KIJEBWB6UURTJZJQC

Dependencies

Change contents

  • edit in iced_nav_scrollable/src/lib.rs at line 6
    [6.309]
    [6.309]
    use iced_futures::MaybeSend;
  • edit in iced_nav_scrollable/src/lib.rs at line 11
    [6.378][6.378:457]()
    pub offsets_ready: bool,
    pub offsets: Vec<f32>,
    pub y_offset: f32,
  • replacement in iced_nav_scrollable/src/lib.rs at line 12
    [6.485][6.485:533]()
    pub sections: IndexMap<container::Id, f32>,
    [6.485]
    [6.533]
    pub height: f32,
    pub offset: f32,
    pub needs_scrolling: NeedsScrolling,
    pub generation: usize,
    pub section_heights: IndexMap<container::Id, f32>,
    pub section_offsets: Vec<f32>,
    pub pending_tasks: Option<usize>,
  • replacement in iced_nav_scrollable/src/lib.rs at line 24
    [6.595][6.595:645]()
    GotHeight { id: container::Id, height: f32 },
    [6.595]
    [6.645]
    GotScrollableHeight {
    height: f32,
    generation: usize,
    },
    GotSectionHeight {
    id: container::Id,
    height: f32,
    generation: usize,
    },
  • edit in iced_nav_scrollable/src/lib.rs at line 36
    [6.717]
    [6.717]
    }
    #[derive(Debug, Clone, Copy)]
    pub enum NeedsScrolling {
    Yes,
    No,
  • replacement in iced_nav_scrollable/src/lib.rs at line 45
    [6.787][6.787:861]()
    let (sections, tasks): (IndexMap<_, _>, Vec<_>) = (0..contents_count)
    [6.787]
    [6.861]
    let generation = 0;
    let (section_heights, mut tasks): (IndexMap<_, _>, Vec<_>) = (0
    ..contents_count)
  • replacement in iced_nav_scrollable/src/lib.rs at line 54
    [6.1017][6.1017:1115]()
    let task =
    height_task(id.clone()).map(move |height| Msg::GotHeight {
    [6.1017]
    [6.1115]
    let task = container_height_task(id.clone()).map(move |height| {
    Msg::GotSectionHeight {
  • replacement in iced_nav_scrollable/src/lib.rs at line 58
    [6.1185][6.1185:1205]()
    });
    [6.1185]
    [6.1205]
    generation,
    }
    });
  • edit in iced_nav_scrollable/src/lib.rs at line 66
    [6.1304]
    [6.1304]
    tasks
    .push(scrollable_height_task(id.clone()).map(move |height| {
    Msg::GotScrollableHeight { height, generation }
    }));
    // To be computed from sizes once tasks complete
    let section_offsets = vec![0.0; section_heights.len()];
    // 1 task to get the scrollable height
    let pending_tasks = Some(contents_count + 1);
  • edit in iced_nav_scrollable/src/lib.rs at line 76
    [6.1334][6.1334:1504]()
    offsets_ready: false,
    // To be computed from sizes once tasks complete
    offsets: vec![0.0; sections.len()],
    y_offset: 0.0,
  • replacement in iced_nav_scrollable/src/lib.rs at line 77
    [6.1520][6.1520:1542]()
    sections,
    [6.1520]
    [6.1542]
    height: 0.0,
    offset: 0.0,
    needs_scrolling: NeedsScrolling::Yes,
    generation,
    section_heights,
    section_offsets,
    // 1 task to get the scrollable height
    pending_tasks,
  • replacement in iced_nav_scrollable/src/lib.rs at line 94
    [6.1687][6.1687:1751]()
    pub fn update(nav: &mut NavScrollable, msg: Msg) -> Task<Msg> {
    [6.1687]
    [6.1751]
    pub fn update<Message, MapFn, OnReady>(
    nav: &mut NavScrollable,
    msg: Msg,
    map_msg: MapFn,
    on_ready: OnReady,
    ) -> Task<Message>
    where
    Message: MaybeSend + 'static,
    MapFn: Fn(Msg) -> Message + MaybeSend + 'static,
    OnReady: Fn(NeedsScrolling) -> Message,
    {
  • replacement in iced_nav_scrollable/src/lib.rs at line 108
    [6.1832][6.1832:2110]()
    Task::batch(nav.sections.keys().map(|id| {
    let id_clone = id.clone();
    height_task(id.clone()).map(move |height| Msg::GotHeight {
    id: id_clone.clone(),
    height,
    })
    }))
    [6.1832]
    [6.2110]
    let generation = nav.generation;
    // 1 task to get the scrollable height
    nav.pending_tasks = Some(nav.section_heights.len() + 1);
    Task::batch(
    nav.section_heights
    .keys()
    .map(|id| {
    let id_clone = id.clone();
    container_height_task(id.clone()).map(move |height| {
    Msg::GotSectionHeight {
    id: id_clone.clone(),
    height,
    generation,
    }
    })
    })
    .chain([scrollable_height_task(nav.id.clone()).map(
    move |height| Msg::GotScrollableHeight {
    height,
    generation,
    },
    )]),
    )
    .map(map_msg)
    }
    Msg::GotScrollableHeight { height, generation } => {
    if generation == nav.generation {
    nav.height = height;
    if let Some(offsets) = nav.pending_tasks.as_mut() {
    *offsets -= 1;
    update_offsets_if_ready(nav);
    if nav.pending_tasks.is_none() {
    return Task::done(on_ready(nav.needs_scrolling));
    }
    }
    }
    Task::none()
  • replacement in iced_nav_scrollable/src/lib.rs at line 148
    [6.2120][6.2120:2240]()
    Msg::GotHeight { id, height } => {
    reset_offsets(nav);
    nav.sections.insert(id, height);
    [6.2120]
    [6.2240]
    Msg::GotSectionHeight {
    id,
    height,
    generation,
    } => {
    if generation == nav.generation {
    nav.section_heights.insert(id, height);
    if let Some(offsets) = nav.pending_tasks.as_mut() {
    *offsets -= 1;
    update_offsets_if_ready(nav);
    if nav.pending_tasks.is_none() {
    return Task::done(on_ready(nav.needs_scrolling));
    }
    }
    }
  • replacement in iced_nav_scrollable/src/lib.rs at line 167
    [6.2312][6.2312:2369]()
    nav.y_offset = viewport.absolute_offset().y;
    [6.2312]
    [6.2369]
    nav.offset = viewport.absolute_offset().y;
  • replacement in iced_nav_scrollable/src/lib.rs at line 171
    [6.2435][6.2435:2614]()
    update_offsets(nav);
    if nav.offsets_ready {
    if let Some(y) =
    nav.offsets.iter().find(|offset| *offset > &nav.y_offset)
    [6.2435]
    [6.2614]
    if nav.pending_tasks.is_none() {
    if let Some(y) = nav
    .section_offsets
    .iter()
    .find(|offset| *offset > &nav.offset)
  • replacement in iced_nav_scrollable/src/lib.rs at line 186
    [6.2913][6.2913:2981]()
    update_offsets(nav);
    if nav.offsets_ready {
    [6.2913]
    [6.2981]
    if nav.pending_tasks.is_none() {
  • replacement in iced_nav_scrollable/src/lib.rs at line 188
    [6.3018][6.3018:3047]()
    .offsets
    [6.3018]
    [6.3047]
    .section_offsets
  • replacement in iced_nav_scrollable/src/lib.rs at line 191
    [6.3102][6.3102:3162]()
    .find(|offset| *offset < &nav.y_offset)
    [6.3102]
    [6.3162]
    .find(|offset| *offset < &nav.offset)
  • replacement in iced_nav_scrollable/src/lib.rs at line 206
    [6.3546][6.3546:3592]()
    pub fn view<'a, Message, Theme, Renderer, F>(
    [6.3546]
    [6.3592]
    pub fn view<'a, Message, Theme, Renderer, MapFn>(
  • replacement in iced_nav_scrollable/src/lib.rs at line 210
    [6.3724][6.3724:3740]()
    map_msg: F,
    [6.3724]
    [6.3740]
    map_msg: MapFn,
  • replacement in iced_nav_scrollable/src/lib.rs at line 216
    [6.3909][6.3909:3941]()
    F: Fn(Msg) -> Message + 'a,
    [6.3909]
    [6.3941]
    MapFn: Fn(Msg) -> Message + 'a,
  • replacement in iced_nav_scrollable/src/lib.rs at line 218
    [6.3943][6.3943:4211]()
    debug_assert_eq!(nav.sections.len(), children.len(), "The `NavScrollable` was most likely initialized with a count different from the number of actual children given to the the view function. Count is {}, but got {} children", nav.sections.len(), children.len());
    [6.3943]
    [6.4211]
    debug_assert_eq!(nav.section_heights.len(), children.len(), "The `NavScrollable` was most likely initialized with a count different from the number of actual children given to the the view function. Count is {}, but got {} children", nav.section_heights.len(), children.len());
  • replacement in iced_nav_scrollable/src/lib.rs at line 222
    [6.4261][6.4261:4295]()
    .zip(nav.sections.keys())
    [6.4261]
    [6.4295]
    .zip(nav.section_heights.keys())
  • replacement in iced_nav_scrollable/src/lib.rs at line 232
    [6.4602][6.4602:4633]()
    nav.offsets_ready = false;
    [6.4602]
    [6.4633]
    nav.section_offsets
    .iter_mut()
    .for_each(|offset| *offset = 0.0);
    nav.generation = nav.generation.wrapping_add(1);
  • replacement in iced_nav_scrollable/src/lib.rs at line 238
    [6.4636][6.4636:4774]()
    fn update_offsets(nav: &mut NavScrollable) {
    if !nav.offsets_ready {
    debug_assert_eq!(nav.sections.len(), nav.offsets.len());
    [6.4636]
    [6.4774]
    fn update_offsets_if_ready(nav: &mut NavScrollable) {
    if nav.pending_tasks == Some(0) {
    debug_assert_eq!(nav.section_heights.len(), nav.section_offsets.len());
  • replacement in iced_nav_scrollable/src/lib.rs at line 242
    [6.4805][6.4805:5103]()
    nav.sections.values().enumerate().for_each(|(i, height)| {
    // The current offset is the value of the acc
    nav.offsets[i] = acc;
    // Increment the acc with the height of this section
    acc += *height;
    });
    nav.offsets_ready = true;
    [6.4805]
    [6.5103]
    nav.section_heights
    .values()
    .enumerate()
    .for_each(|(i, height)| {
    // The current offset is the value of the acc
    nav.section_offsets[i] = acc;
    // Increment the acc with the height of this section
    acc += *height;
    });
    nav.needs_scrolling = if acc > nav.height {
    NeedsScrolling::Yes
    } else {
    NeedsScrolling::No
    };
    nav.pending_tasks = None;
    }
    }
    /// Produces a [`Task`] that queries the height of the contents of [`Scrollable`] with the
    /// given [`Id`].
    fn scrollable_height_task(id: impl Into<scrollable::Id>) -> Task<f32> {
    let id = id.into();
    struct SizeOp {
    target: advanced::widget::Id,
    height: Option<f32>,
    }
    impl advanced::widget::Operation<f32> for SizeOp {
    fn scrollable(
    &mut self,
    id: Option<&advanced::widget::Id>,
    _bounds: Rectangle,
    content_bounds: Rectangle,
    _translation: iced::Vector,
    _state: &mut dyn advanced::widget::operation::Scrollable,
    ) {
    if id == Some(&self.target) {
    dbg!(&_bounds, &content_bounds);
    self.height = Some(content_bounds.height);
    return;
    }
    }
    fn container(
    &mut self,
    _id: Option<&advanced::widget::Id>,
    _bounds: Rectangle,
    operate_on_children: &mut dyn FnMut(
    &mut dyn advanced::widget::Operation<f32>,
    ),
    ) {
    operate_on_children(self);
    }
    fn finish(&self) -> advanced::widget::operation::Outcome<f32> {
    advanced::widget::operation::Outcome::Some(
    self.height.expect("Must be able to determine the size. If this even panics, make the height optional and re-try the task when None"),
    )
    }
  • edit in iced_nav_scrollable/src/lib.rs at line 303
    [6.5109]
    [6.5109]
    advanced::widget::operate(SizeOp {
    target: id.into(),
    height: None,
    })
  • replacement in iced_nav_scrollable/src/lib.rs at line 312
    [6.5208][6.5208:5268]()
    fn height_task(id: impl Into<container::Id>) -> Task<f32> {
    [6.5208]
    [6.5268]
    fn container_height_task(id: impl Into<container::Id>) -> Task<f32> {
  • edit in iced_nav_scrollable/Cargo.toml at line 13
    [6.6625]
    [6.6625]
    workspace = true
    [dependencies.iced_futures]
  • edit in Cargo.toml at line 42
    [3.1060]
    [4.29313]
    [workspace.dependencies.iced_futures]
    git = "https://github.com/iced-rs/iced"
    rev = "c952ea8485b00e58bdff153989f708553272e131"
    # path = "../iced/futures"
  • replacement in Cargo.lock at line 446
    [3.2021][3.2021:2039]()
    version = "0.8.3"
    [3.2021]
    [3.2039]
    version = "0.8.4"
  • replacement in Cargo.lock at line 448
    [3.2104][3.2104:2182]()
    checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e"
    [3.2104]
    [3.2182]
    checksum = "19135c0c7a60bfee564dbe44ab5ce0557c6bf3884e5291a50be76a15640c4fbd"
  • replacement in Cargo.lock at line 1889
    [3.3779][3.3779:3798]()
    version = "0.13.1"
    [3.3779]
    [3.3798]
    version = "0.13.3"
  • replacement in Cargo.lock at line 1891
    [3.3863][3.3863:3941]()
    checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2"
    [3.3863]
    [3.3941]
    checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
  • edit in Cargo.lock at line 2102
    [6.6884]
    [6.6884]
    "iced_futures",
  • replacement in Cargo.lock at line 2438
    [3.4428][5.5204:5222]()
    version = "0.2.2"
    [3.4428]
    [3.4446]
    version = "0.2.3"
  • replacement in Cargo.lock at line 2440
    [3.4511][5.5223:5301]()
    checksum = "14d75c7014ddab93c232bc6bb9f64790d3dfd1d605199acd4b40b6d69e691e9f"
    [3.4511]
    [3.4589]
    checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b"
  • replacement in Cargo.lock at line 2644
    [3.5370][3.5370:5388]()
    version = "0.3.1"
    [3.5370]
    [3.5388]
    version = "0.3.2"
  • replacement in Cargo.lock at line 2646
    [3.5453][3.5453:5531]()
    checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
    [3.5453]
    [2.43754]
    checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
  • replacement in Cargo.lock at line 4066
    [3.7580][3.7580:7599]()
    version = "1.0.16"
    [3.7580]
    [3.7599]
    version = "1.0.17"
  • replacement in Cargo.lock at line 4068
    [3.7664][3.7664:7742]()
    checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30"
    [3.7664]
    [3.7742]
    checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
  • replacement in Cargo.lock at line 4233
    [3.8874][3.8874:8894]()
    version = "0.11.12"
    [3.8874]
    [3.8894]
    version = "0.11.20"
  • replacement in Cargo.lock at line 4235
    [3.8959][3.8959:9037]()
    checksum = "d6a5f31fcf7500f9401fea858ea4ab5525c99f2322cfcee732c0e6c74208c0c6"
    [3.8959]
    [3.9037]
    checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b"
  • replacement in Cargo.lock at line 6780
    [3.12174][5.17258:17277]()
    version = "0.4.17"
    [3.12174]
    [3.12193]
    version = "0.4.18"
  • replacement in Cargo.lock at line 6782
    [3.12258][5.17278:17356]()
    checksum = "0f6fe2e33d02a98ee64423802e16df3de99c43e5cf5ff983767e1128b394c8ac"
    [3.12258]
    [3.12336]
    checksum = "7384255a918371b5af158218d131530f694de9ad3815ebdd0453a940485cb0fa"