conrod 0.36.0

An easy-to-use, extensible 2D GUI library
Documentation
use {CharacterCache, Scalar};
use backend::{self, Backend, ToRawEvent};
use backend::graphics::{Context, Graphics};
use color::Color;
use event;
use glyph_cache::GlyphCache;
use graph::{self, Graph, NodeIndex};
use position::{Align, Direction, Dimensions, Padding, Place, Point, Position, Range, Rect};
use std;
use std::collections::HashSet;
use std::marker::PhantomData;
use theme::Theme;
use utils;
use widget::{self, Widget};
use input;


/// `Ui` is the most important type within Conrod and is necessary for rendering and maintaining
/// widget state.
/// # Ui Handles the following:
/// * Contains the state of all widgets which can be indexed via their widget::Index.
/// * Stores rendering state for each widget until the end of each render cycle.
/// * Contains the theme used for default styling of the widgets.
/// * Maintains the latest user input state (for mouse and keyboard).
/// * Maintains the latest window dimensions.
pub struct Ui<B>
    where B: Backend,
{
    /// The backend used by the `Ui`, providing the `Graphics` and `CharacterCache` types.
    backend: PhantomData<B>,
    /// The theme used to set default styling for widgets.
    pub theme: Theme,
    /// Cache for character textures, used for label width calculation and glyph rendering.
    pub glyph_cache: GlyphCache<B::CharacterCache>,
    /// An index into the root widget of the graph, representing the entire window.
    pub window: NodeIndex,
    /// Handles aggregation of events and providing them to Widgets
    pub global_input: input::Global,
    /// The Widget cache, storing state for all widgets.
    widget_graph: Graph,
    /// The widget::Index of the widget that was last updated/set.
    maybe_prev_widget_idx: Option<widget::Index>,
    /// The widget::Index of the last widget used as a parent for another widget.
    maybe_current_parent_idx: Option<widget::Index>,
    /// The number of frames that that will be used for the `redraw_count` when `need_redraw` is
    /// triggered.
    num_redraw_frames: u8,
    /// Whether or not the `Ui` needs to be re-drawn to screen.
    redraw_count: u8,
    /// A background color to clear the screen with before drawing if one was given.
    maybe_background_color: Option<Color>,
    /// The order in which widgets from the `widget_graph` are drawn.
    depth_order: graph::DepthOrder,
    /// The set of widgets that have been updated since the beginning of the `set_widgets` stage.
    updated_widgets: HashSet<NodeIndex>,
    /// The `updated_widgets` for the previous `set_widgets` stage.
    ///
    /// We use this to compare against the newly generated `updated_widgets` to see whether or not
    /// we require re-drawing.
    prev_updated_widgets: HashSet<NodeIndex>,
    /// Scroll events that have been emitted during a call to `Ui::set_widgets`. These are usually
    /// emitted by some widget like the `Scrollbar`.
    ///
    /// These events will be drained and pushed onto the end of the `global_input` event buffer at
    /// the end of the `Ui::set_widgets` method. This ensures that the events are received by the
    /// target widgets during the next call to `Ui::set_widgets`.
    pending_scroll_events: Vec<event::Ui>,

    // TODO: Remove the following fields as they should now be handled by `input::Global`.

    /// Window width.
    pub win_w: f64,
    /// Window height.
    pub win_h: f64,
}

/// A wrapper around the `Ui` that restricts the user from mutating the `Ui` in certain ways while
/// in the scope of the `Ui::set_widgets` function and within `Widget`s' `update` methods. Using
/// the `UiCell`, users may access the `Ui` immutably (via `Deref`) however they wish, however they
/// may only mutate the `Ui` via the `&mut self` methods provided by the `UiCell`.
///
/// The name came from its likening to a "jail cell for the `Ui`", as it restricts a user's access
/// to it. However, we realise that the name may also cause ambiguity with the std `Cell` and
/// `RefCell` types (which `UiCell` has nothing to do with). Thus, if you have a better name for
/// this type in mind, please let us know at the github repo via an issue or PR sometime before we
/// hit 1.0.0!
pub struct UiCell<'a, B: 'a>
    where B: Backend,
{
    /// A mutable reference to a **Ui**.
    ui: &'a mut Ui<B>,
}


/// Each time conrod is required to redraw the GUI, it must draw for at least the next three frames
/// to ensure that, in the case that graphics buffers are being swapped, we have filled each
/// buffer. Otherwise if we don't draw into each buffer, we will probably be subject to flickering.
pub const SAFE_REDRAW_COUNT: u8 = 3;


impl<B> Ui<B>
    where B: Backend,
{

    /// A new, empty **Ui**.
    pub fn new(character_cache: B::CharacterCache, theme: Theme) -> Self {
        let widget_graph = Graph::new();
        let depth_order = graph::DepthOrder::new();
        let updated_widgets = HashSet::new();
        Self::new_internal(character_cache, theme, widget_graph, depth_order, updated_widgets)
    }

    /// A new **Ui** with the capacity given as a number of widgets.
    pub fn with_capacity(character_cache: B::CharacterCache,
                         theme: Theme,
                         n_widgets: usize) -> Self
    {
        let widget_graph = Graph::with_node_capacity(n_widgets);
        let depth_order = graph::DepthOrder::with_node_capacity(n_widgets);
        let updated_widgets = HashSet::with_capacity(n_widgets);
        Self::new_internal(character_cache, theme, widget_graph, depth_order, updated_widgets)
    }

    /// An internal constructor to share logic between the `new` and `with_capacity` constructors.
    fn new_internal(character_cache: B::CharacterCache,
                    theme: Theme,
                    mut widget_graph: Graph,
                    depth_order: graph::DepthOrder,
                    updated_widgets: HashSet<NodeIndex>) -> Self
    {
        let window = widget_graph.add_placeholder();
        let prev_updated_widgets = updated_widgets.clone();
        Ui {
            backend: PhantomData,
            widget_graph: widget_graph,
            theme: theme,
            window: window,
            glyph_cache: GlyphCache::new(character_cache),
            win_w: 0.0,
            win_h: 0.0,
            maybe_prev_widget_idx: None,
            maybe_current_parent_idx: None,
            num_redraw_frames: SAFE_REDRAW_COUNT,
            redraw_count: SAFE_REDRAW_COUNT,
            maybe_background_color: None,
            depth_order: depth_order,
            updated_widgets: updated_widgets,
            prev_updated_widgets: prev_updated_widgets,
            global_input: input::Global::new(),
            pending_scroll_events: Vec::new(),
        }
    }

    /// Returns a `input::Widget` for the given widget
    pub fn widget_input<I: Into<widget::Index>>(&self, widget: I) -> input::Widget {
        let idx = widget.into();

        // If there's no rectangle for a given widget, then we use one with zero area.
        // This means that the resulting `input::Widget` will not include any mouse events
        // unless it has captured the mouse, since none will have occured over that area.
        let rect = self.rect_of(idx).unwrap_or_else(|| {
            let right_edge = self.win_w / 2.0;
            let bottom_edge = self.win_h / 2.0;
            Rect::from_xy_dim([right_edge, bottom_edge], [0.0, 0.0])
        });
        input::Widget::for_widget(idx, rect, &self.global_input)
    }

    /// The **Rect** for the widget at the given index.
    ///
    /// Returns `None` if there is no widget for the given index.
    pub fn rect_of<I: Into<widget::Index>>(&self, idx: I) -> Option<Rect> {
        let idx: widget::Index = idx.into();
        self.widget_graph.widget(idx).map(|widget| widget.rect)
    }

    /// The absolute width of the widget at the given index.
    ///
    /// Returns `None` if there is no widget for the given index.
    pub fn w_of<I: Into<widget::Index>>(&self, idx: I) -> Option<Scalar> {
        self.rect_of(idx).map(|rect| rect.w())
    }

    /// The absolute height of the widget at the given index.
    ///
    /// Returns `None` if there is no widget for the given index.
    pub fn h_of<I: Into<widget::Index>>(&self, idx: I) -> Option<Scalar> {
        self.rect_of(idx).map(|rect| rect.h())
    }

    /// The absolute dimensions for the widget at the given index.
    ///
    /// Returns `None` if there is no widget for the given index.
    pub fn wh_of<I: Into<widget::Index>>(&self, idx: I) -> Option<Dimensions> {
        self.rect_of(idx).map(|rect| rect.dim())
    }

    /// The coordinates for the widget at the given index.
    ///
    /// Returns `None` if there is no widget for the given index.
    pub fn xy_of<I: Into<widget::Index>>(&self, idx: I) -> Option<Point> {
        self.rect_of(idx).map(|rect| rect.xy())
    }

    /// The `kid_area` of the widget at the given index.
    ///
    /// Returns `None` if there is no widget for the given index.
    pub fn kid_area_of<I: Into<widget::Index>>(&self, idx: I) -> Option<Rect> {
        let idx: widget::Index = idx.into();
        self.widget_graph.widget(idx).map(|widget| {
            widget.kid_area.rect.padding(widget.kid_area.pad)
        })
    }

    /// An index to the previously updated widget if there is one.
    pub fn maybe_prev_widget(&self) -> Option<widget::Index> {
        self.maybe_prev_widget_idx
    }

    /// Borrow the **Ui**'s `widget_graph`.
    pub fn widget_graph(&self) -> &Graph {
        &self.widget_graph
    }

    /// Borrow the **Ui**'s set of updated widgets.
    ///
    /// This set indicates which widgets have been instantiated since the beginning of the most
    /// recent `Ui::set_widgets` call.
    pub fn updated_widgets(&self) -> &HashSet<NodeIndex> {
        &self.updated_widgets
    }

    /// Borrow the **Ui**'s set of updated widgets.
    ///
    /// This set indicates which widgets have were instantiated during the previous call to
    /// `Ui::set_widgets`.
    pub fn prev_updated_widgets(&self) -> &HashSet<NodeIndex> {
        &self.prev_updated_widgets
    }

    /// Scroll the widget at the given index by the given offset amount.
    ///
    /// The produced `Scroll` event will be applied upon the next call to `Ui::set_widgets`.
    pub fn scroll_widget<I>(&mut self, widget_idx: I, offset: [Scalar; 2])
        where I: Into<widget::Index>,
    {
        let widget_idx = widget_idx.into();
        let (x, y) = (offset[0], offset[1]);

        if x != 0.0 || y != 0.0 {
            let event = event::Ui::Scroll(Some(widget_idx), event::Scroll {
                x: x,
                y: y,
                modifiers: self.global_input.current.modifiers,
            }).into();
            self.global_input.push_event(event);
        }
    }

    /// Handle raw window events and update the `Ui` state accordingly.
    ///
    /// This occurs within several stages:
    ///
    /// 1. Convert the user's given `event` to a `RawEvent` so that the `Ui` may use it.
    /// 2. Interpret the `RawEvent` for higher-level `Event`s such as `DoubleClick`,
    ///    `WidgetCapturesKeyboard`, etc.
    /// 3. Update the `Ui`'s `global_input` `State` accordingly, depending on the `RawEvent`.
    /// 4. Store newly produced `event::Ui`s within the `global_input` so that they may be filtered
    ///    and fed to `Widget`s next time `Ui::set_widget` is called.
    ///
    /// This method *drives* the `Ui` forward, and is what allows for using conrod's `Ui` with any
    /// window event stream.
    ///
    /// The given `event` must implement the **ToRawEvent** trait so that it can be converted to a
    /// `RawEvent` that can be used by the `Ui`.
    pub fn handle_event<E>(&mut self, event: E)
        where E: ToRawEvent,
    {
        use backend::event::{Input, Motion, Key, ModifierKey, RawEvent};

        // Determines which widget is currently under the mouse and sets it within the `Ui`'s
        // `input::Global`'s `input::State`.
        //
        // If the `widget_under_mouse` has changed, this function will also update the
        // `widget_capturing_mouse`.
        //
        // If the left mouse button is up, we assume that the widget directly under the
        // mouse cursor captures all input from the mouse.
        //
        // If the left mouse button is down, we assume that the widget that was clicked
        // remains "pinned" and will continue to capture the mouse until it is
        // released.
        //
        // Note: This function expects that `ui.global_input.current.mouse.xy` is up-to-date.
        fn track_widget_under_mouse_and_update_capturing<B: Backend>(ui: &mut Ui<B>) {
            ui.global_input.current.widget_under_mouse =
                graph::algo::pick_widgets(&ui.depth_order.indices,
                                          ui.global_input.current.mouse.xy)
                                          .next(&ui.widget_graph, &ui.depth_order.indices);

            // If MouseButton::Left is up and `widget_under_mouse` has changed, capture new widget
            // under mouse.
            if ui.global_input.current.mouse.buttons.left().is_up() {
                let widget_under_mouse = ui.global_input.current.widget_under_mouse;

                // Check to see if we need to uncapture a widget.
                if let Some(idx) = ui.global_input.current.widget_capturing_mouse {
                    if widget_under_mouse != Some(idx) {
                        let event = event::Ui::WidgetUncapturesMouse(idx).into();
                        ui.global_input.push_event(event);
                        ui.global_input.current.widget_capturing_mouse = None;
                    }
                }

                // Check to see if there is a new widget capturing the mouse.
                if ui.global_input.current.widget_capturing_mouse.is_none() {
                    if let Some(idx) = widget_under_mouse {
                        let event = event::Ui::WidgetCapturesMouse(idx).into();
                        ui.global_input.push_event(event);
                        ui.global_input.current.widget_capturing_mouse = Some(idx);
                    }
                }
            }
        }

        // A function for filtering `ModifierKey`s.
        fn filter_modifier(key: Key) -> Option<ModifierKey> {
            use backend::event::keyboard::{CTRL, SHIFT, ALT, GUI};
            match key {
                Key::LCtrl | Key::RCtrl => Some(CTRL),
                Key::LShift | Key::RShift => Some(SHIFT),
                Key::LAlt | Key::RAlt => Some(ALT),
                Key::LGui | Key::RGui => Some(GUI),
                _ => None
            }
        }

        // Convert the user given event to a `RawEvent` or return early if we cannot.
        let event: RawEvent = match event.to_raw_event(self.win_w, self.win_h) {
            Some(event) => event,
            None => return,
        };

        match event {

            // On each `Render` we should check that our window dimensions are up to date.
            //
            // This event is also the first time that we receive the proper dimensions of the
            // window (when the `Ui` is created, the dimensions are set to `0`).
            backend::event::Event::Render(args) => {
                let (w, h) = (args.width as Scalar, args.height as Scalar);
                if self.win_w != w || self.win_h != h {
                    self.win_w = w;
                    self.win_h = h;
                    track_widget_under_mouse_and_update_capturing(self);
                }
            },

            // Here we handle all user input given to conrod.
            //
            // Not only do we store the `Input` event as a `Event::Raw`, we also use them to
            // interpret higher level events such as `Click` or `Drag`.
            //
            // Finally, we also ensure that the `current_state` is up-to-date.
            backend::event::Event::Input(input_event) => {
                use event;
                use input::Button;
                use input::state::mouse::Button as MouseButton;

                // Update our global_input with the raw input event.
                self.global_input.push_event(input_event.clone().into());

                match input_event {

                    // Some button was pressed, whether keyboard, mouse or some other device.
                    Input::Press(button_type) => match button_type {

                        // Check to see whether we need to (un)capture the keyboard or mouse.
                        Button::Mouse(mouse_button) => {

                            // Create a mouse `Press` event.
                            let mouse_xy = self.global_input.current.mouse.xy;
                            let press = event::Press {
                                button: event::Button::Mouse(mouse_button, mouse_xy),
                                modifiers: self.global_input.current.modifiers,
                            };
                            let widget = self.global_input.current.widget_capturing_mouse;
                            let press_event = event::Ui::Press(widget, press).into();
                            self.global_input.push_event(press_event);

                            if let MouseButton::Left = mouse_button {
                                // Check to see if we need to uncapture the keyboard.
                                if let Some(idx) = self.global_input.current.widget_capturing_keyboard {
                                    if Some(idx) != self.global_input.current.widget_under_mouse {
                                        let event = event::Ui::WidgetUncapturesKeyboard(idx).into();
                                        self.global_input.push_event(event);
                                        self.global_input.current.widget_capturing_keyboard = None;
                                    }
                                }

                                // Check to see if we need to capture the keyboard.
                                if let Some(idx) = self.global_input.current.widget_under_mouse {
                                    let event = event::Ui::WidgetCapturesKeyboard(idx).into();
                                    self.global_input.push_event(event);
                                    self.global_input.current.widget_capturing_keyboard = Some(idx);
                                }
                            }

                            // Keep track of pressed buttons in the current input::State.
                            let xy = self.global_input.current.mouse.xy;
                            let widget = self.global_input.current.widget_under_mouse;
                            self.global_input.current.mouse.buttons.press(mouse_button, xy, widget);
                        },

                        Button::Keyboard(key) => {

                            // Create a keyboard `Press` event.
                            let press = event::Press {
                                button: event::Button::Keyboard(key),
                                modifiers: self.global_input.current.modifiers,
                            };
                            let widget = self.global_input.current.widget_capturing_keyboard;
                            let press_event = event::Ui::Press(widget, press).into();
                            self.global_input.push_event(press_event);

                            // If some modifier key was pressed, add it to the current modifiers.
                            if let Some(modifier) = filter_modifier(key) {
                                self.global_input.current.modifiers.insert(modifier);
                            }

                            // If `Esc` was pressed, check to see if we need to cancel a `Drag` or
                            // uncapture a widget.
                            if let Key::Escape = key {
                                // TODO:
                                // 1. Cancel `Drag` if currently under way.
                                // 2. If mouse is captured due to pinning widget with left mouse button,
                                //    cancel capturing.
                            }
                        },

                        _ => {}
                    },

                    // Some button was released.
                    //
                    // Checks for events in the following order:
                    // 1. Click
                    // 2. DoubleClick
                    // 2. WidgetUncapturesMouse
                    Input::Release(button_type) => match button_type {
                        Button::Mouse(mouse_button) => {

                            // Create a `Release` event.
                            let mouse_xy = self.global_input.current.mouse.xy;
                            let release = event::Release {
                                button: event::Button::Mouse(mouse_button, mouse_xy),
                                modifiers: self.global_input.current.modifiers,
                            };
                            let widget = self.global_input.current.widget_capturing_mouse;
                            let release_event = event::Ui::Release(widget, release).into();
                            self.global_input.push_event(release_event);

                            // Check for `Click` and `DoubleClick` events.
                            let down = self.global_input.current.mouse.buttons[mouse_button].if_down();
                            if let Some((_, widget)) = down {

                                // The widget that's being clicked.
                                let clicked_widget = self.global_input.current.widget_under_mouse
                                    .and_then(|released| widget.and_then(|pressed| {
                                        if pressed == released { Some(released) } else { None }
                                    }));

                                let click = event::Click {
                                    button: mouse_button,
                                    xy: self.global_input.current.mouse.xy,
                                    modifiers: self.global_input.current.modifiers,
                                };

                                let click_event = event::Ui::Click(clicked_widget, click).into();
                                self.global_input.push_event(click_event);

                                let now = std::time::Instant::now();
                                let double_click = self.global_input.last_click
                                    .and_then(|(last_time, last_click)| {

                                        // If the button of this click is different to the button
                                        // of last click, don't create a `DoubleClick`.
                                        if click.button != last_click.button {
                                            return None;
                                        }

                                        // If the mouse has moved since the last click, don't
                                        // create a `DoubleClick`.
                                        if click.xy != last_click.xy {
                                            return None;
                                        }

                                        // If the duration since the last click is longer than the
                                        // double_click_threshold, don't create a `DoubleClick`.
                                        let duration = now.duration_since(last_time);
                                        // TODO: Work out how to get this threshold from the user's
                                        // system preferences.
                                        let threshold = self.theme.double_click_threshold;
                                        if duration >= threshold {
                                            return None;
                                        }

                                        Some(event::DoubleClick {
                                            button: click.button,
                                            xy: click.xy,
                                            modifiers: click.modifiers,
                                        })
                                    });

                                if let Some(double_click) = double_click {
                                    // Reset the `last_click` to `None`, as to not register another
                                    // `DoubleClick` on the next consecutive `Click`.
                                    self.global_input.last_click = None;
                                    let double_click_event =
                                        event::Ui::DoubleClick(clicked_widget, double_click).into();
                                    self.global_input.push_event(double_click_event);

                                } else {
                                    // Set the `Click` that we just stored as the `last_click`.
                                    self.global_input.last_click = Some((now, click));
                                }
                            }

                            // Uncapture widget capturing mouse if MouseButton::Left is down and
                            // widget_under_mouse != capturing widget.
                            if let MouseButton::Left = mouse_button {
                                if let Some(idx) = self.global_input.current.widget_capturing_mouse {
                                    if Some(idx) != self.global_input.current.widget_under_mouse {
                                        let event = event::Ui::WidgetUncapturesMouse(idx).into();
                                        self.global_input.push_event(event);
                                        self.global_input.current.widget_capturing_mouse = None;
                                    }
                                }
                            }

                            // Release the given mouse_button from the input::State.
                            self.global_input.current.mouse.buttons.release(mouse_button);
                        },
                        
                        Button::Keyboard(key) => {

                            // Create a `Release` event.
                            let release = event::Release {
                                button: event::Button::Keyboard(key),
                                modifiers: self.global_input.current.modifiers,
                            };
                            let widget = self.global_input.current.widget_capturing_keyboard;
                            let release_event = event::Ui::Release(widget, release).into();
                            self.global_input.push_event(release_event);

                            // If a modifier key was released, remove it from the current set.
                            if let Some(modifier) = filter_modifier(key) {
                                self.global_input.current.modifiers.remove(modifier);
                            }
                        },

                        _ => (),
                    },

                    // The window was resized.
                    Input::Resize(w, h) => {

                        // Create a `WindowResized` event.
                        let dim = [w as Scalar, h as Scalar];
                        let window_resized = event::Ui::WindowResized(dim).into();
                        self.global_input.push_event(window_resized);

                        self.win_w = w as Scalar;
                        self.win_h = h as Scalar;
                        self.needs_redraw();
                    },

                    // The mouse cursor was moved to a new position.
                    //
                    // Checks for events in the following order:
                    // 1. `Drag`
                    // 2. `WidgetUncapturesMouse`
                    // 3. `WidgetCapturesMouse`
                    Input::Move(motion) => {

                        // Create a `Move` event.
                        let move_ = event::Move {
                            motion: motion,
                            modifiers: self.global_input.current.modifiers,
                        };
                        let widget = self.global_input.current.widget_capturing_mouse;
                        let move_event = event::Ui::Move(widget, move_).into();
                        self.global_input.push_event(move_event);

                        match motion {

                            Motion::MouseCursor(x, y) => {

                                // Check for drag events.
                                let last_mouse_xy = self.global_input.current.mouse.xy;
                                let mouse_xy = [x, y];
                                let delta_xy = utils::vec2_sub(mouse_xy, last_mouse_xy);
                                let distance = (delta_xy[0] + delta_xy[1]).abs().sqrt();
                                if distance > self.theme.mouse_drag_threshold {
                                    // For each button that is down, trigger a drag event.
                                    let buttons = self.global_input.current.mouse.buttons.clone();
                                    for (btn, btn_xy, widget) in buttons.pressed() {
                                        let total_delta_xy = utils::vec2_sub(mouse_xy, btn_xy);
                                        let event = event::Ui::Drag(widget, event::Drag {
                                            button: btn,
                                            origin: btn_xy,
                                            from: last_mouse_xy,
                                            to: mouse_xy,
                                            delta_xy: delta_xy,
                                            total_delta_xy: total_delta_xy,
                                            modifiers: self.global_input.current.modifiers,
                                        }).into();
                                        self.global_input.push_event(event);
                                    }
                                }

                                // TODO: Check for dragging of the scrollbar, and whether or not a
                                // `event::Scroll` needs to be created.

                                // Update the position of the mouse within the global_input's
                                // input::State.
                                self.global_input.current.mouse.xy = mouse_xy;

                                track_widget_under_mouse_and_update_capturing(self);
                            },

                            // The mouse was scrolled.
                            Motion::MouseScroll(x, y) => {

                                let mut scrollable_widgets = {
                                    let depth_order = &self.depth_order.indices;
                                    let mouse_xy = self.global_input.current.mouse.xy;
                                    graph::algo::pick_scrollable_widgets(depth_order, mouse_xy)
                                };

                                // Iterate through the scrollable widgets from top to bottom.
                                //
                                // A scroll event will be created for the first scrollable widget
                                // that hasn't already reached the bound of the scroll event's
                                // direction.
                                while let Some(idx) =
                                    scrollable_widgets.next(&self.widget_graph,
                                                            &self.depth_order.indices)
                                {

                                    let (kid_area, maybe_x_scroll, maybe_y_scroll) =
                                        match self.widget_graph.widget(idx) {
                                            Some(widget) => {
                                                (widget.kid_area,
                                                 widget.maybe_x_scroll_state,
                                                 widget.maybe_y_scroll_state)
                                            },
                                            None => continue,
                                        };

                                    fn offset_is_at_bound<A>(scroll: &widget::scroll::State<A>,
                                                             additional_offset: Scalar) -> bool
                                    {
                                        use utils;

                                        fn approx_eq(a: Scalar, b: Scalar) -> bool {
                                            (a - b).abs() < 0.000001
                                        }

                                        if additional_offset.is_sign_positive() {
                                            let max = utils::partial_max(scroll.offset_bounds.start,
                                                                         scroll.offset_bounds.end);
                                            approx_eq(scroll.offset, max)
                                        } else {
                                            let min = utils::partial_min(scroll.offset_bounds.start,
                                                                         scroll.offset_bounds.end);
                                            approx_eq(scroll.offset, min)
                                        }
                                    }

                                    let mut scroll_x = false;
                                    let mut scroll_y = false;

                                    // Check whether the x axis is scrollable.
                                    if x != 0.0 {
                                        let new_scroll =
                                            widget::scroll::State::update(self, idx, &kid_area,
                                                                          maybe_x_scroll, x);
                                        if let Some(prev_scroll) = maybe_x_scroll {
                                            let (prev_is_at_bound, new_is_at_bound) =
                                                (offset_is_at_bound(&prev_scroll, x),
                                                 offset_is_at_bound(&new_scroll, x));
                                            scroll_x = !prev_is_at_bound || !new_is_at_bound;
                                        }
                                    }

                                    // Check whether the y axis is scrollable.
                                    if y != 0.0 {
                                        let new_scroll =
                                            widget::scroll::State::update(self, idx, &kid_area,
                                                                          maybe_y_scroll, y);
                                        if let Some(prev_scroll) = maybe_y_scroll {
                                            let (prev_is_at_bound, new_is_at_bound) =
                                                (offset_is_at_bound(&prev_scroll, y),
                                                 offset_is_at_bound(&new_scroll, y));
                                            scroll_y = !prev_is_at_bound || !new_is_at_bound;
                                        }
                                    }

                                    // Create a `Scroll` event if either axis is scrollable.
                                    if scroll_x || scroll_y {
                                        let event = event::Ui::Scroll(Some(idx), event::Scroll {
                                            x: x,
                                            y: y,
                                            modifiers: self.global_input.current.modifiers,
                                        }).into();
                                        self.global_input.push_event(event);

                                        // Now that we've scrolled the top, scrollable widget,
                                        // we're done with the loop.
                                        break;
                                    }
                                }

                                // If no scrollable widgets could be scrolled, emit the event to
                                // the widget that currently captures the mouse.
                                if x != 0.0 || y != 0.0 {
                                    let widget = self.global_input.current.widget_capturing_mouse;
                                    if let Some(idx) = widget {
                                        if let Some(widget) = self.widget_graph.widget(idx) {
                                            // Only create the event if the widget is not
                                            // scrollable, as the event would have already been
                                            // created within the above loop.
                                            if widget.maybe_x_scroll_state.is_none()
                                            && widget.maybe_y_scroll_state.is_none() {
                                                let scroll = event::Scroll {
                                                    x: x,
                                                    y: y,
                                                    modifiers: self.global_input.current.modifiers,
                                                };
                                                let event = event::Ui::Scroll(Some(idx), scroll);
                                                self.global_input.push_event(event.into());
                                            }
                                        }
                                    }
                                }

                                // Now that there might be a different widget under the mouse, we
                                // must update the capturing state.
                                track_widget_under_mouse_and_update_capturing(self);
                            },

                            _ => (),

                        }
                    },

                    Input::Text(string) => {
                        // Create a `Text` event.
                        let text = event::Text {
                            string: string,
                            modifiers: self.global_input.current.modifiers,
                        };
                        let widget = self.global_input.current.widget_capturing_keyboard;
                        let text_event = event::Ui::Text(widget, text).into();
                        self.global_input.push_event(text_event);
                    },

                    _ => (),
                }

            },

            _ => (),
        }
    }

    /// Get the centred xy coords for some given `Dimension`s, `Position` and alignment.
    ///
    /// If getting the xy for a specific widget, its `widget::Index` should be specified so that we
    /// can also consider the scroll offset of the scrollable parent widgets.
    ///
    /// The `place_on_kid_area` argument specifies whether or not **Place** **Position** variants
    /// should target a **Widget**'s `kid_area`, or simply the **Widget**'s total area.
    pub fn calc_xy(&self,
                   maybe_idx: Option<widget::Index>,
                   x_position: Position,
                   y_position: Position,
                   dim: Dimensions,
                   place_on_kid_area: bool) -> Point
    {
        use utils::vec2_add;

        // Retrieves the absolute **Scalar** position from the given position for a single axis.
        //
        // The axis used is specified by the given range_from_rect function which, given some
        // **Rect**, returns the relevant **Range**.
        fn abs_from_position<B, R, P>(ui: &Ui<B>,
                                      position: Position,
                                      dim: Scalar,
                                      place_on_kid_area: bool,
                                      range_from_rect: R,
                                      start_and_end_pad: P) -> Scalar
            where B: Backend,
                  R: FnOnce(Rect) -> Range,
                  P: FnOnce(Padding) -> Range,
        {
            match position {

                Position::Absolute(abs) => abs,

                Position::Relative(rel, maybe_idx) =>
                    maybe_idx.or(ui.maybe_prev_widget_idx).or(Some(ui.window.into()))
                        .and_then(|idx| ui.rect_of(idx).map(range_from_rect))
                        .map(|other_range| other_range.middle() + rel)
                        .unwrap_or(rel),

                Position::Direction(direction, amt, maybe_idx) =>
                    maybe_idx.or(ui.maybe_prev_widget_idx)
                        .and_then(|idx| ui.rect_of(idx).map(range_from_rect))
                        .map(|other_range| {
                            let range = Range::from_pos_and_len(0.0, dim);
                            match direction {
                                Direction::Forwards => range.align_after(other_range).middle() + amt,
                                Direction::Backwards => range.align_before(other_range).middle() - amt,
                            }
                        })
                        .unwrap_or_else(|| match direction {
                            Direction::Forwards => amt,
                            Direction::Backwards => -amt,
                        }),

                Position::Align(align, maybe_idx) =>
                    maybe_idx.or(ui.maybe_prev_widget_idx).or(Some(ui.window.into()))
                        .and_then(|idx| ui.rect_of(idx).map(range_from_rect))
                        .map(|other_range| {
                            let range = Range::from_pos_and_len(0.0, dim);
                            match align {
                                Align::Start => range.align_start_of(other_range).middle(),
                                Align::Middle => other_range.middle(),
                                Align::End => range.align_end_of(other_range).middle(),
                            }
                        })
                        .unwrap_or(0.0),

                Position::Place(place, maybe_idx) => {
                    let parent_idx = maybe_idx
                        .or(ui.maybe_current_parent_idx)
                        .unwrap_or(ui.window.into());
                    let maybe_area = match place_on_kid_area {
                        true => ui.widget_graph.widget(parent_idx)
                            .map(|w| w.kid_area)
                            .map(|k| (range_from_rect(k.rect), start_and_end_pad(k.pad))),
                        false => ui.rect_of(parent_idx)
                            .map(|rect| (range_from_rect(rect), Range::new(0.0, 0.0))),
                    };
                    maybe_area
                        .map(|(parent_range, pad)| {
                            let range = Range::from_pos_and_len(0.0, dim);
                            let parent_range = parent_range.pad_start(pad.start).pad_end(pad.end);
                            match place {
                                Place::Start(maybe_mgn) =>
                                    range.align_start_of(parent_range).middle() + maybe_mgn.unwrap_or(0.0),
                                Place::Middle =>
                                    parent_range.middle(),
                                Place::End(maybe_mgn) =>
                                    range.align_end_of(parent_range).middle() - maybe_mgn.unwrap_or(0.0),
                            }
                        })
                        .unwrap_or(0.0)
                },

            }
        }

        fn x_range(rect: Rect) -> Range { rect.x }
        fn y_range(rect: Rect) -> Range { rect.y }
        fn x_pad(pad: Padding) -> Range { pad.x }
        fn y_pad(pad: Padding) -> Range { pad.y }
        let x = abs_from_position(self, x_position, dim[0], place_on_kid_area, x_range, x_pad);
        let y = abs_from_position(self, y_position, dim[1], place_on_kid_area, y_range, y_pad);
        let xy = [x, y];

        // Add the widget's parents' total combined scroll offset to the given xy.
        maybe_idx
            .map(|idx| vec2_add(xy, graph::algo::scroll_offset(&self.widget_graph, idx)))
            .unwrap_or(xy)
    }


    /// A function within which all widgets are instantiated by the user, normally situated within
    /// the "update" stage of an event loop.
    pub fn set_widgets<F>(&mut self, user_widgets_fn: F)
        where F: FnOnce(UiCell<B>),
    {
        self.maybe_prev_widget_idx = None;
        self.maybe_current_parent_idx = None;

        // Move the previous `updated_widgets` to `prev_updated_widgets` and clear
        // `updated_widgets` so that we're ready to store the newly updated widgets.
        {
            let Ui { ref mut updated_widgets, ref mut prev_updated_widgets, .. } = *self;
            std::mem::swap(updated_widgets, prev_updated_widgets);
            updated_widgets.clear();
        }

        // Instantiate the root `Window` `Widget`.
        //
        // This widget acts as the parent-most widget and root node for the Ui's `widget_graph`,
        // upon which all other widgets are placed.
        {
            use {color, Colorable, Frameable, FramedRectangle, Positionable, Widget};
            type Window = FramedRectangle;
            Window::new([self.win_w, self.win_h])
                .no_parent()
                .x_y(0.0, 0.0)
                .frame(0.0)
                .frame_color(color::BLACK.alpha(0.0))
                .color(self.maybe_background_color.unwrap_or(color::BLACK.alpha(0.0)))
                .set(self.window, &mut UiCell { ui: self });
        }

        self.maybe_current_parent_idx = Some(self.window.into());

        // Call the given user function for instantiating Widgets.
        user_widgets_fn(UiCell { ui: self });

        // We'll need to re-draw if we have gained or lost widgets.
        if self.updated_widgets != self.prev_updated_widgets {
            self.needs_redraw();
        }

        // Update the **DepthOrder** so that it reflects the **Graph**'s current state.
        {
            let Ui {
                ref widget_graph,
                ref mut depth_order,
                window,
                ref updated_widgets,
                ..
            } = *self;

            depth_order.update(widget_graph, window, updated_widgets);
        }

        // Reset the global input state. Note that this is the **only** time this should be called.
        self.global_input.clear_events_and_update_start_state();

        // Move all pending `Scroll` events that have been produced since the start of this method
        // into the `global_input` event buffer.
        for scroll_event in self.pending_scroll_events.drain(0..) {
            self.global_input.push_event(scroll_event.into());
        }
    }


    /// Set the number of frames that the `Ui` should draw in the case that `needs_redraw` is
    /// called. The default is `3` (see the SAFE_REDRAW_COUNT docs for details).
    pub fn set_num_redraw_frames(&mut self, num_frames: u8) {
        self.num_redraw_frames = num_frames;
    }


    /// Tells the `Ui` that it needs to be re-draw everything. It does this by setting the redraw
    /// count to `num_redraw_frames`. See the docs for `set_num_redraw_frames`, SAFE_REDRAW_COUNT
    /// or `draw_if_changed` for more info on how/why the redraw count is used.
    pub fn needs_redraw(&mut self) {
        self.redraw_count = self.num_redraw_frames;
    }


    /// Draw the `Ui` in it's current state.
    ///
    /// NOTE: If you don't need to redraw your conrod GUI every frame, it is recommended to use the
    /// `Ui::draw_if_changed` method instead.
    pub fn draw<G>(&mut self, context: Context, graphics: &mut G)
        where G: Graphics<Texture=B::Texture>,
    {
        use backend::graphics::{draw_from_graph, Transformed};
        use std::ops::{Deref, DerefMut};

        let Ui {
            ref mut glyph_cache,
            ref mut redraw_count,
            ref widget_graph,
            ref depth_order,
            ref theme,
            ..
        } = *self;

        let view_size = context.get_view_size();
        let context = context.trans(view_size[0] / 2.0, view_size[1] / 2.0).scale(1.0, -1.0);

        // Retrieve the `CharacterCache` from the `Ui`'s `GlyphCache`.
        let mut ref_mut_character_cache = glyph_cache.deref().borrow_mut();
        let character_cache = ref_mut_character_cache.deref_mut();

        // Use the depth_order indices as the order for drawing.
        let indices = &depth_order.indices;

        // Draw the `Ui` from the `widget_graph`.
        draw_from_graph::<B, G>(context, graphics, character_cache, widget_graph, indices, theme);

        // Because we just drew everything, take one from the redraw count.
        if *redraw_count > 0 {
            *redraw_count -= 1;
        }
    }


    /// Same as the `Ui::draw` method, but *only* draws if the `redraw_count` is greater than 0.
    ///
    /// The `redraw_count` is set to `SAFE_REDRAW_COUNT` whenever a `Widget` indicates that it
    /// needs to be re-drawn.
    ///
    /// It can also be triggered manually by the user using the `Ui::needs_redraw` method.
    ///
    /// This method is generally preferred over `Ui::draw` as it requires far less CPU usage, only
    /// redrawing to the screen if necessary.
    ///
    /// Note that when `Ui::needs_redraw` is triggered, it sets the `redraw_count` to 3 by default.
    /// This ensures that conrod is drawn to each buffer in the case that there is buffer swapping
    /// happening. Let us know if you need finer control over this and we'll expose a way for you
    /// to set the redraw count manually.
    pub fn draw_if_changed<G>(&mut self, context: Context, graphics: &mut G)
        where G: Graphics<Texture=B::Texture>,
    {
        if self.redraw_count > 0 {
            self.draw(context, graphics);
        }
    }


    /// The **Rect** that bounds the kids of the widget with the given index.
    pub fn kids_bounding_box<I: Into<widget::Index>>(&self, idx: I) -> Option<Rect> {
        let idx: widget::Index = idx.into();
        graph::algo::kids_bounding_box(&self.widget_graph, &self.prev_updated_widgets, idx)
    }


    /// The **Rect** that represents the maximum fully visible area for the widget with the given
    /// index, including consideration of cropped scroll area.
    ///
    /// Otherwise, return None if the widget is not visible.
    pub fn visible_area<I: Into<widget::Index>>(&self, idx: I) -> Option<Rect> {
        let idx: widget::Index = idx.into();
        graph::algo::cropped_area_of_widget(&self.widget_graph, idx)
    }

}


impl<'a, B> UiCell<'a, B>
    where B: Backend,
{

    /// A reference to the `Theme` that is currently active within the `Ui`.
    pub fn theme(&self) -> &Theme { &self.ui.theme }

    /// A reference to the `Ui`'s `GlyphCache`.
    pub fn glyph_cache(&self) -> &GlyphCache<B::CharacterCache> { &self.ui.glyph_cache }

    /// Returns the dimensions of the window
    pub fn window_dim(&self) -> Dimensions {
        [self.ui.win_w, self.ui.win_h]
    }

    /// Returns an immutable reference to the `input::Global` of the `Ui`.
    ///
    /// All coordinates here will be relative to the center of the window.
    pub fn global_input(&self) -> &input::Global {
        &self.ui.global_input
    }

    /// Returns a `input::Widget` with input events for the widget.
    ///
    /// All coordinates in the `input::Widget` will be relative to the widget at the given index.
    pub fn widget_input<I: Into<widget::Index>>(&self, idx: I) -> input::Widget {
        self.ui.widget_input(idx.into())
    }

    /// Generate a new, unique NodeIndex into a Placeholder node within the `Ui`'s widget graph.
    /// This should only be called once for each unique widget needed to avoid unnecessary bloat
    /// within the `Ui`'s widget graph.
    ///
    /// When using this method in your `Widget`'s `update` method, be sure to store the returned
    /// NodeIndex somewhere within your `Widget::State` so that it can be re-used on next update.
    ///
    /// **Panics** if adding another node would exceed the maximum capacity for node indices.
    pub fn new_unique_node_index(&mut self) -> NodeIndex {
        widget_graph_mut(&mut self.ui).add_placeholder()
    }

    /// The **Rect** that bounds the kids of the widget with the given index.
    ///
    /// Returns `None` if the widget has no children or if there's is no widget for the given index.
    pub fn kids_bounding_box<I: Into<widget::Index>>(&self, idx: I) -> Option<Rect> {
        self.ui.kids_bounding_box(idx)
    }

    /// Scroll the widget at the given index by the given offset amount.
    ///
    /// The produced `Scroll` event will be pushed to the `pending_scroll_events` and will be
    /// applied to the widget during the next call to `Ui::set_widgets`.
    pub fn scroll_widget<I>(&mut self, widget_idx: I, offset: [Scalar; 2])
        where I: Into<widget::Index>
    {
        let widget_idx = widget_idx.into();
        let (x, y) = (offset[0], offset[1]);

        if x != 0.0 || y != 0.0 {
            let event = event::Ui::Scroll(Some(widget_idx), event::Scroll {
                x: x,
                y: y,
                modifiers: self.ui.global_input.current.modifiers,
            });
            self.ui.pending_scroll_events.push(event);
        }
    }

}

impl<'a, B> ::std::ops::Deref for UiCell<'a, B>
    where B: Backend,
{
    type Target = Ui<B>;
    fn deref(&self) -> &Ui<B> {
        self.ui
    }
}

impl<'a, B> AsRef<Ui<B>> for UiCell<'a, B>
    where B: Backend,
{
    fn as_ref(&self) -> &Ui<B> {
        &self.ui
    }
}

/// A private constructor for the `UiCell` for internal use.
pub fn new_ui_cell<B>(ui: &mut Ui<B>) -> UiCell<B>
    where B: Backend,
{
    UiCell { ui: ui }
}

/// A function for retrieving the `&mut Ui<B>` from a `UiCell<B>`.
///
/// This function is only for internal use to allow for some `Ui` type acrobatics in order to
/// provide a nice *safe* API for the user.
pub fn ref_mut_from_ui_cell<'a, 'b, B>(ui_cell: &'a mut UiCell<'b, B>) -> &'a mut Ui<B>
    where 'b: 'a,
          B: Backend
{
    ui_cell.ui
}

/// A mutable reference to the given `Ui`'s widget `Graph`.
pub fn widget_graph_mut<B>(ui: &mut Ui<B>) -> &mut Graph
    where B: Backend,
{
    &mut ui.widget_graph
}


/// Infer a widget's `Depth` parent by examining it's *x* and *y* `Position`s.
///
/// When a different parent may be inferred from either `Position`, the *x* `Position` is favoured.
pub fn infer_parent_from_position<B>(ui: &Ui<B>, x_pos: Position, y_pos: Position)
    -> Option<widget::Index>
    where B: Backend,
{
    use Position::{Place, Relative, Direction, Align};
    match (x_pos, y_pos) {
        (Place(_, maybe_parent_idx), _) | (_, Place(_, maybe_parent_idx)) =>
            maybe_parent_idx,
        (Direction(_, _, maybe_idx), _) | (_, Direction(_, _, maybe_idx)) |
        (Align(_, maybe_idx), _)        | (_, Align(_, maybe_idx))        |
        (Relative(_, maybe_idx), _)     | (_, Relative(_, maybe_idx))     =>
            maybe_idx.or(ui.maybe_prev_widget_idx)
                .and_then(|idx| ui.widget_graph.depth_parent(idx)),
        _ => None,
    }
}


/// Attempts to infer the parent of a widget from its *x*/*y* `Position`s and the current state of
/// the `Ui`.
///
/// If no parent can be inferred via the `Position`s, the `maybe_current_parent_idx` will be used.
///
/// If `maybe_current_parent_idx` is `None`, the `Ui`'s `window` widget will be used.
///
/// **Note:** This function does not check whether or not using the `window` widget would cause a
/// cycle.
pub fn infer_parent_unchecked<B>(ui: &Ui<B>, x_pos: Position, y_pos: Position) -> widget::Index
    where B: Backend,
{
    infer_parent_from_position(ui, x_pos, y_pos)
        .or(ui.maybe_current_parent_idx)
        .unwrap_or(ui.window.into())
}


/// Cache some `PreUpdateCache` widget data into the widget graph.
/// Set the widget that is being cached as the new `prev_widget`.
/// Set the widget's parent as the new `current_parent`.
pub fn pre_update_cache<B>(ui: &mut Ui<B>, widget: widget::PreUpdateCache)
    where B: Backend,
{
    ui.maybe_prev_widget_idx = Some(widget.idx);
    ui.maybe_current_parent_idx = widget.maybe_parent_idx;
    let widget_idx = widget.idx;
    ui.widget_graph.pre_update_cache(ui.window, widget, ui.updated_widgets.len());

    // Add the widget's `NodeIndex` to the set of updated widgets.
    let node_idx = ui.widget_graph.node_index(widget_idx).expect("No NodeIndex");
    ui.updated_widgets.insert(node_idx);
}

/// Cache some `PostUpdateCache` widget data into the widget graph.
/// Set the widget that is being cached as the new `prev_widget`.
/// Set the widget's parent as the new `current_parent`.
pub fn post_update_cache<B, W>(ui: &mut Ui<B>, widget: widget::PostUpdateCache<W>)
    where B: Backend,
          W: Widget,
          W::State: 'static,
          W::Style: 'static,
{
    ui.maybe_prev_widget_idx = Some(widget.idx);
    ui.maybe_current_parent_idx = widget.maybe_parent_idx;
    ui.widget_graph.post_update_cache(widget);
}


/// Clear the background with the given color.
pub fn clear_with<B>(ui: &mut Ui<B>, color: Color)
    where B: Backend,
{
    ui.maybe_background_color = Some(color);
}