based/src/ui/primitives/scroll.rs
2025-01-21 09:00:45 +01:00

234 lines
5.6 KiB
Rust

use super::{margin::Margin, padding::PaddingWidget};
use crate::ui::UIWidget;
use maud::{Markup, Render, html};
#[allow(non_snake_case)]
pub fn Scroll<T: UIWidget + 'static>(inner: T) -> ScrollWidget {
ScrollWidget(Box::new(inner), true, None, None, None, None, false)
}
pub struct ScrollWidget(
Box<dyn UIWidget>,
bool,
Option<Margin>,
Option<PaddingWidget>,
Option<Overscroll>,
Option<SnapType>,
bool,
);
impl ScrollWidget {
pub fn smooth(mut self, value: bool) -> Self {
self.1 = value;
self
}
pub fn scroll_margin(mut self, margin: Margin) -> Self {
self.2 = Some(margin);
self
}
pub fn scroll_padding(mut self, padding: PaddingWidget) -> Self {
self.3 = Some(padding);
self
}
pub fn overscroll(mut self, behaviour: Overscroll) -> Self {
self.4 = Some(behaviour);
self
}
pub fn snap(mut self, kind: SnapType) -> Self {
self.5 = Some(kind);
self
}
pub fn skip_snap(mut self) -> Self {
self.6 = true;
self
}
}
impl Render for ScrollWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for ScrollWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
let mut ret = Vec::new();
if self.1 {
ret.push("scroll-smooth".to_string());
}
if let Some(margin) = &self.2 {
let classes = margin
.base_class()
.into_iter()
.map(|x| format!("scroll-{x}"))
.collect::<Vec<_>>();
ret.extend_from_slice(&classes);
}
if let Some(padding) = &self.3 {
let classes = padding
.base_class()
.into_iter()
.map(|x| format!("scroll-{x}"))
.collect::<Vec<_>>();
ret.extend_from_slice(&classes);
}
if let Some(overscroll) = &self.4 {
ret.push(overscroll.to_value().to_string());
}
if let Some(snap) = &self.5 {
ret.push(snap.to_value().to_string());
}
if self.6 {
ret.push("snap-normal".to_string());
} else {
ret.push("snap-always".to_string());
}
ret
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.0.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.0.as_ref().can_inherit() {
self.0
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.0.as_ref())
}
}
}
}
}
pub enum Overscroll {
Auto,
Contain,
None,
YAuto,
YContain,
YNone,
XAuto,
XContain,
XNone,
}
impl Overscroll {
pub const fn to_value(&self) -> &str {
match self {
Overscroll::Auto => "overscroll-auto",
Overscroll::Contain => "overscroll-contain",
Overscroll::None => "overscroll-none",
Overscroll::YAuto => "overscroll-y-auto",
Overscroll::YContain => "overscroll-y-contain",
Overscroll::YNone => "overscroll-y-none",
Overscroll::XAuto => "overscroll-x-auto",
Overscroll::XContain => "overscroll-x-contain",
Overscroll::XNone => "overscroll-x-none",
}
}
}
pub enum SnapType {
None,
X,
Y,
Both,
Mandatory,
Proximity,
}
impl SnapType {
pub const fn to_value(&self) -> &str {
match self {
SnapType::None => "snap-none",
SnapType::X => "snap-x",
SnapType::Y => "snap-y",
SnapType::Both => "snap-both",
SnapType::Mandatory => "snap-mandatory",
SnapType::Proximity => "snap-proximity",
}
}
}
pub struct SnapAlign(Box<dyn UIWidget>, String);
impl SnapAlign {
#[allow(non_snake_case)]
pub fn Start<T: UIWidget + 'static>(inner: T) -> Self {
Self(Box::new(inner), "snap-start".to_string())
}
#[allow(non_snake_case)]
pub fn End<T: UIWidget + 'static>(inner: T) -> Self {
Self(Box::new(inner), "snap-end".to_string())
}
#[allow(non_snake_case)]
pub fn Center<T: UIWidget + 'static>(inner: T) -> Self {
Self(Box::new(inner), "snap-center".to_string())
}
#[allow(non_snake_case)]
pub fn None<T: UIWidget + 'static>(inner: T) -> Self {
Self(Box::new(inner), "snap-align-none".to_string())
}
}
impl Render for SnapAlign {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for SnapAlign {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
vec![self.1.clone()]
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.0.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.0.as_ref().can_inherit() {
self.0
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.0.as_ref())
}
}
}
}
}