Files
el/ui/vessels/el-layout/src/scroll.rs
T

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);
}
}