grid.rs 6.16 KB
Newer Older
1
use orbclient::Renderer;
Jeremy Soller's avatar
Jeremy Soller committed
2 3 4 5
use std::cell::{Cell, RefCell};
use std::collections::BTreeMap;
use std::sync::Arc;

Jeremy Soller's avatar
Jeremy Soller committed
6
use cell::CheckSet;
Jeremy Soller's avatar
Jeremy Soller committed
7 8
use event::Event;
use rect::Rect;
9
use point::Point;
10
use thickness::Thickness;
MovingtoMars's avatar
MovingtoMars committed
11
use theme::{Theme};
Jeremy Soller's avatar
Jeremy Soller committed
12
use traits::Place;
13
use widgets::{Widget, VerticalPlacement, HorizontalPlacement};
Jeremy Soller's avatar
Jeremy Soller committed
14 15 16

pub struct Grid {
    pub rect: Cell<Rect>,
17 18 19
    local_position: Cell<Point>,
    vertical_placement: Cell<VerticalPlacement>,
    horizontal_placement: Cell<HorizontalPlacement>,
20
    margin: Cell<Thickness>,
21
    children: RefCell<Vec<Arc<Widget>>>,
Jeremy Soller's avatar
Jeremy Soller committed
22 23
    space_x: Cell<i32>,
    space_y: Cell<i32>,
24 25 26
    columns: Cell<usize>,
    row_count: Cell<usize>,
    column_count: Cell<usize>,
Jeremy Soller's avatar
Jeremy Soller committed
27 28
    entries: RefCell<BTreeMap<(usize, usize), Arc<Widget>>>,
    focused: Cell<Option<(usize, usize)>>
Jeremy Soller's avatar
Jeremy Soller committed
29 30 31 32 33 34
}

impl Grid {
    pub fn new() -> Arc<Self> {
        Arc::new(Grid {
            rect: Cell::new(Rect::default()),
35 36 37
            local_position: Cell::new(Point::new(0, 0)),
            vertical_placement: Cell::new(VerticalPlacement::Absolute),
            horizontal_placement: Cell::new(HorizontalPlacement::Absolute),
38
            margin: Cell::new(Thickness::default()),
39
            children: RefCell::new(vec![]),
Jeremy Soller's avatar
Jeremy Soller committed
40 41
            space_x: Cell::new(0),
            space_y: Cell::new(0),
42 43 44
            columns: Cell::new(0),
            row_count: Cell::new(0),
            column_count: Cell::new(0),
Jeremy Soller's avatar
Jeremy Soller committed
45
            entries: RefCell::new(BTreeMap::new()),
46
            focused: Cell::new(None),
Jeremy Soller's avatar
Jeremy Soller committed
47 48 49
        })
    }

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
    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);
    }

Jeremy Soller's avatar
Jeremy Soller committed
66
    pub fn insert<T: Widget>(&self, col: usize, row: usize, entry: &Arc<T>) {
Jeremy Soller's avatar
Jeremy Soller committed
67
        self.entries.borrow_mut().insert((col, row), entry.clone());
Jeremy Soller's avatar
Jeremy Soller committed
68
        self.arrange(false);
Jeremy Soller's avatar
Jeremy Soller committed
69 70
    }

71 72 73 74
    pub fn clear(&self) {
        self.entries.borrow_mut().clear();
    }

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

Jeremy Soller's avatar
Jeremy Soller committed
79 80 81 82 83 84
    pub fn spacing(&self, x: i32, y: i32) -> &Self {
        self.space_x.set(x);
        self.space_y.set(y);
        self
    }

Jeremy Soller's avatar
Jeremy Soller committed
85
    pub fn arrange(&self, resize: bool) {
Jeremy Soller's avatar
Jeremy Soller committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
        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;
Jeremy Soller's avatar
Jeremy Soller committed
130 131 132 133
            if resize {
                rect.width = cols[col].width;
                rect.height = rows[row].height;
            }
Jeremy Soller's avatar
Jeremy Soller committed
134
            entry.rect().set(rect);
135 136

            entry.arrange();
Jeremy Soller's avatar
Jeremy Soller committed
137 138 139 140 141 142 143 144 145 146 147
        }
    }
}

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

Jeremy Soller's avatar
Jeremy Soller committed
148
        self.arrange(false);
Jeremy Soller's avatar
Jeremy Soller committed
149 150 151 152 153 154

        self
    }
}

impl Widget for Grid {
MovingtoMars's avatar
MovingtoMars committed
155 156 157 158
    fn name(&self) -> &str {
        "Grid"
    }

Jeremy Soller's avatar
Jeremy Soller committed
159 160 161 162
    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }

163 164 165 166 167 168 169 170 171 172 173 174
    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
    }

175 176 177 178
    fn margin(&self) -> &Cell<Thickness> {
        &self.margin
    }

MovingtoMars's avatar
MovingtoMars committed
179
    fn draw(&self, renderer: &mut Renderer, _focused: bool, theme: &Theme) {
180 181 182 183 184 185 186 187 188
        fn draw_widget(widget: &Arc<Widget>, renderer: &mut 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);
            }
        }

Jeremy Soller's avatar
Jeremy Soller committed
189
        for (&(col, row), entry) in self.entries.borrow().iter() {
190
            draw_widget(entry, renderer, self.focused.get() == Some((col, row)), theme);
Jeremy Soller's avatar
Jeremy Soller committed
191 192 193
        }
    }

Jeremy Soller's avatar
Jeremy Soller committed
194
    fn event(&self, event: Event, mut focused: bool, redraw: &mut bool, caught: &mut bool) -> bool {
Jeremy Soller's avatar
Jeremy Soller committed
195 196
        for (&(col, row), entry) in self.entries.borrow().iter() {
            let is_focused = self.focused.get() == Some((col, row));
Jeremy Soller's avatar
Jeremy Soller committed
197
            if entry.event(event, focused && is_focused, redraw, caught) {
Jeremy Soller's avatar
Jeremy Soller committed
198 199 200 201 202 203 204
                if self.focused.check_set(Some((col, row))) || ! focused {
                    focused = true;
                    *redraw = true;
                }
            } else if is_focused {
                self.focused.set(None);
            }
Jeremy Soller's avatar
Jeremy Soller committed
205 206 207 208

            if *caught {
                break;
            }
Jeremy Soller's avatar
Jeremy Soller committed
209 210
        }

Jeremy Soller's avatar
Jeremy Soller committed
211 212
        focused
    }
213 214 215 216

    fn children(&self) -> &RefCell<Vec<Arc<Widget>>> {
        &self.children
    }
Jeremy Soller's avatar
Jeremy Soller committed
217
}