conrod_core/
ui.rs

1use color::Color;
2use cursor;
3use event;
4use fnv;
5use graph::{self, Graph};
6use input;
7use position::{self, Align, Dimensions, Direction, Padding, Point, Position, Range, Rect, Scalar};
8use render;
9use std;
10use std::sync::atomic::{self, AtomicUsize};
11use text;
12use theme::Theme;
13use utils;
14use widget::{self, Widget};
15
16/// A constructor type for building a `Ui` instance with a set of optional parameters.
17pub struct UiBuilder {
18    /// The initial dimensions of the window in which the `Ui` exists.
19    pub window_dimensions: Dimensions,
20    /// The theme used to set default styling for widgets.
21    ///
22    /// If this field is `None` when `build` is called, `Theme::default` will be used.
23    pub maybe_theme: Option<Theme>,
24    /// An estimation of the maximum number of widgets that will be used with this `Ui` instance.
25    ///
26    /// This value is used to determine the size with which various collections should be
27    /// reserved. This may make the first cycle of widget instantiations more efficient as the
28    /// collections will not be required to grow dynamically. These collections include:
29    ///
30    /// - the widget graph node and edge `Vec`s
31    /// - the `HashSet` used to track updated widgets
32    /// - the widget `DepthOrder` (a kind of toposort describing the order of widgets in their
33    /// rendering order).
34    ///
35    /// If this field is `None` when `build` is called, these collections will be initialised with
36    /// no pre-reserved size and will instead grow organically as needed.
37    pub maybe_widgets_capacity: Option<usize>,
38}
39
40/// `Ui` is the most important type within Conrod and is necessary for rendering and maintaining
41/// widget state.
42/// # Ui Handles the following:
43/// * Contains the state of all widgets which can be indexed via their widget::Id.
44/// * Stores rendering state for each widget until the end of each render cycle.
45/// * Contains the theme used for default styling of the widgets.
46/// * Maintains the latest user input state (for mouse and keyboard).
47/// * Maintains the latest window dimensions.
48#[derive(Debug)]
49pub struct Ui {
50    /// The theme used to set default styling for widgets.
51    pub theme: Theme,
52    /// An index into the root widget of the graph, representing the entire window.
53    pub window: widget::Id,
54    /// Handles aggregation of events and providing them to Widgets
55    global_input: input::Global,
56    /// Manages all fonts that have been loaded by the user.
57    pub fonts: text::font::Map,
58    /// The Widget cache, storing state for all widgets.
59    widget_graph: Graph,
60    /// The widget::Id of the widget that was last updated/set.
61    maybe_prev_widget_id: Option<widget::Id>,
62    /// The widget::Id of the last widget used as a parent for another widget.
63    maybe_current_parent_id: Option<widget::Id>,
64    /// The number of frames that will be used for the `redraw_count` when `need_redraw` is
65    /// triggered.
66    num_redraw_frames: u8,
67    /// Whether or not the `Ui` needs to be re-drawn to screen.
68    redraw_count: AtomicUsize,
69    /// A background color to clear the screen with before drawing if one was given.
70    maybe_background_color: Option<Color>,
71    /// The order in which widgets from the `widget_graph` are drawn.
72    depth_order: graph::DepthOrder,
73    /// The set of widgets that have been updated since the beginning of the `set_widgets` stage.
74    updated_widgets: fnv::FnvHashSet<widget::Id>,
75    /// The `updated_widgets` for the previous `set_widgets` stage.
76    ///
77    /// We use this to compare against the newly generated `updated_widgets` to see whether or not
78    /// we require re-drawing.
79    prev_updated_widgets: fnv::FnvHashSet<widget::Id>,
80    /// Scroll events that have been emitted during a call to `Ui::set_widgets`. These are usually
81    /// emitted by some widget like the `Scrollbar`.
82    ///
83    /// These events will be drained and pushed onto the end of the `global_input` event buffer at
84    /// the end of the `Ui::set_widgets` method. This ensures that the events are received by the
85    /// target widgets during the next call to `Ui::set_widgets`.
86    pending_scroll_events: Vec<event::Ui>,
87    /// Mouse cursor
88    mouse_cursor: cursor::MouseCursor,
89
90    // TODO: Remove the following fields as they should now be handled by `input::Global`.
91    /// Window width.
92    pub win_w: f64,
93    /// Window height.
94    pub win_h: f64,
95}
96
97/// A wrapper around the `Ui` that restricts the user from mutating the `Ui` in certain ways while
98/// in the scope of the `Ui::set_widgets` function and within `Widget`s' `update` methods. Using
99/// the `UiCell`, users may access the `Ui` immutably (via `Deref`) however they wish, however they
100/// may only mutate the `Ui` via the `&mut self` methods provided by the `UiCell`.
101///
102/// The name came from its likening to a "jail cell for the `Ui`", as it restricts a user's access
103/// to it. However, we realise that the name may also cause ambiguity with the std `Cell` and
104/// `RefCell` types (which `UiCell` has nothing to do with). Thus, if you have a better name for
105/// this type in mind, please let us know at the github repo via an issue or PR sometime before we
106/// hit 1.0.0!
107#[derive(Debug)]
108pub struct UiCell<'a> {
109    /// A mutable reference to a **Ui**.
110    ui: &'a mut Ui,
111}
112
113/// Each time conrod is required to redraw the GUI, it must draw for at least the next three frames
114/// to ensure that, in the case that graphics buffers are being swapped, we have filled each
115/// buffer. Otherwise if we don't draw into each buffer, we will probably be subject to flickering.
116pub const SAFE_REDRAW_COUNT: u8 = 3;
117
118impl UiBuilder {
119    /// Begin building a new `Ui` instance.
120    ///
121    /// Give the initial dimensions of the window within which the `Ui` will be instantiated as a
122    /// `Scalar` (DPI agnostic) value.
123    pub fn new(window_dimensions: Dimensions) -> Self {
124        UiBuilder {
125            window_dimensions: window_dimensions,
126            maybe_theme: None,
127            maybe_widgets_capacity: None,
128        }
129    }
130
131    /// The theme used to set default styling for widgets.
132    ///
133    /// If this field is `None` when `build` is called, `Theme::default` will be used.
134    pub fn theme(mut self, value: Theme) -> Self {
135        self.maybe_theme = Some(value);
136        self
137    }
138
139    /// An estimation of the maximum number of widgets that will be used with this `Ui` instance.
140    ///
141    /// This value is used to determine the size with which various collections should be
142    /// reserved. This may make the first cycle of widget instantiations more efficient as the
143    /// collections will not be required to grow dynamically. These collections include:
144    ///
145    /// - the widget graph node and edge `Vec`s
146    /// - the `HashSet` used to track updated widgets
147    /// - the widget `DepthOrder` (a kind of toposort describing the order of widgets in their
148    /// rendering order).
149    ///
150    /// If this field is `None` when `build` is called, these collections will be initialised with
151    /// no pre-reserved size and will instead grow organically as required.
152    pub fn widgets_capacity(mut self, value: usize) -> Self {
153        self.maybe_widgets_capacity = Some(value);
154        self
155    }
156
157    /// Build **Ui** from the given builder
158    pub fn build(self) -> Ui {
159        Ui::new(self)
160    }
161}
162
163impl Ui {
164    /// A new, empty **Ui**.
165    fn new(builder: UiBuilder) -> Self {
166        let UiBuilder {
167            window_dimensions,
168            maybe_widgets_capacity,
169            maybe_theme,
170        } = builder;
171
172        let (mut widget_graph, depth_order, updated_widgets) = maybe_widgets_capacity.map_or_else(
173            || {
174                (
175                    Graph::new(),
176                    graph::DepthOrder::new(),
177                    fnv::FnvHashSet::default(),
178                )
179            },
180            |n| {
181                (
182                    Graph::with_node_capacity(n),
183                    graph::DepthOrder::with_node_capacity(n),
184                    std::collections::HashSet::with_capacity_and_hasher(
185                        n,
186                        fnv::FnvBuildHasher::default(),
187                    ),
188                )
189            },
190        );
191
192        let window = widget_graph.add_placeholder();
193        let prev_updated_widgets = updated_widgets.clone();
194        Ui {
195            widget_graph: widget_graph,
196            theme: maybe_theme.unwrap_or_else(|| Theme::default()),
197            fonts: text::font::Map::new(),
198            window: window,
199            win_w: window_dimensions[0],
200            win_h: window_dimensions[1],
201            maybe_prev_widget_id: None,
202            maybe_current_parent_id: None,
203            num_redraw_frames: SAFE_REDRAW_COUNT,
204            redraw_count: AtomicUsize::new(SAFE_REDRAW_COUNT as usize),
205            maybe_background_color: None,
206            depth_order: depth_order,
207            updated_widgets: updated_widgets,
208            prev_updated_widgets: prev_updated_widgets,
209            global_input: input::Global::new(),
210            pending_scroll_events: Vec::new(),
211            mouse_cursor: cursor::MouseCursor::Arrow,
212        }
213    }
214
215    /// Returns a `input::Widget` for the given widget
216    pub fn widget_input(&self, widget: widget::Id) -> input::Widget {
217        // If there's no rectangle for a given widget, then we use one with zero area.
218        // This means that the resulting `input::Widget` will not include any mouse events
219        // unless it has captured the mouse, since none will have occured over that area.
220        let rect = self.rect_of(widget).unwrap_or_else(|| {
221            let right_edge = self.win_w / 2.0;
222            let bottom_edge = self.win_h / 2.0;
223            Rect::from_xy_dim([right_edge, bottom_edge], [0.0, 0.0])
224        });
225        input::Widget::for_widget(widget, rect, &self.global_input)
226    }
227
228    /// The **Rect** for the widget at the given index.
229    ///
230    /// Returns `None` if there is no widget for the given index.
231    pub fn rect_of(&self, id: widget::Id) -> Option<Rect> {
232        self.widget_graph.widget(id).map(|widget| widget.rect)
233    }
234
235    /// The absolute width of the widget at the given index.
236    ///
237    /// Returns `None` if there is no widget for the given index.
238    pub fn w_of(&self, id: widget::Id) -> Option<Scalar> {
239        self.rect_of(id).map(|rect| rect.w())
240    }
241
242    /// The absolute height of the widget at the given index.
243    ///
244    /// Returns `None` if there is no widget for the given index.
245    pub fn h_of(&self, id: widget::Id) -> Option<Scalar> {
246        self.rect_of(id).map(|rect| rect.h())
247    }
248
249    /// The absolute dimensions for the widget at the given index.
250    ///
251    /// Returns `None` if there is no widget for the given index.
252    pub fn wh_of(&self, id: widget::Id) -> Option<Dimensions> {
253        self.rect_of(id).map(|rect| rect.dim())
254    }
255
256    /// The coordinates for the widget at the given index.
257    ///
258    /// Returns `None` if there is no widget for the given index.
259    pub fn xy_of(&self, id: widget::Id) -> Option<Point> {
260        self.rect_of(id).map(|rect| rect.xy())
261    }
262
263    /// The `kid_area` of the widget at the given index.
264    ///
265    /// Returns `None` if there is no widget for the given index.
266    pub fn kid_area_of(&self, id: widget::Id) -> Option<Rect> {
267        self.widget_graph
268            .widget(id)
269            .map(|widget| widget.kid_area.rect.padding(widget.kid_area.pad))
270    }
271
272    /// An index to the previously updated widget if there is one.
273    pub fn maybe_prev_widget(&self) -> Option<widget::Id> {
274        self.maybe_prev_widget_id
275    }
276
277    /// Borrow the **Ui**'s `widget_graph`.
278    pub fn widget_graph(&self) -> &Graph {
279        &self.widget_graph
280    }
281
282    /// Borrow the **Ui**'s set of updated widgets.
283    ///
284    /// This set indicates which widgets have been instantiated since the beginning of the most
285    /// recent `Ui::set_widgets` call.
286    pub fn updated_widgets(&self) -> &fnv::FnvHashSet<widget::Id> {
287        &self.updated_widgets
288    }
289
290    /// Borrow the **Ui**'s set of updated widgets.
291    ///
292    /// This set indicates which widgets have were instantiated during the previous call to
293    /// `Ui::set_widgets`.
294    pub fn prev_updated_widgets(&self) -> &fnv::FnvHashSet<widget::Id> {
295        &self.prev_updated_widgets
296    }
297
298    /// Produces a type that may be used to generate new unique `widget::Id`s.
299    ///
300    /// See the [**widget::id::Generator**](../widget/id/struct.Generator.html) docs for details on
301    /// how to use this correctly.
302    pub fn widget_id_generator(&mut self) -> widget::id::Generator {
303        widget::id::Generator::new(&mut self.widget_graph)
304    }
305
306    /// Scroll the widget at the given index by the given offset amount.
307    ///
308    /// The produced `Scroll` event will be applied upon the next call to `Ui::set_widgets`.
309    pub fn scroll_widget(&mut self, widget_id: widget::Id, offset: [Scalar; 2]) {
310        let (x, y) = (offset[0], offset[1]);
311
312        if x != 0.0 || y != 0.0 {
313            let event = event::Ui::Scroll(
314                Some(widget_id),
315                event::Scroll {
316                    x: x,
317                    y: y,
318                    modifiers: self.global_input.current.modifiers,
319                },
320            )
321            .into();
322            self.global_input.push_event(event);
323        }
324    }
325
326    /// Determines which widget is currently under the mouse and sets it within the `Ui`'s
327    /// `input::Global`'s `input::State`.
328    ///
329    /// If the `widget_under_mouse` has changed, this function will also update the
330    /// `widget_capturing_mouse`.
331    ///
332    /// If the left mouse button is up, we assume that the widget directly under the
333    /// mouse cursor captures all input from the mouse.
334    ///
335    /// If the left mouse button is down, we assume that the widget that was clicked
336    /// remains "pinned" and will continue to capture the mouse until it is
337    /// released.
338    ///
339    /// Note: This function expects that `ui.global_input.current.mouse.xy` is up-to-date.
340    fn track_widget_under_mouse_and_update_capturing(&mut self) {
341        self.global_input.current.widget_under_mouse = graph::algo::pick_widgets(
342            &self.depth_order.indices,
343            self.global_input.current.mouse.xy,
344        )
345        .next(&self.widget_graph, &self.depth_order.indices, &self.theme);
346
347        // If MouseButton::Left is up and `widget_under_mouse` has changed, capture new widget
348        // under mouse.
349        if self.global_input.current.mouse.buttons.left().is_up() {
350            let widget_under_mouse = self.global_input.current.widget_under_mouse;
351
352            // Check to see if we need to uncapture a widget.
353            if let Some(idx) = self.global_input.current.widget_capturing_mouse {
354                if widget_under_mouse != Some(idx) {
355                    let source = input::Source::Mouse;
356                    let event = event::Ui::WidgetUncapturesInputSource(idx, source).into();
357                    self.global_input.push_event(event);
358                    self.global_input.current.widget_capturing_mouse = None;
359                }
360            }
361
362            // Check to see if there is a new widget capturing the mouse.
363            if self.global_input.current.widget_capturing_mouse.is_none() {
364                if let Some(idx) = widget_under_mouse {
365                    let source = input::Source::Mouse;
366                    let event = event::Ui::WidgetCapturesInputSource(idx, source).into();
367                    self.global_input.push_event(event);
368                    self.global_input.current.widget_capturing_mouse = Some(idx);
369                }
370            }
371        }
372    }
373
374    /// Handle raw window events and update the `Ui` state accordingly.
375    ///
376    /// This occurs within several stages:
377    ///
378    /// 1. Convert the user's given `event` to a `RawEvent` so that the `Ui` may use it.
379    /// 2. Interpret the `RawEvent` for higher-level `Event`s such as `DoubleClick`,
380    ///    `WidgetCapturesKeyboard`, etc.
381    /// 3. Update the `Ui`'s `global_input` `State` accordingly, depending on the `RawEvent`.
382    /// 4. Store newly produced `event::Ui`s within the `global_input` so that they may be filtered
383    ///    and fed to `Widget`s next time `Ui::set_widget` is called.
384    ///
385    /// This method *drives* the `Ui` forward, and is what allows for using conrod's `Ui` with any
386    /// window event stream.
387    ///
388    /// The given `event` must implement the **ToRawEvent** trait so that it can be converted to a
389    /// `RawEvent` that can be used by the `Ui`.
390    pub fn handle_event(&mut self, event: event::Input) {
391        use event::Input;
392        use input::state::mouse::Button as MouseButton;
393        use input::{Button, Key, ModifierKey, Motion};
394
395        // A function for filtering `ModifierKey`s.
396        fn filter_modifier(key: Key) -> Option<ModifierKey> {
397            match key {
398                Key::LCtrl | Key::RCtrl => Some(ModifierKey::CTRL),
399                Key::LShift | Key::RShift => Some(ModifierKey::SHIFT),
400                Key::LAlt | Key::RAlt => Some(ModifierKey::ALT),
401                Key::LGui | Key::RGui => Some(ModifierKey::GUI),
402                _ => None,
403            }
404        }
405
406        // Here we handle all user input given to conrod.
407        //
408        // Not only do we store the `Input` event as an `Event::Raw`, we also use them to
409        // interpret higher level events such as `Click` or `Drag`.
410        //
411        // Finally, we also ensure that the `current_state` is up-to-date.
412        self.global_input.push_event(event.clone().into());
413        match event {
414            // Some button was pressed, whether keyboard, mouse or some other device.
415            Input::Press(button_type) => match button_type {
416                // Check to see whether we need to (un)capture the keyboard or mouse.
417                Button::Mouse(mouse_button) => {
418                    // Create a mouse `Press` event.
419                    let mouse_xy = self.global_input.current.mouse.xy;
420                    let press = event::Press {
421                        button: event::Button::Mouse(mouse_button, mouse_xy),
422                        modifiers: self.global_input.current.modifiers,
423                    };
424                    let widget = self.global_input.current.widget_capturing_mouse;
425                    let press_event = event::Ui::Press(widget, press).into();
426                    self.global_input.push_event(press_event);
427
428                    if let MouseButton::Left = mouse_button {
429                        // Check to see if we need to uncapture the keyboard.
430                        if let Some(idx) = self.global_input.current.widget_capturing_keyboard {
431                            if Some(idx) != self.global_input.current.widget_under_mouse {
432                                let source = input::Source::Keyboard;
433                                let event = event::Ui::WidgetUncapturesInputSource(idx, source);
434                                self.global_input.push_event(event.into());
435                                self.global_input.current.widget_capturing_keyboard = None;
436                            }
437                        }
438
439                        // Check to see if we need to capture the keyboard.
440                        if let Some(idx) = self.global_input.current.widget_under_mouse {
441                            let source = input::Source::Keyboard;
442                            let event = event::Ui::WidgetCapturesInputSource(idx, source);
443                            self.global_input.push_event(event.into());
444                            self.global_input.current.widget_capturing_keyboard = Some(idx);
445                        }
446                    }
447
448                    // Keep track of pressed buttons in the current input::State.
449                    let xy = self.global_input.current.mouse.xy;
450                    let widget = self.global_input.current.widget_under_mouse;
451                    self.global_input
452                        .current
453                        .mouse
454                        .buttons
455                        .press(mouse_button, xy, widget);
456                }
457
458                Button::Keyboard(key) => {
459                    // Create a keyboard `Press` event.
460                    let press = event::Press {
461                        button: event::Button::Keyboard(key),
462                        modifiers: self.global_input.current.modifiers,
463                    };
464                    let widget = self.global_input.current.widget_capturing_keyboard;
465                    let press_event = event::Ui::Press(widget, press).into();
466                    self.global_input.push_event(press_event);
467
468                    // If some modifier key was pressed, add it to the current modifiers.
469                    if let Some(modifier) = filter_modifier(key) {
470                        self.global_input.current.modifiers.insert(modifier);
471                    }
472
473                    // If `Esc` was pressed, check to see if we need to cancel a `Drag` or
474                    // uncapture a widget.
475                    if let Key::Escape = key {
476                        // TODO:
477                        // 1. Cancel `Drag` if currently under way.
478                        // 2. If mouse is captured due to pinning widget with left mouse button,
479                        //    cancel capturing.
480                    }
481                }
482
483                _ => {}
484            },
485
486            // Some button was released.
487            //
488            // Checks for events in the following order:
489            // 1. Click
490            // 2. DoubleClick
491            // 2. WidgetUncapturesMouse
492            Input::Release(button_type) => match button_type {
493                Button::Mouse(mouse_button) => {
494                    // Create a `Release` event.
495                    let mouse_xy = self.global_input.current.mouse.xy;
496                    let release = event::Release {
497                        button: event::Button::Mouse(mouse_button, mouse_xy),
498                        modifiers: self.global_input.current.modifiers,
499                    };
500                    let widget = self.global_input.current.widget_capturing_mouse;
501                    let release_event = event::Ui::Release(widget, release).into();
502                    self.global_input.push_event(release_event);
503
504                    // Check for `Click` and `DoubleClick` events.
505                    let down = self.global_input.current.mouse.buttons[mouse_button].if_down();
506                    if let Some((_, widget)) = down {
507                        // The widget that's being clicked.
508                        let clicked_widget =
509                            self.global_input
510                                .current
511                                .widget_under_mouse
512                                .and_then(|released| {
513                                    widget.and_then(|pressed| {
514                                        if pressed == released {
515                                            Some(released)
516                                        } else {
517                                            None
518                                        }
519                                    })
520                                });
521
522                        let click = event::Click {
523                            button: mouse_button,
524                            xy: self.global_input.current.mouse.xy,
525                            modifiers: self.global_input.current.modifiers,
526                        };
527
528                        let click_event = event::Ui::Click(clicked_widget, click).into();
529                        self.global_input.push_event(click_event);
530
531                        let now = instant::Instant::now();
532                        let double_click =
533                            self.global_input
534                                .last_click
535                                .and_then(|(last_time, last_click)| {
536                                    // If the button of this click is different to the button
537                                    // of last click, don't create a `DoubleClick`.
538                                    if click.button != last_click.button {
539                                        return None;
540                                    }
541
542                                    // If the mouse has moved since the last click, don't
543                                    // create a `DoubleClick`.
544                                    if click.xy != last_click.xy {
545                                        return None;
546                                    }
547
548                                    // If the duration since the last click is longer than the
549                                    // double_click_threshold, don't create a `DoubleClick`.
550                                    let duration = now.duration_since(last_time);
551                                    // TODO: Work out how to get this threshold from the user's
552                                    // system preferences.
553                                    let threshold = self.theme.double_click_threshold;
554                                    if duration >= threshold {
555                                        return None;
556                                    }
557
558                                    Some(event::DoubleClick {
559                                        button: click.button,
560                                        xy: click.xy,
561                                        modifiers: click.modifiers,
562                                    })
563                                });
564
565                        if let Some(double_click) = double_click {
566                            // Reset the `last_click` to `None`, as to not register another
567                            // `DoubleClick` on the next consecutive `Click`.
568                            self.global_input.last_click = None;
569                            let double_click_event =
570                                event::Ui::DoubleClick(clicked_widget, double_click).into();
571                            self.global_input.push_event(double_click_event);
572                        } else {
573                            // Set the `Click` that we just stored as the `last_click`.
574                            self.global_input.last_click = Some((now, click));
575                        }
576                    }
577
578                    // Uncapture widget capturing mouse if MouseButton::Left is down and
579                    // widget_under_mouse != capturing widget.
580                    if let MouseButton::Left = mouse_button {
581                        if let Some(idx) = self.global_input.current.widget_capturing_mouse {
582                            if Some(idx) != self.global_input.current.widget_under_mouse {
583                                let source = input::Source::Mouse;
584                                let event = event::Ui::WidgetUncapturesInputSource(idx, source);
585                                self.global_input.push_event(event.into());
586                                self.global_input.current.widget_capturing_mouse = None;
587                            }
588                        }
589                    }
590
591                    // Release the given mouse_button from the input::State.
592                    self.global_input
593                        .current
594                        .mouse
595                        .buttons
596                        .release(mouse_button);
597                }
598
599                Button::Keyboard(key) => {
600                    // Create a `Release` event.
601                    let release = event::Release {
602                        button: event::Button::Keyboard(key),
603                        modifiers: self.global_input.current.modifiers,
604                    };
605                    let widget = self.global_input.current.widget_capturing_keyboard;
606                    let release_event = event::Ui::Release(widget, release).into();
607                    self.global_input.push_event(release_event);
608
609                    // If a modifier key was released, remove it from the current set.
610                    if let Some(modifier) = filter_modifier(key) {
611                        self.global_input.current.modifiers.remove(modifier);
612                    }
613                }
614
615                _ => (),
616            },
617
618            // The window was resized.
619            Input::Resize(w, h) => {
620                // Create a `WindowResized` event.
621                let (w, h) = (w as Scalar, h as Scalar);
622                let window_resized = event::Ui::WindowResized([w, h]).into();
623                self.global_input.push_event(window_resized);
624
625                self.win_w = w;
626                self.win_h = h;
627                self.needs_redraw();
628                self.track_widget_under_mouse_and_update_capturing();
629            }
630
631            // The mouse cursor was moved to a new position.
632            //
633            // Checks for events in the following order:
634            // 1. `Drag`
635            // 2. `WidgetUncapturesMouse`
636            // 3. `WidgetCapturesMouse`
637            Input::Motion(motion) => {
638                // Create a `Motion` event.
639                let move_ = event::Motion {
640                    motion: motion,
641                    modifiers: self.global_input.current.modifiers,
642                };
643                let widget = self.global_input.current.widget_capturing_mouse;
644                let move_event = event::Ui::Motion(widget, move_).into();
645                self.global_input.push_event(move_event);
646
647                match motion {
648                    Motion::MouseCursor { x, y } => {
649                        // Check for drag events.
650                        let last_mouse_xy = self.global_input.current.mouse.xy;
651                        let mouse_xy = [x, y];
652                        let delta_xy = utils::vec2_sub(mouse_xy, last_mouse_xy);
653                        // For each button that is down, trigger a drag event.
654                        let buttons = self.global_input.current.mouse.buttons.clone();
655                        for (btn, btn_xy, widget) in buttons.pressed() {
656                            let total_delta_xy = utils::vec2_sub(mouse_xy, btn_xy);
657                            let distance = (total_delta_xy[0] + total_delta_xy[1]).abs().sqrt();
658                            if distance > self.theme.mouse_drag_threshold {
659                                let event = event::Ui::Drag(
660                                    widget,
661                                    event::Drag {
662                                        button: btn,
663                                        origin: btn_xy,
664                                        from: last_mouse_xy,
665                                        to: mouse_xy,
666                                        delta_xy: delta_xy,
667                                        total_delta_xy: total_delta_xy,
668                                        modifiers: self.global_input.current.modifiers,
669                                    },
670                                )
671                                .into();
672                                self.global_input.push_event(event);
673                            }
674                        }
675
676                        // Update the position of the mouse within the global_input's
677                        // input::State.
678                        self.global_input.current.mouse.xy = mouse_xy;
679
680                        self.track_widget_under_mouse_and_update_capturing();
681                    }
682
683                    // Some scrolling occurred (e.g. mouse scroll wheel).
684                    Motion::Scroll { x, y } => {
685                        let mut scrollable_widgets = {
686                            let depth_order = &self.depth_order.indices;
687                            let mouse_xy = self.global_input.current.mouse.xy;
688                            graph::algo::pick_scrollable_widgets(depth_order, mouse_xy)
689                        };
690
691                        // Iterate through the scrollable widgets from top to bottom.
692                        //
693                        // A scroll event will be created for the first scrollable widget
694                        // that hasn't already reached the bound of the scroll event's
695                        // direction.
696                        while let Some(idx) = scrollable_widgets.next(
697                            &self.widget_graph,
698                            &self.depth_order.indices,
699                            &self.theme,
700                        ) {
701                            let (kid_area, maybe_x_scroll, maybe_y_scroll) =
702                                match self.widget_graph.widget(idx) {
703                                    Some(widget) => (
704                                        widget.kid_area,
705                                        widget.maybe_x_scroll_state,
706                                        widget.maybe_y_scroll_state,
707                                    ),
708                                    None => continue,
709                                };
710
711                            fn offset_is_at_bound<A>(
712                                scroll: &widget::scroll::State<A>,
713                                additional_offset: Scalar,
714                            ) -> bool {
715                                fn approx_eq(a: Scalar, b: Scalar) -> bool {
716                                    (a - b).abs() < 0.000001
717                                }
718
719                                if additional_offset.is_sign_positive() {
720                                    let max = utils::partial_max(
721                                        scroll.offset_bounds.start,
722                                        scroll.offset_bounds.end,
723                                    );
724                                    approx_eq(scroll.offset, max)
725                                } else {
726                                    let min = utils::partial_min(
727                                        scroll.offset_bounds.start,
728                                        scroll.offset_bounds.end,
729                                    );
730                                    approx_eq(scroll.offset, min)
731                                }
732                            }
733
734                            let mut scroll_x = false;
735                            let mut scroll_y = false;
736
737                            // Check whether the x axis is scrollable.
738                            if x != 0.0 {
739                                let new_scroll = widget::scroll::State::update(
740                                    self,
741                                    idx,
742                                    &kid_area,
743                                    maybe_x_scroll,
744                                    x,
745                                );
746                                if let Some(prev_scroll) = maybe_x_scroll {
747                                    let (prev_is_at_bound, new_is_at_bound) = (
748                                        offset_is_at_bound(&prev_scroll, x),
749                                        offset_is_at_bound(&new_scroll, x),
750                                    );
751                                    scroll_x = !prev_is_at_bound || !new_is_at_bound;
752                                }
753                            }
754
755                            // Check whether the y axis is scrollable.
756                            if y != 0.0 {
757                                let new_scroll = widget::scroll::State::update(
758                                    self,
759                                    idx,
760                                    &kid_area,
761                                    maybe_y_scroll,
762                                    y,
763                                );
764                                if let Some(prev_scroll) = maybe_y_scroll {
765                                    let (prev_is_at_bound, new_is_at_bound) = (
766                                        offset_is_at_bound(&prev_scroll, y),
767                                        offset_is_at_bound(&new_scroll, y),
768                                    );
769                                    scroll_y = !prev_is_at_bound || !new_is_at_bound;
770                                }
771                            }
772
773                            // Create a `Scroll` event if either axis is scrollable.
774                            if scroll_x || scroll_y {
775                                let event = event::Ui::Scroll(
776                                    Some(idx),
777                                    event::Scroll {
778                                        x: x,
779                                        y: y,
780                                        modifiers: self.global_input.current.modifiers,
781                                    },
782                                )
783                                .into();
784                                self.global_input.push_event(event);
785
786                                // Now that we've scrolled the top, scrollable widget,
787                                // we're done with the loop.
788                                break;
789                            }
790                        }
791
792                        // If no scrollable widgets could be scrolled, emit the event to
793                        // the widget that currently captures the mouse.
794                        if x != 0.0 || y != 0.0 {
795                            let widget = self.global_input.current.widget_capturing_mouse;
796                            if let Some(idx) = widget {
797                                if let Some(widget) = self.widget_graph.widget(idx) {
798                                    // Only create the event if the widget is not
799                                    // scrollable, as the event would have already been
800                                    // created within the above loop.
801                                    if widget.maybe_x_scroll_state.is_none()
802                                        && widget.maybe_y_scroll_state.is_none()
803                                    {
804                                        let scroll = event::Scroll {
805                                            x: x,
806                                            y: y,
807                                            modifiers: self.global_input.current.modifiers,
808                                        };
809                                        let event = event::Ui::Scroll(Some(idx), scroll);
810                                        self.global_input.push_event(event.into());
811                                    }
812                                }
813                            }
814                        }
815
816                        // Now that there might be a different widget under the mouse, we
817                        // must update the capturing state.
818                        self.track_widget_under_mouse_and_update_capturing();
819                    }
820
821                    _ => (),
822                }
823            }
824
825            Input::Text(string) => {
826                // Create a `Text` event.
827                let text = event::Text {
828                    string: string,
829                    modifiers: self.global_input.current.modifiers,
830                };
831                let widget = self.global_input.current.widget_capturing_keyboard;
832                let text_event = event::Ui::Text(widget, text).into();
833                self.global_input.push_event(text_event);
834            }
835
836            Input::Touch(touch) => match touch.phase {
837                input::touch::Phase::Start => {
838                    // Find the widget under the touch.
839                    let widget_under_touch =
840                        graph::algo::pick_widgets(&self.depth_order.indices, touch.xy).next(
841                            &self.widget_graph,
842                            &self.depth_order.indices,
843                            &self.theme,
844                        );
845
846                    // The start of the touch interaction state to be stored.
847                    let start = input::state::touch::Start {
848                        time: instant::Instant::now(),
849                        xy: touch.xy,
850                        widget: widget_under_touch,
851                    };
852
853                    // The touch interaction state to be stored in the map.
854                    let state = input::state::touch::Touch {
855                        start: start,
856                        xy: touch.xy,
857                        widget: widget_under_touch,
858                    };
859
860                    // Insert the touch state into the map.
861                    self.global_input.current.touch.insert(touch.id, state);
862
863                    // Push touch event.
864                    let event = event::Ui::Touch(widget_under_touch, touch);
865                    self.global_input.push_event(event.into());
866
867                    // Push capture event.
868                    if let Some(widget) = widget_under_touch {
869                        let source = input::Source::Touch(touch.id);
870                        let event = event::Ui::WidgetCapturesInputSource(widget, source);
871                        self.global_input.push_event(event.into());
872                    }
873                }
874
875                input::touch::Phase::Move => {
876                    // Update the widget under the touch and return the widget capturing the touch.
877                    let widget = match self.global_input.current.touch.get_mut(&touch.id) {
878                        Some(touch_state) => {
879                            touch_state.widget =
880                                graph::algo::pick_widgets(&self.depth_order.indices, touch.xy)
881                                    .next(
882                                        &self.widget_graph,
883                                        &self.depth_order.indices,
884                                        &self.theme,
885                                    );
886                            touch_state.xy = touch.xy;
887                            touch_state.start.widget
888                        }
889                        None => None,
890                    };
891                    let event = event::Ui::Touch(widget, touch);
892                    self.global_input.push_event(event.into());
893                }
894
895                input::touch::Phase::Cancel => {
896                    let widget = self
897                        .global_input
898                        .current
899                        .touch
900                        .remove(&touch.id)
901                        .and_then(|t| t.start.widget);
902                    let event = event::Ui::Touch(widget, touch);
903                    self.global_input.push_event(event.into());
904
905                    // Generate an "uncaptures" event if necessary.
906                    if let Some(widget) = widget {
907                        let source = input::Source::Touch(touch.id);
908                        let event = event::Ui::WidgetUncapturesInputSource(widget, source);
909                        self.global_input.push_event(event.into());
910                    }
911                }
912
913                input::touch::Phase::End => {
914                    let old_touch = self
915                        .global_input
916                        .current
917                        .touch
918                        .remove(&touch.id)
919                        .map(|touch| touch);
920                    let widget_capturing = old_touch.as_ref().and_then(|touch| touch.start.widget);
921                    let event = event::Ui::Touch(widget_capturing, touch);
922                    self.global_input.push_event(event.into());
923
924                    // Create a `Tap` event.
925                    //
926                    // If the widget at the end of the touch is the same as the widget at the start
927                    // of the touch, that widget receives the `Tap`.
928                    let tapped_widget =
929                        graph::algo::pick_widgets(&self.depth_order.indices, touch.xy)
930                            .next(&self.widget_graph, &self.depth_order.indices, &self.theme)
931                            .and_then(|widget| match Some(widget) == widget_capturing {
932                                true => Some(widget),
933                                false => None,
934                            });
935                    let tap = event::Tap {
936                        id: touch.id,
937                        xy: touch.xy,
938                    };
939                    let event = event::Ui::Tap(tapped_widget, tap);
940                    self.global_input.push_event(event.into());
941
942                    // Generate an "uncaptures" event if necessary.
943                    if let Some(widget) = widget_capturing {
944                        let source = input::Source::Touch(touch.id);
945                        let event = event::Ui::WidgetUncapturesInputSource(widget, source);
946                        self.global_input.push_event(event.into());
947                    }
948                }
949            },
950
951            Input::Focus(focused) if focused == true => self.needs_redraw(),
952            Input::Focus(_focused) => (),
953
954            Input::Redraw => self.needs_redraw(),
955        }
956    }
957
958    /// Get an immutable reference to global input. Handles aggregation of events and providing them to Widgets
959    ///
960    /// Can be used to access the current input state, e.g. which widgets are currently capturing inputs.
961    pub fn global_input(&self) -> &input::Global {
962        &self.global_input
963    }
964
965    /// Set keyboard capturing widget
966    pub fn keyboard_capture(&mut self, idx: widget::Id) {
967        let source = input::Source::Keyboard;
968
969        if self
970            .global_input
971            .current
972            .widget_capturing_keyboard
973            .is_some()
974        {
975            let event = event::Ui::WidgetUncapturesInputSource(idx, source);
976            self.global_input.push_event(event.into());
977            self.global_input.current.widget_capturing_keyboard = None;
978        }
979
980        let event = event::Ui::WidgetCapturesInputSource(idx, source).into();
981        self.global_input.push_event(event);
982        self.global_input.current.widget_capturing_keyboard = Some(idx);
983    }
984
985    /// Get the centred xy coords for some given `Dimension`s, `Position` and alignment.
986    ///
987    /// If getting the xy for a specific widget, its `widget::Id` should be specified so that we
988    /// can also consider the scroll offset of the scrollable parent widgets.
989    ///
990    /// The `place_on_kid_area` argument specifies whether or not **Place** **Position** variants
991    /// should target a **Widget**'s `kid_area`, or simply the **Widget**'s total area.
992    pub fn calc_xy(
993        &self,
994        maybe_id: Option<widget::Id>,
995        maybe_parent_id: Option<widget::Id>,
996        x_position: Position,
997        y_position: Position,
998        dim: Dimensions,
999        place_on_kid_area: bool,
1000    ) -> Point {
1001        use utils::vec2_add;
1002
1003        // Retrieves the absolute **Scalar** position from the given position for a single axis.
1004        //
1005        // The axis used is specified by the given range_from_rect function which, given some
1006        // **Rect**, returns the relevant **Range**.
1007        fn abs_from_position<R, P>(
1008            ui: &Ui,
1009            maybe_parent_id: Option<widget::Id>,
1010            position: Position,
1011            dim: Scalar,
1012            place_on_kid_area: bool,
1013            range_from_rect: R,
1014            start_and_end_pad: P,
1015        ) -> Scalar
1016        where
1017            R: FnOnce(Rect) -> Range,
1018            P: FnOnce(Padding) -> Range,
1019        {
1020            let (relative, maybe_id) = match position {
1021                Position::Absolute(abs) => return abs,
1022                Position::Relative(relative, maybe_id) => (relative, maybe_id),
1023            };
1024
1025            match relative {
1026                position::Relative::Scalar(scalar) => maybe_id
1027                    .or(ui.maybe_prev_widget_id)
1028                    .or(Some(ui.window.into()))
1029                    .and_then(|idx| ui.rect_of(idx).map(range_from_rect))
1030                    .map(|other_range| other_range.middle() + scalar)
1031                    .unwrap_or(scalar),
1032
1033                position::Relative::Direction(direction, amt) => maybe_id
1034                    .or(ui.maybe_prev_widget_id)
1035                    .and_then(|idx| ui.rect_of(idx).map(range_from_rect))
1036                    .map(|other_range| {
1037                        let range = Range::from_pos_and_len(0.0, dim);
1038                        match direction {
1039                            Direction::Forwards => range.align_after(other_range).middle() + amt,
1040                            Direction::Backwards => range.align_before(other_range).middle() - amt,
1041                        }
1042                    })
1043                    .unwrap_or_else(|| match direction {
1044                        Direction::Forwards => amt,
1045                        Direction::Backwards => -amt,
1046                    }),
1047
1048                position::Relative::Align(align) => maybe_id
1049                    .or(ui.maybe_prev_widget_id)
1050                    .or(Some(ui.window.into()))
1051                    .and_then(|idx| ui.rect_of(idx).map(range_from_rect))
1052                    .map(|other_range| {
1053                        let range = Range::from_pos_and_len(0.0, dim);
1054                        match align {
1055                            Align::Start => range.align_start_of(other_range).middle(),
1056                            Align::Middle => other_range.middle(),
1057                            Align::End => range.align_end_of(other_range).middle(),
1058                        }
1059                    })
1060                    .unwrap_or(0.0),
1061
1062                position::Relative::Place(place) => {
1063                    let parent_id = maybe_id
1064                        .or(maybe_parent_id)
1065                        .or(ui.maybe_current_parent_id)
1066                        .unwrap_or(ui.window.into());
1067                    let maybe_area = match place_on_kid_area {
1068                        true => ui
1069                            .widget_graph
1070                            .widget(parent_id)
1071                            .map(|w| w.kid_area)
1072                            .map(|k| (range_from_rect(k.rect), start_and_end_pad(k.pad))),
1073                        false => ui
1074                            .rect_of(parent_id)
1075                            .map(|rect| (range_from_rect(rect), Range::new(0.0, 0.0))),
1076                    };
1077                    maybe_area
1078                        .map(|(parent_range, pad)| {
1079                            let range = Range::from_pos_and_len(0.0, dim);
1080                            let parent_range = parent_range.pad_start(pad.start).pad_end(pad.end);
1081                            match place {
1082                                position::Place::Start(maybe_mgn) => {
1083                                    range.align_start_of(parent_range).middle()
1084                                        + maybe_mgn.unwrap_or(0.0)
1085                                }
1086                                position::Place::Middle => parent_range.middle(),
1087                                position::Place::End(maybe_mgn) => {
1088                                    range.align_end_of(parent_range).middle()
1089                                        - maybe_mgn.unwrap_or(0.0)
1090                                }
1091                            }
1092                        })
1093                        .unwrap_or(0.0)
1094                }
1095            }
1096        }
1097
1098        fn x_range(rect: Rect) -> Range {
1099            rect.x
1100        }
1101        fn y_range(rect: Rect) -> Range {
1102            rect.y
1103        }
1104        fn x_pad(pad: Padding) -> Range {
1105            pad.x
1106        }
1107        fn y_pad(pad: Padding) -> Range {
1108            pad.y
1109        }
1110        let x = abs_from_position(
1111            self,
1112            maybe_parent_id,
1113            x_position,
1114            dim[0],
1115            place_on_kid_area,
1116            x_range,
1117            x_pad,
1118        );
1119        let y = abs_from_position(
1120            self,
1121            maybe_parent_id,
1122            y_position,
1123            dim[1],
1124            place_on_kid_area,
1125            y_range,
1126            y_pad,
1127        );
1128        let xy = [x, y];
1129
1130        // Add the widget's parents' total combined scroll offset to the given xy.
1131        maybe_id
1132            .map(|idx| vec2_add(xy, graph::algo::scroll_offset(&self.widget_graph, idx)))
1133            .unwrap_or(xy)
1134    }
1135
1136    /// A function within which all widgets are instantiated by the user, normally situated within
1137    /// the "update" stage of an event loop.
1138    pub fn set_widgets(&mut self) -> UiCell {
1139        self.maybe_prev_widget_id = None;
1140        self.maybe_current_parent_id = None;
1141
1142        // Move the previous `updated_widgets` to `prev_updated_widgets` and clear
1143        // `updated_widgets` so that we're ready to store the newly updated widgets.
1144        {
1145            let Ui {
1146                ref mut updated_widgets,
1147                ref mut prev_updated_widgets,
1148                ..
1149            } = *self;
1150            std::mem::swap(updated_widgets, prev_updated_widgets);
1151            updated_widgets.clear();
1152        }
1153
1154        let mut ui_cell = UiCell { ui: self };
1155
1156        // Instantiate the root `Window` `Widget`.
1157        //
1158        // This widget acts as the parent-most widget and root node for the Ui's `widget_graph`,
1159        // upon which all other widgets are placed.
1160        {
1161            use {color, Borderable, Colorable, Positionable};
1162            type Window = widget::BorderedRectangle;
1163            Window::new([ui_cell.win_w, ui_cell.win_h])
1164                .no_parent()
1165                .x_y(0.0, 0.0)
1166                .border(0.0)
1167                .border_color(color::BLACK.alpha(0.0))
1168                .color(
1169                    ui_cell
1170                        .maybe_background_color
1171                        .unwrap_or(color::BLACK.alpha(0.0)),
1172                )
1173                .set(ui_cell.window, &mut ui_cell);
1174        }
1175
1176        ui_cell.ui.maybe_current_parent_id = Some(ui_cell.window.into());
1177
1178        ui_cell.set_mouse_cursor(cursor::MouseCursor::Arrow);
1179
1180        ui_cell
1181    }
1182
1183    /// Set the number of frames that the `Ui` should draw in the case that `needs_redraw` is
1184    /// called. The default is `3` (see the SAFE_REDRAW_COUNT docs for details).
1185    pub fn set_num_redraw_frames(&mut self, num_frames: u8) {
1186        self.num_redraw_frames = num_frames;
1187    }
1188
1189    /// Tells the `Ui` that it needs to re-draw everything. It does this by setting the redraw
1190    /// count to `num_redraw_frames`. See the docs for `set_num_redraw_frames`, SAFE_REDRAW_COUNT
1191    /// or `draw_if_changed` for more info on how/why the redraw count is used.
1192    pub fn needs_redraw(&self) {
1193        self.redraw_count
1194            .store(self.num_redraw_frames as usize, atomic::Ordering::Relaxed);
1195    }
1196
1197    /// The first of the `Primitives` yielded by `Ui::draw` or `Ui::draw_if_changed` will always
1198    /// be a `Rectangle` the size of the window in which conrod is hosted.
1199    ///
1200    /// This method sets the colour with which this `Rectangle` is drawn (the default being
1201    /// `conrod::color::TRANSPARENT`.
1202    pub fn clear_with(&mut self, color: Color) {
1203        self.maybe_background_color = Some(color);
1204    }
1205
1206    /// Draw the `Ui` in it's current state.
1207    ///
1208    /// NOTE: If you don't need to redraw your conrod GUI every frame, it is recommended to use the
1209    /// `Ui::draw_if_changed` method instead.
1210    pub fn draw(&self) -> render::Primitives {
1211        let Ui {
1212            ref redraw_count,
1213            ref widget_graph,
1214            ref depth_order,
1215            ref theme,
1216            ref fonts,
1217            win_w,
1218            win_h,
1219            ..
1220        } = *self;
1221
1222        // Use the depth_order indices as the order for drawing.
1223        let indices = &depth_order.indices;
1224
1225        // We're about to draw everything, so take one from the redraw count.
1226        let remaining_redraws = redraw_count.load(atomic::Ordering::Relaxed);
1227        if remaining_redraws > 0 {
1228            redraw_count.store(remaining_redraws - 1, atomic::Ordering::Relaxed);
1229        }
1230
1231        render::Primitives::new(widget_graph, indices, theme, fonts, [win_w, win_h])
1232    }
1233
1234    /// Same as the `Ui::draw` method, but *only* draws if the `redraw_count` is greater than 0.
1235    ///
1236    /// The `redraw_count` is set to `SAFE_REDRAW_COUNT` whenever a `Widget` indicates that it
1237    /// needs to be re-drawn.
1238    ///
1239    /// It can also be triggered manually by the user using the `Ui::needs_redraw` method.
1240    ///
1241    /// This method is generally preferred over `Ui::draw` as it requires far less CPU usage, only
1242    /// redrawing to the screen if necessary.
1243    ///
1244    /// Note that when `Ui::needs_redraw` is triggered, it sets the `redraw_count` to 3 by default.
1245    /// This ensures that conrod is drawn to each buffer in the case that there is buffer swapping
1246    /// happening. Let us know if you need finer control over this and we'll expose a way for you
1247    /// to set the redraw count manually.
1248    pub fn draw_if_changed(&self) -> Option<render::Primitives> {
1249        if self.has_changed() {
1250            return Some(self.draw());
1251        }
1252
1253        None
1254    }
1255
1256    /// Returns if the redraw_count is greater than 0 and thus draw_if_changed would draw
1257    /// See `Ui::draw_if_changed` for when this is triggered
1258    pub fn has_changed(&self) -> bool {
1259        self.redraw_count.load(atomic::Ordering::Relaxed) > 0
1260    }
1261
1262    /// The **Rect** that bounds the kids of the widget with the given index.
1263    pub fn kids_bounding_box(&self, id: widget::Id) -> Option<Rect> {
1264        graph::algo::kids_bounding_box(&self.widget_graph, &self.prev_updated_widgets, id)
1265    }
1266
1267    /// The **Rect** that represents the maximum fully visible area for the widget with the given
1268    /// index, including consideration of cropped scroll area.
1269    ///
1270    /// Otherwise, return None if the widget is not visible.
1271    pub fn visible_area(&self, id: widget::Id) -> Option<Rect> {
1272        graph::algo::cropped_area_of_widget(&self.widget_graph, id)
1273    }
1274
1275    /// Get mouse cursor state.
1276    pub fn mouse_cursor(&self) -> cursor::MouseCursor {
1277        self.mouse_cursor
1278    }
1279}
1280
1281impl<'a> UiCell<'a> {
1282    /// A reference to the `Theme` that is currently active within the `Ui`.
1283    pub fn theme(&self) -> &Theme {
1284        &self.ui.theme
1285    }
1286
1287    /// A convenience method for borrowing the `Font` for the given `Id` if it exists.
1288    pub fn font(&self, id: text::font::Id) -> Option<&text::Font> {
1289        self.ui.fonts.get(id)
1290    }
1291
1292    /// Returns the dimensions of the window
1293    pub fn window_dim(&self) -> Dimensions {
1294        [self.ui.win_w, self.ui.win_h]
1295    }
1296
1297    /// Returns an immutable reference to the `input::Global` of the `Ui`.
1298    ///
1299    /// All coordinates here will be relative to the center of the window.
1300    pub fn global_input(&self) -> &input::Global {
1301        &self.ui.global_input
1302    }
1303
1304    /// Returns a `input::Widget` with input events for the widget.
1305    ///
1306    /// All coordinates in the `input::Widget` will be relative to the widget at the given index.
1307    pub fn widget_input(&self, id: widget::Id) -> input::Widget {
1308        self.ui.widget_input(id)
1309    }
1310
1311    /// Produces a type that may be used to generate new unique `widget::Id`s.
1312    ///
1313    /// See the [**widget::id::Generator**](../widget/id/struct.Generator.html) docs for details on
1314    /// how to use this correctly.
1315    pub fn widget_id_generator(&mut self) -> widget::id::Generator {
1316        self.ui.widget_id_generator()
1317    }
1318
1319    /// The **Rect** that bounds the kids of the widget with the given index.
1320    ///
1321    /// Returns `None` if the widget has no children or if there's is no widget for the given index.
1322    pub fn kids_bounding_box(&self, id: widget::Id) -> Option<Rect> {
1323        self.ui.kids_bounding_box(id)
1324    }
1325
1326    /// Scroll the widget at the given index by the given offset amount.
1327    ///
1328    /// The produced `Scroll` event will be pushed to the `pending_scroll_events` and will be
1329    /// applied to the widget during the next call to `Ui::set_widgets`.
1330    pub fn scroll_widget(&mut self, id: widget::Id, offset: [Scalar; 2]) {
1331        let (x, y) = (offset[0], offset[1]);
1332
1333        if x != 0.0 || y != 0.0 {
1334            let event = event::Ui::Scroll(
1335                Some(id),
1336                event::Scroll {
1337                    x: x,
1338                    y: y,
1339                    modifiers: self.ui.global_input.current.modifiers,
1340                },
1341            );
1342            self.ui.pending_scroll_events.push(event);
1343        }
1344    }
1345
1346    /// Sets the mouse cursor
1347    pub fn set_mouse_cursor(&mut self, cursor: cursor::MouseCursor) {
1348        self.ui.mouse_cursor = cursor;
1349    }
1350}
1351
1352impl<'a> Drop for UiCell<'a> {
1353    fn drop(&mut self) {
1354        // We'll need to re-draw if we have gained or lost widgets.
1355        let changed = self.ui.updated_widgets != self.ui.prev_updated_widgets;
1356        if changed {
1357            self.ui.needs_redraw();
1358        }
1359
1360        // Update the **DepthOrder** so that it reflects the **Graph**'s current state.
1361        {
1362            let Ui {
1363                ref widget_graph,
1364                ref mut depth_order,
1365                window,
1366                ref updated_widgets,
1367                ..
1368            } = *self.ui;
1369
1370            depth_order.update(widget_graph, window, updated_widgets);
1371        }
1372
1373        // Reset the global input state. Note that this is the **only** time this should be called.
1374        self.ui.global_input.clear_events_and_update_start_state();
1375
1376        // Update which widget is under the cursor.
1377        if changed {
1378            self.ui.track_widget_under_mouse_and_update_capturing();
1379        }
1380
1381        // Move all pending `Scroll` events that have been produced since the start of this method
1382        // into the `global_input` event buffer.
1383        for scroll_event in self.ui.pending_scroll_events.drain(0..) {
1384            self.ui.global_input.push_event(scroll_event.into());
1385        }
1386    }
1387}
1388
1389impl<'a> ::std::ops::Deref for UiCell<'a> {
1390    type Target = Ui;
1391    fn deref(&self) -> &Ui {
1392        self.ui
1393    }
1394}
1395
1396impl<'a> AsRef<Ui> for UiCell<'a> {
1397    fn as_ref(&self) -> &Ui {
1398        &self.ui
1399    }
1400}
1401
1402/// A function for retrieving the `&mut Ui<B>` from a `UiCell<B>`.
1403///
1404/// This function is only for internal use to allow for some `Ui` type acrobatics in order to
1405/// provide a nice *safe* API for the user.
1406pub fn ref_mut_from_ui_cell<'a, 'b: 'a>(ui_cell: &'a mut UiCell<'b>) -> &'a mut Ui {
1407    ui_cell.ui
1408}
1409
1410/// A mutable reference to the given `Ui`'s widget `Graph`.
1411pub fn widget_graph_mut(ui: &mut Ui) -> &mut Graph {
1412    &mut ui.widget_graph
1413}
1414
1415/// Infer a widget's `Depth` parent by examining it's *x* and *y* `Position`s.
1416///
1417/// When a different parent may be inferred from either `Position`, the *x* `Position` is favoured.
1418pub fn infer_parent_from_position(ui: &Ui, x: Position, y: Position) -> Option<widget::Id> {
1419    use position::Relative::{Align, Direction, Place, Scalar};
1420    use Position::Relative;
1421    match (x, y) {
1422        (Relative(Place(_), maybe_parent_id), _) | (_, Relative(Place(_), maybe_parent_id)) => {
1423            maybe_parent_id
1424        }
1425        (Relative(Direction(_, _), maybe_id), _)
1426        | (_, Relative(Direction(_, _), maybe_id))
1427        | (Relative(Align(_), maybe_id), _)
1428        | (_, Relative(Align(_), maybe_id))
1429        | (Relative(Scalar(_), maybe_id), _)
1430        | (_, Relative(Scalar(_), maybe_id)) => maybe_id
1431            .or(ui.maybe_prev_widget_id)
1432            .and_then(|idx| ui.widget_graph.depth_parent(idx)),
1433        _ => None,
1434    }
1435}
1436
1437/// Attempts to infer the parent of a widget from its *x*/*y* `Position`s and the current state of
1438/// the `Ui`.
1439///
1440/// If no parent can be inferred via the `Position`s, the `maybe_current_parent_id` will be used.
1441///
1442/// If `maybe_current_parent_id` is `None`, the `Ui`'s `window` widget will be used.
1443///
1444/// **Note:** This function does not check whether or not using the `window` widget would cause a
1445/// cycle.
1446pub fn infer_parent_unchecked(ui: &Ui, x_pos: Position, y_pos: Position) -> widget::Id {
1447    infer_parent_from_position(ui, x_pos, y_pos)
1448        .or(ui.maybe_current_parent_id)
1449        .unwrap_or(ui.window.into())
1450}
1451
1452/// Cache some `PreUpdateCache` widget data into the widget graph.
1453/// Set the widget that is being cached as the new `prev_widget`.
1454/// Set the widget's parent as the new `current_parent`.
1455pub fn pre_update_cache(ui: &mut Ui, widget: widget::PreUpdateCache) {
1456    ui.maybe_prev_widget_id = Some(widget.id);
1457    ui.maybe_current_parent_id = widget.maybe_parent_id;
1458    let widget_id = widget.id;
1459    ui.widget_graph
1460        .pre_update_cache(ui.window, widget, ui.updated_widgets.len());
1461
1462    // Add the widget's `widget::Id` to the set of updated widgets.
1463    ui.updated_widgets.insert(widget_id);
1464}
1465
1466/// Cache some `PostUpdateCache` widget data into the widget graph.
1467/// Set the widget that is being cached as the new `prev_widget`.
1468/// Set the widget's parent as the new `current_parent`.
1469pub fn post_update_cache<W>(ui: &mut Ui, widget: widget::PostUpdateCache<W>)
1470where
1471    W: Widget,
1472    W::State: 'static,
1473    W::Style: 'static,
1474{
1475    ui.maybe_prev_widget_id = Some(widget.id);
1476    ui.maybe_current_parent_id = widget.maybe_parent_id;
1477    ui.widget_graph.post_update_cache(widget);
1478}