1use crate::{
2 border::BorderBuilder,
3 brush::Brush,
4 canvas::CanvasBuilder,
5 core::{algebra::Vector2, color::Color, pool::Handle},
6 define_constructor,
7 message::{MessageDirection, UiMessage},
8 widget::{Widget, WidgetBuilder, WidgetMessage},
9 BuildContext, Control, NodeHandleMapping, UiNode, UserInterface,
10};
11use std::{
12 any::{Any, TypeId},
13 ops::{Deref, DerefMut},
14};
15
16#[derive(Debug, Clone, PartialEq)]
17pub enum ProgressBarMessage {
18 Progress(f32),
19}
20
21impl ProgressBarMessage {
22 define_constructor!(ProgressBarMessage:Progress => fn progress(f32), layout: false);
23}
24
25#[derive(Clone)]
26pub struct ProgressBar {
27 widget: Widget,
28 progress: f32,
29 indicator: Handle<UiNode>,
30 body: Handle<UiNode>,
31}
32
33crate::define_widget_deref!(ProgressBar);
34
35impl Control for ProgressBar {
36 fn query_component(&self, type_id: TypeId) -> Option<&dyn Any> {
37 if type_id == TypeId::of::<Self>() {
38 Some(self)
39 } else {
40 None
41 }
42 }
43
44 fn resolve(&mut self, node_map: &NodeHandleMapping) {
45 node_map.resolve(&mut self.indicator);
46 node_map.resolve(&mut self.body);
47 }
48
49 fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
50 let size = self.widget.arrange_override(ui, final_size);
51
52 ui.send_message(WidgetMessage::width(
53 self.indicator,
54 MessageDirection::ToWidget,
55 size.x * self.progress,
56 ));
57
58 ui.send_message(WidgetMessage::height(
59 self.indicator,
60 MessageDirection::ToWidget,
61 size.y,
62 ));
63
64 size
65 }
66
67 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
68 self.widget.handle_routed_message(ui, message);
69
70 if message.destination() == self.handle {
71 if let Some(&ProgressBarMessage::Progress(progress)) =
72 message.data::<ProgressBarMessage>()
73 {
74 if progress != self.progress {
75 self.set_progress(progress);
76 self.invalidate_layout();
77 }
78 }
79 }
80 }
81}
82
83impl ProgressBar {
84 pub fn set_progress(&mut self, progress: f32) {
85 self.progress = progress.min(1.0).max(0.0);
86 }
87
88 pub fn progress(&self) -> f32 {
89 self.progress
90 }
91}
92
93pub struct ProgressBarBuilder {
94 widget_builder: WidgetBuilder,
95 body: Option<Handle<UiNode>>,
96 indicator: Option<Handle<UiNode>>,
97 progress: f32,
98}
99
100impl ProgressBarBuilder {
101 pub fn new(widget_builder: WidgetBuilder) -> Self {
102 Self {
103 widget_builder,
104 body: None,
105 indicator: None,
106 progress: 0.0,
107 }
108 }
109
110 pub fn with_body(mut self, body: Handle<UiNode>) -> Self {
111 self.body = Some(body);
112 self
113 }
114
115 pub fn with_indicator(mut self, indicator: Handle<UiNode>) -> Self {
116 self.indicator = Some(indicator);
117 self
118 }
119
120 pub fn with_progress(mut self, progress: f32) -> Self {
121 self.progress = progress.min(1.0).max(0.0);
122 self
123 }
124
125 pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
126 let body = self
127 .body
128 .unwrap_or_else(|| BorderBuilder::new(WidgetBuilder::new()).build(ctx));
129
130 let indicator = self.indicator.unwrap_or_else(|| {
131 BorderBuilder::new(
132 WidgetBuilder::new().with_background(Brush::Solid(Color::opaque(180, 180, 180))),
133 )
134 .build(ctx)
135 });
136
137 let canvas = CanvasBuilder::new(WidgetBuilder::new().with_child(indicator)).build(ctx);
138
139 ctx.link(canvas, body);
140
141 let progress_bar = ProgressBar {
142 widget: self.widget_builder.with_child(body).build(),
143 progress: self.progress,
144 indicator,
145 body,
146 };
147
148 ctx.add_node(UiNode::new(progress_bar))
149 }
150}