From 8c03dd32d904e23a26f1842a42b51bd9f02c7ad7 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Fri, 9 Jun 2023 00:17:37 +0200 Subject: [PATCH 01/13] init --- Cargo.toml | 5 +- examples/context_menu/Cargo.toml | 14 ++ examples/context_menu/src/main.rs | 100 +++++++++ src/lib.rs | 4 + src/native/context_menu.rs | 312 +++++++++++++++++++++++++++++ src/native/mod.rs | 6 + src/native/overlay/context_menu.rs | 217 ++++++++++++++++++++ src/native/overlay/mod.rs | 6 + src/style/context_menu.rs | 55 +++++ src/style/mod.rs | 6 + 10 files changed, 724 insertions(+), 1 deletion(-) create mode 100644 examples/context_menu/Cargo.toml create mode 100644 examples/context_menu/src/main.rs create mode 100644 src/native/context_menu.rs create mode 100644 src/native/overlay/context_menu.rs create mode 100644 src/style/context_menu.rs diff --git a/Cargo.toml b/Cargo.toml index d3fd4d2a..f777b971 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ split = [] menu = [] quad = [] spinner = [] +context_menu = [] default = [ "badge", @@ -52,6 +53,7 @@ default = [ "split", "menu", "quad", + "context_menu" ] [dependencies] @@ -101,7 +103,8 @@ members = [ "examples/split", "examples/split_scroller", "examples/menu", - "examples/spinner" + "examples/spinner", + "examples/context_menu" ] [workspace.dependencies.iced] diff --git a/examples/context_menu/Cargo.toml b/examples/context_menu/Cargo.toml new file mode 100644 index 00000000..95b7e3bf --- /dev/null +++ b/examples/context_menu/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "context_menu" +version = "0.1.0" +authors = ["wiiznokes "] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +iced_aw = { workspace = true, features = [ + "context_menu", +] } +iced_lazy = "0.6" +iced.workspace = true \ No newline at end of file diff --git a/examples/context_menu/src/main.rs b/examples/context_menu/src/main.rs new file mode 100644 index 00000000..215ba456 --- /dev/null +++ b/examples/context_menu/src/main.rs @@ -0,0 +1,100 @@ +use iced::{ + widget::{container, Button, Container, Row, Text}, + Alignment, Element, Sandbox, Settings, +}; + +use iced_aw::ContextMenu; + +fn main() -> iced::Result { + ContextMenuExample::run(Settings::default()) +} + +#[derive(Clone, Debug)] +enum Message { + OpenModal, + CloseModal, +} + +#[derive(Default)] +struct ContextMenuExample { + show_modal: bool, + last_message: Option, +} + +impl Sandbox for ContextMenuExample { + type Message = Message; + + fn new() -> Self { + Self::default() + } + + fn title(&self) -> String { + String::from("Modal example") + } + + fn update(&mut self, message: Self::Message) { + match message { + Message::OpenModal => self.show_modal = true, + Message::CloseModal => self.show_modal = false, + } + self.last_message = Some(message) + } + + fn view(&self) -> Element<'_, Self::Message> { + let content = Container::new( + Row::new() + .spacing(10) + .align_items(Alignment::Center) + .push(Button::new(Text::new("Open modal!")).on_press(Message::OpenModal)) + .push(Text::new(format!( + "Last message: {}", + match self.last_message.as_ref() { + Some(message) => match message { + Message::OpenModal => "Modal opened", + Message::CloseModal => "Modal closed", + }, + None => "None", + } + ))), + ); + + ContextMenu::new(self.show_modal, content, || { + container(my_component::MyComponent).into() + }) + .backdrop(Message::CloseModal) + .on_esc(Message::CloseModal) + .into() + } +} + +mod my_component { + use iced::{ + widget::{container, row, text}, + Element, + }; + use iced_lazy::{self, Component}; + + pub struct MyComponent; + + impl Component for MyComponent { + type State = (); + type Event = (); + + fn update(&mut self, _state: &mut Self::State, _event: Self::Event) -> Option { + None + } + + fn view(&self, _state: &Self::State) -> Element { + container(row![text("Hello there")]).into() + } + } + + impl<'a, Message> From for Element<'a, Message, iced::Renderer> + where + Message: 'a, + { + fn from(my_component: MyComponent) -> Self { + iced_lazy::component(my_component) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 21de6cbe..91139ca4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,6 +154,10 @@ mod platform { #[doc(no_inline)] #[cfg(feature = "spinner")] pub use {crate::native::spinner, crate::style::SpinnerStyle, spinner::Spinner}; + + #[doc(no_inline)] + #[cfg(feature = "context_menu")] + pub use {crate::native::context_menu, crate::style::ContextMenuStyle, context_menu::ContextMenu}; } #[doc(no_inline)] diff --git a/src/native/context_menu.rs b/src/native/context_menu.rs new file mode 100644 index 00000000..64bcc527 --- /dev/null +++ b/src/native/context_menu.rs @@ -0,0 +1,312 @@ +//! A modal for showing elements as an overlay on top of another. +//! +//! *This API requires the following crate features to be activated: modal* +use iced_native::{ + event, mouse, + widget::{Operation, Tree}, + Clipboard, Element, Event, Layout, Length, Point, Rectangle, Shell, Widget, +}; + +use crate::native::overlay::ContextMenuOverlay; + +pub use crate::style::context_menu::StyleSheet; + +/// A modal content as an overlay. +/// +/// Can be used in combination with the [`Card`](crate::card::Card) +/// widget to form dialog elements. +/// +/// # Example +/// ``` +/// # use iced_native::renderer::Null; +/// # use iced_native::widget::Text; +/// # use iced_aw::native::modal; +/// # +/// # pub type Modal<'a, Content, Message> +/// # = modal::Modal<'a, Message, Content, Null>; +/// #[derive(Debug, Clone)] +/// enum Message { +/// CloseModal, +/// } +/// +/// let modal = Modal::new( +/// true, +/// Text::new("Underlay"), +/// || Text::new("Overlay").into() +/// ) +/// .backdrop(Message::CloseModal); +/// ``` +#[allow(missing_debug_implementations)] +pub struct ContextMenu<'a, Content, Message, Renderer> +where + Content: Fn() -> Element<'a, Message, Renderer>, + Message: Clone, + Renderer: iced_native::Renderer, + Renderer::Theme: StyleSheet, +{ + /// Show the modal. + show_modal: bool, + /// The underlying element. + underlay: Element<'a, Message, Renderer>, + /// The content of teh [`ModalOverlay`](ModalOverlay). + content: Content, + /// The optional message that will be send when the user clicked on the backdrop. + backdrop: Option, + /// The optional message that will be send when the ESC key was pressed. + esc: Option, + /// The style of the [`ModalOverlay`](ModalOverlay). + style: ::Style, +} + +impl<'a, Content, Message, Renderer> ContextMenu<'a, Content, Message, Renderer> +where + Content: Fn() -> Element<'a, Message, Renderer>, + Message: Clone, + Renderer: iced_native::Renderer, + Renderer::Theme: StyleSheet, +{ + /// Creates a new [`Modal`](Modal) wrapping the underlying element to + /// show some content as an overlay. + /// + /// `state` is the content's state, assigned at the creation of the + /// overlying content. + /// + /// It expects: + /// * if the overlay of the date picker is visible. + /// * the underlay [`Element`](iced_native::Element) on which this [`Modal`](Modal) + /// will be wrapped around. + /// * the content [`Element`](iced_native::Element) of the [`Modal`](Modal). + pub fn new(show_modal: bool, underlay: U, content: Content) -> Self + where + U: Into>, + { + ContextMenu { + show_modal, + underlay: underlay.into(), + content, + backdrop: None, + esc: None, + style: ::Style::default(), + } + } + + /// Sets the message that will be produced when the backdrop of the + /// [`Modal`](Modal) is clicked. + #[must_use] + pub fn backdrop(mut self, message: Message) -> Self { + self.backdrop = Some(message); + self + } + + /// Sets the message that will be produced when the Escape Key is + /// pressed when the modal is open. + /// + /// This can be used to close the modal on ESC. + #[must_use] + pub fn on_esc(mut self, message: Message) -> Self { + self.esc = Some(message); + self + } + + /// Sets the style of the [`Modal`](Modal). + #[must_use] + pub fn style(mut self, style: ::Style) -> Self { + self.style = style; + self + } +} + +impl<'a, Content, Message, Renderer> Widget + for ContextMenu<'a, Content, Message, Renderer> +where + Content: 'a + Fn() -> Element<'a, Message, Renderer>, + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, +{ + fn children(&self) -> Vec { + vec![Tree::new(&self.underlay), Tree::new(&(self.content)())] + } + + fn diff(&self, tree: &mut Tree) { + tree.diff_children(&[&self.underlay, &(self.content)()]); + } + + fn width(&self) -> Length { + self.underlay.as_widget().width() + } + + fn height(&self) -> Length { + self.underlay.as_widget().height() + } + + fn layout( + &self, + renderer: &Renderer, + limits: &iced_native::layout::Limits, + ) -> iced_native::layout::Node { + self.underlay.as_widget().layout(renderer, limits) + } + + fn on_event( + &mut self, + state: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + ) -> event::Status { + self.underlay.as_widget_mut().on_event( + &mut state.children[0], + event, + layout, + cursor_position, + renderer, + clipboard, + shell, + ) + } + + fn mouse_interaction( + &self, + state: &Tree, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + self.underlay.as_widget().mouse_interaction( + &state.children[0], + layout, + cursor_position, + viewport, + renderer, + ) + } + + fn draw( + &self, + state: &iced_native::widget::Tree, + renderer: &mut Renderer, + theme: &Renderer::Theme, + style: &iced_native::renderer::Style, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + ) { + self.underlay.as_widget().draw( + &state.children[0], + renderer, + theme, + style, + layout, + cursor_position, + viewport, + ); + } + + fn overlay<'b>( + &'b mut self, + state: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + ) -> Option> { + if !self.show_modal { + return self + .underlay + .as_widget_mut() + .overlay(&mut state.children[0], layout, renderer); + } + + let bounds = layout.bounds(); + let position = Point::new(bounds.x, bounds.y); + let content = (self.content)(); + content.as_widget().diff(&mut state.children[1]); + + Some( + ContextMenuOverlay::new( + &mut state.children[1], + content, + self.backdrop.clone(), + self.esc.clone(), + self.style, + ) + .overlay(position), + ) + } + + fn operate<'b>( + &'b self, + state: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation, + ) { + if self.show_modal { + let content = (self.content)(); + content.as_widget().diff(&mut state.children[1]); + + content + .as_widget() + .operate(&mut state.children[1], layout, renderer, operation); + } else { + self.underlay + .as_widget() + .operate(&mut state.children[0], layout, renderer, operation); + } + } +} + +impl<'a, Content, Message, Renderer> From> + for Element<'a, Message, Renderer> +where + Content: 'a + Fn() -> Element<'a, Message, Renderer>, + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, +{ + fn from(modal: ContextMenu<'a, Content, Message, Renderer>) -> Self { + Element::new(modal) + } +} +/// The state of the modal. +#[derive(Debug, Default)] +pub struct State { + /// The visibility of the [`Modal`](Modal) overlay. + show: bool, + /// The state of the content of the [`Modal`](Modal) overlay. + state: S, +} + +impl State { + /// Creates a new [`State`](State) containing the given state data. + pub const fn new(s: S) -> Self { + Self { + show: false, + state: s, + } + } + + /// Setting this to true shows the modal (the modal is open), false means + /// the modal is hidden (closed). + pub fn show(&mut self, b: bool) { + self.show = b; + } + + /// See if this modal will be shown or not. + pub const fn is_shown(&self) -> bool { + self.show + } + + /// Get a mutable reference to the inner state data. + pub fn inner_mut(&mut self) -> &mut S { + &mut self.state + } + + /// Get a reference to the inner state data. + pub const fn inner(&self) -> &S { + &self.state + } +} diff --git a/src/native/mod.rs b/src/native/mod.rs index a05793a8..1e1e82a2 100644 --- a/src/native/mod.rs +++ b/src/native/mod.rs @@ -97,3 +97,9 @@ pub mod spinner; #[cfg(feature = "spinner")] pub use spinner::Spinner; + + +#[cfg(feature = "context_menu")] +pub mod context_menu; +#[cfg(feature = "context_menu")] +pub use context_menu::ContextMenu; diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs new file mode 100644 index 00000000..5d1775a1 --- /dev/null +++ b/src/native/overlay/context_menu.rs @@ -0,0 +1,217 @@ +//! A modal for showing elements as an overlay on top of another. +//! +//! *This API requires the following crate features to be activated: modal* +use iced_graphics::Vector; +use iced_native::{ + event, keyboard, layout::Limits, mouse, overlay, renderer, touch, Clipboard, Color, Event, + Layout, Point, Shell, Size, +}; +use iced_native::{widget::Tree, Element}; + +use crate::style::context_menu::StyleSheet; + +/// The overlay of the modal. +#[allow(missing_debug_implementations)] +pub struct ContextMenuOverlay<'a, Message, Renderer> +where + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, +{ + /// The state of the [`ModalOverlay`](ModalOverlay). + state: &'a mut Tree, + /// The content of the [`ModalOverlay`](ModalOverlay). + content: Element<'a, Message, Renderer>, + /// The optional message that will be send when the user clicks on the backdrop. + backdrop: Option, + /// The optional message that will be send when the ESC key was pressed. + esc: Option, + /// The style of the [`ModalOverlay`](ModalOverlay). + style: ::Style, +} + +impl<'a, Message, Renderer> ContextMenuOverlay<'a, Message, Renderer> +where + Message: Clone, + Renderer: iced_native::Renderer, + Renderer::Theme: StyleSheet, +{ + /// Creates a new [`ModalOverlay`](ModalOverlay). + pub fn new( + state: &'a mut Tree, + content: C, + backdrop: Option, + esc: Option, + style: ::Style, + ) -> Self + where + C: Into>, + { + ContextMenuOverlay { + state, + content: content.into(), + backdrop, + esc, + style, + } + } + + /// Turn this [`ModalOverlay`] into an overlay + /// [`Element`](iced_native::overlay::Element). + pub fn overlay(self, position: Point) -> overlay::Element<'a, Message, Renderer> { + overlay::Element::new(position, Box::new(self)) + } +} + +impl<'a, Message, Renderer> iced_native::Overlay + for ContextMenuOverlay<'a, Message, Renderer> +where + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, +{ + fn layout( + &self, + renderer: &Renderer, + bounds: iced_graphics::Size, + position: Point, + ) -> iced_native::layout::Node { + let limits = Limits::new(Size::ZERO, bounds); + + let mut content = self.content.as_widget().layout(renderer, &limits); + + // Center position + let max_size = limits.max(); + let container_half_width = max_size.width / 2.0; + let container_half_height = max_size.height / 2.0; + let content_half_width = content.bounds().width / 2.0; + let content_half_height = content.bounds().height / 2.0; + + let position = position + + Vector::new( + container_half_width - content_half_width, + container_half_height - content_half_height, + ); + + content.move_to(position); + + iced_native::layout::Node::with_children(max_size, vec![content]) + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell, + ) -> event::Status { + // TODO clean this up + let esc_status = self + .esc + .as_ref() + .map_or(event::Status::Ignored, |esc| match event { + Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { + if key_code == keyboard::KeyCode::Escape { + shell.publish(esc.to_owned()); + event::Status::Captured + } else { + event::Status::Ignored + } + } + _ => event::Status::Ignored, + }); + + let backdrop_status = self.backdrop.as_ref().zip(layout.children().next()).map_or( + event::Status::Ignored, + |(backdrop, layout)| match event { + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerPressed { .. }) => { + if layout.bounds().contains(cursor_position) { + event::Status::Ignored + } else { + shell.publish(backdrop.to_owned()); + event::Status::Captured + } + } + _ => event::Status::Ignored, + }, + ); + + match esc_status.merge(backdrop_status) { + event::Status::Ignored => self.content.as_widget_mut().on_event( + self.state, + event, + layout + .children() + .next() + .expect("Native: Layout should have a content layout."), + cursor_position, + renderer, + clipboard, + shell, + ), + event::Status::Captured => event::Status::Captured, + } + } + + fn mouse_interaction( + &self, + layout: Layout<'_>, + cursor_position: Point, + viewport: &iced_graphics::Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + self.content.as_widget().mouse_interaction( + self.state, + layout + .children() + .next() + .expect("Native: Layout should have a content layout."), + cursor_position, + viewport, + renderer, + ) + } + + fn draw( + &self, + renderer: &mut Renderer, + theme: &Renderer::Theme, + style: &iced_native::renderer::Style, + layout: iced_native::Layout<'_>, + cursor_position: Point, + ) { + let bounds = layout.bounds(); + + let style_sheet = theme.active(self.style); + + // Background + renderer.fill_quad( + renderer::Quad { + bounds, + border_radius: (0.0).into(), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }, + style_sheet.background, + ); + + let content_layout = layout + .children() + .next() + .expect("Native: Layout should have a content layout."); + + // Modal + self.content.as_widget().draw( + self.state, + renderer, + theme, + style, + content_layout, + cursor_position, + &bounds, + ); + } +} diff --git a/src/native/overlay/mod.rs b/src/native/overlay/mod.rs index 25148efc..5f35fa02 100644 --- a/src/native/overlay/mod.rs +++ b/src/native/overlay/mod.rs @@ -24,3 +24,9 @@ pub use modal::ModalOverlay; pub mod time_picker; #[cfg(feature = "time_picker")] pub use time_picker::{State, TimePickerOverlay}; + + +#[cfg(feature = "context_menu")] +pub mod context_menu; +#[cfg(feature = "context_menu")] +pub use context_menu::ContextMenuOverlay; \ No newline at end of file diff --git a/src/style/context_menu.rs b/src/style/context_menu.rs new file mode 100644 index 00000000..da5283ab --- /dev/null +++ b/src/style/context_menu.rs @@ -0,0 +1,55 @@ +//! Use a badge for color highlighting important information. +//! +//! *This API requires the following crate features to be activated: badge* +use iced_graphics::Color; + +use iced_native::Background; +use iced_style::Theme; + +/// The appearance of a [`Modal`](crate::native::Modal). +#[derive(Clone, Copy, Debug)] +pub struct Appearance { + /// The backgronud of the [`Modal`](crate::native::Modal). + /// + /// This is used to color the backdrop of the modal. + pub background: Background, +} + +impl Default for Appearance { + fn default() -> Self { + Self { + background: Background::Color([0.87, 0.87, 0.87, 0.30].into()), + } + } +} +/// The appearance of a [`Modal`](crate::native::Modal). +pub trait StyleSheet { + ///Style for the trait to use. + type Style: Default + Copy; + /// The normal appearance of a [`Modal`](crate::native::Modal). + fn active(&self, style: Self::Style) -> Appearance; +} + +/// The default appearance of a [`Modal`](crate::native::Modal). +#[derive(Clone, Copy, Debug, Default)] +#[allow(missing_docs, clippy::missing_docs_in_private_items)] +pub enum ContextMenuStyle { + #[default] + Default, +} + +impl StyleSheet for Theme { + type Style = ContextMenuStyle; + + fn active(&self, _style: Self::Style) -> Appearance { + let palette = self.extended_palette(); + + Appearance { + background: Color { + a: palette.background.base.color.a * 0.5, + ..palette.background.base.color + } + .into(), + } + } +} diff --git a/src/style/mod.rs b/src/style/mod.rs index a76d46b9..bd9e605a 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -56,3 +56,9 @@ pub use menu_bar::MenuBarStyle; pub mod spinner; #[cfg(feature = "spinner")] pub use spinner::SpinnerStyle; + + +#[cfg(feature = "context_menu")] +pub mod context_menu; +#[cfg(feature = "context_menu")] +pub use context_menu::ContextMenuStyle; \ No newline at end of file From ca2797db3aea16a08b9dad6a81724b370707fb6f Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Fri, 9 Jun 2023 03:38:15 +0200 Subject: [PATCH 02/13] internal state! --- examples/context_menu/src/main.rs | 2 +- src/native/context_menu.rs | 83 +++++++++++++++++------------- src/native/overlay/context_menu.rs | 23 +++++---- 3 files changed, 63 insertions(+), 45 deletions(-) diff --git a/examples/context_menu/src/main.rs b/examples/context_menu/src/main.rs index 215ba456..329b9f4a 100644 --- a/examples/context_menu/src/main.rs +++ b/examples/context_menu/src/main.rs @@ -58,7 +58,7 @@ impl Sandbox for ContextMenuExample { ))), ); - ContextMenu::new(self.show_modal, content, || { + ContextMenu::new(content, || { container(my_component::MyComponent).into() }) .backdrop(Message::CloseModal) diff --git a/src/native/context_menu.rs b/src/native/context_menu.rs index 64bcc527..d280174d 100644 --- a/src/native/context_menu.rs +++ b/src/native/context_menu.rs @@ -2,8 +2,8 @@ //! //! *This API requires the following crate features to be activated: modal* use iced_native::{ - event, mouse, - widget::{Operation, Tree}, + event, mouse::{self, Button}, + widget::{Operation, Tree, tree}, Clipboard, Element, Event, Layout, Length, Point, Rectangle, Shell, Widget, }; @@ -11,6 +11,8 @@ use crate::native::overlay::ContextMenuOverlay; pub use crate::style::context_menu::StyleSheet; +use super::overlay; + /// A modal content as an overlay. /// /// Can be used in combination with the [`Card`](crate::card::Card) @@ -44,8 +46,6 @@ where Renderer: iced_native::Renderer, Renderer::Theme: StyleSheet, { - /// Show the modal. - show_modal: bool, /// The underlying element. underlay: Element<'a, Message, Renderer>, /// The content of teh [`ModalOverlay`](ModalOverlay). @@ -76,12 +76,11 @@ where /// * the underlay [`Element`](iced_native::Element) on which this [`Modal`](Modal) /// will be wrapped around. /// * the content [`Element`](iced_native::Element) of the [`Modal`](Modal). - pub fn new(show_modal: bool, underlay: U, content: Content) -> Self + pub fn new(underlay: U, content: Content) -> Self where U: Into>, { ContextMenu { - show_modal, underlay: underlay.into(), content, backdrop: None, @@ -140,6 +139,8 @@ where self.underlay.as_widget().height() } + + fn layout( &self, renderer: &Renderer, @@ -158,6 +159,19 @@ where clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, ) -> event::Status { + + + if let Event::Mouse(mouse::Event::ButtonPressed(Button::Right)) = event { + let bounds = layout.bounds(); + + if bounds.contains(cursor_position) { + let s: &mut State = state.state.downcast_mut(); + s.show = !s.show; + return event::Status::Captured; + } + } + + self.underlay.as_widget_mut().on_event( &mut state.children[0], event, @@ -169,6 +183,16 @@ where ) } + fn state(&self) -> tree::State { + tree::State::new(State::new()) + } + + fn tag(&self) -> tree::Tag { + tree::Tag::of::() + } + + + fn mouse_interaction( &self, state: &Tree, @@ -177,6 +201,9 @@ where viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { + + + self.underlay.as_widget().mouse_interaction( &state.children[0], layout, @@ -213,7 +240,13 @@ where layout: Layout<'_>, renderer: &Renderer, ) -> Option> { - if !self.show_modal { + + + let s: &mut State = state.state.downcast_mut(); + + + + if !s.show { return self .underlay .as_widget_mut() @@ -232,6 +265,7 @@ where self.backdrop.clone(), self.esc.clone(), self.style, + s, ) .overlay(position), ) @@ -244,7 +278,9 @@ where renderer: &Renderer, operation: &mut dyn Operation, ) { - if self.show_modal { + let s: &mut State = state.state.downcast_mut(); + + if s.show { let content = (self.content)(); content.as_widget().diff(&mut state.children[1]); @@ -273,40 +309,17 @@ where } /// The state of the modal. #[derive(Debug, Default)] -pub struct State { +pub(crate) struct State{ /// The visibility of the [`Modal`](Modal) overlay. - show: bool, - /// The state of the content of the [`Modal`](Modal) overlay. - state: S, + pub show: bool, } -impl State { +impl State { /// Creates a new [`State`](State) containing the given state data. - pub const fn new(s: S) -> Self { + pub const fn new() -> Self { Self { show: false, - state: s, } } - /// Setting this to true shows the modal (the modal is open), false means - /// the modal is hidden (closed). - pub fn show(&mut self, b: bool) { - self.show = b; - } - - /// See if this modal will be shown or not. - pub const fn is_shown(&self) -> bool { - self.show - } - - /// Get a mutable reference to the inner state data. - pub fn inner_mut(&mut self) -> &mut S { - &mut self.state - } - - /// Get a reference to the inner state data. - pub const fn inner(&self) -> &S { - &self.state - } } diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs index 5d1775a1..186c4935 100644 --- a/src/native/overlay/context_menu.rs +++ b/src/native/overlay/context_menu.rs @@ -8,6 +8,7 @@ use iced_native::{ }; use iced_native::{widget::Tree, Element}; +use crate::context_menu; use crate::style::context_menu::StyleSheet; /// The overlay of the modal. @@ -19,7 +20,7 @@ where Renderer::Theme: StyleSheet, { /// The state of the [`ModalOverlay`](ModalOverlay). - state: &'a mut Tree, + tree: &'a mut Tree, /// The content of the [`ModalOverlay`](ModalOverlay). content: Element<'a, Message, Renderer>, /// The optional message that will be send when the user clicks on the backdrop. @@ -28,6 +29,8 @@ where esc: Option, /// The style of the [`ModalOverlay`](ModalOverlay). style: ::Style, + + state: &'a mut context_menu::State } impl<'a, Message, Renderer> ContextMenuOverlay<'a, Message, Renderer> @@ -37,22 +40,24 @@ where Renderer::Theme: StyleSheet, { /// Creates a new [`ModalOverlay`](ModalOverlay). - pub fn new( - state: &'a mut Tree, + pub(crate) fn new( + tree: &'a mut Tree, content: C, backdrop: Option, esc: Option, style: ::Style, + state: &'a mut context_menu::State ) -> Self where C: Into>, { ContextMenuOverlay { - state, + tree, content: content.into(), backdrop, esc, style, + state, } } @@ -114,7 +119,7 @@ where .map_or(event::Status::Ignored, |esc| match event { Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { if key_code == keyboard::KeyCode::Escape { - shell.publish(esc.to_owned()); + self.state.show = false; event::Status::Captured } else { event::Status::Ignored @@ -131,7 +136,7 @@ where if layout.bounds().contains(cursor_position) { event::Status::Ignored } else { - shell.publish(backdrop.to_owned()); + self.state.show = false; event::Status::Captured } } @@ -141,7 +146,7 @@ where match esc_status.merge(backdrop_status) { event::Status::Ignored => self.content.as_widget_mut().on_event( - self.state, + self.tree, event, layout .children() @@ -164,7 +169,7 @@ where renderer: &Renderer, ) -> mouse::Interaction { self.content.as_widget().mouse_interaction( - self.state, + self.tree, layout .children() .next() @@ -205,7 +210,7 @@ where // Modal self.content.as_widget().draw( - self.state, + self.tree, renderer, theme, style, From 187488a677b2a9e68609fac43d355c1344ce5d93 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Fri, 9 Jun 2023 04:11:48 +0200 Subject: [PATCH 03/13] Update main.rs --- examples/context_menu/src/main.rs | 67 ++++++++++--------------------- 1 file changed, 21 insertions(+), 46 deletions(-) diff --git a/examples/context_menu/src/main.rs b/examples/context_menu/src/main.rs index 329b9f4a..68ddbcb4 100644 --- a/examples/context_menu/src/main.rs +++ b/examples/context_menu/src/main.rs @@ -1,5 +1,5 @@ use iced::{ - widget::{container, Button, Container, Row, Text}, + widget::{container, column, Button, Container, Row, Text}, Alignment, Element, Sandbox, Settings, }; @@ -10,14 +10,16 @@ fn main() -> iced::Result { } #[derive(Clone, Debug)] -enum Message { - OpenModal, - CloseModal, +pub enum Message { + ButtonClicked, + Choice1, + Choice2, + Choice3, + Choice4, } #[derive(Default)] struct ContextMenuExample { - show_modal: bool, last_message: Option, } @@ -33,11 +35,7 @@ impl Sandbox for ContextMenuExample { } fn update(&mut self, message: Self::Message) { - match message { - Message::OpenModal => self.show_modal = true, - Message::CloseModal => self.show_modal = false, - } - self.last_message = Some(message) + self.last_message = Some(message); } fn view(&self) -> Element<'_, Self::Message> { @@ -45,13 +43,16 @@ impl Sandbox for ContextMenuExample { Row::new() .spacing(10) .align_items(Alignment::Center) - .push(Button::new(Text::new("Open modal!")).on_press(Message::OpenModal)) + .push(Button::new(Text::new("I'm a special button!")).on_press(Message::ButtonClicked)) .push(Text::new(format!( "Last message: {}", match self.last_message.as_ref() { Some(message) => match message { - Message::OpenModal => "Modal opened", - Message::CloseModal => "Modal closed", + Message::ButtonClicked => "button clicked", + Message::Choice1 => "choice 1", + Message::Choice2 => "choice 2", + Message::Choice3 => "choice 3", + Message::Choice4 => "choice 4", }, None => "None", } @@ -59,42 +60,16 @@ impl Sandbox for ContextMenuExample { ); ContextMenu::new(content, || { - container(my_component::MyComponent).into() + column( vec![ + iced::widget::button("Choice 1").on_press(Message::Choice1).into(), + iced::widget::button("Choice 2").on_press(Message::Choice2).into(), + iced::widget::button("Choice 3").on_press(Message::Choice3).into(), + iced::widget::button("Choice 4").on_press(Message::Choice4).into(), + ] + ).into() }) - .backdrop(Message::CloseModal) - .on_esc(Message::CloseModal) .into() } } -mod my_component { - use iced::{ - widget::{container, row, text}, - Element, - }; - use iced_lazy::{self, Component}; - pub struct MyComponent; - - impl Component for MyComponent { - type State = (); - type Event = (); - - fn update(&mut self, _state: &mut Self::State, _event: Self::Event) -> Option { - None - } - - fn view(&self, _state: &Self::State) -> Element { - container(row![text("Hello there")]).into() - } - } - - impl<'a, Message> From for Element<'a, Message, iced::Renderer> - where - Message: 'a, - { - fn from(my_component: MyComponent) -> Self { - iced_lazy::component(my_component) - } - } -} From 5044001583a38d84f30543f655ccf92923280ed2 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Fri, 9 Jun 2023 04:33:02 +0200 Subject: [PATCH 04/13] remove backdrop && esc --- examples/context_menu/src/main.rs | 39 ++++++++++++++-------- src/native/context_menu.rs | 28 +--------------- src/native/overlay/context_menu.rs | 52 ++++++++++++------------------ 3 files changed, 47 insertions(+), 72 deletions(-) diff --git a/examples/context_menu/src/main.rs b/examples/context_menu/src/main.rs index 68ddbcb4..f0959867 100644 --- a/examples/context_menu/src/main.rs +++ b/examples/context_menu/src/main.rs @@ -1,6 +1,6 @@ use iced::{ - widget::{container, column, Button, Container, Row, Text}, - Alignment, Element, Sandbox, Settings, + widget::{column, Button, Container, Row, Text}, + Alignment, Element, Length, Sandbox, Settings, }; use iced_aw::ContextMenu; @@ -39,11 +39,14 @@ impl Sandbox for ContextMenuExample { } fn view(&self) -> Element<'_, Self::Message> { - let content = Container::new( + let underlay = Container::new( Row::new() .spacing(10) .align_items(Alignment::Center) - .push(Button::new(Text::new("I'm a special button!")).on_press(Message::ButtonClicked)) + .push( + Button::new(Text::new("I'm a special button!")) + .on_press(Message::ButtonClicked), + ) .push(Text::new(format!( "Last message: {}", match self.last_message.as_ref() { @@ -59,17 +62,25 @@ impl Sandbox for ContextMenuExample { ))), ); - ContextMenu::new(content, || { - column( vec![ - iced::widget::button("Choice 1").on_press(Message::Choice1).into(), - iced::widget::button("Choice 2").on_press(Message::Choice2).into(), - iced::widget::button("Choice 3").on_press(Message::Choice3).into(), - iced::widget::button("Choice 4").on_press(Message::Choice4).into(), - ] - ).into() + ContextMenu::new(underlay, || { + column(vec![ + iced::widget::button("Choice 1") + .on_press(Message::Choice1) + .into(), + iced::widget::button("Choice 2") + .on_press(Message::Choice2) + .into(), + iced::widget::button("Choice 3") + .on_press(Message::Choice3) + .into(), + iced::widget::button("Choice 4") + .on_press(Message::Choice4) + .into(), + ]) + .width(Length::Shrink) + .height(Length::Shrink) + .into() }) .into() } } - - diff --git a/src/native/context_menu.rs b/src/native/context_menu.rs index d280174d..b8639289 100644 --- a/src/native/context_menu.rs +++ b/src/native/context_menu.rs @@ -11,7 +11,7 @@ use crate::native::overlay::ContextMenuOverlay; pub use crate::style::context_menu::StyleSheet; -use super::overlay; + /// A modal content as an overlay. /// @@ -50,10 +50,6 @@ where underlay: Element<'a, Message, Renderer>, /// The content of teh [`ModalOverlay`](ModalOverlay). content: Content, - /// The optional message that will be send when the user clicked on the backdrop. - backdrop: Option, - /// The optional message that will be send when the ESC key was pressed. - esc: Option, /// The style of the [`ModalOverlay`](ModalOverlay). style: ::Style, } @@ -83,29 +79,11 @@ where ContextMenu { underlay: underlay.into(), content, - backdrop: None, - esc: None, style: ::Style::default(), } } - /// Sets the message that will be produced when the backdrop of the - /// [`Modal`](Modal) is clicked. - #[must_use] - pub fn backdrop(mut self, message: Message) -> Self { - self.backdrop = Some(message); - self - } - /// Sets the message that will be produced when the Escape Key is - /// pressed when the modal is open. - /// - /// This can be used to close the modal on ESC. - #[must_use] - pub fn on_esc(mut self, message: Message) -> Self { - self.esc = Some(message); - self - } /// Sets the style of the [`Modal`](Modal). #[must_use] @@ -202,8 +180,6 @@ where renderer: &Renderer, ) -> mouse::Interaction { - - self.underlay.as_widget().mouse_interaction( &state.children[0], layout, @@ -262,8 +238,6 @@ where ContextMenuOverlay::new( &mut state.children[1], content, - self.backdrop.clone(), - self.esc.clone(), self.style, s, ) diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs index 186c4935..527281c3 100644 --- a/src/native/overlay/context_menu.rs +++ b/src/native/overlay/context_menu.rs @@ -23,10 +23,6 @@ where tree: &'a mut Tree, /// The content of the [`ModalOverlay`](ModalOverlay). content: Element<'a, Message, Renderer>, - /// The optional message that will be send when the user clicks on the backdrop. - backdrop: Option, - /// The optional message that will be send when the ESC key was pressed. - esc: Option, /// The style of the [`ModalOverlay`](ModalOverlay). style: ::Style, @@ -43,8 +39,6 @@ where pub(crate) fn new( tree: &'a mut Tree, content: C, - backdrop: Option, - esc: Option, style: ::Style, state: &'a mut context_menu::State ) -> Self @@ -54,8 +48,6 @@ where ContextMenuOverlay { tree, content: content.into(), - backdrop, - esc, style, state, } @@ -112,39 +104,37 @@ where clipboard: &mut dyn Clipboard, shell: &mut Shell, ) -> event::Status { - // TODO clean this up - let esc_status = self - .esc - .as_ref() - .map_or(event::Status::Ignored, |esc| match event { - Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { - if key_code == keyboard::KeyCode::Escape { - self.state.show = false; - event::Status::Captured - } else { - event::Status::Ignored - } - } - _ => event::Status::Ignored, - }); - let backdrop_status = self.backdrop.as_ref().zip(layout.children().next()).map_or( - event::Status::Ignored, - |(backdrop, layout)| match event { - Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + //println!("on_event !"); + + let status = match event { + Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { + if key_code == keyboard::KeyCode::Escape { + self.state.show = false; + println!("exit!"); + event::Status::Captured + } else { + event::Status::Ignored + } + } + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) | Event::Touch(touch::Event::FingerPressed { .. }) => { if layout.bounds().contains(cursor_position) { + println!("ignore in bound!"); + event::Status::Ignored } else { self.state.show = false; + println!("exit!"); event::Status::Captured } } - _ => event::Status::Ignored, - }, - ); + _ => event::Status::Ignored, + }; + + - match esc_status.merge(backdrop_status) { + match status { event::Status::Ignored => self.content.as_widget_mut().on_event( self.tree, event, From 4a4462dd91472ee84b3feef508a2b8c81fc8b905 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Fri, 9 Jun 2023 04:39:40 +0200 Subject: [PATCH 05/13] Update context_menu.rs --- src/style/context_menu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/style/context_menu.rs b/src/style/context_menu.rs index da5283ab..73278c4c 100644 --- a/src/style/context_menu.rs +++ b/src/style/context_menu.rs @@ -46,7 +46,7 @@ impl StyleSheet for Theme { Appearance { background: Color { - a: palette.background.base.color.a * 0.5, + a: 0f32, ..palette.background.base.color } .into(), From 092a76f6a64cd680a80abfb6dd5fb310e7aad385 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sat, 10 Jun 2023 22:00:18 +0200 Subject: [PATCH 06/13] Update context_menu.rs --- src/native/overlay/context_menu.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs index 527281c3..025ca594 100644 --- a/src/native/overlay/context_menu.rs +++ b/src/native/overlay/context_menu.rs @@ -7,6 +7,7 @@ use iced_native::{ Layout, Point, Shell, Size, }; use iced_native::{widget::Tree, Element}; +use iced_native::event::Status; use crate::context_menu; use crate::style::context_menu::StyleSheet; @@ -121,7 +122,8 @@ where | Event::Touch(touch::Event::FingerPressed { .. }) => { if layout.bounds().contains(cursor_position) { println!("ignore in bound!"); - + println!("cursor_position: {:?}", cursor_position); + println!("layout.bounds(): {:?}", layout.bounds()); event::Status::Ignored } else { self.state.show = false; From a4bbe7500073ead2efd8c785574fe67bacb81ce4 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sun, 11 Jun 2023 16:53:17 +0200 Subject: [PATCH 07/13] fix on_event overlay --- src/native/overlay/context_menu.rs | 57 ++++++++++++++---------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs index 025ca594..2b941158 100644 --- a/src/native/overlay/context_menu.rs +++ b/src/native/overlay/context_menu.rs @@ -55,7 +55,7 @@ where } /// Turn this [`ModalOverlay`] into an overlay - /// [`Element`](iced_native::overlay::Element). + /// [`Element`](overlay::Element). pub fn overlay(self, position: Point) -> overlay::Element<'a, Message, Renderer> { overlay::Element::new(position, Box::new(self)) } @@ -71,7 +71,7 @@ where fn layout( &self, renderer: &Renderer, - bounds: iced_graphics::Size, + bounds: Size, position: Point, ) -> iced_native::layout::Node { let limits = Limits::new(Size::ZERO, bounds); @@ -104,40 +104,37 @@ where renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell, - ) -> event::Status { + ) -> Status { - //println!("on_event !"); - - let status = match event { - Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { - if key_code == keyboard::KeyCode::Escape { - self.state.show = false; - println!("exit!"); - event::Status::Captured - } else { - event::Status::Ignored - } - } - Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) - | Event::Touch(touch::Event::FingerPressed { .. }) => { - if layout.bounds().contains(cursor_position) { - println!("ignore in bound!"); - println!("cursor_position: {:?}", cursor_position); - println!("layout.bounds(): {:?}", layout.bounds()); - event::Status::Ignored - } else { + // i kept child because we will need it if we want to adapt menu here + let status = if let Some(child) = layout.children().next() { + match event { + Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { + if key_code == keyboard::KeyCode::Escape { self.state.show = false; - println!("exit!"); - event::Status::Captured + Status::Captured + } else { + Status::Ignored } } - _ => event::Status::Ignored, + + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) + | Event::Touch(touch::Event::FingerPressed { .. }) => { + self.state.show = false; + Status::Captured + } + _ => Status::Ignored + + } + } else { + Status::Ignored }; match status { - event::Status::Ignored => self.content.as_widget_mut().on_event( + Status::Ignored => self.content.as_widget_mut().on_event( self.tree, event, layout @@ -149,7 +146,7 @@ where clipboard, shell, ), - event::Status::Captured => event::Status::Captured, + Status::Captured => Status::Captured, } } @@ -176,8 +173,8 @@ where &self, renderer: &mut Renderer, theme: &Renderer::Theme, - style: &iced_native::renderer::Style, - layout: iced_native::Layout<'_>, + style: &renderer::Style, + layout: Layout<'_>, cursor_position: Point, ) { let bounds = layout.bounds(); From 7fb69844ffba018e3df785239f7902f2cd32088a Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sun, 11 Jun 2023 16:59:17 +0200 Subject: [PATCH 08/13] idea fix --- src/native/context_menu.rs | 134 ++++++++++++++--------------- src/native/overlay/context_menu.rs | 83 +++++++++--------- 2 files changed, 108 insertions(+), 109 deletions(-) diff --git a/src/native/context_menu.rs b/src/native/context_menu.rs index b8639289..9354f95b 100644 --- a/src/native/context_menu.rs +++ b/src/native/context_menu.rs @@ -69,9 +69,9 @@ where /// /// It expects: /// * if the overlay of the date picker is visible. - /// * the underlay [`Element`](iced_native::Element) on which this [`Modal`](Modal) + /// * the underlay [`Element`](Element) on which this [`Modal`](Modal) /// will be wrapped around. - /// * the content [`Element`](iced_native::Element) of the [`Modal`](Modal). + /// * the content [`Element`](Element) of the [`Modal`](Modal). pub fn new(underlay: U, content: Content) -> Self where U: Into>, @@ -101,14 +101,6 @@ where Renderer: 'a + iced_native::Renderer, Renderer::Theme: StyleSheet, { - fn children(&self) -> Vec { - vec![Tree::new(&self.underlay), Tree::new(&(self.content)())] - } - - fn diff(&self, tree: &mut Tree) { - tree.diff_children(&[&self.underlay, &(self.content)()]); - } - fn width(&self) -> Length { self.underlay.as_widget().width() } @@ -117,8 +109,6 @@ where self.underlay.as_widget().height() } - - fn layout( &self, renderer: &Renderer, @@ -127,6 +117,68 @@ where self.underlay.as_widget().layout(renderer, limits) } + fn draw( + &self, + state: &Tree, + renderer: &mut Renderer, + theme: &Renderer::Theme, + style: &iced_native::renderer::Style, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + ) { + self.underlay.as_widget().draw( + &state.children[0], + renderer, + theme, + style, + layout, + cursor_position, + viewport, + ); + } + + + fn tag(&self) -> tree::Tag { + tree::Tag::of::() + } + + fn state(&self) -> tree::State { + tree::State::new(State::new()) + } + + fn children(&self) -> Vec { + vec![Tree::new(&self.underlay), Tree::new(&(self.content)())] + } + + fn diff(&self, tree: &mut Tree) { + tree.diff_children(&[&self.underlay, &(self.content)()]); + } + + + fn operate<'b>( + &'b self, + state: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation, + ) { + let s: &mut State = state.state.downcast_mut(); + + if s.show { + let content = (self.content)(); + content.as_widget().diff(&mut state.children[1]); + + content + .as_widget() + .operate(&mut state.children[1], layout, renderer, operation); + } else { + self.underlay + .as_widget() + .operate(&mut state.children[0], layout, renderer, operation); + } + } + fn on_event( &mut self, state: &mut Tree, @@ -161,16 +213,6 @@ where ) } - fn state(&self) -> tree::State { - tree::State::new(State::new()) - } - - fn tag(&self) -> tree::Tag { - tree::Tag::of::() - } - - - fn mouse_interaction( &self, state: &Tree, @@ -189,27 +231,6 @@ where ) } - fn draw( - &self, - state: &iced_native::widget::Tree, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &iced_native::renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - ) { - self.underlay.as_widget().draw( - &state.children[0], - renderer, - theme, - style, - layout, - cursor_position, - viewport, - ); - } - fn overlay<'b>( &'b mut self, state: &'b mut Tree, @@ -217,10 +238,10 @@ where renderer: &Renderer, ) -> Option> { - + let s: &mut State = state.state.downcast_mut(); - + if !s.show { return self @@ -244,29 +265,6 @@ where .overlay(position), ) } - - fn operate<'b>( - &'b self, - state: &'b mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn Operation, - ) { - let s: &mut State = state.state.downcast_mut(); - - if s.show { - let content = (self.content)(); - content.as_widget().diff(&mut state.children[1]); - - content - .as_widget() - .operate(&mut state.children[1], layout, renderer, operation); - } else { - self.underlay - .as_widget() - .operate(&mut state.children[0], layout, renderer, operation); - } - } } impl<'a, Content, Message, Renderer> From> diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs index 2b941158..d9754c7e 100644 --- a/src/native/overlay/context_menu.rs +++ b/src/native/overlay/context_menu.rs @@ -96,6 +96,47 @@ where iced_native::layout::Node::with_children(max_size, vec![content]) } + fn draw( + &self, + renderer: &mut Renderer, + theme: &Renderer::Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor_position: Point, + ) { + let bounds = layout.bounds(); + + let style_sheet = theme.active(self.style); + + // Background + renderer.fill_quad( + renderer::Quad { + bounds, + border_radius: (0.0).into(), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }, + style_sheet.background, + ); + + let content_layout = layout + .children() + .next() + .expect("Native: Layout should have a content layout."); + + // Modal + self.content.as_widget().draw( + self.tree, + renderer, + theme, + style, + content_layout, + cursor_position, + &bounds, + ); + } + + #[allow(unused_variables)] fn on_event( &mut self, event: Event, @@ -131,7 +172,7 @@ where Status::Ignored }; - + match status { Status::Ignored => self.content.as_widget_mut().on_event( @@ -168,44 +209,4 @@ where renderer, ) } - - fn draw( - &self, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - ) { - let bounds = layout.bounds(); - - let style_sheet = theme.active(self.style); - - // Background - renderer.fill_quad( - renderer::Quad { - bounds, - border_radius: (0.0).into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, - }, - style_sheet.background, - ); - - let content_layout = layout - .children() - .next() - .expect("Native: Layout should have a content layout."); - - // Modal - self.content.as_widget().draw( - self.tree, - renderer, - theme, - style, - content_layout, - cursor_position, - &bounds, - ); - } } From 4658b82d3b08c49565f2c42adaefde43368c6f55 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sun, 11 Jun 2023 19:46:55 +0200 Subject: [PATCH 09/13] overlay position relative cursor bug: on_press button not trigger in overlay --- .vscode/launch.json | 18 ++++++++++++++++ examples/context_menu/src/main.rs | 26 +++++++++++------------ src/native/context_menu.rs | 6 ++++-- src/native/overlay/context_menu.rs | 34 ++++++++++++------------------ 4 files changed, 48 insertions(+), 36 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 7602021b..3bfbf7b3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -328,5 +328,23 @@ "args": [], "cwd": "${workspaceFolder}" }, + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'context_menu'", + "cargo": { + "args": [ + "build", + "--bin=context_menu", + "--package=context_menu" + ], + "filter": { + "name": "context_menu", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, ] } \ No newline at end of file diff --git a/examples/context_menu/src/main.rs b/examples/context_menu/src/main.rs index f0959867..36f94a43 100644 --- a/examples/context_menu/src/main.rs +++ b/examples/context_menu/src/main.rs @@ -2,7 +2,10 @@ use iced::{ widget::{column, Button, Container, Row, Text}, Alignment, Element, Length, Sandbox, Settings, }; +use iced::alignment::Horizontal; +use iced::theme; +use iced::widget::text; use iced_aw::ContextMenu; fn main() -> iced::Result { @@ -31,20 +34,22 @@ impl Sandbox for ContextMenuExample { } fn title(&self) -> String { - String::from("Modal example") + String::from("ContextMenu example") } fn update(&mut self, message: Self::Message) { + println!("Update: {:?}", message); + self.last_message = Some(message); } fn view(&self) -> Element<'_, Self::Message> { - let underlay = Container::new( - Row::new() + let underlay = + Container::new(Row::new() .spacing(10) .align_items(Alignment::Center) .push( - Button::new(Text::new("I'm a special button!")) + Button::new(Text::new("right click me!")) .on_press(Message::ButtonClicked), ) .push(Text::new(format!( @@ -59,10 +64,9 @@ impl Sandbox for ContextMenuExample { }, None => "None", } - ))), - ); + )))); - ContextMenu::new(underlay, || { + ContextMenu::new(underlay, || { column(vec![ iced::widget::button("Choice 1") .on_press(Message::Choice1) @@ -76,11 +80,7 @@ impl Sandbox for ContextMenuExample { iced::widget::button("Choice 4") .on_press(Message::Choice4) .into(), - ]) - .width(Length::Shrink) - .height(Length::Shrink) - .into() - }) - .into() + ]).into() + }).into() } } diff --git a/src/native/context_menu.rs b/src/native/context_menu.rs index 9354f95b..3ec7ec3f 100644 --- a/src/native/context_menu.rs +++ b/src/native/context_menu.rs @@ -196,6 +196,7 @@ where if bounds.contains(cursor_position) { let s: &mut State = state.state.downcast_mut(); + s.cursor_position = cursor_position; s.show = !s.show; return event::Status::Captured; } @@ -250,8 +251,7 @@ where .overlay(&mut state.children[0], layout, renderer); } - let bounds = layout.bounds(); - let position = Point::new(bounds.x, bounds.y); + let position = s.cursor_position.clone(); let content = (self.content)(); content.as_widget().diff(&mut state.children[1]); @@ -284,6 +284,7 @@ where pub(crate) struct State{ /// The visibility of the [`Modal`](Modal) overlay. pub show: bool, + pub cursor_position: Point, } impl State { @@ -291,6 +292,7 @@ impl State { pub const fn new() -> Self { Self { show: false, + cursor_position: Point::ORIGIN } } diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs index d9754c7e..c41999f5 100644 --- a/src/native/overlay/context_menu.rs +++ b/src/native/overlay/context_menu.rs @@ -1,9 +1,8 @@ //! A modal for showing elements as an overlay on top of another. //! //! *This API requires the following crate features to be activated: modal* -use iced_graphics::Vector; use iced_native::{ - event, keyboard, layout::Limits, mouse, overlay, renderer, touch, Clipboard, Color, Event, + keyboard, layout::Limits, mouse, overlay, renderer, touch, Clipboard, Color, Event, Layout, Point, Shell, Size, }; use iced_native::{widget::Tree, Element}; @@ -75,22 +74,9 @@ where position: Point, ) -> iced_native::layout::Node { let limits = Limits::new(Size::ZERO, bounds); - - let mut content = self.content.as_widget().layout(renderer, &limits); - - // Center position let max_size = limits.max(); - let container_half_width = max_size.width / 2.0; - let container_half_height = max_size.height / 2.0; - let content_half_width = content.bounds().width / 2.0; - let content_half_height = content.bounds().height / 2.0; - - let position = position - + Vector::new( - container_half_width - content_half_width, - container_half_height - content_half_height, - ); + let mut content = self.content.as_widget().layout(renderer, &limits); content.move_to(position); iced_native::layout::Node::with_children(max_size, vec![content]) @@ -147,7 +133,6 @@ where shell: &mut Shell, ) -> Status { - // i kept child because we will need it if we want to adapt menu here let status = if let Some(child) = layout.children().next() { match event { Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { @@ -163,7 +148,12 @@ where | Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) | Event::Touch(touch::Event::FingerPressed { .. }) => { self.state.show = false; - Status::Captured + + if child.bounds().contains(cursor_position) { + Status::Ignored // ignore this if there are buttons inside overlay + } else { + Status::Captured + } } _ => Status::Ignored @@ -172,9 +162,9 @@ where Status::Ignored }; + //println!("status: {:?}", status); - - match status { + let s = match status { Status::Ignored => self.content.as_widget_mut().on_event( self.tree, event, @@ -188,7 +178,9 @@ where shell, ), Status::Captured => Status::Captured, - } + }; + println!("{:?}", s); + s } fn mouse_interaction( From 27440aa748dae7151fa8f465733dea6bb0c529bc Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sun, 11 Jun 2023 20:36:51 +0200 Subject: [PATCH 10/13] fix --- examples/context_menu/src/main.rs | 5 +-- src/native/overlay/context_menu.rs | 62 +++++++++++++++--------------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/examples/context_menu/src/main.rs b/examples/context_menu/src/main.rs index 36f94a43..f19dadb7 100644 --- a/examples/context_menu/src/main.rs +++ b/examples/context_menu/src/main.rs @@ -1,11 +1,8 @@ use iced::{ widget::{column, Button, Container, Row, Text}, - Alignment, Element, Length, Sandbox, Settings, + Alignment, Element, Sandbox, Settings, }; -use iced::alignment::Horizontal; -use iced::theme; -use iced::widget::text; use iced_aw::ContextMenu; fn main() -> iced::Result { diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs index c41999f5..0e873198 100644 --- a/src/native/overlay/context_menu.rs +++ b/src/native/overlay/context_menu.rs @@ -122,7 +122,6 @@ where ); } - #[allow(unused_variables)] fn on_event( &mut self, event: Event, @@ -133,54 +132,55 @@ where shell: &mut Shell, ) -> Status { - let status = if let Some(child) = layout.children().next() { - match event { - Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { - if key_code == keyboard::KeyCode::Escape { - self.state.show = false; - Status::Captured - } else { - Status::Ignored - } - } + let layout_children = layout.children().next().expect("Native: Layout should have a content layout."); - Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) - | Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) - | Event::Touch(touch::Event::FingerPressed { .. }) => { + let status = match event { + Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { + if key_code == keyboard::KeyCode::Escape { self.state.show = false; + Status::Captured + } else { + Status::Ignored + } + } - if child.bounds().contains(cursor_position) { - Status::Ignored // ignore this if there are buttons inside overlay - } else { - Status::Captured - } + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) + | Event::Touch(touch::Event::FingerPressed { .. })=> { + if layout_children.bounds().contains(cursor_position) { + Status::Ignored + } else { + self.state.show = false; + Status::Captured } - _ => Status::Ignored + } + Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => { + // close when released because because button send message on release + self.state.show = false; + if layout_children.bounds().contains(cursor_position) { + Status::Ignored + } else { + Status::Captured + } } - } else { - Status::Ignored + + _ => Status::Ignored }; - //println!("status: {:?}", status); - let s = match status { + match status { Status::Ignored => self.content.as_widget_mut().on_event( self.tree, event, - layout - .children() - .next() - .expect("Native: Layout should have a content layout."), + layout_children, cursor_position, renderer, clipboard, shell, ), Status::Captured => Status::Captured, - }; - println!("{:?}", s); - s + } } fn mouse_interaction( From 63bf7361bfed5a7d971e68af723b2ac9c51bcf1a Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sun, 11 Jun 2023 21:00:56 +0200 Subject: [PATCH 11/13] add docs + clean code with idea --- examples/context_menu/src/main.rs | 8 +- src/native/context_menu.rs | 143 +++++++++++++---------------- src/native/overlay/context_menu.rs | 59 ++++++------ src/style/context_menu.rs | 14 +-- 4 files changed, 102 insertions(+), 122 deletions(-) diff --git a/examples/context_menu/src/main.rs b/examples/context_menu/src/main.rs index f19dadb7..f083f1dc 100644 --- a/examples/context_menu/src/main.rs +++ b/examples/context_menu/src/main.rs @@ -1,6 +1,6 @@ use iced::{ - widget::{column, Button, Container, Row, Text}, - Alignment, Element, Sandbox, Settings, + Alignment, + Element, Sandbox, Settings, widget::{Button, column, Container, Row, Text}, }; use iced_aw::ContextMenu; @@ -35,8 +35,6 @@ impl Sandbox for ContextMenuExample { } fn update(&mut self, message: Self::Message) { - println!("Update: {:?}", message); - self.last_message = Some(message); } @@ -63,7 +61,7 @@ impl Sandbox for ContextMenuExample { } )))); - ContextMenu::new(underlay, || { + ContextMenu::new(underlay, || { column(vec![ iced::widget::button("Choice 1") .on_press(Message::Choice1) diff --git a/src/native/context_menu.rs b/src/native/context_menu.rs index 3ec7ec3f..d2091e65 100644 --- a/src/native/context_menu.rs +++ b/src/native/context_menu.rs @@ -1,91 +1,79 @@ -//! A modal for showing elements as an overlay on top of another. +//! A context menu for showing actions on right click. //! -//! *This API requires the following crate features to be activated: modal* use iced_native::{ - event, mouse::{self, Button}, - widget::{Operation, Tree, tree}, - Clipboard, Element, Event, Layout, Length, Point, Rectangle, Shell, Widget, + Clipboard, Element, + event, + Event, Layout, Length, mouse::{self, Button}, Point, Rectangle, Shell, widget::{Operation, Tree, tree}, Widget, }; use crate::native::overlay::ContextMenuOverlay; - pub use crate::style::context_menu::StyleSheet; - - -/// A modal content as an overlay. +/// A context menu /// -/// Can be used in combination with the [`Card`](crate::card::Card) -/// widget to form dialog elements. /// /// # Example /// ``` /// # use iced_native::renderer::Null; /// # use iced_native::widget::Text; -/// # use iced_aw::native::modal; +/// # use iced_native::widget::Button; +/// # use iced_aw::native::context_menu; /// # -/// # pub type Modal<'a, Content, Message> -/// # = modal::Modal<'a, Message, Content, Null>; +/// # pub type ContextMenu<'a, Content, Message> +/// # = context_menu::ContextMenu<'a, Message, Content, Null>; /// #[derive(Debug, Clone)] /// enum Message { -/// CloseModal, +/// Action1, /// } /// -/// let modal = Modal::new( -/// true, -/// Text::new("Underlay"), -/// || Text::new("Overlay").into() -/// ) -/// .backdrop(Message::CloseModal); +/// let underlay = Text::new("right click me"); +/// +/// let cm = ContextMenu::new( +/// underlay, +/// || Button::new("action1").on_press(Message::Action1).into() +/// ); /// ``` #[allow(missing_debug_implementations)] -pub struct ContextMenu<'a, Content, Message, Renderer> -where - Content: Fn() -> Element<'a, Message, Renderer>, - Message: Clone, - Renderer: iced_native::Renderer, - Renderer::Theme: StyleSheet, +pub struct ContextMenu<'a, Overlay, Message, Renderer> + where + Overlay: Fn() -> Element<'a, Message, Renderer>, + Message: Clone, + Renderer: iced_native::Renderer, + Renderer::Theme: StyleSheet, { /// The underlying element. underlay: Element<'a, Message, Renderer>, - /// The content of teh [`ModalOverlay`](ModalOverlay). - content: Content, - /// The style of the [`ModalOverlay`](ModalOverlay). + /// The content of [`ContextMenuOverlay`](ContextMenuOverlay). + overlay: Overlay, + /// The style of the [`ContextMenu`](ContextMenu). style: ::Style, } -impl<'a, Content, Message, Renderer> ContextMenu<'a, Content, Message, Renderer> -where - Content: Fn() -> Element<'a, Message, Renderer>, - Message: Clone, - Renderer: iced_native::Renderer, - Renderer::Theme: StyleSheet, +impl<'a, Overlay, Message, Renderer> ContextMenu<'a, Overlay, Message, Renderer> + where + Overlay: Fn() -> Element<'a, Message, Renderer>, + Message: Clone, + Renderer: iced_native::Renderer, + Renderer::Theme: StyleSheet, { - /// Creates a new [`Modal`](Modal) wrapping the underlying element to - /// show some content as an overlay. + /// Creates a new [`ContextMenu`](ContextMenu) /// - /// `state` is the content's state, assigned at the creation of the - /// overlying content. + /// `underlay`: The underlying element. /// - /// It expects: - /// * if the overlay of the date picker is visible. - /// * the underlay [`Element`](Element) on which this [`Modal`](Modal) - /// will be wrapped around. - /// * the content [`Element`](Element) of the [`Modal`](Modal). - pub fn new(underlay: U, content: Content) -> Self - where - U: Into>, + /// `overlay`: The content of [`ContextMenuOverlay`](ContextMenuOverlay) which will be displayed when `underlay` is clicked. + pub fn new(underlay: U, overlay: Overlay) -> Self + where + U: Into>, { ContextMenu { underlay: underlay.into(), - content, + overlay, style: ::Style::default(), } } - - /// Sets the style of the [`Modal`](Modal). + /// Sets the style of the [`ContextMenu`](ContextMenu). #[must_use] pub fn style(mut self, style: ::Style) -> Self { self.style = style; @@ -94,12 +82,12 @@ where } impl<'a, Content, Message, Renderer> Widget - for ContextMenu<'a, Content, Message, Renderer> -where - Content: 'a + Fn() -> Element<'a, Message, Renderer>, - Message: 'a + Clone, - Renderer: 'a + iced_native::Renderer, - Renderer::Theme: StyleSheet, +for ContextMenu<'a, Content, Message, Renderer> + where + Content: 'a + Fn() -> Element<'a, Message, Renderer>, + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.underlay.as_widget().width() @@ -148,11 +136,11 @@ where } fn children(&self) -> Vec { - vec![Tree::new(&self.underlay), Tree::new(&(self.content)())] + vec![Tree::new(&self.underlay), Tree::new(&(self.overlay)())] } fn diff(&self, tree: &mut Tree) { - tree.diff_children(&[&self.underlay, &(self.content)()]); + tree.diff_children(&[&self.underlay, &(self.overlay)()]); } @@ -165,8 +153,8 @@ where ) { let s: &mut State = state.state.downcast_mut(); - if s.show { - let content = (self.content)(); + if s.show { + let content = (self.overlay)(); content.as_widget().diff(&mut state.children[1]); content @@ -189,8 +177,6 @@ where clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, ) -> event::Status { - - if let Event::Mouse(mouse::Event::ButtonPressed(Button::Right)) = event { let bounds = layout.bounds(); @@ -222,7 +208,6 @@ where viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { - self.underlay.as_widget().mouse_interaction( &state.children[0], layout, @@ -238,12 +223,9 @@ where layout: Layout<'_>, renderer: &Renderer, ) -> Option> { - - let s: &mut State = state.state.downcast_mut(); - if !s.show { return self .underlay @@ -252,7 +234,7 @@ where } let position = s.cursor_position.clone(); - let content = (self.content)(); + let content = (self.overlay)(); content.as_widget().diff(&mut state.children[1]); Some( @@ -262,28 +244,30 @@ where self.style, s, ) - .overlay(position), + .overlay(position), ) } } impl<'a, Content, Message, Renderer> From> - for Element<'a, Message, Renderer> -where - Content: 'a + Fn() -> Element<'a, Message, Renderer>, - Message: 'a + Clone, - Renderer: 'a + iced_native::Renderer, - Renderer::Theme: StyleSheet, +for Element<'a, Message, Renderer> + where + Content: 'a + Fn() -> Element<'a, Message, Renderer>, + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, { fn from(modal: ContextMenu<'a, Content, Message, Renderer>) -> Self { Element::new(modal) } } -/// The state of the modal. + +/// The state of the context_menu. #[derive(Debug, Default)] -pub(crate) struct State{ - /// The visibility of the [`Modal`](Modal) overlay. +pub(crate) struct State { + /// The visibility of the [`ContextMenu`](ContextMenu) overlay. pub show: bool, + /// Use for showing the overlay where the click was made. pub cursor_position: Point, } @@ -292,8 +276,7 @@ impl State { pub const fn new() -> Self { Self { show: false, - cursor_position: Point::ORIGIN + cursor_position: Point::ORIGIN, } } - } diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs index 0e873198..75b9ae27 100644 --- a/src/native/overlay/context_menu.rs +++ b/src/native/overlay/context_menu.rs @@ -1,49 +1,49 @@ //! A modal for showing elements as an overlay on top of another. //! -//! *This API requires the following crate features to be activated: modal* +//! *This API requires the following crate features to be activated: context_menu* use iced_native::{ - keyboard, layout::Limits, mouse, overlay, renderer, touch, Clipboard, Color, Event, - Layout, Point, Shell, Size, + Clipboard, Color, Event, keyboard, Layout, layout::Limits, mouse, overlay, Point, + renderer, Shell, Size, touch, }; -use iced_native::{widget::Tree, Element}; +use iced_native::{Element, widget::Tree}; use iced_native::event::Status; use crate::context_menu; use crate::style::context_menu::StyleSheet; -/// The overlay of the modal. +/// The overlay of the [`ContextMenu`](crate::native::ContextMenu). #[allow(missing_debug_implementations)] pub struct ContextMenuOverlay<'a, Message, Renderer> -where - Message: 'a + Clone, - Renderer: 'a + iced_native::Renderer, - Renderer::Theme: StyleSheet, + where + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, { - /// The state of the [`ModalOverlay`](ModalOverlay). + /// The state of the [`ContextMenuOverlay`](ContextMenuOverlay). tree: &'a mut Tree, - /// The content of the [`ModalOverlay`](ModalOverlay). + /// The content of the [`ContextMenuOverlay`](ContextMenuOverlay). content: Element<'a, Message, Renderer>, - /// The style of the [`ModalOverlay`](ModalOverlay). + /// The style of the [`ContextMenuOverlay`](ContextMenuOverlay). style: ::Style, - - state: &'a mut context_menu::State + /// The state shared between [`ContextMenu`](crate::native::ContextMenu) and [`ContextMenuOverlay`](ContextMenuOverlay). + state: &'a mut context_menu::State, } impl<'a, Message, Renderer> ContextMenuOverlay<'a, Message, Renderer> -where - Message: Clone, - Renderer: iced_native::Renderer, - Renderer::Theme: StyleSheet, + where + Message: Clone, + Renderer: iced_native::Renderer, + Renderer::Theme: StyleSheet, { - /// Creates a new [`ModalOverlay`](ModalOverlay). + /// Creates a new [`ContextMenuOverlay`](ContextMenuOverlay). pub(crate) fn new( tree: &'a mut Tree, content: C, style: ::Style, - state: &'a mut context_menu::State + state: &'a mut context_menu::State, ) -> Self - where - C: Into>, + where + C: Into>, { ContextMenuOverlay { tree, @@ -53,7 +53,7 @@ where } } - /// Turn this [`ModalOverlay`] into an overlay + /// Turn this [`ContextMenuOverlay`] into an overlay /// [`Element`](overlay::Element). pub fn overlay(self, position: Point) -> overlay::Element<'a, Message, Renderer> { overlay::Element::new(position, Box::new(self)) @@ -61,11 +61,11 @@ where } impl<'a, Message, Renderer> iced_native::Overlay - for ContextMenuOverlay<'a, Message, Renderer> -where - Message: 'a + Clone, - Renderer: 'a + iced_native::Renderer, - Renderer::Theme: StyleSheet, +for ContextMenuOverlay<'a, Message, Renderer> + where + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, { fn layout( &self, @@ -131,7 +131,6 @@ where clipboard: &mut dyn Clipboard, shell: &mut Shell, ) -> Status { - let layout_children = layout.children().next().expect("Native: Layout should have a content layout."); let status = match event { @@ -146,7 +145,7 @@ where Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) | Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) - | Event::Touch(touch::Event::FingerPressed { .. })=> { + | Event::Touch(touch::Event::FingerPressed { .. }) => { if layout_children.bounds().contains(cursor_position) { Status::Ignored } else { diff --git a/src/style/context_menu.rs b/src/style/context_menu.rs index 73278c4c..4836e539 100644 --- a/src/style/context_menu.rs +++ b/src/style/context_menu.rs @@ -2,14 +2,13 @@ //! //! *This API requires the following crate features to be activated: badge* use iced_graphics::Color; - use iced_native::Background; use iced_style::Theme; -/// The appearance of a [`Modal`](crate::native::Modal). +/// The appearance of a [`ContextMenu`](crate::native::ContextMenu). #[derive(Clone, Copy, Debug)] pub struct Appearance { - /// The backgronud of the [`Modal`](crate::native::Modal). + /// The backgronud of the [`ContextMenu`](crate::native::ContextMenu). /// /// This is used to color the backdrop of the modal. pub background: Background, @@ -22,15 +21,16 @@ impl Default for Appearance { } } } -/// The appearance of a [`Modal`](crate::native::Modal). + +/// The appearance of a [`ContextMenu`](crate::native::ContextMenu). pub trait StyleSheet { ///Style for the trait to use. type Style: Default + Copy; - /// The normal appearance of a [`Modal`](crate::native::Modal). + /// The normal appearance of a [`ContextMenu`](crate::native::ContextMenu). fn active(&self, style: Self::Style) -> Appearance; } -/// The default appearance of a [`Modal`](crate::native::Modal). +/// The default appearance of a [`ContextMenu`](crate::native::ContextMenu). #[derive(Clone, Copy, Debug, Default)] #[allow(missing_docs, clippy::missing_docs_in_private_items)] pub enum ContextMenuStyle { @@ -49,7 +49,7 @@ impl StyleSheet for Theme { a: 0f32, ..palette.background.base.color } - .into(), + .into(), } } } From 2de767fba523c04234b81c1bb679ecff0734571f Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:05:11 +0200 Subject: [PATCH 12/13] begin fmt --- examples/context_menu/Cargo.toml | 1 - examples/context_menu/src/main.rs | 22 +++++++++++----------- examples/floating_element/src/main.rs | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/examples/context_menu/Cargo.toml b/examples/context_menu/Cargo.toml index 95b7e3bf..f8347d9b 100644 --- a/examples/context_menu/Cargo.toml +++ b/examples/context_menu/Cargo.toml @@ -10,5 +10,4 @@ edition = "2021" iced_aw = { workspace = true, features = [ "context_menu", ] } -iced_lazy = "0.6" iced.workspace = true \ No newline at end of file diff --git a/examples/context_menu/src/main.rs b/examples/context_menu/src/main.rs index f083f1dc..731d7750 100644 --- a/examples/context_menu/src/main.rs +++ b/examples/context_menu/src/main.rs @@ -1,6 +1,6 @@ use iced::{ - Alignment, - Element, Sandbox, Settings, widget::{Button, column, Container, Row, Text}, + widget::{column, Button, Container, Row, Text}, + Alignment, Element, Sandbox, Settings, }; use iced_aw::ContextMenu; @@ -39,14 +39,11 @@ impl Sandbox for ContextMenuExample { } fn view(&self) -> Element<'_, Self::Message> { - let underlay = - Container::new(Row::new() + let underlay = Container::new( + Row::new() .spacing(10) .align_items(Alignment::Center) - .push( - Button::new(Text::new("right click me!")) - .on_press(Message::ButtonClicked), - ) + .push(Button::new(Text::new("right click me!")).on_press(Message::ButtonClicked)) .push(Text::new(format!( "Last message: {}", match self.last_message.as_ref() { @@ -59,7 +56,8 @@ impl Sandbox for ContextMenuExample { }, None => "None", } - )))); + ))), + ); ContextMenu::new(underlay, || { column(vec![ @@ -75,7 +73,9 @@ impl Sandbox for ContextMenuExample { iced::widget::button("Choice 4") .on_press(Message::Choice4) .into(), - ]).into() - }).into() + ]) + .into() + }) + .into() } } diff --git a/examples/floating_element/src/main.rs b/examples/floating_element/src/main.rs index 3f5f00d4..3e9f73d3 100644 --- a/examples/floating_element/src/main.rs +++ b/examples/floating_element/src/main.rs @@ -6,7 +6,7 @@ use iced::{ Element, Length, Sandbox, Settings, Theme, }; -use iced_aw::floating_element::{Anchor}; +use iced_aw::floating_element::Anchor; use iced_aw::{helpers::floating_element, Icon, ICON_FONT}; fn main() -> iced::Result { From a845b639d9485a8c3dfc6e9d9205a88635119d49 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Tue, 13 Jun 2023 20:58:03 +0200 Subject: [PATCH 13/13] fmt fix --- examples/grid/src/main.rs | 3 +- examples/number_input/src/main.rs | 2 +- examples/tab_bar/src/main.rs | 2 +- examples/tabs/src/main.rs | 24 +++++++-- src/lib.rs | 4 +- src/native/context_menu.rs | 65 ++++++++++------------- src/native/cupertino/cupertino_spinner.rs | 2 +- src/native/helpers.rs | 10 +++- src/native/mod.rs | 1 - src/native/overlay/context_menu.rs | 51 +++++++++--------- src/native/overlay/mod.rs | 3 +- src/native/tab_bar.rs | 20 +++---- src/native/tabs.rs | 46 ++++++++-------- src/style/context_menu.rs | 2 +- src/style/mod.rs | 3 +- 15 files changed, 126 insertions(+), 112 deletions(-) diff --git a/examples/grid/src/main.rs b/examples/grid/src/main.rs index 39d5dcd3..e0afda9e 100644 --- a/examples/grid/src/main.rs +++ b/examples/grid/src/main.rs @@ -46,7 +46,8 @@ impl Sandbox for GridExample { let mut grid = grid!( Text::new("Column 1").style(theme::Text::Color(Color::from_rgb8(255, 0, 0))), Text::new("Column 2").style(theme::Text::Color(Color::from_rgb8(255, 0, 0))), - ).strategy(iced_aw::Strategy::Columns(2)); + ) + .strategy(iced_aw::Strategy::Columns(2)); // Add elements to the grid for i in 0..self.element_index { diff --git a/examples/number_input/src/main.rs b/examples/number_input/src/main.rs index 898b9eaa..5aa31376 100644 --- a/examples/number_input/src/main.rs +++ b/examples/number_input/src/main.rs @@ -2,7 +2,7 @@ use iced::{ widget::{Container, Row, Text}, window, Alignment, Element, Length, Sandbox, Settings, }; -use iced_aw::{number_input, style::NumberInputStyles}; +use iced_aw::{number_input, style::NumberInputStyles}; #[derive(Default)] pub struct NumberInputDemo { diff --git a/examples/tab_bar/src/main.rs b/examples/tab_bar/src/main.rs index 644e1f83..4b29f64f 100644 --- a/examples/tab_bar/src/main.rs +++ b/examples/tab_bar/src/main.rs @@ -45,7 +45,7 @@ impl Sandbox for TabBarExample { Message::TabSelected(index) => { println!("Tab selected: {}", index); self.active_tab = index - }, + } Message::TabClosed(index) => { self.tabs.remove(index); println!("active tab before: {}", self.active_tab); diff --git a/examples/tabs/src/main.rs b/examples/tabs/src/main.rs index c67be468..c943c535 100644 --- a/examples/tabs/src/main.rs +++ b/examples/tabs/src/main.rs @@ -110,10 +110,26 @@ impl Sandbox for TabBarExample { .unwrap_or_default(); Tabs::new(Message::TabSelected) - .push(TabId::Login, self.login_tab.tab_label(), self.login_tab.view()) - .push(TabId::Ferris, self.ferris_tab.tab_label(), self.ferris_tab.view()) - .push(TabId::Counter, self.counter_tab.tab_label(), self.counter_tab.view()) - .push(TabId::Settings, self.settings_tab.tab_label(), self.settings_tab.view()) + .push( + TabId::Login, + self.login_tab.tab_label(), + self.login_tab.view(), + ) + .push( + TabId::Ferris, + self.ferris_tab.tab_label(), + self.ferris_tab.view(), + ) + .push( + TabId::Counter, + self.counter_tab.tab_label(), + self.counter_tab.view(), + ) + .push( + TabId::Settings, + self.settings_tab.tab_label(), + self.settings_tab.view(), + ) .set_active_tab(&self.active_tab) .tab_bar_style(theme) .icon_font(ICON_FONT) diff --git a/src/lib.rs b/src/lib.rs index 91139ca4..f12c4a84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -157,7 +157,9 @@ mod platform { #[doc(no_inline)] #[cfg(feature = "context_menu")] - pub use {crate::native::context_menu, crate::style::ContextMenuStyle, context_menu::ContextMenu}; + pub use { + crate::native::context_menu, crate::style::ContextMenuStyle, context_menu::ContextMenu, + }; } #[doc(no_inline)] diff --git a/src/native/context_menu.rs b/src/native/context_menu.rs index d2091e65..c7497c17 100644 --- a/src/native/context_menu.rs +++ b/src/native/context_menu.rs @@ -1,9 +1,10 @@ //! A context menu for showing actions on right click. //! use iced_native::{ - Clipboard, Element, event, - Event, Layout, Length, mouse::{self, Button}, Point, Rectangle, Shell, widget::{Operation, Tree, tree}, Widget, + mouse::{self, Button}, + widget::{tree, Operation, Tree}, + Clipboard, Element, Event, Layout, Length, Point, Rectangle, Shell, Widget, }; use crate::native::overlay::ContextMenuOverlay; @@ -35,11 +36,11 @@ pub use crate::style::context_menu::StyleSheet; /// ``` #[allow(missing_debug_implementations)] pub struct ContextMenu<'a, Overlay, Message, Renderer> - where - Overlay: Fn() -> Element<'a, Message, Renderer>, - Message: Clone, - Renderer: iced_native::Renderer, - Renderer::Theme: StyleSheet, +where + Overlay: Fn() -> Element<'a, Message, Renderer>, + Message: Clone, + Renderer: iced_native::Renderer, + Renderer::Theme: StyleSheet, { /// The underlying element. underlay: Element<'a, Message, Renderer>, @@ -50,11 +51,11 @@ pub struct ContextMenu<'a, Overlay, Message, Renderer> } impl<'a, Overlay, Message, Renderer> ContextMenu<'a, Overlay, Message, Renderer> - where - Overlay: Fn() -> Element<'a, Message, Renderer>, - Message: Clone, - Renderer: iced_native::Renderer, - Renderer::Theme: StyleSheet, +where + Overlay: Fn() -> Element<'a, Message, Renderer>, + Message: Clone, + Renderer: iced_native::Renderer, + Renderer::Theme: StyleSheet, { /// Creates a new [`ContextMenu`](ContextMenu) /// @@ -62,8 +63,8 @@ impl<'a, Overlay, Message, Renderer> ContextMenu<'a, Overlay, Message, Renderer> /// /// `overlay`: The content of [`ContextMenuOverlay`](ContextMenuOverlay) which will be displayed when `underlay` is clicked. pub fn new(underlay: U, overlay: Overlay) -> Self - where - U: Into>, + where + U: Into>, { ContextMenu { underlay: underlay.into(), @@ -72,7 +73,6 @@ impl<'a, Overlay, Message, Renderer> ContextMenu<'a, Overlay, Message, Renderer> } } - /// Sets the style of the [`ContextMenu`](ContextMenu). #[must_use] pub fn style(mut self, style: ::Style) -> Self { @@ -82,12 +82,12 @@ impl<'a, Overlay, Message, Renderer> ContextMenu<'a, Overlay, Message, Renderer> } impl<'a, Content, Message, Renderer> Widget -for ContextMenu<'a, Content, Message, Renderer> - where - Content: 'a + Fn() -> Element<'a, Message, Renderer>, - Message: 'a + Clone, - Renderer: 'a + iced_native::Renderer, - Renderer::Theme: StyleSheet, + for ContextMenu<'a, Content, Message, Renderer> +where + Content: 'a + Fn() -> Element<'a, Message, Renderer>, + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.underlay.as_widget().width() @@ -126,7 +126,6 @@ for ContextMenu<'a, Content, Message, Renderer> ); } - fn tag(&self) -> tree::Tag { tree::Tag::of::() } @@ -143,7 +142,6 @@ for ContextMenu<'a, Content, Message, Renderer> tree.diff_children(&[&self.underlay, &(self.overlay)()]); } - fn operate<'b>( &'b self, state: &'b mut Tree, @@ -188,7 +186,6 @@ for ContextMenu<'a, Content, Message, Renderer> } } - self.underlay.as_widget_mut().on_event( &mut state.children[0], event, @@ -225,7 +222,6 @@ for ContextMenu<'a, Content, Message, Renderer> ) -> Option> { let s: &mut State = state.state.downcast_mut(); - if !s.show { return self .underlay @@ -238,24 +234,19 @@ for ContextMenu<'a, Content, Message, Renderer> content.as_widget().diff(&mut state.children[1]); Some( - ContextMenuOverlay::new( - &mut state.children[1], - content, - self.style, - s, - ) + ContextMenuOverlay::new(&mut state.children[1], content, self.style, s) .overlay(position), ) } } impl<'a, Content, Message, Renderer> From> -for Element<'a, Message, Renderer> - where - Content: 'a + Fn() -> Element<'a, Message, Renderer>, - Message: 'a + Clone, - Renderer: 'a + iced_native::Renderer, - Renderer::Theme: StyleSheet, + for Element<'a, Message, Renderer> +where + Content: 'a + Fn() -> Element<'a, Message, Renderer>, + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, { fn from(modal: ContextMenu<'a, Content, Message, Renderer>) -> Self { Element::new(modal) diff --git a/src/native/cupertino/cupertino_spinner.rs b/src/native/cupertino/cupertino_spinner.rs index fa0c3fdd..a3530895 100644 --- a/src/native/cupertino/cupertino_spinner.rs +++ b/src/native/cupertino/cupertino_spinner.rs @@ -1,3 +1,4 @@ +use iced_graphics::{Backend, Renderer}; use iced_native::event::Status; use iced_native::layout::{Limits, Node}; use iced_native::renderer::Style; @@ -5,7 +6,6 @@ use iced_native::widget::{ tree::{State, Tag}, Tree, }; -use iced_graphics::{Backend, Renderer}; use iced_native::{ window, Clipboard, Color, Element, Event, Layout, Length, Point, Rectangle, Shell, Size, diff --git a/src/native/helpers.rs b/src/native/helpers.rs index 13a7162a..c1c9facc 100644 --- a/src/native/helpers.rs +++ b/src/native/helpers.rs @@ -2,7 +2,15 @@ //! //! -#[cfg(any(feature = "grid", feature = "menu", feature = "badge", feature = "color_picker", feature = "date_picker", feature = "floating_element", feature = "modal"))] +#[cfg(any( + feature = "grid", + feature = "menu", + feature = "badge", + feature = "color_picker", + feature = "date_picker", + feature = "floating_element", + feature = "modal" +))] use iced_native::Element; #[cfg(feature = "color_picker")] use iced_style::Color; diff --git a/src/native/mod.rs b/src/native/mod.rs index 1e1e82a2..7460456e 100644 --- a/src/native/mod.rs +++ b/src/native/mod.rs @@ -98,7 +98,6 @@ pub mod spinner; #[cfg(feature = "spinner")] pub use spinner::Spinner; - #[cfg(feature = "context_menu")] pub mod context_menu; #[cfg(feature = "context_menu")] diff --git a/src/native/overlay/context_menu.rs b/src/native/overlay/context_menu.rs index 75b9ae27..b8636d70 100644 --- a/src/native/overlay/context_menu.rs +++ b/src/native/overlay/context_menu.rs @@ -1,23 +1,22 @@ //! A modal for showing elements as an overlay on top of another. //! //! *This API requires the following crate features to be activated: context_menu* -use iced_native::{ - Clipboard, Color, Event, keyboard, Layout, layout::Limits, mouse, overlay, Point, - renderer, Shell, Size, touch, -}; -use iced_native::{Element, widget::Tree}; -use iced_native::event::Status; - use crate::context_menu; use crate::style::context_menu::StyleSheet; +use iced_native::event::Status; +use iced_native::{ + keyboard, layout::Limits, mouse, overlay, renderer, touch, Clipboard, Color, Event, Layout, + Point, Shell, Size, +}; +use iced_native::{widget::Tree, Element}; /// The overlay of the [`ContextMenu`](crate::native::ContextMenu). #[allow(missing_debug_implementations)] pub struct ContextMenuOverlay<'a, Message, Renderer> - where - Message: 'a + Clone, - Renderer: 'a + iced_native::Renderer, - Renderer::Theme: StyleSheet, +where + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, { /// The state of the [`ContextMenuOverlay`](ContextMenuOverlay). tree: &'a mut Tree, @@ -30,10 +29,10 @@ pub struct ContextMenuOverlay<'a, Message, Renderer> } impl<'a, Message, Renderer> ContextMenuOverlay<'a, Message, Renderer> - where - Message: Clone, - Renderer: iced_native::Renderer, - Renderer::Theme: StyleSheet, +where + Message: Clone, + Renderer: iced_native::Renderer, + Renderer::Theme: StyleSheet, { /// Creates a new [`ContextMenuOverlay`](ContextMenuOverlay). pub(crate) fn new( @@ -42,8 +41,8 @@ impl<'a, Message, Renderer> ContextMenuOverlay<'a, Message, Renderer> style: ::Style, state: &'a mut context_menu::State, ) -> Self - where - C: Into>, + where + C: Into>, { ContextMenuOverlay { tree, @@ -61,11 +60,11 @@ impl<'a, Message, Renderer> ContextMenuOverlay<'a, Message, Renderer> } impl<'a, Message, Renderer> iced_native::Overlay -for ContextMenuOverlay<'a, Message, Renderer> - where - Message: 'a + Clone, - Renderer: 'a + iced_native::Renderer, - Renderer::Theme: StyleSheet, + for ContextMenuOverlay<'a, Message, Renderer> +where + Message: 'a + Clone, + Renderer: 'a + iced_native::Renderer, + Renderer::Theme: StyleSheet, { fn layout( &self, @@ -131,7 +130,10 @@ for ContextMenuOverlay<'a, Message, Renderer> clipboard: &mut dyn Clipboard, shell: &mut Shell, ) -> Status { - let layout_children = layout.children().next().expect("Native: Layout should have a content layout."); + let layout_children = layout + .children() + .next() + .expect("Native: Layout should have a content layout."); let status = match event { Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => { @@ -164,10 +166,9 @@ for ContextMenuOverlay<'a, Message, Renderer> } } - _ => Status::Ignored + _ => Status::Ignored, }; - match status { Status::Ignored => self.content.as_widget_mut().on_event( self.tree, diff --git a/src/native/overlay/mod.rs b/src/native/overlay/mod.rs index 5f35fa02..9803c9b2 100644 --- a/src/native/overlay/mod.rs +++ b/src/native/overlay/mod.rs @@ -25,8 +25,7 @@ pub mod time_picker; #[cfg(feature = "time_picker")] pub use time_picker::{State, TimePickerOverlay}; - #[cfg(feature = "context_menu")] pub mod context_menu; #[cfg(feature = "context_menu")] -pub use context_menu::ContextMenuOverlay; \ No newline at end of file +pub use context_menu::ContextMenuOverlay; diff --git a/src/native/tab_bar.rs b/src/native/tab_bar.rs index 9f9e52b0..0b3760ed 100644 --- a/src/native/tab_bar.rs +++ b/src/native/tab_bar.rs @@ -67,7 +67,7 @@ pub struct TabBar where Renderer: iced_native::Renderer + iced_native::text::Renderer, Renderer::Theme: StyleSheet, - TabId: Eq + Clone + TabId: Eq + Clone, { /// The index of the currently active tab. active_tab: usize, @@ -111,7 +111,7 @@ impl TabBar where Renderer: iced_native::Renderer + iced_native::text::Renderer, Renderer::Theme: StyleSheet, - TabId: Eq + Clone + TabId: Eq + Clone, { /// Creates a new [`TabBar`](TabBar) with the index of the selected tab and a /// specified message which will be send when a tab is selected by the user. @@ -304,12 +304,11 @@ where /// Sets up the active tab on the [`TabBar`](TabBar). #[must_use] pub fn set_active_tab(mut self, active_tab: &TabId) -> Self { - self.active_tab = if let Some(a) = self - .tab_indices - .iter() - .position(|id| id == active_tab) { + self.active_tab = if let Some(a) = self.tab_indices.iter().position(|id| id == active_tab) { a - } else { 0 }; + } else { + 0 + }; self } } @@ -318,7 +317,7 @@ impl Widget for TabBar, Renderer::Theme: StyleSheet + iced_style::text::StyleSheet, - TabId: Eq + Clone + TabId: Eq + Clone, { fn width(&self) -> Length { self.width @@ -647,12 +646,13 @@ fn draw_tab( }; } -impl<'a, Message, TabId, Renderer> From> for Element<'a, Message, Renderer> +impl<'a, Message, TabId, Renderer> From> + for Element<'a, Message, Renderer> where Renderer: 'a + iced_native::Renderer + iced_native::text::Renderer, Renderer::Theme: StyleSheet + iced_style::text::StyleSheet, Message: 'a, - TabId: 'a + Eq + Clone + TabId: 'a + Eq + Clone, { fn from(tab_bar: TabBar) -> Self { Element::new(tab_bar) diff --git a/src/native/tabs.rs b/src/native/tabs.rs index fe40ccf7..1c1f445f 100644 --- a/src/native/tabs.rs +++ b/src/native/tabs.rs @@ -55,7 +55,7 @@ pub struct Tabs<'a, Message, TabId, Renderer> where Renderer: 'a + iced_native::Renderer + iced_native::text::Renderer, Renderer::Theme: StyleSheet, - TabId: Eq + Clone + TabId: Eq + Clone, { /// The [`TabBar`](crate::native::TabBar) of the [`Tabs`](Tabs). tab_bar: TabBar, @@ -112,7 +112,7 @@ where let mut elements = Vec::with_capacity(tabs.len()); let mut indices = Vec::with_capacity(tabs.len()); - for (id,tab_label, element) in tabs { + for (id, tab_label, element) in tabs { tab_labels.push((id.clone(), tab_label)); indices.push(id); elements.push(element); @@ -306,15 +306,18 @@ where .width(self.width) .height(self.height); - let mut tab_content_node = self.tabs.get(self.tab_bar.get_active_tab_idx()).map_or_else( - || { - Row::::new() - .width(Length::Fill) - .height(Length::Fill) - .layout(renderer, &tab_content_limits) - }, - |element| element.as_widget().layout(renderer, &tab_content_limits), - ); + let mut tab_content_node = self + .tabs + .get(self.tab_bar.get_active_tab_idx()) + .map_or_else( + || { + Row::::new() + .width(Length::Fill) + .height(Length::Fill) + .layout(renderer, &tab_content_limits) + }, + |element| element.as_widget().layout(renderer, &tab_content_limits), + ); tab_bar_node.move_to(Point::new( tab_bar_node.bounds().x, @@ -388,9 +391,10 @@ where shell, ); let idx = self.tab_bar.get_active_tab_idx(); - let status_element = self.tabs.get_mut(idx).map_or( - event::Status::Ignored, - |element| { + let status_element = self + .tabs + .get_mut(idx) + .map_or(event::Status::Ignored, |element| { element.as_widget_mut().on_event( &mut state.children[idx], event, @@ -400,8 +404,7 @@ where clipboard, shell, ) - }, - ); + }); status_tab_bar.merge(status_element) } @@ -537,13 +540,7 @@ where self.tabs .get_mut(idx) .map(Element::as_widget_mut) - .and_then(|w| { - w.overlay( - &mut state.children[idx], - layout, - renderer, - ) - }) + .and_then(|w| w.overlay(&mut state.children[idx], layout, renderer)) }) } @@ -569,7 +566,8 @@ where } } -impl<'a, Message, TabId, Renderer> From> for Element<'a, Message, Renderer> +impl<'a, Message, TabId, Renderer> From> + for Element<'a, Message, Renderer> where Renderer: 'a + iced_native::Renderer + iced_native::text::Renderer, Renderer::Theme: StyleSheet + iced_style::text::StyleSheet, diff --git a/src/style/context_menu.rs b/src/style/context_menu.rs index 4836e539..c4582bed 100644 --- a/src/style/context_menu.rs +++ b/src/style/context_menu.rs @@ -49,7 +49,7 @@ impl StyleSheet for Theme { a: 0f32, ..palette.background.base.color } - .into(), + .into(), } } } diff --git a/src/style/mod.rs b/src/style/mod.rs index bd9e605a..241d2f92 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -57,8 +57,7 @@ pub mod spinner; #[cfg(feature = "spinner")] pub use spinner::SpinnerStyle; - #[cfg(feature = "context_menu")] pub mod context_menu; #[cfg(feature = "context_menu")] -pub use context_menu::ContextMenuStyle; \ No newline at end of file +pub use context_menu::ContextMenuStyle;