ui/src/elements/progress_bar.rs

355 lines
9.2 KiB
Rust
Raw Normal View History

2023-01-16 09:53:52 +00:00
use crate::{builder::validator::progressbar_info::ProgressBarInfo, prelude::*};
use anyhow::Result;
use std::sync::{
atomic::{AtomicBool, Ordering::SeqCst},
Arc, Mutex,
};
2023-01-16 11:58:59 +00:00
use utilities::prelude::*;
2023-01-16 09:53:52 +00:00
use super::{
fill_type::{FillType, InnerFillType},
2024-04-04 15:57:50 +00:00
wrapper::TextableWrapper,
2023-01-16 09:53:52 +00:00
};
2023-01-17 14:40:53 +00:00
#[derive(Clone)]
2023-01-16 09:53:52 +00:00
pub enum GrowDirection {
LeftToRight,
BottomToTop,
}
pub struct ProgressBarBuilder {
// bar
background: Option<FillTypeInfo>,
foreground: Option<FillTypeInfo>,
direction: GrowDirection,
// text
text: Option<String>,
text_ratio: f32,
text_color: Color,
text_alignment: TextAlignment,
}
impl ProgressBarBuilder {
pub fn set_background(mut self, background: impl Into<FillTypeInfo>) -> Self {
self.background = Some(background.into());
self
}
pub fn set_foreground(mut self, foreground: impl Into<FillTypeInfo>) -> Self {
self.foreground = Some(foreground.into());
self
}
pub fn set_grow_direction(mut self, direction: GrowDirection) -> Self {
self.direction = direction;
self
}
pub fn set_text(mut self, text: &str) -> Self {
self.text = Some(text.to_string());
self
}
pub fn set_text_ratio(mut self, ratio: f32) -> Self {
self.text_ratio = ratio;
self
}
pub fn set_text_color(mut self, text_color: Color) -> Self {
self.text_color = text_color;
self
}
pub fn set_text_alignment(mut self, text_alignment: TextAlignment) -> Self {
self.text_alignment = text_alignment;
self
}
pub fn build(self, gui_handler: Arc<GuiHandler>) -> Result<Arc<ProgressBar>> {
let framable = Framable::new(gui_handler, false)?;
let background = self
.background
.map(|r#type| FillType::new(framable.clone(), r#type))
.transpose()?;
let foreground = self
.foreground
.map(|r#type| FillType::new(framable.clone(), r#type))
.transpose()?;
let textable_wrapper = TextableWrapper::new(
framable.clone(),
self.text_color,
self.text_ratio,
self.text_alignment,
);
if let Some(text) = self.text {
textable_wrapper.set_text(&text, false)?;
}
Ok(Arc::new(ProgressBar {
framable,
textable_wrapper,
background,
foreground,
direction: self.direction,
visible: AtomicBool::new(false),
progress: Mutex::new(0.0),
}))
}
}
pub struct ProgressBar {
framable: Arc<Framable>,
textable_wrapper: TextableWrapper,
background: Option<FillType>,
foreground: Option<FillType>,
direction: GrowDirection,
visible: AtomicBool,
progress: Mutex<f32>,
}
impl ProgressBar {
pub fn builder() -> ProgressBarBuilder {
ProgressBarBuilder {
background: None,
foreground: None,
direction: GrowDirection::LeftToRight,
text: None,
text_ratio: 0.7,
text_color: Color::default(),
text_alignment: TextAlignment::default(),
}
}
pub fn set_progress(&self, mut progress: f32) -> Result<()> {
if progress < 0.0 {
progress = 0.0;
} else if progress > 1.0 {
progress = 1.0;
}
if !almost_eq(self.progress(), progress) {
*self.progress.lock().unwrap() = progress;
if let Some(foreground) = &self.foreground {
match self.direction {
GrowDirection::LeftToRight => match &foreground.inner {
InnerFillType::Image(displayable) => {
displayable.set_right_factor(progress);
displayable.set_right_uv_factor(progress);
displayable.update_frame()?;
}
InnerFillType::Color(colorable) => {
colorable.set_right_factor(progress);
colorable.update_frame()?;
}
},
GrowDirection::BottomToTop => match &foreground.inner {
InnerFillType::Image(displayable) => {
displayable.set_top_factor(progress);
displayable.set_top_uv_factor(progress);
displayable.update_frame()?;
}
InnerFillType::Color(colorable) => {
colorable.set_top_factor(progress);
colorable.update_frame()?;
}
},
}
}
}
Ok(())
}
pub fn set_text(&self, text: impl ToString) -> Result<()> {
self.textable_wrapper.set_text(text, self.visible())
}
pub fn set_text_color(&self, text_color: Color) -> Result<()> {
self.textable_wrapper.set_text_color(text_color)
}
pub fn set_text_ratio(&self, ratio: f32) -> Result<()> {
self.textable_wrapper.set_height_ratio(ratio)
}
pub fn set_text_alignment(&self, text_alignment: TextAlignment) -> Result<()> {
self.textable_wrapper.set_alignment(text_alignment)
}
pub fn try_from(
progress_bar_info: &ProgressBarInfo,
gui_handler: &Arc<GuiHandler>,
) -> Result<Arc<Self>> {
let mut progress_bar_builder = ProgressBar::builder()
.set_text_alignment(progress_bar_info.text_alignment)
.set_text_color(progress_bar_info.text_color);
if let Some(text_ratio) = progress_bar_info.text_ratio {
progress_bar_builder = progress_bar_builder.set_text_ratio(text_ratio);
}
let text = progress_bar_info.text.read().unwrap().clone();
if !text.is_empty() {
progress_bar_builder = progress_bar_builder.set_text(&text);
}
if let Some(background) = progress_bar_info.background.clone() {
progress_bar_builder = progress_bar_builder.set_background(background);
}
if let Some(foreground) = progress_bar_info.foreground.clone() {
progress_bar_builder = progress_bar_builder.set_foreground(foreground);
}
2023-01-17 14:40:53 +00:00
if let Some(dir) = progress_bar_info.direction.clone() {
progress_bar_builder = progress_bar_builder.set_grow_direction(dir);
}
2023-01-16 09:53:52 +00:00
progress_bar_builder.build(gui_handler.clone())
}
#[inline]
fn progress(&self) -> f32 {
*self.progress.lock().unwrap()
}
fn disable_base(&self) -> Result<()> {
Framable::delete(&self.framable)?;
if let Some(background) = &self.background {
background.disable()?;
}
if let Some(foreground) = &self.foreground {
foreground.disable()?;
}
self.textable_wrapper.disable()?;
Ok(())
}
}
impl GuiElementTraits for ProgressBar {
fn gridable(&self) -> Option<&dyn Gridable> {
Some(self)
}
fn visibility(&self) -> Option<&dyn Visibility> {
Some(self)
}
fn downcast<'a>(&'a self) -> Option<GuiElement<'a>> {
Some(GuiElement::ProgressBar(self))
}
}
impl Visibility for ProgressBar {
fn visible(&self) -> bool {
self.visible.load(SeqCst)
}
fn set_visibility(&self, visibility: bool) -> Result<()> {
if visibility != self.visible() {
self.visible.store(visibility, SeqCst);
if visibility {
Framable::add(&self.framable)?;
if let Some(background) = &self.background {
background.enable()?;
}
if let Some(foreground) = &self.foreground {
foreground.enable()?;
}
self.textable_wrapper.enable()?;
} else {
self.disable_base()?;
}
}
Ok(())
}
}
impl Gridable for ProgressBar {
fn set_frame(
&self,
x: i32,
y: i32,
w: u32,
h: u32,
vert_align: VerticalAlign,
hori_align: HorizontalAlign,
) -> Result<()> {
self.framable.set_frame(x, y, w, h, vert_align, hori_align);
if let Some(background) = &self.background {
background.update_frame()?;
}
if let Some(foreground) = &self.foreground {
foreground.update_frame()?;
}
self.textable_wrapper.update()?;
Ok(())
}
fn selectable(&self) -> Option<&Arc<Selectable>> {
None
}
fn type_name(&self) -> &str {
"ProgressBar"
}
fn set_layer(&self, layer: i32) -> Result<()> {
self.framable.set_ui_layer(layer);
self.textable_wrapper.set_ui_layer(layer)?;
if let Some(background) = &self.background {
background.set_ui_layer(layer);
}
if let Some(foreground) = &self.foreground {
foreground.set_ui_layer(layer);
}
Ok(())
}
}
impl Drop for ProgressBar {
fn drop(&mut self) {
if self.visible.load(SeqCst) {
self.disable_base().unwrap();
}
}
}