use std::panic::Location;
use crate::anim::Timing;
use crate::cursor::Cursor;
use crate::metrics::MetricsRole;
use crate::style::StyleProfile;
use crate::tokens;
use crate::tree::*;
use crate::{IntoIconSource, icon, text};
#[track_caller]
pub fn button(label: impl Into<String>) -> El {
El::new(Kind::Custom("button"))
.at_loc(Location::caller())
.style_profile(StyleProfile::Solid)
.metrics_role(MetricsRole::Button)
.surface_role(SurfaceRole::Raised)
.focusable()
.paint_overflow(Sides::all(tokens::RING_WIDTH))
.hit_overflow(Sides::all(tokens::HIT_OVERFLOW))
.cursor(Cursor::Pointer)
.text(label)
.text_align(TextAlign::Center)
.text_role(TextRole::Label)
.fill(tokens::SECONDARY)
.stroke(tokens::BORDER)
.text_color(tokens::SECONDARY_FOREGROUND)
.default_radius(tokens::RADIUS_MD)
.default_width(Size::Hug)
.default_height(Size::Fixed(tokens::CONTROL_HEIGHT))
.default_padding(Sides::xy(tokens::SPACE_3, 0.0))
.animate(Timing::SPRING_QUICK)
}
#[track_caller]
pub fn icon_button(source: impl IntoIconSource) -> El {
El::new(Kind::Custom("icon_button"))
.at_loc(Location::caller())
.style_profile(StyleProfile::Solid)
.metrics_role(MetricsRole::IconButton)
.surface_role(SurfaceRole::Raised)
.focusable()
.paint_overflow(Sides::all(tokens::RING_WIDTH))
.hit_overflow(Sides::all(tokens::HIT_OVERFLOW))
.cursor(Cursor::Pointer)
.icon_source(source)
.icon_size(tokens::ICON_SM)
.icon_stroke_width(2.0)
.fill(tokens::SECONDARY)
.stroke(tokens::BORDER)
.text_color(tokens::SECONDARY_FOREGROUND)
.default_radius(tokens::RADIUS_MD)
.default_width(Size::Fixed(tokens::CONTROL_HEIGHT))
.default_height(Size::Fixed(tokens::CONTROL_HEIGHT))
.animate(Timing::SPRING_QUICK)
}
#[track_caller]
pub fn button_with_icon(source: impl IntoIconSource, label: impl Into<String>) -> El {
El::new(Kind::Custom("button_with_icon"))
.at_loc(Location::caller())
.style_profile(StyleProfile::Solid)
.metrics_role(MetricsRole::Button)
.surface_role(SurfaceRole::Raised)
.focusable()
.paint_overflow(Sides::all(tokens::RING_WIDTH))
.hit_overflow(Sides::all(tokens::HIT_OVERFLOW))
.cursor(Cursor::Pointer)
.axis(Axis::Row)
.default_gap(tokens::SPACE_2)
.align(Align::Center)
.justify(Justify::Center)
.child(
icon(source)
.icon_size(tokens::ICON_SM)
.color(tokens::SECONDARY_FOREGROUND),
)
.child(text(label).label())
.fill(tokens::SECONDARY)
.stroke(tokens::BORDER)
.text_color(tokens::SECONDARY_FOREGROUND)
.default_radius(tokens::RADIUS_MD)
.default_width(Size::Hug)
.default_height(Size::Fixed(tokens::CONTROL_HEIGHT))
.default_padding(Sides::xy(tokens::SPACE_3, 0.0))
.animate(Timing::SPRING_QUICK)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn buttons_ease_variant_changes() {
assert!(button("Save").animate.is_some());
assert!(button("Save").primary().animate.is_some());
assert!(icon_button("settings").animate.is_some());
assert!(button_with_icon("folder", "Open").animate.is_some());
}
#[test]
fn buttons_have_conservative_default_hit_overflow() {
assert_eq!(
button("Save").hit_overflow,
Sides::all(tokens::HIT_OVERFLOW)
);
assert_eq!(
icon_button("settings").hit_overflow,
Sides::all(tokens::HIT_OVERFLOW)
);
assert_eq!(
button_with_icon("folder", "Open").hit_overflow,
Sides::all(tokens::HIT_OVERFLOW)
);
}
}