diff options
Diffstat (limited to 'widget/src')
-rw-r--r-- | widget/src/button.rs | 2 | ||||
-rw-r--r-- | widget/src/canvas.rs | 4 | ||||
-rw-r--r-- | widget/src/column.rs | 2 | ||||
-rw-r--r-- | widget/src/combo_box.rs | 38 | ||||
-rw-r--r-- | widget/src/container.rs | 2 | ||||
-rw-r--r-- | widget/src/helpers.rs | 35 | ||||
-rw-r--r-- | widget/src/image.rs | 13 | ||||
-rw-r--r-- | widget/src/image/viewer.rs | 15 | ||||
-rw-r--r-- | widget/src/keyed/column.rs | 2 | ||||
-rw-r--r-- | widget/src/lazy.rs | 2 | ||||
-rw-r--r-- | widget/src/lazy/component.rs | 6 | ||||
-rw-r--r-- | widget/src/lazy/responsive.rs | 2 | ||||
-rw-r--r-- | widget/src/mouse_area.rs | 2 | ||||
-rw-r--r-- | widget/src/pane_grid.rs | 2 | ||||
-rw-r--r-- | widget/src/pane_grid/content.rs | 2 | ||||
-rw-r--r-- | widget/src/pane_grid/title_bar.rs | 2 | ||||
-rw-r--r-- | widget/src/row.rs | 202 | ||||
-rw-r--r-- | widget/src/scrollable.rs | 2 | ||||
-rw-r--r-- | widget/src/stack.rs | 2 | ||||
-rw-r--r-- | widget/src/svg.rs | 10 | ||||
-rw-r--r-- | widget/src/text_editor.rs | 2 | ||||
-rw-r--r-- | widget/src/text_input.rs | 2 | ||||
-rw-r--r-- | widget/src/themer.rs | 4 |
23 files changed, 299 insertions, 56 deletions
diff --git a/widget/src/button.rs b/widget/src/button.rs index 64a639d2..eafa71b9 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -236,7 +236,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { operation.container(None, layout.bounds(), &mut |operation| { self.content.as_widget().operate( diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs index 73cef087..185fa082 100644 --- a/widget/src/canvas.rs +++ b/widget/src/canvas.rs @@ -8,8 +8,8 @@ pub use program::Program; pub use crate::graphics::cache::Group; pub use crate::graphics::geometry::{ - fill, gradient, path, stroke, Fill, Gradient, LineCap, LineDash, LineJoin, - Path, Stroke, Style, Text, + fill, gradient, path, stroke, Fill, Gradient, Image, LineCap, LineDash, + LineJoin, Path, Stroke, Style, Text, }; use crate::core; diff --git a/widget/src/column.rs b/widget/src/column.rs index ae82ccaa..d3ea4cf7 100644 --- a/widget/src/column.rs +++ b/widget/src/column.rs @@ -222,7 +222,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { operation.container(None, layout.bounds(), &mut |operation| { self.children diff --git a/widget/src/combo_box.rs b/widget/src/combo_box.rs index 0a4624cb..62785b2c 100644 --- a/widget/src/combo_box.rs +++ b/widget/src/combo_box.rs @@ -208,12 +208,14 @@ where /// The local state of a [`ComboBox`]. #[derive(Debug, Clone)] -pub struct State<T>(RefCell<Inner<T>>); +pub struct State<T> { + options: Vec<T>, + inner: RefCell<Inner<T>>, +} #[derive(Debug, Clone)] struct Inner<T> { value: String, - options: Vec<T>, option_matchers: Vec<String>, filtered_options: Filtered<T>, } @@ -247,34 +249,44 @@ where .collect(), ); - Self(RefCell::new(Inner { - value, + Self { options, - option_matchers, - filtered_options, - })) + inner: RefCell::new(Inner { + value, + option_matchers, + filtered_options, + }), + } + } + + /// Returns the options of the [`State`]. + /// + /// These are the options provided when the [`State`] + /// was constructed with [`State::new`]. + pub fn options(&self) -> &[T] { + &self.options } fn value(&self) -> String { - let inner = self.0.borrow(); + let inner = self.inner.borrow(); inner.value.clone() } fn with_inner<O>(&self, f: impl FnOnce(&Inner<T>) -> O) -> O { - let inner = self.0.borrow(); + let inner = self.inner.borrow(); f(&inner) } fn with_inner_mut(&self, f: impl FnOnce(&mut Inner<T>)) { - let mut inner = self.0.borrow_mut(); + let mut inner = self.inner.borrow_mut(); f(&mut inner); } fn sync_filtered_options(&self, options: &mut Filtered<T>) { - let inner = self.0.borrow(); + let inner = self.inner.borrow(); inner.filtered_options.sync(options); } @@ -440,7 +452,7 @@ where state.filtered_options.update( search( - &state.options, + &self.state.options, &state.option_matchers, &state.value, ) @@ -589,7 +601,7 @@ where if let Some(selection) = menu.new_selection.take() { // Clear the value and reset the options and menu state.value = String::new(); - state.filtered_options.update(state.options.clone()); + state.filtered_options.update(self.state.options.clone()); menu.menu = menu::State::default(); // Notify the selection diff --git a/widget/src/container.rs b/widget/src/container.rs index 9224f2ce..54043ad0 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -245,7 +245,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { operation.container( self.id.as_ref().map(|id| &id.0), diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 0eb5f974..c3ffea45 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -4,7 +4,8 @@ use crate::checkbox::{self, Checkbox}; use crate::combo_box::{self, ComboBox}; use crate::container::{self, Container}; use crate::core; -use crate::core::widget::operation; +use crate::core::widget::operation::{self, Operation}; +use crate::core::window; use crate::core::{Element, Length, Pixels, Widget}; use crate::keyed; use crate::overlay; @@ -289,7 +290,7 @@ where state: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn operation::Operation<()>, + operation: &mut dyn operation::Operation, ) { self.content .as_widget() @@ -397,6 +398,7 @@ where struct Hover<'a, Message, Theme, Renderer> { base: Element<'a, Message, Theme, Renderer>, top: Element<'a, Message, Theme, Renderer>, + is_top_focused: bool, is_top_overlay_active: bool, } @@ -472,7 +474,9 @@ where viewport, ); - if cursor.is_over(layout.bounds()) || self.is_top_overlay_active + if cursor.is_over(layout.bounds()) + || self.is_top_focused + || self.is_top_overlay_active { let (top_layout, top_tree) = children.next().unwrap(); @@ -491,7 +495,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn operation::Operation<()>, + operation: &mut dyn operation::Operation, ) { let children = [&self.base, &self.top] .into_iter() @@ -515,6 +519,24 @@ where ) -> event::Status { let mut children = layout.children().zip(&mut tree.children); let (base_layout, base_tree) = children.next().unwrap(); + let (top_layout, top_tree) = children.next().unwrap(); + + if matches!(event, Event::Window(window::Event::RedrawRequested(_))) + { + let mut count_focused = operation::focusable::count(); + + self.top.as_widget_mut().operate( + top_tree, + top_layout, + renderer, + &mut operation::black_box(&mut count_focused), + ); + + self.is_top_focused = match count_focused.finish() { + operation::Outcome::Some(count) => count.focused.is_some(), + _ => false, + }; + } let top_status = if matches!( event, @@ -523,9 +545,9 @@ where | mouse::Event::ButtonReleased(_) ) ) || cursor.is_over(layout.bounds()) + || self.is_top_focused + || self.is_top_overlay_active { - let (top_layout, top_tree) = children.next().unwrap(); - self.top.as_widget_mut().on_event( top_tree, event.clone(), @@ -611,6 +633,7 @@ where Element::new(Hover { base: base.into(), top: top.into(), + is_top_focused: false, is_top_overlay_active: false, }) } diff --git a/widget/src/image.rs b/widget/src/image.rs index 80e17263..e04f2d6f 100644 --- a/widget/src/image.rs +++ b/widget/src/image.rs @@ -43,7 +43,7 @@ pub struct Image<Handle> { impl<Handle> Image<Handle> { /// Creates a new [`Image`] with the given path. - pub fn new<T: Into<Handle>>(handle: T) -> Self { + pub fn new(handle: impl Into<Handle>) -> Self { Image { handle: handle.into(), width: Length::Shrink, @@ -181,11 +181,14 @@ pub fn draw<Renderer, Handle>( let render = |renderer: &mut Renderer| { renderer.draw_image( - handle.clone(), - filter_method, + image::Image { + handle: handle.clone(), + filter_method, + rotation: rotation.radians(), + opacity, + snap: true, + }, drawing_bounds, - rotation.radians(), - opacity, ); }; diff --git a/widget/src/image/viewer.rs b/widget/src/image/viewer.rs index b8b69b60..b1aad22c 100644 --- a/widget/src/image/viewer.rs +++ b/widget/src/image/viewer.rs @@ -6,8 +6,8 @@ use crate::core::mouse; use crate::core::renderer; use crate::core::widget::tree::{self, Tree}; use crate::core::{ - Clipboard, ContentFit, Element, Layout, Length, Pixels, Point, Radians, - Rectangle, Shell, Size, Vector, Widget, + Clipboard, ContentFit, Element, Image, Layout, Length, Pixels, Point, + Radians, Rectangle, Shell, Size, Vector, Widget, }; /// A frame that displays an image with the ability to zoom in/out and pan. @@ -349,11 +349,14 @@ where let render = |renderer: &mut Renderer| { renderer.with_translation(translation, |renderer| { renderer.draw_image( - self.handle.clone(), - self.filter_method, + Image { + handle: self.handle.clone(), + filter_method: self.filter_method, + rotation: Radians(0.0), + opacity: 1.0, + snap: true, + }, drawing_bounds, - Radians(0.0), - 1.0, ); }); }; diff --git a/widget/src/keyed/column.rs b/widget/src/keyed/column.rs index 69991d1f..2c56c605 100644 --- a/widget/src/keyed/column.rs +++ b/widget/src/keyed/column.rs @@ -265,7 +265,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { operation.container(None, layout.bounds(), &mut |operation| { self.children diff --git a/widget/src/lazy.rs b/widget/src/lazy.rs index 606da22d..4bcf8628 100644 --- a/widget/src/lazy.rs +++ b/widget/src/lazy.rs @@ -182,7 +182,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn widget::Operation<()>, + operation: &mut dyn widget::Operation, ) { self.with_element(|element| { element.as_widget().operate( diff --git a/widget/src/lazy/component.rs b/widget/src/lazy/component.rs index f079c0df..1bf04195 100644 --- a/widget/src/lazy/component.rs +++ b/widget/src/lazy/component.rs @@ -59,7 +59,7 @@ pub trait Component<Message, Theme = crate::Theme, Renderer = crate::Renderer> { fn operate( &self, _state: &mut Self::State, - _operation: &mut dyn widget::Operation<()>, + _operation: &mut dyn widget::Operation, ) { } @@ -172,7 +172,7 @@ where fn rebuild_element_with_operation( &self, - operation: &mut dyn widget::Operation<()>, + operation: &mut dyn widget::Operation, ) { let heads = self.state.borrow_mut().take().unwrap().into_heads(); @@ -358,7 +358,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn widget::Operation<()>, + operation: &mut dyn widget::Operation, ) { self.rebuild_element_with_operation(operation); diff --git a/widget/src/lazy/responsive.rs b/widget/src/lazy/responsive.rs index 27f52617..2e24f2b3 100644 --- a/widget/src/lazy/responsive.rs +++ b/widget/src/lazy/responsive.rs @@ -161,7 +161,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn widget::Operation<()>, + operation: &mut dyn widget::Operation, ) { let state = tree.state.downcast_mut::<State>(); let mut content = self.content.borrow_mut(); diff --git a/widget/src/mouse_area.rs b/widget/src/mouse_area.rs index 17cae53b..366335f4 100644 --- a/widget/src/mouse_area.rs +++ b/widget/src/mouse_area.rs @@ -178,7 +178,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { self.content.as_widget().operate( &mut tree.children[0], diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index c3da3879..0aab1ab5 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -324,7 +324,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn widget::Operation<()>, + operation: &mut dyn widget::Operation, ) { operation.container(None, layout.bounds(), &mut |operation| { self.contents diff --git a/widget/src/pane_grid/content.rs b/widget/src/pane_grid/content.rs index d45fc0cd..ec0676b1 100644 --- a/widget/src/pane_grid/content.rs +++ b/widget/src/pane_grid/content.rs @@ -214,7 +214,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn widget::Operation<()>, + operation: &mut dyn widget::Operation, ) { let body_layout = if let Some(title_bar) = &self.title_bar { let mut children = layout.children(); diff --git a/widget/src/pane_grid/title_bar.rs b/widget/src/pane_grid/title_bar.rs index c05f1252..791fab4a 100644 --- a/widget/src/pane_grid/title_bar.rs +++ b/widget/src/pane_grid/title_bar.rs @@ -278,7 +278,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn widget::Operation<()>, + operation: &mut dyn widget::Operation, ) { let mut children = layout.children(); let padded = children.next().unwrap(); diff --git a/widget/src/row.rs b/widget/src/row.rs index 3feeaa7e..85af912f 100644 --- a/widget/src/row.rs +++ b/widget/src/row.rs @@ -142,6 +142,13 @@ where ) -> Self { children.into_iter().fold(self, Self::push) } + + /// Turns the [`Row`] into a [`Wrapping`] row. + /// + /// The original alignment of the [`Row`] is preserved per row wrapped. + pub fn wrap(self) -> Wrapping<'a, Message, Theme, Renderer> { + Wrapping { row: self } + } } impl<'a, Message, Renderer> Default for Row<'a, Message, Renderer> @@ -211,7 +218,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { operation.container(None, layout.bounds(), &mut |operation| { self.children @@ -339,3 +346,196 @@ where Self::new(row) } } + +/// A [`Row`] that wraps its contents. +/// +/// Create a [`Row`] first, and then call [`Row::wrap`] to +/// obtain a [`Row`] that wraps its contents. +/// +/// The original alignment of the [`Row`] is preserved per row wrapped. +#[allow(missing_debug_implementations)] +pub struct Wrapping< + 'a, + Message, + Theme = crate::Theme, + Renderer = crate::Renderer, +> { + row: Row<'a, Message, Theme, Renderer>, +} + +impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer> + for Wrapping<'a, Message, Theme, Renderer> +where + Renderer: crate::core::Renderer, +{ + fn children(&self) -> Vec<Tree> { + self.row.children() + } + + fn diff(&self, tree: &mut Tree) { + self.row.diff(tree); + } + + fn size(&self) -> Size<Length> { + self.row.size() + } + + fn layout( + &self, + tree: &mut Tree, + renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let limits = limits + .width(self.row.width) + .height(self.row.height) + .shrink(self.row.padding); + + let spacing = self.row.spacing; + let max_width = limits.max().width; + + let mut children: Vec<layout::Node> = Vec::new(); + let mut intrinsic_size = Size::ZERO; + let mut row_start = 0; + let mut row_height = 0.0; + let mut x = 0.0; + let mut y = 0.0; + + let align_factor = match self.row.align { + Alignment::Start => 0.0, + Alignment::Center => 2.0, + Alignment::End => 1.0, + }; + + let align = |row_start: std::ops::Range<usize>, + row_height: f32, + children: &mut Vec<layout::Node>| { + if align_factor != 0.0 { + for node in &mut children[row_start] { + let height = node.size().height; + + node.translate_mut(Vector::new( + 0.0, + (row_height - height) / align_factor, + )); + } + } + }; + + for (i, child) in self.row.children.iter().enumerate() { + let node = child.as_widget().layout( + &mut tree.children[i], + renderer, + &limits, + ); + + let child_size = node.size(); + + if x != 0.0 && x + child_size.width > max_width { + intrinsic_size.width = intrinsic_size.width.max(x - spacing); + + align(row_start..i, row_height, &mut children); + + y += row_height + spacing; + x = 0.0; + row_start = i; + row_height = 0.0; + } + + row_height = row_height.max(child_size.height); + + children.push(node.move_to(( + x + self.row.padding.left, + y + self.row.padding.top, + ))); + + x += child_size.width + spacing; + } + + if x != 0.0 { + intrinsic_size.width = intrinsic_size.width.max(x - spacing); + } + + intrinsic_size.height = (y - spacing).max(0.0) + row_height; + align(row_start..children.len(), row_height, &mut children); + + let size = + limits.resolve(self.row.width, self.row.height, intrinsic_size); + + layout::Node::with_children(size.expand(self.row.padding), children) + } + + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation, + ) { + self.row.operate(tree, layout, renderer, operation); + } + + fn on_event( + &mut self, + tree: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor: mouse::Cursor, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + viewport: &Rectangle, + ) -> event::Status { + self.row.on_event( + tree, event, layout, cursor, renderer, clipboard, shell, viewport, + ) + } + + fn mouse_interaction( + &self, + tree: &Tree, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + self.row + .mouse_interaction(tree, layout, cursor, viewport, renderer) + } + + fn draw( + &self, + tree: &Tree, + renderer: &mut Renderer, + theme: &Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + ) { + self.row + .draw(tree, renderer, theme, style, layout, cursor, viewport); + } + + fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + translation: Vector, + ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> { + self.row.overlay(tree, layout, renderer, translation) + } +} + +impl<'a, Message, Theme, Renderer> From<Wrapping<'a, Message, Theme, Renderer>> + for Element<'a, Message, Theme, Renderer> +where + Message: 'a, + Theme: 'a, + Renderer: crate::core::Renderer + 'a, +{ + fn from(row: Wrapping<'a, Message, Theme, Renderer>) -> Self { + Self::new(row) + } +} diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 9ba8c39b..cf504eda 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -415,7 +415,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { let state = tree.state.downcast_mut::<State>(); diff --git a/widget/src/stack.rs b/widget/src/stack.rs index efa9711d..001376ac 100644 --- a/widget/src/stack.rs +++ b/widget/src/stack.rs @@ -189,7 +189,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { operation.container(None, layout.bounds(), &mut |operation| { self.children diff --git a/widget/src/svg.rs b/widget/src/svg.rs index 4551bcad..bec0090f 100644 --- a/widget/src/svg.rs +++ b/widget/src/svg.rs @@ -211,11 +211,13 @@ where let render = |renderer: &mut Renderer| { renderer.draw_svg( - self.handle.clone(), - style.color, + svg::Svg { + handle: self.handle.clone(), + color: style.color, + rotation: self.rotation.radians(), + opacity: self.opacity, + }, drawing_bounds, - self.rotation.radians(), - self.opacity, ); }; diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index e41c50d7..85332ba4 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -878,7 +878,7 @@ where tree: &mut widget::Tree, _layout: Layout<'_>, _renderer: &Renderer, - operation: &mut dyn widget::Operation<()>, + operation: &mut dyn widget::Operation, ) { let state = tree.state.downcast_mut::<State<Highlighter>>(); diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index 20e80ba5..173de136 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -542,7 +542,7 @@ where tree: &mut Tree, _layout: Layout<'_>, _renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>(); diff --git a/widget/src/themer.rs b/widget/src/themer.rs index 9eb47d84..499a9fe8 100644 --- a/widget/src/themer.rs +++ b/widget/src/themer.rs @@ -104,7 +104,7 @@ where tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { self.content .as_widget() @@ -236,7 +236,7 @@ where &mut self, layout: Layout<'_>, renderer: &Renderer, - operation: &mut dyn Operation<()>, + operation: &mut dyn Operation, ) { self.content.operate(layout, renderer, operation); } |