orbtk 0.2.31

The Orbital Widget Toolkit
Documentation
use orbclient::Renderer;
use std::cell::{Cell, RefCell};
use std::collections::BTreeMap;
use std::sync::Arc;

use cell::CheckSet;
use event::Event;
use rect::Rect;
use point::Point;
use thickness::Thickness;
use theme::{Theme};
use traits::Place;
use widgets::{Widget, VerticalPlacement, HorizontalPlacement};

pub struct Grid {
    pub rect: Cell<Rect>,
    local_position: Cell<Point>,
    vertical_placement: Cell<VerticalPlacement>,
    horizontal_placement: Cell<HorizontalPlacement>,
    margin: Cell<Thickness>,
    children: RefCell<Vec<Arc<dyn Widget>>>,
    space_x: Cell<i32>,
    space_y: Cell<i32>,
    columns: Cell<usize>,
    row_count: Cell<usize>,
    column_count: Cell<usize>,
    entries: RefCell<BTreeMap<(usize, usize), Arc<dyn Widget>>>,
    focused: Cell<Option<(usize, usize)>>
}

impl Grid {
    pub fn new() -> Arc<Self> {
        Arc::new(Grid {
            rect: Cell::new(Rect::default()),
            local_position: Cell::new(Point::new(0, 0)),
            vertical_placement: Cell::new(VerticalPlacement::Absolute),
            horizontal_placement: Cell::new(HorizontalPlacement::Absolute),
            margin: Cell::new(Thickness::default()),
            children: RefCell::new(vec![]),
            space_x: Cell::new(0),
            space_y: Cell::new(0),
            columns: Cell::new(0),
            row_count: Cell::new(0),
            column_count: Cell::new(0),
            entries: RefCell::new(BTreeMap::new()),
            focused: Cell::new(None),
        })
    }

    pub fn columns(&self, columns: usize) -> &Self {
        self.columns.set(columns);
        self
    }

    pub fn add<T: Widget>(&self, entry: &Arc<T>) {
        if self.column_count.get() == self.columns.get() {
            self.row_count.set(self.row_count.get() + 1);
            self.column_count.set(0);
        }

        self.entries.borrow_mut().insert((self.column_count.get(), self.row_count.get()), entry.clone());
        self.column_count.set(self.column_count.get() + 1);
        self.arrange(false);
    }

    pub fn insert<T: Widget>(&self, col: usize, row: usize, entry: &Arc<T>) {
        self.entries.borrow_mut().insert((col, row), entry.clone());
        self.arrange(false);
    }

    pub fn clear(&self) {
        self.entries.borrow_mut().clear();
    }

    pub fn remove(&self, col: usize, row: usize) {
        self.entries.borrow_mut().remove(&(col, row));
    }

    pub fn spacing(&self, x: i32, y: i32) -> &Self {
        self.space_x.set(x);
        self.space_y.set(y);
        self
    }

    pub fn arrange(&self, resize: bool) {
        let mut cols = Vec::new();
        let mut rows = Vec::new();
        for (&(col, row), entry) in self.entries.borrow().iter() {
            while col >= cols.len() {
                cols.push(Rect::default());
            }
            while row >= rows.len() {
                rows.push(Rect::default());
            }
            let rect = entry.rect().get();
            if rect.width >= cols[col].width {
                cols[col as usize].width = rect.width;
            }
            if rect.width >= rows[row].width {
                rows[row as usize].width = rect.width;
            }
            if rect.height >= cols[col].height {
                cols[col as usize].height = rect.height;
            }
            if rect.height >= rows[row].height {
                rows[row as usize].height = rect.height;
            }
        }

        let rect = self.rect.get();
        let space_x = self.space_x.get();
        let space_y = self.space_y.get();

        let mut x = rect.x;
        for col in cols.iter_mut() {
            col.x = x;
            x += col.width as i32 + space_x;
        }

        let mut y = rect.y;
        for row in rows.iter_mut() {
            row.y = y;
            y += row.height as i32 + space_y;
        }

        for (&(col, row), entry) in self.entries.borrow().iter() {
            let mut rect = entry.rect().get();
            rect.x = cols[col].x;
            rect.y = rows[row].y;
            if resize {
                rect.width = cols[col].width;
                rect.height = rows[row].height;
            }
            entry.rect().set(rect);

            entry.arrange();
        }
    }
}

impl Place for Grid {
    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.arrange(false);

        self
    }
}

impl Widget for Grid {
    fn name(&self) -> &str {
        "Grid"
    }

    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }

    fn local_position(&self) -> &Cell<Point> {
        &self.local_position
    }

    fn vertical_placement(&self) -> &Cell<VerticalPlacement> {
        &self.vertical_placement
    }

    fn horizontal_placement(&self) -> &Cell<HorizontalPlacement> {
        &self.horizontal_placement
    }

    fn margin(&self) -> &Cell<Thickness> {
        &self.margin
    }

    fn draw(&self, renderer: &mut dyn Renderer, _focused: bool, theme: &Theme) {
        fn draw_widget(widget: &Arc<dyn Widget>, renderer: &mut dyn Renderer, focused: bool, theme: &Theme) {
            widget.update();
            widget.draw(renderer, focused, theme);

            for child in widget.children().borrow().iter() {
                draw_widget(child, renderer, focused, theme);
            }
        }

        for (&(col, row), entry) in self.entries.borrow().iter() {
            draw_widget(entry, renderer, self.focused.get() == Some((col, row)), theme);
        }
    }

    fn event(&self, event: Event, mut focused: bool, redraw: &mut bool, caught: &mut bool) -> bool {
        for (&(col, row), entry) in self.entries.borrow().iter() {
            let is_focused = self.focused.get() == Some((col, row));
            if entry.event(event, focused && is_focused, redraw, caught) {
                if self.focused.check_set(Some((col, row))) || ! focused {
                    focused = true;
                    *redraw = true;
                }
            } else if is_focused {
                self.focused.set(None);
            }

            if *caught {
                break;
            }
        }

        focused
    }

    fn children(&self) -> &RefCell<Vec<Arc<dyn Widget>>> {
        &self.children
    }
}