conrod_core/widget/mod.rs
1//! Widgets are the core building blocks for every conrod user interface.
2//!
3//! This module contains items related to the implementation of the `Widget` trait. It also
4//! re-exports all widgets (and their modules) that are provided by conrod.
5
6use graph::{Container, UniqueWidgetState};
7use position::{
8 Align, Depth, Dimension, Dimensions, Padding, Point, Position, Positionable, Rect, Relative,
9 Sizeable,
10};
11use std;
12use text::font;
13use theme::{self, Theme};
14use ui::{self, Ui, UiCell};
15
16pub use self::id::Id;
17
18pub use self::primitive::image::{self, Image};
19pub use self::primitive::line::{self, Line};
20pub use self::primitive::point_path::{self, PointPath};
21pub use self::primitive::shape::circle::{self, Circle};
22pub use self::primitive::shape::oval::{self, Oval};
23pub use self::primitive::shape::polygon::{self, Polygon};
24pub use self::primitive::shape::rectangle::{self, Rectangle};
25pub use self::primitive::shape::triangles::{self, Triangles};
26pub use self::primitive::text::{self, Text};
27
28pub use self::bordered_rectangle::BorderedRectangle;
29pub use self::button::Button;
30pub use self::canvas::Canvas;
31pub use self::collapsible_area::CollapsibleArea;
32pub use self::drop_down_list::DropDownList;
33pub use self::envelope_editor::EnvelopeEditor;
34pub use self::file_navigator::FileNavigator;
35pub use self::graph::Graph;
36pub use self::grid::Grid;
37pub use self::list::List;
38pub use self::list_select::ListSelect;
39pub use self::matrix::Matrix;
40pub use self::number_dialer::NumberDialer;
41pub use self::plot_path::PlotPath;
42pub use self::range_slider::RangeSlider;
43pub use self::rounded_rectangle::RoundedRectangle;
44pub use self::scrollbar::Scrollbar;
45pub use self::slider::Slider;
46pub use self::tabs::Tabs;
47pub use self::text_box::TextBox;
48pub use self::text_edit::TextEdit;
49pub use self::title_bar::TitleBar;
50pub use self::toggle::Toggle;
51pub use self::xy_pad::XYPad;
52
53// Macro providing modules.
54#[macro_use]
55mod builder;
56
57// Widget functionality modules.
58#[macro_use]
59pub mod id;
60pub mod scroll;
61
62// Primitive widget modules.
63pub mod primitive;
64
65// Widget modules.
66
67pub mod bordered_rectangle;
68pub mod button;
69pub mod canvas;
70pub mod collapsible_area;
71pub mod drop_down_list;
72pub mod envelope_editor;
73pub mod file_navigator;
74pub mod graph;
75pub mod grid;
76pub mod list;
77pub mod list_select;
78pub mod matrix;
79pub mod number_dialer;
80pub mod plot_path;
81pub mod range_slider;
82pub mod rounded_rectangle;
83pub mod scrollbar;
84pub mod slider;
85pub mod tabs;
86pub mod text_box;
87pub mod text_edit;
88pub mod title_bar;
89pub mod toggle;
90pub mod xy_pad;
91
92/// Arguments for the [**Widget::update**](./trait.Widget#method.update) method in a struct to
93/// simplify the method signature.
94pub struct UpdateArgs<'a, 'b: 'a, 'c, 'd: 'c, W>
95where
96 W: Widget,
97{
98 /// The **Widget**'s unique index.
99 pub id: Id,
100 /// The **Widget**'s parent unique index, if there is one.
101 pub maybe_parent_id: Option<Id>,
102 /// The **Widget**'s previous state. Specifically, the state that is common between all widgets,
103 /// such as positioning, floatability, draggability, etc.
104 pub prev: &'a CommonState,
105 /// A wrapper around the **Widget**'s unique state, providing methods for both immutably viewing
106 /// and mutably updating the state.
107 ///
108 /// We wrap mutation in a method so that we can keep track of whether or not the unique state
109 /// has been updated.
110 ///
111 /// If **State::update** is called, we assume that there has been some mutation and in turn
112 /// will require re-drawing the **Widget**. Thus, it is recommended that you *only* call
113 /// **State::update** if you need to update the unique state in some way.
114 pub state: &'a mut State<'b, W::State>,
115 /// The rectangle describing the **Widget**'s area.
116 pub rect: Rect,
117 /// The **Widget**'s current **Widget::Style**.
118 pub style: &'a W::Style,
119 /// Restricted access to the `Ui`.
120 ///
121 /// Provides methods for immutably accessing the `Ui`'s `Theme` and `GlyphCache`. Also allows
122 /// calling `Widget::set` within the `Widget::update` method.
123 pub ui: &'c mut UiCell<'d>,
124}
125
126/// Arguments to the [**Widget::kid_area**](./trait.Widget#method.kid_area) method in a struct to
127/// simplify the method signature.
128pub struct KidAreaArgs<'a, W>
129where
130 W: Widget,
131{
132 /// The **Rect** describing the **Widget**'s position and dimensions.
133 pub rect: Rect,
134 /// Current **Widget::Style** of the **Widget**.
135 pub style: &'a W::Style,
136 /// The active **Theme** within the **Ui**.
137 pub theme: &'a Theme,
138 /// The **Font** (for determining text width).
139 pub fonts: &'a font::Map,
140}
141
142/// The area upon which a **Widget**'s child widgets will be placed.
143#[derive(Copy, Clone, Debug, PartialEq)]
144pub struct KidArea {
145 /// The **Rect** bounds describing the position and area.
146 pub rect: Rect,
147 /// The distance between the edge of the area and where the widgets will be placed.
148 pub pad: Padding,
149}
150
151/// The builder argument for the **Widget**'s parent.
152#[derive(Copy, Clone, Debug, PartialEq)]
153pub enum MaybeParent {
154 /// The user specified the widget should not have any parents, so the Root will be used.
155 None,
156 /// The user gave a specific parent widget.
157 Some(Id),
158 /// No parent widget was specified, so we will assume they want the last parent.
159 Unspecified,
160}
161
162impl MaybeParent {
163 /// Convert the **MaybeParent** into an **Option<Id>**.
164 ///
165 /// If `Unspecified`, check the positioning to retrieve the **Id** from there.
166 ///
167 /// If `None`, the `Ui`'s `window` widget will be used.
168 ///
169 /// **Note:** This method does not check whether or not using the `window` widget as the parent
170 /// would cause a cycle. If it is important that the inferred parent should not cause a cycle,
171 /// use `get` instead.
172 pub fn get_unchecked(&self, ui: &Ui, x_pos: Position, y_pos: Position) -> Id {
173 match *self {
174 MaybeParent::Some(id) => id,
175 MaybeParent::None => ui.window.into(),
176 MaybeParent::Unspecified => ui::infer_parent_unchecked(ui, x_pos, y_pos),
177 }
178 }
179
180 /// The same as `get_unchecked`, but checks whether or not the widget that we're inferring the
181 /// parent for is the `Ui`'s window (which cannot have a parent, without creating a cycle).
182 pub fn get(&self, id: Id, ui: &Ui, x_pos: Position, y_pos: Position) -> Option<Id> {
183 if id == ui.window {
184 None
185 } else {
186 Some(self.get_unchecked(ui, x_pos, y_pos))
187 }
188 }
189}
190
191/// State necessary for "floating" (pop-up style) widgets.
192#[derive(Copy, Clone, Debug, PartialEq)]
193pub struct Floating {
194 /// The time the **Widget** was last clicked (used for depth sorting in the widget **Graph**).
195 pub time_last_clicked: instant::Instant,
196}
197
198/// A struct containing builder data common to all **Widget** types.
199///
200/// This type also allows us to do a blanket impl of **Positionable** and **Sizeable** for `T: Widget`.
201///
202/// When Rust gets some sort of field inheritance feature, this will most likely be refactored to
203/// take advantage of that.
204#[derive(Clone, Copy, Debug)]
205pub struct CommonBuilder {
206 /// Styling and positioning data that is common between all widget types.
207 pub style: CommonStyle,
208 /// The parent widget of the Widget.
209 pub maybe_parent_id: MaybeParent,
210 /// Whether or not the Widget is a "floating" Widget.
211 pub is_floating: bool,
212 /// Whether or not the children of this **Widget** should be cropped to its `kid_area`.
213 ///
214 /// By default, the kid_area is the size of the entire widget, though it may be specified
215 /// otherwise via the `Widget::kid_area` method.
216 pub crop_kids: bool,
217 /// Arguments to the scrolling of the widget's *x* axis.
218 pub maybe_x_scroll: Option<scroll::Scroll>,
219 /// Arguments to the scrolling of the widget's *y* axis.
220 pub maybe_y_scroll: Option<scroll::Scroll>,
221 /// Whether or not the **Widget** should be placed on the kid_area.
222 ///
223 /// If `true`, the **Widget** will be placed on the `kid_area` of the parent **Widget** if the
224 /// **Widget** is given a **Place** variant for its **Position**.
225 ///
226 /// If `false`, the **Widget** will be placed on the parent **Widget**'s *total* area.
227 pub place_on_kid_area: bool,
228 /// Describes whether or not the **Widget** is instantiated as a graphical element for some
229 /// other **Widget**.
230 ///
231 /// When adding an edge *a -> b* where *b* is considered to be a graphical element of *a*,
232 /// several things are implied about *b*:
233 ///
234 /// - If *b* is picked within either **Graph::pick_widget** or
235 /// **Graph::pick_top_scrollable_widget**, it will instead return the index for *a*.
236 /// - When determining the **Graph::scroll_offset** for *b*, *a*'s scrolling (if it is
237 /// scrollable, that is) will be skipped.
238 /// - *b* will always be placed upon *a*'s total area, rather than its kid_area which is the
239 /// default.
240 /// - Any **Graphic** child of *b* will be considered as a **Graphic** child of *a*.
241 pub maybe_graphics_for: Option<Id>,
242}
243
244/// Styling and positioning data that is common between all widget types.
245#[derive(Clone, Copy, Debug, Default, PartialEq)]
246pub struct CommonStyle {
247 /// The width of a Widget.
248 pub maybe_x_dimension: Option<Dimension>,
249 /// The height of a Widget.
250 pub maybe_y_dimension: Option<Dimension>,
251 /// The position of a Widget along the *x* axis.
252 pub maybe_x_position: Option<Position>,
253 /// The position of a Widget along the *y* axis.
254 pub maybe_y_position: Option<Position>,
255 /// The rendering Depth of the Widget.
256 pub maybe_depth: Option<Depth>,
257}
258
259/// A wrapper around a **Widget**'s unique **Widget::State**.
260///
261/// This type is used to provide limited access to the **Widget::State** within the
262/// [**Widget::update**](./trait.Widget#method.update) method (to which it is passed via the
263/// [**UpdateArgs**](./struct.UpdateArgs)).
264///
265/// The type provides only two methods. One for viewing the state, the other for mutating it.
266///
267/// We do this so that we can keep track of whether or not the **Widget::State** has been mutated
268/// (using an internal `has_updated` flag). This allows us to know whether or not we need to
269/// re-draw the **Widget**, without having to compare the previous and new **Widget::State**s.
270pub struct State<'a, T: 'a> {
271 state: &'a mut T,
272 /// A flag indicating whether or not the widget's State has been updated.
273 has_updated: bool,
274}
275
276/// A wrapper around state that is common to all **Widget** types.
277#[derive(Copy, Clone, Debug, PartialEq)]
278pub struct CommonState {
279 /// The rectangle describing the `Widget`'s area.
280 pub rect: Rect,
281 /// The rendering depth for the Widget (the default is 0.0).
282 pub depth: Depth,
283 /// If widget is draggable and is being dragged, this is where it started
284 pub maybe_dragged_from: Option<Point>,
285 /// Floating state for the widget if it is floating.
286 pub maybe_floating: Option<Floating>,
287 /// The area of the widget upon which kid widgets are placed.
288 pub kid_area: KidArea,
289 /// If the widget is scrollable across the *x* axis.
290 pub maybe_x_scroll_state: Option<scroll::StateX>,
291 /// If the widget is scrollable across the *y* axis.
292 pub maybe_y_scroll_state: Option<scroll::StateY>,
293}
294
295// **Widget** data to be cached prior to the **Widget::update** call in the **widget::set_widget**
296// function.
297//
298// We do this so that if this **Widget** were to internally `set` some other **Widget**s, this
299// **Widget**'s positioning and dimension data already exists within the widget **Graph** for
300// reference.
301#[allow(missing_docs)]
302#[allow(missing_copy_implementations)]
303pub struct PreUpdateCache {
304 /// The **Widget**'s unique type identifier.
305 pub type_id: std::any::TypeId,
306 /// The **Widget**'s unique Id.
307 pub id: Id,
308 /// The **Widget**'s parent's unique index (if it has a parent).
309 pub maybe_parent_id: Option<Id>,
310 /// If this **Widget** is relatively positioned to another **Widget**, this will be the index
311 /// of the **Widget** to which this **Widget** is relatively positioned along the *x* axis.
312 pub maybe_x_positioned_relatively_id: Option<Id>,
313 /// If this **Widget** is relatively positioned to another **Widget**, this will be the index
314 /// of the **Widget** to which this **Widget** is relatively positioned along the *y* axis.
315 pub maybe_y_positioned_relatively_id: Option<Id>,
316 /// The **Rect** describing the **Widget**'s position and dimensions.
317 pub rect: Rect,
318 /// The z-axis depth - affects the render order of sibling widgets.
319 pub depth: Depth,
320 /// The area upon which the **Widget**'s children widgets will be placed.
321 pub kid_area: KidArea,
322 /// If **Widget** is draggable and is being dragged, this is where it started
323 pub maybe_dragged_from: Option<Point>,
324 /// Floating data for the **Widget** if there is some.
325 pub maybe_floating: Option<Floating>,
326 /// Whether or not the children of the **Widget** should be cropped to its `kid_area`.
327 pub crop_kids: bool,
328 /// Scrolling data for the **Widget**'s *x* axis if there is some.
329 pub maybe_x_scroll_state: Option<scroll::StateX>,
330 /// Scrolling data for the **Widget**'s *y* axis if there is some.
331 pub maybe_y_scroll_state: Option<scroll::StateY>,
332 /// Whether or not the **Widget** has been instantiated as a graphical element for some other
333 /// widget.
334 pub maybe_graphics_for: Option<Id>,
335 /// A function describing whether or not a given point is over the widget.
336 pub is_over: IsOverFn,
337}
338
339// **Widget** data to be cached after the **Widget::update** call in the **widget::set_widget**
340// function.
341//
342// We do this so that if this **Widget** were to internally **Widget::set** some other
343// **Widget**s, this **Widget**'s positioning and dimension data will already exist within the
344// widget **Graph** for reference.
345#[allow(missing_docs)]
346pub struct PostUpdateCache<W>
347where
348 W: Widget,
349{
350 /// The **Widget**'s unique **Id**.
351 pub id: Id,
352 /// The **Widget**'s parent's unique **Id** (if it has a parent).
353 pub maybe_parent_id: Option<Id>,
354 /// The newly produced unique **Widget::State** associated with the **Widget**.
355 pub state: W::State,
356 /// The newly produced unique **Widget::Style** associated with the **Widget**.
357 pub style: W::Style,
358}
359
360/// Returned by the `Widget::is_over` method.
361#[derive(Copy, Clone)]
362pub enum IsOver {
363 /// Whether or not the point was over the widget.
364 Bool(bool),
365 /// Check whether or not the point is over the widget at the given `Id` and if so, assume it is
366 /// over this widget.
367 Widget(Id),
368}
369
370impl From<bool> for IsOver {
371 fn from(b: bool) -> Self {
372 IsOver::Bool(b)
373 }
374}
375
376impl From<Id> for IsOver {
377 fn from(id: Id) -> Self {
378 IsOver::Widget(id)
379 }
380}
381
382/// A function type used to determine whether or not a given point is over a widget.
383pub type IsOverFn = fn(&Container, Point, &Theme) -> IsOver;
384
385/// The default `IsOverFn` used if the `Widget::is_over` method is not overridden.
386pub fn is_over_rect(container: &Container, point: Point, _: &Theme) -> IsOver {
387 container.rect.is_over(point).into()
388}
389
390/// The necessary bounds for a **Widget**'s associated **Style** type.
391pub trait Style: std::any::Any + std::fmt::Debug + PartialEq + Sized {}
392
393/// Auto-implement the **Style** trait for all applicable types.
394impl<T> Style for T where T: std::any::Any + std::fmt::Debug + PartialEq + Sized {}
395
396/// Determines the default **Dimension** for a **Widget**.
397///
398/// This function checks for a default dimension in the following order.
399/// 1. Check for a default value within the **Ui**'s **Theme**.
400/// 2. Otherwise attempts to copy the dimension of the previously set widget if there is one.
401/// 3. Otherwise attempts to copy the dimension of our parent widget.
402/// 4. If no parent widget can be inferred, the window dimensions are used.
403fn default_dimension<W, F>(widget: &W, ui: &Ui, f: F) -> Dimension
404where
405 W: Widget,
406 F: FnOnce(theme::UniqueDefault<W::Style>) -> Option<Dimension>,
407{
408 ui.theme
409 .widget_style::<W::Style>()
410 .and_then(f)
411 .or_else(|| ui.maybe_prev_widget().map(|id| Dimension::Of(id, None)))
412 .unwrap_or_else(|| {
413 let x_pos = widget.get_x_position(ui);
414 let y_pos = widget.get_y_position(ui);
415 let parent_id = widget
416 .common()
417 .maybe_parent_id
418 .get_unchecked(ui, x_pos, y_pos);
419 Dimension::Of(parent_id, None)
420 })
421}
422
423/// Determines the default **Dimension** for a **Widget**.
424///
425/// This function checks for a default dimension in the following order.
426/// 1. Check for a default value within the **Ui**'s **Theme**.
427/// 2. Otherwise attempts to copy the dimension of the previously set widget if there is one.
428/// 3. Otherwise attempts to copy the dimension of our parent widget.
429/// 4. If no parent widget can be inferred, the window dimensions are used.
430///
431/// This is called by the default implementations of **Widget::default_x_dimension**.
432///
433/// If you wish to override **Widget::default_x_dimension**, feel free to call this function
434/// internally if you partly require the bahaviour of the default implementations.
435pub fn default_x_dimension<W>(widget: &W, ui: &Ui) -> Dimension
436where
437 W: Widget,
438{
439 default_dimension(widget, ui, |default| default.common.maybe_x_dimension)
440}
441
442/// Determines the default **Dimension** for a **Widget**.
443///
444/// This function checks for a default dimension in the following order.
445/// 1. Check for a default value within the **Ui**'s **Theme**.
446/// 2. Otherwise attempts to copy the dimension of the previously set widget if there is one.
447/// 3. Otherwise attempts to copy the dimension of our parent widget.
448/// 4. If no parent widget can be inferred, the window dimensions are used.
449///
450/// This is called by the default implementations of **Widget::default_y_dimension**.
451///
452/// If you wish to override **Widget::default_y_dimension**, feel free to call this function
453/// internally if you partly require the bahaviour of the default implementations.
454pub fn default_y_dimension<W>(widget: &W, ui: &Ui) -> Dimension
455where
456 W: Widget,
457{
458 default_dimension(widget, ui, |default| default.common.maybe_y_dimension)
459}
460
461/// A trait implemented by all **Widget** types.
462///
463/// This trait provides access to a field of type **CommonBuilder** on the implementor. This allows
464/// the `Widget` trait to automatically provide a large number of methods including those from the
465/// **Positionable** and **Sizeable** traits.
466///
467/// The **Common** trait can be automatically derived for widgets like so:
468///
469/// ```ignore
470/// extern crate conrod_core;
471/// #[macro_use] extern crate conrod_derive;
472///
473/// #[derive(WidgetCommon)]
474/// struct MyWidget {
475/// #[conrod(common_builder)]
476/// common: conrod_core::widget::CommonBuilder,
477/// // etc
478/// }
479/// ```
480pub trait Common {
481 /// Borrows the `CommonBuilder` field.
482 fn common(&self) -> &CommonBuilder;
483 /// Mutably borrows the `CommonBuilder` field.
484 fn common_mut(&mut self) -> &mut CommonBuilder;
485}
486
487/// A trait to be implemented by all **Widget** types.
488///
489/// A type that implements **Widget** can be thought of as a collection of arguments to the
490/// **Widget**'s **Widget::update** method. They type itself is not stored between updates, but
491/// rather is used to update an instance of the **Widget**'s **Widget::State**, which *is* stored.
492///
493/// Methods that *must* be overridden:
494///
495/// - init_state
496/// - style
497/// - update
498///
499/// Methods that can be optionally overridden:
500///
501/// - default_x_position
502/// - default_y_position
503/// - default_width
504/// - default_height
505/// - drag_area
506/// - kid_area
507///
508/// Methods that should not be overridden:
509///
510/// - floating
511/// - scroll_kids
512/// - scroll_kids_vertically
513/// - scroll_kids_horizontally
514/// - place_widget_on_kid_area
515/// - parent
516/// - no_parent
517/// - set
518pub trait Widget: Common + Sized {
519 /// State to be stored within the `Ui`s widget cache.
520 ///
521 /// Take advantage of this type for any large allocations that you would like to avoid
522 /// repeating between updates, or any calculations that you'd like to avoid repeating between
523 /// calls to `update`.
524 ///
525 /// Conrod will never clone the state, it will only ever be moved.
526 type State: std::any::Any + Send;
527 /// Every widget is required to have its own associated `Style` type. This type is intended to
528 /// contain high-level styling information for the widget that can be *optionally specified* by
529 /// a user of the widget.
530 ///
531 /// All `Style` structs are typically `Copy` and contain simple, descriptive fields like
532 /// `color`, `font_size`, `line_spacing`, `border_width`, etc. These types are also required to
533 /// be `PartialEq`. This is so that the `Ui` may automatically compare the previous style to
534 /// the new style each time `.set` is called, allowing conrod to automatically determine
535 /// whether or not something has changed and if a re-draw is required.
536 ///
537 /// Each field in a `Style` struct is typically an `Option<T>`. This is so that each field may
538 /// be *optionally specified*, indicating to fall back to defaults if the fields are `None`
539 /// upon style retrieval.
540 ///
541 /// The reason this data is required to be in its own `Style` type (rather than in the widget
542 /// type itself) is so that conrod can distinguish between default style data that may be
543 /// stored within the `Theme`'s `widget_styling` field, and other data that is necessary for
544 /// the widget's behaviour logic. Having `Style` be an associated type makes it trivial to
545 /// retrieve unique, widget-specific styling data for each widget from a single method (see
546 /// [`Theme::widget_style`](./theme/struct.Theme.html#method.widget_style)).
547 ///
548 /// ## `#[derive(WidgetStyle)]`
549 ///
550 /// These `Style` types are often quite similar and their implementations can involve a lot of
551 /// boilerplate when written by hand. To get around this, conrod provides
552 /// `#[derive(WidgetStyle)]`.
553 ///
554 /// This procedural macro generates a "getter"-style method for each struct field that is
555 /// decorated with a `#[conrod(default = "expr")]` attribute. The generated methods have the
556 /// same name as their respective fields and behave as follows:
557 ///
558 /// 1. First, the method will attempt to return the value directly if the field is `Some`.
559 /// 2. If the field is `None`, the method will fall back to the `Widget::Style` stored within
560 /// the `Theme`'s `widget_styling` map.
561 /// 3. If there are no style defaults for the widget in the `Theme`, or if there is but the
562 /// default field is also `None`, the method will fall back to the expression specified
563 /// within the field's `#[conrod(default = "expr")]` attribute.
564 ///
565 /// The given "expr" can be a string containing any expression that returns the type specified
566 /// within the field's `Option` type parameter. The expression may also utilise the `theme` and
567 /// `self` bindings, where `theme` is a binding to the borrowed `Theme` and `self` is a binding
568 /// to the borrowed instance of this `Style` type.
569 ///
570 /// # Examples
571 ///
572 /// ```
573 /// # extern crate conrod_core;
574 /// # #[macro_use] extern crate conrod_derive;
575 /// # use conrod_core::{Color, FontSize, Scalar};
576 /// # fn main() {}
577 /// /// Unique styling for a Button widget.
578 /// #[derive(Copy, Clone, Debug, Default, PartialEq, WidgetStyle)]
579 /// pub struct Style {
580 /// /// Color of the Button's pressable area.
581 /// #[conrod(default = "theme.shape_color")]
582 /// pub color: Option<Color>,
583 /// /// Width of the border surrounding the button.
584 /// #[conrod(default = "1.0")]
585 /// pub border: Option<Scalar>,
586 /// /// The color of the Button's rectangular border.
587 /// #[conrod(default = "conrod_core::color::BLACK")]
588 /// pub border_color: Option<Color>,
589 /// /// The color of the Button's label.
590 /// #[conrod(default = "theme.label_color")]
591 /// pub label_color: Option<Color>,
592 /// /// The font size for the Button's label.
593 /// #[conrod(default = "12")]
594 /// pub label_font_size: Option<FontSize>,
595 /// }
596 /// ```
597 type Style: Style + Send;
598 /// The type of event yielded by the widget, returned via the `Widget::set` function.
599 ///
600 /// For a `Toggle` widget, this might be a `bool`.
601 ///
602 /// For a non-interactive, purely graphical widget, this might be `()`.
603 type Event;
604
605 /// Return the initial **State** of the Widget.
606 ///
607 /// The `Ui` will only call this once, immediately prior to the first time that
608 /// **Widget::update** is first called.
609 fn init_state(&self, id_gen: id::Generator) -> Self::State;
610
611 /// Return the styling of the widget.
612 ///
613 /// The `Ui` will call this once prior to each `update`. It does this so that it can check for
614 /// differences in `Style` in case we need to re-draw the widget.
615 fn style(&self) -> Self::Style;
616
617 /// Update our **Widget**'s unique **Widget::State** via the **State** wrapper type (the
618 /// `state` field within the [**UpdateArgs**](./struct.UpdateArgs)).
619 ///
620 /// Whenever [**State::update**](./struct.State.html#method.update) is called, a `has_updated`
621 /// flag is set within the **State**, indicating that there has been some change to the unique
622 /// **Widget::State** and that we require re-drawing the **Widget**. As a result, widget
623 /// designers should only call **State::update** when necessary, checking whether or not the
624 /// state has changed before invoking the method. See the custom_widget.rs example for a
625 /// demonstration of this.
626 ///
627 /// # Arguments
628 /// * id - The `Widget`'s unique index (whether `Public` or `Internal`).
629 /// * prev - The previous common state of the Widget. If this is the first time **update** is
630 /// called, `Widget::init_state` will be used to produce some initial state instead.
631 /// * state - A wrapper around the `Widget::State`. See the [**State** docs](./struct.State)
632 /// for more details.
633 /// * rect - The position (centered) and dimensions of the widget.
634 /// * style - The style produced by the `Widget::style` method.
635 /// * ui - A wrapper around the `Ui`, offering restricted access to its functionality. See the
636 /// docs for `UiCell` for more details.
637 fn update(self, args: UpdateArgs<Self>) -> Self::Event;
638
639 /// The default **Position** for the widget along the *x* axis.
640 ///
641 /// This is used when no **Position** is explicitly given when instantiating the Widget.
642 fn default_x_position(&self, ui: &Ui) -> Position {
643 ui.theme
644 .widget_style::<Self::Style>()
645 .and_then(|style| style.common.maybe_x_position)
646 .unwrap_or(ui.theme.x_position)
647 }
648
649 /// The default **Position** for the widget along the *y* axis.
650 ///
651 /// This is used when no **Position** is explicitly given when instantiating the Widget.
652 fn default_y_position(&self, ui: &Ui) -> Position {
653 ui.theme
654 .widget_style::<Self::Style>()
655 .and_then(|style| style.common.maybe_y_position)
656 .unwrap_or(ui.theme.y_position)
657 }
658
659 /// The default width for the **Widget**.
660 ///
661 /// This method is only used if no height is explicitly given.
662 ///
663 /// By default, this simply calls [**default_dimension**](./fn.default_dimension) with a
664 /// fallback absolute dimension of 0.0.
665 fn default_x_dimension(&self, ui: &Ui) -> Dimension {
666 default_x_dimension(self, ui)
667 }
668
669 /// The default height of the widget.
670 ///
671 /// By default, this simply calls [**default_dimension**](./fn.default_dimension) with a
672 /// fallback absolute dimension of 0.0.
673 fn default_y_dimension(&self, ui: &Ui) -> Dimension {
674 default_y_dimension(self, ui)
675 }
676
677 /// If the widget is draggable, implement this method and return the position and dimensions of
678 /// the draggable space. The position should be relative to the center of the widget.
679 fn drag_area(&self, _dim: Dimensions, _style: &Self::Style, _theme: &Theme) -> Option<Rect> {
680 None
681 }
682
683 /// The area on which child widgets will be placed when using the `Place` `Position` methods.
684 fn kid_area(&self, args: KidAreaArgs<Self>) -> KidArea {
685 KidArea {
686 rect: args.rect,
687 pad: Padding::none(),
688 }
689 }
690
691 /// Returns either of the following:
692 ///
693 /// - A `Function` that can be used to describe whether or not a given point is over the
694 /// widget.
695 /// - The `Id` of another `Widget` that can be used to determine if the point is over this
696 /// widget.
697 ///
698 /// By default, this is a function returns `true` if the given `Point` is over the bounding
699 /// `Rect` and returns `false` otherwise.
700 ///
701 /// *NOTE: It could be worth removing this in favour of adding a `widget::State` trait, adding
702 /// an `is_over` method to it and then refactoring the `Container` to store a
703 /// `Box<widget::State>` and `Box<widget::Style>` rather than `Box<Any>`. This would however
704 /// involve some significant breakage (which could perhaps be mitigated by adding a
705 /// `derive(WidgetState)` macro - a fair chunk of work) so this might be the easiest temporary
706 /// way forward for now.*
707 fn is_over(&self) -> IsOverFn {
708 is_over_rect
709 }
710
711 // None of the following methods should require overriding. Perhaps they should be split off
712 // into a separate trait which is impl'ed for W: Widget to make this clearer?
713 // Most of them would benefit by some sort of field inheritance as they are mainly just used to
714 // set common data.
715
716 /// Set the parent widget for this Widget by passing the WidgetId of the parent.
717 ///
718 /// This will attach this Widget to the parent widget.
719 fn parent(mut self, parent_id: Id) -> Self {
720 self.common_mut().maybe_parent_id = MaybeParent::Some(parent_id);
721 self
722 }
723
724 /// Specify that this widget has no parent widgets.
725 fn no_parent(mut self) -> Self {
726 self.common_mut().maybe_parent_id = MaybeParent::None;
727 self
728 }
729
730 /// Set whether or not the **Widget** should be placed on the kid_area.
731 ///
732 /// If `true`, the **Widget** will be placed on the `kid_area` of the parent **Widget** if the
733 /// **Widget** is given a **Place** variant for its **Position**.
734 ///
735 /// If `false`, the **Widget** will be placed on the parent **Widget**'s *total* area.
736 ///
737 /// By default, conrod will automatically determine this for you by checking whether or not the
738 /// **Widget** that our **Widget** is being placed upon returns `Some` from its
739 /// **Widget::kid_area** method.
740 fn place_on_kid_area(mut self, b: bool) -> Self {
741 self.common_mut().place_on_kid_area = b;
742 self
743 }
744
745 /// Indicates that the **Widget** is used as a non-interactive graphical element for some other
746 /// widget.
747 ///
748 /// This is useful for **Widget**s that are used to compose some other **Widget**.
749 ///
750 /// When adding an edge *a -> b* where *b* is considered to be a graphical element of *a*,
751 /// several things are implied about *b*:
752 ///
753 /// - If *b* is picked within either **Graph::pick_widget** or
754 /// **Graph::pick_top_scrollable_widget**, it will instead return the index for *a*.
755 /// - When determining the **Graph::scroll_offset** for *b*, *a*'s scrolling (if it is
756 /// scrollable, that is) will be skipped.
757 /// - *b* will always be placed upon *a*'s total area, rather than its kid_area which is the
758 /// default.
759 /// - Any **Graphic** child of *b* will be considered as a **Graphic** child of *a*.
760 fn graphics_for(mut self, id: Id) -> Self {
761 self.common_mut().maybe_graphics_for = Some(id);
762 self
763 }
764
765 /// Set whether or not the widget is floating (the default is `false`).
766 /// A typical example of a floating widget would be a pop-up or alert window.
767 ///
768 /// A "floating" widget will always be rendered *after* its parent tree and all widgets
769 /// connected to its parent tree. If two sibling widgets are both floating, then the one that
770 /// was last clicked will be rendered last. If neither are clicked, they will be rendered in
771 /// the order in which they were cached into the `Ui`.
772 fn floating(mut self, is_floating: bool) -> Self {
773 self.common_mut().is_floating = is_floating;
774 self
775 }
776
777 /// Indicates that all widgets who are children of this widget should be cropped to the
778 /// `kid_area` of this widget.
779 fn crop_kids(mut self) -> Self {
780 self.common_mut().crop_kids = true;
781 self
782 }
783
784 /// Makes the widget's `KidArea` scrollable.
785 ///
786 /// If a widget is scrollable and it has children widgets that fall outside of its `KidArea`,
787 /// the `KidArea` will become scrollable.
788 ///
789 /// This method calls `Widget::crop_kids` internally.
790 fn scroll_kids(self) -> Self {
791 self.scroll_kids_vertically()
792 .scroll_kids_horizontally()
793 .crop_kids()
794 }
795
796 /// Makes the widget's `KidArea` scrollable.
797 ///
798 /// If a widget is scrollable and it has children widgets that fall outside of its `KidArea`,
799 /// the `KidArea` will become scrollable.
800 ///
801 /// This method calls `Widget::crop_kids` internally.
802 fn scroll_kids_vertically(mut self) -> Self {
803 self.common_mut().maybe_y_scroll = Some(scroll::Scroll::new());
804 self.crop_kids()
805 }
806
807 /// Set whether or not the widget's `KidArea` is scrollable (the default is false).
808 ///
809 /// If a widget is scrollable and it has children widgets that fall outside of its `KidArea`,
810 /// the `KidArea` will become scrollable.
811 ///
812 /// This method calls `Widget::crop_kids` internally.
813 fn scroll_kids_horizontally(mut self) -> Self {
814 self.common_mut().maybe_x_scroll = Some(scroll::Scroll::new());
815 self.crop_kids()
816 }
817
818 /// A builder method that "lifts" the **Widget** through the given `build` function.
819 ///
820 /// This method is solely for providing slight ergonomic improvement by helping to maintain
821 /// the symmetry of the `builder` pattern in some cases.
822 #[inline]
823 fn and<F>(self, build: F) -> Self
824 where
825 F: FnOnce(Self) -> Self,
826 {
827 build(self)
828 }
829
830 /// A builder method that mutates the **Widget** with the given `mutate` function.
831 ///
832 /// This method is solely for providing slight ergonomic improvement by helping to maintain
833 /// the symmetry of the `builder` pattern in some cases.
834 #[inline]
835 fn and_mut<F>(mut self, mutate: F) -> Self
836 where
837 F: FnOnce(&mut Self),
838 {
839 mutate(&mut self);
840 self
841 }
842
843 /// A method that conditionally builds the **Widget** with the given `build` function.
844 ///
845 /// If `cond` is `true`, `build(self)` is evaluated and returned.
846 ///
847 /// If `false`, `self` is returned.
848 #[inline]
849 fn and_if<F>(self, cond: bool, build: F) -> Self
850 where
851 F: FnOnce(Self) -> Self,
852 {
853 if cond {
854 build(self)
855 } else {
856 self
857 }
858 }
859
860 /// A method that optionally builds the **Widget** with the given `build` function.
861 ///
862 /// If `maybe` is `Some(t)`, `build(self, t)` is evaluated and returned.
863 ///
864 /// If `None`, `self` is returned.
865 #[inline]
866 fn and_then<T, F>(self, maybe: Option<T>, build: F) -> Self
867 where
868 F: FnOnce(Self, T) -> Self,
869 {
870 if let Some(t) = maybe {
871 build(self, t)
872 } else {
873 self
874 }
875 }
876
877 /// Note: There should be no need to override this method.
878 ///
879 /// After building the widget, you call this method to set its current state into the given
880 /// `Ui`. More precisely, the following will occur when calling this method:
881 /// - The widget's previous state and style will be retrieved.
882 /// - The widget's current `Style` will be retrieved (from the `Widget::style` method).
883 /// - The widget's state will be updated (using the `Widget::udpate` method).
884 /// - If the widget's state or style has changed, the **Ui** will be notified that the widget
885 /// needs to be re-drawn.
886 /// - The new State and Style will be cached within the `Ui`.
887 fn set<'a, 'b>(self, id: Id, ui_cell: &'a mut UiCell<'b>) -> Self::Event {
888 set_widget(self, id, ui_cell)
889 }
890}
891
892/// Updates the given widget and caches it within the given `Ui`'s `widget_graph`.
893///
894/// If it is the first time a widget has been set, it will be cached into the `Ui`'s widget_graph.
895/// For all following occasions, the pre-existing cached state will be compared and updated.
896///
897/// Note that this is a very imperative, mutation oriented segment of code. We try to move as much
898/// imperativeness and mutation out of the users hands and into this function as possible, so that
899/// users have a clear, concise, purely functional `Widget` API. As a result, we try to keep this
900/// as verbosely annotated as possible. If anything is unclear, feel free to post an issue or PR
901/// with concerns/improvements to the github repo.
902fn set_widget<'a, 'b, W>(widget: W, id: Id, ui: &'a mut UiCell<'b>) -> W::Event
903where
904 W: Widget,
905{
906 let type_id = std::any::TypeId::of::<W::State>();
907
908 // Take the previous state of the widget from the cache if there is some to collect.
909 let (maybe_prev_unique_state, maybe_prev_common, maybe_prev_style) =
910 ui::widget_graph_mut(ui::ref_mut_from_ui_cell(ui))
911 .widget_mut(id)
912 .and_then(|container| {
913 // If the cache is already initialised for a different widget type, warn the user.
914 if container.type_id != type_id {
915 use std::io::Write;
916 writeln!(
917 std::io::stderr(),
918 "A widget of a different type already exists at the given WidgetId \
919 ({:?}). You tried to insert a {:?}, however the existing widget is a \
920 {:?}. Check your widgets' `WidgetId`s for errors.",
921 id,
922 type_id,
923 container.type_id
924 )
925 .unwrap();
926 return None;
927 }
928
929 // Destructure the cached state.
930 let Container {
931 ref mut maybe_state,
932 rect,
933 depth,
934 kid_area,
935 maybe_dragged_from,
936 maybe_floating,
937 maybe_x_scroll_state,
938 maybe_y_scroll_state,
939 ..
940 } = *container;
941
942 let (state, style) = match maybe_state.take().and_then(|a| a.downcast().ok()) {
943 Some(boxed) => {
944 let unique: UniqueWidgetState<W::State, W::Style> = *boxed;
945 let UniqueWidgetState { state, style } = unique;
946 (state, style)
947 }
948 None => return None,
949 };
950
951 // Use the cached state to construct the prev_state (to be fed to Widget::update).
952 let prev_common = CommonState {
953 rect: rect,
954 depth: depth,
955 maybe_dragged_from: maybe_dragged_from,
956 maybe_floating: maybe_floating,
957 kid_area: kid_area,
958 maybe_x_scroll_state: maybe_x_scroll_state,
959 maybe_y_scroll_state: maybe_y_scroll_state,
960 };
961
962 Some((Some(state), Some(prev_common), Some(style)))
963 })
964 .unwrap_or_else(|| (None, None, None));
965
966 // We need to hold onto the current "previously set widget", as this may change during our
967 // `Widget`'s update method (i.e. if it sets any of its own widgets, they will become the last
968 // previous widget).
969 let maybe_prev_widget_id = ui.maybe_prev_widget();
970
971 let new_style = widget.style();
972 let depth = widget.get_depth();
973 let dim = widget.get_wh(&ui).unwrap_or([0.0, 0.0]);
974 let x_pos = widget.get_x_position(ui);
975 let y_pos = widget.get_y_position(ui);
976 let place_on_kid_area = widget.common().place_on_kid_area;
977
978 // Determine the id of the canvas that the widget is attached to. If not given explicitly,
979 // check the positioning to retrieve the Id from there.
980 let maybe_parent_id = widget.common().maybe_parent_id.get(id, ui, x_pos, y_pos);
981
982 // Calculate the `xy` location of the widget, considering drag.
983 let (xy, maybe_dragged_from) = maybe_prev_common
984 .as_ref()
985 .and_then(|prev| {
986 if widget.common().maybe_graphics_for.is_some() {
987 return None;
988 }
989 let maybe_drag_area = widget.drag_area(dim, &new_style, &ui.theme);
990 maybe_drag_area.map(|drag_area| {
991 let mut current_dragged_from = prev.maybe_dragged_from;
992 let mut current_xy = prev.rect.xy();
993
994 for event in ui.widget_input(id).events() {
995 match event {
996 ::event::Widget::Drag(drag) => {
997 if drag.button == input::MouseButton::Left {
998 if current_dragged_from.is_none() && drag_area.is_over(drag.origin)
999 {
1000 current_dragged_from = Some(prev.rect.xy());
1001 }
1002
1003 if let Some(dragged_from) = current_dragged_from {
1004 current_xy = [
1005 dragged_from[0] + drag.to[0] - drag.origin[0],
1006 dragged_from[1] + drag.to[1] - drag.origin[1],
1007 ];
1008 }
1009 }
1010 }
1011 ::event::Widget::Release(::event::Release {
1012 button: ::event::Button::Mouse(input::MouseButton::Left, _),
1013 ..
1014 }) => {
1015 current_dragged_from = None;
1016 }
1017 _ => {}
1018 }
1019 }
1020 (current_xy, current_dragged_from)
1021 })
1022 })
1023 // If there is no previous state to compare for dragging, return an initial state.
1024 //
1025 // A function for generating the xy coords from the given alignment and Position.
1026 .unwrap_or_else(|| {
1027 (
1028 ui.calc_xy(
1029 Some(id),
1030 maybe_parent_id,
1031 x_pos,
1032 y_pos,
1033 dim,
1034 place_on_kid_area,
1035 ),
1036 None,
1037 )
1038 });
1039
1040 // Construct the rectangle describing our Widget's area.
1041 let rect = Rect::from_xy_dim(xy, dim);
1042
1043 // Check whether or not the widget is a "floating" (hovering / pop-up style) widget.
1044 let maybe_floating = if widget.common().is_floating {
1045 fn new_floating() -> Floating {
1046 Floating {
1047 time_last_clicked: instant::Instant::now(),
1048 }
1049 }
1050
1051 // If it is floating, check to see if we need to update the last time it was clicked.
1052 match maybe_prev_common.as_ref() {
1053 Some(prev) => {
1054 let maybe_mouse = ui.widget_input(id).mouse();
1055 match (prev.maybe_floating, maybe_mouse) {
1056 (Some(prev_floating), Some(mouse)) => {
1057 if mouse.buttons.left().is_down() {
1058 Some(new_floating())
1059 } else {
1060 Some(prev_floating)
1061 }
1062 }
1063 (Some(prev_floating), None) => Some(prev_floating),
1064 _ => Some(new_floating()),
1065 }
1066 }
1067 None => Some(new_floating()),
1068 }
1069 } else {
1070 None
1071 };
1072
1073 // Retrieve the area upon which kid widgets will be placed.
1074 let kid_area = {
1075 let args: KidAreaArgs<W> = KidAreaArgs {
1076 rect: rect,
1077 style: &new_style,
1078 theme: &ui.theme,
1079 fonts: &ui.fonts,
1080 };
1081 widget.kid_area(args)
1082 };
1083
1084 // If either axis is scrollable, retrieve the up-to-date `scroll::State` for that axis.
1085 //
1086 // We must step the scrolling using the previous `kid_area` state so that the bounding box
1087 // around our kid widgets is in sync with the position of the `kid_area`.
1088 let prev_kid_area = maybe_prev_common
1089 .map(|common| common.kid_area)
1090 .unwrap_or_else(|| kid_area);
1091
1092 // If the widget is scrollable, check for given `Scroll` events.
1093 //
1094 // TODO: On the first time the widget is set (i.e. if `maybe_prev_*_scroll_state` is `None` and
1095 // `maybe_*_scroll` is `Some`) we should consider and handle the `scroll_args`'
1096 // `maybe_initial_alignment` field.
1097 let mut maybe_x_scroll_state = widget.common().maybe_x_scroll.map(|_scroll_args| {
1098 let maybe_prev = maybe_prev_common
1099 .as_ref()
1100 .and_then(|p| p.maybe_x_scroll_state);
1101 scroll::State::update(ui, id, &prev_kid_area, maybe_prev, 0.0)
1102 });
1103 let mut maybe_y_scroll_state = widget.common().maybe_y_scroll.map(|_scroll_args| {
1104 let maybe_prev = maybe_prev_common
1105 .as_ref()
1106 .and_then(|p| p.maybe_y_scroll_state);
1107 scroll::State::update(ui, id, &prev_kid_area, maybe_prev, 0.0)
1108 });
1109
1110 for scroll in ui.widget_input(id).scrolls() {
1111 if widget.common().maybe_x_scroll.is_some() {
1112 maybe_x_scroll_state = Some(scroll::State::update(
1113 ui,
1114 id,
1115 &prev_kid_area,
1116 maybe_x_scroll_state,
1117 scroll.x,
1118 ))
1119 }
1120
1121 if widget.common().maybe_y_scroll.is_some() {
1122 maybe_y_scroll_state = Some(scroll::State::update(
1123 ui,
1124 id,
1125 &prev_kid_area,
1126 maybe_y_scroll_state,
1127 scroll.y,
1128 ))
1129 }
1130 }
1131
1132 // Determine whether or not this is the first time set has been called.
1133 // We'll use this to determine whether or not we need to draw for the first time.
1134 let is_first_set = maybe_prev_common.is_none();
1135
1136 // Update all positioning and dimension related data prior to calling `Widget::update`.
1137 // We do this so that if this widget were to internally `set` some other `Widget`s, this
1138 // `Widget`s positioning and dimension data already exists within the `Graph`.
1139 {
1140 // Some widget to which this widget is relatively positioned (if there is one).
1141 let maybe_positioned_relatively_id = |pos: Position| match pos {
1142 Position::Relative(_, maybe_id) => maybe_id.or(maybe_prev_widget_id),
1143 Position::Absolute(_) => None,
1144 };
1145
1146 let maybe_x_positioned_relatively_id = maybe_positioned_relatively_id(x_pos);
1147 let maybe_y_positioned_relatively_id = maybe_positioned_relatively_id(y_pos);
1148
1149 // Retrieve whether or not the widget's children should be cropped to it.
1150 let crop_kids = widget.common().crop_kids;
1151
1152 // This will cache the given data into the `ui`'s `widget_graph`.
1153 let ui: &mut Ui = ui::ref_mut_from_ui_cell(ui);
1154 ui::pre_update_cache(
1155 ui,
1156 PreUpdateCache {
1157 type_id: type_id,
1158 id: id,
1159 maybe_parent_id: maybe_parent_id,
1160 maybe_x_positioned_relatively_id: maybe_x_positioned_relatively_id,
1161 maybe_y_positioned_relatively_id: maybe_y_positioned_relatively_id,
1162 rect: rect,
1163 depth: depth,
1164 kid_area: kid_area,
1165 maybe_dragged_from: maybe_dragged_from,
1166 maybe_floating: maybe_floating,
1167 crop_kids: crop_kids,
1168 maybe_y_scroll_state: maybe_y_scroll_state,
1169 maybe_x_scroll_state: maybe_x_scroll_state,
1170 maybe_graphics_for: widget.common().maybe_graphics_for,
1171 is_over: widget.is_over(),
1172 },
1173 );
1174 }
1175
1176 // Unwrap the widget's previous common state. If there is no previous common state, we'll
1177 // use the new state in it's place.
1178 let prev_common = maybe_prev_common.unwrap_or_else(|| CommonState {
1179 rect: rect,
1180 depth: depth,
1181 maybe_dragged_from: maybe_dragged_from,
1182 maybe_floating: maybe_floating,
1183 kid_area: kid_area,
1184 maybe_x_scroll_state: maybe_x_scroll_state,
1185 maybe_y_scroll_state: maybe_y_scroll_state,
1186 });
1187
1188 // Retrieve the widget's unique state and update it via `Widget::update`.
1189 let (unique_state, has_state_updated, event) = {
1190 // Unwrap our unique widget state. If there is no previous state to unwrap, call the
1191 // `init_state` method to construct some initial state.
1192 let mut unique_state =
1193 maybe_prev_unique_state.unwrap_or_else(|| widget.init_state(ui.widget_id_generator()));
1194 let (has_updated, event) = {
1195 // A wrapper around the widget's unique state in order to keep track of whether or not it
1196 // has been updated during the `Widget::update` method.
1197 let mut state = State {
1198 state: &mut unique_state,
1199 has_updated: false,
1200 };
1201
1202 let event = widget.update(UpdateArgs {
1203 id: id,
1204 maybe_parent_id: maybe_parent_id,
1205 state: &mut state,
1206 prev: &prev_common,
1207 rect: rect,
1208 style: &new_style,
1209 ui: ui,
1210 });
1211
1212 (state.has_updated, event)
1213 };
1214
1215 (unique_state, has_updated, event)
1216 };
1217
1218 // Determine whether or not the `State` has changed.
1219 let state_has_changed =
1220 has_state_updated || rect != prev_common.rect || depth != prev_common.depth || is_first_set;
1221
1222 // Determine whether or not the widget's `Style` has changed.
1223 let style_has_changed = maybe_prev_style
1224 .map(|style| style != new_style)
1225 .unwrap_or(false);
1226
1227 // We need to know if the scroll state has changed to see if we need to redraw.
1228 let scroll_has_changed = maybe_x_scroll_state
1229 != maybe_prev_common
1230 .as_ref()
1231 .and_then(|p| p.maybe_x_scroll_state)
1232 || maybe_y_scroll_state
1233 != maybe_prev_common
1234 .as_ref()
1235 .and_then(|p| p.maybe_y_scroll_state);
1236
1237 // We only need to redraw if some visible part of our widget has changed.
1238 let requires_redraw = style_has_changed || state_has_changed || scroll_has_changed;
1239
1240 let ui: &mut Ui = ui::ref_mut_from_ui_cell(ui);
1241
1242 // If we require a redraw, we should notify the `Ui`.
1243 if requires_redraw {
1244 ui.needs_redraw();
1245 }
1246
1247 // Finally, cache the `Widget`'s newly updated `State` and `Style` within the `ui`'s
1248 // `widget_graph`.
1249 ui::post_update_cache::<W>(
1250 ui,
1251 PostUpdateCache {
1252 id: id,
1253 maybe_parent_id: maybe_parent_id,
1254 state: unique_state,
1255 style: new_style,
1256 },
1257 );
1258
1259 event
1260}
1261
1262impl<'a, T> State<'a, T> {
1263 /// Mutate the internal widget state and set a flag notifying us that there has been a mutation.
1264 ///
1265 /// If this method is *not* called, we assume that there has been no mutation and in turn we do
1266 /// not need to re-draw the Widget.
1267 ///
1268 /// If this method *is* called, we assume that there has been some mutation and in turn will
1269 /// need to re-draw the Widget. Thus, it is recommended that you *only* call this method if you
1270 /// need to update the unique state in some way.
1271 pub fn update<F>(&mut self, f: F)
1272 where
1273 F: FnOnce(&mut T),
1274 {
1275 self.has_updated = true;
1276 f(self.state);
1277 }
1278}
1279
1280impl<'a, T> std::ops::Deref for State<'a, T> {
1281 type Target = T;
1282 fn deref(&self) -> &T {
1283 &self.state
1284 }
1285}
1286
1287impl Default for CommonBuilder {
1288 fn default() -> Self {
1289 CommonBuilder {
1290 style: CommonStyle::default(),
1291 maybe_parent_id: MaybeParent::Unspecified,
1292 place_on_kid_area: true,
1293 maybe_graphics_for: None,
1294 is_floating: false,
1295 maybe_x_scroll: None,
1296 maybe_y_scroll: None,
1297 crop_kids: false,
1298 }
1299 }
1300}
1301
1302impl<W> Positionable for W
1303where
1304 W: Widget,
1305{
1306 fn x_position(mut self, x: Position) -> Self {
1307 self.common_mut().style.maybe_x_position = Some(x);
1308 self
1309 }
1310 fn y_position(mut self, y: Position) -> Self {
1311 self.common_mut().style.maybe_y_position = Some(y);
1312 self
1313 }
1314 fn get_x_position(&self, ui: &Ui) -> Position {
1315 let from_y_position = || {
1316 self.common()
1317 .style
1318 .maybe_y_position
1319 .and_then(|y_pos| infer_position_from_other_position(y_pos, Align::Start))
1320 };
1321 self.common()
1322 .style
1323 .maybe_x_position
1324 .or_else(from_y_position)
1325 .unwrap_or(self.default_x_position(ui))
1326 }
1327 fn get_y_position(&self, ui: &Ui) -> Position {
1328 let from_x_position = || {
1329 self.common()
1330 .style
1331 .maybe_x_position
1332 .and_then(|x_pos| infer_position_from_other_position(x_pos, Align::End))
1333 };
1334 self.common()
1335 .style
1336 .maybe_y_position
1337 .or_else(from_x_position)
1338 .unwrap_or(self.default_y_position(ui))
1339 }
1340 fn depth(mut self, depth: Depth) -> Self {
1341 self.common_mut().style.maybe_depth = Some(depth);
1342 self
1343 }
1344 fn get_depth(&self) -> Depth {
1345 const DEFAULT_DEPTH: Depth = 0.0;
1346 self.common().style.maybe_depth.unwrap_or(DEFAULT_DEPTH)
1347 }
1348}
1349
1350/// In the case that a position hasn't been given for one of the axes, we must first check to see
1351/// if we can infer the missing axis position from the other axis.
1352///
1353/// This is used within the impl of **Positionable** for **Widget**.
1354fn infer_position_from_other_position(other_pos: Position, dir_align: Align) -> Option<Position> {
1355 match other_pos {
1356 Position::Relative(Relative::Direction(_, _), maybe_id) => {
1357 Some(Position::Relative(Relative::Align(dir_align), maybe_id))
1358 }
1359 Position::Relative(Relative::Place(_), maybe_id) => {
1360 Some(Position::Relative(Relative::Align(Align::Middle), maybe_id))
1361 }
1362 Position::Relative(Relative::Scalar(_), maybe_id) => {
1363 Some(Position::Relative(Relative::Scalar(0.0), maybe_id))
1364 }
1365 Position::Relative(Relative::Align(_), _) | Position::Absolute(_) => None,
1366 }
1367}
1368
1369impl<W> Sizeable for W
1370where
1371 W: Widget,
1372{
1373 fn x_dimension(mut self, w: Dimension) -> Self {
1374 self.common_mut().style.maybe_x_dimension = Some(w);
1375 self
1376 }
1377 fn y_dimension(mut self, h: Dimension) -> Self {
1378 self.common_mut().style.maybe_y_dimension = Some(h);
1379 self
1380 }
1381 /// We attempt to retrieve the `x` **Dimension** for the widget via the following:
1382 /// - Check for specified value at `maybe_x_dimension`
1383 /// - Otherwise, use the default returned by **Widget::default_x_dimension**.
1384 fn get_x_dimension(&self, ui: &Ui) -> Dimension {
1385 self.common()
1386 .style
1387 .maybe_x_dimension
1388 .unwrap_or_else(|| self.default_x_dimension(ui))
1389 }
1390 /// We attempt to retrieve the `y` **Dimension** for the widget via the following:
1391 /// - Check for specified value at `maybe_y_dimension`
1392 /// - Otherwise, use the default returned by **Widget::default_y_dimension**.
1393 fn get_y_dimension(&self, ui: &Ui) -> Dimension {
1394 self.common()
1395 .style
1396 .maybe_y_dimension
1397 .unwrap_or_else(|| self.default_y_dimension(ui))
1398 }
1399}