kas_widgets/
progress.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Progress bar
7
8use kas::prelude::*;
9use kas::theme::Feature;
10
11#[impl_self]
12mod ProgressBar {
13    /// A progress bar
14    ///
15    /// The "progress" value may range from 0.0 to 1.0.
16    #[autoimpl(Debug ignore self.value_fn)]
17    #[widget]
18    pub struct ProgressBar<A, D: Directional = kas::dir::Right> {
19        core: widget_core!(),
20        direction: D,
21        value: f32,
22        value_fn: Box<dyn Fn(&ConfigCx, &A) -> f32>,
23    }
24
25    impl Self
26    where
27        D: Default,
28    {
29        /// Construct a slider
30        ///
31        /// Closure `value_fn` returns the current progress as a value between
32        /// 0.0 and 1.0.
33        #[inline]
34        pub fn new(value_fn: impl Fn(&ConfigCx, &A) -> f32 + 'static) -> Self {
35            Self::new_dir(value_fn, D::default())
36        }
37    }
38    impl<A> ProgressBar<A, kas::dir::Right> {
39        /// Construct a progress bar (horizontal)
40        ///
41        /// Closure `value_fn` returns the current progress as a value between
42        /// 0.0 and 1.0.
43        #[inline]
44        pub fn right(value_fn: impl Fn(&ConfigCx, &A) -> f32 + 'static) -> Self {
45            ProgressBar::new(value_fn)
46        }
47    }
48
49    impl Self {
50        /// Construct a slider with the given `direction`
51        ///
52        /// Closure `value_fn` returns the current progress as a value between
53        /// 0.0 and 1.0.
54        #[inline]
55        pub fn new_dir(value_fn: impl Fn(&ConfigCx, &A) -> f32 + 'static, direction: D) -> Self {
56            ProgressBar {
57                core: Default::default(),
58                direction,
59                value: 0.0,
60                value_fn: Box::new(value_fn),
61            }
62        }
63
64        /// Get the progress bar's direction
65        #[inline]
66        pub fn direction(&self) -> Direction {
67            self.direction.as_direction()
68        }
69    }
70
71    impl Layout for Self {
72        fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
73            sizer.feature(Feature::ProgressBar(self.direction()), axis)
74        }
75
76        fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
77            let align = match self.direction.is_vertical() {
78                false => AlignPair::new(Align::Stretch, hints.vert.unwrap_or(Align::Center)),
79                true => AlignPair::new(hints.horiz.unwrap_or(Align::Center), Align::Stretch),
80            };
81            let rect = cx.align_feature(Feature::ProgressBar(self.direction()), rect, align);
82            widget_set_rect!(rect);
83        }
84
85        fn draw(&self, mut draw: DrawCx) {
86            let dir = self.direction.as_direction();
87            draw.progress_bar(self.rect(), dir, self.value);
88        }
89    }
90
91    impl Tile for Self {
92        fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
93            Role::ProgressBar {
94                fraction: self.value,
95                direction: self.direction.as_direction(),
96            }
97        }
98    }
99
100    impl Events for Self {
101        type Data = A;
102
103        fn update(&mut self, cx: &mut ConfigCx, data: &A) {
104            let value = (self.value_fn)(cx, data);
105            self.value = value.clamp(0.0, 1.0);
106        }
107    }
108}