summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/arc/src/main.rs7
-rw-r--r--examples/bezier_tool/src/main.rs12
-rw-r--r--examples/clock/src/main.rs14
-rw-r--r--examples/color_palette/src/main.rs13
-rw-r--r--examples/combo_box/src/main.rs6
-rw-r--r--examples/component/src/main.rs156
-rw-r--r--examples/counter/src/main.rs4
-rw-r--r--examples/custom_quad/src/main.rs43
-rw-r--r--examples/custom_shader/src/main.rs9
-rw-r--r--examples/custom_widget/src/main.rs18
-rw-r--r--examples/download_progress/Cargo.toml4
-rw-r--r--examples/download_progress/index.html12
-rw-r--r--examples/download_progress/src/download.rs105
-rw-r--r--examples/download_progress/src/main.rs30
-rw-r--r--examples/editor/src/main.rs113
-rw-r--r--examples/events/src/main.rs17
-rw-r--r--examples/exit/src/main.rs4
-rw-r--r--examples/ferris/src/main.rs18
-rw-r--r--examples/game_of_life/src/main.rs20
-rw-r--r--examples/gradient/src/main.rs10
-rw-r--r--examples/integration/src/controls.rs6
-rw-r--r--examples/integration/src/main.rs2
-rw-r--r--examples/layout/src/main.rs28
-rw-r--r--examples/lazy/src/main.rs4
-rw-r--r--examples/loading_spinners/src/main.rs6
-rw-r--r--examples/loupe/src/main.rs4
-rw-r--r--examples/markdown/Cargo.toml (renamed from examples/component/Cargo.toml)6
-rw-r--r--examples/markdown/overview.md93
-rw-r--r--examples/markdown/src/main.rs82
-rw-r--r--examples/modal/src/main.rs39
-rw-r--r--examples/multi_window/src/main.rs29
-rw-r--r--examples/multitouch/src/main.rs7
-rw-r--r--examples/pane_grid/src/main.rs50
-rw-r--r--examples/pick_list/src/main.rs6
-rw-r--r--examples/pokedex/Cargo.toml2
-rw-r--r--examples/pokedex/src/main.rs33
-rw-r--r--examples/qr_code/src/main.rs6
-rw-r--r--examples/screenshot/src/main.rs103
-rw-r--r--examples/scrollable/src/main.rs105
-rw-r--r--examples/sierpinski_triangle/src/main.rs8
-rw-r--r--examples/slider/Cargo.toml1
-rw-r--r--examples/slider/src/main.rs43
-rw-r--r--examples/solar_system/Cargo.toml2
-rw-r--r--examples/solar_system/assets/earth.pngbin0 -> 91888 bytes
-rw-r--r--examples/solar_system/assets/moon.pngbin0 -> 105100 bytes
-rw-r--r--examples/solar_system/assets/sun.pngbin0 -> 114689 bytes
-rw-r--r--examples/solar_system/src/main.rs70
-rw-r--r--examples/stopwatch/src/main.rs16
-rw-r--r--examples/styling/src/main.rs23
-rw-r--r--examples/svg/src/main.rs26
-rw-r--r--examples/the_matrix/src/main.rs8
-rw-r--r--examples/toast/src/main.rs24
-rw-r--r--examples/todos/src/main.rs54
-rw-r--r--examples/tour/src/main.rs52
-rw-r--r--examples/vectorial_text/src/main.rs8
-rw-r--r--examples/visible_bounds/src/main.rs10
-rw-r--r--examples/websocket/src/echo.rs102
-rw-r--r--examples/websocket/src/main.rs48
58 files changed, 830 insertions, 891 deletions
diff --git a/examples/arc/src/main.rs b/examples/arc/src/main.rs
index b1e8402a..18873259 100644
--- a/examples/arc/src/main.rs
+++ b/examples/arc/src/main.rs
@@ -4,7 +4,7 @@ use iced::mouse;
use iced::widget::canvas::{
self, stroke, Cache, Canvas, Geometry, Path, Stroke,
};
-use iced::{Element, Length, Point, Rectangle, Renderer, Subscription, Theme};
+use iced::{Element, Fill, Point, Rectangle, Renderer, Subscription, Theme};
pub fn main() -> iced::Result {
iced::application("Arc - Iced", Arc::update, Arc::view)
@@ -30,10 +30,7 @@ impl Arc {
}
fn view(&self) -> Element<Message> {
- Canvas::new(self)
- .width(Length::Fill)
- .height(Length::Fill)
- .into()
+ Canvas::new(self).width(Fill).height(Fill).into()
}
fn subscription(&self) -> Subscription<Message> {
diff --git a/examples/bezier_tool/src/main.rs b/examples/bezier_tool/src/main.rs
index eaf84b97..949bfad7 100644
--- a/examples/bezier_tool/src/main.rs
+++ b/examples/bezier_tool/src/main.rs
@@ -1,7 +1,6 @@
//! This example showcases an interactive `Canvas` for drawing Bézier curves.
-use iced::alignment;
use iced::widget::{button, container, horizontal_space, hover};
-use iced::{Element, Length, Theme};
+use iced::{Element, Fill, Theme};
pub fn main() -> iced::Result {
iced::application("Bezier Tool - Iced", Example::update, Example::view)
@@ -48,8 +47,7 @@ impl Example {
.on_press(Message::Clear),
)
.padding(10)
- .width(Length::Fill)
- .align_x(alignment::Horizontal::Right)
+ .align_right(Fill)
},
))
.padding(20)
@@ -61,7 +59,7 @@ mod bezier {
use iced::mouse;
use iced::widget::canvas::event::{self, Event};
use iced::widget::canvas::{self, Canvas, Frame, Geometry, Path, Stroke};
- use iced::{Element, Length, Point, Rectangle, Renderer, Theme};
+ use iced::{Element, Fill, Point, Rectangle, Renderer, Theme};
#[derive(Default)]
pub struct State {
@@ -74,8 +72,8 @@ mod bezier {
state: self,
curves,
})
- .width(Length::Fill)
- .height(Length::Fill)
+ .width(Fill)
+ .height(Fill)
.into()
}
diff --git a/examples/clock/src/main.rs b/examples/clock/src/main.rs
index 4584a0c7..ef3064c7 100644
--- a/examples/clock/src/main.rs
+++ b/examples/clock/src/main.rs
@@ -4,7 +4,7 @@ use iced::time;
use iced::widget::canvas::{stroke, Cache, Geometry, LineCap, Path, Stroke};
use iced::widget::{canvas, container};
use iced::{
- Degrees, Element, Font, Length, Point, Rectangle, Renderer, Subscription,
+ Degrees, Element, Fill, Font, Point, Rectangle, Renderer, Subscription,
Theme, Vector,
};
@@ -43,15 +43,9 @@ impl Clock {
}
fn view(&self) -> Element<Message> {
- let canvas = canvas(self as &Self)
- .width(Length::Fill)
- .height(Length::Fill);
-
- container(canvas)
- .width(Length::Fill)
- .height(Length::Fill)
- .padding(20)
- .into()
+ let canvas = canvas(self as &Self).width(Fill).height(Fill);
+
+ container(canvas).padding(20).into()
}
fn subscription(&self) -> Subscription<Message> {
diff --git a/examples/color_palette/src/main.rs b/examples/color_palette/src/main.rs
index e4b19731..7f21003b 100644
--- a/examples/color_palette/src/main.rs
+++ b/examples/color_palette/src/main.rs
@@ -1,10 +1,10 @@
-use iced::alignment::{self, Alignment};
+use iced::alignment;
use iced::mouse;
use iced::widget::canvas::{self, Canvas, Frame, Geometry, Path};
use iced::widget::{column, row, text, Slider};
use iced::{
- Color, Element, Font, Length, Pixels, Point, Rectangle, Renderer, Size,
- Vector,
+ Center, Color, Element, Fill, Font, Pixels, Point, Rectangle, Renderer,
+ Size, Vector,
};
use palette::{convert::FromColor, rgb::Rgb, Darken, Hsl, Lighten, ShiftHue};
use std::marker::PhantomData;
@@ -150,10 +150,7 @@ impl Theme {
}
pub fn view(&self) -> Element<Message> {
- Canvas::new(self)
- .width(Length::Fill)
- .height(Length::Fill)
- .into()
+ Canvas::new(self).width(Fill).height(Fill).into()
}
fn draw(&self, frame: &mut Frame, text_color: Color) {
@@ -320,7 +317,7 @@ impl<C: ColorSpace + Copy> ColorPicker<C> {
text(color.to_string()).width(185).size(12),
]
.spacing(10)
- .align_items(Alignment::Center)
+ .align_y(Center)
.into()
}
}
diff --git a/examples/combo_box/src/main.rs b/examples/combo_box/src/main.rs
index ff759ab4..af53b17a 100644
--- a/examples/combo_box/src/main.rs
+++ b/examples/combo_box/src/main.rs
@@ -1,7 +1,7 @@
use iced::widget::{
center, column, combo_box, scrollable, text, vertical_space,
};
-use iced::{Alignment, Element, Length};
+use iced::{Center, Element, Fill};
pub fn main() -> iced::Result {
iced::run("Combo Box - Iced", Example::update, Example::view)
@@ -64,8 +64,8 @@ impl Example {
combo_box,
vertical_space().height(150),
]
- .width(Length::Fill)
- .align_items(Alignment::Center)
+ .width(Fill)
+ .align_x(Center)
.spacing(10);
center(scrollable(content)).into()
diff --git a/examples/component/src/main.rs b/examples/component/src/main.rs
deleted file mode 100644
index 5625f12a..00000000
--- a/examples/component/src/main.rs
+++ /dev/null
@@ -1,156 +0,0 @@
-use iced::widget::center;
-use iced::Element;
-
-use numeric_input::numeric_input;
-
-pub fn main() -> iced::Result {
- iced::run("Component - Iced", Component::update, Component::view)
-}
-
-#[derive(Default)]
-struct Component {
- value: Option<u32>,
-}
-
-#[derive(Debug, Clone, Copy)]
-enum Message {
- NumericInputChanged(Option<u32>),
-}
-
-impl Component {
- fn update(&mut self, message: Message) {
- match message {
- Message::NumericInputChanged(value) => {
- self.value = value;
- }
- }
- }
-
- fn view(&self) -> Element<Message> {
- center(numeric_input(self.value, Message::NumericInputChanged))
- .padding(20)
- .into()
- }
-}
-
-mod numeric_input {
- use iced::alignment::{self, Alignment};
- use iced::widget::{button, component, row, text, text_input, Component};
- use iced::{Element, Length, Size};
-
- pub struct NumericInput<Message> {
- value: Option<u32>,
- on_change: Box<dyn Fn(Option<u32>) -> Message>,
- }
-
- pub fn numeric_input<Message>(
- value: Option<u32>,
- on_change: impl Fn(Option<u32>) -> Message + 'static,
- ) -> NumericInput<Message> {
- NumericInput::new(value, on_change)
- }
-
- #[derive(Debug, Clone)]
- pub enum Event {
- InputChanged(String),
- IncrementPressed,
- DecrementPressed,
- }
-
- impl<Message> NumericInput<Message> {
- pub fn new(
- value: Option<u32>,
- on_change: impl Fn(Option<u32>) -> Message + 'static,
- ) -> Self {
- Self {
- value,
- on_change: Box::new(on_change),
- }
- }
- }
-
- impl<Message, Theme> Component<Message, Theme> for NumericInput<Message>
- where
- Theme: text::Catalog + button::Catalog + text_input::Catalog + 'static,
- {
- type State = ();
- type Event = Event;
-
- fn update(
- &mut self,
- _state: &mut Self::State,
- event: Event,
- ) -> Option<Message> {
- match event {
- Event::IncrementPressed => Some((self.on_change)(Some(
- self.value.unwrap_or_default().saturating_add(1),
- ))),
- Event::DecrementPressed => Some((self.on_change)(Some(
- self.value.unwrap_or_default().saturating_sub(1),
- ))),
- Event::InputChanged(value) => {
- if value.is_empty() {
- Some((self.on_change)(None))
- } else {
- value
- .parse()
- .ok()
- .map(Some)
- .map(self.on_change.as_ref())
- }
- }
- }
- }
-
- fn view(&self, _state: &Self::State) -> Element<'_, Event, Theme> {
- let button = |label, on_press| {
- button(
- text(label)
- .width(Length::Fill)
- .height(Length::Fill)
- .horizontal_alignment(alignment::Horizontal::Center)
- .vertical_alignment(alignment::Vertical::Center),
- )
- .width(40)
- .height(40)
- .on_press(on_press)
- };
-
- row![
- button("-", Event::DecrementPressed),
- text_input(
- "Type a number",
- self.value
- .as_ref()
- .map(u32::to_string)
- .as_deref()
- .unwrap_or(""),
- )
- .on_input(Event::InputChanged)
- .padding(10),
- button("+", Event::IncrementPressed),
- ]
- .align_items(Alignment::Center)
- .spacing(10)
- .into()
- }
-
- fn size_hint(&self) -> Size<Length> {
- Size {
- width: Length::Fill,
- height: Length::Shrink,
- }
- }
- }
-
- impl<'a, Message, Theme> From<NumericInput<Message>>
- for Element<'a, Message, Theme>
- where
- Theme: text::Catalog + button::Catalog + text_input::Catalog + 'static,
- Message: 'a,
- {
- fn from(numeric_input: NumericInput<Message>) -> Self {
- component(numeric_input)
- }
- }
-}
diff --git a/examples/counter/src/main.rs b/examples/counter/src/main.rs
index 0dd7a976..81684c1c 100644
--- a/examples/counter/src/main.rs
+++ b/examples/counter/src/main.rs
@@ -1,5 +1,5 @@
use iced::widget::{button, column, text, Column};
-use iced::Alignment;
+use iced::Center;
pub fn main() -> iced::Result {
iced::run("A cool counter", Counter::update, Counter::view)
@@ -35,6 +35,6 @@ impl Counter {
button("Decrement").on_press(Message::Decrement)
]
.padding(20)
- .align_items(Alignment::Center)
+ .align_x(Center)
}
}
diff --git a/examples/custom_quad/src/main.rs b/examples/custom_quad/src/main.rs
index b53a40d6..dc425cc6 100644
--- a/examples/custom_quad/src/main.rs
+++ b/examples/custom_quad/src/main.rs
@@ -3,12 +3,13 @@ mod quad {
use iced::advanced::layout::{self, Layout};
use iced::advanced::renderer;
use iced::advanced::widget::{self, Widget};
+ use iced::border;
use iced::mouse;
use iced::{Border, Color, Element, Length, Rectangle, Shadow, Size};
pub struct CustomQuad {
size: f32,
- radius: [f32; 4],
+ radius: border::Radius,
border_width: f32,
shadow: Shadow,
}
@@ -16,7 +17,7 @@ mod quad {
impl CustomQuad {
pub fn new(
size: f32,
- radius: [f32; 4],
+ radius: border::Radius,
border_width: f32,
shadow: Shadow,
) -> Self {
@@ -63,7 +64,7 @@ mod quad {
renderer::Quad {
bounds: layout.bounds(),
border: Border {
- radius: self.radius.into(),
+ radius: self.radius,
width: self.border_width,
color: Color::from_rgb(1.0, 0.0, 0.0),
},
@@ -81,15 +82,16 @@ mod quad {
}
}
+use iced::border;
use iced::widget::{center, column, slider, text};
-use iced::{Alignment, Color, Element, Shadow, Vector};
+use iced::{Center, Color, Element, Shadow, Vector};
pub fn main() -> iced::Result {
iced::run("Custom Quad - Iced", Example::update, Example::view)
}
struct Example {
- radius: [f32; 4],
+ radius: border::Radius,
border_width: f32,
shadow: Shadow,
}
@@ -110,7 +112,7 @@ enum Message {
impl Example {
fn new() -> Self {
Self {
- radius: [50.0; 4],
+ radius: border::radius(50),
border_width: 0.0,
shadow: Shadow {
color: Color::from_rgba(0.0, 0.0, 0.0, 0.8),
@@ -121,19 +123,18 @@ impl Example {
}
fn update(&mut self, message: Message) {
- let [tl, tr, br, bl] = self.radius;
match message {
Message::RadiusTopLeftChanged(radius) => {
- self.radius = [radius, tr, br, bl];
+ self.radius = self.radius.top_left(radius);
}
Message::RadiusTopRightChanged(radius) => {
- self.radius = [tl, radius, br, bl];
+ self.radius = self.radius.top_right(radius);
}
Message::RadiusBottomRightChanged(radius) => {
- self.radius = [tl, tr, radius, bl];
+ self.radius = self.radius.bottom_right(radius);
}
Message::RadiusBottomLeftChanged(radius) => {
- self.radius = [tl, tr, br, radius];
+ self.radius = self.radius.bottom_left(radius);
}
Message::BorderWidthChanged(width) => {
self.border_width = width;
@@ -151,7 +152,13 @@ impl Example {
}
fn view(&self) -> Element<Message> {
- let [tl, tr, br, bl] = self.radius;
+ let border::Radius {
+ top_left,
+ top_right,
+ bottom_right,
+ bottom_left,
+ } = self.radius;
+
let Shadow {
offset: Vector { x: sx, y: sy },
blur_radius: sr,
@@ -165,12 +172,12 @@ impl Example {
self.border_width,
self.shadow
),
- text!("Radius: {tl:.2}/{tr:.2}/{br:.2}/{bl:.2}"),
- slider(1.0..=100.0, tl, Message::RadiusTopLeftChanged).step(0.01),
- slider(1.0..=100.0, tr, Message::RadiusTopRightChanged).step(0.01),
- slider(1.0..=100.0, br, Message::RadiusBottomRightChanged)
+ text!("Radius: {top_left:.2}/{top_right:.2}/{bottom_right:.2}/{bottom_left:.2}"),
+ slider(1.0..=100.0, top_left, Message::RadiusTopLeftChanged).step(0.01),
+ slider(1.0..=100.0, top_right, Message::RadiusTopRightChanged).step(0.01),
+ slider(1.0..=100.0, bottom_right, Message::RadiusBottomRightChanged)
.step(0.01),
- slider(1.0..=100.0, bl, Message::RadiusBottomLeftChanged)
+ slider(1.0..=100.0, bottom_left, Message::RadiusBottomLeftChanged)
.step(0.01),
slider(1.0..=10.0, self.border_width, Message::BorderWidthChanged)
.step(0.01),
@@ -185,7 +192,7 @@ impl Example {
.padding(20)
.spacing(20)
.max_width(500)
- .align_items(Alignment::Center);
+ .align_x(Center);
center(content).into()
}
diff --git a/examples/custom_shader/src/main.rs b/examples/custom_shader/src/main.rs
index b04a8183..5886f6bb 100644
--- a/examples/custom_shader/src/main.rs
+++ b/examples/custom_shader/src/main.rs
@@ -6,7 +6,7 @@ use iced::time::Instant;
use iced::widget::shader::wgpu;
use iced::widget::{center, checkbox, column, row, shader, slider, text};
use iced::window;
-use iced::{Alignment, Color, Element, Length, Subscription};
+use iced::{Center, Color, Element, Fill, Subscription};
fn main() -> iced::Result {
iced::application(
@@ -122,12 +122,11 @@ impl IcedCubes {
let controls = column![top_controls, bottom_controls,]
.spacing(10)
.padding(20)
- .align_items(Alignment::Center);
+ .align_x(Center);
- let shader =
- shader(&self.scene).width(Length::Fill).height(Length::Fill);
+ let shader = shader(&self.scene).width(Fill).height(Fill);
- center(column![shader, controls].align_items(Alignment::Center)).into()
+ center(column![shader, controls].align_x(Center)).into()
}
fn subscription(&self) -> Subscription<Message> {
diff --git a/examples/custom_widget/src/main.rs b/examples/custom_widget/src/main.rs
index 3cf10e22..58f3c54a 100644
--- a/examples/custom_widget/src/main.rs
+++ b/examples/custom_widget/src/main.rs
@@ -1,19 +1,11 @@
//! This example showcases a simple native custom widget that draws a circle.
mod circle {
- // For now, to implement a custom native widget you will need to add
- // `iced_native` and `iced_wgpu` to your dependencies.
- //
- // Then, you simply need to define your widget type and implement the
- // `iced_native::Widget` trait with the `iced_wgpu::Renderer`.
- //
- // Of course, you can choose to make the implementation renderer-agnostic,
- // if you wish to, by creating your own `Renderer` trait, which could be
- // implemented by `iced_wgpu` and other renderers.
use iced::advanced::layout::{self, Layout};
use iced::advanced::renderer;
use iced::advanced::widget::{self, Widget};
+ use iced::border;
use iced::mouse;
- use iced::{Border, Color, Element, Length, Rectangle, Size};
+ use iced::{Color, Element, Length, Rectangle, Size};
pub struct Circle {
radius: f32,
@@ -62,7 +54,7 @@ mod circle {
renderer.fill_quad(
renderer::Quad {
bounds: layout.bounds(),
- border: Border::rounded(self.radius),
+ border: border::rounded(self.radius),
..renderer::Quad::default()
},
Color::BLACK,
@@ -83,7 +75,7 @@ mod circle {
use circle::circle;
use iced::widget::{center, column, slider, text};
-use iced::{Alignment, Element};
+use iced::{Center, Element};
pub fn main() -> iced::Result {
iced::run("Custom Widget - Iced", Example::update, Example::view)
@@ -120,7 +112,7 @@ impl Example {
.padding(20)
.spacing(20)
.max_width(500)
- .align_items(Alignment::Center);
+ .align_x(Center);
center(content).into()
}
diff --git a/examples/download_progress/Cargo.toml b/examples/download_progress/Cargo.toml
index 18a49f66..61a1b257 100644
--- a/examples/download_progress/Cargo.toml
+++ b/examples/download_progress/Cargo.toml
@@ -10,6 +10,6 @@ iced.workspace = true
iced.features = ["tokio"]
[dependencies.reqwest]
-version = "0.11"
+version = "0.12"
default-features = false
-features = ["rustls-tls"]
+features = ["stream", "rustls-tls"]
diff --git a/examples/download_progress/index.html b/examples/download_progress/index.html
new file mode 100644
index 00000000..c79e32c1
--- /dev/null
+++ b/examples/download_progress/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en" style="height: 100%">
+<head>
+ <meta charset="utf-8" content="text/html; charset=utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <title>Download_Progress - Iced</title>
+ <base data-trunk-public-url />
+</head>
+<body style="height: 100%; margin: 0">
+<link data-trunk rel="rust" href="Cargo.toml" data-wasm-opt="z" data-bin="download_progress" />
+</body>
+</html>
diff --git a/examples/download_progress/src/download.rs b/examples/download_progress/src/download.rs
index d6cc1e24..a8e7b404 100644
--- a/examples/download_progress/src/download.rs
+++ b/examples/download_progress/src/download.rs
@@ -1,85 +1,62 @@
-use iced::subscription;
+use iced::futures::{SinkExt, Stream, StreamExt};
+use iced::stream::try_channel;
+use iced::Subscription;
use std::hash::Hash;
+use std::sync::Arc;
// Just a little utility function
pub fn file<I: 'static + Hash + Copy + Send + Sync, T: ToString>(
id: I,
url: T,
-) -> iced::Subscription<(I, Progress)> {
- subscription::unfold(id, State::Ready(url.to_string()), move |state| {
- download(id, state)
- })
+) -> iced::Subscription<(I, Result<Progress, Error>)> {
+ Subscription::run_with_id(
+ id,
+ download(url.to_string()).map(move |progress| (id, progress)),
+ )
}
-async fn download<I: Copy>(id: I, state: State) -> ((I, Progress), State) {
- match state {
- State::Ready(url) => {
- let response = reqwest::get(&url).await;
+fn download(url: String) -> impl Stream<Item = Result<Progress, Error>> {
+ try_channel(1, move |mut output| async move {
+ let response = reqwest::get(&url).await?;
+ let total = response.content_length().ok_or(Error::NoContentLength)?;
- match response {
- Ok(response) => {
- if let Some(total) = response.content_length() {
- (
- (id, Progress::Started),
- State::Downloading {
- response,
- total,
- downloaded: 0,
- },
- )
- } else {
- ((id, Progress::Errored), State::Finished)
- }
- }
- Err(_) => ((id, Progress::Errored), State::Finished),
- }
- }
- State::Downloading {
- mut response,
- total,
- downloaded,
- } => match response.chunk().await {
- Ok(Some(chunk)) => {
- let downloaded = downloaded + chunk.len() as u64;
+ let _ = output.send(Progress::Downloading { percent: 0.0 }).await;
+
+ let mut byte_stream = response.bytes_stream();
+ let mut downloaded = 0;
- let percentage = (downloaded as f32 / total as f32) * 100.0;
+ while let Some(next_bytes) = byte_stream.next().await {
+ let bytes = next_bytes?;
+ downloaded += bytes.len();
- (
- (id, Progress::Advanced(percentage)),
- State::Downloading {
- response,
- total,
- downloaded,
- },
- )
- }
- Ok(None) => ((id, Progress::Finished), State::Finished),
- Err(_) => ((id, Progress::Errored), State::Finished),
- },
- State::Finished => {
- // We do not let the stream die, as it would start a
- // new download repeatedly if the user is not careful
- // in case of errors.
- iced::futures::future::pending().await
+ let _ = output
+ .send(Progress::Downloading {
+ percent: 100.0 * downloaded as f32 / total as f32,
+ })
+ .await;
}
- }
+
+ let _ = output.send(Progress::Finished).await;
+
+ Ok(())
+ })
}
#[derive(Debug, Clone)]
pub enum Progress {
- Started,
- Advanced(f32),
+ Downloading { percent: f32 },
Finished,
- Errored,
}
-pub enum State {
- Ready(String),
- Downloading {
- response: reqwest::Response,
- total: u64,
- downloaded: u64,
- },
- Finished,
+#[derive(Debug, Clone)]
+pub enum Error {
+ RequestFailed(Arc<reqwest::Error>),
+ NoContentLength,
+}
+
+impl From<reqwest::Error> for Error {
+ fn from(error: reqwest::Error) -> Self {
+ Error::RequestFailed(Arc::new(error))
+ }
}
diff --git a/examples/download_progress/src/main.rs b/examples/download_progress/src/main.rs
index d91e5eab..bcc01606 100644
--- a/examples/download_progress/src/main.rs
+++ b/examples/download_progress/src/main.rs
@@ -1,7 +1,7 @@
mod download;
use iced::widget::{button, center, column, progress_bar, text, Column};
-use iced::{Alignment, Element, Subscription};
+use iced::{Center, Element, Right, Subscription};
pub fn main() -> iced::Result {
iced::application(
@@ -23,7 +23,7 @@ struct Example {
pub enum Message {
Add,
Download(usize),
- DownloadProgressed((usize, download::Progress)),
+ DownloadProgressed((usize, Result<download::Progress, download::Error>)),
}
impl Example {
@@ -69,7 +69,7 @@ impl Example {
.padding(10),
)
.spacing(20)
- .align_items(Alignment::End);
+ .align_x(Right);
center(downloads).padding(20).into()
}
@@ -114,19 +114,19 @@ impl Download {
}
}
- pub fn progress(&mut self, new_progress: download::Progress) {
+ pub fn progress(
+ &mut self,
+ new_progress: Result<download::Progress, download::Error>,
+ ) {
if let State::Downloading { progress } = &mut self.state {
match new_progress {
- download::Progress::Started => {
- *progress = 0.0;
+ Ok(download::Progress::Downloading { percent }) => {
+ *progress = percent;
}
- download::Progress::Advanced(percentage) => {
- *progress = percentage;
- }
- download::Progress::Finished => {
+ Ok(download::Progress::Finished) => {
self.state = State::Finished;
}
- download::Progress::Errored => {
+ Err(_error) => {
self.state = State::Errored;
}
}
@@ -136,7 +136,7 @@ impl Download {
pub fn subscription(&self) -> Subscription<Message> {
match self.state {
State::Downloading { .. } => {
- download::file(self.id, "https://speed.hetzner.de/100MB.bin?")
+ download::file(self.id, "https://huggingface.co/mattshumer/Reflection-Llama-3.1-70B/resolve/main/model-00001-of-00162.safetensors")
.map(Message::DownloadProgressed)
}
_ => Subscription::none(),
@@ -160,7 +160,7 @@ impl Download {
State::Finished => {
column!["Download finished!", button("Start again")]
.spacing(10)
- .align_items(Alignment::Center)
+ .align_x(Center)
.into()
}
State::Downloading { .. } => {
@@ -171,14 +171,14 @@ impl Download {
button("Try again").on_press(Message::Download(self.id)),
]
.spacing(10)
- .align_items(Alignment::Center)
+ .align_x(Center)
.into(),
};
Column::new()
.spacing(10)
.padding(10)
- .align_items(Alignment::Center)
+ .align_x(Center)
.push(progress_bar)
.push(control)
.into()
diff --git a/examples/editor/src/main.rs b/examples/editor/src/main.rs
index bed9d94a..d55f9bdf 100644
--- a/examples/editor/src/main.rs
+++ b/examples/editor/src/main.rs
@@ -1,10 +1,10 @@
-use iced::highlighter::{self, Highlighter};
+use iced::highlighter;
use iced::keyboard;
use iced::widget::{
- button, column, container, horizontal_space, pick_list, row, text,
- text_editor, tooltip,
+ self, button, column, container, horizontal_space, pick_list, row, text,
+ text_editor, toggler, tooltip,
};
-use iced::{Alignment, Element, Font, Length, Subscription, Task, Theme};
+use iced::{Center, Element, Fill, Font, Task, Theme};
use std::ffi;
use std::io;
@@ -13,18 +13,17 @@ use std::sync::Arc;
pub fn main() -> iced::Result {
iced::application("Editor - Iced", Editor::update, Editor::view)
- .load(Editor::load)
- .subscription(Editor::subscription)
.theme(Editor::theme)
.font(include_bytes!("../fonts/icons.ttf").as_slice())
.default_font(Font::MONOSPACE)
- .run()
+ .run_with(Editor::new)
}
struct Editor {
file: Option<PathBuf>,
content: text_editor::Content,
theme: highlighter::Theme,
+ word_wrap: bool,
is_loading: bool,
is_dirty: bool,
}
@@ -33,6 +32,7 @@ struct Editor {
enum Message {
ActionPerformed(text_editor::Action),
ThemeSelected(highlighter::Theme),
+ WordWrapToggled(bool),
NewFile,
OpenFile,
FileOpened(Result<(PathBuf, Arc<String>), Error>),
@@ -41,20 +41,26 @@ enum Message {
}
impl Editor {
- fn new() -> Self {
- Self {
- file: None,
- content: text_editor::Content::new(),
- theme: highlighter::Theme::SolarizedDark,
- is_loading: true,
- is_dirty: false,
- }
- }
-
- fn load() -> Task<Message> {
- Task::perform(
- load_file(format!("{}/src/main.rs", env!("CARGO_MANIFEST_DIR"))),
- Message::FileOpened,
+ fn new() -> (Self, Task<Message>) {
+ (
+ Self {
+ file: None,
+ content: text_editor::Content::new(),
+ theme: highlighter::Theme::SolarizedDark,
+ word_wrap: true,
+ is_loading: true,
+ is_dirty: false,
+ },
+ Task::batch([
+ Task::perform(
+ load_file(format!(
+ "{}/src/main.rs",
+ env!("CARGO_MANIFEST_DIR")
+ )),
+ Message::FileOpened,
+ ),
+ widget::focus_next(),
+ ]),
)
}
@@ -72,6 +78,11 @@ impl Editor {
Task::none()
}
+ Message::WordWrapToggled(word_wrap) => {
+ self.word_wrap = word_wrap;
+
+ Task::none()
+ }
Message::NewFile => {
if !self.is_loading {
self.file = None;
@@ -125,15 +136,6 @@ impl Editor {
}
}
- fn subscription(&self) -> Subscription<Message> {
- keyboard::on_key_press(|key, modifiers| match key.as_ref() {
- keyboard::Key::Character("s") if modifiers.command() => {
- Some(Message::SaveFile)
- }
- _ => None,
- })
- }
-
fn view(&self) -> Element<Message> {
let controls = row![
action(new_icon(), "New file", Some(Message::NewFile)),
@@ -148,6 +150,9 @@ impl Editor {
self.is_dirty.then_some(Message::SaveFile)
),
horizontal_space(),
+ toggler(self.word_wrap)
+ .label("Word Wrap")
+ .on_toggle(Message::WordWrapToggled),
pick_list(
highlighter::Theme::ALL,
Some(self.theme),
@@ -157,7 +162,7 @@ impl Editor {
.padding([5, 10])
]
.spacing(10)
- .align_items(Alignment::Center);
+ .align_y(Center);
let status = row![
text(if let Some(path) = &self.file {
@@ -183,21 +188,33 @@ impl Editor {
column![
controls,
text_editor(&self.content)
- .height(Length::Fill)
+ .height(Fill)
.on_action(Message::ActionPerformed)
- .highlight::<Highlighter>(
- highlighter::Settings {
- theme: self.theme,
- extension: self
- .file
- .as_deref()
- .and_then(Path::extension)
- .and_then(ffi::OsStr::to_str)
- .map(str::to_string)
- .unwrap_or(String::from("rs")),
- },
- |highlight, _theme| highlight.to_format()
- ),
+ .wrapping(if self.word_wrap {
+ text::Wrapping::Word
+ } else {
+ text::Wrapping::None
+ })
+ .highlight(
+ self.file
+ .as_deref()
+ .and_then(Path::extension)
+ .and_then(ffi::OsStr::to_str)
+ .unwrap_or("rs"),
+ self.theme,
+ )
+ .key_binding(|key_press| {
+ match key_press.key.as_ref() {
+ keyboard::Key::Character("s")
+ if key_press.modifiers.command() =>
+ {
+ Some(text_editor::Binding::Custom(
+ Message::SaveFile,
+ ))
+ }
+ _ => text_editor::Binding::from_key_press(key_press),
+ }
+ }),
status,
]
.spacing(10)
@@ -214,12 +231,6 @@ impl Editor {
}
}
-impl Default for Editor {
- fn default() -> Self {
- Self::new()
- }
-}
-
#[derive(Debug, Clone)]
pub enum Error {
DialogClosed,
diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs
index 2cd3c5d8..5bada9b5 100644
--- a/examples/events/src/main.rs
+++ b/examples/events/src/main.rs
@@ -1,8 +1,7 @@
-use iced::alignment;
use iced::event::{self, Event};
use iced::widget::{button, center, checkbox, text, Column};
use iced::window;
-use iced::{Alignment, Element, Length, Subscription, Task};
+use iced::{Center, Element, Fill, Subscription, Task};
pub fn main() -> iced::Result {
iced::application("Events - Iced", Events::update, Events::view)
@@ -67,17 +66,13 @@ impl Events {
let toggle = checkbox("Listen to runtime events", self.enabled)
.on_toggle(Message::Toggled);
- let exit = button(
- text("Exit")
- .width(Length::Fill)
- .horizontal_alignment(alignment::Horizontal::Center),
- )
- .width(100)
- .padding(10)
- .on_press(Message::Exit);
+ let exit = button(text("Exit").width(Fill).align_x(Center))
+ .width(100)
+ .padding(10)
+ .on_press(Message::Exit);
let content = Column::new()
- .align_items(Alignment::Center)
+ .align_x(Center)
.spacing(20)
.push(events)
.push(toggle)
diff --git a/examples/exit/src/main.rs b/examples/exit/src/main.rs
index 1f108df2..48b0864c 100644
--- a/examples/exit/src/main.rs
+++ b/examples/exit/src/main.rs
@@ -1,6 +1,6 @@
use iced::widget::{button, center, column};
use iced::window;
-use iced::{Alignment, Element, Task};
+use iced::{Center, Element, Task};
pub fn main() -> iced::Result {
iced::application("Exit - Iced", Exit::update, Exit::view).run()
@@ -44,7 +44,7 @@ impl Exit {
]
}
.spacing(10)
- .align_items(Alignment::Center);
+ .align_x(Center);
center(content).padding(20).into()
}
diff --git a/examples/ferris/src/main.rs b/examples/ferris/src/main.rs
index 88006898..eaf51354 100644
--- a/examples/ferris/src/main.rs
+++ b/examples/ferris/src/main.rs
@@ -4,8 +4,8 @@ use iced::widget::{
};
use iced::window;
use iced::{
- Alignment, Color, ContentFit, Degrees, Element, Length, Radians, Rotation,
- Subscription, Theme,
+ Bottom, Center, Color, ContentFit, Degrees, Element, Fill, Radians,
+ Rotation, Subscription, Theme,
};
pub fn main() -> iced::Result {
@@ -108,7 +108,7 @@ impl Image {
"I am Ferris!"
]
.spacing(20)
- .align_items(Alignment::Center);
+ .align_x(Center);
let fit = row![
pick_list(
@@ -122,7 +122,7 @@ impl Image {
Some(self.content_fit),
Message::ContentFitChanged
)
- .width(Length::Fill),
+ .width(Fill),
pick_list(
[RotationStrategy::Floating, RotationStrategy::Solid],
Some(match self.rotation {
@@ -131,10 +131,10 @@ impl Image {
}),
Message::RotationStrategyChanged,
)
- .width(Length::Fill),
+ .width(Fill),
]
.spacing(10)
- .align_items(Alignment::End);
+ .align_y(Bottom);
let properties = row![
with_value(
@@ -159,12 +159,12 @@ impl Image {
.size(12)
]
.spacing(10)
- .align_items(Alignment::Center),
+ .align_y(Center),
format!("Rotation: {:.0}°", f32::from(self.rotation.degrees()))
)
]
.spacing(10)
- .align_items(Alignment::End);
+ .align_y(Bottom);
container(column![fit, center(i_am_ferris), properties].spacing(10))
.padding(10)
@@ -206,6 +206,6 @@ fn with_value<'a>(
) -> Element<'a, Message> {
column![control.into(), text(value).size(12).line_height(1.0)]
.spacing(2)
- .align_items(Alignment::Center)
+ .align_x(Center)
.into()
}
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs
index 421f862a..9dcebecc 100644
--- a/examples/game_of_life/src/main.rs
+++ b/examples/game_of_life/src/main.rs
@@ -9,7 +9,7 @@ use iced::time;
use iced::widget::{
button, checkbox, column, container, pick_list, row, slider, text,
};
-use iced::{Alignment, Element, Length, Subscription, Task, Theme};
+use iced::{Center, Element, Fill, Subscription, Task, Theme};
use std::time::Duration;
pub fn main() -> iced::Result {
@@ -135,12 +135,9 @@ impl GameOfLife {
.map(move |message| Message::Grid(message, version)),
controls,
]
- .height(Length::Fill);
+ .height(Fill);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .into()
+ container(content).width(Fill).height(Fill).into()
}
}
@@ -169,7 +166,7 @@ fn view_controls<'a>(
slider(1.0..=1000.0, speed as f32, Message::SpeedChanged),
text!("x{speed}").size(16),
]
- .align_items(Alignment::Center)
+ .align_y(Center)
.spacing(10);
row![
@@ -186,7 +183,7 @@ fn view_controls<'a>(
]
.padding(10)
.spacing(20)
- .align_items(Alignment::Center)
+ .align_y(Center)
.into()
}
@@ -199,7 +196,7 @@ mod grid {
use iced::widget::canvas::event::{self, Event};
use iced::widget::canvas::{Cache, Canvas, Frame, Geometry, Path, Text};
use iced::{
- Color, Element, Length, Point, Rectangle, Renderer, Size, Theme, Vector,
+ Color, Element, Fill, Point, Rectangle, Renderer, Size, Theme, Vector,
};
use rustc_hash::{FxHashMap, FxHashSet};
use std::future::Future;
@@ -333,10 +330,7 @@ mod grid {
}
pub fn view(&self) -> Element<Message> {
- Canvas::new(self)
- .width(Length::Fill)
- .height(Length::Fill)
- .into()
+ Canvas::new(self).width(Fill).height(Fill).into()
}
pub fn clear(&mut self) {
diff --git a/examples/gradient/src/main.rs b/examples/gradient/src/main.rs
index e5b19443..b2de069f 100644
--- a/examples/gradient/src/main.rs
+++ b/examples/gradient/src/main.rs
@@ -3,7 +3,7 @@ use iced::gradient;
use iced::widget::{
checkbox, column, container, horizontal_space, row, slider, text,
};
-use iced::{Alignment, Color, Element, Length, Radians, Theme};
+use iced::{Center, Color, Element, Fill, Radians, Theme};
pub fn main() -> iced::Result {
tracing_subscriber::fmt::init();
@@ -67,8 +67,8 @@ impl Gradient {
gradient.into()
})
- .width(Length::Fill)
- .height(Length::Fill);
+ .width(Fill)
+ .height(Fill);
let angle_picker = row![
text("Angle").width(64),
@@ -77,7 +77,7 @@ impl Gradient {
]
.spacing(8)
.padding(8)
- .align_items(Alignment::Center);
+ .align_y(Center);
let transparency_toggle = iced::widget::Container::new(
checkbox("Transparent window", transparent)
@@ -129,6 +129,6 @@ fn color_picker(label: &str, color: Color) -> Element<'_, Color> {
]
.spacing(8)
.padding(8)
- .align_items(Alignment::Center)
+ .align_y(Center)
.into()
}
diff --git a/examples/integration/src/controls.rs b/examples/integration/src/controls.rs
index d0654996..0b11a323 100644
--- a/examples/integration/src/controls.rs
+++ b/examples/integration/src/controls.rs
@@ -1,7 +1,6 @@
use iced_wgpu::Renderer;
use iced_widget::{column, container, row, slider, text, text_input};
-use iced_winit::core::alignment;
-use iced_winit::core::{Color, Element, Length, Theme};
+use iced_winit::core::{Color, Element, Length::*, Theme};
use iced_winit::runtime::{Program, Task};
pub struct Controls {
@@ -86,8 +85,7 @@ impl Program for Controls {
.spacing(10),
)
.padding(10)
- .height(Length::Fill)
- .align_y(alignment::Vertical::Bottom)
+ .align_bottom(Fill)
.into()
}
}
diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs
index 9818adf3..5b64cbd1 100644
--- a/examples/integration/src/main.rs
+++ b/examples/integration/src/main.rs
@@ -68,7 +68,7 @@ pub fn main() -> Result<(), winit::error::EventLoopError> {
Size::new(physical_size.width, physical_size.height),
window.scale_factor(),
);
- let clipboard = Clipboard::connect(&window);
+ let clipboard = Clipboard::connect(window.clone());
let backend =
wgpu::util::backend_bits_from_env().unwrap_or_default();
diff --git a/examples/layout/src/main.rs b/examples/layout/src/main.rs
index 2e774415..cb33369b 100644
--- a/examples/layout/src/main.rs
+++ b/examples/layout/src/main.rs
@@ -1,3 +1,4 @@
+use iced::border;
use iced::keyboard;
use iced::mouse;
use iced::widget::{
@@ -5,7 +6,7 @@ use iced::widget::{
pick_list, row, scrollable, text,
};
use iced::{
- color, Alignment, Element, Font, Length, Point, Rectangle, Renderer,
+ color, Center, Element, Fill, Font, Length, Point, Rectangle, Renderer,
Subscription, Theme,
};
@@ -74,7 +75,7 @@ impl Layout {
pick_list(Theme::ALL, Some(&self.theme), Message::ThemeSelected),
]
.spacing(20)
- .align_items(Alignment::Center);
+ .align_y(Center);
let example = center(if self.explain {
self.example.view().explain(color!(0x0000ff))
@@ -85,7 +86,7 @@ impl Layout {
let palette = theme.extended_palette();
container::Style::default()
- .with_border(palette.background.strong.color, 4.0)
+ .border(border::color(palette.background.strong.color).width(4))
})
.padding(4);
@@ -234,13 +235,13 @@ fn application<'a>() -> Element<'a, Message> {
square(40),
]
.padding(10)
- .align_items(Alignment::Center),
+ .align_y(Center),
)
.style(|theme| {
let palette = theme.extended_palette();
container::Style::default()
- .with_border(palette.background.strong.color, 1)
+ .border(border::color(palette.background.strong.color).width(1))
});
let sidebar = container(
@@ -248,25 +249,26 @@ fn application<'a>() -> Element<'a, Message> {
.spacing(40)
.padding(10)
.width(200)
- .align_items(Alignment::Center),
+ .align_x(Center),
)
.style(container::rounded_box)
- .center_y(Length::Fill);
+ .center_y(Fill);
let content = container(
scrollable(
column![
"Content!",
- square(400),
- square(200),
- square(400),
+ row((1..10).map(|i| square(if i % 2 == 0 { 80 } else { 160 })))
+ .spacing(20)
+ .align_y(Center)
+ .wrap(),
"The end"
]
.spacing(40)
- .align_items(Alignment::Center)
- .width(Length::Fill),
+ .align_x(Center)
+ .width(Fill),
)
- .height(Length::Fill),
+ .height(Fill),
)
.padding(10);
diff --git a/examples/lazy/src/main.rs b/examples/lazy/src/main.rs
index f24c0d62..8f756210 100644
--- a/examples/lazy/src/main.rs
+++ b/examples/lazy/src/main.rs
@@ -2,7 +2,7 @@ use iced::widget::{
button, column, horizontal_space, lazy, pick_list, row, scrollable, text,
text_input,
};
-use iced::{Element, Length};
+use iced::{Element, Fill};
use std::collections::HashSet;
use std::hash::Hash;
@@ -187,7 +187,7 @@ impl App {
});
column![
- scrollable(options).height(Length::Fill),
+ scrollable(options).height(Fill),
row![
text_input("Add a new option", &self.input)
.on_input(Message::InputChanged)
diff --git a/examples/loading_spinners/src/main.rs b/examples/loading_spinners/src/main.rs
index 503f2d7a..3b178148 100644
--- a/examples/loading_spinners/src/main.rs
+++ b/examples/loading_spinners/src/main.rs
@@ -1,5 +1,5 @@
use iced::widget::{center, column, row, slider, text};
-use iced::Element;
+use iced::{Center, Element};
use std::time::Duration;
@@ -67,7 +67,7 @@ impl LoadingSpinners {
Duration::from_secs_f32(self.cycle_duration)
)
]
- .align_items(iced::Alignment::Center)
+ .align_y(Center)
.spacing(20.0),
)
})
@@ -83,7 +83,7 @@ impl LoadingSpinners {
.width(200.0),
text!("{:.2}s", self.cycle_duration),
]
- .align_items(iced::Alignment::Center)
+ .align_y(Center)
.spacing(20.0),
),
)
diff --git a/examples/loupe/src/main.rs b/examples/loupe/src/main.rs
index c4d3b449..1c748d42 100644
--- a/examples/loupe/src/main.rs
+++ b/examples/loupe/src/main.rs
@@ -1,5 +1,5 @@
use iced::widget::{button, center, column, text};
-use iced::{Alignment, Element};
+use iced::{Center, Element};
use loupe::loupe;
@@ -39,7 +39,7 @@ impl Loupe {
button("Decrement").on_press(Message::Decrement)
]
.padding(20)
- .align_items(Alignment::Center),
+ .align_x(Center),
))
.into()
}
diff --git a/examples/component/Cargo.toml b/examples/markdown/Cargo.toml
index 83b7b8a4..cb74b954 100644
--- a/examples/component/Cargo.toml
+++ b/examples/markdown/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "component"
+name = "markdown"
version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
@@ -7,4 +7,6 @@ publish = false
[dependencies]
iced.workspace = true
-iced.features = ["debug", "lazy"]
+iced.features = ["markdown", "highlighter", "debug"]
+
+open = "5.3"
diff --git a/examples/markdown/overview.md b/examples/markdown/overview.md
new file mode 100644
index 00000000..66336c5b
--- /dev/null
+++ b/examples/markdown/overview.md
@@ -0,0 +1,93 @@
+# Overview
+
+Inspired by [The Elm Architecture], Iced expects you to split user interfaces into four different concepts:
+
+* __State__ — the state of your application
+* __Messages__ — user interactions or meaningful events that you care about
+* __View logic__ — a way to display your __state__ as widgets that may produce __messages__ on user interaction
+* __Update logic__ — a way to react to __messages__ and update your __state__
+
+We can build something to see how this works! Let's say we want a simple counter that can be incremented and decremented using two buttons.
+
+We start by modelling the __state__ of our application:
+
+```rust
+#[derive(Default)]
+struct Counter {
+ value: i32,
+}
+```
+
+Next, we need to define the possible user interactions of our counter: the button presses. These interactions are our __messages__:
+
+```rust
+#[derive(Debug, Clone, Copy)]
+pub enum Message {
+ Increment,
+ Decrement,
+}
+```
+
+Now, let's show the actual counter by putting it all together in our __view logic__:
+
+```rust
+use iced::widget::{button, column, text, Column};
+
+impl Counter {
+ pub fn view(&self) -> Column<Message> {
+ // We use a column: a simple vertical layout
+ column![
+ // The increment button. We tell it to produce an
+ // `Increment` message when pressed
+ button("+").on_press(Message::Increment),
+
+ // We show the value of the counter here
+ text(self.value).size(50),
+
+ // The decrement button. We tell it to produce a
+ // `Decrement` message when pressed
+ button("-").on_press(Message::Decrement),
+ ]
+ }
+}
+```
+
+Finally, we need to be able to react to any produced __messages__ and change our __state__ accordingly in our __update logic__:
+
+```rust
+impl Counter {
+ // ...
+
+ pub fn update(&mut self, message: Message) {
+ match message {
+ Message::Increment => {
+ self.value += 1;
+ }
+ Message::Decrement => {
+ self.value -= 1;
+ }
+ }
+ }
+}
+```
+
+And that's everything! We just wrote a whole user interface. Let's run it:
+
+```rust
+fn main() -> iced::Result {
+ iced::run("A cool counter", Counter::update, Counter::view)
+}
+```
+
+Iced will automatically:
+
+ 1. Take the result of our __view logic__ and layout its widgets.
+ 1. Process events from our system and produce __messages__ for our __update logic__.
+ 1. Draw the resulting user interface.
+
+Read the [book], the [documentation], and the [examples] to learn more!
+
+[book]: https://book.iced.rs/
+[documentation]: https://docs.rs/iced/
+[examples]: https://github.com/iced-rs/iced/tree/master/examples#examples
+[The Elm Architecture]: https://guide.elm-lang.org/architecture/
diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs
new file mode 100644
index 00000000..5605478f
--- /dev/null
+++ b/examples/markdown/src/main.rs
@@ -0,0 +1,82 @@
+use iced::highlighter;
+use iced::widget::{self, markdown, row, scrollable, text_editor};
+use iced::{Element, Fill, Font, Task, Theme};
+
+pub fn main() -> iced::Result {
+ iced::application("Markdown - Iced", Markdown::update, Markdown::view)
+ .theme(Markdown::theme)
+ .run_with(Markdown::new)
+}
+
+struct Markdown {
+ content: text_editor::Content,
+ items: Vec<markdown::Item>,
+ theme: Theme,
+}
+
+#[derive(Debug, Clone)]
+enum Message {
+ Edit(text_editor::Action),
+ LinkClicked(markdown::Url),
+}
+
+impl Markdown {
+ fn new() -> (Self, Task<Message>) {
+ const INITIAL_CONTENT: &str = include_str!("../overview.md");
+
+ let theme = Theme::TokyoNight;
+
+ (
+ Self {
+ content: text_editor::Content::with_text(INITIAL_CONTENT),
+ items: markdown::parse(INITIAL_CONTENT).collect(),
+ theme,
+ },
+ widget::focus_next(),
+ )
+ }
+
+ fn update(&mut self, message: Message) {
+ match message {
+ Message::Edit(action) => {
+ let is_edit = action.is_edit();
+
+ self.content.perform(action);
+
+ if is_edit {
+ self.items =
+ markdown::parse(&self.content.text()).collect();
+ }
+ }
+ Message::LinkClicked(link) => {
+ let _ = open::that_in_background(link.to_string());
+ }
+ }
+ }
+
+ fn view(&self) -> Element<Message> {
+ let editor = text_editor(&self.content)
+ .placeholder("Type your Markdown here...")
+ .on_action(Message::Edit)
+ .height(Fill)
+ .padding(10)
+ .font(Font::MONOSPACE)
+ .highlight("markdown", highlighter::Theme::Base16Ocean);
+
+ let preview = markdown(
+ &self.items,
+ markdown::Settings::default(),
+ markdown::Style::from_palette(self.theme.palette()),
+ )
+ .map(Message::LinkClicked);
+
+ row![editor, scrollable(preview).spacing(10).height(Fill)]
+ .spacing(10)
+ .padding(10)
+ .into()
+ }
+
+ fn theme(&self) -> Theme {
+ self.theme.clone()
+ }
+}
diff --git a/examples/modal/src/main.rs b/examples/modal/src/main.rs
index 413485e7..067ca24d 100644
--- a/examples/modal/src/main.rs
+++ b/examples/modal/src/main.rs
@@ -5,7 +5,7 @@ use iced::widget::{
self, button, center, column, container, horizontal_space, mouse_area,
opaque, pick_list, row, stack, text, text_input,
};
-use iced::{Alignment, Color, Element, Length, Subscription, Task};
+use iced::{Bottom, Color, Element, Fill, Subscription, Task};
use std::fmt;
@@ -96,18 +96,17 @@ impl App {
let content = container(
column![
row![text("Top Left"), horizontal_space(), text("Top Right")]
- .align_items(Alignment::Start)
- .height(Length::Fill),
+ .height(Fill),
center(button(text("Show Modal")).on_press(Message::ShowModal)),
row![
text("Bottom Left"),
horizontal_space(),
text("Bottom Right")
]
- .align_items(Alignment::End)
- .height(Length::Fill),
+ .align_y(Bottom)
+ .height(Fill),
]
- .height(Length::Fill),
+ .height(Fill),
)
.padding(10);
@@ -202,19 +201,21 @@ where
{
stack![
base.into(),
- mouse_area(center(opaque(content)).style(|_theme| {
- container::Style {
- background: Some(
- Color {
- a: 0.8,
- ..Color::BLACK
- }
- .into(),
- ),
- ..container::Style::default()
- }
- }))
- .on_press(on_blur)
+ opaque(
+ mouse_area(center(opaque(content)).style(|_theme| {
+ container::Style {
+ background: Some(
+ Color {
+ a: 0.8,
+ ..Color::BLACK
+ }
+ .into(),
+ ),
+ ..container::Style::default()
+ }
+ }))
+ .on_press(on_blur)
+ )
]
.into()
}
diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs
index 98e753ab..ab09116e 100644
--- a/examples/multi_window/src/main.rs
+++ b/examples/multi_window/src/main.rs
@@ -3,22 +3,18 @@ use iced::widget::{
text_input,
};
use iced::window;
-use iced::{Alignment, Element, Length, Subscription, Task, Theme, Vector};
+use iced::{Center, Element, Fill, Subscription, Task, Theme, Vector};
use std::collections::BTreeMap;
fn main() -> iced::Result {
iced::daemon(Example::title, Example::update, Example::view)
- .load(|| {
- window::open(window::Settings::default()).map(Message::WindowOpened)
- })
.subscription(Example::subscription)
.theme(Example::theme)
.scale_factor(Example::scale_factor)
- .run()
+ .run_with(Example::new)
}
-#[derive(Default)]
struct Example {
windows: BTreeMap<window::Id, Window>,
}
@@ -43,6 +39,17 @@ enum Message {
}
impl Example {
+ fn new() -> (Self, Task<Message>) {
+ let (_id, open) = window::open(window::Settings::default());
+
+ (
+ Self {
+ windows: BTreeMap::new(),
+ },
+ open.map(Message::WindowOpened),
+ )
+ }
+
fn title(&self, window: window::Id) -> String {
self.windows
.get(&window)
@@ -68,10 +75,12 @@ impl Example {
},
);
- window::open(window::Settings {
+ let (_id, open) = window::open(window::Settings {
position,
..window::Settings::default()
- })
+ });
+
+ open
})
.map(Message::WindowOpened)
}
@@ -182,8 +191,8 @@ impl Window {
let content = scrollable(
column![scale_input, title_input, new_window_button]
.spacing(50)
- .width(Length::Fill)
- .align_items(Alignment::Center),
+ .width(Fill)
+ .align_x(Center),
);
container(content).center_x(200).into()
diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs
index 69717310..a0105a8a 100644
--- a/examples/multitouch/src/main.rs
+++ b/examples/multitouch/src/main.rs
@@ -6,7 +6,7 @@ use iced::touch;
use iced::widget::canvas::event;
use iced::widget::canvas::stroke::{self, Stroke};
use iced::widget::canvas::{self, Canvas, Geometry};
-use iced::{Color, Element, Length, Point, Rectangle, Renderer, Theme};
+use iced::{Color, Element, Fill, Point, Rectangle, Renderer, Theme};
use std::collections::HashMap;
@@ -46,10 +46,7 @@ impl Multitouch {
}
fn view(&self) -> Element<Message> {
- Canvas::new(self)
- .width(Length::Fill)
- .height(Length::Fill)
- .into()
+ Canvas::new(self).width(Fill).height(Fill).into()
}
}
diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs
index db9f7a05..67f4d27f 100644
--- a/examples/pane_grid/src/main.rs
+++ b/examples/pane_grid/src/main.rs
@@ -1,10 +1,9 @@
-use iced::alignment::{self, Alignment};
use iced::keyboard;
use iced::widget::pane_grid::{self, PaneGrid};
use iced::widget::{
button, column, container, responsive, row, scrollable, text,
};
-use iced::{Color, Element, Length, Size, Subscription};
+use iced::{Center, Color, Element, Fill, Size, Subscription};
pub fn main() -> iced::Result {
iced::application("Pane Grid - Iced", Example::update, Example::view)
@@ -155,11 +154,23 @@ impl Example {
.spacing(5);
let title_bar = pane_grid::TitleBar::new(title)
- .controls(view_controls(
- id,
- total_panes,
- pane.is_pinned,
- is_maximized,
+ .controls(pane_grid::Controls::dynamic(
+ view_controls(
+ id,
+ total_panes,
+ pane.is_pinned,
+ is_maximized,
+ ),
+ button(text("X").size(14))
+ .style(button::danger)
+ .padding(3)
+ .on_press_maybe(
+ if total_panes > 1 && !pane.is_pinned {
+ Some(Message::Close(id))
+ } else {
+ None
+ },
+ ),
))
.padding(10)
.style(if is_focused {
@@ -178,16 +189,16 @@ impl Example {
style::pane_active
})
})
- .width(Length::Fill)
- .height(Length::Fill)
+ .width(Fill)
+ .height(Fill)
.spacing(10)
.on_click(Message::Clicked)
.on_drag(Message::Dragged)
.on_resize(10, Message::Resized);
container(pane_grid)
- .width(Length::Fill)
- .height(Length::Fill)
+ .width(Fill)
+ .height(Fill)
.padding(10)
.into()
}
@@ -255,15 +266,10 @@ fn view_content<'a>(
size: Size,
) -> Element<'a, Message> {
let button = |label, message| {
- button(
- text(label)
- .width(Length::Fill)
- .horizontal_alignment(alignment::Horizontal::Center)
- .size(16),
- )
- .width(Length::Fill)
- .padding(8)
- .on_press(message)
+ button(text(label).width(Fill).align_x(Center).size(16))
+ .width(Fill)
+ .padding(8)
+ .on_press(message)
};
let controls = column![
@@ -287,10 +293,10 @@ fn view_content<'a>(
let content =
column![text!("{}x{}", size.width, size.height).size(24), controls,]
.spacing(10)
- .align_items(Alignment::Center);
+ .align_x(Center);
container(scrollable(content))
- .center_y(Length::Fill)
+ .center_y(Fill)
.padding(5)
.into()
}
diff --git a/examples/pick_list/src/main.rs b/examples/pick_list/src/main.rs
index 2be6f5b0..d8b2b389 100644
--- a/examples/pick_list/src/main.rs
+++ b/examples/pick_list/src/main.rs
@@ -1,5 +1,5 @@
use iced::widget::{column, pick_list, scrollable, vertical_space};
-use iced::{Alignment, Element, Length};
+use iced::{Center, Element, Fill};
pub fn main() -> iced::Result {
iced::run("Pick List - Iced", Example::update, Example::view)
@@ -38,8 +38,8 @@ impl Example {
pick_list,
vertical_space().height(600),
]
- .width(Length::Fill)
- .align_items(Alignment::Center)
+ .width(Fill)
+ .align_x(Center)
.spacing(10);
scrollable(content).into()
diff --git a/examples/pokedex/Cargo.toml b/examples/pokedex/Cargo.toml
index bf7e1e35..1a6d5445 100644
--- a/examples/pokedex/Cargo.toml
+++ b/examples/pokedex/Cargo.toml
@@ -16,7 +16,7 @@ version = "1.0"
features = ["derive"]
[dependencies.reqwest]
-version = "0.11"
+version = "0.12"
default-features = false
features = ["json", "rustls-tls"]
diff --git a/examples/pokedex/src/main.rs b/examples/pokedex/src/main.rs
index b22ffe7f..2e972f6b 100644
--- a/examples/pokedex/src/main.rs
+++ b/examples/pokedex/src/main.rs
@@ -1,20 +1,16 @@
use iced::futures;
use iced::widget::{self, center, column, image, row, text};
-use iced::{Alignment, Element, Length, Task};
+use iced::{Center, Element, Fill, Right, Task};
pub fn main() -> iced::Result {
iced::application(Pokedex::title, Pokedex::update, Pokedex::view)
- .load(Pokedex::search)
- .run()
+ .run_with(Pokedex::new)
}
-#[derive(Debug, Default)]
+#[derive(Debug)]
enum Pokedex {
- #[default]
Loading,
- Loaded {
- pokemon: Pokemon,
- },
+ Loaded { pokemon: Pokemon },
Errored,
}
@@ -25,6 +21,10 @@ enum Message {
}
impl Pokedex {
+ fn new() -> (Self, Task<Message>) {
+ (Self::Loading, Self::search())
+ }
+
fn search() -> Task<Message> {
Task::perform(Pokemon::search(), Message::PokemonFound)
}
@@ -63,10 +63,9 @@ impl Pokedex {
}
fn view(&self) -> Element<Message> {
- let content = match self {
+ let content: Element<_> = match self {
Pokedex::Loading => {
- column![text("Searching for Pokémon...").size(40),]
- .width(Length::Shrink)
+ text("Searching for Pokémon...").size(40).into()
}
Pokedex::Loaded { pokemon } => column![
pokemon.view(),
@@ -74,13 +73,15 @@ impl Pokedex {
]
.max_width(500)
.spacing(20)
- .align_items(Alignment::End),
+ .align_x(Right)
+ .into(),
Pokedex::Errored => column![
text("Whoops! Something went wrong...").size(40),
button("Try again").on_press(Message::Search)
]
.spacing(20)
- .align_items(Alignment::End),
+ .align_x(Right)
+ .into(),
};
center(content).into()
@@ -103,17 +104,17 @@ impl Pokemon {
image::viewer(self.image.clone()),
column![
row![
- text(&self.name).size(30).width(Length::Fill),
+ text(&self.name).size(30).width(Fill),
text!("#{}", self.number).size(20).color([0.5, 0.5, 0.5]),
]
- .align_items(Alignment::Center)
+ .align_y(Center)
.spacing(20),
self.description.as_ref(),
]
.spacing(20),
]
.spacing(20)
- .align_items(Alignment::Center)
+ .align_y(Center)
.into()
}
diff --git a/examples/qr_code/src/main.rs b/examples/qr_code/src/main.rs
index b30ecf15..f1b654e0 100644
--- a/examples/qr_code/src/main.rs
+++ b/examples/qr_code/src/main.rs
@@ -1,5 +1,5 @@
use iced::widget::{center, column, pick_list, qr_code, row, text, text_input};
-use iced::{Alignment, Element, Theme};
+use iced::{Center, Element, Theme};
pub fn main() -> iced::Result {
iced::application(
@@ -58,7 +58,7 @@ impl QRGenerator {
pick_list(Theme::ALL, Some(&self.theme), Message::ThemeChanged,)
]
.spacing(10)
- .align_items(Alignment::Center);
+ .align_y(Center);
let content = column![title, input, choose_theme]
.push_maybe(
@@ -68,7 +68,7 @@ impl QRGenerator {
)
.width(700)
.spacing(20)
- .align_items(Alignment::Center);
+ .align_x(Center);
center(content).padding(20).into()
}
diff --git a/examples/screenshot/src/main.rs b/examples/screenshot/src/main.rs
index acde8367..5c105f6c 100644
--- a/examples/screenshot/src/main.rs
+++ b/examples/screenshot/src/main.rs
@@ -1,10 +1,10 @@
-use iced::alignment;
use iced::keyboard;
use iced::widget::{button, column, container, image, row, text, text_input};
use iced::window;
use iced::window::screenshot::{self, Screenshot};
use iced::{
- Alignment, ContentFit, Element, Length, Rectangle, Subscription, Task,
+ Center, ContentFit, Element, Fill, FillPortion, Rectangle, Subscription,
+ Task,
};
use ::image as img;
@@ -20,7 +20,7 @@ fn main() -> iced::Result {
#[derive(Default)]
struct Example {
- screenshot: Option<Screenshot>,
+ screenshot: Option<(Screenshot, image::Handle)>,
saved_png_path: Option<Result<String, PngError>>,
png_saving: bool,
crop_error: Option<screenshot::CropError>,
@@ -52,10 +52,17 @@ impl Example {
.map(Message::Screenshotted);
}
Message::Screenshotted(screenshot) => {
- self.screenshot = Some(screenshot);
+ self.screenshot = Some((
+ screenshot.clone(),
+ image::Handle::from_rgba(
+ screenshot.size.width,
+ screenshot.size.height,
+ screenshot.bytes,
+ ),
+ ));
}
Message::Png => {
- if let Some(screenshot) = &self.screenshot {
+ if let Some((screenshot, _handle)) = &self.screenshot {
self.png_saving = true;
return Task::perform(
@@ -81,7 +88,7 @@ impl Example {
self.height_input_value = new_value;
}
Message::Crop => {
- if let Some(screenshot) = &self.screenshot {
+ if let Some((screenshot, _handle)) = &self.screenshot {
let cropped = screenshot.crop(Rectangle::<u32> {
x: self.x_input_value.unwrap_or(0),
y: self.y_input_value.unwrap_or(0),
@@ -91,7 +98,14 @@ impl Example {
match cropped {
Ok(screenshot) => {
- self.screenshot = Some(screenshot);
+ self.screenshot = Some((
+ screenshot.clone(),
+ image::Handle::from_rgba(
+ screenshot.size.width,
+ screenshot.size.height,
+ screenshot.bytes,
+ ),
+ ));
self.crop_error = None;
}
Err(crop_error) => {
@@ -106,53 +120,41 @@ impl Example {
}
fn view(&self) -> Element<'_, Message> {
- let image: Element<Message> = if let Some(screenshot) = &self.screenshot
- {
- image(image::Handle::from_rgba(
- screenshot.size.width,
- screenshot.size.height,
- screenshot.clone(),
- ))
- .content_fit(ContentFit::Contain)
- .width(Length::Fill)
- .height(Length::Fill)
- .into()
- } else {
- text("Press the button to take a screenshot!").into()
- };
+ let image: Element<Message> =
+ if let Some((_screenshot, handle)) = &self.screenshot {
+ image(handle)
+ .content_fit(ContentFit::Contain)
+ .width(Fill)
+ .height(Fill)
+ .into()
+ } else {
+ text("Press the button to take a screenshot!").into()
+ };
let image = container(image)
- .center_y(Length::FillPortion(2))
+ .center_y(FillPortion(2))
.padding(10)
.style(container::rounded_box);
let crop_origin_controls = row![
- text("X:")
- .vertical_alignment(alignment::Vertical::Center)
- .width(30),
+ text("X:").width(30),
numeric_input("0", self.x_input_value).map(Message::XInputChanged),
- text("Y:")
- .vertical_alignment(alignment::Vertical::Center)
- .width(30),
+ text("Y:").width(30),
numeric_input("0", self.y_input_value).map(Message::YInputChanged)
]
.spacing(10)
- .align_items(Alignment::Center);
+ .align_y(Center);
let crop_dimension_controls = row![
- text("W:")
- .vertical_alignment(alignment::Vertical::Center)
- .width(30),
+ text("W:").width(30),
numeric_input("0", self.width_input_value)
.map(Message::WidthInputChanged),
- text("H:")
- .vertical_alignment(alignment::Vertical::Center)
- .width(30),
+ text("H:").width(30),
numeric_input("0", self.height_input_value)
.map(Message::HeightInputChanged)
]
.spacing(10)
- .align_items(Alignment::Center);
+ .align_y(Center);
let crop_controls =
column![crop_origin_controls, crop_dimension_controls]
@@ -162,7 +164,7 @@ impl Example {
.map(|error| text!("Crop error! \n{error}")),
)
.spacing(10)
- .align_items(Alignment::Center);
+ .align_x(Center);
let controls = {
let save_result =
@@ -178,8 +180,8 @@ impl Example {
column![
column![
button(centered_text("Screenshot!"))
- .padding([10, 20, 10, 20])
- .width(Length::Fill)
+ .padding([10, 20])
+ .width(Fill)
.on_press(Message::Screenshot),
if !self.png_saving {
button(centered_text("Save as png")).on_press_maybe(
@@ -190,8 +192,8 @@ impl Example {
.style(button::secondary)
}
.style(button::secondary)
- .padding([10, 20, 10, 20])
- .width(Length::Fill)
+ .padding([10, 20])
+ .width(Fill)
]
.spacing(10),
column![
@@ -199,23 +201,23 @@ impl Example {
button(centered_text("Crop"))
.on_press(Message::Crop)
.style(button::danger)
- .padding([10, 20, 10, 20])
- .width(Length::Fill),
+ .padding([10, 20])
+ .width(Fill),
]
.spacing(10)
- .align_items(Alignment::Center),
+ .align_x(Center),
]
.push_maybe(save_result.map(text))
.spacing(40)
};
- let side_content = container(controls).center_y(Length::Fill);
+ let side_content = container(controls).center_y(Fill);
let content = row![side_content, image]
.spacing(10)
- .width(Length::Fill)
- .height(Length::Fill)
- .align_items(Alignment::Center);
+ .width(Fill)
+ .height(Fill)
+ .align_y(Center);
container(content).padding(10).into()
}
@@ -276,8 +278,5 @@ fn numeric_input(
}
fn centered_text(content: &str) -> Element<'_, Message> {
- text(content)
- .width(Length::Fill)
- .horizontal_alignment(alignment::Horizontal::Center)
- .into()
+ text(content).width(Fill).align_x(Center).into()
}
diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs
index f2a853e1..de4f2f9a 100644
--- a/examples/scrollable/src/main.rs
+++ b/examples/scrollable/src/main.rs
@@ -1,9 +1,8 @@
-use iced::widget::scrollable::Properties;
use iced::widget::{
button, column, container, horizontal_space, progress_bar, radio, row,
- scrollable, slider, text, vertical_space, Scrollable,
+ scrollable, slider, text, vertical_space,
};
-use iced::{Alignment, Border, Color, Element, Length, Task, Theme};
+use iced::{Border, Center, Color, Element, Fill, Task, Theme};
use once_cell::sync::Lazy;
@@ -25,7 +24,7 @@ struct ScrollableDemo {
scrollbar_margin: u16,
scroller_width: u16,
current_scroll_offset: scrollable::RelativeOffset,
- alignment: scrollable::Alignment,
+ anchor: scrollable::Anchor,
}
#[derive(Debug, Clone, Eq, PartialEq, Copy)]
@@ -38,7 +37,7 @@ enum Direction {
#[derive(Debug, Clone)]
enum Message {
SwitchDirection(Direction),
- AlignmentChanged(scrollable::Alignment),
+ AlignmentChanged(scrollable::Anchor),
ScrollbarWidthChanged(u16),
ScrollbarMarginChanged(u16),
ScrollerWidthChanged(u16),
@@ -55,7 +54,7 @@ impl ScrollableDemo {
scrollbar_margin: 0,
scroller_width: 10,
current_scroll_offset: scrollable::RelativeOffset::START,
- alignment: scrollable::Alignment::Start,
+ anchor: scrollable::Anchor::Start,
}
}
@@ -72,7 +71,7 @@ impl ScrollableDemo {
}
Message::AlignmentChanged(alignment) => {
self.current_scroll_offset = scrollable::RelativeOffset::START;
- self.alignment = alignment;
+ self.anchor = alignment;
scrollable::snap_to(
SCROLLABLE_ID.clone(),
@@ -169,14 +168,14 @@ impl ScrollableDemo {
text("Scrollable alignment:"),
radio(
"Start",
- scrollable::Alignment::Start,
- Some(self.alignment),
+ scrollable::Anchor::Start,
+ Some(self.anchor),
Message::AlignmentChanged,
),
radio(
"End",
- scrollable::Alignment::End,
- Some(self.alignment),
+ scrollable::Anchor::End,
+ Some(self.anchor),
Message::AlignmentChanged,
)
]
@@ -203,7 +202,7 @@ impl ScrollableDemo {
let scrollable_content: Element<Message> =
Element::from(match self.scrollable_direction {
- Direction::Vertical => Scrollable::with_direction(
+ Direction::Vertical => scrollable(
column![
scroll_to_end_button(),
text("Beginning!"),
@@ -213,22 +212,22 @@ impl ScrollableDemo {
text("End!"),
scroll_to_beginning_button(),
]
- .align_items(Alignment::Center)
- .padding([40, 0, 40, 0])
+ .align_x(Center)
+ .padding([40, 0])
.spacing(40),
- scrollable::Direction::Vertical(
- Properties::new()
- .width(self.scrollbar_width)
- .margin(self.scrollbar_margin)
- .scroller_width(self.scroller_width)
- .alignment(self.alignment),
- ),
)
- .width(Length::Fill)
- .height(Length::Fill)
+ .direction(scrollable::Direction::Vertical(
+ scrollable::Scrollbar::new()
+ .width(self.scrollbar_width)
+ .margin(self.scrollbar_margin)
+ .scroller_width(self.scroller_width)
+ .anchor(self.anchor),
+ ))
+ .width(Fill)
+ .height(Fill)
.id(SCROLLABLE_ID.clone())
.on_scroll(Message::Scrolled),
- Direction::Horizontal => Scrollable::with_direction(
+ Direction::Horizontal => scrollable(
row![
scroll_to_end_button(),
text("Beginning!"),
@@ -239,22 +238,22 @@ impl ScrollableDemo {
scroll_to_beginning_button(),
]
.height(450)
- .align_items(Alignment::Center)
- .padding([0, 40, 0, 40])
+ .align_y(Center)
+ .padding([0, 40])
.spacing(40),
- scrollable::Direction::Horizontal(
- Properties::new()
- .width(self.scrollbar_width)
- .margin(self.scrollbar_margin)
- .scroller_width(self.scroller_width)
- .alignment(self.alignment),
- ),
)
- .width(Length::Fill)
- .height(Length::Fill)
+ .direction(scrollable::Direction::Horizontal(
+ scrollable::Scrollbar::new()
+ .width(self.scrollbar_width)
+ .margin(self.scrollbar_margin)
+ .scroller_width(self.scroller_width)
+ .anchor(self.anchor),
+ ))
+ .width(Fill)
+ .height(Fill)
.id(SCROLLABLE_ID.clone())
.on_scroll(Message::Scrolled),
- Direction::Multi => Scrollable::with_direction(
+ Direction::Multi => scrollable(
//horizontal content
row![
column![
@@ -281,24 +280,24 @@ impl ScrollableDemo {
text("Horizontal - End!"),
scroll_to_beginning_button(),
]
- .align_items(Alignment::Center)
- .padding([0, 40, 0, 40])
+ .align_y(Center)
+ .padding([0, 40])
.spacing(40),
- {
- let properties = Properties::new()
- .width(self.scrollbar_width)
- .margin(self.scrollbar_margin)
- .scroller_width(self.scroller_width)
- .alignment(self.alignment);
-
- scrollable::Direction::Both {
- horizontal: properties,
- vertical: properties,
- }
- },
)
- .width(Length::Fill)
- .height(Length::Fill)
+ .direction({
+ let scrollbar = scrollable::Scrollbar::new()
+ .width(self.scrollbar_width)
+ .margin(self.scrollbar_margin)
+ .scroller_width(self.scroller_width)
+ .anchor(self.anchor);
+
+ scrollable::Direction::Both {
+ horizontal: scrollbar,
+ vertical: scrollbar,
+ }
+ })
+ .width(Fill)
+ .height(Fill)
.id(SCROLLABLE_ID.clone())
.on_scroll(Message::Scrolled),
});
@@ -323,7 +322,7 @@ impl ScrollableDemo {
let content: Element<Message> =
column![scroll_controls, scrollable_content, progress_bars]
- .align_items(Alignment::Center)
+ .align_x(Center)
.spacing(10)
.into();
diff --git a/examples/sierpinski_triangle/src/main.rs b/examples/sierpinski_triangle/src/main.rs
index 4c751937..99e7900a 100644
--- a/examples/sierpinski_triangle/src/main.rs
+++ b/examples/sierpinski_triangle/src/main.rs
@@ -2,7 +2,7 @@ use iced::mouse;
use iced::widget::canvas::event::{self, Event};
use iced::widget::canvas::{self, Canvas, Geometry};
use iced::widget::{column, row, slider, text};
-use iced::{Color, Length, Point, Rectangle, Renderer, Size, Theme};
+use iced::{Center, Color, Fill, Point, Rectangle, Renderer, Size, Theme};
use rand::Rng;
use std::fmt::Debug;
@@ -50,9 +50,7 @@ impl SierpinskiEmulator {
fn view(&self) -> iced::Element<'_, Message> {
column![
- Canvas::new(&self.graph)
- .width(Length::Fill)
- .height(Length::Fill),
+ Canvas::new(&self.graph).width(Fill).height(Fill),
row![
text!("Iteration: {:?}", self.graph.iteration),
slider(0..=10000, self.graph.iteration, Message::IterationSet)
@@ -60,7 +58,7 @@ impl SierpinskiEmulator {
.padding(10)
.spacing(20),
]
- .align_items(iced::Alignment::Center)
+ .align_x(Center)
.into()
}
}
diff --git a/examples/slider/Cargo.toml b/examples/slider/Cargo.toml
index fad8916e..05e74d2c 100644
--- a/examples/slider/Cargo.toml
+++ b/examples/slider/Cargo.toml
@@ -7,3 +7,4 @@ publish = false
[dependencies]
iced.workspace = true
+iced.features = ["svg"]
diff --git a/examples/slider/src/main.rs b/examples/slider/src/main.rs
index 0b4c29aa..ffb5475f 100644
--- a/examples/slider/src/main.rs
+++ b/examples/slider/src/main.rs
@@ -1,5 +1,5 @@
-use iced::widget::{center, column, container, slider, text, vertical_slider};
-use iced::{Element, Length};
+use iced::widget::{column, container, iced, slider, text, vertical_slider};
+use iced::{Center, Element, Fill};
pub fn main() -> iced::Result {
iced::run("Slider - Iced", Slider::update, Slider::view)
@@ -12,19 +12,11 @@ pub enum Message {
pub struct Slider {
value: u8,
- default: u8,
- step: u8,
- shift_step: u8,
}
impl Slider {
fn new() -> Self {
- Slider {
- value: 50,
- default: 50,
- step: 5,
- shift_step: 1,
- }
+ Slider { value: 50 }
}
fn update(&mut self, message: Message) {
@@ -37,32 +29,27 @@ impl Slider {
fn view(&self) -> Element<Message> {
let h_slider = container(
- slider(0..=100, self.value, Message::SliderChanged)
- .default(self.default)
- .step(self.step)
- .shift_step(self.shift_step),
+ slider(1..=100, self.value, Message::SliderChanged)
+ .default(50)
+ .shift_step(5),
)
.width(250);
let v_slider = container(
- vertical_slider(0..=100, self.value, Message::SliderChanged)
- .default(self.default)
- .step(self.step)
- .shift_step(self.shift_step),
+ vertical_slider(1..=100, self.value, Message::SliderChanged)
+ .default(50)
+ .shift_step(5),
)
.height(200);
let text = text(self.value);
- center(
- column![
- container(v_slider).center_x(Length::Fill),
- container(h_slider).center_x(Length::Fill),
- container(text).center_x(Length::Fill)
- ]
- .spacing(25),
- )
- .into()
+ column![v_slider, h_slider, text, iced(self.value as f32),]
+ .width(Fill)
+ .align_x(Center)
+ .spacing(20)
+ .padding(20)
+ .into()
}
}
diff --git a/examples/solar_system/Cargo.toml b/examples/solar_system/Cargo.toml
index ca64da14..e2c18c50 100644
--- a/examples/solar_system/Cargo.toml
+++ b/examples/solar_system/Cargo.toml
@@ -7,7 +7,7 @@ publish = false
[dependencies]
iced.workspace = true
-iced.features = ["debug", "canvas", "tokio"]
+iced.features = ["debug", "canvas", "image", "tokio"]
rand = "0.8.3"
tracing-subscriber = "0.3"
diff --git a/examples/solar_system/assets/earth.png b/examples/solar_system/assets/earth.png
new file mode 100644
index 00000000..e81321d9
--- /dev/null
+++ b/examples/solar_system/assets/earth.png
Binary files differ
diff --git a/examples/solar_system/assets/moon.png b/examples/solar_system/assets/moon.png
new file mode 100644
index 00000000..03f10cb7
--- /dev/null
+++ b/examples/solar_system/assets/moon.png
Binary files differ
diff --git a/examples/solar_system/assets/sun.png b/examples/solar_system/assets/sun.png
new file mode 100644
index 00000000..29a928a7
--- /dev/null
+++ b/examples/solar_system/assets/sun.png
Binary files differ
diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs
index 2a67e23e..1e74f2bd 100644
--- a/examples/solar_system/src/main.rs
+++ b/examples/solar_system/src/main.rs
@@ -7,13 +7,12 @@
//!
//! [1]: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations#An_animated_solar_system
use iced::mouse;
-use iced::widget::canvas;
-use iced::widget::canvas::gradient;
use iced::widget::canvas::stroke::{self, Stroke};
use iced::widget::canvas::{Geometry, Path};
+use iced::widget::{canvas, image};
use iced::window;
use iced::{
- Color, Element, Length, Point, Rectangle, Renderer, Size, Subscription,
+ Color, Element, Fill, Point, Rectangle, Renderer, Size, Subscription,
Theme, Vector,
};
@@ -52,10 +51,7 @@ impl SolarSystem {
}
fn view(&self) -> Element<Message> {
- canvas(&self.state)
- .width(Length::Fill)
- .height(Length::Fill)
- .into()
+ canvas(&self.state).width(Fill).height(Fill).into()
}
fn theme(&self) -> Theme {
@@ -69,6 +65,9 @@ impl SolarSystem {
#[derive(Debug)]
struct State {
+ sun: image::Handle,
+ earth: image::Handle,
+ moon: image::Handle,
space_cache: canvas::Cache,
system_cache: canvas::Cache,
start: Instant,
@@ -88,6 +87,15 @@ impl State {
let size = window::Settings::default().size;
State {
+ sun: image::Handle::from_bytes(
+ include_bytes!("../assets/sun.png").as_slice(),
+ ),
+ earth: image::Handle::from_bytes(
+ include_bytes!("../assets/earth.png").as_slice(),
+ ),
+ moon: image::Handle::from_bytes(
+ include_bytes!("../assets/moon.png").as_slice(),
+ ),
space_cache: canvas::Cache::default(),
system_cache: canvas::Cache::default(),
start: now,
@@ -135,6 +143,8 @@ impl<Message> canvas::Program<Message> for State {
let background =
self.space_cache.draw(renderer, bounds.size(), |frame| {
+ frame.fill_rectangle(Point::ORIGIN, frame.size(), Color::BLACK);
+
let stars = Path::new(|path| {
for (p, size) in &self.stars {
path.rectangle(*p, Size::new(*size, *size));
@@ -147,17 +157,18 @@ impl<Message> canvas::Program<Message> for State {
let system = self.system_cache.draw(renderer, bounds.size(), |frame| {
let center = frame.center();
+ frame.translate(Vector::new(center.x, center.y));
- let sun = Path::circle(center, Self::SUN_RADIUS);
- let orbit = Path::circle(center, Self::ORBIT_RADIUS);
+ frame.draw_image(
+ Rectangle::with_radius(Self::SUN_RADIUS),
+ &self.sun,
+ );
- frame.fill(&sun, Color::from_rgb8(0xF9, 0xD7, 0x1C));
+ let orbit = Path::circle(Point::ORIGIN, Self::ORBIT_RADIUS);
frame.stroke(
&orbit,
Stroke {
- style: stroke::Style::Solid(Color::from_rgba8(
- 0, 153, 255, 0.1,
- )),
+ style: stroke::Style::Solid(Color::WHITE.scale_alpha(0.1)),
width: 1.0,
line_dash: canvas::LineDash {
offset: 0,
@@ -171,30 +182,21 @@ impl<Message> canvas::Program<Message> for State {
let rotation = (2.0 * PI / 60.0) * elapsed.as_secs() as f32
+ (2.0 * PI / 60_000.0) * elapsed.subsec_millis() as f32;
- frame.with_save(|frame| {
- frame.translate(Vector::new(center.x, center.y));
- frame.rotate(rotation);
- frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0));
-
- let earth = Path::circle(Point::ORIGIN, Self::EARTH_RADIUS);
-
- let earth_fill = gradient::Linear::new(
- Point::new(-Self::EARTH_RADIUS, 0.0),
- Point::new(Self::EARTH_RADIUS, 0.0),
- )
- .add_stop(0.2, Color::from_rgb(0.15, 0.50, 1.0))
- .add_stop(0.8, Color::from_rgb(0.0, 0.20, 0.47));
+ frame.rotate(rotation);
+ frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0));
- frame.fill(&earth, earth_fill);
+ frame.draw_image(
+ Rectangle::with_radius(Self::EARTH_RADIUS),
+ canvas::Image::new(&self.earth).rotation(-rotation * 20.0),
+ );
- frame.with_save(|frame| {
- frame.rotate(rotation * 10.0);
- frame.translate(Vector::new(0.0, Self::MOON_DISTANCE));
+ frame.rotate(rotation * 10.0);
+ frame.translate(Vector::new(0.0, Self::MOON_DISTANCE));
- let moon = Path::circle(Point::ORIGIN, Self::MOON_RADIUS);
- frame.fill(&moon, Color::WHITE);
- });
- });
+ frame.draw_image(
+ Rectangle::with_radius(Self::MOON_RADIUS),
+ &self.moon,
+ );
});
vec![background, system]
diff --git a/examples/stopwatch/src/main.rs b/examples/stopwatch/src/main.rs
index bd56785a..0d824d36 100644
--- a/examples/stopwatch/src/main.rs
+++ b/examples/stopwatch/src/main.rs
@@ -1,8 +1,7 @@
-use iced::alignment;
use iced::keyboard;
use iced::time;
use iced::widget::{button, center, column, row, text};
-use iced::{Alignment, Element, Subscription, Theme};
+use iced::{Center, Element, Subscription, Theme};
use std::time::{Duration, Instant};
@@ -101,13 +100,8 @@ impl Stopwatch {
)
.size(40);
- let button = |label| {
- button(
- text(label).horizontal_alignment(alignment::Horizontal::Center),
- )
- .padding(10)
- .width(80)
- };
+ let button =
+ |label| button(text(label).align_x(Center)).padding(10).width(80);
let toggle_button = {
let label = match self.state {
@@ -124,9 +118,7 @@ impl Stopwatch {
let controls = row![toggle_button, reset_button].spacing(20);
- let content = column![duration, controls]
- .align_items(Alignment::Center)
- .spacing(20);
+ let content = column![duration, controls].align_x(Center).spacing(20);
center(content).into()
}
diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs
index 3124493b..534f5e32 100644
--- a/examples/styling/src/main.rs
+++ b/examples/styling/src/main.rs
@@ -3,7 +3,7 @@ use iced::widget::{
row, scrollable, slider, text, text_input, toggler, vertical_rule,
vertical_space,
};
-use iced::{Alignment, Element, Length, Theme};
+use iced::{Center, Element, Fill, Theme};
pub fn main() -> iced::Result {
iced::application("Styling - Iced", Styling::update, Styling::view)
@@ -48,7 +48,7 @@ impl Styling {
let choose_theme = column![
text("Theme:"),
pick_list(Theme::ALL, Some(&self.theme), Message::ThemeChanged)
- .width(Length::Fill),
+ .width(Fill),
]
.spacing(10);
@@ -71,26 +71,21 @@ impl Styling {
vertical_space().height(800),
"You did it!"
])
- .width(Length::Fill)
+ .width(Fill)
.height(100);
let checkbox = checkbox("Check me!", self.checkbox_value)
.on_toggle(Message::CheckboxToggled);
- let toggler = toggler(
- String::from("Toggle me!"),
- self.toggler_value,
- Message::TogglerToggled,
- )
- .width(Length::Shrink)
- .spacing(10);
+ let toggler = toggler(self.toggler_value)
+ .label("Toggle me!")
+ .on_toggle(Message::TogglerToggled)
+ .spacing(10);
let content = column![
choose_theme,
horizontal_rule(38),
- row![text_input, button]
- .spacing(10)
- .align_items(Alignment::Center),
+ row![text_input, button].spacing(10).align_y(Center),
slider,
progress_bar,
row![
@@ -100,7 +95,7 @@ impl Styling {
]
.spacing(10)
.height(100)
- .align_items(Alignment::Center),
+ .align_y(Center),
]
.spacing(20)
.padding(20)
diff --git a/examples/svg/src/main.rs b/examples/svg/src/main.rs
index e071c3af..02cb85cc 100644
--- a/examples/svg/src/main.rs
+++ b/examples/svg/src/main.rs
@@ -1,5 +1,5 @@
use iced::widget::{center, checkbox, column, container, svg};
-use iced::{color, Element, Length};
+use iced::{color, Element, Fill};
pub fn main() -> iced::Result {
iced::run("SVG - Iced", Tiger::update, Tiger::view)
@@ -30,24 +30,26 @@ impl Tiger {
env!("CARGO_MANIFEST_DIR")
));
- let svg = svg(handle).width(Length::Fill).height(Length::Fill).style(
- |_theme, _status| svg::Style {
- color: if self.apply_color_filter {
- Some(color!(0x0000ff))
- } else {
- None
- },
- },
- );
+ let svg =
+ svg(handle)
+ .width(Fill)
+ .height(Fill)
+ .style(|_theme, _status| svg::Style {
+ color: if self.apply_color_filter {
+ Some(color!(0x0000ff))
+ } else {
+ None
+ },
+ });
let apply_color_filter =
checkbox("Apply a color filter", self.apply_color_filter)
.on_toggle(Message::ToggleColorFilter);
center(
- column![svg, container(apply_color_filter).center_x(Length::Fill)]
+ column![svg, container(apply_color_filter).center_x(Fill)]
.spacing(20)
- .height(Length::Fill),
+ .height(Fill),
)
.padding(20)
.into()
diff --git a/examples/the_matrix/src/main.rs b/examples/the_matrix/src/main.rs
index 2ae1cc3a..0ed52dda 100644
--- a/examples/the_matrix/src/main.rs
+++ b/examples/the_matrix/src/main.rs
@@ -2,8 +2,7 @@ use iced::mouse;
use iced::time::{self, Instant};
use iced::widget::canvas;
use iced::{
- Color, Element, Font, Length, Point, Rectangle, Renderer, Subscription,
- Theme,
+ Color, Element, Fill, Font, Point, Rectangle, Renderer, Subscription, Theme,
};
use std::cell::RefCell;
@@ -37,10 +36,7 @@ impl TheMatrix {
}
fn view(&self) -> Element<Message> {
- canvas(self as &Self)
- .width(Length::Fill)
- .height(Length::Fill)
- .into()
+ canvas(self as &Self).width(Fill).height(Fill).into()
}
fn subscription(&self) -> Subscription<Message> {
diff --git a/examples/toast/src/main.rs b/examples/toast/src/main.rs
index 232133b1..8f6a836e 100644
--- a/examples/toast/src/main.rs
+++ b/examples/toast/src/main.rs
@@ -4,7 +4,7 @@ use iced::keyboard::key;
use iced::widget::{
self, button, center, column, pick_list, row, slider, text, text_input,
};
-use iced::{Alignment, Element, Length, Subscription, Task};
+use iced::{Center, Element, Fill, Subscription, Task};
use toast::{Status, Toast};
@@ -125,7 +125,7 @@ impl App {
Some(self.editing.status),
Message::Status
)
- .width(Length::Fill)
+ .width(Fill)
.into()
),
subtitle(
@@ -142,7 +142,7 @@ impl App {
.spacing(5)
.into()
),
- column![add_toast].align_items(Alignment::End)
+ column![add_toast].align_x(Center)
]
.spacing(10)
.max_width(200),
@@ -177,8 +177,8 @@ mod toast {
};
use iced::window;
use iced::{
- Alignment, Element, Length, Point, Rectangle, Renderer, Size, Theme,
- Vector,
+ Alignment, Center, Element, Fill, Length, Point, Rectangle, Renderer,
+ Size, Theme, Vector,
};
pub const DEFAULT_TIMEOUT: u64 = 5;
@@ -245,9 +245,9 @@ mod toast {
.on_press((on_close)(index))
.padding(3),
]
- .align_items(Alignment::Center)
+ .align_y(Center)
)
- .width(Length::Fill)
+ .width(Fill)
.padding(5)
.style(match toast.status {
Status::Primary => primary,
@@ -257,7 +257,7 @@ mod toast {
}),
horizontal_rule(1),
container(text(toast.body.as_str()))
- .width(Length::Fill)
+ .width(Fill)
.padding(5)
.style(container::rounded_box),
])
@@ -347,7 +347,7 @@ mod toast {
state: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
- operation: &mut dyn Operation<()>,
+ operation: &mut dyn Operation,
) {
operation.container(None, layout.bounds(), &mut |operation| {
self.content.as_widget().operate(
@@ -479,8 +479,8 @@ mod toast {
layout::flex::Axis::Vertical,
renderer,
&limits,
- Length::Fill,
- Length::Fill,
+ Fill,
+ Fill,
10.into(),
10.0,
Alignment::End,
@@ -589,7 +589,7 @@ mod toast {
&mut self,
layout: Layout<'_>,
renderer: &Renderer,
- operation: &mut dyn widget::Operation<()>,
+ operation: &mut dyn widget::Operation,
) {
operation.container(None, layout.bounds(), &mut |operation| {
self.toasts
diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs
index 6ed50d31..a5f7b36a 100644
--- a/examples/todos/src/main.rs
+++ b/examples/todos/src/main.rs
@@ -1,11 +1,10 @@
-use iced::alignment::{self, Alignment};
use iced::keyboard;
use iced::widget::{
self, button, center, checkbox, column, container, keyed_column, row,
scrollable, text, text_input, Text,
};
use iced::window;
-use iced::{Element, Font, Length, Subscription, Task as Command};
+use iced::{Center, Element, Fill, Font, Subscription, Task as Command};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
@@ -18,16 +17,14 @@ pub fn main() -> iced::Result {
tracing_subscriber::fmt::init();
iced::application(Todos::title, Todos::update, Todos::view)
- .load(Todos::load)
.subscription(Todos::subscription)
.font(include_bytes!("../fonts/icons.ttf").as_slice())
.window_size((500.0, 800.0))
- .run()
+ .run_with(Todos::new)
}
-#[derive(Default, Debug)]
+#[derive(Debug)]
enum Todos {
- #[default]
Loading,
Loaded(State),
}
@@ -54,8 +51,11 @@ enum Message {
}
impl Todos {
- fn load() -> Command<Message> {
- Command::perform(SavedState::load(), Message::Loaded)
+ fn new() -> (Self, Command<Message>) {
+ (
+ Self::Loading,
+ Command::perform(SavedState::load(), Message::Loaded),
+ )
}
fn title(&self) -> String {
@@ -192,17 +192,18 @@ impl Todos {
..
}) => {
let title = text("todos")
- .width(Length::Fill)
+ .width(Fill)
.size(100)
.color([0.5, 0.5, 0.5])
- .horizontal_alignment(alignment::Horizontal::Center);
+ .align_x(Center);
let input = text_input("What needs to be done?", input_value)
.id(INPUT_ID.clone())
.on_input(Message::InputChanged)
.on_submit(Message::CreateTask)
.padding(15)
- .size(30);
+ .size(30)
+ .align_x(Center);
let controls = view_controls(tasks, *filter);
let filtered_tasks =
@@ -239,10 +240,7 @@ impl Todos {
.spacing(20)
.max_width(800);
- scrollable(
- container(content).center_x(Length::Fill).padding(40),
- )
- .into()
+ scrollable(container(content).center_x(Fill).padding(40)).into()
}
}
}
@@ -342,7 +340,7 @@ impl Task {
TaskState::Idle => {
let checkbox = checkbox(&self.description, self.completed)
.on_toggle(TaskMessage::Completed)
- .width(Length::Fill)
+ .width(Fill)
.size(17)
.text_shaping(text::Shaping::Advanced);
@@ -354,7 +352,7 @@ impl Task {
.style(button::text),
]
.spacing(20)
- .align_items(Alignment::Center)
+ .align_y(Center)
.into()
}
TaskState::Editing => {
@@ -370,14 +368,14 @@ impl Task {
button(
row![delete_icon(), "Delete"]
.spacing(10)
- .align_items(Alignment::Center)
+ .align_y(Center)
)
.on_press(TaskMessage::Delete)
.padding(10)
.style(button::danger)
]
.spacing(20)
- .align_items(Alignment::Center)
+ .align_y(Center)
.into()
}
}
@@ -404,17 +402,16 @@ fn view_controls(tasks: &[Task], current_filter: Filter) -> Element<Message> {
"{tasks_left} {} left",
if tasks_left == 1 { "task" } else { "tasks" }
)
- .width(Length::Fill),
+ .width(Fill),
row![
filter_button("All", Filter::All, current_filter),
filter_button("Active", Filter::Active, current_filter),
filter_button("Completed", Filter::Completed, current_filter,),
]
- .width(Length::Shrink)
.spacing(10)
]
.spacing(20)
- .align_items(Alignment::Center)
+ .align_y(Center)
.into()
}
@@ -439,20 +436,15 @@ impl Filter {
}
fn loading_message<'a>() -> Element<'a, Message> {
- center(
- text("Loading...")
- .horizontal_alignment(alignment::Horizontal::Center)
- .size(50),
- )
- .into()
+ center(text("Loading...").width(Fill).align_x(Center).size(50)).into()
}
fn empty_message(message: &str) -> Element<'_, Message> {
center(
text(message)
- .width(Length::Fill)
+ .width(Fill)
.size(25)
- .horizontal_alignment(alignment::Horizontal::Center)
+ .align_x(Center)
.color([0.7, 0.7, 0.7]),
)
.height(200)
@@ -466,7 +458,7 @@ fn icon(unicode: char) -> Text<'static> {
text(unicode.to_string())
.font(ICONS)
.width(20)
- .horizontal_alignment(alignment::Horizontal::Center)
+ .align_x(Center)
}
fn edit_icon() -> Text<'static> {
diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs
index 94ba78ee..d8c0b29a 100644
--- a/examples/tour/src/main.rs
+++ b/examples/tour/src/main.rs
@@ -1,10 +1,9 @@
-use iced::alignment::{self, Alignment};
use iced::widget::{
button, checkbox, column, container, horizontal_space, image, radio, row,
scrollable, slider, text, text_input, toggler, vertical_space,
};
use iced::widget::{Button, Column, Container, Slider};
-use iced::{Color, Element, Font, Length, Pixels};
+use iced::{Center, Color, Element, Fill, Font, Pixels};
pub fn main() -> iced::Result {
#[cfg(target_arch = "wasm32")]
@@ -173,10 +172,10 @@ impl Tour {
} else {
content
})
- .center_x(Length::Fill),
+ .center_x(Fill),
);
- container(scrollable).center_y(Length::Fill).into()
+ container(scrollable).center_y(Fill).into()
}
fn can_continue(&self) -> bool {
@@ -235,11 +234,7 @@ impl Tour {
0 to 100:",
)
.push(slider(0..=100, self.slider, Message::SliderChanged))
- .push(
- text(self.slider.to_string())
- .width(Length::Fill)
- .horizontal_alignment(alignment::Horizontal::Center),
- )
+ .push(text(self.slider.to_string()).width(Fill).align_x(Center))
}
fn rows_and_columns(&self) -> Column<Message> {
@@ -268,9 +263,7 @@ impl Tour {
let spacing_section = column![
slider(0..=80, self.spacing, Message::SpacingChanged),
- text!("{} px", self.spacing)
- .width(Length::Fill)
- .horizontal_alignment(alignment::Horizontal::Center),
+ text!("{} px", self.spacing).width(Fill).align_x(Center),
]
.spacing(10);
@@ -364,11 +357,11 @@ impl Tour {
Self::container("Toggler")
.push("A toggler is mostly used to enable or disable something.")
.push(
- Container::new(toggler(
- "Toggle me to continue...".to_owned(),
- self.toggler,
- Message::TogglerChanged,
- ))
+ Container::new(
+ toggler(self.toggler)
+ .label("Toggle me to continue...")
+ .on_toggle(Message::TogglerChanged),
+ )
.padding([0, 40]),
)
}
@@ -381,11 +374,7 @@ impl Tour {
.push("An image that tries to keep its aspect ratio.")
.push(ferris(width, filter_method))
.push(slider(100..=500, width, Message::ImageWidthChanged))
- .push(
- text!("Width: {width} px")
- .width(Length::Fill)
- .horizontal_alignment(alignment::Horizontal::Center),
- )
+ .push(text!("Width: {width} px").width(Fill).align_x(Center))
.push(
checkbox(
"Use nearest interpolation",
@@ -393,7 +382,7 @@ impl Tour {
)
.on_toggle(Message::ImageUseNearestToggled),
)
- .align_items(Alignment::Center)
+ .align_x(Center)
}
fn scrollable(&self) -> Column<Message> {
@@ -409,18 +398,13 @@ impl Tour {
.push(vertical_space().height(4096))
.push(
text("You are halfway there!")
- .width(Length::Fill)
+ .width(Fill)
.size(30)
- .horizontal_alignment(alignment::Horizontal::Center),
+ .align_x(Center),
)
.push(vertical_space().height(4096))
.push(ferris(300, image::FilterMethod::Linear))
- .push(
- text("You made it!")
- .width(Length::Fill)
- .size(50)
- .horizontal_alignment(alignment::Horizontal::Center),
- )
+ .push(text("You made it!").width(Fill).size(50).align_x(Center))
}
fn text_input(&self) -> Column<Message> {
@@ -464,8 +448,8 @@ impl Tour {
} else {
value
})
- .width(Length::Fill)
- .horizontal_alignment(alignment::Horizontal::Center),
+ .width(Fill)
+ .align_x(Center),
)
}
@@ -570,7 +554,7 @@ fn ferris<'a>(
.filter_method(filter_method)
.width(width),
)
- .center_x(Length::Fill)
+ .center_x(Fill)
}
fn padded_button<Message: Clone>(label: &str) -> Button<'_, Message> {
diff --git a/examples/vectorial_text/src/main.rs b/examples/vectorial_text/src/main.rs
index 6dd3273a..ce34d826 100644
--- a/examples/vectorial_text/src/main.rs
+++ b/examples/vectorial_text/src/main.rs
@@ -1,9 +1,9 @@
-use iced::alignment::{self, Alignment};
+use iced::alignment;
use iced::mouse;
use iced::widget::{
canvas, checkbox, column, horizontal_space, row, slider, text,
};
-use iced::{Element, Length, Point, Rectangle, Renderer, Theme, Vector};
+use iced::{Center, Element, Fill, Point, Rectangle, Renderer, Theme, Vector};
pub fn main() -> iced::Result {
iced::application(
@@ -59,7 +59,7 @@ impl VectorialText {
};
column![
- canvas(&self.state).width(Length::Fill).height(Length::Fill),
+ canvas(&self.state).width(Fill).height(Fill),
column![
checkbox("Use Japanese", self.state.use_japanese,)
.on_toggle(Message::ToggleJapanese),
@@ -85,7 +85,7 @@ impl VectorialText {
]
.spacing(20),
]
- .align_items(Alignment::Center)
+ .align_x(Center)
.spacing(10)
]
.spacing(10)
diff --git a/examples/visible_bounds/src/main.rs b/examples/visible_bounds/src/main.rs
index e46d1ff0..77fec65e 100644
--- a/examples/visible_bounds/src/main.rs
+++ b/examples/visible_bounds/src/main.rs
@@ -5,8 +5,8 @@ use iced::widget::{
};
use iced::window;
use iced::{
- Alignment, Color, Element, Font, Length, Point, Rectangle, Subscription,
- Task, Theme,
+ Center, Color, Element, Fill, Font, Point, Rectangle, Subscription, Task,
+ Theme,
};
pub fn main() -> iced::Result {
@@ -70,7 +70,7 @@ impl Example {
.color_maybe(color),
]
.height(40)
- .align_items(Alignment::Center)
+ .align_y(Center)
};
let view_bounds = |label, bounds: Option<Rectangle>| {
@@ -130,13 +130,13 @@ impl Example {
.padding(20)
)
.on_scroll(|_| Message::Scrolled)
- .width(Length::Fill)
+ .width(Fill)
.height(300),
]
.padding(20)
)
.on_scroll(|_| Message::Scrolled)
- .width(Length::Fill)
+ .width(Fill)
.height(300),
]
.spacing(10)
diff --git a/examples/websocket/src/echo.rs b/examples/websocket/src/echo.rs
index cd32cb66..14652936 100644
--- a/examples/websocket/src/echo.rs
+++ b/examples/websocket/src/echo.rs
@@ -1,87 +1,79 @@
pub mod server;
use iced::futures;
-use iced::subscription::{self, Subscription};
+use iced::stream;
use iced::widget::text;
use futures::channel::mpsc;
use futures::sink::SinkExt;
-use futures::stream::StreamExt;
+use futures::stream::{Stream, StreamExt};
use async_tungstenite::tungstenite;
use std::fmt;
-pub fn connect() -> Subscription<Event> {
- struct Connect;
+pub fn connect() -> impl Stream<Item = Event> {
+ stream::channel(100, |mut output| async move {
+ let mut state = State::Disconnected;
- subscription::channel(
- std::any::TypeId::of::<Connect>(),
- 100,
- |mut output| async move {
- let mut state = State::Disconnected;
+ loop {
+ match &mut state {
+ State::Disconnected => {
+ const ECHO_SERVER: &str = "ws://127.0.0.1:3030";
- loop {
- match &mut state {
- State::Disconnected => {
- const ECHO_SERVER: &str = "ws://127.0.0.1:3030";
-
- match async_tungstenite::tokio::connect_async(
- ECHO_SERVER,
- )
+ match async_tungstenite::tokio::connect_async(ECHO_SERVER)
.await
- {
- Ok((websocket, _)) => {
- let (sender, receiver) = mpsc::channel(100);
-
- let _ = output
- .send(Event::Connected(Connection(sender)))
- .await;
+ {
+ Ok((websocket, _)) => {
+ let (sender, receiver) = mpsc::channel(100);
- state = State::Connected(websocket, receiver);
- }
- Err(_) => {
- tokio::time::sleep(
- tokio::time::Duration::from_secs(1),
- )
+ let _ = output
+ .send(Event::Connected(Connection(sender)))
.await;
- let _ = output.send(Event::Disconnected).await;
- }
+ state = State::Connected(websocket, receiver);
+ }
+ Err(_) => {
+ tokio::time::sleep(
+ tokio::time::Duration::from_secs(1),
+ )
+ .await;
+
+ let _ = output.send(Event::Disconnected).await;
}
}
- State::Connected(websocket, input) => {
- let mut fused_websocket = websocket.by_ref().fuse();
-
- futures::select! {
- received = fused_websocket.select_next_some() => {
- match received {
- Ok(tungstenite::Message::Text(message)) => {
- let _ = output.send(Event::MessageReceived(Message::User(message))).await;
- }
- Err(_) => {
- let _ = output.send(Event::Disconnected).await;
-
- state = State::Disconnected;
- }
- Ok(_) => continue,
+ }
+ State::Connected(websocket, input) => {
+ let mut fused_websocket = websocket.by_ref().fuse();
+
+ futures::select! {
+ received = fused_websocket.select_next_some() => {
+ match received {
+ Ok(tungstenite::Message::Text(message)) => {
+ let _ = output.send(Event::MessageReceived(Message::User(message))).await;
}
- }
-
- message = input.select_next_some() => {
- let result = websocket.send(tungstenite::Message::Text(message.to_string())).await;
-
- if result.is_err() {
+ Err(_) => {
let _ = output.send(Event::Disconnected).await;
state = State::Disconnected;
}
+ Ok(_) => continue,
+ }
+ }
+
+ message = input.select_next_some() => {
+ let result = websocket.send(tungstenite::Message::Text(message.to_string())).await;
+
+ if result.is_err() {
+ let _ = output.send(Event::Disconnected).await;
+
+ state = State::Disconnected;
}
}
}
}
}
- },
- )
+ }
+ })
}
#[derive(Debug)]
diff --git a/examples/websocket/src/main.rs b/examples/websocket/src/main.rs
index 8422ce16..8b1efb41 100644
--- a/examples/websocket/src/main.rs
+++ b/examples/websocket/src/main.rs
@@ -1,20 +1,17 @@
mod echo;
-use iced::alignment::{self, Alignment};
use iced::widget::{
self, button, center, column, row, scrollable, text, text_input,
};
-use iced::{color, Element, Length, Subscription, Task};
+use iced::{color, Center, Element, Fill, Subscription, Task};
use once_cell::sync::Lazy;
pub fn main() -> iced::Result {
iced::application("WebSocket - Iced", WebSocket::update, WebSocket::view)
- .load(WebSocket::load)
.subscription(WebSocket::subscription)
- .run()
+ .run_with(WebSocket::new)
}
-#[derive(Default)]
struct WebSocket {
messages: Vec<echo::Message>,
new_message: String,
@@ -30,11 +27,18 @@ enum Message {
}
impl WebSocket {
- fn load() -> Task<Message> {
- Task::batch([
- Task::perform(echo::server::run(), |_| Message::Server),
- widget::focus_next(),
- ])
+ fn new() -> (Self, Task<Message>) {
+ (
+ Self {
+ messages: Vec::new(),
+ new_message: String::new(),
+ state: State::Disconnected,
+ },
+ Task::batch([
+ Task::perform(echo::server::run(), |_| Message::Server),
+ widget::focus_next(),
+ ]),
+ )
}
fn update(&mut self, message: Message) -> Task<Message> {
@@ -83,7 +87,7 @@ impl WebSocket {
}
fn subscription(&self) -> Subscription<Message> {
- echo::connect().map(Message::Echo)
+ Subscription::run(echo::connect).map(Message::Echo)
}
fn view(&self) -> Element<Message> {
@@ -99,7 +103,7 @@ impl WebSocket {
.spacing(10),
)
.id(MESSAGE_LOG.clone())
- .height(Length::Fill)
+ .height(Fill)
.into()
};
@@ -108,12 +112,8 @@ impl WebSocket {
.on_input(Message::NewMessageChanged)
.padding(10);
- let mut button = button(
- text("Send")
- .height(40)
- .vertical_alignment(alignment::Vertical::Center),
- )
- .padding([0, 20]);
+ let mut button = button(text("Send").height(40).align_y(Center))
+ .padding([0, 20]);
if matches!(self.state, State::Connected(_)) {
if let Some(message) = echo::Message::new(&self.new_message) {
@@ -122,13 +122,11 @@ impl WebSocket {
}
}
- row![input, button]
- .spacing(10)
- .align_items(Alignment::Center)
+ row![input, button].spacing(10).align_y(Center)
};
column![message_log, new_message_input]
- .height(Length::Fill)
+ .height(Fill)
.padding(20)
.spacing(10)
.into()
@@ -140,10 +138,4 @@ enum State {
Connected(echo::Connection),
}
-impl Default for State {
- fn default() -> Self {
- Self::Disconnected
- }
-}
-
static MESSAGE_LOG: Lazy<scrollable::Id> = Lazy::new(scrollable::Id::unique);