use crate::prelude::*; pub struct Scroll { inner: StrongWidget, axis: Axis, amt: f32, snap_end: bool, container_len: f32, content_len: f32, } impl Widget for Scroll { fn draw(&mut self, painter: &mut Painter) -> Size { let output_len = painter.output_len(self.axis); // Its size is its content's, whatever box that is scrolled within. let container_len = UiScalar::px(painter.px_len_for_draw(self.axis)); // Draw in the whole container only when its scrolling-axis length is // not already known, then place it at the scrolled offset. let known_len = painter.known_len(&self.inner, self.axis, UiRegion::FULL); let measured = known_len.is_none(); let child = measured.then(|| painter.place(&self.inner, UiRegion::FULL).size()); let content_len = known_len .unwrap_or_else(|| child.unwrap().axis(self.axis)) .apply_rest() .within_len(container_len) .to_px(output_len); self.container_len = container_len.to_px(output_len); self.content_len = content_len; if self.snap_end { self.amt = self.content_len - self.container_len; } self.update_amt(); let mut region = UiRegion::FULL.offset(Vec2::from_axis(self.axis, -self.amt, 0.0)); region.axis_mut(self.axis).end = region.axis(self.axis).start.offset(self.content_len); let placed = painter.place(&self.inner, region).size(); child.unwrap_or(placed) } } impl Scroll { pub fn new(inner: StrongWidget, axis: Axis) -> Self { Self { inner, axis, amt: 0.0, snap_end: true, container_len: 0.0, content_len: 0.0, } } pub fn update_amt(&mut self) { self.amt = self.amt.max(0.0); let len = (self.content_len - self.container_len).max(0.0); self.amt = self.amt.min(len); self.snap_end = self.amt == len; } pub fn scroll(&mut self, amt: f32) { self.amt -= amt; self.update_amt(); } }