diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/arc/src/main.rs | 14 | ||||
-rw-r--r-- | examples/cached/Cargo.toml | 10 | ||||
-rw-r--r-- | examples/cached/src/main.rs | 139 | ||||
-rw-r--r-- | examples/clock/src/main.rs | 54 | ||||
-rw-r--r-- | examples/geometry/Cargo.toml | 11 | ||||
-rw-r--r-- | examples/geometry/README.md | 18 | ||||
-rw-r--r-- | examples/geometry/src/main.rs | 217 | ||||
-rw-r--r-- | examples/lazy/Cargo.toml | 10 | ||||
-rw-r--r-- | examples/lazy/src/main.rs | 139 | ||||
-rw-r--r-- | examples/modern_art/Cargo.toml | 10 | ||||
-rw-r--r-- | examples/modern_art/src/main.rs | 140 | ||||
-rw-r--r-- | examples/multitouch/src/main.rs | 5 | ||||
-rw-r--r-- | examples/scrollable/src/main.rs | 23 | ||||
-rw-r--r-- | examples/solar_system/src/main.rs | 45 | ||||
-rw-r--r-- | examples/styling/src/main.rs | 57 |
15 files changed, 569 insertions, 323 deletions
diff --git a/examples/arc/src/main.rs b/examples/arc/src/main.rs index 0c619dc9..7b6ea0e1 100644 --- a/examples/arc/src/main.rs +++ b/examples/arc/src/main.rs @@ -2,7 +2,7 @@ use std::{f32::consts::PI, time::Instant}; use iced::executor; use iced::widget::canvas::{ - self, Cache, Canvas, Cursor, Geometry, Path, Stroke, + self, stroke, Cache, Canvas, Cursor, Geometry, Path, Stroke, }; use iced::{ Application, Command, Element, Length, Point, Rectangle, Settings, @@ -52,11 +52,6 @@ impl Application for Arc { Command::none() } - fn subscription(&self) -> Subscription<Message> { - iced::time::every(std::time::Duration::from_millis(10)) - .map(|_| Message::Tick) - } - fn view(&self) -> Element<Message> { Canvas::new(self) .width(Length::Fill) @@ -67,6 +62,11 @@ impl Application for Arc { fn theme(&self) -> Theme { Theme::Dark } + + fn subscription(&self) -> Subscription<Message> { + iced::time::every(std::time::Duration::from_millis(10)) + .map(|_| Message::Tick) + } } impl<Message> canvas::Program<Message> for Arc { @@ -114,7 +114,7 @@ impl<Message> canvas::Program<Message> for Arc { frame.stroke( &path, Stroke { - color: palette.text, + style: stroke::Style::Solid(palette.text), width: 10.0, ..Stroke::default() }, diff --git a/examples/cached/Cargo.toml b/examples/cached/Cargo.toml new file mode 100644 index 00000000..2c7edde2 --- /dev/null +++ b/examples/cached/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "cached" +version = "0.1.0" +authors = ["Nick Senger <dev@nsenger.com>"] +edition = "2021" +publish = false + +[dependencies] +iced = { path = "../..", features = ["debug"] } +iced_lazy = { path = "../../lazy" } diff --git a/examples/cached/src/main.rs b/examples/cached/src/main.rs new file mode 100644 index 00000000..8845b874 --- /dev/null +++ b/examples/cached/src/main.rs @@ -0,0 +1,139 @@ +use iced::theme; +use iced::widget::{ + button, column, horizontal_space, row, scrollable, text, text_input, +}; +use iced::{Element, Length, Sandbox, Settings}; +use iced_lazy::lazy; + +use std::collections::HashSet; + +pub fn main() -> iced::Result { + App::run(Settings::default()) +} + +struct App { + options: HashSet<String>, + input: String, + order: Order, +} + +impl Default for App { + fn default() -> Self { + Self { + options: ["Foo", "Bar", "Baz", "Qux", "Corge", "Waldo", "Fred"] + .into_iter() + .map(ToString::to_string) + .collect(), + input: Default::default(), + order: Order::Ascending, + } + } +} + +#[derive(Debug, Clone)] +enum Message { + InputChanged(String), + ToggleOrder, + DeleteOption(String), + AddOption(String), +} + +impl Sandbox for App { + type Message = Message; + + fn new() -> Self { + Self::default() + } + + fn title(&self) -> String { + String::from("Cached - Iced") + } + + fn update(&mut self, message: Message) { + match message { + Message::InputChanged(input) => { + self.input = input; + } + Message::ToggleOrder => { + self.order = match self.order { + Order::Ascending => Order::Descending, + Order::Descending => Order::Ascending, + } + } + Message::AddOption(option) => { + self.options.insert(option); + self.input.clear(); + } + Message::DeleteOption(option) => { + self.options.remove(&option); + } + } + } + + fn view(&self) -> Element<Message> { + let options = lazy((&self.order, self.options.len()), || { + let mut options: Vec<_> = self.options.iter().collect(); + + options.sort_by(|a, b| match self.order { + Order::Ascending => a.to_lowercase().cmp(&b.to_lowercase()), + Order::Descending => b.to_lowercase().cmp(&a.to_lowercase()), + }); + + column( + options + .into_iter() + .map(|option| { + row![ + text(option), + horizontal_space(Length::Fill), + button("Delete") + .on_press(Message::DeleteOption( + option.to_string(), + ),) + .style(theme::Button::Destructive) + ] + .into() + }) + .collect(), + ) + .spacing(10) + }); + + column![ + scrollable(options).height(Length::Fill), + row![ + text_input( + "Add a new option", + &self.input, + Message::InputChanged, + ) + .on_submit(Message::AddOption(self.input.clone())), + button(text(format!("Toggle Order ({})", self.order))) + .on_press(Message::ToggleOrder) + ] + .spacing(10) + ] + .spacing(20) + .padding(20) + .into() + } +} + +#[derive(Debug, Hash)] +enum Order { + Ascending, + Descending, +} + +impl std::fmt::Display for Order { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Self::Ascending => "Ascending", + Self::Descending => "Descending", + } + ) + } +} diff --git a/examples/clock/src/main.rs b/examples/clock/src/main.rs index 8818fb54..a389c54f 100644 --- a/examples/clock/src/main.rs +++ b/examples/clock/src/main.rs @@ -1,5 +1,7 @@ use iced::executor; -use iced::widget::canvas::{Cache, Cursor, Geometry, LineCap, Path, Stroke}; +use iced::widget::canvas::{ + stroke, Cache, Cursor, Geometry, LineCap, Path, Stroke, +}; use iced::widget::{canvas, container}; use iced::{ Application, Color, Command, Element, Length, Point, Rectangle, Settings, @@ -24,9 +26,9 @@ enum Message { } impl Application for Clock { + type Executor = executor::Default; type Message = Message; type Theme = Theme; - type Executor = executor::Default; type Flags = (); fn new(_flags: ()) -> (Self, Command<Message>) { @@ -59,15 +61,6 @@ impl Application for Clock { Command::none() } - 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()), - ) - }) - } - fn view(&self) -> Element<Message> { let canvas = canvas(self as &Self) .width(Length::Fill) @@ -79,6 +72,15 @@ impl Application for Clock { .padding(20) .into() } + + 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()), + ) + }) + } } impl<Message> canvas::Program<Message> for Clock { @@ -104,33 +106,41 @@ impl<Message> canvas::Program<Message> for Clock { let long_hand = Path::line(Point::ORIGIN, Point::new(0.0, -0.8 * radius)); - let thin_stroke = Stroke { - width: radius / 100.0, - color: Color::WHITE, - line_cap: LineCap::Round, - ..Stroke::default() + let width = radius / 100.0; + + let thin_stroke = || -> Stroke { + Stroke { + width, + style: stroke::Style::Solid(Color::WHITE), + line_cap: LineCap::Round, + ..Stroke::default() + } }; - let wide_stroke = Stroke { - width: thin_stroke.width * 3.0, - ..thin_stroke + let wide_stroke = || -> Stroke { + Stroke { + width: width * 3.0, + style: stroke::Style::Solid(Color::WHITE), + line_cap: LineCap::Round, + ..Stroke::default() + } }; frame.translate(Vector::new(center.x, center.y)); frame.with_save(|frame| { frame.rotate(hand_rotation(self.now.hour(), 12)); - frame.stroke(&short_hand, wide_stroke); + frame.stroke(&short_hand, wide_stroke()); }); frame.with_save(|frame| { frame.rotate(hand_rotation(self.now.minute(), 60)); - frame.stroke(&long_hand, wide_stroke); + frame.stroke(&long_hand, wide_stroke()); }); frame.with_save(|frame| { frame.rotate(hand_rotation(self.now.second(), 60)); - frame.stroke(&long_hand, thin_stroke); + frame.stroke(&long_hand, thin_stroke()); }) }); diff --git a/examples/geometry/Cargo.toml b/examples/geometry/Cargo.toml deleted file mode 100644 index 22ede0e0..00000000 --- a/examples/geometry/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "geometry" -version = "0.1.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -publish = false - -[dependencies] -iced = { path = "../.." } -iced_native = { path = "../../native" } -iced_graphics = { path = "../../graphics" } diff --git a/examples/geometry/README.md b/examples/geometry/README.md deleted file mode 100644 index 4d5c81cb..00000000 --- a/examples/geometry/README.md +++ /dev/null @@ -1,18 +0,0 @@ -## Geometry - -A custom widget showcasing how to draw geometry with the `Mesh2D` primitive in [`iced_wgpu`](../../wgpu). - -The __[`main`]__ file contains all the code of the example. - -<div align="center"> - <a href="https://gfycat.com/activeunfitkangaroo"> - <img src="https://thumbs.gfycat.com/ActiveUnfitKangaroo-small.gif"> - </a> -</div> - -You can run it with `cargo run`: -``` -cargo run --package geometry -``` - -[`main`]: src/main.rs diff --git a/examples/geometry/src/main.rs b/examples/geometry/src/main.rs deleted file mode 100644 index d8b99ab3..00000000 --- a/examples/geometry/src/main.rs +++ /dev/null @@ -1,217 +0,0 @@ -//! This example showcases a simple native custom widget that renders using -//! arbitrary low-level geometry. -mod rainbow { - // 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_graphics::renderer::{self, Renderer}; - use iced_graphics::{Backend, Primitive}; - - use iced_native::widget::{self, Widget}; - use iced_native::{ - layout, Element, Layout, Length, Point, Rectangle, Size, Vector, - }; - - #[derive(Default)] - pub struct Rainbow; - - impl Rainbow { - pub fn new() -> Self { - Self - } - } - - pub fn rainbow() -> Rainbow { - Rainbow - } - - impl<Message, B, T> Widget<Message, Renderer<B, T>> for Rainbow - where - B: Backend, - { - fn width(&self) -> Length { - Length::Fill - } - - fn height(&self) -> Length { - Length::Shrink - } - - fn layout( - &self, - _renderer: &Renderer<B, T>, - limits: &layout::Limits, - ) -> layout::Node { - let size = limits.width(Length::Fill).resolve(Size::ZERO); - - layout::Node::new(Size::new(size.width, size.width)) - } - - fn draw( - &self, - _tree: &widget::Tree, - renderer: &mut Renderer<B, T>, - _theme: &T, - _style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - _viewport: &Rectangle, - ) { - use iced_graphics::triangle::{Mesh2D, Vertex2D}; - use iced_native::Renderer as _; - - let b = layout.bounds(); - - // R O Y G B I V - let color_r = [1.0, 0.0, 0.0, 1.0]; - let color_o = [1.0, 0.5, 0.0, 1.0]; - let color_y = [1.0, 1.0, 0.0, 1.0]; - let color_g = [0.0, 1.0, 0.0, 1.0]; - let color_gb = [0.0, 1.0, 0.5, 1.0]; - let color_b = [0.0, 0.2, 1.0, 1.0]; - let color_i = [0.5, 0.0, 1.0, 1.0]; - let color_v = [0.75, 0.0, 0.5, 1.0]; - - let posn_center = { - if b.contains(cursor_position) { - [cursor_position.x - b.x, cursor_position.y - b.y] - } else { - [b.width / 2.0, b.height / 2.0] - } - }; - - let posn_tl = [0.0, 0.0]; - let posn_t = [b.width / 2.0, 0.0]; - let posn_tr = [b.width, 0.0]; - let posn_r = [b.width, b.height / 2.0]; - let posn_br = [b.width, b.height]; - let posn_b = [(b.width / 2.0), b.height]; - let posn_bl = [0.0, b.height]; - let posn_l = [0.0, b.height / 2.0]; - - let mesh = Primitive::Mesh2D { - size: b.size(), - buffers: Mesh2D { - vertices: vec![ - Vertex2D { - position: posn_center, - color: [1.0, 1.0, 1.0, 1.0], - }, - Vertex2D { - position: posn_tl, - color: color_r, - }, - Vertex2D { - position: posn_t, - color: color_o, - }, - Vertex2D { - position: posn_tr, - color: color_y, - }, - Vertex2D { - position: posn_r, - color: color_g, - }, - Vertex2D { - position: posn_br, - color: color_gb, - }, - Vertex2D { - position: posn_b, - color: color_b, - }, - Vertex2D { - position: posn_bl, - color: color_i, - }, - Vertex2D { - position: posn_l, - color: color_v, - }, - ], - indices: vec![ - 0, 1, 2, // TL - 0, 2, 3, // T - 0, 3, 4, // TR - 0, 4, 5, // R - 0, 5, 6, // BR - 0, 6, 7, // B - 0, 7, 8, // BL - 0, 8, 1, // L - ], - }, - }; - - renderer.with_translation(Vector::new(b.x, b.y), |renderer| { - renderer.draw_primitive(mesh); - }); - } - } - - impl<'a, Message, B, T> From<Rainbow> for Element<'a, Message, Renderer<B, T>> - where - B: Backend, - { - fn from(rainbow: Rainbow) -> Self { - Self::new(rainbow) - } - } -} - -use iced::widget::{column, container, scrollable}; -use iced::{Alignment, Element, Length, Sandbox, Settings}; -use rainbow::rainbow; - -pub fn main() -> iced::Result { - Example::run(Settings::default()) -} - -struct Example; - -impl Sandbox for Example { - type Message = (); - - fn new() -> Self { - Example - } - - fn title(&self) -> String { - String::from("Custom 2D geometry - Iced") - } - - fn update(&mut self, _: ()) {} - - fn view(&self) -> Element<()> { - let content = column![ - rainbow(), - "In this example we draw a custom widget Rainbow, using \ - the Mesh2D primitive. This primitive supplies a list of \ - triangles, expressed as vertices and indices.", - "Move your cursor over it, and see the center vertex \ - follow you!", - "Every Vertex2D defines its own color. You could use the \ - Mesh2D primitive to render virtually any two-dimensional \ - geometry for your widget.", - ] - .padding(20) - .spacing(20) - .max_width(500) - .align_items(Alignment::Start); - - let scrollable = - scrollable(container(content).width(Length::Fill).center_x()); - - container(scrollable) - .width(Length::Fill) - .height(Length::Fill) - .center_y() - .into() - } -} diff --git a/examples/lazy/Cargo.toml b/examples/lazy/Cargo.toml new file mode 100644 index 00000000..79255c25 --- /dev/null +++ b/examples/lazy/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "lazy" +version = "0.1.0" +authors = ["Nick Senger <dev@nsenger.com>"] +edition = "2021" +publish = false + +[dependencies] +iced = { path = "../..", features = ["debug"] } +iced_lazy = { path = "../../lazy" } diff --git a/examples/lazy/src/main.rs b/examples/lazy/src/main.rs new file mode 100644 index 00000000..8845b874 --- /dev/null +++ b/examples/lazy/src/main.rs @@ -0,0 +1,139 @@ +use iced::theme; +use iced::widget::{ + button, column, horizontal_space, row, scrollable, text, text_input, +}; +use iced::{Element, Length, Sandbox, Settings}; +use iced_lazy::lazy; + +use std::collections::HashSet; + +pub fn main() -> iced::Result { + App::run(Settings::default()) +} + +struct App { + options: HashSet<String>, + input: String, + order: Order, +} + +impl Default for App { + fn default() -> Self { + Self { + options: ["Foo", "Bar", "Baz", "Qux", "Corge", "Waldo", "Fred"] + .into_iter() + .map(ToString::to_string) + .collect(), + input: Default::default(), + order: Order::Ascending, + } + } +} + +#[derive(Debug, Clone)] +enum Message { + InputChanged(String), + ToggleOrder, + DeleteOption(String), + AddOption(String), +} + +impl Sandbox for App { + type Message = Message; + + fn new() -> Self { + Self::default() + } + + fn title(&self) -> String { + String::from("Cached - Iced") + } + + fn update(&mut self, message: Message) { + match message { + Message::InputChanged(input) => { + self.input = input; + } + Message::ToggleOrder => { + self.order = match self.order { + Order::Ascending => Order::Descending, + Order::Descending => Order::Ascending, + } + } + Message::AddOption(option) => { + self.options.insert(option); + self.input.clear(); + } + Message::DeleteOption(option) => { + self.options.remove(&option); + } + } + } + + fn view(&self) -> Element<Message> { + let options = lazy((&self.order, self.options.len()), || { + let mut options: Vec<_> = self.options.iter().collect(); + + options.sort_by(|a, b| match self.order { + Order::Ascending => a.to_lowercase().cmp(&b.to_lowercase()), + Order::Descending => b.to_lowercase().cmp(&a.to_lowercase()), + }); + + column( + options + .into_iter() + .map(|option| { + row![ + text(option), + horizontal_space(Length::Fill), + button("Delete") + .on_press(Message::DeleteOption( + option.to_string(), + ),) + .style(theme::Button::Destructive) + ] + .into() + }) + .collect(), + ) + .spacing(10) + }); + + column![ + scrollable(options).height(Length::Fill), + row![ + text_input( + "Add a new option", + &self.input, + Message::InputChanged, + ) + .on_submit(Message::AddOption(self.input.clone())), + button(text(format!("Toggle Order ({})", self.order))) + .on_press(Message::ToggleOrder) + ] + .spacing(10) + ] + .spacing(20) + .padding(20) + .into() + } +} + +#[derive(Debug, Hash)] +enum Order { + Ascending, + Descending, +} + +impl std::fmt::Display for Order { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Self::Ascending => "Ascending", + Self::Descending => "Descending", + } + ) + } +} diff --git a/examples/modern_art/Cargo.toml b/examples/modern_art/Cargo.toml new file mode 100644 index 00000000..a48361ae --- /dev/null +++ b/examples/modern_art/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "modern_art" +version = "0.1.0" +authors = ["Bingus <shankern@protonmail.com>"] +edition = "2021" +publish = false + +[dependencies] +iced = { path = "../..", features = ["canvas", "tokio", "debug"] } +rand = "0.8.5" diff --git a/examples/modern_art/src/main.rs b/examples/modern_art/src/main.rs new file mode 100644 index 00000000..0dd21c74 --- /dev/null +++ b/examples/modern_art/src/main.rs @@ -0,0 +1,140 @@ +use iced::widget::canvas::{ + self, gradient::Location, gradient::Position, Cache, Canvas, Cursor, Frame, + Geometry, Gradient, +}; +use iced::{ + executor, Application, Color, Command, Element, Length, Point, Rectangle, + Renderer, Settings, Size, Theme, +}; +use rand::{thread_rng, Rng}; + +fn main() -> iced::Result { + ModernArt::run(Settings { + antialiasing: true, + ..Settings::default() + }) +} + +#[derive(Debug, Clone, Copy)] +enum Message {} + +struct ModernArt { + cache: Cache, +} + +impl Application for ModernArt { + type Executor = executor::Default; + type Message = Message; + type Theme = Theme; + type Flags = (); + + fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) { + ( + ModernArt { + cache: Default::default(), + }, + Command::none(), + ) + } + + fn title(&self) -> String { + String::from("Modern Art") + } + + fn update(&mut self, _message: Message) -> Command<Message> { + Command::none() + } + + fn view(&self) -> Element<'_, Self::Message, Renderer<Self::Theme>> { + Canvas::new(self) + .width(Length::Fill) + .height(Length::Fill) + .into() + } +} + +impl<Message> canvas::Program<Message> for ModernArt { + type State = (); + + fn draw( + &self, + _state: &Self::State, + _theme: &Theme, + bounds: Rectangle, + _cursor: Cursor, + ) -> Vec<Geometry> { + let geometry = self.cache.draw(bounds.size(), |frame| { + let num_squares = thread_rng().gen_range(0..1200); + + let mut i = 0; + while i <= num_squares { + generate_box(frame, bounds.size()); + i += 1; + } + }); + + vec![geometry] + } +} + +fn random_direction() -> Location { + match thread_rng().gen_range(0..8) { + 0 => Location::TopLeft, + 1 => Location::Top, + 2 => Location::TopRight, + 3 => Location::Right, + 4 => Location::BottomRight, + 5 => Location::Bottom, + 6 => Location::BottomLeft, + 7 => Location::Left, + _ => Location::TopLeft, + } +} + +fn generate_box(frame: &mut Frame, bounds: Size) -> bool { + let solid = rand::random::<bool>(); + + let random_color = || -> Color { + Color::from_rgb( + thread_rng().gen_range(0.0..1.0), + thread_rng().gen_range(0.0..1.0), + thread_rng().gen_range(0.0..1.0), + ) + }; + + let gradient = |top_left: Point, size: Size| -> Gradient { + let mut builder = Gradient::linear(Position::Relative { + top_left, + size, + start: random_direction(), + end: random_direction(), + }); + let stops = thread_rng().gen_range(1..15u32); + + let mut i = 0; + while i <= stops { + builder = builder.add_stop(i as f32 / stops as f32, random_color()); + i += 1; + } + + builder.build().unwrap() + }; + + let top_left = Point::new( + thread_rng().gen_range(0.0..bounds.width), + thread_rng().gen_range(0.0..bounds.height), + ); + + let size = Size::new( + thread_rng().gen_range(50.0..200.0), + thread_rng().gen_range(50.0..200.0), + ); + + if solid { + frame.fill_rectangle(top_left, size, random_color()); + } else { + frame.fill_rectangle(top_left, size, gradient(top_left, size)); + }; + + solid +} diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs index 0345ceb7..f5faae0f 100644 --- a/examples/multitouch/src/main.rs +++ b/examples/multitouch/src/main.rs @@ -2,7 +2,8 @@ //! a circle around each fingertip. This only works on touch-enabled //! computers like Microsoft Surface. use iced::widget::canvas::event; -use iced::widget::canvas::{self, Canvas, Cursor, Geometry, Stroke}; +use iced::widget::canvas::stroke::{self, Stroke}; +use iced::widget::canvas::{self, Canvas, Cursor, Geometry}; use iced::{ executor, touch, window, Application, Color, Command, Element, Length, Point, Rectangle, Settings, Subscription, Theme, @@ -186,7 +187,7 @@ impl canvas::Program<Message> for State { frame.stroke( &path, Stroke { - color: Color::BLACK, + style: stroke::Style::Solid(Color::BLACK), width: 3.0, ..Stroke::default() }, diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs index b7b3dedc..6eba34e2 100644 --- a/examples/scrollable/src/main.rs +++ b/examples/scrollable/src/main.rs @@ -14,9 +14,15 @@ struct ScrollableDemo { variants: Vec<Variant>, } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum ThemeType { + Light, + Dark, +} + #[derive(Debug, Clone)] enum Message { - ThemeChanged(Theme), + ThemeChanged(ThemeType), ScrollToTop(usize), ScrollToBottom(usize), Scrolled(usize, f32), @@ -45,7 +51,10 @@ impl Application for ScrollableDemo { fn update(&mut self, message: Message) -> Command<Message> { match message { Message::ThemeChanged(theme) => { - self.theme = theme; + self.theme = match theme { + ThemeType::Light => Theme::Light, + ThemeType::Dark => Theme::Dark, + }; Command::none() } @@ -78,17 +87,15 @@ impl Application for ScrollableDemo { } fn view(&self) -> Element<Message> { - let ScrollableDemo { - theme, variants, .. - } = self; + let ScrollableDemo { variants, .. } = self; - let choose_theme = [Theme::Light, Theme::Dark].iter().fold( + let choose_theme = [ThemeType::Light, ThemeType::Dark].iter().fold( column!["Choose a theme:"].spacing(10), |column, option| { column.push(radio( format!("{:?}", option), *option, - Some(*theme), + Some(*option), Message::ThemeChanged, )) }, @@ -198,7 +205,7 @@ impl Application for ScrollableDemo { } fn theme(&self) -> Theme { - self.theme + self.theme.clone() } } diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs index c59d73a8..56787a99 100644 --- a/examples/solar_system/src/main.rs +++ b/examples/solar_system/src/main.rs @@ -11,7 +11,9 @@ use iced::executor; use iced::theme::{self, Theme}; use iced::time; use iced::widget::canvas; -use iced::widget::canvas::{Cursor, Path, Stroke}; +use iced::widget::canvas::gradient::{self, Gradient}; +use iced::widget::canvas::stroke::{self, Stroke}; +use iced::widget::canvas::{Cursor, Path}; use iced::window; use iced::{ Application, Color, Command, Element, Length, Point, Rectangle, Settings, @@ -37,9 +39,9 @@ enum Message { } impl Application for SolarSystem { + type Executor = executor::Default; type Message = Message; type Theme = Theme; - type Executor = executor::Default; type Flags = (); fn new(_flags: ()) -> (Self, Command<Message>) { @@ -65,10 +67,6 @@ impl Application for SolarSystem { Command::none() } - fn subscription(&self) -> Subscription<Message> { - time::every(std::time::Duration::from_millis(10)).map(Message::Tick) - } - fn view(&self) -> Element<Message> { canvas(&self.state) .width(Length::Fill) @@ -86,6 +84,10 @@ impl Application for SolarSystem { text_color: Color::WHITE, }) } + + fn subscription(&self) -> Subscription<Message> { + time::every(time::Duration::from_millis(10)).map(Message::Tick) + } } #[derive(Debug)] @@ -178,8 +180,10 @@ impl<Message> canvas::Program<Message> for State { frame.stroke( &orbit, Stroke { + style: stroke::Style::Solid(Color::from_rgba8( + 0, 153, 255, 0.1, + )), width: 1.0, - color: Color::from_rgba8(0, 153, 255, 0.1), line_dash: canvas::LineDash { offset: 0, segments: &[3.0, 6.0], @@ -198,15 +202,18 @@ impl<Message> canvas::Program<Message> for State { frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0)); let earth = Path::circle(Point::ORIGIN, Self::EARTH_RADIUS); - let shadow = Path::rectangle( - Point::new(0.0, -Self::EARTH_RADIUS), - Size::new( - Self::EARTH_RADIUS * 4.0, - Self::EARTH_RADIUS * 2.0, - ), - ); - frame.fill(&earth, Color::from_rgb8(0x6B, 0x93, 0xD6)); + let earth_fill = + Gradient::linear(gradient::Position::Absolute { + start: Point::new(-Self::EARTH_RADIUS, 0.0), + end: 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)) + .build() + .expect("Build Earth fill gradient"); + + frame.fill(&earth, earth_fill); frame.with_save(|frame| { frame.rotate(rotation * 10.0); @@ -215,14 +222,6 @@ impl<Message> canvas::Program<Message> for State { let moon = Path::circle(Point::ORIGIN, Self::MOON_RADIUS); frame.fill(&moon, Color::WHITE); }); - - frame.fill( - &shadow, - Color { - a: 0.7, - ..Color::BLACK - }, - ); }); }); diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs index cda53e87..e16860ad 100644 --- a/examples/styling/src/main.rs +++ b/examples/styling/src/main.rs @@ -1,9 +1,10 @@ +use iced::theme::{self, Theme}; use iced::widget::{ button, checkbox, column, container, horizontal_rule, progress_bar, radio, row, scrollable, slider, text, text_input, toggler, vertical_rule, vertical_space, }; -use iced::{Alignment, Element, Length, Sandbox, Settings, Theme}; +use iced::{Alignment, Color, Element, Length, Sandbox, Settings}; pub fn main() -> iced::Result { Styling::run(Settings::default()) @@ -18,9 +19,16 @@ struct Styling { toggler_value: bool, } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum ThemeType { + Light, + Dark, + Custom, +} + #[derive(Debug, Clone)] enum Message { - ThemeChanged(Theme), + ThemeChanged(ThemeType), InputChanged(String), ButtonPressed, SliderChanged(f32), @@ -41,7 +49,19 @@ impl Sandbox for Styling { fn update(&mut self, message: Message) { match message { - Message::ThemeChanged(theme) => self.theme = theme, + Message::ThemeChanged(theme) => { + self.theme = match theme { + ThemeType::Light => Theme::Light, + ThemeType::Dark => Theme::Dark, + ThemeType::Custom => Theme::custom(theme::Palette { + background: Color::from_rgb(1.0, 0.9, 1.0), + text: Color::BLACK, + primary: Color::from_rgb(0.5, 0.5, 0.0), + success: Color::from_rgb(0.0, 1.0, 0.0), + danger: Color::from_rgb(1.0, 0.0, 0.0), + }), + } + } Message::InputChanged(value) => self.input_value = value, Message::ButtonPressed => {} Message::SliderChanged(value) => self.slider_value = value, @@ -51,17 +71,24 @@ impl Sandbox for Styling { } fn view(&self) -> Element<Message> { - let choose_theme = [Theme::Light, Theme::Dark].iter().fold( - column![text("Choose a theme:")].spacing(10), - |column, theme| { - column.push(radio( - format!("{:?}", theme), - *theme, - Some(self.theme), - Message::ThemeChanged, - )) - }, - ); + let choose_theme = + [ThemeType::Light, ThemeType::Dark, ThemeType::Custom] + .iter() + .fold( + column![text("Choose a theme:")].spacing(10), + |column, theme| { + column.push(radio( + format!("{:?}", theme), + *theme, + Some(match self.theme { + Theme::Light => ThemeType::Light, + Theme::Dark => ThemeType::Dark, + Theme::Custom { .. } => ThemeType::Custom, + }), + Message::ThemeChanged, + )) + }, + ); let text_input = text_input( "Type something...", @@ -132,6 +159,6 @@ impl Sandbox for Styling { } fn theme(&self) -> Theme { - self.theme + self.theme.clone() } } |