diff options
Diffstat (limited to '')
| -rw-r--r-- | core/src/element.rs | 21 | ||||
| -rw-r--r-- | core/src/layout/flex.rs | 53 | ||||
| -rw-r--r-- | core/src/overlay.rs | 8 | ||||
| -rw-r--r-- | core/src/overlay/element.rs | 17 | ||||
| -rw-r--r-- | core/src/overlay/group.rs | 29 | ||||
| -rw-r--r-- | core/src/shell.rs | 47 | ||||
| -rw-r--r-- | core/src/widget.rs | 8 | 
7 files changed, 126 insertions, 57 deletions
| diff --git a/core/src/element.rs b/core/src/element.rs index 6ebb8a15..03e56b43 100644 --- a/core/src/element.rs +++ b/core/src/element.rs @@ -1,4 +1,3 @@ -use crate::event::{self, Event};  use crate::layout;  use crate::mouse;  use crate::overlay; @@ -6,8 +5,8 @@ use crate::renderer;  use crate::widget;  use crate::widget::tree::{self, Tree};  use crate::{ -    Border, Clipboard, Color, Layout, Length, Rectangle, Shell, Size, Vector, -    Widget, +    Border, Clipboard, Color, Event, Layout, Length, Rectangle, Shell, Size, +    Vector, Widget,  };  use std::borrow::Borrow; @@ -309,7 +308,7 @@ where          self.widget.operate(tree, layout, renderer, operation);      } -    fn on_event( +    fn update(          &mut self,          tree: &mut Tree,          event: Event, @@ -319,11 +318,11 @@ where          clipboard: &mut dyn Clipboard,          shell: &mut Shell<'_, B>,          viewport: &Rectangle, -    ) -> event::Status { +    ) {          let mut local_messages = Vec::new();          let mut local_shell = Shell::new(&mut local_messages); -        let status = self.widget.on_event( +        self.widget.update(              tree,              event,              layout, @@ -335,8 +334,6 @@ where          );          shell.merge(local_shell, &self.mapper); - -        status      }      fn draw( @@ -447,7 +444,7 @@ where              .operate(state, layout, renderer, operation);      } -    fn on_event( +    fn update(          &mut self,          state: &mut Tree,          event: Event, @@ -457,10 +454,10 @@ where          clipboard: &mut dyn Clipboard,          shell: &mut Shell<'_, Message>,          viewport: &Rectangle, -    ) -> event::Status { -        self.element.widget.on_event( +    ) { +        self.element.widget.update(              state, event, layout, cursor, renderer, clipboard, shell, viewport, -        ) +        );      }      fn draw( diff --git a/core/src/layout/flex.rs b/core/src/layout/flex.rs index ac80d393..2cff5bfd 100644 --- a/core/src/layout/flex.rs +++ b/core/src/layout/flex.rs @@ -79,6 +79,7 @@ where      let max_cross = axis.cross(limits.max());      let mut fill_main_sum = 0; +    let mut some_fill_cross = false;      let (mut cross, cross_compress) = match axis {          Axis::Vertical if width == Length::Shrink => (0.0, true),          Axis::Horizontal if height == Length::Shrink => (0.0, true), @@ -90,6 +91,10 @@ where      let mut nodes: Vec<Node> = Vec::with_capacity(items.len());      nodes.resize(items.len(), Node::default()); +    // FIRST PASS +    // We lay out non-fluid elements in the main axis. +    // If we need to compress the cross axis, then we skip any of these elements +    // that are also fluid in the cross axis.      for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() {          let (fill_main_factor, fill_cross_factor) = {              let size = child.as_widget().size(); @@ -121,6 +126,41 @@ where              nodes[i] = layout;          } else {              fill_main_sum += fill_main_factor; +            some_fill_cross = some_fill_cross || fill_cross_factor != 0; +        } +    } + +    // SECOND PASS (conditional) +    // If we must compress the cross axis and there are fluid elements in the +    // cross axis, we lay out any of these elements that are also non-fluid in +    // the main axis (i.e. the ones we deliberately skipped in the first pass). +    // +    // We use the maximum cross length obtained in the first pass as the maximum +    // cross limit. +    if cross_compress && some_fill_cross { +        for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() +        { +            let (fill_main_factor, fill_cross_factor) = { +                let size = child.as_widget().size(); + +                axis.pack(size.width.fill_factor(), size.height.fill_factor()) +            }; + +            if fill_main_factor == 0 && fill_cross_factor != 0 { +                let (max_width, max_height) = axis.pack(available, cross); + +                let child_limits = +                    Limits::new(Size::ZERO, Size::new(max_width, max_height)); + +                let layout = +                    child.as_widget().layout(tree, renderer, &child_limits); +                let size = layout.size(); + +                available -= axis.main(size); +                cross = cross.max(axis.cross(size)); + +                nodes[i] = layout; +            }          }      } @@ -135,6 +175,9 @@ where          },      }; +    // THIRD PASS +    // We only have the elements that are fluid in the main axis left. +    // We use the remaining space to evenly allocate space based on fill factors.      for (i, (child, tree)) in items.iter().zip(trees).enumerate() {          let (fill_main_factor, fill_cross_factor) = {              let size = child.as_widget().size(); @@ -142,10 +185,16 @@ where              axis.pack(size.width.fill_factor(), size.height.fill_factor())          }; -        if fill_main_factor != 0 || (cross_compress && fill_cross_factor != 0) { +        if fill_main_factor != 0 {              let max_main =                  remaining * fill_main_factor as f32 / fill_main_sum as f32; +            let max_main = if max_main.is_nan() { +                f32::INFINITY +            } else { +                max_main +            }; +              let min_main = if max_main.is_infinite() {                  0.0              } else { @@ -178,6 +227,8 @@ where      let pad = axis.pack(padding.left, padding.top);      let mut main = pad.0; +    // FOURTH PASS +    // We align all the laid out nodes in the cross axis, if needed.      for (i, node) in nodes.iter_mut().enumerate() {          if i > 0 {              main += spacing; diff --git a/core/src/overlay.rs b/core/src/overlay.rs index f09de831..383663af 100644 --- a/core/src/overlay.rs +++ b/core/src/overlay.rs @@ -5,13 +5,12 @@ mod group;  pub use element::Element;  pub use group::Group; -use crate::event::{self, Event};  use crate::layout;  use crate::mouse;  use crate::renderer;  use crate::widget;  use crate::widget::Tree; -use crate::{Clipboard, Layout, Point, Rectangle, Shell, Size, Vector}; +use crate::{Clipboard, Event, Layout, Point, Rectangle, Shell, Size, Vector};  /// An interactive component that can be displayed on top of other widgets.  pub trait Overlay<Message, Theme, Renderer> @@ -57,7 +56,7 @@ where      ///   * a [`Clipboard`], if available      ///      /// By default, it does nothing. -    fn on_event( +    fn update(          &mut self,          _event: Event,          _layout: Layout<'_>, @@ -65,8 +64,7 @@ where          _renderer: &Renderer,          _clipboard: &mut dyn Clipboard,          _shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        event::Status::Ignored +    ) {      }      /// Returns the current [`mouse::Interaction`] of the [`Overlay`]. diff --git a/core/src/overlay/element.rs b/core/src/overlay/element.rs index 32e987a3..ed870feb 100644 --- a/core/src/overlay/element.rs +++ b/core/src/overlay/element.rs @@ -1,11 +1,10 @@  pub use crate::Overlay; -use crate::event::{self, Event};  use crate::layout;  use crate::mouse;  use crate::renderer;  use crate::widget; -use crate::{Clipboard, Layout, Point, Rectangle, Shell, Size}; +use crate::{Clipboard, Event, Layout, Point, Rectangle, Shell, Size};  /// A generic [`Overlay`].  #[allow(missing_debug_implementations)] @@ -50,7 +49,7 @@ where      }      /// Processes a runtime [`Event`]. -    pub fn on_event( +    pub fn update(          &mut self,          event: Event,          layout: Layout<'_>, @@ -58,9 +57,9 @@ where          renderer: &Renderer,          clipboard: &mut dyn Clipboard,          shell: &mut Shell<'_, Message>, -    ) -> event::Status { +    ) {          self.overlay -            .on_event(event, layout, cursor, renderer, clipboard, shell) +            .update(event, layout, cursor, renderer, clipboard, shell);      }      /// Returns the current [`mouse::Interaction`] of the [`Element`]. @@ -149,7 +148,7 @@ where          self.content.operate(layout, renderer, operation);      } -    fn on_event( +    fn update(          &mut self,          event: Event,          layout: Layout<'_>, @@ -157,11 +156,11 @@ where          renderer: &Renderer,          clipboard: &mut dyn Clipboard,          shell: &mut Shell<'_, B>, -    ) -> event::Status { +    ) {          let mut local_messages = Vec::new();          let mut local_shell = Shell::new(&mut local_messages); -        let event_status = self.content.on_event( +        self.content.update(              event,              layout,              cursor, @@ -171,8 +170,6 @@ where          );          shell.merge(local_shell, self.mapper); - -        event_status      }      fn mouse_interaction( diff --git a/core/src/overlay/group.rs b/core/src/overlay/group.rs index 6541d311..2b374252 100644 --- a/core/src/overlay/group.rs +++ b/core/src/overlay/group.rs @@ -1,4 +1,3 @@ -use crate::event;  use crate::layout;  use crate::mouse;  use crate::overlay; @@ -73,7 +72,7 @@ where          )      } -    fn on_event( +    fn update(          &mut self,          event: Event,          layout: Layout<'_>, @@ -81,21 +80,17 @@ where          renderer: &Renderer,          clipboard: &mut dyn Clipboard,          shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        self.children -            .iter_mut() -            .zip(layout.children()) -            .map(|(child, layout)| { -                child.on_event( -                    event.clone(), -                    layout, -                    cursor, -                    renderer, -                    clipboard, -                    shell, -                ) -            }) -            .fold(event::Status::Ignored, event::Status::merge) +    ) { +        for (child, layout) in self.children.iter_mut().zip(layout.children()) { +            child.update( +                event.clone(), +                layout, +                cursor, +                renderer, +                clipboard, +                shell, +            ); +        }      }      fn draw( diff --git a/core/src/shell.rs b/core/src/shell.rs index 2952ceff..12ebbaa8 100644 --- a/core/src/shell.rs +++ b/core/src/shell.rs @@ -1,3 +1,5 @@ +use crate::event; +use crate::time::Instant;  use crate::window;  /// A connection to the state of a shell. @@ -9,6 +11,7 @@ use crate::window;  #[derive(Debug)]  pub struct Shell<'a, Message> {      messages: &'a mut Vec<Message>, +    event_status: event::Status,      redraw_request: Option<window::RedrawRequest>,      is_layout_invalid: bool,      are_widgets_invalid: bool, @@ -19,6 +22,7 @@ impl<'a, Message> Shell<'a, Message> {      pub fn new(messages: &'a mut Vec<Message>) -> Self {          Self {              messages, +            event_status: event::Status::Ignored,              redraw_request: None,              is_layout_invalid: false,              are_widgets_invalid: false, @@ -35,14 +39,37 @@ impl<'a, Message> Shell<'a, Message> {          self.messages.push(message);      } -    /// Requests a new frame to be drawn. -    pub fn request_redraw(&mut self, request: window::RedrawRequest) { +    /// Marks the current event as captured. Prevents "event bubbling". +    /// +    /// A widget should capture an event when no ancestor should +    /// handle it. +    pub fn capture_event(&mut self) { +        self.event_status = event::Status::Captured; +    } + +    /// Returns the current [`event::Status`] of the [`Shell`]. +    pub fn event_status(&self) -> event::Status { +        self.event_status +    } + +    /// Returns whether the current event has been captured. +    pub fn is_event_captured(&self) -> bool { +        self.event_status == event::Status::Captured +    } + +    /// Requests a new frame to be drawn as soon as possible. +    pub fn request_redraw(&mut self) { +        self.redraw_request = Some(window::RedrawRequest::NextFrame); +    } + +    /// Requests a new frame to be drawn at the given [`Instant`]. +    pub fn request_redraw_at(&mut self, at: Instant) {          match self.redraw_request {              None => { -                self.redraw_request = Some(request); +                self.redraw_request = Some(window::RedrawRequest::At(at));              } -            Some(current) if request < current => { -                self.redraw_request = Some(request); +            Some(window::RedrawRequest::At(current)) if at < current => { +                self.redraw_request = Some(window::RedrawRequest::At(at));              }              _ => {}          } @@ -95,8 +122,12 @@ impl<'a, Message> Shell<'a, Message> {      pub fn merge<B>(&mut self, other: Shell<'_, B>, f: impl Fn(B) -> Message) {          self.messages.extend(other.messages.drain(..).map(f)); -        if let Some(at) = other.redraw_request { -            self.request_redraw(at); +        if let Some(new) = other.redraw_request { +            self.redraw_request = Some( +                self.redraw_request +                    .map(|current| if current < new { current } else { new }) +                    .unwrap_or(new), +            );          }          self.is_layout_invalid = @@ -104,5 +135,7 @@ impl<'a, Message> Shell<'a, Message> {          self.are_widgets_invalid =              self.are_widgets_invalid || other.are_widgets_invalid; + +        self.event_status = self.event_status.merge(other.event_status);      }  } diff --git a/core/src/widget.rs b/core/src/widget.rs index 9cfff83d..2a40f823 100644 --- a/core/src/widget.rs +++ b/core/src/widget.rs @@ -10,12 +10,11 @@ pub use operation::Operation;  pub use text::Text;  pub use tree::Tree; -use crate::event::{self, Event};  use crate::layout::{self, Layout};  use crate::mouse;  use crate::overlay;  use crate::renderer; -use crate::{Clipboard, Length, Rectangle, Shell, Size, Vector}; +use crate::{Clipboard, Event, Length, Rectangle, Shell, Size, Vector};  /// A component that displays information and allows interaction.  /// @@ -112,7 +111,7 @@ where      /// Processes a runtime [`Event`].      ///      /// By default, it does nothing. -    fn on_event( +    fn update(          &mut self,          _state: &mut Tree,          _event: Event, @@ -122,8 +121,7 @@ where          _clipboard: &mut dyn Clipboard,          _shell: &mut Shell<'_, Message>,          _viewport: &Rectangle, -    ) -> event::Status { -        event::Status::Ignored +    ) {      }      /// Returns the current [`mouse::Interaction`] of the [`Widget`]. | 
