summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorLibravatar Bingus <shankern@protonmail.com>2023-02-15 14:55:02 -0800
committerLibravatar Bingus <shankern@protonmail.com>2023-02-15 14:55:02 -0800
commit63fb608d8bea8a653bf011f5f9cffc88525576e0 (patch)
tree938c15b85fd9d27ee3a82806cf83bc211e7b94dd /examples
parent64e0e817c27d720dc954ee94de58ded35b3f9f9a (diff)
parent0cb72f69716adc82ad85a0ee7120edb6e653b0c0 (diff)
downloadiced-63fb608d8bea8a653bf011f5f9cffc88525576e0.tar.gz
iced-63fb608d8bea8a653bf011f5f9cffc88525576e0.tar.bz2
iced-63fb608d8bea8a653bf011f5f9cffc88525576e0.zip
Merge remote-tracking branch 'origin/master' into feat/multi-window-support
# Conflicts: # native/src/command/action.rs # native/src/window/action.rs # winit/src/window.rs
Diffstat (limited to 'examples')
-rw-r--r--examples/download_progress/src/main.rs2
-rw-r--r--examples/events/src/main.rs2
-rw-r--r--examples/game_of_life/src/main.rs2
-rw-r--r--examples/game_of_life/src/preset.rs9
-rw-r--r--examples/integration_opengl/src/controls.rs2
-rw-r--r--examples/integration_opengl/src/scene.rs2
-rw-r--r--examples/integration_wgpu/src/controls.rs2
-rw-r--r--examples/integration_wgpu/src/main.rs2
-rw-r--r--examples/pokedex/src/main.rs8
-rw-r--r--examples/styling/src/main.rs2
-rw-r--r--examples/system_information/src/main.rs5
-rw-r--r--examples/toast/Cargo.toml10
-rw-r--r--examples/toast/src/main.rs670
-rw-r--r--examples/todos/src/main.rs2
-rw-r--r--examples/tour/src/main.rs8
-rw-r--r--examples/websocket/src/echo.rs2
-rw-r--r--examples/websocket/src/echo/server.rs2
17 files changed, 702 insertions, 30 deletions
diff --git a/examples/download_progress/src/main.rs b/examples/download_progress/src/main.rs
index 3ef9ef7a..001a1f8f 100644
--- a/examples/download_progress/src/main.rs
+++ b/examples/download_progress/src/main.rs
@@ -177,7 +177,7 @@ impl Download {
.into()
}
State::Downloading { .. } => {
- text(format!("Downloading... {:.2}%", current_progress)).into()
+ text(format!("Downloading... {current_progress:.2}%")).into()
}
State::Errored => column![
"Something went wrong :(",
diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs
index f519fc3d..9f5c9971 100644
--- a/examples/events/src/main.rs
+++ b/examples/events/src/main.rs
@@ -77,7 +77,7 @@ impl Application for Events {
let events = Column::with_children(
self.last
.iter()
- .map(|event| text(format!("{:?}", event)).size(40))
+ .map(|event| text(format!("{event:?}")).size(40))
.map(Element::from)
.collect(),
);
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs
index b0f1c96d..ed911160 100644
--- a/examples/game_of_life/src/main.rs
+++ b/examples/game_of_life/src/main.rs
@@ -176,7 +176,7 @@ fn view_controls<'a>(
let speed_controls = row![
slider(1.0..=1000.0, speed as f32, Message::SpeedChanged),
- text(format!("x{}", speed)).size(16),
+ text(format!("x{speed}")).size(16),
]
.width(Length::Fill)
.align_items(Alignment::Center)
diff --git a/examples/game_of_life/src/preset.rs b/examples/game_of_life/src/preset.rs
index 964b9120..552527b1 100644
--- a/examples/game_of_life/src/preset.rs
+++ b/examples/game_of_life/src/preset.rs
@@ -1,6 +1,7 @@
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum Preset {
Custom,
+ #[default]
Xkcd,
Glider,
SmallExploder,
@@ -114,12 +115,6 @@ impl Preset {
}
}
-impl Default for Preset {
- fn default() -> Preset {
- Preset::Xkcd
- }
-}
-
impl std::fmt::Display for Preset {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
diff --git a/examples/integration_opengl/src/controls.rs b/examples/integration_opengl/src/controls.rs
index 076d37d3..22c41066 100644
--- a/examples/integration_opengl/src/controls.rs
+++ b/examples/integration_opengl/src/controls.rs
@@ -90,7 +90,7 @@ impl Program for Controls {
)
.push(sliders)
.push(
- Text::new(format!("{:?}", background_color))
+ Text::new(format!("{background_color:?}"))
.size(14)
.style(Color::WHITE),
),
diff --git a/examples/integration_opengl/src/scene.rs b/examples/integration_opengl/src/scene.rs
index fc74b78a..c1d05b65 100644
--- a/examples/integration_opengl/src/scene.rs
+++ b/examples/integration_opengl/src/scene.rs
@@ -49,7 +49,7 @@ impl Scene {
.expect("Cannot create shader");
gl.shader_source(
shader,
- &format!("{}\n{}", shader_version, shader_source),
+ &format!("{shader_version}\n{shader_source}"),
);
gl.compile_shader(shader);
if !gl.get_shader_compile_status(shader) {
diff --git a/examples/integration_wgpu/src/controls.rs b/examples/integration_wgpu/src/controls.rs
index 6c41738c..92300a45 100644
--- a/examples/integration_wgpu/src/controls.rs
+++ b/examples/integration_wgpu/src/controls.rs
@@ -96,7 +96,7 @@ impl Program for Controls {
)
.push(sliders)
.push(
- Text::new(format!("{:?}", background_color))
+ Text::new(format!("{background_color:?}"))
.size(14)
.style(Color::WHITE),
)
diff --git a/examples/integration_wgpu/src/main.rs b/examples/integration_wgpu/src/main.rs
index 219573ea..1f42013b 100644
--- a/examples/integration_wgpu/src/main.rs
+++ b/examples/integration_wgpu/src/main.rs
@@ -275,7 +275,7 @@ pub fn main() {
}
Err(error) => match error {
wgpu::SurfaceError::OutOfMemory => {
- panic!("Swapchain error: {}. Rendering cannot continue.", error)
+ panic!("Swapchain error: {error}. Rendering cannot continue.")
}
_ => {
// Try rendering again next frame.
diff --git a/examples/pokedex/src/main.rs b/examples/pokedex/src/main.rs
index 4fe2d07c..748acae0 100644
--- a/examples/pokedex/src/main.rs
+++ b/examples/pokedex/src/main.rs
@@ -41,7 +41,7 @@ impl Application for Pokedex {
Pokedex::Errored { .. } => "Whoops!",
};
- format!("{} - Pokédex", subtitle)
+ format!("{subtitle} - Pokédex")
}
fn update(&mut self, message: Message) -> Command<Message> {
@@ -157,8 +157,7 @@ impl Pokemon {
};
let fetch_entry = async {
- let url =
- format!("https://pokeapi.co/api/v2/pokemon-species/{}", id);
+ let url = format!("https://pokeapi.co/api/v2/pokemon-species/{id}");
reqwest::get(&url).await?.json().await
};
@@ -187,8 +186,7 @@ impl Pokemon {
async fn fetch_image(id: u16) -> Result<image::Handle, reqwest::Error> {
let url = format!(
- "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png",
- id
+ "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{id}.png"
);
#[cfg(not(target_arch = "wasm32"))]
diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs
index e16860ad..49bedce7 100644
--- a/examples/styling/src/main.rs
+++ b/examples/styling/src/main.rs
@@ -78,7 +78,7 @@ impl Sandbox for Styling {
column![text("Choose a theme:")].spacing(10),
|column, theme| {
column.push(radio(
- format!("{:?}", theme),
+ format!("{theme:?}"),
*theme,
Some(match self.theme {
Theme::Light => ThemeType::Light,
diff --git a/examples/system_information/src/main.rs b/examples/system_information/src/main.rs
index 175b4387..633b6e2b 100644
--- a/examples/system_information/src/main.rs
+++ b/examples/system_information/src/main.rs
@@ -114,13 +114,12 @@ impl Application for Example {
{
let memory_readable = ByteSize::kb(memory_used).to_string();
- format!("{} kb ({})", memory_used, memory_readable)
+ format!("{memory_used} kb ({memory_readable})")
} else {
String::from("None")
};
- let memory_used =
- text(format!("Memory (used): {}", memory_text));
+ let memory_used = text(format!("Memory (used): {memory_text}"));
let graphics_adapter = text(format!(
"Graphics adapter: {}",
diff --git a/examples/toast/Cargo.toml b/examples/toast/Cargo.toml
new file mode 100644
index 00000000..f1f986aa
--- /dev/null
+++ b/examples/toast/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "toast"
+version = "0.1.0"
+authors = ["tarkah <admin@tarkah.dev>"]
+edition = "2021"
+publish = false
+
+[dependencies]
+iced = { path = "../..", features = [] }
+iced_native = { path = "../../native" }
diff --git a/examples/toast/src/main.rs b/examples/toast/src/main.rs
new file mode 100644
index 00000000..e74b3ee6
--- /dev/null
+++ b/examples/toast/src/main.rs
@@ -0,0 +1,670 @@
+use iced::widget::{
+ self, button, column, container, pick_list, row, slider, text, text_input,
+};
+use iced::{
+ executor, keyboard, subscription, Alignment, Application, Command, Element,
+ Event, Length, Settings, Subscription,
+};
+
+use toast::{Status, Toast};
+
+pub fn main() -> iced::Result {
+ App::run(Settings::default())
+}
+
+#[derive(Default)]
+struct App {
+ toasts: Vec<Toast>,
+ editing: Toast,
+ timeout_secs: u64,
+}
+
+#[derive(Debug, Clone)]
+#[allow(clippy::enum_variant_names)]
+enum Message {
+ Add,
+ Close(usize),
+ Title(String),
+ Body(String),
+ Status(Status),
+ Timeout(f64),
+ Event(Event),
+}
+
+impl Application for App {
+ type Executor = executor::Default;
+ type Message = Message;
+ type Theme = iced::Theme;
+ type Flags = ();
+
+ fn new(_flags: ()) -> (Self, Command<Message>) {
+ (
+ App {
+ toasts: vec![Toast {
+ title: "Example Toast".into(),
+ body: "Add more toasts in the form below!".into(),
+ status: Status::Primary,
+ }],
+ timeout_secs: toast::DEFAULT_TIMEOUT,
+ ..Default::default()
+ },
+ Command::none(),
+ )
+ }
+
+ fn title(&self) -> String {
+ String::from("Toast - Iced")
+ }
+
+ fn subscription(&self) -> Subscription<Self::Message> {
+ subscription::events().map(Message::Event)
+ }
+
+ fn update(&mut self, message: Message) -> Command<Message> {
+ match message {
+ Message::Add => {
+ if !self.editing.title.is_empty()
+ && !self.editing.body.is_empty()
+ {
+ self.toasts.push(std::mem::take(&mut self.editing));
+ }
+ Command::none()
+ }
+ Message::Close(index) => {
+ self.toasts.remove(index);
+ Command::none()
+ }
+ Message::Title(title) => {
+ self.editing.title = title;
+ Command::none()
+ }
+ Message::Body(body) => {
+ self.editing.body = body;
+ Command::none()
+ }
+ Message::Status(status) => {
+ self.editing.status = status;
+ Command::none()
+ }
+ Message::Timeout(timeout) => {
+ self.timeout_secs = timeout as u64;
+ Command::none()
+ }
+ Message::Event(Event::Keyboard(keyboard::Event::KeyPressed {
+ key_code: keyboard::KeyCode::Tab,
+ modifiers,
+ })) if modifiers.shift() => widget::focus_previous(),
+ Message::Event(Event::Keyboard(keyboard::Event::KeyPressed {
+ key_code: keyboard::KeyCode::Tab,
+ ..
+ })) => widget::focus_next(),
+ Message::Event(_) => Command::none(),
+ }
+ }
+
+ fn view<'a>(&'a self) -> Element<'a, Message> {
+ let subtitle = |title, content: Element<'a, Message>| {
+ column![text(title).size(14), content]
+ .width(Length::Fill)
+ .spacing(5)
+ };
+
+ let mut add_toast = button("Add Toast");
+
+ if !self.editing.body.is_empty() && !self.editing.title.is_empty() {
+ add_toast = add_toast.on_press(Message::Add);
+ }
+
+ let content = container(
+ column![
+ subtitle(
+ "Title",
+ text_input("", &self.editing.title, Message::Title)
+ .on_submit(Message::Add)
+ .into()
+ ),
+ subtitle(
+ "Message",
+ text_input("", &self.editing.body, Message::Body)
+ .on_submit(Message::Add)
+ .into()
+ ),
+ subtitle(
+ "Status",
+ pick_list(
+ toast::Status::ALL,
+ Some(self.editing.status),
+ Message::Status
+ )
+ .width(Length::Fill)
+ .into()
+ ),
+ subtitle(
+ "Timeout",
+ row![
+ text(format!("{:0>2} sec", self.timeout_secs)),
+ slider(
+ 1.0..=30.0,
+ self.timeout_secs as f64,
+ Message::Timeout
+ )
+ .step(1.0)
+ .width(Length::Fill)
+ ]
+ .spacing(5)
+ .into()
+ ),
+ column![add_toast]
+ .width(Length::Fill)
+ .align_items(Alignment::End)
+ ]
+ .spacing(10)
+ .max_width(200),
+ )
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .center_x()
+ .center_y();
+
+ toast::Manager::new(content, &self.toasts, Message::Close)
+ .timeout(self.timeout_secs)
+ .into()
+ }
+}
+
+mod toast {
+ use std::fmt;
+ use std::time::{Duration, Instant};
+
+ use iced::theme;
+ use iced::widget::{
+ button, column, container, horizontal_rule, horizontal_space, row, text,
+ };
+ use iced::{
+ Alignment, Element, Length, Point, Rectangle, Renderer, Size, Theme,
+ Vector,
+ };
+ use iced_native::widget::{tree, Operation, Tree};
+ use iced_native::{event, layout, mouse, overlay, renderer, window};
+ use iced_native::{Clipboard, Event, Layout, Shell, Widget};
+
+ pub const DEFAULT_TIMEOUT: u64 = 5;
+
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+ pub enum Status {
+ #[default]
+ Primary,
+ Secondary,
+ Success,
+ Danger,
+ }
+
+ impl Status {
+ pub const ALL: &[Self] =
+ &[Self::Primary, Self::Secondary, Self::Success, Self::Danger];
+ }
+
+ impl container::StyleSheet for Status {
+ type Style = Theme;
+
+ fn appearance(&self, theme: &Theme) -> container::Appearance {
+ let palette = theme.extended_palette();
+
+ let pair = match self {
+ Status::Primary => palette.primary.weak,
+ Status::Secondary => palette.secondary.weak,
+ Status::Success => palette.success.weak,
+ Status::Danger => palette.danger.weak,
+ };
+
+ container::Appearance {
+ background: pair.color.into(),
+ text_color: pair.text.into(),
+ ..Default::default()
+ }
+ }
+ }
+
+ impl fmt::Display for Status {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Status::Primary => "Primary",
+ Status::Secondary => "Secondary",
+ Status::Success => "Success",
+ Status::Danger => "Danger",
+ }
+ .fmt(f)
+ }
+ }
+
+ #[derive(Debug, Clone, Default)]
+ pub struct Toast {
+ pub title: String,
+ pub body: String,
+ pub status: Status,
+ }
+
+ pub struct Manager<'a, Message> {
+ content: Element<'a, Message>,
+ toasts: Vec<Element<'a, Message>>,
+ timeout_secs: u64,
+ on_close: Box<dyn Fn(usize) -> Message + 'a>,
+ }
+
+ impl<'a, Message> Manager<'a, Message>
+ where
+ Message: 'a + Clone,
+ {
+ pub fn new(
+ content: impl Into<Element<'a, Message>>,
+ toasts: &'a [Toast],
+ on_close: impl Fn(usize) -> Message + 'a,
+ ) -> Self {
+ let toasts = toasts
+ .iter()
+ .enumerate()
+ .map(|(index, toast)| {
+ container(column![
+ container(
+ row![
+ text(toast.title.as_str()),
+ horizontal_space(Length::Fill),
+ button("X")
+ .on_press((on_close)(index))
+ .padding(3),
+ ]
+ .align_items(Alignment::Center)
+ )
+ .width(Length::Fill)
+ .padding(5)
+ .style(
+ theme::Container::Custom(Box::new(toast.status))
+ ),
+ horizontal_rule(1),
+ container(text(toast.body.as_str()))
+ .width(Length::Fill)
+ .padding(5)
+ .style(theme::Container::Box),
+ ])
+ .max_width(200)
+ .into()
+ })
+ .collect();
+
+ Self {
+ content: content.into(),
+ toasts,
+ timeout_secs: DEFAULT_TIMEOUT,
+ on_close: Box::new(on_close),
+ }
+ }
+
+ pub fn timeout(self, seconds: u64) -> Self {
+ Self {
+ timeout_secs: seconds,
+ ..self
+ }
+ }
+ }
+
+ impl<'a, Message> Widget<Message, Renderer> for Manager<'a, Message> {
+ fn width(&self) -> Length {
+ self.content.as_widget().width()
+ }
+
+ fn height(&self) -> Length {
+ self.content.as_widget().height()
+ }
+
+ fn layout(
+ &self,
+ renderer: &Renderer,
+ limits: &layout::Limits,
+ ) -> layout::Node {
+ self.content.as_widget().layout(renderer, limits)
+ }
+
+ fn tag(&self) -> tree::Tag {
+ struct Marker(Vec<Instant>);
+ iced_native::widget::tree::Tag::of::<Marker>()
+ }
+
+ fn state(&self) -> tree::State {
+ iced_native::widget::tree::State::new(Vec::<Option<Instant>>::new())
+ }
+
+ fn children(&self) -> Vec<Tree> {
+ std::iter::once(Tree::new(&self.content))
+ .chain(self.toasts.iter().map(Tree::new))
+ .collect()
+ }
+
+ fn diff(&self, tree: &mut Tree) {
+ let instants = tree.state.downcast_mut::<Vec<Option<Instant>>>();
+
+ // Invalidating removed instants to None allows us to remove
+ // them here so that diffing for removed / new toast instants
+ // is accurate
+ instants.retain(Option::is_some);
+
+ match (instants.len(), self.toasts.len()) {
+ (old, new) if old > new => {
+ instants.truncate(new);
+ }
+ (old, new) if old < new => {
+ instants.extend(
+ std::iter::repeat(Some(Instant::now())).take(new - old),
+ );
+ }
+ _ => {}
+ }
+
+ tree.diff_children(
+ &std::iter::once(&self.content)
+ .chain(self.toasts.iter())
+ .collect::<Vec<_>>(),
+ );
+ }
+
+ fn operate(
+ &self,
+ state: &mut Tree,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ operation: &mut dyn Operation<Message>,
+ ) {
+ operation.container(None, &mut |operation| {
+ self.content.as_widget().operate(
+ &mut state.children[0],
+ layout,
+ renderer,
+ operation,
+ );
+ });
+ }
+
+ 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.content.as_widget_mut().on_event(
+ &mut state.children[0],
+ event,
+ layout,
+ cursor_position,
+ renderer,
+ clipboard,
+ shell,
+ )
+ }
+
+ fn draw(
+ &self,
+ state: &Tree,
+ renderer: &mut Renderer,
+ theme: &Theme,
+ style: &renderer::Style,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ ) {
+ self.content.as_widget().draw(
+ &state.children[0],
+ renderer,
+ theme,
+ style,
+ layout,
+ cursor_position,
+ viewport,
+ );
+ }
+
+ fn mouse_interaction(
+ &self,
+ state: &Tree,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ renderer: &Renderer,
+ ) -> mouse::Interaction {
+ self.content.as_widget().mouse_interaction(
+ &state.children[0],
+ layout,
+ cursor_position,
+ viewport,
+ renderer,
+ )
+ }
+
+ fn overlay<'b>(
+ &'b mut self,
+ state: &'b mut Tree,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ ) -> Option<overlay::Element<'b, Message, Renderer>> {
+ let instants = state.state.downcast_mut::<Vec<Option<Instant>>>();
+
+ let (content_state, toasts_state) = state.children.split_at_mut(1);
+
+ let content = self.content.as_widget_mut().overlay(
+ &mut content_state[0],
+ layout,
+ renderer,
+ );
+
+ let toasts = (!self.toasts.is_empty()).then(|| {
+ overlay::Element::new(
+ layout.bounds().position(),
+ Box::new(Overlay {
+ toasts: &mut self.toasts,
+ state: toasts_state,
+ instants,
+ on_close: &self.on_close,
+ timeout_secs: self.timeout_secs,
+ }),
+ )
+ });
+ let overlays =
+ content.into_iter().chain(toasts).collect::<Vec<_>>();
+
+ (!overlays.is_empty())
+ .then(|| overlay::Group::with_children(overlays).overlay())
+ }
+ }
+
+ struct Overlay<'a, 'b, Message> {
+ toasts: &'b mut [Element<'a, Message>],
+ state: &'b mut [Tree],
+ instants: &'b mut [Option<Instant>],
+ on_close: &'b dyn Fn(usize) -> Message,
+ timeout_secs: u64,
+ }
+
+ impl<'a, 'b, Message> overlay::Overlay<Message, Renderer>
+ for Overlay<'a, 'b, Message>
+ {
+ fn layout(
+ &self,
+ renderer: &Renderer,
+ bounds: Size,
+ position: Point,
+ ) -> layout::Node {
+ let limits = layout::Limits::new(Size::ZERO, bounds)
+ .width(Length::Fill)
+ .height(Length::Fill);
+
+ layout::flex::resolve(
+ layout::flex::Axis::Vertical,
+ renderer,
+ &limits,
+ 10.into(),
+ 10.0,
+ Alignment::End,
+ self.toasts,
+ )
+ .translate(Vector::new(position.x, position.y))
+ }
+
+ fn on_event(
+ &mut self,
+ event: Event,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ renderer: &Renderer,
+ clipboard: &mut dyn Clipboard,
+ shell: &mut Shell<'_, Message>,
+ ) -> event::Status {
+ if let Event::Window(window::Event::RedrawRequested(now)) = &event {
+ let mut next_redraw: Option<window::RedrawRequest> = None;
+
+ self.instants.iter_mut().enumerate().for_each(
+ |(index, maybe_instant)| {
+ if let Some(instant) = maybe_instant.as_mut() {
+ let remaining =
+ Duration::from_secs(self.timeout_secs)
+ .saturating_sub(instant.elapsed());
+
+ if remaining == Duration::ZERO {
+ maybe_instant.take();
+ shell.publish((self.on_close)(index));
+ next_redraw =
+ Some(window::RedrawRequest::NextFrame);
+ } else {
+ let redraw_at =
+ window::RedrawRequest::At(*now + remaining);
+ next_redraw = next_redraw
+ .map(|redraw| redraw.min(redraw_at))
+ .or(Some(redraw_at));
+ }
+ }
+ },
+ );
+
+ if let Some(redraw) = next_redraw {
+ shell.request_redraw(redraw);
+ }
+ }
+
+ self.toasts
+ .iter_mut()
+ .zip(self.state.iter_mut())
+ .zip(layout.children())
+ .zip(self.instants.iter_mut())
+ .map(|(((child, state), layout), instant)| {
+ let mut local_messages = vec![];
+ let mut local_shell = Shell::new(&mut local_messages);
+
+ let status = child.as_widget_mut().on_event(
+ state,
+ event.clone(),
+ layout,
+ cursor_position,
+ renderer,
+ clipboard,
+ &mut local_shell,
+ );
+
+ if !local_shell.is_empty() {
+ instant.take();
+ }
+
+ shell.merge(local_shell, std::convert::identity);
+
+ status
+ })
+ .fold(event::Status::Ignored, event::Status::merge)
+ }
+
+ fn draw(
+ &self,
+ renderer: &mut Renderer,
+ theme: &<Renderer as iced_native::Renderer>::Theme,
+ style: &renderer::Style,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ ) {
+ let viewport = layout.bounds();
+
+ for ((child, state), layout) in self
+ .toasts
+ .iter()
+ .zip(self.state.iter())
+ .zip(layout.children())
+ {
+ child.as_widget().draw(
+ state,
+ renderer,
+ theme,
+ style,
+ layout,
+ cursor_position,
+ &viewport,
+ );
+ }
+ }
+
+ fn operate(
+ &mut self,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ operation: &mut dyn iced_native::widget::Operation<Message>,
+ ) {
+ operation.container(None, &mut |operation| {
+ self.toasts
+ .iter()
+ .zip(self.state.iter_mut())
+ .zip(layout.children())
+ .for_each(|((child, state), layout)| {
+ child
+ .as_widget()
+ .operate(state, layout, renderer, operation);
+ })
+ });
+ }
+
+ fn mouse_interaction(
+ &self,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ renderer: &Renderer,
+ ) -> mouse::Interaction {
+ self.toasts
+ .iter()
+ .zip(self.state.iter())
+ .zip(layout.children())
+ .map(|((child, state), layout)| {
+ child.as_widget().mouse_interaction(
+ state,
+ layout,
+ cursor_position,
+ viewport,
+ renderer,
+ )
+ })
+ .max()
+ .unwrap_or_default()
+ }
+
+ fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
+ layout
+ .children()
+ .any(|layout| layout.bounds().contains(cursor_position))
+ }
+ }
+
+ impl<'a, Message> From<Manager<'a, Message>> for Element<'a, Message>
+ where
+ Message: 'a,
+ {
+ fn from(manager: Manager<'a, Message>) -> Self {
+ Element::new(manager)
+ }
+ }
+}
diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs
index 690d9c09..04411ed7 100644
--- a/examples/todos/src/main.rs
+++ b/examples/todos/src/main.rs
@@ -303,7 +303,7 @@ pub enum TaskMessage {
impl Task {
fn text_input_id(i: usize) -> text_input::Id {
- text_input::Id::new(format!("task-{}", i))
+ text_input::Id::new(format!("task-{i}"))
}
fn new(description: String) -> Self {
diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs
index 378508e1..5ee65562 100644
--- a/examples/tour/src/main.rs
+++ b/examples/tour/src/main.rs
@@ -388,7 +388,7 @@ impl<'a> Step {
let spacing_section = column![
slider(0..=80, spacing, StepMessage::SpacingChanged),
- text(format!("{} px", spacing))
+ text(format!("{spacing} px"))
.width(Length::Fill)
.horizontal_alignment(alignment::Horizontal::Center),
]
@@ -412,7 +412,7 @@ impl<'a> Step {
fn text(size: u16, color: Color) -> Column<'a, StepMessage> {
let size_section = column![
"You can change its size:",
- text(format!("This text is {} pixels", size)).size(size),
+ text(format!("This text is {size} pixels")).size(size),
slider(10..=70, size, StepMessage::TextSizeChanged),
]
.padding(20)
@@ -427,7 +427,7 @@ impl<'a> Step {
let color_section = column![
"And its color:",
- text(format!("{:?}", color)).style(color),
+ text(format!("{color:?}")).style(color),
color_sliders,
]
.padding(20)
@@ -497,7 +497,7 @@ impl<'a> Step {
.push(ferris(width))
.push(slider(100..=500, width, StepMessage::ImageWidthChanged))
.push(
- text(format!("Width: {} px", width))
+ text(format!("Width: {width} px"))
.width(Length::Fill)
.horizontal_alignment(alignment::Horizontal::Center),
)
diff --git a/examples/websocket/src/echo.rs b/examples/websocket/src/echo.rs
index ae65e064..e74768a6 100644
--- a/examples/websocket/src/echo.rs
+++ b/examples/websocket/src/echo.rs
@@ -141,7 +141,7 @@ impl fmt::Display for Message {
Message::Disconnected => {
write!(f, "Connection lost... Retrying...")
}
- Message::User(message) => write!(f, "{}", message),
+ Message::User(message) => write!(f, "{message}"),
}
}
}
diff --git a/examples/websocket/src/echo/server.rs b/examples/websocket/src/echo/server.rs
index fef89a12..dd234984 100644
--- a/examples/websocket/src/echo/server.rs
+++ b/examples/websocket/src/echo/server.rs
@@ -41,7 +41,7 @@ async fn user_connected(ws: WebSocket) {
tokio::task::spawn(async move {
while let Some(message) = rx.next().await {
user_ws_tx.send(message).await.unwrap_or_else(|e| {
- eprintln!("websocket send error: {}", e);
+ eprintln!("websocket send error: {e}");
});
}
});