llimphi_widget_fab/
lib.rs1#![forbid(unsafe_code)]
13
14use llimphi_ui::Shadow;
15use llimphi_ui::llimphi_layout::taffy::{
16 prelude::{length, Size, Style},
17 AlignItems, JustifyContent,
18};
19use llimphi_ui::llimphi_raster::peniko::Color;
20use llimphi_ui::llimphi_text::Alignment;
21use llimphi_ui::View;
22use llimphi_theme::{elevation, motion, Theme};
23
24#[derive(Debug, Clone, Copy)]
29pub enum FabSize {
30 Regular,
31 Mini,
32}
33
34impl FabSize {
35 pub fn px(self) -> f32 {
36 match self {
37 FabSize::Regular => 56.0,
38 FabSize::Mini => 40.0,
39 }
40 }
41}
42
43#[derive(Debug, Clone, Copy)]
45pub struct FabPalette {
46 pub bg: Color,
48 pub fg: Color,
50}
51
52impl FabPalette {
53 pub fn from_theme(t: &Theme) -> Self {
54 Self {
55 bg: t.accent,
56 fg: Color::from_rgba8(255, 255, 255, 255),
59 }
60 }
61}
62
63pub fn fab_view<Msg: Clone + 'static>(
66 glyph: impl Into<String>,
67 size: FabSize,
68 key: u64,
69 palette: &FabPalette,
70 on_click: Msg,
71) -> View<Msg> {
72 let s = size.px();
73 let (a, blur, dy) = elevation::E3;
74 let shadow = Shadow {
75 color: Color::from_rgba8(0, 0, 0, a),
76 blur,
77 dx: 0.0,
78 dy,
79 spread: 0.0,
80 };
81 let glyph: String = glyph.into();
82 let aria = glyph.clone();
83 View::new(Style {
84 size: Size { width: length(s), height: length(s) },
85 align_items: Some(AlignItems::Center),
86 justify_content: Some(JustifyContent::Center),
87 ..Default::default()
88 })
89 .fill(palette.bg)
90 .radius((s as f64) * 0.5)
91 .shadow(shadow)
92 .animated_pop_in(key, motion::FAST)
93 .text_aligned(
94 glyph,
95 (s * 0.42).round(),
96 palette.fg,
97 Alignment::Center,
98 )
99 .role(llimphi_ui::Role::Button)
103 .aria_label(aria)
104 .on_click(on_click)
105 .cursor(llimphi_ui::Cursor::Pointer)
106}
107
108pub fn fab_extended<Msg: Clone + 'static>(
111 label: impl Into<String>,
112 key: u64,
113 palette: &FabPalette,
114 on_click: Msg,
115) -> View<Msg> {
116 let label: String = label.into();
117 let h = 48.0_f32;
118 let (a, blur, dy) = elevation::E3;
119 let shadow = Shadow {
120 color: Color::from_rgba8(0, 0, 0, a),
121 blur,
122 dx: 0.0,
123 dy,
124 spread: 0.0,
125 };
126 View::new(Style {
127 size: Size {
128 width: llimphi_ui::llimphi_layout::taffy::prelude::auto(),
129 height: length(h),
130 },
131 align_items: Some(AlignItems::Center),
132 justify_content: Some(JustifyContent::Center),
133 padding: llimphi_ui::llimphi_layout::taffy::Rect {
134 left: length(20.0_f32),
135 right: length(20.0_f32),
136 top: length(0.0_f32),
137 bottom: length(0.0_f32),
138 },
139 ..Default::default()
140 })
141 .fill(palette.bg)
142 .radius((h as f64) * 0.5)
143 .shadow(shadow)
144 .animated_pop_in(key, motion::FAST)
145 .text_aligned(label.clone(), 14.0, palette.fg, Alignment::Center)
146 .role(llimphi_ui::Role::Button)
147 .aria_label(label)
148 .on_click(on_click)
149 .cursor(llimphi_ui::Cursor::Pointer)
150}