#![warn(missing_docs)]
use crate::style::resource::StyleResourceExt;
use crate::style::Style;
use crate::{
border::BorderBuilder,
canvas::CanvasBuilder,
core::{
algebra::Vector2, pool::Handle, reflect::prelude::*, type_traits::prelude::*,
visitor::prelude::*,
},
define_constructor,
message::{MessageDirection, UiMessage},
widget::{Widget, WidgetBuilder, WidgetMessage},
BuildContext, Control, UiNode, UserInterface,
};
use fyrox_core::uuid_provider;
use fyrox_core::variable::InheritableVariable;
use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone, PartialEq)]
pub enum ProgressBarMessage {
Progress(f32),
}
impl ProgressBarMessage {
define_constructor!(
ProgressBarMessage:Progress => fn progress(f32), layout: false
);
}
#[derive(Default, Clone, Debug, Visit, Reflect, ComponentProvider)]
pub struct ProgressBar {
pub widget: Widget,
pub progress: InheritableVariable<f32>,
pub indicator: InheritableVariable<Handle<UiNode>>,
pub body: InheritableVariable<Handle<UiNode>>,
}
impl ConstructorProvider<UiNode, UserInterface> for ProgressBar {
fn constructor() -> GraphNodeConstructor<UiNode, UserInterface> {
GraphNodeConstructor::new::<Self>()
.with_variant("Progress Bar", |ui| {
ProgressBarBuilder::new(WidgetBuilder::new().with_name("Progress Bar"))
.build(&mut ui.build_ctx())
.into()
})
.with_group("Visual")
}
}
crate::define_widget_deref!(ProgressBar);
uuid_provider!(ProgressBar = "d6ebb853-d945-46bc-86db-4c8b5d5faf8e");
impl Control for ProgressBar {
fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
let size = self.widget.arrange_override(ui, final_size);
ui.send_message(WidgetMessage::width(
*self.indicator,
MessageDirection::ToWidget,
size.x * *self.progress,
));
ui.send_message(WidgetMessage::height(
*self.indicator,
MessageDirection::ToWidget,
size.y,
));
size
}
fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
self.widget.handle_routed_message(ui, message);
if message.destination() == self.handle {
if let Some(&ProgressBarMessage::Progress(progress)) =
message.data::<ProgressBarMessage>()
{
if progress != *self.progress {
self.set_progress(progress);
self.invalidate_layout();
}
}
}
}
}
impl ProgressBar {
fn set_progress(&mut self, progress: f32) {
self.progress
.set_value_and_mark_modified(progress.clamp(0.0, 1.0));
}
}
pub struct ProgressBarBuilder {
widget_builder: WidgetBuilder,
body: Option<Handle<UiNode>>,
indicator: Option<Handle<UiNode>>,
progress: f32,
}
impl ProgressBarBuilder {
pub fn new(widget_builder: WidgetBuilder) -> Self {
Self {
widget_builder,
body: None,
indicator: None,
progress: 0.0,
}
}
pub fn with_body(mut self, body: Handle<UiNode>) -> Self {
self.body = Some(body);
self
}
pub fn with_indicator(mut self, indicator: Handle<UiNode>) -> Self {
self.indicator = Some(indicator);
self
}
pub fn with_progress(mut self, progress: f32) -> Self {
self.progress = progress.clamp(0.0, 1.0);
self
}
pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
let body = self
.body
.unwrap_or_else(|| BorderBuilder::new(WidgetBuilder::new()).build(ctx));
let indicator = self.indicator.unwrap_or_else(|| {
BorderBuilder::new(
WidgetBuilder::new().with_background(ctx.style.property(Style::BRUSH_BRIGHTEST)),
)
.build(ctx)
});
let canvas = CanvasBuilder::new(WidgetBuilder::new().with_child(indicator)).build(ctx);
ctx.link(canvas, body);
let progress_bar = ProgressBar {
widget: self.widget_builder.with_child(body).build(ctx),
progress: self.progress.into(),
indicator: indicator.into(),
body: body.into(),
};
ctx.add_node(UiNode::new(progress_bar))
}
}
#[cfg(test)]
mod test {
use crate::progress_bar::ProgressBarBuilder;
use crate::{test::test_widget_deletion, widget::WidgetBuilder};
#[test]
fn test_deletion() {
test_widget_deletion(|ctx| ProgressBarBuilder::new(WidgetBuilder::new()).build(ctx));
}
}