From 8b1c514c3816795437da2ec25c2cfc559ebe5b9a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 25 Apr 2024 01:40:06 +0200 Subject: Showcase new `Stack` widget in `bezier_tool` example --- examples/bezier_tool/src/main.rs | 53 ++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 18 deletions(-) (limited to 'examples') diff --git a/examples/bezier_tool/src/main.rs b/examples/bezier_tool/src/main.rs index 289c919b..ba51a00e 100644 --- a/examples/bezier_tool/src/main.rs +++ b/examples/bezier_tool/src/main.rs @@ -1,9 +1,11 @@ //! This example showcases an interactive `Canvas` for drawing Bézier curves. -use iced::widget::{button, column, text}; -use iced::{Alignment, Element, Length}; +use iced::alignment; +use iced::widget::{button, container, stack}; +use iced::{Element, Length, Theme}; pub fn main() -> iced::Result { iced::program("Bezier Tool - Iced", Example::update, Example::view) + .theme(|_| Theme::CatppuccinMocha) .antialiasing(true) .run() } @@ -35,16 +37,18 @@ impl Example { } fn view(&self) -> Element { - column![ - text("Bezier tool example").width(Length::Shrink).size(50), + container(stack![ self.bezier.view(&self.curves).map(Message::AddCurve), - button("Clear") - .style(button::danger) - .on_press(Message::Clear), - ] + container( + button("Clear") + .style(button::danger) + .on_press(Message::Clear) + ) + .padding(10) + .width(Length::Fill) + .align_x(alignment::Horizontal::Right), + ]) .padding(20) - .spacing(20) - .align_items(Alignment::Center) .into() } } @@ -139,22 +143,24 @@ mod bezier { &self, state: &Self::State, renderer: &Renderer, - _theme: &Theme, + theme: &Theme, bounds: Rectangle, cursor: mouse::Cursor, ) -> Vec { let content = self.state.cache.draw(renderer, bounds.size(), |frame| { - Curve::draw_all(self.curves, frame); + Curve::draw_all(self.curves, frame, theme); frame.stroke( &Path::rectangle(Point::ORIGIN, frame.size()), - Stroke::default().with_width(2.0), + Stroke::default() + .with_width(2.0) + .with_color(theme.palette().text), ); }); if let Some(pending) = state { - vec![content, pending.draw(renderer, bounds, cursor)] + vec![content, pending.draw(renderer, theme, bounds, cursor)] } else { vec![content] } @@ -182,7 +188,7 @@ mod bezier { } impl Curve { - fn draw_all(curves: &[Curve], frame: &mut Frame) { + fn draw_all(curves: &[Curve], frame: &mut Frame, theme: &Theme) { let curves = Path::new(|p| { for curve in curves { p.move_to(curve.from); @@ -190,7 +196,12 @@ mod bezier { } }); - frame.stroke(&curves, Stroke::default().with_width(2.0)); + frame.stroke( + &curves, + Stroke::default() + .with_width(2.0) + .with_color(theme.palette().text), + ); } } @@ -204,6 +215,7 @@ mod bezier { fn draw( &self, renderer: &Renderer, + theme: &Theme, bounds: Rectangle, cursor: mouse::Cursor, ) -> Geometry { @@ -213,7 +225,12 @@ mod bezier { match *self { Pending::One { from } => { let line = Path::line(from, cursor_position); - frame.stroke(&line, Stroke::default().with_width(2.0)); + frame.stroke( + &line, + Stroke::default() + .with_width(2.0) + .with_color(theme.palette().text), + ); } Pending::Two { from, to } => { let curve = Curve { @@ -222,7 +239,7 @@ mod bezier { control: cursor_position, }; - Curve::draw_all(&[curve], &mut frame); + Curve::draw_all(&[curve], &mut frame, theme); } }; } -- cgit From 4cd45643d7d2aa83212162f17a9b28ddae4a9340 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 25 Apr 2024 06:05:00 +0200 Subject: Introduce `opaque` widget helper --- examples/loupe/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/loupe/src/main.rs b/examples/loupe/src/main.rs index 6a5ff123..42b7f471 100644 --- a/examples/loupe/src/main.rs +++ b/examples/loupe/src/main.rs @@ -159,7 +159,7 @@ mod loupe { if cursor.is_over(layout.bounds()) { mouse::Interaction::ZoomIn } else { - mouse::Interaction::Idle + mouse::Interaction::None } } } -- cgit From 4fc342c97963a7a7e7983604b9399fccf017aa53 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 25 Apr 2024 06:05:40 +0200 Subject: Simplify `modal` example :tada: --- examples/modal/src/main.rs | 363 +++++---------------------------------------- 1 file changed, 35 insertions(+), 328 deletions(-) (limited to 'examples') diff --git a/examples/modal/src/main.rs b/examples/modal/src/main.rs index 398728e0..a345924d 100644 --- a/examples/modal/src/main.rs +++ b/examples/modal/src/main.rs @@ -2,12 +2,11 @@ use iced::event::{self, Event}; use iced::keyboard; use iced::keyboard::key; use iced::widget::{ - self, button, column, container, horizontal_space, pick_list, row, text, - text_input, + self, button, column, container, horizontal_space, mouse_area, opaque, + pick_list, row, stack, text, text_input, }; -use iced::{Alignment, Command, Element, Length, Subscription}; +use iced::{Alignment, Color, Command, Element, Length, Subscription}; -use modal::Modal; use std::fmt; pub fn main() -> iced::Result { @@ -121,7 +120,7 @@ impl App { .height(Length::Fill); if self.show_modal { - let modal = container( + let signup = container( column![ text("Sign Up").size(24), column![ @@ -162,9 +161,7 @@ impl App { .padding(10) .style(container::rounded_box); - Modal::new(content, modal) - .on_blur(Message::HideModal) - .into() + modal(content, signup, Message::HideModal) } else { content.into() } @@ -203,326 +200,36 @@ impl fmt::Display for Plan { } } -mod modal { - use iced::advanced::layout::{self, Layout}; - use iced::advanced::overlay; - use iced::advanced::renderer; - use iced::advanced::widget::{self, Widget}; - use iced::advanced::{self, Clipboard, Shell}; - use iced::alignment::Alignment; - use iced::event; - use iced::mouse; - use iced::{Color, Element, Event, Length, Point, Rectangle, Size, Vector}; - - /// A widget that centers a modal element over some base element - pub struct Modal<'a, Message, Theme, Renderer> { - base: Element<'a, Message, Theme, Renderer>, - modal: Element<'a, Message, Theme, Renderer>, - on_blur: Option, - } - - impl<'a, Message, Theme, Renderer> Modal<'a, Message, Theme, Renderer> { - /// Returns a new [`Modal`] - pub fn new( - base: impl Into>, - modal: impl Into>, - ) -> Self { - Self { - base: base.into(), - modal: modal.into(), - on_blur: None, - } - } - - /// Sets the message that will be produces when the background - /// of the [`Modal`] is pressed - pub fn on_blur(self, on_blur: Message) -> Self { - Self { - on_blur: Some(on_blur), - ..self - } - } - } - - impl<'a, Message, Theme, Renderer> Widget - for Modal<'a, Message, Theme, Renderer> - where - Renderer: advanced::Renderer, - Message: Clone, - { - fn children(&self) -> Vec { - vec![ - widget::Tree::new(&self.base), - widget::Tree::new(&self.modal), - ] - } - - fn diff(&self, tree: &mut widget::Tree) { - tree.diff_children(&[&self.base, &self.modal]); - } - - fn size(&self) -> Size { - self.base.as_widget().size() - } - - fn layout( - &self, - tree: &mut widget::Tree, - renderer: &Renderer, - limits: &layout::Limits, - ) -> layout::Node { - self.base.as_widget().layout( - &mut tree.children[0], - renderer, - limits, - ) - } - - fn on_event( - &mut self, - state: &mut widget::Tree, - event: Event, - layout: Layout<'_>, - cursor: mouse::Cursor, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - viewport: &Rectangle, - ) -> event::Status { - self.base.as_widget_mut().on_event( - &mut state.children[0], - event, - layout, - cursor, - renderer, - clipboard, - shell, - viewport, - ) - } - - fn draw( - &self, - state: &widget::Tree, - renderer: &mut Renderer, - theme: &Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor: mouse::Cursor, - viewport: &Rectangle, - ) { - self.base.as_widget().draw( - &state.children[0], - renderer, - theme, - style, - layout, - cursor, - viewport, - ); - } - - fn overlay<'b>( - &'b mut self, - state: &'b mut widget::Tree, - layout: Layout<'_>, - _renderer: &Renderer, - translation: Vector, - ) -> Option> { - Some(overlay::Element::new(Box::new(Overlay { - position: layout.position() + translation, - content: &mut self.modal, - tree: &mut state.children[1], - size: layout.bounds().size(), - on_blur: self.on_blur.clone(), - }))) - } - - fn mouse_interaction( - &self, - state: &widget::Tree, - layout: Layout<'_>, - cursor: mouse::Cursor, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - self.base.as_widget().mouse_interaction( - &state.children[0], - layout, - cursor, - viewport, - renderer, - ) - } - - fn operate( - &self, - state: &mut widget::Tree, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn widget::Operation, - ) { - self.base.as_widget().operate( - &mut state.children[0], - layout, - renderer, - operation, - ); - } - } - - struct Overlay<'a, 'b, Message, Theme, Renderer> { - position: Point, - content: &'b mut Element<'a, Message, Theme, Renderer>, - tree: &'b mut widget::Tree, - size: Size, - on_blur: Option, - } - - impl<'a, 'b, Message, Theme, Renderer> - overlay::Overlay - for Overlay<'a, 'b, Message, Theme, Renderer> - where - Renderer: advanced::Renderer, - Message: Clone, - { - fn layout( - &mut self, - renderer: &Renderer, - _bounds: Size, - ) -> layout::Node { - let limits = layout::Limits::new(Size::ZERO, self.size) +fn modal<'a, Message>( + base: impl Into>, + content: impl Into>, + on_blur: Message, +) -> Element<'a, Message> +where + Message: Clone + 'a, +{ + stack![ + base.into(), + mouse_area( + container(opaque(content)) .width(Length::Fill) - .height(Length::Fill); - - let child = self - .content - .as_widget() - .layout(self.tree, renderer, &limits) - .align(Alignment::Center, Alignment::Center, limits.max()); - - layout::Node::with_children(self.size, vec![child]) - .move_to(self.position) - } - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor: mouse::Cursor, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - ) -> event::Status { - let content_bounds = layout.children().next().unwrap().bounds(); - - if let Some(message) = self.on_blur.as_ref() { - if let Event::Mouse(mouse::Event::ButtonPressed( - mouse::Button::Left, - )) = &event - { - if !cursor.is_over(content_bounds) { - shell.publish(message.clone()); - return event::Status::Captured; + .height(Length::Fill) + .center_x() + .center_y() + .style(|_theme| { + container::Style { + background: Some( + Color { + a: 0.8, + ..Color::BLACK + } + .into(), + ), + ..container::Style::default() } - } - } - - self.content.as_widget_mut().on_event( - self.tree, - event, - layout.children().next().unwrap(), - cursor, - renderer, - clipboard, - shell, - &layout.bounds(), - ) - } - - fn draw( - &self, - renderer: &mut Renderer, - theme: &Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor: mouse::Cursor, - ) { - renderer.fill_quad( - renderer::Quad { - bounds: layout.bounds(), - ..renderer::Quad::default() - }, - Color { - a: 0.80, - ..Color::BLACK - }, - ); - - self.content.as_widget().draw( - self.tree, - renderer, - theme, - style, - layout.children().next().unwrap(), - cursor, - &layout.bounds(), - ); - } - - fn operate( - &mut self, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn widget::Operation, - ) { - self.content.as_widget().operate( - self.tree, - layout.children().next().unwrap(), - renderer, - operation, - ); - } - - fn mouse_interaction( - &self, - layout: Layout<'_>, - cursor: mouse::Cursor, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - self.content.as_widget().mouse_interaction( - self.tree, - layout.children().next().unwrap(), - cursor, - viewport, - renderer, - ) - } - - fn overlay<'c>( - &'c mut self, - layout: Layout<'_>, - renderer: &Renderer, - ) -> Option> { - self.content.as_widget_mut().overlay( - self.tree, - layout.children().next().unwrap(), - renderer, - Vector::ZERO, - ) - } - } - - impl<'a, Message, Theme, Renderer> From> - for Element<'a, Message, Theme, Renderer> - where - Theme: 'a, - Message: 'a + Clone, - Renderer: 'a + advanced::Renderer, - { - fn from(modal: Modal<'a, Message, Theme, Renderer>) -> Self { - Element::new(modal) - } - } + }) + ) + .on_press(on_blur) + ] + .into() } -- cgit