1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use derive_setters::Setters;
use glam::vec2;
use crate::{
element::{MeasureContext, ProcessContext, UiElement},
frame::{Frame, RectFrame},
layout::{compute_size, Size, Size2d},
measure::Response,
};
//TODO: Use Frames here instead of FillColor
#[derive(Setters)]
#[setters(prefix = "with_")]
pub struct ProgressBar {
/// Current progress, should be in the range 0.0..=1.0
pub value: f32,
/// Size of the progress bar element
#[setters(into)]
pub size: Size2d,
/// Foreground (bar) color
#[setters(skip)]
pub foreground: Box<dyn Frame>,
/// Background color
#[setters(skip)]
pub background: Box<dyn Frame>,
}
impl ProgressBar {
pub const DEFAULT_HEIGHT: f32 = 20.0;
pub fn with_background(mut self, frame: impl Frame + 'static) -> Self {
self.background = Box::new(frame);
self
}
pub fn with_foreground(mut self, frame: impl Frame + 'static) -> Self {
self.foreground = Box::new(frame);
self
}
}
impl Default for ProgressBar {
fn default() -> Self {
Self {
value: 0.,
size: Size::Auto.into(),
foreground: Box::new(RectFrame::color((0.0, 0.0, 1.0, 1.0))),
background: Box::new(RectFrame::color((0.0, 0.0, 0.0, 1.0))),
}
}
}
impl UiElement for ProgressBar {
fn name(&self) -> &'static str {
"progress_bar"
}
fn measure(&self, ctx: MeasureContext) -> Response {
Response {
size: compute_size(ctx.layout, self.size, vec2(
ctx.layout.max_size.x.max(300.), //XXX: remove .max(300)?
Self::DEFAULT_HEIGHT,
)),
hints: Default::default(),
user_data: None,
..Default::default()
}
}
fn process(&self, ctx: ProcessContext) {
let value = self.value.clamp(0., 1.);
//FIXME: these optimizations may not be valid
if value < 1. || !self.foreground.covers_opaque() {
self.background.draw(ctx.draw, (ctx.layout.position, ctx.measure.size).into());
}
if value > 0. {
self.foreground.draw(ctx.draw, (ctx.layout.position, ctx.measure.size * vec2(value, 1.)).into());
}
// let rounded_corners =
// (self.corner_radius.max_f32() > 0.).then_some({
// //HACK: fix clipping issues; //todo: get rid of this
// let mut radii = self.corner_radius;
// let width = ctx.measure.size.x * value;
// if width <= radii.max_f32() * 2. {
// radii.bottom_right = 0.;
// radii.top_right = 0.;
// }
// if width <= radii.max_f32() {
// radii.bottom_left = 0.;
// radii.top_left = 0.;
// }
// RoundedCorners::from_radius(radii)
// });
// if value < 1. {
// ctx.draw.add(UiDrawCommand::Rectangle {
// position: ctx.layout.position,
// size: ctx.measure.size,
// color: self.background.corners(),
// texture: None,
// texture_uv: None,
// rounded_corners
// });
// }
// if value > 0. {
// ctx.draw.add(UiDrawCommand::Rectangle {
// position: ctx.layout.position,
// size: ctx.measure.size * vec2(value, 1.0),
// color: self.foreground.corners(),
// texture: None,
// texture_uv: None,
// rounded_corners,
// });
// }
}
}