orbtk 0.1.1

The Orbital Widget Toolkit
use super::{Color, CopyCell, Event, Place, Point, Rect, Renderer, Widget, Window};
use super::callback::Click;
use super::cell::CheckSet;

use std::cmp::{min, max};
use std::sync::Arc;

pub struct ProgressBar {
    pub rect: CopyCell<Rect>,
    pub value: CopyCell<i32>,
    pub minimum: i32,
    pub maximum: i32,
    pub bg: Color,
    pub fg: Color,
    click_callback: Option<Arc<Fn(&ProgressBar, Point)>>,
    pressed: CopyCell<bool>,
}

impl ProgressBar {
    pub fn new() -> Self {
        ProgressBar {
            rect: CopyCell::new(Rect::default()),
            value: CopyCell::new(0),
            minimum: 0,
            maximum: 100,
            bg: Color::rgb(255, 255, 255),
            fg: Color::rgb(65, 139, 212),
            click_callback: None,
            pressed: CopyCell::new(false),
        }
    }

    pub fn place(self, window: &mut Window) -> Arc<Self> {
        let arc = Arc::new(self);

        window.widgets.push(arc.clone());

        arc
    }

    pub fn value(self, value: i32) -> Self {
        self.value.set(value);
        self
    }
}

impl Click for ProgressBar {
    fn emit_click(&self, point: Point) {
        if let Some(ref click_callback) = self.click_callback {
            click_callback(self, point);
        }
    }

    fn on_click<T: Fn(&Self, Point) + 'static>(mut self, func: T) -> Self {
        self.click_callback = Some(Arc::new(func));

        self
    }
}

impl Place for ProgressBar {
    fn position(self, x: i32, y: i32) -> Self {
        let mut rect = self.rect.get();
        rect.x = x;
        rect.y = y;
        self.rect.set(rect);

        self
    }

    fn size(self, width: u32, height: u32) -> Self {
        let mut rect = self.rect.get();
        rect.width = width;
        rect.height = height;
        self.rect.set(rect);

        self
    }
}

impl Widget for ProgressBar {
    fn draw(&self, renderer: &mut Renderer, _focused: bool) {
        let rect = self.rect.get();
        renderer.rect(rect, self.bg);
        renderer.rect(Rect::new(rect.x,
                                rect.y,
                                ((rect.width as i32 *
                                  max(0, min(self.maximum, self.value.get() - self.minimum))) /
                                 max(1,
                                     self.maximum -
                                     self.minimum)) as u32,
                                rect.height),
                      self.fg);
    }

    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool {
        match event {
            Event::Mouse { point, left_button, .. } => {
                let mut click = false;

                let rect = self.rect.get();
                if rect.contains(point) {
                    if left_button {
                        if self.pressed.check_set(true) {
                            *redraw = true;
                        }
                    } else {
                        if self.pressed.check_set(false) {
                            click = true;
                            *redraw = true;
                        }
                    }
                } else {
                    if !left_button {
                        if self.pressed.check_set(false) {
                            *redraw = true;
                        }
                    }
                }

                if click {
                    let click_point: Point = point - rect.point();
                    self.emit_click(click_point);
                }
            }
            _ => (),
        }

        focused
    }
}