142 lines
3.5 KiB
Rust
142 lines
3.5 KiB
Rust
/// ScrollView — scrollable container.
|
|
///
|
|
/// Wraps content that may exceed the available space. Scrolling axis can be
|
|
/// vertical (default), horizontal, or both. On platforms with native scroll
|
|
/// behaviors (iOS, Android), the backend translates this to a native scroll
|
|
/// container — you get momentum, overscroll, pull-to-refresh for free.
|
|
|
|
use el_style::modifier::{StyleModifier, StyleSet};
|
|
|
|
/// Which axis (or axes) can scroll.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum ScrollAxis {
|
|
/// Vertical scrolling only (default). Most content views.
|
|
Vertical,
|
|
/// Horizontal scrolling only. Carousels, horizontal lists.
|
|
Horizontal,
|
|
/// Free scrolling in both directions. Maps, canvases.
|
|
Both,
|
|
}
|
|
|
|
/// Scroll indicator visibility.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum ScrollIndicator {
|
|
/// Show when scrolling, hide otherwise (platform default).
|
|
Automatic,
|
|
/// Always show.
|
|
Always,
|
|
/// Never show.
|
|
Never,
|
|
}
|
|
|
|
/// A scrollable container.
|
|
#[derive(Debug, Clone)]
|
|
pub struct ScrollView {
|
|
pub axis: ScrollAxis,
|
|
pub indicator: ScrollIndicator,
|
|
/// Whether the user can zoom (pinch-to-zoom). Default: false.
|
|
pub zoomable: bool,
|
|
/// Minimum zoom scale (only relevant when zoomable = true).
|
|
pub min_zoom: f32,
|
|
/// Maximum zoom scale (only relevant when zoomable = true).
|
|
pub max_zoom: f32,
|
|
/// Whether to clip content to the scroll view bounds. Default: true.
|
|
pub clips_to_bounds: bool,
|
|
pub style: StyleSet,
|
|
}
|
|
|
|
impl Default for ScrollView {
|
|
fn default() -> Self {
|
|
Self {
|
|
axis: ScrollAxis::Vertical,
|
|
indicator: ScrollIndicator::Automatic,
|
|
zoomable: false,
|
|
min_zoom: 1.0,
|
|
max_zoom: 3.0,
|
|
clips_to_bounds: true,
|
|
style: StyleSet::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ScrollView {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
pub fn horizontal() -> Self {
|
|
Self {
|
|
axis: ScrollAxis::Horizontal,
|
|
..Self::default()
|
|
}
|
|
}
|
|
|
|
pub fn both_axes() -> Self {
|
|
Self {
|
|
axis: ScrollAxis::Both,
|
|
..Self::default()
|
|
}
|
|
}
|
|
|
|
pub fn indicator(mut self, indicator: ScrollIndicator) -> Self {
|
|
self.indicator = indicator;
|
|
self
|
|
}
|
|
|
|
pub fn zoomable(mut self, min: f32, max: f32) -> Self {
|
|
self.zoomable = true;
|
|
self.min_zoom = min;
|
|
self.max_zoom = max;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl StyleModifier for ScrollView {
|
|
fn style_mut(&mut self) -> &mut StyleSet {
|
|
&mut self.style
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn scroll_default_is_vertical() {
|
|
let sv = ScrollView::new();
|
|
assert_eq!(sv.axis, ScrollAxis::Vertical);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_horizontal_constructor() {
|
|
let sv = ScrollView::horizontal();
|
|
assert_eq!(sv.axis, ScrollAxis::Horizontal);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_both_axes() {
|
|
let sv = ScrollView::both_axes();
|
|
assert_eq!(sv.axis, ScrollAxis::Both);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_zoomable() {
|
|
let sv = ScrollView::new().zoomable(0.5, 4.0);
|
|
assert!(sv.zoomable);
|
|
assert_eq!(sv.min_zoom, 0.5);
|
|
assert_eq!(sv.max_zoom, 4.0);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_clips_by_default() {
|
|
let sv = ScrollView::new();
|
|
assert!(sv.clips_to_bounds);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_indicator_setting() {
|
|
let sv = ScrollView::new().indicator(ScrollIndicator::Never);
|
|
assert_eq!(sv.indicator, ScrollIndicator::Never);
|
|
}
|
|
}
|