orbtk 0.2.17

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 traits::Place;
use widgets::Widget;

pub struct Grid {
    pub rect: Cell<Rect>,
    space_x: Cell<i32>,
    space_y: Cell<i32>,
    entries: RefCell<BTreeMap<(usize, usize), Arc<Widget>>>,
    focused: Cell<Option<(usize, usize)>>
}

impl Grid {
    pub fn new() -> Arc<Self> {
        Arc::new(Grid {
            rect: Cell::new(Rect::default()),
            space_x: Cell::new(0),
            space_y: Cell::new(0),
            entries: RefCell::new(BTreeMap::new()),
            focused: Cell::new(None)
        })
    }

    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 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);
        }
    }
}

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 rect(&self) -> &Cell<Rect> {
        &self.rect
    }

    fn draw(&self, renderer: &mut Renderer, _focused: bool) {
        for (&(col, row), entry) in self.entries.borrow().iter() {
            entry.draw(renderer, self.focused.get() == Some((col, row)));
        }
    }

    fn event(&self, event: Event, mut focused: bool, redraw: &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) {
                if self.focused.check_set(Some((col, row))) || ! focused {
                    focused = true;
                    *redraw = true;
                }
            } else if is_focused {
                self.focused.set(None);
            }
        }

        focused
    }
}