1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Widgets are the primary elements to create user interfaces with orbtk.
//!
//! This module contains base structures to create widgets and a set of
//! default widgets.

use orbclient::Renderer;
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::sync::Arc;

use event::Event;
use rect::Rect;
use point::Point;
use theme::Theme;
use thickness::Thickness;

pub use self::button::Button;
pub use self::combo_box::ComboBox;
pub use self::label::Label;
pub use self::menu::{Action, Menu, Separator};
pub use self::progress_bar::ProgressBar;
pub use self::text_box::TextBox;
pub use self::list::{Entry, List};

mod button;
mod combo_box;
mod label;
mod menu;
mod progress_bar;
mod text_box;
mod list;

/// Describes the vertical placement of a widget.
#[derive(PartialEq, Copy, Clone)]
pub enum VerticalPlacement {
    Top,
    Center,
    Bottom,
    Absolute,
    Stretch,
}

/// Describes the horizontal placement of a widget.
#[derive(PartialEq, Copy, Clone)]
pub enum HorizontalPlacement {
    Left,
    Center,
    Right,
    Absolute,
    Stretch,
}

/// Represents the base of all widgets.
pub trait Widget: Any {
    /// Borrow the render rect of the widget.
    fn rect(&self) -> &Cell<Rect>;

    /// Borrow the local position of the widget. The local position describes position of the widget relative to it's parent.
    fn local_position(&self) -> &Cell<Point>;

    /// Borrow the vertical placement of the widget.
    fn vertical_placement(&self) -> &Cell<VerticalPlacement>;

    /// Borrow the horizontal placement of the widget.
    fn horizontal_placement(&self) -> &Cell<HorizontalPlacement>;

    /// Borrow the margin of the widget.
    fn margin(&self) -> &Cell<Thickness>;

    /// Used to draw the widget by render code.
    fn draw(&self, _renderer: &mut Renderer, _focused: bool, _theme: &Theme) {}

    /// Handle the incoming events by tunneling from parent to child.
    /// Must have overwritten to create a custom tunneling event handling.
    fn preview_event(&self, _event: Event, _focused: bool, _redraw: &mut bool, _handled: bool) -> bool {
        _focused
    }

    /// Handle the incoming events by bubbling from child to parent.
    /// Must have overwritten to create a custom bubbling event handling.
    fn event(&self, _event: Event, _focused: bool, _redraw: &mut bool, _caught: &mut bool) -> bool {
        false
    }

    /// Return the name of the widget.
    fn name(&self) -> &str;

    /// Borrow the children of the widget.
    fn children(&self) -> &RefCell<Vec<Arc<Widget>>>;

    /// Add a child to the widget.
    fn add(&self, widget: Arc<Widget>) {
        (*self.children().borrow_mut()).push(widget);
        self.arrange();
    }

    /// Used to update the state of the widget. Could be used to update the selector.
    fn update(&self) {}

    /// Arrange the children of the widget. Could be override to create a custom layout.
    fn arrange(&self) {
        let parent_rect = self.rect().get();

        for child in &*self.children().borrow_mut() {
            let mut child_rect = child.rect().get();
            let child_position = child.local_position().get();
            let margin = child.margin().get();

            match child.vertical_placement().get() {
                VerticalPlacement::Absolute => {
                    child_rect.y = parent_rect.y + child_position.y;
                }
                VerticalPlacement::Stretch => {
                    child_rect.height =
                        parent_rect.height - margin.top as u32 - margin.bottom as u32;
                    child_rect.y = parent_rect.y + margin.top;
                }
                VerticalPlacement::Top => {
                    child_rect.y = parent_rect.y + margin.top;
                }
                VerticalPlacement::Center => {
                    child_rect.y = parent_rect.y + parent_rect.height as i32 / 2
                        - child_rect.height as i32 / 2;
                }
                VerticalPlacement::Bottom => {
                    child_rect.y = parent_rect.y + parent_rect.height as i32 - margin.bottom
                        - child_rect.height as i32;
                }
            }

            match child.horizontal_placement().get() {
                HorizontalPlacement::Absolute => {
                    child_rect.x = parent_rect.x + child_position.x;
                }
                HorizontalPlacement::Stretch => {
                    child_rect.width =
                        parent_rect.width - margin.left as u32 - margin.right as u32;
                    child_rect.x = parent_rect.x + margin.left;
                }
                HorizontalPlacement::Left => {
                    child_rect.x = parent_rect.x + margin.left;
                }
                HorizontalPlacement::Center => {
                    child_rect.x = parent_rect.x + parent_rect.width as i32 / 2
                        - child_rect.width as i32 / 2;
                }
                HorizontalPlacement::Right => {
                    child_rect.x = parent_rect.x + parent_rect.width as i32 - margin.right
                        - child_rect.width as i32;
                }
            }

            child.rect().set(child_rect);
            child.arrange();
        }
    }
}