freya_components/
progressbar.rs1use freya_animation::{
2 easing::Function,
3 hook::{
4 Ease,
5 use_animation_transition,
6 },
7 prelude::AnimNum,
8};
9use freya_core::prelude::*;
10use torin::{
11 prelude::Alignment,
12 size::Size,
13};
14
15use crate::{
16 define_theme,
17 get_theme,
18};
19
20define_theme! {
21 %[component]
22 pub ProgressBar {
23 %[fields]
24 color: Color,
25 background: Color,
26 progress_background: Color,
27 height: f32,
28 }
29}
30
31#[cfg_attr(feature = "docs",
50 doc = embed_doc_image::embed_image!("progressbar", "images/gallery_progressbar.png")
51)]
52#[derive(Clone, PartialEq)]
53pub struct ProgressBar {
54 pub(crate) theme: Option<ProgressBarThemePartial>,
55 width: Size,
56 show_progress: bool,
57 progress: f32,
58 key: DiffKey,
59}
60
61impl KeyExt for ProgressBar {
62 fn write_key(&mut self) -> &mut DiffKey {
63 &mut self.key
64 }
65}
66
67impl ProgressBar {
68 pub fn new(progress: impl Into<f32>) -> Self {
69 Self {
70 width: Size::fill(),
71 theme: None,
72 show_progress: true,
73 progress: progress.into(),
74 key: DiffKey::None,
75 }
76 }
77
78 pub fn width(mut self, width: impl Into<Size>) -> Self {
79 self.width = width.into();
80 self
81 }
82
83 pub fn show_progress(mut self, show_progress: bool) -> Self {
87 self.show_progress = show_progress;
88 self
89 }
90}
91
92impl Component for ProgressBar {
93 fn render(&self) -> impl IntoElement {
94 let progressbar_theme = get_theme!(&self.theme, ProgressBarThemePreference, "progressbar");
95
96 let progress = use_reactive(&self.progress.clamp(0., 100.));
97 let animation = use_animation_transition(progress, |from, to| {
98 AnimNum::new(from, to)
99 .time(500)
100 .ease(Ease::Out)
101 .function(Function::Expo)
102 });
103
104 rect()
105 .a11y_alt(format!("Progress {}%", progress()))
106 .a11y_focusable(true)
107 .a11y_role(AccessibilityRole::ProgressIndicator)
108 .horizontal()
109 .width(self.width.clone())
110 .height(Size::px(progressbar_theme.height))
111 .corner_radius(99.)
112 .overflow(Overflow::Clip)
113 .background(progressbar_theme.background)
114 .border(
115 Border::new()
116 .width(1.)
117 .alignment(BorderAlignment::Outer)
118 .fill(progressbar_theme.background),
119 )
120 .font_size(13.)
121 .child(
122 rect()
123 .horizontal()
124 .width(Size::percent(&*animation.read()))
125 .cross_align(Alignment::Center)
126 .height(Size::fill())
127 .corner_radius(99.)
128 .background(progressbar_theme.progress_background)
129 .maybe(self.show_progress, |el| {
130 el.child(
131 label()
132 .width(Size::fill())
133 .color(progressbar_theme.color)
134 .text_align(TextAlign::Center)
135 .text(format!("{}%", self.progress))
136 .max_lines(1),
137 )
138 }),
139 )
140 }
141
142 fn render_key(&self) -> DiffKey {
143 self.key.clone().or(self.default_key())
144 }
145}