summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2024-05-23 13:29:45 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2024-05-23 13:29:45 +0200
commitd8ba6b0673a33724a177f3a1ba59705527280142 (patch)
tree89482c8d1e3a03e00b3a8151abbb81e30ae5898c /examples
parent72ed8bcc8def9956e25f3720a3095fc96bb2eef0 (diff)
parent468794d918eb06c1dbebb33c32b10017ad335f05 (diff)
downloadiced-d8ba6b0673a33724a177f3a1ba59705527280142.tar.gz
iced-d8ba6b0673a33724a177f3a1ba59705527280142.tar.bz2
iced-d8ba6b0673a33724a177f3a1ba59705527280142.zip
Merge branch 'master' into feat/text-macro
Diffstat (limited to 'examples')
-rw-r--r--examples/bezier_tool/src/main.rs68
-rw-r--r--examples/checkbox/src/main.rs11
-rw-r--r--examples/clock/Cargo.toml4
-rw-r--r--examples/clock/src/main.rs24
-rw-r--r--examples/color_palette/src/main.rs4
-rw-r--r--examples/combo_box/src/main.rs9
-rw-r--r--examples/component/src/main.rs18
-rw-r--r--examples/custom_quad/src/main.rs11
-rw-r--r--examples/custom_shader/src/main.rs9
-rw-r--r--examples/custom_shader/src/scene.rs33
-rw-r--r--examples/custom_widget/src/main.rs11
-rw-r--r--examples/download_progress/src/download.rs6
-rw-r--r--examples/download_progress/src/main.rs12
-rw-r--r--examples/editor/src/main.rs2
-rw-r--r--examples/events/src/main.rs9
-rw-r--r--examples/exit/src/main.rs12
-rw-r--r--examples/ferris/Cargo.toml10
-rw-r--r--examples/ferris/src/main.rs211
-rw-r--r--examples/game_of_life/src/main.rs6
-rw-r--r--examples/geometry/src/main.rs21
-rw-r--r--examples/gradient/src/main.rs2
-rw-r--r--examples/integration/Cargo.toml2
-rw-r--r--examples/integration/README.md19
-rw-r--r--examples/integration/index.html21
-rw-r--r--examples/integration/src/main.rs571
-rw-r--r--examples/layout/src/main.rs30
-rw-r--r--examples/lazy/src/main.rs2
-rw-r--r--examples/loading_spinners/src/circular.rs2
-rw-r--r--examples/loading_spinners/src/main.rs10
-rw-r--r--examples/loupe/src/main.rs12
-rw-r--r--examples/modal/src/main.rs368
-rw-r--r--examples/multi_window/src/main.rs13
-rw-r--r--examples/pane_grid/src/main.rs32
-rw-r--r--examples/pokedex/src/main.rs11
-rw-r--r--examples/qr_code/src/main.rs14
-rw-r--r--examples/screenshot/src/main.rs24
-rw-r--r--examples/scrollable/src/main.rs6
-rw-r--r--examples/sierpinski_triangle/src/main.rs4
-rw-r--r--examples/slider/src/main.rs14
-rw-r--r--examples/solar_system/src/main.rs4
-rw-r--r--examples/stopwatch/src/main.rs11
-rw-r--r--examples/styling/src/main.rs13
-rw-r--r--examples/svg/src/main.rs19
-rw-r--r--examples/system_information/src/main.rs11
-rw-r--r--examples/the_matrix/Cargo.toml13
-rw-r--r--examples/the_matrix/src/main.rs115
-rw-r--r--examples/toast/src/main.rs34
-rw-r--r--examples/todos/src/main.rs17
-rw-r--r--examples/tooltip/src/main.rs11
-rw-r--r--examples/tour/src/main.rs14
-rw-r--r--examples/url_handler/src/main.rs11
-rw-r--r--examples/websocket/src/echo.rs23
-rw-r--r--examples/websocket/src/main.rs19
53 files changed, 926 insertions, 1037 deletions
diff --git a/examples/bezier_tool/src/main.rs b/examples/bezier_tool/src/main.rs
index cf70bd40..29df3eeb 100644
--- a/examples/bezier_tool/src/main.rs
+++ b/examples/bezier_tool/src/main.rs
@@ -1,9 +1,11 @@
//! This example showcases an interactive `Canvas` for drawing Bézier curves.
-use iced::widget::{button, column, text};
-use iced::{Alignment, Element, Length};
+use iced::alignment;
+use iced::widget::{button, container, horizontal_space, hover};
+use iced::{Element, Length, Theme};
pub fn main() -> iced::Result {
iced::program("Bezier Tool - Iced", Example::update, Example::view)
+ .theme(|_| Theme::CatppuccinMocha)
.antialiasing(true)
.run()
}
@@ -35,16 +37,22 @@ impl Example {
}
fn view(&self) -> Element<Message> {
- column![
- text("Bezier tool example").width(Length::Shrink).size(50),
+ container(hover(
self.bezier.view(&self.curves).map(Message::AddCurve),
- button("Clear")
- .style(button::danger)
- .on_press(Message::Clear),
- ]
+ if self.curves.is_empty() {
+ container(horizontal_space())
+ } else {
+ container(
+ button("Clear")
+ .style(button::danger)
+ .on_press(Message::Clear),
+ )
+ .padding(10)
+ .width(Length::Fill)
+ .align_x(alignment::Horizontal::Right)
+ },
+ ))
.padding(20)
- .spacing(20)
- .align_items(Alignment::Center)
.into()
}
}
@@ -139,27 +147,24 @@ mod bezier {
&self,
state: &Self::State,
renderer: &Renderer,
- _theme: &Theme,
+ theme: &Theme,
bounds: Rectangle,
cursor: mouse::Cursor,
) -> Vec<Geometry> {
- let content = self.state.cache.draw(
- renderer,
- bounds.size(),
- |frame: &mut Frame| {
- Curve::draw_all(self.curves, frame);
+ let content =
+ self.state.cache.draw(renderer, bounds.size(), |frame| {
+ Curve::draw_all(self.curves, frame, theme);
frame.stroke(
&Path::rectangle(Point::ORIGIN, frame.size()),
- Stroke::default().with_width(2.0),
+ Stroke::default()
+ .with_width(2.0)
+ .with_color(theme.palette().text),
);
- },
- );
+ });
if let Some(pending) = state {
- let pending_curve = pending.draw(renderer, bounds, cursor);
-
- vec![content, pending_curve]
+ vec![content, pending.draw(renderer, theme, bounds, cursor)]
} else {
vec![content]
}
@@ -187,7 +192,7 @@ mod bezier {
}
impl Curve {
- fn draw_all(curves: &[Curve], frame: &mut Frame) {
+ fn draw_all(curves: &[Curve], frame: &mut Frame, theme: &Theme) {
let curves = Path::new(|p| {
for curve in curves {
p.move_to(curve.from);
@@ -195,7 +200,12 @@ mod bezier {
}
});
- frame.stroke(&curves, Stroke::default().with_width(2.0));
+ frame.stroke(
+ &curves,
+ Stroke::default()
+ .with_width(2.0)
+ .with_color(theme.palette().text),
+ );
}
}
@@ -209,6 +219,7 @@ mod bezier {
fn draw(
&self,
renderer: &Renderer,
+ theme: &Theme,
bounds: Rectangle,
cursor: mouse::Cursor,
) -> Geometry {
@@ -218,7 +229,12 @@ mod bezier {
match *self {
Pending::One { from } => {
let line = Path::line(from, cursor_position);
- frame.stroke(&line, Stroke::default().with_width(2.0));
+ frame.stroke(
+ &line,
+ Stroke::default()
+ .with_width(2.0)
+ .with_color(theme.palette().text),
+ );
}
Pending::Two { from, to } => {
let curve = Curve {
@@ -227,7 +243,7 @@ mod bezier {
control: cursor_position,
};
- Curve::draw_all(&[curve], &mut frame);
+ Curve::draw_all(&[curve], &mut frame, theme);
}
};
}
diff --git a/examples/checkbox/src/main.rs b/examples/checkbox/src/main.rs
index 38949336..bec4a954 100644
--- a/examples/checkbox/src/main.rs
+++ b/examples/checkbox/src/main.rs
@@ -1,5 +1,5 @@
-use iced::widget::{checkbox, column, container, row, text};
-use iced::{Element, Font, Length};
+use iced::widget::{center, checkbox, column, row, text};
+use iced::{Element, Font};
const ICON_FONT: Font = Font::with_name("icons");
@@ -68,11 +68,6 @@ impl Example {
let content =
column![default_checkbox, checkboxes, custom_checkbox].spacing(20);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(content).into()
}
}
diff --git a/examples/clock/Cargo.toml b/examples/clock/Cargo.toml
index 2d3d5908..bc6c202b 100644
--- a/examples/clock/Cargo.toml
+++ b/examples/clock/Cargo.toml
@@ -8,5 +8,5 @@ publish = false
[dependencies]
iced.workspace = true
iced.features = ["canvas", "tokio", "debug"]
-
-time = { version = "0.3", features = ["local-offset"] }
+chrono = "0.4"
+tracing-subscriber = "0.3"
diff --git a/examples/clock/src/main.rs b/examples/clock/src/main.rs
index 897f8f1b..7c4685c4 100644
--- a/examples/clock/src/main.rs
+++ b/examples/clock/src/main.rs
@@ -1,5 +1,6 @@
use iced::alignment;
use iced::mouse;
+use iced::time;
use iced::widget::canvas::{stroke, Cache, Geometry, LineCap, Path, Stroke};
use iced::widget::{canvas, container};
use iced::{
@@ -8,6 +9,8 @@ use iced::{
};
pub fn main() -> iced::Result {
+ tracing_subscriber::fmt::init();
+
iced::program("Clock - Iced", Clock::update, Clock::view)
.subscription(Clock::subscription)
.theme(Clock::theme)
@@ -16,13 +19,13 @@ pub fn main() -> iced::Result {
}
struct Clock {
- now: time::OffsetDateTime,
+ now: chrono::DateTime<chrono::Local>,
clock: Cache,
}
#[derive(Debug, Clone, Copy)]
enum Message {
- Tick(time::OffsetDateTime),
+ Tick(chrono::DateTime<chrono::Local>),
}
impl Clock {
@@ -52,16 +55,12 @@ impl Clock {
}
fn subscription(&self) -> Subscription<Message> {
- iced::time::every(std::time::Duration::from_millis(500)).map(|_| {
- Message::Tick(
- time::OffsetDateTime::now_local()
- .unwrap_or_else(|_| time::OffsetDateTime::now_utc()),
- )
- })
+ time::every(time::Duration::from_millis(500))
+ .map(|_| Message::Tick(chrono::offset::Local::now()))
}
fn theme(&self) -> Theme {
- Theme::ALL[(self.now.unix_timestamp() as usize / 10) % Theme::ALL.len()]
+ Theme::ALL[(self.now.timestamp() as usize / 10) % Theme::ALL.len()]
.clone()
}
}
@@ -69,8 +68,7 @@ impl Clock {
impl Default for Clock {
fn default() -> Self {
Self {
- now: time::OffsetDateTime::now_local()
- .unwrap_or_else(|_| time::OffsetDateTime::now_utc()),
+ now: chrono::offset::Local::now(),
clock: Cache::default(),
}
}
@@ -87,6 +85,8 @@ impl<Message> canvas::Program<Message> for Clock {
bounds: Rectangle,
_cursor: mouse::Cursor,
) -> Vec<Geometry> {
+ use chrono::Timelike;
+
let clock = self.clock.draw(renderer, bounds.size(), |frame| {
let palette = theme.extended_palette();
@@ -167,7 +167,7 @@ impl<Message> canvas::Program<Message> for Clock {
}
}
-fn hand_rotation(n: u8, total: u8) -> Degrees {
+fn hand_rotation(n: u32, total: u32) -> Degrees {
let turns = n as f32 / total as f32;
Degrees(360.0 * turns)
diff --git a/examples/color_palette/src/main.rs b/examples/color_palette/src/main.rs
index 29337508..d9325edb 100644
--- a/examples/color_palette/src/main.rs
+++ b/examples/color_palette/src/main.rs
@@ -6,9 +6,7 @@ use iced::{
Color, Element, Font, Length, Pixels, Point, Rectangle, Renderer, Size,
Vector,
};
-use palette::{
- self, convert::FromColor, rgb::Rgb, Darken, Hsl, Lighten, ShiftHue,
-};
+use palette::{convert::FromColor, rgb::Rgb, Darken, Hsl, Lighten, ShiftHue};
use std::marker::PhantomData;
use std::ops::RangeInclusive;
diff --git a/examples/combo_box/src/main.rs b/examples/combo_box/src/main.rs
index 2feb4522..ff759ab4 100644
--- a/examples/combo_box/src/main.rs
+++ b/examples/combo_box/src/main.rs
@@ -1,5 +1,5 @@
use iced::widget::{
- column, combo_box, container, scrollable, text, vertical_space,
+ center, column, combo_box, scrollable, text, vertical_space,
};
use iced::{Alignment, Element, Length};
@@ -68,12 +68,7 @@ impl Example {
.align_items(Alignment::Center)
.spacing(10);
- container(scrollable(content))
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(scrollable(content)).into()
}
}
diff --git a/examples/component/src/main.rs b/examples/component/src/main.rs
index 43ba3187..5625f12a 100644
--- a/examples/component/src/main.rs
+++ b/examples/component/src/main.rs
@@ -1,5 +1,5 @@
-use iced::widget::container;
-use iced::{Element, Length};
+use iced::widget::center;
+use iced::Element;
use numeric_input::numeric_input;
@@ -27,10 +27,8 @@ impl Component {
}
fn view(&self) -> Element<Message> {
- container(numeric_input(self.value, Message::NumericInputChanged))
+ center(numeric_input(self.value, Message::NumericInputChanged))
.padding(20)
- .height(Length::Fill)
- .center_y()
.into()
}
}
@@ -73,10 +71,7 @@ mod numeric_input {
impl<Message, Theme> Component<Message, Theme> for NumericInput<Message>
where
- Theme: text::DefaultStyle
- + button::DefaultStyle
- + text_input::DefaultStyle
- + 'static,
+ Theme: text::Catalog + button::Catalog + text_input::Catalog + 'static,
{
type State = ();
type Event = Event;
@@ -151,10 +146,7 @@ mod numeric_input {
impl<'a, Message, Theme> From<NumericInput<Message>>
for Element<'a, Message, Theme>
where
- Theme: text::DefaultStyle
- + button::DefaultStyle
- + text_input::DefaultStyle
- + 'static,
+ Theme: text::Catalog + button::Catalog + text_input::Catalog + 'static,
Message: 'a,
{
fn from(numeric_input: NumericInput<Message>) -> Self {
diff --git a/examples/custom_quad/src/main.rs b/examples/custom_quad/src/main.rs
index d8aac1d0..b53a40d6 100644
--- a/examples/custom_quad/src/main.rs
+++ b/examples/custom_quad/src/main.rs
@@ -81,8 +81,8 @@ mod quad {
}
}
-use iced::widget::{column, container, slider, text};
-use iced::{Alignment, Color, Element, Length, Shadow, Vector};
+use iced::widget::{center, column, slider, text};
+use iced::{Alignment, Color, Element, Shadow, Vector};
pub fn main() -> iced::Result {
iced::run("Custom Quad - Iced", Example::update, Example::view)
@@ -187,12 +187,7 @@ impl Example {
.max_width(500)
.align_items(Alignment::Center);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(content).into()
}
}
diff --git a/examples/custom_shader/src/main.rs b/examples/custom_shader/src/main.rs
index aa3dafe9..463b2df9 100644
--- a/examples/custom_shader/src/main.rs
+++ b/examples/custom_shader/src/main.rs
@@ -4,7 +4,7 @@ use scene::Scene;
use iced::time::Instant;
use iced::widget::shader::wgpu;
-use iced::widget::{checkbox, column, container, row, shader, slider, text};
+use iced::widget::{center, checkbox, column, row, shader, slider, text};
use iced::window;
use iced::{Alignment, Color, Element, Length, Subscription};
@@ -123,12 +123,7 @@ impl IcedCubes {
let shader =
shader(&self.scene).width(Length::Fill).height(Length::Fill);
- container(column![shader, controls].align_items(Alignment::Center))
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(column![shader, controls].align_items(Alignment::Center)).into()
}
fn subscription(&self) -> Subscription<Message> {
diff --git a/examples/custom_shader/src/scene.rs b/examples/custom_shader/src/scene.rs
index a35efdd9..5fa42188 100644
--- a/examples/custom_shader/src/scene.rs
+++ b/examples/custom_shader/src/scene.rs
@@ -9,8 +9,8 @@ use pipeline::cube::{self, Cube};
use iced::mouse;
use iced::time::Duration;
-use iced::widget::shader;
-use iced::{Color, Rectangle, Size};
+use iced::widget::shader::{self, Viewport};
+use iced::{Color, Rectangle};
use glam::Vec3;
use rand::Rng;
@@ -130,25 +130,29 @@ impl Primitive {
impl shader::Primitive for Primitive {
fn prepare(
&self,
- format: wgpu::TextureFormat,
device: &wgpu::Device,
queue: &wgpu::Queue,
- _bounds: Rectangle,
- target_size: Size<u32>,
- _scale_factor: f32,
+ format: wgpu::TextureFormat,
storage: &mut shader::Storage,
+ _bounds: &Rectangle,
+ viewport: &Viewport,
) {
if !storage.has::<Pipeline>() {
- storage.store(Pipeline::new(device, queue, format, target_size));
+ storage.store(Pipeline::new(
+ device,
+ queue,
+ format,
+ viewport.physical_size(),
+ ));
}
let pipeline = storage.get_mut::<Pipeline>().unwrap();
- //upload data to GPU
+ // Upload data to GPU
pipeline.update(
device,
queue,
- target_size,
+ viewport.physical_size(),
&self.uniforms,
self.cubes.len(),
&self.cubes,
@@ -157,20 +161,19 @@ impl shader::Primitive for Primitive {
fn render(
&self,
+ encoder: &mut wgpu::CommandEncoder,
storage: &shader::Storage,
target: &wgpu::TextureView,
- _target_size: Size<u32>,
- viewport: Rectangle<u32>,
- encoder: &mut wgpu::CommandEncoder,
+ clip_bounds: &Rectangle<u32>,
) {
- //at this point our pipeline should always be initialized
+ // At this point our pipeline should always be initialized
let pipeline = storage.get::<Pipeline>().unwrap();
- //render primitive
+ // Render primitive
pipeline.render(
target,
encoder,
- viewport,
+ *clip_bounds,
self.cubes.len() as u32,
self.show_depth_buffer,
);
diff --git a/examples/custom_widget/src/main.rs b/examples/custom_widget/src/main.rs
index 0c9e774d..3cf10e22 100644
--- a/examples/custom_widget/src/main.rs
+++ b/examples/custom_widget/src/main.rs
@@ -82,8 +82,8 @@ mod circle {
}
use circle::circle;
-use iced::widget::{column, container, slider, text};
-use iced::{Alignment, Element, Length};
+use iced::widget::{center, column, slider, text};
+use iced::{Alignment, Element};
pub fn main() -> iced::Result {
iced::run("Custom Widget - Iced", Example::update, Example::view)
@@ -122,12 +122,7 @@ impl Example {
.max_width(500)
.align_items(Alignment::Center);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(content).into()
}
}
diff --git a/examples/download_progress/src/download.rs b/examples/download_progress/src/download.rs
index 3b11cb76..d6cc1e24 100644
--- a/examples/download_progress/src/download.rs
+++ b/examples/download_progress/src/download.rs
@@ -12,12 +12,6 @@ pub fn file<I: 'static + Hash + Copy + Send + Sync, T: ToString>(
})
}
-#[derive(Debug, Hash, Clone)]
-pub struct Download<I> {
- id: I,
- url: String,
-}
-
async fn download<I: Copy>(id: I, state: State) -> ((I, Progress), State) {
match state {
State::Ready(url) => {
diff --git a/examples/download_progress/src/main.rs b/examples/download_progress/src/main.rs
index a4136415..7974d5a0 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, column, container, progress_bar, text, Column};
-use iced::{Alignment, Element, Length, Subscription};
+use iced::widget::{button, center, column, progress_bar, text, Column};
+use iced::{Alignment, Element, Subscription};
pub fn main() -> iced::Result {
iced::program("Download Progress - Iced", Example::update, Example::view)
@@ -67,13 +67,7 @@ impl Example {
.spacing(20)
.align_items(Alignment::End);
- container(downloads)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .padding(20)
- .into()
+ center(downloads).padding(20).into()
}
}
diff --git a/examples/editor/src/main.rs b/examples/editor/src/main.rs
index ed16018a..c20a7d67 100644
--- a/examples/editor/src/main.rs
+++ b/examples/editor/src/main.rs
@@ -277,7 +277,7 @@ fn action<'a, Message: Clone + 'a>(
label: &'a str,
on_press: Option<Message>,
) -> Element<'a, Message> {
- let action = button(container(content).width(30).center_x());
+ let action = button(container(content).center_x(30));
if let Some(on_press) = on_press {
tooltip(
diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs
index 4734e20c..9d1c502a 100644
--- a/examples/events/src/main.rs
+++ b/examples/events/src/main.rs
@@ -1,6 +1,6 @@
use iced::alignment;
use iced::event::{self, Event};
-use iced::widget::{button, checkbox, container, text, Column};
+use iced::widget::{button, center, checkbox, text, Column};
use iced::window;
use iced::{Alignment, Command, Element, Length, Subscription};
@@ -84,11 +84,6 @@ impl Events {
.push(toggle)
.push(exit);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(content).into()
}
}
diff --git a/examples/exit/src/main.rs b/examples/exit/src/main.rs
index 7bed272d..2de97e20 100644
--- a/examples/exit/src/main.rs
+++ b/examples/exit/src/main.rs
@@ -1,6 +1,6 @@
-use iced::widget::{button, column, container};
+use iced::widget::{button, center, column};
use iced::window;
-use iced::{Alignment, Command, Element, Length};
+use iced::{Alignment, Command, Element};
pub fn main() -> iced::Result {
iced::program("Exit - Iced", Exit::update, Exit::view).run()
@@ -46,12 +46,6 @@ impl Exit {
.spacing(10)
.align_items(Alignment::Center);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .padding(20)
- .center_x()
- .center_y()
- .into()
+ center(content).padding(20).into()
}
}
diff --git a/examples/ferris/Cargo.toml b/examples/ferris/Cargo.toml
new file mode 100644
index 00000000..e98341d2
--- /dev/null
+++ b/examples/ferris/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "ferris"
+version = "0.1.0"
+authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
+edition = "2021"
+publish = false
+
+[dependencies]
+iced.workspace = true
+iced.features = ["image", "tokio", "debug"]
diff --git a/examples/ferris/src/main.rs b/examples/ferris/src/main.rs
new file mode 100644
index 00000000..0400c376
--- /dev/null
+++ b/examples/ferris/src/main.rs
@@ -0,0 +1,211 @@
+use iced::time::Instant;
+use iced::widget::{
+ center, checkbox, column, container, image, pick_list, row, slider, text,
+};
+use iced::window;
+use iced::{
+ Alignment, Color, ContentFit, Degrees, Element, Length, Radians, Rotation,
+ Subscription, Theme,
+};
+
+pub fn main() -> iced::Result {
+ iced::program("Ferris - Iced", Image::update, Image::view)
+ .subscription(Image::subscription)
+ .theme(|_| Theme::TokyoNight)
+ .run()
+}
+
+struct Image {
+ width: f32,
+ opacity: f32,
+ rotation: Rotation,
+ content_fit: ContentFit,
+ spin: bool,
+ last_tick: Instant,
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Message {
+ WidthChanged(f32),
+ OpacityChanged(f32),
+ RotationStrategyChanged(RotationStrategy),
+ RotationChanged(Degrees),
+ ContentFitChanged(ContentFit),
+ SpinToggled(bool),
+ RedrawRequested(Instant),
+}
+
+impl Image {
+ fn update(&mut self, message: Message) {
+ match message {
+ Message::WidthChanged(width) => {
+ self.width = width;
+ }
+ Message::OpacityChanged(opacity) => {
+ self.opacity = opacity;
+ }
+ Message::RotationStrategyChanged(strategy) => {
+ self.rotation = match strategy {
+ RotationStrategy::Floating => {
+ Rotation::Floating(self.rotation.radians())
+ }
+ RotationStrategy::Solid => {
+ Rotation::Solid(self.rotation.radians())
+ }
+ };
+ }
+ Message::RotationChanged(rotation) => {
+ self.rotation = match self.rotation {
+ Rotation::Floating(_) => {
+ Rotation::Floating(rotation.into())
+ }
+ Rotation::Solid(_) => Rotation::Solid(rotation.into()),
+ };
+ }
+ Message::ContentFitChanged(content_fit) => {
+ self.content_fit = content_fit;
+ }
+ Message::SpinToggled(spin) => {
+ self.spin = spin;
+ self.last_tick = Instant::now();
+ }
+ Message::RedrawRequested(now) => {
+ const ROTATION_SPEED: Degrees = Degrees(360.0);
+
+ let delta = (now - self.last_tick).as_millis() as f32 / 1_000.0;
+
+ *self.rotation.radians_mut() = (self.rotation.radians()
+ + ROTATION_SPEED * delta)
+ % (2.0 * Radians::PI);
+
+ self.last_tick = now;
+ }
+ }
+ }
+
+ fn subscription(&self) -> Subscription<Message> {
+ if self.spin {
+ window::frames().map(Message::RedrawRequested)
+ } else {
+ Subscription::none()
+ }
+ }
+
+ fn view(&self) -> Element<Message> {
+ let i_am_ferris = column![
+ "Hello!",
+ Element::from(
+ image(format!(
+ "{}/../tour/images/ferris.png",
+ env!("CARGO_MANIFEST_DIR")
+ ))
+ .width(self.width)
+ .content_fit(self.content_fit)
+ .rotation(self.rotation)
+ .opacity(self.opacity)
+ )
+ .explain(Color::WHITE),
+ "I am Ferris!"
+ ]
+ .spacing(20)
+ .align_items(Alignment::Center);
+
+ let fit = row![
+ pick_list(
+ [
+ ContentFit::Contain,
+ ContentFit::Cover,
+ ContentFit::Fill,
+ ContentFit::None,
+ ContentFit::ScaleDown
+ ],
+ Some(self.content_fit),
+ Message::ContentFitChanged
+ )
+ .width(Length::Fill),
+ pick_list(
+ [RotationStrategy::Floating, RotationStrategy::Solid],
+ Some(match self.rotation {
+ Rotation::Floating(_) => RotationStrategy::Floating,
+ Rotation::Solid(_) => RotationStrategy::Solid,
+ }),
+ Message::RotationStrategyChanged,
+ )
+ .width(Length::Fill),
+ ]
+ .spacing(10)
+ .align_items(Alignment::End);
+
+ let properties = row![
+ with_value(
+ slider(100.0..=500.0, self.width, Message::WidthChanged),
+ format!("Width: {}px", self.width)
+ ),
+ with_value(
+ slider(0.0..=1.0, self.opacity, Message::OpacityChanged)
+ .step(0.01),
+ format!("Opacity: {:.2}", self.opacity)
+ ),
+ with_value(
+ row![
+ slider(
+ Degrees::RANGE,
+ self.rotation.degrees(),
+ Message::RotationChanged
+ ),
+ checkbox("Spin!", self.spin)
+ .text_size(12)
+ .on_toggle(Message::SpinToggled)
+ .size(12)
+ ]
+ .spacing(10)
+ .align_items(Alignment::Center),
+ format!("Rotation: {:.0}°", f32::from(self.rotation.degrees()))
+ )
+ ]
+ .spacing(10)
+ .align_items(Alignment::End);
+
+ container(column![fit, center(i_am_ferris), properties].spacing(10))
+ .padding(10)
+ .into()
+ }
+}
+
+impl Default for Image {
+ fn default() -> Self {
+ Self {
+ width: 300.0,
+ opacity: 1.0,
+ rotation: Rotation::default(),
+ content_fit: ContentFit::default(),
+ spin: false,
+ last_tick: Instant::now(),
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum RotationStrategy {
+ Floating,
+ Solid,
+}
+
+impl std::fmt::Display for RotationStrategy {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(match self {
+ Self::Floating => "Floating",
+ Self::Solid => "Solid",
+ })
+ }
+}
+
+fn with_value<'a>(
+ control: impl Into<Element<'a, Message>>,
+ value: String,
+) -> Element<'a, Message> {
+ column![control.into(), text(value).size(12).line_height(1.0)]
+ .spacing(2)
+ .align_items(Alignment::Center)
+ .into()
+}
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs
index 48574247..8f1f7a54 100644
--- a/examples/game_of_life/src/main.rs
+++ b/examples/game_of_life/src/main.rs
@@ -602,9 +602,7 @@ mod grid {
frame.into_geometry()
};
- if self.scaling < 0.2 || !self.show_lines {
- vec![life, overlay]
- } else {
+ if self.scaling >= 0.2 && self.show_lines {
let grid =
self.grid_cache.draw(renderer, bounds.size(), |frame| {
frame.translate(center);
@@ -641,6 +639,8 @@ mod grid {
});
vec![life, grid, overlay]
+ } else {
+ vec![life, overlay]
}
}
diff --git a/examples/geometry/src/main.rs b/examples/geometry/src/main.rs
index 63efcbdd..3c7969c5 100644
--- a/examples/geometry/src/main.rs
+++ b/examples/geometry/src/main.rs
@@ -6,7 +6,10 @@ mod rainbow {
use iced::advanced::renderer;
use iced::advanced::widget::{self, Widget};
use iced::mouse;
- use iced::{Element, Length, Rectangle, Renderer, Size, Theme, Vector};
+ use iced::{
+ Element, Length, Rectangle, Renderer, Size, Theme, Transformation,
+ Vector,
+ };
#[derive(Debug, Clone, Copy, Default)]
pub struct Rainbow;
@@ -44,7 +47,9 @@ mod rainbow {
cursor: mouse::Cursor,
_viewport: &Rectangle,
) {
- use iced::advanced::graphics::mesh::{self, Mesh, SolidVertex2D};
+ use iced::advanced::graphics::mesh::{
+ self, Mesh, Renderer as _, SolidVertex2D,
+ };
use iced::advanced::Renderer as _;
let bounds = layout.bounds();
@@ -77,7 +82,6 @@ mod rainbow {
let posn_l = [0.0, bounds.height / 2.0];
let mesh = Mesh::Solid {
- size: bounds.size(),
buffers: mesh::Indexed {
vertices: vec![
SolidVertex2D {
@@ -128,6 +132,8 @@ mod rainbow {
0, 8, 1, // L
],
},
+ transformation: Transformation::IDENTITY,
+ clip_bounds: Rectangle::INFINITE,
};
renderer.with_translation(
@@ -170,12 +176,7 @@ fn view(_state: &()) -> Element<'_, ()> {
.spacing(20)
.max_width(500);
- let scrollable =
- scrollable(container(content).width(Length::Fill).center_x());
+ let scrollable = scrollable(container(content).center_x(Length::Fill));
- container(scrollable)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_y()
- .into()
+ container(scrollable).center_y(Length::Fill).into()
}
diff --git a/examples/gradient/src/main.rs b/examples/gradient/src/main.rs
index 22c21cdd..2b906c32 100644
--- a/examples/gradient/src/main.rs
+++ b/examples/gradient/src/main.rs
@@ -60,7 +60,7 @@ impl Gradient {
} = *self;
let gradient_box = container(horizontal_space())
- .style(move |_theme, _status| {
+ .style(move |_theme| {
let gradient = gradient::Linear::new(angle)
.add_stop(0.0, start)
.add_stop(1.0, end);
diff --git a/examples/integration/Cargo.toml b/examples/integration/Cargo.toml
index a4a961f8..7f8feb3f 100644
--- a/examples/integration/Cargo.toml
+++ b/examples/integration/Cargo.toml
@@ -8,7 +8,9 @@ publish = false
[dependencies]
iced_winit.workspace = true
iced_wgpu.workspace = true
+
iced_widget.workspace = true
+iced_widget.features = ["wgpu"]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tracing-subscriber = "0.3"
diff --git a/examples/integration/README.md b/examples/integration/README.md
index aa3a6e94..bac0640c 100644
--- a/examples/integration/README.md
+++ b/examples/integration/README.md
@@ -10,25 +10,8 @@ The __[`main`]__ file contains all the code of the example.
You can run it with `cargo run`:
```
-cargo run --package integration_wgpu
+cargo run --package integration
```
-### How to run this example with WebGL backend
-NOTE: Currently, WebGL backend is still experimental, so expect bugs.
-
-```sh
-# 0. Install prerequisites
-cargo install wasm-bindgen-cli https
-# 1. cd to the current folder
-# 2. Compile wasm module
-cargo build -p integration_wgpu --target wasm32-unknown-unknown
-# 3. Invoke wasm-bindgen
-wasm-bindgen ../../target/wasm32-unknown-unknown/debug/integration_wgpu.wasm --out-dir . --target web --no-typescript
-# 4. run http server
-http
-# 5. Open 127.0.0.1:8000 in browser
-```
-
-
[`main`]: src/main.rs
[`wgpu`]: https://github.com/gfx-rs/wgpu
diff --git a/examples/integration/index.html b/examples/integration/index.html
deleted file mode 100644
index 920bc4a0..00000000
--- a/examples/integration/index.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
- <title>Iced - wgpu + WebGL integration</title>
- </head>
- <body>
- <h1>integration_wgpu</h1>
- <canvas id="iced_canvas"></canvas>
- <script type="module">
- import init from "./integration.js";
- init('./integration_bg.wasm');
- </script>
- <style>
- body {
- width: 100%;
- text-align: center;
- }
- </style>
- </body>
-</html>
diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs
index 9cd801b2..e1c7d62f 100644
--- a/examples/integration/src/main.rs
+++ b/examples/integration/src/main.rs
@@ -5,7 +5,7 @@ use controls::Controls;
use scene::Scene;
use iced_wgpu::graphics::Viewport;
-use iced_wgpu::{wgpu, Backend, Renderer, Settings};
+use iced_wgpu::{wgpu, Engine, Renderer};
use iced_winit::conversion;
use iced_winit::core::mouse;
use iced_winit::core::renderer;
@@ -18,309 +18,342 @@ use iced_winit::winit;
use iced_winit::Clipboard;
use winit::{
- event::{Event, WindowEvent},
+ event::WindowEvent,
event_loop::{ControlFlow, EventLoop},
keyboard::ModifiersState,
};
use std::sync::Arc;
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::JsCast;
-#[cfg(target_arch = "wasm32")]
-use web_sys::HtmlCanvasElement;
-#[cfg(target_arch = "wasm32")]
-use winit::platform::web::WindowBuilderExtWebSys;
-
-pub fn main() -> Result<(), Box<dyn std::error::Error>> {
- #[cfg(target_arch = "wasm32")]
- let canvas_element = {
- console_log::init().expect("Initialize logger");
-
- std::panic::set_hook(Box::new(console_error_panic_hook::hook));
-
- web_sys::window()
- .and_then(|win| win.document())
- .and_then(|doc| doc.get_element_by_id("iced_canvas"))
- .and_then(|element| element.dyn_into::<HtmlCanvasElement>().ok())
- .expect("Get canvas element")
- };
-
- #[cfg(not(target_arch = "wasm32"))]
+pub fn main() -> Result<(), winit::error::EventLoopError> {
tracing_subscriber::fmt::init();
// Initialize winit
let event_loop = EventLoop::new()?;
- #[cfg(target_arch = "wasm32")]
- let window = winit::window::WindowBuilder::new()
- .with_canvas(Some(canvas_element))
- .build(&event_loop)?;
-
- #[cfg(not(target_arch = "wasm32"))]
- let window = winit::window::Window::new(&event_loop)?;
-
- let window = Arc::new(window);
-
- let physical_size = window.inner_size();
- let mut viewport = Viewport::with_physical_size(
- Size::new(physical_size.width, physical_size.height),
- window.scale_factor(),
- );
- let mut cursor_position = None;
- let mut modifiers = ModifiersState::default();
- let mut clipboard = Clipboard::connect(&window);
-
- // Initialize wgpu
- #[cfg(target_arch = "wasm32")]
- let default_backend = wgpu::Backends::GL;
- #[cfg(not(target_arch = "wasm32"))]
- let default_backend = wgpu::Backends::PRIMARY;
-
- let backend =
- wgpu::util::backend_bits_from_env().unwrap_or(default_backend);
-
- let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
- backends: backend,
- ..Default::default()
- });
- let surface = instance.create_surface(window.clone())?;
-
- let (format, adapter, device, queue) =
- futures::futures::executor::block_on(async {
- let adapter = wgpu::util::initialize_adapter_from_env_or_default(
- &instance,
- Some(&surface),
- )
- .await
- .expect("Create adapter");
-
- let adapter_features = adapter.features();
-
- #[cfg(target_arch = "wasm32")]
- let needed_limits = wgpu::Limits::downlevel_webgl2_defaults()
- .using_resolution(adapter.limits());
-
- #[cfg(not(target_arch = "wasm32"))]
- let needed_limits = wgpu::Limits::default();
-
- let capabilities = surface.get_capabilities(&adapter);
-
- let (device, queue) = adapter
- .request_device(
- &wgpu::DeviceDescriptor {
- label: None,
- required_features: adapter_features
- & wgpu::Features::default(),
- required_limits: needed_limits,
- },
- None,
- )
- .await
- .expect("Request device");
-
- (
- capabilities
- .formats
- .iter()
- .copied()
- .find(wgpu::TextureFormat::is_srgb)
- .or_else(|| capabilities.formats.first().copied())
- .expect("Get preferred format"),
- adapter,
- device,
- queue,
- )
- });
-
- surface.configure(
- &device,
- &wgpu::SurfaceConfiguration {
- usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
- format,
- width: physical_size.width,
- height: physical_size.height,
- present_mode: wgpu::PresentMode::AutoVsync,
- alpha_mode: wgpu::CompositeAlphaMode::Auto,
- view_formats: vec![],
- desired_maximum_frame_latency: 2,
+ #[allow(clippy::large_enum_variant)]
+ enum Runner {
+ Loading,
+ Ready {
+ window: Arc<winit::window::Window>,
+ device: wgpu::Device,
+ queue: wgpu::Queue,
+ surface: wgpu::Surface<'static>,
+ format: wgpu::TextureFormat,
+ engine: Engine,
+ renderer: Renderer,
+ scene: Scene,
+ state: program::State<Controls>,
+ cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,
+ clipboard: Clipboard,
+ viewport: Viewport,
+ modifiers: ModifiersState,
+ resized: bool,
+ debug: Debug,
},
- );
-
- let mut resized = false;
-
- // Initialize scene and GUI controls
- let scene = Scene::new(&device, format);
- let controls = Controls::new();
-
- // Initialize iced
- let mut debug = Debug::new();
- let mut renderer = Renderer::new(
- Backend::new(&adapter, &device, &queue, Settings::default(), format),
- Font::default(),
- Pixels(16.0),
- );
-
- let mut state = program::State::new(
- controls,
- viewport.logical_size(),
- &mut renderer,
- &mut debug,
- );
-
- // Run event loop
- event_loop.run(move |event, window_target| {
- // You should change this if you want to render continuously
- window_target.set_control_flow(ControlFlow::Wait);
-
- match event {
- Event::WindowEvent {
- event: WindowEvent::RedrawRequested,
- ..
- } => {
- if resized {
- let size = window.inner_size();
-
- viewport = Viewport::with_physical_size(
- Size::new(size.width, size.height),
- window.scale_factor(),
- );
-
- surface.configure(
- &device,
- &wgpu::SurfaceConfiguration {
- format,
- usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
- width: size.width,
- height: size.height,
- present_mode: wgpu::PresentMode::AutoVsync,
- alpha_mode: wgpu::CompositeAlphaMode::Auto,
- view_formats: vec![],
- desired_maximum_frame_latency: 2,
- },
- );
+ }
+
+ impl winit::application::ApplicationHandler for Runner {
+ fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
+ if let Self::Loading = self {
+ let window = Arc::new(
+ event_loop
+ .create_window(
+ winit::window::WindowAttributes::default(),
+ )
+ .expect("Create window"),
+ );
+
+ let physical_size = window.inner_size();
+ let viewport = Viewport::with_physical_size(
+ Size::new(physical_size.width, physical_size.height),
+ window.scale_factor(),
+ );
+ let clipboard = Clipboard::connect(&window);
+
+ let backend =
+ wgpu::util::backend_bits_from_env().unwrap_or_default();
+
+ let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
+ backends: backend,
+ ..Default::default()
+ });
+ let surface = instance
+ .create_surface(window.clone())
+ .expect("Create window surface");
+
+ let (format, adapter, device, queue) =
+ futures::futures::executor::block_on(async {
+ let adapter =
+ wgpu::util::initialize_adapter_from_env_or_default(
+ &instance,
+ Some(&surface),
+ )
+ .await
+ .expect("Create adapter");
- resized = false;
- }
+ let adapter_features = adapter.features();
- match surface.get_current_texture() {
- Ok(frame) => {
- let mut encoder = device.create_command_encoder(
- &wgpu::CommandEncoderDescriptor { label: None },
- );
+ let capabilities = surface.get_capabilities(&adapter);
- let program = state.program();
+ let (device, queue) = adapter
+ .request_device(
+ &wgpu::DeviceDescriptor {
+ label: None,
+ required_features: adapter_features
+ & wgpu::Features::default(),
+ required_limits: wgpu::Limits::default(),
+ },
+ None,
+ )
+ .await
+ .expect("Request device");
+
+ (
+ capabilities
+ .formats
+ .iter()
+ .copied()
+ .find(wgpu::TextureFormat::is_srgb)
+ .or_else(|| {
+ capabilities.formats.first().copied()
+ })
+ .expect("Get preferred format"),
+ adapter,
+ device,
+ queue,
+ )
+ });
+
+ surface.configure(
+ &device,
+ &wgpu::SurfaceConfiguration {
+ usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
+ format,
+ width: physical_size.width,
+ height: physical_size.height,
+ present_mode: wgpu::PresentMode::AutoVsync,
+ alpha_mode: wgpu::CompositeAlphaMode::Auto,
+ view_formats: vec![],
+ desired_maximum_frame_latency: 2,
+ },
+ );
+
+ // Initialize scene and GUI controls
+ let scene = Scene::new(&device, format);
+ let controls = Controls::new();
+
+ // Initialize iced
+ let mut debug = Debug::new();
+ let engine =
+ Engine::new(&adapter, &device, &queue, format, None);
+ let mut renderer = Renderer::new(
+ &device,
+ &engine,
+ Font::default(),
+ Pixels::from(16),
+ );
+
+ let state = program::State::new(
+ controls,
+ viewport.logical_size(),
+ &mut renderer,
+ &mut debug,
+ );
+
+ // You should change this if you want to render continuously
+ event_loop.set_control_flow(ControlFlow::Wait);
+
+ *self = Self::Ready {
+ window,
+ device,
+ queue,
+ surface,
+ format,
+ engine,
+ renderer,
+ scene,
+ state,
+ cursor_position: None,
+ modifiers: ModifiersState::default(),
+ clipboard,
+ viewport,
+ resized: false,
+ debug,
+ };
+ }
+ }
- let view = frame.texture.create_view(
- &wgpu::TextureViewDescriptor::default(),
+ fn window_event(
+ &mut self,
+ event_loop: &winit::event_loop::ActiveEventLoop,
+ _window_id: winit::window::WindowId,
+ event: WindowEvent,
+ ) {
+ let Self::Ready {
+ window,
+ device,
+ queue,
+ surface,
+ format,
+ engine,
+ renderer,
+ scene,
+ state,
+ viewport,
+ cursor_position,
+ modifiers,
+ clipboard,
+ resized,
+ debug,
+ } = self
+ else {
+ return;
+ };
+
+ match event {
+ WindowEvent::RedrawRequested => {
+ if *resized {
+ let size = window.inner_size();
+
+ *viewport = Viewport::with_physical_size(
+ Size::new(size.width, size.height),
+ window.scale_factor(),
);
- {
- // We clear the frame
- let mut render_pass = Scene::clear(
- &view,
- &mut encoder,
- program.background_color(),
+ surface.configure(
+ device,
+ &wgpu::SurfaceConfiguration {
+ format: *format,
+ usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
+ width: size.width,
+ height: size.height,
+ present_mode: wgpu::PresentMode::AutoVsync,
+ alpha_mode: wgpu::CompositeAlphaMode::Auto,
+ view_formats: vec![],
+ desired_maximum_frame_latency: 2,
+ },
+ );
+
+ *resized = false;
+ }
+
+ match surface.get_current_texture() {
+ Ok(frame) => {
+ let mut encoder = device.create_command_encoder(
+ &wgpu::CommandEncoderDescriptor { label: None },
);
- // Draw the scene
- scene.draw(&mut render_pass);
- }
+ let program = state.program();
+
+ let view = frame.texture.create_view(
+ &wgpu::TextureViewDescriptor::default(),
+ );
- // And then iced on top
- renderer.with_primitives(|backend, primitive| {
- backend.present(
- &device,
- &queue,
+ {
+ // We clear the frame
+ let mut render_pass = Scene::clear(
+ &view,
+ &mut encoder,
+ program.background_color(),
+ );
+
+ // Draw the scene
+ scene.draw(&mut render_pass);
+ }
+
+ // And then iced on top
+ renderer.present(
+ engine,
+ device,
+ queue,
&mut encoder,
None,
frame.texture.format(),
&view,
- primitive,
- &viewport,
+ viewport,
&debug.overlay(),
);
- });
- // Then we submit the work
- queue.submit(Some(encoder.finish()));
- frame.present();
+ // Then we submit the work
+ engine.submit(queue, encoder);
+ frame.present();
- // Update the mouse cursor
- window.set_cursor_icon(
- iced_winit::conversion::mouse_interaction(
- state.mouse_interaction(),
- ),
- );
- }
- Err(error) => match error {
- wgpu::SurfaceError::OutOfMemory => {
- panic!(
- "Swapchain error: {error}. \
- Rendering cannot continue."
- )
- }
- _ => {
- // Try rendering again next frame.
- window.request_redraw();
+ // Update the mouse cursor
+ window.set_cursor(
+ iced_winit::conversion::mouse_interaction(
+ state.mouse_interaction(),
+ ),
+ );
}
- },
- }
- }
- Event::WindowEvent { event, .. } => {
- match event {
- WindowEvent::CursorMoved { position, .. } => {
- cursor_position = Some(position);
- }
- WindowEvent::ModifiersChanged(new_modifiers) => {
- modifiers = new_modifiers.state();
- }
- WindowEvent::Resized(_) => {
- resized = true;
- }
- WindowEvent::CloseRequested => {
- window_target.exit();
+ Err(error) => match error {
+ wgpu::SurfaceError::OutOfMemory => {
+ panic!(
+ "Swapchain error: {error}. \
+ Rendering cannot continue."
+ )
+ }
+ _ => {
+ // Try rendering again next frame.
+ window.request_redraw();
+ }
+ },
}
- _ => {}
}
-
- // Map window event to iced event
- if let Some(event) = iced_winit::conversion::window_event(
- window::Id::MAIN,
- event,
- window.scale_factor(),
- modifiers,
- ) {
- state.queue_event(event);
+ WindowEvent::CursorMoved { position, .. } => {
+ *cursor_position = Some(position);
+ }
+ WindowEvent::ModifiersChanged(new_modifiers) => {
+ *modifiers = new_modifiers.state();
}
+ WindowEvent::Resized(_) => {
+ *resized = true;
+ }
+ WindowEvent::CloseRequested => {
+ event_loop.exit();
+ }
+ _ => {}
}
- _ => {}
- }
- // If there are events pending
- if !state.is_queue_empty() {
- // We update iced
- let _ = state.update(
- viewport.logical_size(),
- cursor_position
- .map(|p| {
- conversion::cursor_position(p, viewport.scale_factor())
- })
- .map(mouse::Cursor::Available)
- .unwrap_or(mouse::Cursor::Unavailable),
- &mut renderer,
- &Theme::Dark,
- &renderer::Style {
- text_color: Color::WHITE,
- },
- &mut clipboard,
- &mut debug,
- );
-
- // and request a redraw
- window.request_redraw();
+ // Map window event to iced event
+ if let Some(event) = iced_winit::conversion::window_event(
+ window::Id::MAIN,
+ event,
+ window.scale_factor(),
+ *modifiers,
+ ) {
+ state.queue_event(event);
+ }
+
+ // If there are events pending
+ if !state.is_queue_empty() {
+ // We update iced
+ let _ = state.update(
+ viewport.logical_size(),
+ cursor_position
+ .map(|p| {
+ conversion::cursor_position(
+ p,
+ viewport.scale_factor(),
+ )
+ })
+ .map(mouse::Cursor::Available)
+ .unwrap_or(mouse::Cursor::Unavailable),
+ renderer,
+ &Theme::Dark,
+ &renderer::Style {
+ text_color: Color::WHITE,
+ },
+ clipboard,
+ debug,
+ );
+
+ // and request a redraw
+ window.request_redraw();
+ }
}
- })?;
+ }
- Ok(())
+ let mut runner = Runner::Loading;
+ event_loop.run_app(&mut runner)
}
diff --git a/examples/layout/src/main.rs b/examples/layout/src/main.rs
index 713e2b70..c40ac820 100644
--- a/examples/layout/src/main.rs
+++ b/examples/layout/src/main.rs
@@ -1,8 +1,8 @@
use iced::keyboard;
use iced::mouse;
use iced::widget::{
- button, canvas, checkbox, column, container, horizontal_space, pick_list,
- row, scrollable, text,
+ button, canvas, center, checkbox, column, container, horizontal_space,
+ pick_list, row, scrollable, text,
};
use iced::{
color, Alignment, Element, Font, Length, Point, Rectangle, Renderer,
@@ -76,22 +76,18 @@ impl Layout {
.spacing(20)
.align_items(Alignment::Center);
- let example = container(if self.explain {
+ let example = center(if self.explain {
self.example.view().explain(color!(0x0000ff))
} else {
self.example.view()
})
- .style(|theme, _status| {
+ .style(|theme| {
let palette = theme.extended_palette();
- container::Appearance::default()
+ container::Style::default()
.with_border(palette.background.strong.color, 4.0)
})
- .padding(4)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y();
+ .padding(4);
let controls = row([
(!self.example.is_first()).then_some(
@@ -195,12 +191,7 @@ impl Default for Example {
}
fn centered<'a>() -> Element<'a, Message> {
- container(text("I am centered!").size(50))
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(text("I am centered!").size(50)).into()
}
fn column_<'a>() -> Element<'a, Message> {
@@ -245,10 +236,10 @@ fn application<'a>() -> Element<'a, Message> {
.padding(10)
.align_items(Alignment::Center),
)
- .style(|theme, _status| {
+ .style(|theme| {
let palette = theme.extended_palette();
- container::Appearance::default()
+ container::Style::default()
.with_border(palette.background.strong.color, 1)
});
@@ -260,8 +251,7 @@ fn application<'a>() -> Element<'a, Message> {
.align_items(Alignment::Center),
)
.style(container::rounded_box)
- .height(Length::Fill)
- .center_y();
+ .center_y(Length::Fill);
let content = container(
scrollable(
diff --git a/examples/lazy/src/main.rs b/examples/lazy/src/main.rs
index 627aba23..f24c0d62 100644
--- a/examples/lazy/src/main.rs
+++ b/examples/lazy/src/main.rs
@@ -173,7 +173,7 @@ impl App {
.style(button::danger);
row![
- text(&item.name).color(item.color),
+ text(item.name.clone()).color(item.color),
horizontal_space(),
pick_list(Color::ALL, Some(item.color), move |color| {
Message::ItemColorChanged(item.clone(), color)
diff --git a/examples/loading_spinners/src/circular.rs b/examples/loading_spinners/src/circular.rs
index 12670ed1..de728af2 100644
--- a/examples/loading_spinners/src/circular.rs
+++ b/examples/loading_spinners/src/circular.rs
@@ -358,7 +358,7 @@ where
|renderer| {
use iced::advanced::graphics::geometry::Renderer as _;
- renderer.draw(vec![geometry]);
+ renderer.draw_geometry(geometry);
},
);
}
diff --git a/examples/loading_spinners/src/main.rs b/examples/loading_spinners/src/main.rs
index 2b2abad5..a63c51d4 100644
--- a/examples/loading_spinners/src/main.rs
+++ b/examples/loading_spinners/src/main.rs
@@ -1,5 +1,5 @@
-use iced::widget::{column, container, row, slider, text};
-use iced::{Element, Length};
+use iced::widget::{center, column, row, slider, text};
+use iced::Element;
use std::time::Duration;
@@ -73,7 +73,7 @@ impl LoadingSpinners {
})
.spacing(20);
- container(
+ center(
column.push(
row![
text("Cycle duration:"),
@@ -87,10 +87,6 @@ impl LoadingSpinners {
.spacing(20.0),
),
)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
.into()
}
}
diff --git a/examples/loupe/src/main.rs b/examples/loupe/src/main.rs
index 6a5ff123..c4d3b449 100644
--- a/examples/loupe/src/main.rs
+++ b/examples/loupe/src/main.rs
@@ -1,5 +1,5 @@
-use iced::widget::{button, column, container, text};
-use iced::{Alignment, Element, Length};
+use iced::widget::{button, center, column, text};
+use iced::{Alignment, Element};
use loupe::loupe;
@@ -31,7 +31,7 @@ impl Loupe {
}
fn view(&self) -> Element<Message> {
- container(loupe(
+ center(loupe(
3.0,
column![
button("Increment").on_press(Message::Increment),
@@ -41,10 +41,6 @@ impl Loupe {
.padding(20)
.align_items(Alignment::Center),
))
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
.into()
}
}
@@ -159,7 +155,7 @@ mod loupe {
if cursor.is_over(layout.bounds()) {
mouse::Interaction::ZoomIn
} else {
- mouse::Interaction::Idle
+ mouse::Interaction::None
}
}
}
diff --git a/examples/modal/src/main.rs b/examples/modal/src/main.rs
index 398728e0..a012c310 100644
--- a/examples/modal/src/main.rs
+++ b/examples/modal/src/main.rs
@@ -2,12 +2,11 @@ use iced::event::{self, Event};
use iced::keyboard;
use iced::keyboard::key;
use iced::widget::{
- self, button, column, container, horizontal_space, pick_list, row, text,
- text_input,
+ self, button, center, column, container, horizontal_space, mouse_area,
+ opaque, pick_list, row, stack, text, text_input,
};
-use iced::{Alignment, Command, Element, Length, Subscription};
+use iced::{Alignment, Color, Command, Element, Length, Subscription};
-use modal::Modal;
use std::fmt;
pub fn main() -> iced::Result {
@@ -99,13 +98,7 @@ impl App {
row![text("Top Left"), horizontal_space(), text("Top Right")]
.align_items(Alignment::Start)
.height(Length::Fill),
- container(
- button(text("Show Modal")).on_press(Message::ShowModal)
- )
- .center_x()
- .center_y()
- .width(Length::Fill)
- .height(Length::Fill),
+ center(button(text("Show Modal")).on_press(Message::ShowModal)),
row![
text("Bottom Left"),
horizontal_space(),
@@ -116,12 +109,10 @@ impl App {
]
.height(Length::Fill),
)
- .padding(10)
- .width(Length::Fill)
- .height(Length::Fill);
+ .padding(10);
if self.show_modal {
- let modal = container(
+ let signup = container(
column![
text("Sign Up").size(24),
column![
@@ -162,9 +153,7 @@ impl App {
.padding(10)
.style(container::rounded_box);
- Modal::new(content, modal)
- .on_blur(Message::HideModal)
- .into()
+ modal(content, signup, Message::HideModal)
} else {
content.into()
}
@@ -203,326 +192,29 @@ impl fmt::Display for Plan {
}
}
-mod modal {
- use iced::advanced::layout::{self, Layout};
- use iced::advanced::overlay;
- use iced::advanced::renderer;
- use iced::advanced::widget::{self, Widget};
- use iced::advanced::{self, Clipboard, Shell};
- use iced::alignment::Alignment;
- use iced::event;
- use iced::mouse;
- use iced::{Color, Element, Event, Length, Point, Rectangle, Size, Vector};
-
- /// A widget that centers a modal element over some base element
- pub struct Modal<'a, Message, Theme, Renderer> {
- base: Element<'a, Message, Theme, Renderer>,
- modal: Element<'a, Message, Theme, Renderer>,
- on_blur: Option<Message>,
- }
-
- impl<'a, Message, Theme, Renderer> Modal<'a, Message, Theme, Renderer> {
- /// Returns a new [`Modal`]
- pub fn new(
- base: impl Into<Element<'a, Message, Theme, Renderer>>,
- modal: impl Into<Element<'a, Message, Theme, Renderer>>,
- ) -> Self {
- Self {
- base: base.into(),
- modal: modal.into(),
- on_blur: None,
- }
- }
-
- /// Sets the message that will be produces when the background
- /// of the [`Modal`] is pressed
- pub fn on_blur(self, on_blur: Message) -> Self {
- Self {
- on_blur: Some(on_blur),
- ..self
- }
- }
- }
-
- impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
- for Modal<'a, Message, Theme, Renderer>
- where
- Renderer: advanced::Renderer,
- Message: Clone,
- {
- fn children(&self) -> Vec<widget::Tree> {
- vec![
- widget::Tree::new(&self.base),
- widget::Tree::new(&self.modal),
- ]
- }
-
- fn diff(&self, tree: &mut widget::Tree) {
- tree.diff_children(&[&self.base, &self.modal]);
- }
-
- fn size(&self) -> Size<Length> {
- self.base.as_widget().size()
- }
-
- fn layout(
- &self,
- tree: &mut widget::Tree,
- renderer: &Renderer,
- limits: &layout::Limits,
- ) -> layout::Node {
- self.base.as_widget().layout(
- &mut tree.children[0],
- renderer,
- limits,
- )
- }
-
- fn on_event(
- &mut self,
- state: &mut widget::Tree,
- event: Event,
- layout: Layout<'_>,
- cursor: mouse::Cursor,
- renderer: &Renderer,
- clipboard: &mut dyn Clipboard,
- shell: &mut Shell<'_, Message>,
- viewport: &Rectangle,
- ) -> event::Status {
- self.base.as_widget_mut().on_event(
- &mut state.children[0],
- event,
- layout,
- cursor,
- renderer,
- clipboard,
- shell,
- viewport,
- )
- }
-
- fn draw(
- &self,
- state: &widget::Tree,
- renderer: &mut Renderer,
- theme: &Theme,
- style: &renderer::Style,
- layout: Layout<'_>,
- cursor: mouse::Cursor,
- viewport: &Rectangle,
- ) {
- self.base.as_widget().draw(
- &state.children[0],
- renderer,
- theme,
- style,
- layout,
- cursor,
- viewport,
- );
- }
-
- fn overlay<'b>(
- &'b mut self,
- state: &'b mut widget::Tree,
- layout: Layout<'_>,
- _renderer: &Renderer,
- translation: Vector,
- ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
- Some(overlay::Element::new(Box::new(Overlay {
- position: layout.position() + translation,
- content: &mut self.modal,
- tree: &mut state.children[1],
- size: layout.bounds().size(),
- on_blur: self.on_blur.clone(),
- })))
- }
-
- fn mouse_interaction(
- &self,
- state: &widget::Tree,
- layout: Layout<'_>,
- cursor: mouse::Cursor,
- viewport: &Rectangle,
- renderer: &Renderer,
- ) -> mouse::Interaction {
- self.base.as_widget().mouse_interaction(
- &state.children[0],
- layout,
- cursor,
- viewport,
- renderer,
- )
- }
-
- fn operate(
- &self,
- state: &mut widget::Tree,
- layout: Layout<'_>,
- renderer: &Renderer,
- operation: &mut dyn widget::Operation<Message>,
- ) {
- self.base.as_widget().operate(
- &mut state.children[0],
- layout,
- renderer,
- operation,
- );
- }
- }
-
- struct Overlay<'a, 'b, Message, Theme, Renderer> {
- position: Point,
- content: &'b mut Element<'a, Message, Theme, Renderer>,
- tree: &'b mut widget::Tree,
- size: Size,
- on_blur: Option<Message>,
- }
-
- impl<'a, 'b, Message, Theme, Renderer>
- overlay::Overlay<Message, Theme, Renderer>
- for Overlay<'a, 'b, Message, Theme, Renderer>
- where
- Renderer: advanced::Renderer,
- Message: Clone,
- {
- fn layout(
- &mut self,
- renderer: &Renderer,
- _bounds: Size,
- ) -> layout::Node {
- let limits = layout::Limits::new(Size::ZERO, self.size)
- .width(Length::Fill)
- .height(Length::Fill);
-
- let child = self
- .content
- .as_widget()
- .layout(self.tree, renderer, &limits)
- .align(Alignment::Center, Alignment::Center, limits.max());
-
- layout::Node::with_children(self.size, vec![child])
- .move_to(self.position)
- }
-
- fn on_event(
- &mut self,
- event: Event,
- layout: Layout<'_>,
- cursor: mouse::Cursor,
- renderer: &Renderer,
- clipboard: &mut dyn Clipboard,
- shell: &mut Shell<'_, Message>,
- ) -> event::Status {
- let content_bounds = layout.children().next().unwrap().bounds();
-
- if let Some(message) = self.on_blur.as_ref() {
- if let Event::Mouse(mouse::Event::ButtonPressed(
- mouse::Button::Left,
- )) = &event
- {
- if !cursor.is_over(content_bounds) {
- shell.publish(message.clone());
- return event::Status::Captured;
+fn modal<'a, Message>(
+ base: impl Into<Element<'a, Message>>,
+ content: impl Into<Element<'a, Message>>,
+ on_blur: Message,
+) -> Element<'a, Message>
+where
+ Message: Clone + 'a,
+{
+ stack![
+ base.into(),
+ mouse_area(center(opaque(content)).style(|_theme| {
+ container::Style {
+ background: Some(
+ Color {
+ a: 0.8,
+ ..Color::BLACK
}
- }
+ .into(),
+ ),
+ ..container::Style::default()
}
-
- self.content.as_widget_mut().on_event(
- self.tree,
- event,
- layout.children().next().unwrap(),
- cursor,
- renderer,
- clipboard,
- shell,
- &layout.bounds(),
- )
- }
-
- fn draw(
- &self,
- renderer: &mut Renderer,
- theme: &Theme,
- style: &renderer::Style,
- layout: Layout<'_>,
- cursor: mouse::Cursor,
- ) {
- renderer.fill_quad(
- renderer::Quad {
- bounds: layout.bounds(),
- ..renderer::Quad::default()
- },
- Color {
- a: 0.80,
- ..Color::BLACK
- },
- );
-
- self.content.as_widget().draw(
- self.tree,
- renderer,
- theme,
- style,
- layout.children().next().unwrap(),
- cursor,
- &layout.bounds(),
- );
- }
-
- fn operate(
- &mut self,
- layout: Layout<'_>,
- renderer: &Renderer,
- operation: &mut dyn widget::Operation<Message>,
- ) {
- self.content.as_widget().operate(
- self.tree,
- layout.children().next().unwrap(),
- renderer,
- operation,
- );
- }
-
- fn mouse_interaction(
- &self,
- layout: Layout<'_>,
- cursor: mouse::Cursor,
- viewport: &Rectangle,
- renderer: &Renderer,
- ) -> mouse::Interaction {
- self.content.as_widget().mouse_interaction(
- self.tree,
- layout.children().next().unwrap(),
- cursor,
- viewport,
- renderer,
- )
- }
-
- fn overlay<'c>(
- &'c mut self,
- layout: Layout<'_>,
- renderer: &Renderer,
- ) -> Option<overlay::Element<'c, Message, Theme, Renderer>> {
- self.content.as_widget_mut().overlay(
- self.tree,
- layout.children().next().unwrap(),
- renderer,
- Vector::ZERO,
- )
- }
- }
-
- impl<'a, Message, Theme, Renderer> From<Modal<'a, Message, Theme, Renderer>>
- for Element<'a, Message, Theme, Renderer>
- where
- Theme: 'a,
- Message: 'a + Clone,
- Renderer: 'a + advanced::Renderer,
- {
- fn from(modal: Modal<'a, Message, Theme, Renderer>) -> Self {
- Element::new(modal)
- }
- }
+ }))
+ .on_press(on_blur)
+ ]
+ .into()
}
diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs
index 5a5e70c1..31c2e4f6 100644
--- a/examples/multi_window/src/main.rs
+++ b/examples/multi_window/src/main.rs
@@ -1,7 +1,9 @@
use iced::event;
use iced::executor;
use iced::multi_window::{self, Application};
-use iced::widget::{button, column, container, scrollable, text, text_input};
+use iced::widget::{
+ button, center, column, container, scrollable, text, text_input,
+};
use iced::window;
use iced::{
Alignment, Command, Element, Length, Point, Settings, Subscription, Theme,
@@ -128,12 +130,7 @@ impl multi_window::Application for Example {
fn view(&self, window: window::Id) -> Element<Message> {
let content = self.windows.get(&window).unwrap().view(window);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(content).into()
}
fn theme(&self, window: window::Id) -> Self::Theme {
@@ -210,6 +207,6 @@ impl Window {
.align_items(Alignment::Center),
);
- container(content).width(200).center_x().into()
+ container(content).center_x(200).into()
}
}
diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs
index 9e78ad0b..6b5bd332 100644
--- a/examples/pane_grid/src/main.rs
+++ b/examples/pane_grid/src/main.rs
@@ -290,10 +290,8 @@ fn view_content<'a>(
.align_items(Alignment::Center);
container(scrollable(content))
- .width(Length::Fill)
- .height(Length::Fill)
+ .center_y(Length::Fill)
.padding(5)
- .center_y()
.into()
}
@@ -336,39 +334,30 @@ mod style {
use iced::widget::container;
use iced::{Border, Theme};
- pub fn title_bar_active(
- theme: &Theme,
- _status: container::Status,
- ) -> container::Appearance {
+ pub fn title_bar_active(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
- container::Appearance {
+ container::Style {
text_color: Some(palette.background.strong.text),
background: Some(palette.background.strong.color.into()),
..Default::default()
}
}
- pub fn title_bar_focused(
- theme: &Theme,
- _status: container::Status,
- ) -> container::Appearance {
+ pub fn title_bar_focused(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
- container::Appearance {
+ container::Style {
text_color: Some(palette.primary.strong.text),
background: Some(palette.primary.strong.color.into()),
..Default::default()
}
}
- pub fn pane_active(
- theme: &Theme,
- _status: container::Status,
- ) -> container::Appearance {
+ pub fn pane_active(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
- container::Appearance {
+ container::Style {
background: Some(palette.background.weak.color.into()),
border: Border {
width: 2.0,
@@ -379,13 +368,10 @@ mod style {
}
}
- pub fn pane_focused(
- theme: &Theme,
- _status: container::Status,
- ) -> container::Appearance {
+ pub fn pane_focused(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
- container::Appearance {
+ container::Style {
background: Some(palette.background.weak.color.into()),
border: Border {
width: 2.0,
diff --git a/examples/pokedex/src/main.rs b/examples/pokedex/src/main.rs
index 6ba6fe66..cffa3727 100644
--- a/examples/pokedex/src/main.rs
+++ b/examples/pokedex/src/main.rs
@@ -1,5 +1,5 @@
use iced::futures;
-use iced::widget::{self, column, container, image, row, text};
+use iced::widget::{self, center, column, image, row, text};
use iced::{Alignment, Command, Element, Length};
pub fn main() -> iced::Result {
@@ -83,12 +83,7 @@ impl Pokedex {
.align_items(Alignment::End),
};
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(content).into()
}
}
@@ -186,7 +181,7 @@ impl Pokemon {
{
let bytes = reqwest::get(&url).await?.bytes().await?;
- Ok(image::Handle::from_memory(bytes))
+ Ok(image::Handle::from_bytes(bytes))
}
#[cfg(target_arch = "wasm32")]
diff --git a/examples/qr_code/src/main.rs b/examples/qr_code/src/main.rs
index b93adf04..c6a90458 100644
--- a/examples/qr_code/src/main.rs
+++ b/examples/qr_code/src/main.rs
@@ -1,7 +1,5 @@
-use iced::widget::{
- column, container, pick_list, qr_code, row, text, text_input,
-};
-use iced::{Alignment, Element, Length, Theme};
+use iced::widget::{center, column, pick_list, qr_code, row, text, text_input};
+use iced::{Alignment, Element, Theme};
pub fn main() -> iced::Result {
iced::program(
@@ -72,13 +70,7 @@ impl QRGenerator {
.spacing(20)
.align_items(Alignment::Center);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .padding(20)
- .center_x()
- .center_y()
- .into()
+ center(content).padding(20).into()
}
fn theme(&self) -> Theme {
diff --git a/examples/screenshot/src/main.rs b/examples/screenshot/src/main.rs
index c73d8dfd..fb19e556 100644
--- a/examples/screenshot/src/main.rs
+++ b/examples/screenshot/src/main.rs
@@ -109,7 +109,7 @@ impl Example {
fn view(&self) -> Element<'_, Message> {
let image: Element<Message> = if let Some(screenshot) = &self.screenshot
{
- image(image::Handle::from_pixels(
+ image(image::Handle::from_rgba(
screenshot.size.width,
screenshot.size.height,
screenshot.clone(),
@@ -123,12 +123,9 @@ impl Example {
};
let image = container(image)
+ .center_y(Length::FillPortion(2))
.padding(10)
- .style(container::rounded_box)
- .width(Length::FillPortion(2))
- .height(Length::Fill)
- .center_x()
- .center_y();
+ .style(container::rounded_box);
let crop_origin_controls = row![
text("X:")
@@ -213,12 +210,7 @@ impl Example {
.spacing(40)
};
- let side_content = container(controls)
- .align_x(alignment::Horizontal::Center)
- .width(Length::FillPortion(1))
- .height(Length::Fill)
- .center_y()
- .center_x();
+ let side_content = container(controls).center_y(Length::Fill);
let content = row![side_content, image]
.spacing(10)
@@ -226,13 +218,7 @@ impl Example {
.height(Length::Fill)
.align_items(Alignment::Center);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .padding(10)
- .center_x()
- .center_y()
- .into()
+ container(content).padding(10).into()
}
fn subscription(&self) -> Subscription<Message> {
diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs
index 240ae908..bbb6497f 100644
--- a/examples/scrollable/src/main.rs
+++ b/examples/scrollable/src/main.rs
@@ -327,7 +327,7 @@ impl ScrollableDemo {
.spacing(10)
.into();
- container(content).padding(20).center_x().center_y().into()
+ container(content).padding(20).into()
}
fn theme(&self) -> Theme {
@@ -341,8 +341,8 @@ impl Default for ScrollableDemo {
}
}
-fn progress_bar_custom_style(theme: &Theme) -> progress_bar::Appearance {
- progress_bar::Appearance {
+fn progress_bar_custom_style(theme: &Theme) -> progress_bar::Style {
+ progress_bar::Style {
background: theme.extended_palette().background.strong.color.into(),
bar: Color::from_rgb8(250, 85, 134).into(),
border: Border::default(),
diff --git a/examples/sierpinski_triangle/src/main.rs b/examples/sierpinski_triangle/src/main.rs
index b805e7d5..7dd7be5e 100644
--- a/examples/sierpinski_triangle/src/main.rs
+++ b/examples/sierpinski_triangle/src/main.rs
@@ -1,6 +1,6 @@
use iced::mouse;
use iced::widget::canvas::event::{self, Event};
-use iced::widget::canvas::{self, Canvas};
+use iced::widget::canvas::{self, Canvas, Geometry};
use iced::widget::{column, row, slider, text};
use iced::{Color, Length, Point, Rectangle, Renderer, Size, Theme};
@@ -111,7 +111,7 @@ impl canvas::Program<Message> for SierpinskiGraph {
_theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor,
- ) -> Vec<canvas::Geometry> {
+ ) -> Vec<Geometry> {
let geom = self.cache.draw(renderer, bounds.size(), |frame| {
frame.stroke(
&canvas::Path::rectangle(Point::ORIGIN, frame.size()),
diff --git a/examples/slider/src/main.rs b/examples/slider/src/main.rs
index b3a47614..0b4c29aa 100644
--- a/examples/slider/src/main.rs
+++ b/examples/slider/src/main.rs
@@ -1,4 +1,4 @@
-use iced::widget::{column, container, slider, text, vertical_slider};
+use iced::widget::{center, column, container, slider, text, vertical_slider};
use iced::{Element, Length};
pub fn main() -> iced::Result {
@@ -54,18 +54,14 @@ impl Slider {
let text = text(self.value);
- container(
+ center(
column![
- container(v_slider).width(Length::Fill).center_x(),
- container(h_slider).width(Length::Fill).center_x(),
- container(text).width(Length::Fill).center_x(),
+ container(v_slider).center_x(Length::Fill),
+ container(h_slider).center_x(Length::Fill),
+ container(text).center_x(Length::Fill)
]
.spacing(25),
)
- .height(Length::Fill)
- .width(Length::Fill)
- .center_x()
- .center_y()
.into()
}
}
diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs
index b5228f09..deb211d8 100644
--- a/examples/solar_system/src/main.rs
+++ b/examples/solar_system/src/main.rs
@@ -10,7 +10,7 @@ use iced::mouse;
use iced::widget::canvas;
use iced::widget::canvas::gradient;
use iced::widget::canvas::stroke::{self, Stroke};
-use iced::widget::canvas::Path;
+use iced::widget::canvas::{Geometry, Path};
use iced::window;
use iced::{
Color, Element, Length, Point, Rectangle, Renderer, Size, Subscription,
@@ -130,7 +130,7 @@ impl<Message> canvas::Program<Message> for State {
_theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor,
- ) -> Vec<canvas::Geometry> {
+ ) -> Vec<Geometry> {
use std::f32::consts::PI;
let background =
diff --git a/examples/stopwatch/src/main.rs b/examples/stopwatch/src/main.rs
index 6bd5ce3e..a8149753 100644
--- a/examples/stopwatch/src/main.rs
+++ b/examples/stopwatch/src/main.rs
@@ -1,8 +1,8 @@
use iced::alignment;
use iced::keyboard;
use iced::time;
-use iced::widget::{button, column, container, row, text};
-use iced::{Alignment, Element, Length, Subscription, Theme};
+use iced::widget::{button, center, column, row, text};
+use iced::{Alignment, Element, Subscription, Theme};
use std::time::{Duration, Instant};
@@ -128,12 +128,7 @@ impl Stopwatch {
.align_items(Alignment::Center)
.spacing(20);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(content).into()
}
fn theme(&self) -> Theme {
diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs
index 73268da0..57e8f47e 100644
--- a/examples/styling/src/main.rs
+++ b/examples/styling/src/main.rs
@@ -1,7 +1,7 @@
use iced::widget::{
- button, checkbox, column, container, horizontal_rule, pick_list,
- progress_bar, row, scrollable, slider, text, text_input, toggler,
- vertical_rule, vertical_space,
+ button, center, checkbox, column, horizontal_rule, pick_list, progress_bar,
+ row, scrollable, slider, text, text_input, toggler, vertical_rule,
+ vertical_space,
};
use iced::{Alignment, Element, Length, Theme};
@@ -106,12 +106,7 @@ impl Styling {
.padding(20)
.max_width(600);
- container(content)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(content).into()
}
fn theme(&self) -> Theme {
diff --git a/examples/svg/src/main.rs b/examples/svg/src/main.rs
index cc686dca..e071c3af 100644
--- a/examples/svg/src/main.rs
+++ b/examples/svg/src/main.rs
@@ -1,4 +1,4 @@
-use iced::widget::{checkbox, column, container, svg};
+use iced::widget::{center, checkbox, column, container, svg};
use iced::{color, Element, Length};
pub fn main() -> iced::Result {
@@ -31,7 +31,7 @@ impl Tiger {
));
let svg = svg(handle).width(Length::Fill).height(Length::Fill).style(
- |_theme, _status| svg::Appearance {
+ |_theme, _status| svg::Style {
color: if self.apply_color_filter {
Some(color!(0x0000ff))
} else {
@@ -44,19 +44,12 @@ impl Tiger {
checkbox("Apply a color filter", self.apply_color_filter)
.on_toggle(Message::ToggleColorFilter);
- container(
- column![
- svg,
- container(apply_color_filter).width(Length::Fill).center_x()
- ]
- .spacing(20)
- .height(Length::Fill),
+ center(
+ column![svg, container(apply_color_filter).center_x(Length::Fill)]
+ .spacing(20)
+ .height(Length::Fill),
)
- .width(Length::Fill)
- .height(Length::Fill)
.padding(20)
- .center_x()
- .center_y()
.into()
}
}
diff --git a/examples/system_information/src/main.rs b/examples/system_information/src/main.rs
index cae764dc..8ce12e1c 100644
--- a/examples/system_information/src/main.rs
+++ b/examples/system_information/src/main.rs
@@ -1,5 +1,5 @@
-use iced::widget::{button, column, container, text};
-use iced::{system, Command, Element, Length};
+use iced::widget::{button, center, column, text};
+use iced::{system, Command, Element};
pub fn main() -> iced::Result {
iced::program("System Information - Iced", Example::update, Example::view)
@@ -132,11 +132,6 @@ impl Example {
}
};
- container(content)
- .center_x()
- .center_y()
- .width(Length::Fill)
- .height(Length::Fill)
- .into()
+ center(content).into()
}
}
diff --git a/examples/the_matrix/Cargo.toml b/examples/the_matrix/Cargo.toml
new file mode 100644
index 00000000..775e76e0
--- /dev/null
+++ b/examples/the_matrix/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "the_matrix"
+version = "0.1.0"
+authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
+edition = "2021"
+publish = false
+
+[dependencies]
+iced.workspace = true
+iced.features = ["canvas", "tokio", "debug"]
+
+rand = "0.8"
+tracing-subscriber = "0.3"
diff --git a/examples/the_matrix/src/main.rs b/examples/the_matrix/src/main.rs
new file mode 100644
index 00000000..f3a67ac8
--- /dev/null
+++ b/examples/the_matrix/src/main.rs
@@ -0,0 +1,115 @@
+use iced::mouse;
+use iced::time::{self, Instant};
+use iced::widget::canvas;
+use iced::{
+ Color, Element, Font, Length, Point, Rectangle, Renderer, Subscription,
+ Theme,
+};
+
+use std::cell::RefCell;
+
+pub fn main() -> iced::Result {
+ tracing_subscriber::fmt::init();
+
+ iced::program("The Matrix - Iced", TheMatrix::update, TheMatrix::view)
+ .subscription(TheMatrix::subscription)
+ .antialiasing(true)
+ .run()
+}
+
+#[derive(Default)]
+struct TheMatrix {
+ tick: usize,
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Message {
+ Tick(Instant),
+}
+
+impl TheMatrix {
+ fn update(&mut self, message: Message) {
+ match message {
+ Message::Tick(_now) => {
+ self.tick += 1;
+ }
+ }
+ }
+
+ fn view(&self) -> Element<Message> {
+ canvas(self as &Self)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .into()
+ }
+
+ fn subscription(&self) -> Subscription<Message> {
+ time::every(std::time::Duration::from_millis(50)).map(Message::Tick)
+ }
+}
+
+impl<Message> canvas::Program<Message> for TheMatrix {
+ type State = RefCell<Vec<canvas::Cache>>;
+
+ fn draw(
+ &self,
+ state: &Self::State,
+ renderer: &Renderer,
+ _theme: &Theme,
+ bounds: Rectangle,
+ _cursor: mouse::Cursor,
+ ) -> Vec<canvas::Geometry> {
+ use rand::distributions::Distribution;
+ use rand::Rng;
+
+ const CELL_SIZE: f32 = 10.0;
+
+ let mut caches = state.borrow_mut();
+
+ if caches.is_empty() {
+ let group = canvas::Group::unique();
+
+ caches.resize_with(30, || canvas::Cache::with_group(group));
+ }
+
+ vec![caches[self.tick % caches.len()].draw(
+ renderer,
+ bounds.size(),
+ |frame| {
+ frame.fill_rectangle(Point::ORIGIN, frame.size(), Color::BLACK);
+
+ let mut rng = rand::thread_rng();
+ let rows = (frame.height() / CELL_SIZE).ceil() as usize;
+ let columns = (frame.width() / CELL_SIZE).ceil() as usize;
+
+ for row in 0..rows {
+ for column in 0..columns {
+ let position = Point::new(
+ column as f32 * CELL_SIZE,
+ row as f32 * CELL_SIZE,
+ );
+
+ let alphas = [0.05, 0.1, 0.2, 0.5];
+ let weights = [10, 4, 2, 1];
+ let distribution =
+ rand::distributions::WeightedIndex::new(weights)
+ .expect("Create distribution");
+
+ frame.fill_text(canvas::Text {
+ content: rng.gen_range('!'..'z').to_string(),
+ position,
+ color: Color {
+ a: alphas[distribution.sample(&mut rng)],
+ g: 1.0,
+ ..Color::BLACK
+ },
+ size: CELL_SIZE.into(),
+ font: Font::MONOSPACE,
+ ..canvas::Text::default()
+ });
+ }
+ }
+ },
+ )]
+ }
+}
diff --git a/examples/toast/src/main.rs b/examples/toast/src/main.rs
index 4916ceb6..355c40b8 100644
--- a/examples/toast/src/main.rs
+++ b/examples/toast/src/main.rs
@@ -2,7 +2,7 @@ use iced::event::{self, Event};
use iced::keyboard;
use iced::keyboard::key;
use iced::widget::{
- self, button, column, container, pick_list, row, slider, text, text_input,
+ self, button, center, column, pick_list, row, slider, text, text_input,
};
use iced::{Alignment, Command, Element, Length, Subscription};
@@ -102,7 +102,7 @@ impl App {
.then_some(Message::Add),
);
- let content = container(
+ let content = center(
column![
subtitle(
"Title",
@@ -146,11 +146,7 @@ impl App {
]
.spacing(10)
.max_width(200),
- )
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y();
+ );
toast::Manager::new(content, &self.toasts, Message::Close)
.timeout(self.timeout_secs)
@@ -651,45 +647,33 @@ mod toast {
}
}
- fn styled(pair: theme::palette::Pair) -> container::Appearance {
- container::Appearance {
+ fn styled(pair: theme::palette::Pair) -> container::Style {
+ container::Style {
background: Some(pair.color.into()),
text_color: pair.text.into(),
..Default::default()
}
}
- fn primary(
- theme: &Theme,
- _status: container::Status,
- ) -> container::Appearance {
+ fn primary(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
styled(palette.primary.weak)
}
- fn secondary(
- theme: &Theme,
- _status: container::Status,
- ) -> container::Appearance {
+ fn secondary(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
styled(palette.secondary.weak)
}
- fn success(
- theme: &Theme,
- _status: container::Status,
- ) -> container::Appearance {
+ fn success(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
styled(palette.success.weak)
}
- fn danger(
- theme: &Theme,
- _status: container::Status,
- ) -> container::Appearance {
+ fn danger(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
styled(palette.danger.weak)
diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs
index f5fb94c9..dd1e5213 100644
--- a/examples/todos/src/main.rs
+++ b/examples/todos/src/main.rs
@@ -1,8 +1,8 @@
use iced::alignment::{self, Alignment};
use iced::keyboard;
use iced::widget::{
- self, button, checkbox, column, container, keyed_column, row, scrollable,
- text, text_input, Text,
+ self, button, center, checkbox, column, container, keyed_column, row,
+ scrollable, text, text_input, Text,
};
use iced::window;
use iced::{Command, Element, Font, Length, Subscription};
@@ -238,7 +238,10 @@ impl Todos {
.spacing(20)
.max_width(800);
- scrollable(container(content).padding(40).center_x()).into()
+ scrollable(
+ container(content).center_x(Length::Fill).padding(40),
+ )
+ .into()
}
}
}
@@ -435,19 +438,16 @@ impl Filter {
}
fn loading_message<'a>() -> Element<'a, Message> {
- container(
+ center(
text("Loading...")
.horizontal_alignment(alignment::Horizontal::Center)
.size(50),
)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_y()
.into()
}
fn empty_message(message: &str) -> Element<'_, Message> {
- container(
+ center(
text(message)
.width(Length::Fill)
.size(25)
@@ -455,7 +455,6 @@ fn empty_message(message: &str) -> Element<'_, Message> {
.color([0.7, 0.7, 0.7]),
)
.height(200)
- .center_y()
.into()
}
diff --git a/examples/tooltip/src/main.rs b/examples/tooltip/src/main.rs
index b6603068..f48f688a 100644
--- a/examples/tooltip/src/main.rs
+++ b/examples/tooltip/src/main.rs
@@ -1,6 +1,6 @@
use iced::widget::tooltip::Position;
-use iced::widget::{button, container, tooltip};
-use iced::{Element, Length};
+use iced::widget::{button, center, container, tooltip};
+use iced::Element;
pub fn main() -> iced::Result {
iced::run("Tooltip - Iced", Tooltip::update, Tooltip::view)
@@ -43,12 +43,7 @@ impl Tooltip {
.gap(10)
.style(container::rounded_box);
- container(tooltip)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(tooltip).into()
}
}
diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs
index 3fb8b460..f624053c 100644
--- a/examples/tour/src/main.rs
+++ b/examples/tour/src/main.rs
@@ -76,11 +76,10 @@ impl Tour {
} else {
content
})
- .width(Length::Fill)
- .center_x(),
+ .center_x(Length::Fill),
);
- container(scrollable).height(Length::Fill).center_y().into()
+ container(scrollable).center_y(Length::Fill).into()
}
}
@@ -357,7 +356,7 @@ impl<'a> Step {
.into()
}
- fn container(title: &str) -> Column<'a, StepMessage> {
+ fn container(title: &str) -> Column<'_, StepMessage> {
column![text(title).size(50)].spacing(20)
}
@@ -589,7 +588,7 @@ impl<'a> Step {
value: &str,
is_secure: bool,
is_showing_icon: bool,
- ) -> Column<'a, StepMessage> {
+ ) -> Column<'_, StepMessage> {
let mut text_input = text_input("Type something to continue...", value)
.on_input(StepMessage::InputChanged)
.padding(10)
@@ -670,11 +669,10 @@ fn ferris<'a>(
.filter_method(filter_method)
.width(width),
)
- .width(Length::Fill)
- .center_x()
+ .center_x(Length::Fill)
}
-fn padded_button<'a, Message: Clone>(label: &str) -> Button<'a, Message> {
+fn padded_button<Message: Clone>(label: &str) -> Button<'_, Message> {
button(text(label)).padding([12, 24])
}
diff --git a/examples/url_handler/src/main.rs b/examples/url_handler/src/main.rs
index df705b6c..800a188b 100644
--- a/examples/url_handler/src/main.rs
+++ b/examples/url_handler/src/main.rs
@@ -1,6 +1,6 @@
use iced::event::{self, Event};
-use iced::widget::{container, text};
-use iced::{Element, Length, Subscription};
+use iced::widget::{center, text};
+use iced::{Element, Subscription};
pub fn main() -> iced::Result {
iced::program("URL Handler - Iced", App::update, App::view)
@@ -44,11 +44,6 @@ impl App {
None => text("No URL received yet!"),
};
- container(content.size(48))
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
- .into()
+ center(content.size(48)).into()
}
}
diff --git a/examples/websocket/src/echo.rs b/examples/websocket/src/echo.rs
index 281ed4bd..cd32cb66 100644
--- a/examples/websocket/src/echo.rs
+++ b/examples/websocket/src/echo.rs
@@ -2,6 +2,7 @@ pub mod server;
use iced::futures;
use iced::subscription::{self, Subscription};
+use iced::widget::text;
use futures::channel::mpsc;
use futures::sink::SinkExt;
@@ -136,16 +137,24 @@ impl Message {
pub fn disconnected() -> Self {
Message::Disconnected
}
+
+ pub fn as_str(&self) -> &str {
+ match self {
+ Message::Connected => "Connected successfully!",
+ Message::Disconnected => "Connection lost... Retrying...",
+ Message::User(message) => message.as_str(),
+ }
+ }
}
impl fmt::Display for Message {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Message::Connected => write!(f, "Connected successfully!"),
- Message::Disconnected => {
- write!(f, "Connection lost... Retrying...")
- }
- Message::User(message) => write!(f, "{message}"),
- }
+ f.write_str(self.as_str())
+ }
+}
+
+impl<'a> text::IntoFragment<'a> for &'a Message {
+ fn into_fragment(self) -> text::Fragment<'a> {
+ text::Fragment::Borrowed(self.as_str())
}
}
diff --git a/examples/websocket/src/main.rs b/examples/websocket/src/main.rs
index 460d9a08..ba1e1029 100644
--- a/examples/websocket/src/main.rs
+++ b/examples/websocket/src/main.rs
@@ -2,7 +2,7 @@ mod echo;
use iced::alignment::{self, Alignment};
use iced::widget::{
- button, column, container, row, scrollable, text, text_input,
+ self, button, center, column, row, scrollable, text, text_input,
};
use iced::{color, Command, Element, Length, Subscription};
use once_cell::sync::Lazy;
@@ -31,7 +31,10 @@ enum Message {
impl WebSocket {
fn load() -> Command<Message> {
- Command::perform(echo::server::run(), |_| Message::Server)
+ Command::batch([
+ Command::perform(echo::server::run(), |_| Message::Server),
+ widget::focus_next(),
+ ])
}
fn update(&mut self, message: Message) -> Command<Message> {
@@ -85,21 +88,15 @@ impl WebSocket {
fn view(&self) -> Element<Message> {
let message_log: Element<_> = if self.messages.is_empty() {
- container(
+ center(
text("Your messages will appear here...")
.color(color!(0x888888)),
)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_x()
- .center_y()
.into()
} else {
scrollable(
- column(
- self.messages.iter().cloned().map(text).map(Element::from),
- )
- .spacing(10),
+ column(self.messages.iter().map(text).map(Element::from))
+ .spacing(10),
)
.id(MESSAGE_LOG.clone())
.height(Length::Fill)