diff --git a/Cargo.toml b/Cargo.toml index 93241c4dc..2304de19d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "conrod" -version = "0.27.0" +version = "0.28.0" authors = [ "Mitchell Nordine ", "Sven Nilsen " diff --git a/examples/custom_widget.rs b/examples/custom_widget.rs index 22626f6e0..8307c4a88 100644 --- a/examples/custom_widget.rs +++ b/examples/custom_widget.rs @@ -24,14 +24,11 @@ extern crate vecmath; /// The module in which we'll implement our own custom circular button. mod circular_button { use conrod::{ - default_x_dimension, - default_y_dimension, CharacterCache, Circle, Color, Colorable, CommonBuilder, - Dimension, Dimensions, FontSize, IndexSlot, @@ -45,7 +42,6 @@ mod circular_button { UpdateArgs, Widget, WidgetKind, - Ui, }; @@ -229,34 +225,6 @@ mod circular_button { self.style.clone() } - /// Default width of the widget. - /// - /// This method is optional. - /// - /// The default implementation is the same as below, but unwraps to an absolute scalar of - /// `0.0` instead of `64.0`. - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - // If no width was given via the `Sizeable` (a trait implemented for all widgets) - // methods, some default width must be chosen. - // - // Defaults can come from several places. Here, we define how certain defaults take - // precedence over others. - // - // Most commonly, defaults are to be retrieved from the `Theme`, however in some cases - // some other logic may need to be considered. - default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(64.0)) - } - - /// Default height of the widget. - /// - /// This method is optional. - /// - /// The default implementation is the same as below, but unwraps to an absolute scalar of - /// `0.0` instead of `64.0`. - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(64.0)) - } - /// Update the state of the button. The state may or may not have changed since /// the last update. (E.g. it may have changed because the user moused over the /// button.) If the state has changed, return the new state. Else, return None. diff --git a/src/position/matrix.rs b/src/position/matrix.rs index 66208af07..17bb6ee27 100644 --- a/src/position/matrix.rs +++ b/src/position/matrix.rs @@ -60,9 +60,8 @@ impl Matrix { // If we can infer some new current parent from the position, set that as the current // parent within the given `Ui`. - if let Some(idx) = ui::parent_from_position(ui, x_pos, y_pos) { - ui::set_current_parent_idx(ui, idx); - } + let parent_idx = ui::infer_parent_unchecked(ui, x_pos, y_pos); + ui::set_current_parent_idx(ui, parent_idx); let xy = ui.calc_xy(None, x_pos, y_pos, dim, true); let (half_w, half_h) = (dim[0] / 2.0, dim[1] / 2.0); diff --git a/src/ui.rs b/src/ui.rs index f1fecf60b..d3ddf9687 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -602,12 +602,14 @@ pub fn widget_graph_mut(ui: &mut Ui) -> &mut Graph { } -/// Check the given position for an attached parent widget. -pub fn parent_from_position(ui: &Ui, x_pos: Position, y_pos: Position) +/// Infer a widget's `Depth` parent by examining it's *x* and *y* `Position`s. +/// +/// When a different parent may be inferred from either `Position`, the *x* `Position` is favoured. +pub fn infer_parent_from_position(ui: &Ui, x_pos: Position, y_pos: Position) -> Option { use Position::{Place, Relative, Direction, Align}; - let maybe_parent = match (x_pos, y_pos) { + match (x_pos, y_pos) { (Place(_, maybe_parent_idx), _) | (_, Place(_, maybe_parent_idx)) => maybe_parent_idx, (Direction(_, _, maybe_idx), _) | (_, Direction(_, _, maybe_idx)) | @@ -616,8 +618,23 @@ pub fn parent_from_position(ui: &Ui, x_pos: Position, y_pos: Position) maybe_idx.or(ui.maybe_prev_widget_idx) .and_then(|idx| ui.widget_graph.depth_parent(idx)), _ => None, - }; - maybe_parent.or(ui.maybe_current_parent_idx) + } +} + + +/// Attempts to infer the parent of a widget from its *x*/*y* `Position`s and the current state of +/// the `Ui`. +/// +/// If no parent can be inferred via the `Position`s, the `maybe_current_parent_idx` will be used. +/// +/// If `maybe_current_parent_idx` is `None`, the `Ui`'s `window` widget will be used. +/// +/// **Note:** This function does not check whether or not using the `window` widget would cause a +/// cycle. +pub fn infer_parent_unchecked(ui: &Ui, x_pos: Position, y_pos: Position) -> widget::Index { + infer_parent_from_position(ui, x_pos, y_pos) + .or(ui.maybe_prev_widget_idx) + .unwrap_or(ui.window.into()) } diff --git a/src/widget/button.rs b/src/widget/button.rs index b0327908b..e5e8a32ec 100644 --- a/src/widget/button.rs +++ b/src/widget/button.rs @@ -3,7 +3,6 @@ use { CharacterCache, Color, Colorable, - Dimension, FontSize, Frameable, FramedRectangle, @@ -13,7 +12,6 @@ use { Positionable, Text, Theme, - Ui, Widget, }; use widget; @@ -148,14 +146,6 @@ impl<'a, F> Widget for Button<'a, F> self.style.clone() } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(64.0)) - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(64.0)) - } - /// Update the state of the Button. fn update(self, args: widget::UpdateArgs) { let widget::UpdateArgs { idx, state, style, rect, mut ui, .. } = args; diff --git a/src/widget/canvas.rs b/src/widget/canvas.rs index 04e55bd26..ad8d3bf97 100644 --- a/src/widget/canvas.rs +++ b/src/widget/canvas.rs @@ -2,7 +2,6 @@ use { CharacterCache, Color, Colorable, - Dimension, Dimensions, FontSize, Frameable, @@ -266,18 +265,6 @@ impl<'a> Widget for Canvas<'a> { Position::Place(Place::Middle, None) } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui) - .or_else(|| ui.w_of(ui.window).map(|w| Dimension::Absolute(w))) - .expect("`Ui.window` should always have some width") - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui) - .or_else(|| ui.h_of(ui.window).map(|h| Dimension::Absolute(h))) - .expect("`Ui.window` should always have some height") - } - /// The title bar area at which the Canvas can be clicked and dragged. /// /// Note: the position of the returned **Rect** should be relative to the center of the widget. diff --git a/src/widget/drop_down_list.rs b/src/widget/drop_down_list.rs index 949fa1483..b3c4a3341 100644 --- a/src/widget/drop_down_list.rs +++ b/src/widget/drop_down_list.rs @@ -5,7 +5,6 @@ use ::{ CharacterCache, Color, Colorable, - Dimension, FontSize, Frameable, IndexSlot, @@ -17,7 +16,6 @@ use ::{ Scalar, Sizeable, Theme, - Ui, }; use widget::{self, Widget}; @@ -158,14 +156,6 @@ impl<'a, F> Widget for DropDownList<'a, F> where self.style.clone() } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(128.0)) - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(32.0)) - } - /// Update the state of the DropDownList. fn update(mut self, args: widget::UpdateArgs) { let widget::UpdateArgs { idx, state, rect, style, mut ui, .. } = args; diff --git a/src/widget/envelope_editor.rs b/src/widget/envelope_editor.rs index be745da0a..054f364ae 100644 --- a/src/widget/envelope_editor.rs +++ b/src/widget/envelope_editor.rs @@ -4,7 +4,6 @@ use { Circle, Color, Colorable, - Dimension, Direction, Edge, Frameable, @@ -21,7 +20,6 @@ use { Sizeable, Text, Theme, - Ui, Widget, }; use num::Float; @@ -317,14 +315,6 @@ impl<'a, E, F> Widget for EnvelopeEditor<'a, E, F> self.style.clone() } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(256.0)) - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(128.0)) - } - /// Update the state of the EnvelopeEditor's cached state. fn update(self, args: widget::UpdateArgs) { use self::Interaction::{Clicked, Highlighted, Normal}; diff --git a/src/widget/matrix.rs b/src/widget/matrix.rs index 6850f0c9f..784d4bb7c 100644 --- a/src/widget/matrix.rs +++ b/src/widget/matrix.rs @@ -1,6 +1,6 @@ -use ::{CharacterCache, Dimension, NodeIndex, Scalar, Theme, Ui}; -use widget::{self, Widget}; +use {CharacterCache, NodeIndex, Scalar, Theme, Widget}; +use widget; /// Reaction params. @@ -105,14 +105,6 @@ impl<'a, F, W> Widget for Matrix where self.style.clone() } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(128.0)) - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(64.0)) - } - /// Update the state of the Matrix. fn update(self, args: widget::UpdateArgs) { let widget::UpdateArgs { idx, state, rect, style, mut ui, .. } = args; diff --git a/src/widget/mod.rs b/src/widget/mod.rs index bd425b639..4a13ca653 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -133,12 +133,30 @@ pub enum MaybeParent { impl MaybeParent { /// Convert the **MaybeParent** into an **Option**. /// - /// If not given explicitly, check the positioning to retrieve the **Index** from there. - pub fn get(&self, ui: &Ui, x_pos: Position, y_pos: Position) -> Option { + /// If `Unspecified`, check the positioning to retrieve the **Index** from there. + /// + /// If `None`, the `Ui`'s `window` widget will be used. + /// + /// **Note:** This method does not check whether or not using the `window` widget as the parent + /// would cause a cycle. If it is important that the inferred parent should not cause a cycle, + /// use `get` instead. + pub fn get_unchecked(&self, ui: &Ui, x_pos: Position, y_pos: Position) -> Index { match *self { - MaybeParent::Some(idx) => Some(idx), - MaybeParent::None => None, - MaybeParent::Unspecified => ui::parent_from_position(ui, x_pos, y_pos), + MaybeParent::Some(idx) => idx, + MaybeParent::None => ui.window.into(), + MaybeParent::Unspecified => ui::infer_parent_unchecked(ui, x_pos, y_pos), + } + } + + /// The same as `get_unchecked`, but checks whether or not the widget that we're inferring the + /// parent for is the `Ui`'s window (which cannot have a parent, without creating a cycle). + pub fn get(&self, idx: Index, ui: &Ui, x_pos: Position, y_pos: Position) + -> Option + { + if idx == ui.window.into() { + None + } else { + Some(self.get_unchecked(ui, x_pos, y_pos)) } } } @@ -342,9 +360,8 @@ impl Style for T where T: Any + Debug + PartialEq + Sized {} /// 1. Check for a default value within the **Ui**'s **Theme**. /// 2. Otherwise attempts to copy the dimension of the previously set widget if there is one. /// 3. Otherwise attempts to copy the dimension of our parent widget. -/// -/// Returns **None** if no default can be found. -fn default_dimension(widget: &W, ui: &Ui, f: F) -> Option +/// 4. If no parent widget can be inferred, the window dimensions are used. +fn default_dimension(widget: &W, ui: &Ui, f: F) -> Dimension where W: Widget, C: CharacterCache, F: FnOnce(theme::UniqueDefault) -> Option, @@ -352,11 +369,11 @@ fn default_dimension(widget: &W, ui: &Ui, f: F) -> Option ui.theme.widget_style::(widget.unique_kind()) .and_then(f) .or_else(|| ui.maybe_prev_widget().map(|idx| Dimension::Of(idx, None))) - .or_else(|| { + .unwrap_or_else(|| { let x_pos = widget.get_x_position(ui); let y_pos = widget.get_y_position(ui); - widget.common().maybe_parent_idx.get(ui, x_pos, y_pos) - .map(|idx| Dimension::Of(idx, None)) + let parent_idx = widget.common().maybe_parent_idx.get_unchecked(ui, x_pos, y_pos); + Dimension::Of(parent_idx, None) }) } @@ -366,14 +383,13 @@ fn default_dimension(widget: &W, ui: &Ui, f: F) -> Option /// 1. Check for a default value within the **Ui**'s **Theme**. /// 2. Otherwise attempts to copy the dimension of the previously set widget if there is one. /// 3. Otherwise attempts to copy the dimension of our parent widget. +/// 4. If no parent widget can be inferred, the window dimensions are used. /// /// This is called by the default implementations of **Widget::default_x_dimension**. /// /// If you wish to override **Widget::default_x_dimension**, feel free to call this function /// internally if you partly require the bahaviour of the default implementations. -/// -/// Returns **None** if no default can be found. -pub fn default_x_dimension(widget: &W, ui: &Ui) -> Option +pub fn default_x_dimension(widget: &W, ui: &Ui) -> Dimension where W: Widget, C: CharacterCache, { @@ -386,14 +402,13 @@ pub fn default_x_dimension(widget: &W, ui: &Ui) -> Option /// 1. Check for a default value within the **Ui**'s **Theme**. /// 2. Otherwise attempts to copy the dimension of the previously set widget if there is one. /// 3. Otherwise attempts to copy the dimension of our parent widget. +/// 4. If no parent widget can be inferred, the window dimensions are used. /// /// This is called by the default implementations of **Widget::default_y_dimension**. /// /// If you wish to override **Widget::default_y_dimension**, feel free to call this function /// internally if you partly require the bahaviour of the default implementations. -/// -/// Returns **None** if no default can be found. -pub fn default_y_dimension(widget: &W, ui: &Ui) -> Option +pub fn default_y_dimension(widget: &W, ui: &Ui) -> Dimension where W: Widget, C: CharacterCache, { @@ -531,7 +546,7 @@ pub trait Widget: Sized { /// By default, this simply calls [**default_dimension**](./fn.default_dimension) with a /// fallback absolute dimension of 0.0. fn default_x_dimension(&self, ui: &Ui) -> Dimension { - default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(0.0)) + default_x_dimension(self, ui) } /// The default height of the widget. @@ -539,7 +554,7 @@ pub trait Widget: Sized { /// By default, this simply calls [**default_dimension**](./fn.default_dimension) with a /// fallback absolute dimension of 0.0. fn default_y_dimension(&self, ui: &Ui) -> Dimension { - default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(0.0)) + default_y_dimension(self, ui) } /// If the widget is draggable, implement this method and return the position an dimensions @@ -750,6 +765,10 @@ fn set_widget<'a, C, W>(widget: W, idx: Index, ui: &mut Ui) where let y_pos = widget.get_y_position(ui); let place_on_kid_area = widget.common().place_on_kid_area; + // Determine the id of the canvas that the widget is attached to. If not given explicitly, + // check the positioning to retrieve the Id from there. + let maybe_parent_idx = widget.common().maybe_parent_idx.get(idx, ui, x_pos, y_pos); + let (xy, drag_state) = { // A function for generating the xy coords from the given alignment and Position. let calc_xy = || ui.calc_xy(Some(idx), x_pos, y_pos, dim, place_on_kid_area); @@ -802,10 +821,6 @@ fn set_widget<'a, C, W>(widget: W, idx: Index, ui: &mut Ui) where _ => (), } - // Determine the id of the canvas that the widget is attached to. If not given explicitly, - // check the positioning to retrieve the Id from there. - let maybe_parent_idx = widget.common().maybe_parent_idx.get(ui, x_pos, y_pos); - // Check whether or not the widget is a "floating" (hovering / pop-up style) widget. let maybe_floating = if widget.common().is_floating { diff --git a/src/widget/number_dialer.rs b/src/widget/number_dialer.rs index 3c11d7cb5..bd4d9192c 100644 --- a/src/widget/number_dialer.rs +++ b/src/widget/number_dialer.rs @@ -3,7 +3,6 @@ use { CharacterCache, Color, Colorable, - Dimension, Dimensions, FontSize, Frameable, @@ -18,7 +17,6 @@ use { Sizeable, Text, Theme, - Ui, Widget, }; use num::{Float, NumCast}; @@ -279,14 +277,6 @@ impl<'a, T, F> Widget for NumberDialer<'a, T, F> where self.style.clone() } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(128.0)) - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(48.0)) - } - /// Update the state of the NumberDialer. fn update(self, args: widget::UpdateArgs) { use self::Interaction::{Clicked, Highlighted, Normal}; diff --git a/src/widget/slider.rs b/src/widget/slider.rs index 82d8c4c01..f576657d5 100644 --- a/src/widget/slider.rs +++ b/src/widget/slider.rs @@ -3,7 +3,6 @@ use { CharacterCache, Color, Colorable, - Dimension, FontSize, Frameable, Labelable, @@ -18,7 +17,6 @@ use { Scalar, Text, Theme, - Ui, Widget, }; use num::{Float, NumCast, ToPrimitive}; @@ -189,14 +187,6 @@ impl<'a, T, F> Widget for Slider<'a, T, F> where self.style.clone() } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(192.0)) - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(48.0)) - } - fn kid_area(&self, args: widget::KidAreaArgs) -> KidArea { const LABEL_PADDING: Scalar = 10.0; KidArea { diff --git a/src/widget/text_box.rs b/src/widget/text_box.rs index 90080758a..2cac7d6d4 100644 --- a/src/widget/text_box.rs +++ b/src/widget/text_box.rs @@ -2,7 +2,6 @@ use { CharacterCache, Color, Colorable, - Dimension, Dimensions, FontSize, Frameable, @@ -20,7 +19,6 @@ use { Text, Theme, Widget, - Ui, }; use input::keyboard::Key::{Backspace, Left, Right, Return, A, E, LCtrl, RCtrl}; use vecmath::vec2_sub; @@ -373,14 +371,6 @@ impl<'a, F> Widget for TextBox<'a, F> where F: FnMut(&mut String) { self.style.clone() } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(192.0)) - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(48.0)) - } - fn kid_area(&self, args: widget::KidAreaArgs) -> widget::KidArea { KidArea { rect: args.rect, diff --git a/src/widget/toggle.rs b/src/widget/toggle.rs index 14b8b3924..c096d86bc 100644 --- a/src/widget/toggle.rs +++ b/src/widget/toggle.rs @@ -3,7 +3,6 @@ use { CharacterCache, Color, Colorable, - Dimension, FontSize, Frameable, FramedRectangle, @@ -14,7 +13,6 @@ use { Scalar, Text, Theme, - Ui, Widget, }; use widget; @@ -159,14 +157,6 @@ impl<'a, F> Widget for Toggle<'a, F> self.style.clone() } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(64.0)) - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(64.0)) - } - /// Update the state of the Toggle. fn update(self, args: widget::UpdateArgs) { let widget::UpdateArgs { idx, state, style, rect, mut ui, .. } = args; diff --git a/src/widget/xy_pad.rs b/src/widget/xy_pad.rs index e58202119..6b49fccdf 100644 --- a/src/widget/xy_pad.rs +++ b/src/widget/xy_pad.rs @@ -3,7 +3,6 @@ use { CharacterCache, Color, Colorable, - Dimension, Frameable, FramedRectangle, FontSize, @@ -16,7 +15,6 @@ use { Sizeable, Text, Theme, - Ui, Widget, }; use num::Float; @@ -191,14 +189,6 @@ impl<'a, X, Y, F> Widget for XYPad<'a, X, Y, F> self.style.clone() } - fn default_x_dimension(&self, ui: &Ui) -> Dimension { - widget::default_x_dimension(self, ui).unwrap_or(Dimension::Absolute(128.0)) - } - - fn default_y_dimension(&self, ui: &Ui) -> Dimension { - widget::default_y_dimension(self, ui).unwrap_or(Dimension::Absolute(128.0)) - } - /// Update the XYPad's cached state. fn update(self, args: widget::UpdateArgs) { use position::{Direction, Edge};