summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md29
-rw-r--r--core/src/angle.rs24
-rw-r--r--examples/arc/src/main.rs53
-rw-r--r--examples/bezier_tool/src/main.rs21
-rw-r--r--examples/checkbox/src/main.rs33
-rw-r--r--examples/clock/src/main.rs83
-rw-r--r--examples/color_palette/src/main.rs30
-rw-r--r--examples/combo_box/src/main.rs18
-rw-r--r--examples/component/src/main.rs16
-rw-r--r--examples/counter/src/main.rs36
-rw-r--r--examples/custom_quad/src/main.rs20
-rw-r--r--examples/custom_shader/src/main.rs52
-rw-r--r--examples/custom_widget/src/main.rs18
-rw-r--r--examples/download_progress/src/main.rs54
-rw-r--r--examples/events/src/main.rs32
-rw-r--r--examples/exit/src/main.rs20
-rw-r--r--examples/geometry/src/main.rs58
-rw-r--r--examples/layout/src/main.rs34
-rw-r--r--examples/lazy/src/main.rs16
-rw-r--r--examples/loading_spinners/src/main.rs49
-rw-r--r--examples/loupe/src/main.rs33
-rw-r--r--examples/multitouch/src/main.rs73
-rw-r--r--examples/pane_grid/src/main.rs46
-rw-r--r--examples/pick_list/src/main.rs16
-rw-r--r--examples/pokedex/src/main.rs29
-rw-r--r--examples/progress_bar/src/main.rs16
-rw-r--r--examples/qr_code/src/main.rs22
-rw-r--r--examples/screenshot/src/main.rs42
-rw-r--r--examples/scrollable/src/main.rs54
-rw-r--r--examples/sierpinski_triangle/src/main.rs53
-rw-r--r--examples/slider/src/main.rs20
-rw-r--r--examples/solar_system/src/main.rs58
-rw-r--r--examples/stopwatch/src/main.rs43
-rw-r--r--examples/styling/src/main.rs18
-rw-r--r--examples/svg/src/main.rs20
-rw-r--r--examples/system_information/src/main.rs39
-rw-r--r--examples/tooltip/src/main.rs23
-rw-r--r--examples/tour/src/main.rs20
-rw-r--r--examples/url_handler/src/main.rs30
-rw-r--r--examples/vectorial_text/src/main.rs42
-rw-r--r--renderer/src/geometry.rs4
-rw-r--r--runtime/src/command.rs6
-rw-r--r--src/lib.rs48
-rw-r--r--src/program.rs687
-rw-r--r--src/settings.rs2
-rw-r--r--tiny_skia/src/geometry.rs12
-rw-r--r--wgpu/src/geometry.rs8
-rw-r--r--widget/src/tooltip.rs7
48 files changed, 1271 insertions, 896 deletions
diff --git a/README.md b/README.md
index 9f21fc83..dee8b99d 100644
--- a/README.md
+++ b/README.md
@@ -98,8 +98,8 @@ that can be incremented and decremented using two buttons.
We start by modelling the __state__ of our application:
```rust
+#[derive(Default)]
struct Counter {
- // The counter value
value: i32,
}
```
@@ -110,8 +110,8 @@ the button presses. These interactions are our __messages__:
```rust
#[derive(Debug, Clone, Copy)]
pub enum Message {
- IncrementPressed,
- DecrementPressed,
+ Increment,
+ Decrement,
}
```
@@ -126,15 +126,15 @@ impl Counter {
// We use a column: a simple vertical layout
column![
// The increment button. We tell it to produce an
- // `IncrementPressed` message when pressed
- button("+").on_press(Message::IncrementPressed),
+ // `Increment` message when pressed
+ button("+").on_press(Message::Increment),
// We show the value of the counter here
text(self.value).size(50),
// The decrement button. We tell it to produce a
- // `DecrementPressed` message when pressed
- button("-").on_press(Message::DecrementPressed),
+ // `Decrement` message when pressed
+ button("-").on_press(Message::Decrement),
]
}
}
@@ -149,10 +149,10 @@ impl Counter {
pub fn update(&mut self, message: Message) {
match message {
- Message::IncrementPressed => {
+ Message::Increment => {
self.value += 1;
}
- Message::DecrementPressed => {
+ Message::Decrement => {
self.value -= 1;
}
}
@@ -160,8 +160,15 @@ impl Counter {
}
```
-And that's everything! We just wrote a whole user interface. Iced is now able
-to:
+And that's everything! We just wrote a whole user interface. Let's run it:
+
+```rust
+fn main() -> iced::Result {
+ iced::run("A cool counter", Counter::update, Counter::view)
+}
+```
+
+Iced will automatically:
1. Take the result of our __view logic__ and layout its widgets.
1. Process events from our system and produce __messages__ for our
diff --git a/core/src/angle.rs b/core/src/angle.rs
index 30ddad83..dc3c0e93 100644
--- a/core/src/angle.rs
+++ b/core/src/angle.rs
@@ -7,6 +7,18 @@ use std::ops::{Add, AddAssign, Div, Mul, RangeInclusive, Sub, SubAssign};
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct Degrees(pub f32);
+impl PartialEq<f32> for Degrees {
+ fn eq(&self, other: &f32) -> bool {
+ self.0.eq(other)
+ }
+}
+
+impl PartialOrd<f32> for Degrees {
+ fn partial_cmp(&self, other: &f32) -> Option<std::cmp::Ordering> {
+ self.0.partial_cmp(other)
+ }
+}
+
/// Radians
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct Radians(pub f32);
@@ -140,3 +152,15 @@ impl Div for Radians {
Self(self.0 / rhs.0)
}
}
+
+impl PartialEq<f32> for Radians {
+ fn eq(&self, other: &f32) -> bool {
+ self.0.eq(other)
+ }
+}
+
+impl PartialOrd<f32> for Radians {
+ fn partial_cmp(&self, other: &f32) -> Option<std::cmp::Ordering> {
+ self.0.partial_cmp(other)
+ }
+}
diff --git a/examples/arc/src/main.rs b/examples/arc/src/main.rs
index 6a68cca1..cd62ac17 100644
--- a/examples/arc/src/main.rs
+++ b/examples/arc/src/main.rs
@@ -1,20 +1,17 @@
use std::{f32::consts::PI, time::Instant};
-use iced::executor;
use iced::mouse;
use iced::widget::canvas::{
self, stroke, Cache, Canvas, Geometry, Path, Stroke,
};
-use iced::{
- Application, Command, Element, Length, Point, Rectangle, Renderer,
- Settings, Subscription, Theme,
-};
+use iced::{Element, Length, Point, Rectangle, Renderer, Subscription, Theme};
pub fn main() -> iced::Result {
- Arc::run(Settings {
- antialiasing: true,
- ..Settings::default()
- })
+ iced::application("Arc - Iced", Arc::update, Arc::view)
+ .subscription(Arc::subscription)
+ .theme(|_| Theme::Dark)
+ .antialiased()
+ .run()
}
struct Arc {
@@ -27,30 +24,9 @@ enum Message {
Tick,
}
-impl Application for Arc {
- type Executor = executor::Default;
- type Message = Message;
- type Theme = Theme;
- type Flags = ();
-
- fn new(_flags: ()) -> (Self, Command<Message>) {
- (
- Arc {
- start: Instant::now(),
- cache: Cache::default(),
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- String::from("Arc - Iced")
- }
-
- fn update(&mut self, _: Message) -> Command<Message> {
+impl Arc {
+ fn update(&mut self, _: Message) {
self.cache.clear();
-
- Command::none()
}
fn view(&self) -> Element<Message> {
@@ -60,16 +36,21 @@ impl Application for Arc {
.into()
}
- fn theme(&self) -> Theme {
- Theme::Dark
- }
-
fn subscription(&self) -> Subscription<Message> {
iced::time::every(std::time::Duration::from_millis(10))
.map(|_| Message::Tick)
}
}
+impl Default for Arc {
+ fn default() -> Self {
+ Arc {
+ start: Instant::now(),
+ cache: Cache::default(),
+ }
+ }
+}
+
impl<Message> canvas::Program<Message> for Arc {
type State = ();
diff --git a/examples/bezier_tool/src/main.rs b/examples/bezier_tool/src/main.rs
index 897e7df8..1d9f7ddb 100644
--- a/examples/bezier_tool/src/main.rs
+++ b/examples/bezier_tool/src/main.rs
@@ -1,12 +1,11 @@
//! This example showcases an interactive `Canvas` for drawing Bézier curves.
use iced::widget::{button, column, text};
-use iced::{Alignment, Element, Length, Sandbox, Settings};
+use iced::{Alignment, Element, Length};
pub fn main() -> iced::Result {
- Example::run(Settings {
- antialiasing: true,
- ..Settings::default()
- })
+ iced::application("Bezier Tool - Iced", Example::update, Example::view)
+ .antialiased()
+ .run()
}
#[derive(Default)]
@@ -21,17 +20,7 @@ enum Message {
Clear,
}
-impl Sandbox for Example {
- type Message = Message;
-
- fn new() -> Self {
- Example::default()
- }
-
- fn title(&self) -> String {
- String::from("Bezier tool - Iced")
- }
-
+impl Example {
fn update(&mut self, message: Message) {
match message {
Message::AddCurve(curve) => {
diff --git a/examples/checkbox/src/main.rs b/examples/checkbox/src/main.rs
index ee745c03..6a3b9464 100644
--- a/examples/checkbox/src/main.rs
+++ b/examples/checkbox/src/main.rs
@@ -1,12 +1,12 @@
-use iced::executor;
-use iced::font::{self, Font};
use iced::widget::{checkbox, column, container, row, text};
-use iced::{Application, Command, Element, Length, Settings, Theme};
+use iced::{Element, Font, Length};
const ICON_FONT: Font = Font::with_name("icons");
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::application("Checkbox - Iced", Example::update, Example::view)
+ .font(include_bytes!("../fonts/icons.ttf").as_slice())
+ .run()
}
#[derive(Default)]
@@ -21,28 +21,10 @@ enum Message {
DefaultToggled(bool),
CustomToggled(bool),
StyledToggled(bool),
- FontLoaded(Result<(), font::Error>),
}
-impl Application for Example {
- type Message = Message;
- type Flags = ();
- type Executor = executor::Default;
- type Theme = Theme;
-
- fn new(_flags: Self::Flags) -> (Self, Command<Message>) {
- (
- Self::default(),
- font::load(include_bytes!("../fonts/icons.ttf").as_slice())
- .map(Message::FontLoaded),
- )
- }
-
- fn title(&self) -> String {
- String::from("Checkbox - Iced")
- }
-
- fn update(&mut self, message: Message) -> Command<Message> {
+impl Example {
+ fn update(&mut self, message: Message) {
match message {
Message::DefaultToggled(default) => {
self.default = default;
@@ -53,10 +35,7 @@ impl Application for Example {
Message::CustomToggled(custom) => {
self.custom = custom;
}
- Message::FontLoaded(_) => (),
}
-
- Command::none()
}
fn view(&self) -> Element<Message> {
diff --git a/examples/clock/src/main.rs b/examples/clock/src/main.rs
index 87da0c7e..e3f3fa34 100644
--- a/examples/clock/src/main.rs
+++ b/examples/clock/src/main.rs
@@ -1,17 +1,18 @@
-use iced::executor;
+use iced::alignment;
use iced::mouse;
use iced::widget::canvas::{stroke, Cache, Geometry, LineCap, Path, Stroke};
use iced::widget::{canvas, container};
use iced::{
- Application, Command, Element, Length, Point, Rectangle, Renderer,
- Settings, Subscription, Theme, Vector,
+ Degrees, Element, Font, Length, Point, Rectangle, Renderer, Subscription,
+ Theme, Vector,
};
pub fn main() -> iced::Result {
- Clock::run(Settings {
- antialiasing: true,
- ..Settings::default()
- })
+ iced::application("Clock - Iced", Clock::update, Clock::view)
+ .subscription(Clock::subscription)
+ .theme(Clock::theme)
+ .antialiased()
+ .run()
}
struct Clock {
@@ -24,28 +25,8 @@ enum Message {
Tick(time::OffsetDateTime),
}
-impl Application for Clock {
- type Executor = executor::Default;
- type Message = Message;
- type Theme = Theme;
- type Flags = ();
-
- fn new(_flags: ()) -> (Self, Command<Message>) {
- (
- Clock {
- now: time::OffsetDateTime::now_local()
- .unwrap_or_else(|_| time::OffsetDateTime::now_utc()),
- clock: Cache::default(),
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- String::from("Clock - Iced")
- }
-
- fn update(&mut self, message: Message) -> Command<Message> {
+impl Clock {
+ fn update(&mut self, message: Message) {
match message {
Message::Tick(local_time) => {
let now = local_time;
@@ -56,8 +37,6 @@ impl Application for Clock {
}
}
}
-
- Command::none()
}
fn view(&self) -> Element<Message> {
@@ -82,7 +61,18 @@ impl Application for Clock {
}
fn theme(&self) -> Theme {
- Theme::TokyoNight
+ Theme::ALL[(self.now.unix_timestamp() as usize / 60) % Theme::ALL.len()]
+ .clone()
+ }
+}
+
+impl Default for Clock {
+ fn default() -> Self {
+ Self {
+ now: time::OffsetDateTime::now_local()
+ .unwrap_or_else(|_| time::OffsetDateTime::now_utc()),
+ clock: Cache::default(),
+ }
}
}
@@ -145,8 +135,31 @@ impl<Message> canvas::Program<Message> for Clock {
});
frame.with_save(|frame| {
- frame.rotate(hand_rotation(self.now.second(), 60));
+ let rotation = hand_rotation(self.now.second(), 60);
+
+ frame.rotate(rotation);
frame.stroke(&long_hand, thin_stroke());
+
+ let rotate_factor = if rotation < 180.0 { 1.0 } else { -1.0 };
+
+ frame.rotate(Degrees(-90.0 * rotate_factor));
+ frame.fill_text(canvas::Text {
+ content: theme.to_string(),
+ size: (radius / 15.0).into(),
+ position: Point::new(
+ (0.78 * radius) * rotate_factor,
+ -width * 2.0,
+ ),
+ color: palette.primary.weak.text,
+ horizontal_alignment: if rotate_factor > 0.0 {
+ alignment::Horizontal::Right
+ } else {
+ alignment::Horizontal::Left
+ },
+ vertical_alignment: alignment::Vertical::Bottom,
+ font: Font::MONOSPACE,
+ ..canvas::Text::default()
+ });
});
});
@@ -154,8 +167,8 @@ impl<Message> canvas::Program<Message> for Clock {
}
}
-fn hand_rotation(n: u8, total: u8) -> f32 {
+fn hand_rotation(n: u8, total: u8) -> Degrees {
let turns = n as f32 / total as f32;
- 2.0 * std::f32::consts::PI * turns
+ Degrees(360.0 * turns)
}
diff --git a/examples/color_palette/src/main.rs b/examples/color_palette/src/main.rs
index 4150c641..b997563f 100644
--- a/examples/color_palette/src/main.rs
+++ b/examples/color_palette/src/main.rs
@@ -3,8 +3,8 @@ use iced::mouse;
use iced::widget::canvas::{self, Canvas, Frame, Geometry, Path};
use iced::widget::{column, row, text, Slider};
use iced::{
- Color, Element, Font, Length, Pixels, Point, Rectangle, Renderer, Sandbox,
- Settings, Size, Vector,
+ Color, Element, Font, Length, Pixels, Point, Rectangle, Renderer, Size,
+ Vector,
};
use palette::{
self, convert::FromColor, rgb::Rgb, Darken, Hsl, Lighten, ShiftHue,
@@ -13,11 +13,15 @@ use std::marker::PhantomData;
use std::ops::RangeInclusive;
pub fn main() -> iced::Result {
- ColorPalette::run(Settings {
- antialiasing: true,
- default_font: Font::MONOSPACE,
- ..Settings::default()
- })
+ iced::application(
+ "Color Palette - Iced",
+ ColorPalette::update,
+ ColorPalette::view,
+ )
+ .theme(ColorPalette::theme)
+ .default_font(Font::MONOSPACE)
+ .antialiased()
+ .run()
}
#[derive(Default)]
@@ -41,17 +45,7 @@ pub enum Message {
LchColorChanged(palette::Lch),
}
-impl Sandbox for ColorPalette {
- type Message = Message;
-
- fn new() -> Self {
- Self::default()
- }
-
- fn title(&self) -> String {
- String::from("Color palette - Iced")
- }
-
+impl ColorPalette {
fn update(&mut self, message: Message) {
let srgb = match message {
Message::RgbColorChanged(rgb) => Rgb::from(rgb),
diff --git a/examples/combo_box/src/main.rs b/examples/combo_box/src/main.rs
index fcf5feaa..2feb4522 100644
--- a/examples/combo_box/src/main.rs
+++ b/examples/combo_box/src/main.rs
@@ -1,10 +1,10 @@
use iced::widget::{
column, combo_box, container, scrollable, text, vertical_space,
};
-use iced::{Alignment, Element, Length, Sandbox, Settings};
+use iced::{Alignment, Element, Length};
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::run("Combo Box - Iced", Example::update, Example::view)
}
struct Example {
@@ -20,9 +20,7 @@ enum Message {
Closed,
}
-impl Sandbox for Example {
- type Message = Message;
-
+impl Example {
fn new() -> Self {
Self {
languages: combo_box::State::new(Language::ALL.to_vec()),
@@ -31,10 +29,6 @@ impl Sandbox for Example {
}
}
- fn title(&self) -> String {
- String::from("Combo box - Iced")
- }
-
fn update(&mut self, message: Message) {
match message {
Message::Selected(language) => {
@@ -83,6 +77,12 @@ impl Sandbox for Example {
}
}
+impl Default for Example {
+ fn default() -> Self {
+ Example::new()
+ }
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Language {
Danish,
diff --git a/examples/component/src/main.rs b/examples/component/src/main.rs
index d4f99798..43ba3187 100644
--- a/examples/component/src/main.rs
+++ b/examples/component/src/main.rs
@@ -1,10 +1,10 @@
use iced::widget::container;
-use iced::{Element, Length, Sandbox, Settings};
+use iced::{Element, Length};
use numeric_input::numeric_input;
pub fn main() -> iced::Result {
- Component::run(Settings::default())
+ iced::run("Component - Iced", Component::update, Component::view)
}
#[derive(Default)]
@@ -17,17 +17,7 @@ enum Message {
NumericInputChanged(Option<u32>),
}
-impl Sandbox for Component {
- type Message = Message;
-
- fn new() -> Self {
- Self::default()
- }
-
- fn title(&self) -> String {
- String::from("Component - Iced")
- }
-
+impl Component {
fn update(&mut self, message: Message) {
match message {
Message::NumericInputChanged(value) => {
diff --git a/examples/counter/src/main.rs b/examples/counter/src/main.rs
index 13dcbf86..0dd7a976 100644
--- a/examples/counter/src/main.rs
+++ b/examples/counter/src/main.rs
@@ -1,50 +1,40 @@
-use iced::widget::{button, column, text};
-use iced::{Alignment, Element, Sandbox, Settings};
+use iced::widget::{button, column, text, Column};
+use iced::Alignment;
pub fn main() -> iced::Result {
- Counter::run(Settings::default())
+ iced::run("A cool counter", Counter::update, Counter::view)
}
+#[derive(Default)]
struct Counter {
- value: i32,
+ value: i64,
}
#[derive(Debug, Clone, Copy)]
enum Message {
- IncrementPressed,
- DecrementPressed,
+ Increment,
+ Decrement,
}
-impl Sandbox for Counter {
- type Message = Message;
-
- fn new() -> Self {
- Self { value: 0 }
- }
-
- fn title(&self) -> String {
- String::from("Counter - Iced")
- }
-
+impl Counter {
fn update(&mut self, message: Message) {
match message {
- Message::IncrementPressed => {
+ Message::Increment => {
self.value += 1;
}
- Message::DecrementPressed => {
+ Message::Decrement => {
self.value -= 1;
}
}
}
- fn view(&self) -> Element<Message> {
+ fn view(&self) -> Column<Message> {
column![
- button("Increment").on_press(Message::IncrementPressed),
+ button("Increment").on_press(Message::Increment),
text(self.value).size(50),
- button("Decrement").on_press(Message::DecrementPressed)
+ button("Decrement").on_press(Message::Decrement)
]
.padding(20)
.align_items(Alignment::Center)
- .into()
}
}
diff --git a/examples/custom_quad/src/main.rs b/examples/custom_quad/src/main.rs
index f64379fa..c093e240 100644
--- a/examples/custom_quad/src/main.rs
+++ b/examples/custom_quad/src/main.rs
@@ -82,12 +82,10 @@ mod quad {
}
use iced::widget::{column, container, slider, text};
-use iced::{
- Alignment, Color, Element, Length, Sandbox, Settings, Shadow, Vector,
-};
+use iced::{Alignment, Color, Element, Length, Shadow, Vector};
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::run("Custom Quad - Iced", Example::update, Example::view)
}
struct Example {
@@ -109,9 +107,7 @@ enum Message {
ShadowBlurRadiusChanged(f32),
}
-impl Sandbox for Example {
- type Message = Message;
-
+impl Example {
fn new() -> Self {
Self {
radius: [50.0; 4],
@@ -124,10 +120,6 @@ impl Sandbox for Example {
}
}
- fn title(&self) -> String {
- String::from("Custom widget - Iced")
- }
-
fn update(&mut self, message: Message) {
let [tl, tr, br, bl] = self.radius;
match message {
@@ -203,3 +195,9 @@ impl Sandbox for Example {
.into()
}
}
+
+impl Default for Example {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/examples/custom_shader/src/main.rs b/examples/custom_shader/src/main.rs
index 9e8da3ba..4457a15a 100644
--- a/examples/custom_shader/src/main.rs
+++ b/examples/custom_shader/src/main.rs
@@ -2,18 +2,20 @@ mod scene;
use scene::Scene;
-use iced::executor;
use iced::time::Instant;
use iced::widget::shader::wgpu;
use iced::widget::{checkbox, column, container, row, shader, slider, text};
use iced::window;
-use iced::{
- Alignment, Application, Color, Command, Element, Length, Subscription,
- Theme,
-};
+use iced::{Alignment, Color, Element, Length, Subscription};
fn main() -> iced::Result {
- IcedCubes::run(iced::Settings::default())
+ iced::application(
+ "Custom Shader - Iced",
+ IcedCubes::update,
+ IcedCubes::view,
+ )
+ .subscription(IcedCubes::subscription)
+ .run()
}
struct IcedCubes {
@@ -30,27 +32,15 @@ enum Message {
LightColorChanged(Color),
}
-impl Application for IcedCubes {
- type Executor = executor::Default;
- type Message = Message;
- type Theme = Theme;
- type Flags = ();
-
- fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) {
- (
- Self {
- start: Instant::now(),
- scene: Scene::new(),
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- "Iced Cubes".to_string()
+impl IcedCubes {
+ fn new() -> Self {
+ Self {
+ start: Instant::now(),
+ scene: Scene::new(),
+ }
}
- fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
+ fn update(&mut self, message: Message) {
match message {
Message::CubeAmountChanged(amount) => {
self.scene.change_amount(amount);
@@ -68,11 +58,9 @@ impl Application for IcedCubes {
self.scene.light_color = color;
}
}
-
- Command::none()
}
- fn view(&self) -> Element<'_, Self::Message> {
+ fn view(&self) -> Element<'_, Message> {
let top_controls = row![
control(
"Amount",
@@ -147,11 +135,17 @@ impl Application for IcedCubes {
.into()
}
- fn subscription(&self) -> Subscription<Self::Message> {
+ fn subscription(&self) -> Subscription<Message> {
window::frames().map(Message::Tick)
}
}
+impl Default for IcedCubes {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
fn control<'a>(
label: &'static str,
control: impl Into<Element<'a, Message>>,
diff --git a/examples/custom_widget/src/main.rs b/examples/custom_widget/src/main.rs
index 305ef7dd..aa49ebd0 100644
--- a/examples/custom_widget/src/main.rs
+++ b/examples/custom_widget/src/main.rs
@@ -83,10 +83,10 @@ mod circle {
use circle::circle;
use iced::widget::{column, container, slider, text};
-use iced::{Alignment, Element, Length, Sandbox, Settings};
+use iced::{Alignment, Element, Length};
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::run("Custom Widget - Iced", Example::update, Example::view)
}
struct Example {
@@ -98,17 +98,11 @@ enum Message {
RadiusChanged(f32),
}
-impl Sandbox for Example {
- type Message = Message;
-
+impl Example {
fn new() -> Self {
Example { radius: 50.0 }
}
- fn title(&self) -> String {
- String::from("Custom widget - Iced")
- }
-
fn update(&mut self, message: Message) {
match message {
Message::RadiusChanged(radius) => {
@@ -136,3 +130,9 @@ impl Sandbox for Example {
.into()
}
}
+
+impl Default for Example {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/examples/download_progress/src/main.rs b/examples/download_progress/src/main.rs
index 675e9e26..8d7994c8 100644
--- a/examples/download_progress/src/main.rs
+++ b/examples/download_progress/src/main.rs
@@ -1,14 +1,16 @@
-use iced::executor;
-use iced::widget::{button, column, container, progress_bar, text, Column};
-use iced::{
- Alignment, Application, Command, Element, Length, Settings, Subscription,
- Theme,
-};
-
mod download;
+use iced::widget::{button, column, container, progress_bar, text, Column};
+use iced::{Alignment, Element, Length, Subscription};
+
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::application(
+ "Download Progress - Iced",
+ Example::update,
+ Example::view,
+ )
+ .subscription(Example::subscription)
+ .run()
}
#[derive(Debug)]
@@ -24,27 +26,15 @@ pub enum Message {
DownloadProgressed((usize, download::Progress)),
}
-impl Application for Example {
- type Message = Message;
- type Theme = Theme;
- type Executor = executor::Default;
- type Flags = ();
-
- fn new(_flags: ()) -> (Example, Command<Message>) {
- (
- Example {
- downloads: vec![Download::new(0)],
- last_id: 0,
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- String::from("Download progress - Iced")
+impl Example {
+ fn new() -> Self {
+ Self {
+ downloads: vec![Download::new(0)],
+ last_id: 0,
+ }
}
- fn update(&mut self, message: Message) -> Command<Message> {
+ fn update(&mut self, message: Message) {
match message {
Message::Add => {
self.last_id += 1;
@@ -63,9 +53,7 @@ impl Application for Example {
download.progress(progress);
}
}
- };
-
- Command::none()
+ }
}
fn subscription(&self) -> Subscription<Message> {
@@ -93,6 +81,12 @@ impl Application for Example {
}
}
+impl Default for Example {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
#[derive(Debug)]
struct Download {
id: usize,
diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs
index d5d496c7..6eb11cb8 100644
--- a/examples/events/src/main.rs
+++ b/examples/events/src/main.rs
@@ -1,21 +1,14 @@
use iced::alignment;
use iced::event::{self, Event};
-use iced::executor;
use iced::widget::{button, checkbox, container, text, Column};
use iced::window;
-use iced::{
- Alignment, Application, Command, Element, Length, Settings, Subscription,
- Theme,
-};
+use iced::{Alignment, Command, Element, Length, Subscription};
pub fn main() -> iced::Result {
- Events::run(Settings {
- window: window::Settings {
- exit_on_close_request: false,
- ..window::Settings::default()
- },
- ..Settings::default()
- })
+ iced::application("Events - Iced", Events::update, Events::view)
+ .subscription(Events::subscription)
+ .ignore_close_request()
+ .run()
}
#[derive(Debug, Default)]
@@ -31,20 +24,7 @@ enum Message {
Exit,
}
-impl Application for Events {
- type Message = Message;
- type Theme = Theme;
- type Executor = executor::Default;
- type Flags = ();
-
- fn new(_flags: ()) -> (Events, Command<Message>) {
- (Events::default(), Command::none())
- }
-
- fn title(&self) -> String {
- String::from("Events - Iced")
- }
-
+impl Events {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::EventOccurred(event) if self.enabled => {
diff --git a/examples/exit/src/main.rs b/examples/exit/src/main.rs
index ec618dc1..4948bd0f 100644
--- a/examples/exit/src/main.rs
+++ b/examples/exit/src/main.rs
@@ -1,10 +1,9 @@
-use iced::executor;
use iced::widget::{button, column, container};
use iced::window;
-use iced::{Alignment, Application, Command, Element, Length, Settings, Theme};
+use iced::{Alignment, Command, Element, Length};
pub fn main() -> iced::Result {
- Exit::run(Settings::default())
+ iced::application("Exit - Iced", Exit::update, Exit::view).run()
}
#[derive(Default)]
@@ -18,20 +17,7 @@ enum Message {
Exit,
}
-impl Application for Exit {
- type Executor = executor::Default;
- type Message = Message;
- type Theme = Theme;
- type Flags = ();
-
- fn new(_flags: ()) -> (Self, Command<Message>) {
- (Self::default(), Command::none())
- }
-
- fn title(&self) -> String {
- String::from("Exit - Iced")
- }
-
+impl Exit {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Confirm => window::close(window::Id::MAIN),
diff --git a/examples/geometry/src/main.rs b/examples/geometry/src/main.rs
index 1ccc4dd6..63efcbdd 100644
--- a/examples/geometry/src/main.rs
+++ b/examples/geometry/src/main.rs
@@ -147,51 +147,35 @@ mod rainbow {
}
use iced::widget::{column, container, scrollable};
-use iced::{Element, Length, Sandbox, Settings};
+use iced::{Element, Length};
use rainbow::rainbow;
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::run("Custom 2D Geometry - Iced", |_: &mut _, _| {}, view)
}
-struct Example;
-
-impl Sandbox for Example {
- type Message = ();
-
- fn new() -> Self {
- Self
- }
-
- 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 \
+fn view(_state: &()) -> 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 \
+ "Move your cursor over it, and see the center vertex \
follow you!",
- "Every Vertex2D defines its own color. You could use the \
+ "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);
-
- let scrollable =
- scrollable(container(content).width(Length::Fill).center_x());
-
- container(scrollable)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_y()
- .into()
- }
+ ]
+ .padding(20)
+ .spacing(20)
+ .max_width(500);
+
+ 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/layout/src/main.rs b/examples/layout/src/main.rs
index 17c51e3d..e6b521b2 100644
--- a/examples/layout/src/main.rs
+++ b/examples/layout/src/main.rs
@@ -1,4 +1,3 @@
-use iced::executor;
use iced::keyboard;
use iced::mouse;
use iced::widget::{
@@ -6,15 +5,18 @@ use iced::widget::{
row, scrollable, text,
};
use iced::{
- color, Alignment, Application, Command, Element, Font, Length, Point,
- Rectangle, Renderer, Settings, Subscription, Theme,
+ color, Alignment, Element, Font, Length, Point, Rectangle, Renderer,
+ Subscription, Theme,
};
pub fn main() -> iced::Result {
- Layout::run(Settings::default())
+ iced::application(Layout::title, Layout::update, Layout::view)
+ .subscription(Layout::subscription)
+ .theme(Layout::theme)
+ .run()
}
-#[derive(Debug)]
+#[derive(Default, Debug)]
struct Layout {
example: Example,
explain: bool,
@@ -29,28 +31,12 @@ enum Message {
ThemeSelected(Theme),
}
-impl Application for Layout {
- type Message = Message;
- type Theme = Theme;
- type Executor = executor::Default;
- type Flags = ();
-
- fn new(_flags: Self::Flags) -> (Self, Command<Message>) {
- (
- Self {
- example: Example::default(),
- explain: false,
- theme: Theme::Light,
- },
- Command::none(),
- )
- }
-
+impl Layout {
fn title(&self) -> String {
format!("{} - Layout - Iced", self.example.title)
}
- fn update(&mut self, message: Self::Message) -> Command<Message> {
+ fn update(&mut self, message: Message) {
match message {
Message::Next => {
self.example = self.example.next();
@@ -65,8 +51,6 @@ impl Application for Layout {
self.theme = theme;
}
}
-
- Command::none()
}
fn subscription(&self) -> Subscription<Message> {
diff --git a/examples/lazy/src/main.rs b/examples/lazy/src/main.rs
index 8758fa66..2d53df93 100644
--- a/examples/lazy/src/main.rs
+++ b/examples/lazy/src/main.rs
@@ -2,13 +2,13 @@ use iced::widget::{
button, column, horizontal_space, lazy, pick_list, row, scrollable, text,
text_input,
};
-use iced::{Element, Length, Sandbox, Settings};
+use iced::{Element, Length};
use std::collections::HashSet;
use std::hash::Hash;
pub fn main() -> iced::Result {
- App::run(Settings::default())
+ iced::run("Lazy - Iced", App::update, App::view)
}
struct App {
@@ -120,17 +120,7 @@ enum Message {
ItemColorChanged(Item, Color),
}
-impl Sandbox for App {
- type Message = Message;
-
- fn new() -> Self {
- Self::default()
- }
-
- fn title(&self) -> String {
- String::from("Lazy - Iced")
- }
-
+impl App {
fn update(&mut self, message: Message) {
match message {
Message::InputChanged(input) => {
diff --git a/examples/loading_spinners/src/main.rs b/examples/loading_spinners/src/main.rs
index 93a4605e..c3308134 100644
--- a/examples/loading_spinners/src/main.rs
+++ b/examples/loading_spinners/src/main.rs
@@ -1,6 +1,5 @@
-use iced::executor;
use iced::widget::{column, container, row, slider, text};
-use iced::{Application, Command, Element, Length, Settings, Theme};
+use iced::{Element, Length};
use std::time::Duration;
@@ -12,51 +11,31 @@ use circular::Circular;
use linear::Linear;
pub fn main() -> iced::Result {
- LoadingSpinners::run(Settings {
- antialiasing: true,
- ..Default::default()
- })
+ iced::application(
+ "Loading Spinners - Iced",
+ LoadingSpinners::update,
+ LoadingSpinners::view,
+ )
+ .antialiased()
+ .run()
}
struct LoadingSpinners {
cycle_duration: f32,
}
-impl Default for LoadingSpinners {
- fn default() -> Self {
- Self {
- cycle_duration: 2.0,
- }
- }
-}
-
#[derive(Debug, Clone, Copy)]
enum Message {
CycleDurationChanged(f32),
}
-impl Application for LoadingSpinners {
- type Message = Message;
- type Flags = ();
- type Executor = executor::Default;
- type Theme = Theme;
-
- fn new(_flags: Self::Flags) -> (Self, Command<Message>) {
- (Self::default(), Command::none())
- }
-
- fn title(&self) -> String {
- String::from("Loading Spinners - Iced")
- }
-
- fn update(&mut self, message: Message) -> Command<Message> {
+impl LoadingSpinners {
+ fn update(&mut self, message: Message) {
match message {
Message::CycleDurationChanged(duration) => {
self.cycle_duration = duration;
}
}
-
- Command::none()
}
fn view(&self) -> Element<Message> {
@@ -115,3 +94,11 @@ impl Application for LoadingSpinners {
.into()
}
}
+
+impl Default for LoadingSpinners {
+ fn default() -> Self {
+ Self {
+ cycle_duration: 2.0,
+ }
+ }
+}
diff --git a/examples/loupe/src/main.rs b/examples/loupe/src/main.rs
index 8602edb7..6a5ff123 100644
--- a/examples/loupe/src/main.rs
+++ b/examples/loupe/src/main.rs
@@ -1,39 +1,30 @@
use iced::widget::{button, column, container, text};
-use iced::{Alignment, Element, Length, Sandbox, Settings};
+use iced::{Alignment, Element, Length};
use loupe::loupe;
pub fn main() -> iced::Result {
- Counter::run(Settings::default())
+ iced::run("Loupe - Iced", Loupe::update, Loupe::view)
}
-struct Counter {
- value: i32,
+#[derive(Default)]
+struct Loupe {
+ value: i64,
}
#[derive(Debug, Clone, Copy)]
enum Message {
- IncrementPressed,
- DecrementPressed,
+ Increment,
+ Decrement,
}
-impl Sandbox for Counter {
- type Message = Message;
-
- fn new() -> Self {
- Self { value: 0 }
- }
-
- fn title(&self) -> String {
- String::from("Counter - Iced")
- }
-
+impl Loupe {
fn update(&mut self, message: Message) {
match message {
- Message::IncrementPressed => {
+ Message::Increment => {
self.value += 1;
}
- Message::DecrementPressed => {
+ Message::Decrement => {
self.value -= 1;
}
}
@@ -43,9 +34,9 @@ impl Sandbox for Counter {
container(loupe(
3.0,
column![
- button("Increment").on_press(Message::IncrementPressed),
+ button("Increment").on_press(Message::Increment),
text(self.value).size(50),
- button("Decrement").on_press(Message::DecrementPressed)
+ button("Decrement").on_press(Message::Decrement)
]
.padding(20)
.align_items(Alignment::Center),
diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs
index 956ad471..985c0ab9 100644
--- a/examples/multitouch/src/main.rs
+++ b/examples/multitouch/src/main.rs
@@ -2,101 +2,58 @@
//! a circle around each fingertip. This only works on touch-enabled
//! computers like Microsoft Surface.
use iced::mouse;
+use iced::touch;
use iced::widget::canvas::event;
use iced::widget::canvas::stroke::{self, Stroke};
use iced::widget::canvas::{self, Canvas, Geometry};
-use iced::{
- executor, touch, window, Application, Color, Command, Element, Length,
- Point, Rectangle, Renderer, Settings, Subscription, Theme,
-};
+use iced::{Color, Element, Length, Point, Rectangle, Renderer, Theme};
use std::collections::HashMap;
pub fn main() -> iced::Result {
tracing_subscriber::fmt::init();
- Multitouch::run(Settings {
- antialiasing: true,
- window: window::Settings {
- position: window::Position::Centered,
- ..window::Settings::default()
- },
- ..Settings::default()
- })
+ iced::application("Multitouch - Iced", Multitouch::update, Multitouch::view)
+ .antialiased()
+ .centered()
+ .run()
}
+#[derive(Default)]
struct Multitouch {
- state: State,
-}
-
-#[derive(Debug)]
-struct State {
cache: canvas::Cache,
fingers: HashMap<touch::Finger, Point>,
}
-impl State {
- fn new() -> Self {
- Self {
- cache: canvas::Cache::new(),
- fingers: HashMap::new(),
- }
- }
-}
-
#[derive(Debug)]
enum Message {
FingerPressed { id: touch::Finger, position: Point },
FingerLifted { id: touch::Finger },
}
-impl Application for Multitouch {
- type Executor = executor::Default;
- type Message = Message;
- type Theme = Theme;
- type Flags = ();
-
- fn new(_flags: ()) -> (Self, Command<Message>) {
- (
- Multitouch {
- state: State::new(),
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- String::from("Multitouch - Iced")
- }
-
- fn update(&mut self, message: Message) -> Command<Message> {
+impl Multitouch {
+ fn update(&mut self, message: Message) {
match message {
Message::FingerPressed { id, position } => {
- self.state.fingers.insert(id, position);
- self.state.cache.clear();
+ self.fingers.insert(id, position);
+ self.cache.clear();
}
Message::FingerLifted { id } => {
- self.state.fingers.remove(&id);
- self.state.cache.clear();
+ self.fingers.remove(&id);
+ self.cache.clear();
}
}
-
- Command::none()
- }
-
- fn subscription(&self) -> Subscription<Message> {
- Subscription::none()
}
fn view(&self) -> Element<Message> {
- Canvas::new(&self.state)
+ Canvas::new(self)
.width(Length::Fill)
.height(Length::Fill)
.into()
}
}
-impl canvas::Program<Message> for State {
+impl canvas::Program<Message> for Multitouch {
type State = ();
fn update(
diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs
index 5e728ce1..439e9ee5 100644
--- a/examples/pane_grid/src/main.rs
+++ b/examples/pane_grid/src/main.rs
@@ -1,17 +1,15 @@
use iced::alignment::{self, Alignment};
-use iced::executor;
use iced::keyboard;
use iced::widget::pane_grid::{self, PaneGrid};
use iced::widget::{
button, column, container, responsive, row, scrollable, text,
};
-use iced::{
- Application, Color, Command, Element, Length, Settings, Size, Subscription,
- Theme,
-};
+use iced::{Color, Element, Length, Size, Subscription};
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::application("Pane Grid - Iced", Example::update, Example::view)
+ .subscription(Example::subscription)
+ .run()
}
struct Example {
@@ -35,30 +33,18 @@ enum Message {
CloseFocused,
}
-impl Application for Example {
- type Message = Message;
- type Theme = Theme;
- type Executor = executor::Default;
- type Flags = ();
-
- fn new(_flags: ()) -> (Self, Command<Message>) {
+impl Example {
+ fn new() -> Self {
let (panes, _) = pane_grid::State::new(Pane::new(0));
- (
- Example {
- panes,
- panes_created: 1,
- focus: None,
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- String::from("Pane grid - Iced")
+ Example {
+ panes,
+ panes_created: 1,
+ focus: None,
+ }
}
- fn update(&mut self, message: Message) -> Command<Message> {
+ fn update(&mut self, message: Message) {
match message {
Message::Split(axis, pane) => {
let result =
@@ -132,8 +118,6 @@ impl Application for Example {
}
}
}
-
- Command::none()
}
fn subscription(&self) -> Subscription<Message> {
@@ -209,6 +193,12 @@ impl Application for Example {
}
}
+impl Default for Example {
+ fn default() -> Self {
+ Example::new()
+ }
+}
+
const PANE_ID_COLOR_UNFOCUSED: Color = Color::from_rgb(
0xFF as f32 / 255.0,
0xC7 as f32 / 255.0,
diff --git a/examples/pick_list/src/main.rs b/examples/pick_list/src/main.rs
index c40493e2..2be6f5b0 100644
--- a/examples/pick_list/src/main.rs
+++ b/examples/pick_list/src/main.rs
@@ -1,8 +1,8 @@
use iced::widget::{column, pick_list, scrollable, vertical_space};
-use iced::{Alignment, Element, Length, Sandbox, Settings};
+use iced::{Alignment, Element, Length};
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::run("Pick List - Iced", Example::update, Example::view)
}
#[derive(Default)]
@@ -15,17 +15,7 @@ enum Message {
LanguageSelected(Language),
}
-impl Sandbox for Example {
- type Message = Message;
-
- fn new() -> Self {
- Self::default()
- }
-
- fn title(&self) -> String {
- String::from("Pick list - Iced")
- }
-
+impl Example {
fn update(&mut self, message: Message) {
match message {
Message::LanguageSelected(language) => {
diff --git a/examples/pokedex/src/main.rs b/examples/pokedex/src/main.rs
index 193f85f2..c737b87e 100644
--- a/examples/pokedex/src/main.rs
+++ b/examples/pokedex/src/main.rs
@@ -1,15 +1,20 @@
use iced::futures;
use iced::widget::{self, column, container, image, row, text};
-use iced::{Alignment, Application, Command, Element, Length, Settings, Theme};
+use iced::{Alignment, Command, Element, Length};
pub fn main() -> iced::Result {
- Pokedex::run(Settings::default())
+ iced::application(Pokedex::title, Pokedex::update, Pokedex::view)
+ .load(Pokedex::search)
+ .run()
}
-#[derive(Debug)]
+#[derive(Debug, Default)]
enum Pokedex {
+ #[default]
Loading,
- Loaded { pokemon: Pokemon },
+ Loaded {
+ pokemon: Pokemon,
+ },
Errored,
}
@@ -19,17 +24,9 @@ enum Message {
Search,
}
-impl Application for Pokedex {
- type Message = Message;
- type Theme = Theme;
- type Executor = iced::executor::Default;
- type Flags = ();
-
- fn new(_flags: ()) -> (Pokedex, Command<Message>) {
- (
- Pokedex::Loading,
- Command::perform(Pokemon::search(), Message::PokemonFound),
- )
+impl Pokedex {
+ fn search() -> Command<Message> {
+ Command::perform(Pokemon::search(), Message::PokemonFound)
}
fn title(&self) -> String {
@@ -59,7 +56,7 @@ impl Application for Pokedex {
_ => {
*self = Pokedex::Loading;
- Command::perform(Pokemon::search(), Message::PokemonFound)
+ Self::search()
}
},
}
diff --git a/examples/progress_bar/src/main.rs b/examples/progress_bar/src/main.rs
index d4ebe4d3..67da62f2 100644
--- a/examples/progress_bar/src/main.rs
+++ b/examples/progress_bar/src/main.rs
@@ -1,8 +1,8 @@
use iced::widget::{column, progress_bar, slider};
-use iced::{Element, Sandbox, Settings};
+use iced::Element;
pub fn main() -> iced::Result {
- Progress::run(Settings::default())
+ iced::run("Progress Bar - Iced", Progress::update, Progress::view)
}
#[derive(Default)]
@@ -15,17 +15,7 @@ enum Message {
SliderChanged(f32),
}
-impl Sandbox for Progress {
- type Message = Message;
-
- fn new() -> Self {
- Self::default()
- }
-
- fn title(&self) -> String {
- String::from("A simple Progressbar")
- }
-
+impl Progress {
fn update(&mut self, message: Message) {
match message {
Message::SliderChanged(x) => self.value = x,
diff --git a/examples/qr_code/src/main.rs b/examples/qr_code/src/main.rs
index 36f79a31..1a23331d 100644
--- a/examples/qr_code/src/main.rs
+++ b/examples/qr_code/src/main.rs
@@ -1,10 +1,16 @@
use iced::widget::{
column, container, pick_list, qr_code, row, text, text_input,
};
-use iced::{Alignment, Element, Length, Sandbox, Settings, Theme};
+use iced::{Alignment, Element, Length, Theme};
pub fn main() -> iced::Result {
- QRGenerator::run(Settings::default())
+ iced::application(
+ "QR Code Generator - Iced",
+ QRGenerator::update,
+ QRGenerator::view,
+ )
+ .theme(QRGenerator::theme)
+ .run()
}
#[derive(Default)]
@@ -20,17 +26,7 @@ enum Message {
ThemeChanged(Theme),
}
-impl Sandbox for QRGenerator {
- type Message = Message;
-
- fn new() -> Self {
- QRGenerator::default()
- }
-
- fn title(&self) -> String {
- String::from("QR Code Generator - Iced")
- }
-
+impl QRGenerator {
fn update(&mut self, message: Message) {
match message {
Message::DataChanged(mut data) => {
diff --git a/examples/screenshot/src/main.rs b/examples/screenshot/src/main.rs
index 2a1eded7..296a7f54 100644
--- a/examples/screenshot/src/main.rs
+++ b/examples/screenshot/src/main.rs
@@ -1,12 +1,10 @@
use iced::alignment;
-use iced::executor;
use iced::keyboard;
use iced::widget::{button, column, container, image, row, text, text_input};
use iced::window;
use iced::window::screenshot::{self, Screenshot};
use iced::{
- Alignment, Application, Command, ContentFit, Element, Length, Rectangle,
- Subscription, Theme,
+ Alignment, Command, ContentFit, Element, Length, Rectangle, Subscription,
};
use ::image as img;
@@ -15,9 +13,12 @@ use ::image::ColorType;
fn main() -> iced::Result {
tracing_subscriber::fmt::init();
- Example::run(iced::Settings::default())
+ iced::application("Screenshot - Iced", Example::update, Example::view)
+ .subscription(Example::subscription)
+ .run()
}
+#[derive(Default)]
struct Example {
screenshot: Option<Screenshot>,
saved_png_path: Option<Result<String, PngError>>,
@@ -42,33 +43,8 @@ enum Message {
HeightInputChanged(Option<u32>),
}
-impl Application for Example {
- type Executor = executor::Default;
- type Message = Message;
- type Theme = Theme;
- type Flags = ();
-
- fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) {
- (
- Example {
- screenshot: None,
- saved_png_path: None,
- png_saving: false,
- crop_error: None,
- x_input_value: None,
- y_input_value: None,
- width_input_value: None,
- height_input_value: None,
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- "Screenshot".to_string()
- }
-
- fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
+impl Example {
+ fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Screenshot => {
return iced::window::screenshot(
@@ -130,7 +106,7 @@ impl Application for Example {
Command::none()
}
- fn view(&self) -> Element<'_, Self::Message> {
+ fn view(&self) -> Element<'_, Message> {
let image: Element<Message> = if let Some(screenshot) = &self.screenshot
{
image(image::Handle::from_pixels(
@@ -259,7 +235,7 @@ impl Application for Example {
.into()
}
- fn subscription(&self) -> Subscription<Self::Message> {
+ fn subscription(&self) -> Subscription<Message> {
use keyboard::key;
keyboard::on_key_press(|key, _modifiers| {
diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs
index 2ad7272b..a6f3c689 100644
--- a/examples/scrollable/src/main.rs
+++ b/examples/scrollable/src/main.rs
@@ -1,20 +1,22 @@
-use iced::executor;
use iced::widget::scrollable::Properties;
use iced::widget::{
button, column, container, horizontal_space, progress_bar, radio, row,
scrollable, slider, text, vertical_space, Scrollable,
};
-use iced::{
- Alignment, Application, Border, Color, Command, Element, Length, Settings,
- Theme,
-};
+use iced::{Alignment, Border, Color, Command, Element, Length, Theme};
use once_cell::sync::Lazy;
static SCROLLABLE_ID: Lazy<scrollable::Id> = Lazy::new(scrollable::Id::unique);
pub fn main() -> iced::Result {
- ScrollableDemo::run(Settings::default())
+ iced::application(
+ "Scrollable - Iced",
+ ScrollableDemo::update,
+ ScrollableDemo::view,
+ )
+ .theme(ScrollableDemo::theme)
+ .run()
}
struct ScrollableDemo {
@@ -45,28 +47,16 @@ enum Message {
Scrolled(scrollable::Viewport),
}
-impl Application for ScrollableDemo {
- type Executor = executor::Default;
- type Message = Message;
- type Theme = Theme;
- type Flags = ();
-
- fn new(_flags: Self::Flags) -> (Self, Command<Message>) {
- (
- ScrollableDemo {
- scrollable_direction: Direction::Vertical,
- scrollbar_width: 10,
- scrollbar_margin: 0,
- scroller_width: 10,
- current_scroll_offset: scrollable::RelativeOffset::START,
- alignment: scrollable::Alignment::Start,
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- String::from("Scrollable - Iced")
+impl ScrollableDemo {
+ fn new() -> Self {
+ ScrollableDemo {
+ scrollable_direction: Direction::Vertical,
+ scrollbar_width: 10,
+ scrollbar_margin: 0,
+ scroller_width: 10,
+ current_scroll_offset: scrollable::RelativeOffset::START,
+ alignment: scrollable::Alignment::Start,
+ }
}
fn update(&mut self, message: Message) -> Command<Message> {
@@ -340,11 +330,17 @@ impl Application for ScrollableDemo {
container(content).padding(20).center_x().center_y().into()
}
- fn theme(&self) -> Self::Theme {
+ fn theme(&self) -> Theme {
Theme::Dark
}
}
+impl Default for ScrollableDemo {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
fn progress_bar_custom_style(theme: &Theme) -> progress_bar::Appearance {
progress_bar::Appearance {
background: theme.extended_palette().background.strong.color.into(),
diff --git a/examples/sierpinski_triangle/src/main.rs b/examples/sierpinski_triangle/src/main.rs
index 01a114bb..ee3039d8 100644
--- a/examples/sierpinski_triangle/src/main.rs
+++ b/examples/sierpinski_triangle/src/main.rs
@@ -1,25 +1,23 @@
-use std::fmt::Debug;
-
-use iced::executor;
use iced::mouse;
use iced::widget::canvas::event::{self, Event};
use iced::widget::canvas::{self, Canvas};
use iced::widget::{column, row, slider, text};
-use iced::{
- Application, Color, Command, Length, Point, Rectangle, Renderer, Settings,
- Size, Theme,
-};
+use iced::{Color, Length, Point, Rectangle, Renderer, Size, Theme};
use rand::Rng;
+use std::fmt::Debug;
fn main() -> iced::Result {
- SierpinskiEmulator::run(Settings {
- antialiasing: true,
- ..Settings::default()
- })
+ iced::application(
+ "Sierpinski Triangle - Iced",
+ SierpinskiEmulator::update,
+ SierpinskiEmulator::view,
+ )
+ .antialiased()
+ .run()
}
-#[derive(Debug)]
+#[derive(Debug, Default)]
struct SierpinskiEmulator {
graph: SierpinskiGraph,
}
@@ -31,27 +29,8 @@ pub enum Message {
PointRemoved,
}
-impl Application for SierpinskiEmulator {
- type Executor = executor::Default;
- type Message = Message;
- type Theme = Theme;
- type Flags = ();
-
- fn new(_flags: Self::Flags) -> (Self, iced::Command<Self::Message>) {
- let emulator = SierpinskiEmulator {
- graph: SierpinskiGraph::new(),
- };
- (emulator, Command::none())
- }
-
- fn title(&self) -> String {
- "Sierpinski Triangle Emulator".to_string()
- }
-
- fn update(
- &mut self,
- message: Self::Message,
- ) -> iced::Command<Self::Message> {
+impl SierpinskiEmulator {
+ fn update(&mut self, message: Message) {
match message {
Message::IterationSet(cur_iter) => {
self.graph.iteration = cur_iter;
@@ -67,11 +46,9 @@ impl Application for SierpinskiEmulator {
}
self.graph.redraw();
-
- Command::none()
}
- fn view(&self) -> iced::Element<'_, Self::Message> {
+ fn view(&self) -> iced::Element<'_, Message> {
column![
Canvas::new(&self.graph)
.width(Length::Fill)
@@ -167,10 +144,6 @@ impl canvas::Program<Message> for SierpinskiGraph {
}
impl SierpinskiGraph {
- fn new() -> SierpinskiGraph {
- SierpinskiGraph::default()
- }
-
fn redraw(&mut self) {
self.cache.clear();
}
diff --git a/examples/slider/src/main.rs b/examples/slider/src/main.rs
index f71dac01..b3a47614 100644
--- a/examples/slider/src/main.rs
+++ b/examples/slider/src/main.rs
@@ -1,8 +1,8 @@
use iced::widget::{column, container, slider, text, vertical_slider};
-use iced::{Element, Length, Sandbox, Settings};
+use iced::{Element, Length};
pub fn main() -> iced::Result {
- Slider::run(Settings::default())
+ iced::run("Slider - Iced", Slider::update, Slider::view)
}
#[derive(Debug, Clone)]
@@ -17,10 +17,8 @@ pub struct Slider {
shift_step: u8,
}
-impl Sandbox for Slider {
- type Message = Message;
-
- fn new() -> Slider {
+impl Slider {
+ fn new() -> Self {
Slider {
value: 50,
default: 50,
@@ -29,10 +27,6 @@ impl Sandbox for Slider {
}
}
- fn title(&self) -> String {
- String::from("Slider - Iced")
- }
-
fn update(&mut self, message: Message) {
match message {
Message::SliderChanged(value) => {
@@ -75,3 +69,9 @@ impl Sandbox for Slider {
.into()
}
}
+
+impl Default for Slider {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs
index 4cc625da..40fd6b12 100644
--- a/examples/solar_system/src/main.rs
+++ b/examples/solar_system/src/main.rs
@@ -6,8 +6,6 @@
//! Inspired by the example found in the MDN docs[1].
//!
//! [1]: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations#An_animated_solar_system
-use iced::application;
-use iced::executor;
use iced::mouse;
use iced::widget::canvas;
use iced::widget::canvas::gradient;
@@ -15,8 +13,8 @@ use iced::widget::canvas::stroke::{self, Stroke};
use iced::widget::canvas::Path;
use iced::window;
use iced::{
- Application, Color, Command, Element, Length, Point, Rectangle, Renderer,
- Settings, Size, Subscription, Theme, Vector,
+ Color, Element, Length, Point, Rectangle, Renderer, Size, Subscription,
+ Theme, Vector,
};
use std::time::Instant;
@@ -24,12 +22,17 @@ use std::time::Instant;
pub fn main() -> iced::Result {
tracing_subscriber::fmt::init();
- SolarSystem::run(Settings {
- antialiasing: true,
- ..Settings::default()
- })
+ iced::application(
+ "Solar System - Iced",
+ SolarSystem::update,
+ SolarSystem::view,
+ )
+ .subscription(SolarSystem::subscription)
+ .theme(SolarSystem::theme)
+ .run()
}
+#[derive(Default)]
struct SolarSystem {
state: State,
}
@@ -39,33 +42,13 @@ enum Message {
Tick(Instant),
}
-impl Application for SolarSystem {
- type Executor = executor::Default;
- type Message = Message;
- type Theme = Theme;
- type Flags = ();
-
- fn new(_flags: ()) -> (Self, Command<Message>) {
- (
- SolarSystem {
- state: State::new(),
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- String::from("Solar system - Iced")
- }
-
- fn update(&mut self, message: Message) -> Command<Message> {
+impl SolarSystem {
+ fn update(&mut self, message: Message) {
match message {
Message::Tick(instant) => {
self.state.update(instant);
}
}
-
- Command::none()
}
fn view(&self) -> Element<Message> {
@@ -76,14 +59,7 @@ impl Application for SolarSystem {
}
fn theme(&self) -> Theme {
- Theme::Dark
- }
-
- fn style(&self, _theme: &Theme) -> application::Appearance {
- application::Appearance {
- background_color: Color::BLACK,
- text_color: Color::WHITE,
- }
+ Theme::Moonfly
}
fn subscription(&self) -> Subscription<Message> {
@@ -224,3 +200,9 @@ impl<Message> canvas::Program<Message> for State {
vec![background, system]
}
}
+
+impl Default for State {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/examples/stopwatch/src/main.rs b/examples/stopwatch/src/main.rs
index 56b7686e..2496b85b 100644
--- a/examples/stopwatch/src/main.rs
+++ b/examples/stopwatch/src/main.rs
@@ -1,27 +1,31 @@
use iced::alignment;
-use iced::executor;
use iced::keyboard;
use iced::time;
use iced::widget::{button, column, container, row, text};
-use iced::{
- Alignment, Application, Command, Element, Length, Settings, Subscription,
- Theme,
-};
+use iced::{Alignment, Element, Length, Subscription, Theme};
use std::time::{Duration, Instant};
pub fn main() -> iced::Result {
- Stopwatch::run(Settings::default())
+ iced::application("Stopwatch - Iced", Stopwatch::update, Stopwatch::view)
+ .subscription(Stopwatch::subscription)
+ .theme(Stopwatch::theme)
+ .run()
}
+#[derive(Default)]
struct Stopwatch {
duration: Duration,
state: State,
}
+#[derive(Default)]
enum State {
+ #[default]
Idle,
- Ticking { last_tick: Instant },
+ Ticking {
+ last_tick: Instant,
+ },
}
#[derive(Debug, Clone)]
@@ -31,27 +35,8 @@ enum Message {
Tick(Instant),
}
-impl Application for Stopwatch {
- type Message = Message;
- type Theme = Theme;
- type Executor = executor::Default;
- type Flags = ();
-
- fn new(_flags: ()) -> (Stopwatch, Command<Message>) {
- (
- Stopwatch {
- duration: Duration::default(),
- state: State::Idle,
- },
- Command::none(),
- )
- }
-
- fn title(&self) -> String {
- String::from("Stopwatch - Iced")
- }
-
- fn update(&mut self, message: Message) -> Command<Message> {
+impl Stopwatch {
+ fn update(&mut self, message: Message) {
match message {
Message::Toggle => match self.state {
State::Idle => {
@@ -73,8 +58,6 @@ impl Application for Stopwatch {
self.duration = Duration::default();
}
}
-
- Command::none()
}
fn subscription(&self) -> Subscription<Message> {
diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs
index befdfc1b..ce14aacb 100644
--- a/examples/styling/src/main.rs
+++ b/examples/styling/src/main.rs
@@ -3,10 +3,12 @@ use iced::widget::{
progress_bar, row, scrollable, slider, text, text_input, toggler,
vertical_rule, vertical_space,
};
-use iced::{Alignment, Element, Length, Sandbox, Settings, Theme};
+use iced::{Alignment, Element, Length, Theme};
pub fn main() -> iced::Result {
- Styling::run(Settings::default())
+ iced::application("Styling - Iced", Styling::update, Styling::view)
+ .theme(Styling::theme)
+ .run()
}
#[derive(Default)]
@@ -28,17 +30,7 @@ enum Message {
TogglerToggled(bool),
}
-impl Sandbox for Styling {
- type Message = Message;
-
- fn new() -> Self {
- Styling::default()
- }
-
- fn title(&self) -> String {
- String::from("Styling - Iced")
- }
-
+impl Styling {
fn update(&mut self, message: Message) {
match message {
Message::ThemeChanged(theme) => {
diff --git a/examples/svg/src/main.rs b/examples/svg/src/main.rs
index 0870dce4..cc686dca 100644
--- a/examples/svg/src/main.rs
+++ b/examples/svg/src/main.rs
@@ -1,8 +1,8 @@
use iced::widget::{checkbox, column, container, svg};
-use iced::{color, Element, Length, Sandbox, Settings};
+use iced::{color, Element, Length};
pub fn main() -> iced::Result {
- Tiger::run(Settings::default())
+ iced::run("SVG - Iced", Tiger::update, Tiger::view)
}
#[derive(Debug, Default)]
@@ -15,18 +15,8 @@ pub enum Message {
ToggleColorFilter(bool),
}
-impl Sandbox for Tiger {
- type Message = Message;
-
- fn new() -> Self {
- Tiger::default()
- }
-
- fn title(&self) -> String {
- String::from("SVG - Iced")
- }
-
- fn update(&mut self, message: Self::Message) {
+impl Tiger {
+ fn update(&mut self, message: Message) {
match message {
Message::ToggleColorFilter(apply_color_filter) => {
self.apply_color_filter = apply_color_filter;
@@ -34,7 +24,7 @@ impl Sandbox for Tiger {
}
}
- fn view(&self) -> Element<Self::Message> {
+ fn view(&self) -> Element<Message> {
let handle = svg::Handle::from_path(format!(
"{}/resources/tiger.svg",
env!("CARGO_MANIFEST_DIR")
diff --git a/examples/system_information/src/main.rs b/examples/system_information/src/main.rs
index 31dc92f1..75a4d8d6 100644
--- a/examples/system_information/src/main.rs
+++ b/examples/system_information/src/main.rs
@@ -1,18 +1,23 @@
use iced::widget::{button, column, container, text};
-use iced::{
- executor, system, Application, Command, Element, Length, Settings, Theme,
-};
-
-use bytesize::ByteSize;
+use iced::{system, Command, Element, Length};
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::application(
+ "System Information - Iced",
+ Example::update,
+ Example::view,
+ )
+ .run()
}
+#[derive(Default)]
#[allow(clippy::large_enum_variant)]
enum Example {
+ #[default]
Loading,
- Loaded { information: system::Information },
+ Loaded {
+ information: system::Information,
+ },
}
#[derive(Clone, Debug)]
@@ -22,23 +27,7 @@ enum Message {
Refresh,
}
-impl Application for Example {
- type Message = Message;
- type Theme = Theme;
- type Executor = executor::Default;
- type Flags = ();
-
- fn new(_flags: ()) -> (Self, Command<Message>) {
- (
- Self::Loading,
- system::fetch_information(Message::InformationReceived),
- )
- }
-
- fn title(&self) -> String {
- String::from("System Information - Iced")
- }
-
+impl Example {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Refresh => {
@@ -55,6 +44,8 @@ impl Application for Example {
}
fn view(&self) -> Element<Message> {
+ use bytesize::ByteSize;
+
let content: Element<_> = match self {
Example::Loading => text("Loading...").size(40).into(),
Example::Loaded { information } => {
diff --git a/examples/tooltip/src/main.rs b/examples/tooltip/src/main.rs
index ee757311..b6603068 100644
--- a/examples/tooltip/src/main.rs
+++ b/examples/tooltip/src/main.rs
@@ -1,12 +1,13 @@
use iced::widget::tooltip::Position;
use iced::widget::{button, container, tooltip};
-use iced::{Element, Length, Sandbox, Settings};
+use iced::{Element, Length};
pub fn main() -> iced::Result {
- Example::run(Settings::default())
+ iced::run("Tooltip - Iced", Tooltip::update, Tooltip::view)
}
-struct Example {
+#[derive(Default)]
+struct Tooltip {
position: Position,
}
@@ -15,28 +16,16 @@ enum Message {
ChangePosition,
}
-impl Sandbox for Example {
- type Message = Message;
-
- fn new() -> Self {
- Self {
- position: Position::Bottom,
- }
- }
-
- fn title(&self) -> String {
- String::from("Tooltip - Iced")
- }
-
+impl Tooltip {
fn update(&mut self, message: Message) {
match message {
Message::ChangePosition => {
let position = match &self.position {
- Position::FollowCursor => Position::Top,
Position::Top => Position::Bottom,
Position::Bottom => Position::Left,
Position::Left => Position::Right,
Position::Right => Position::FollowCursor,
+ Position::FollowCursor => Position::Top,
};
self.position = position;
diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs
index f5791ad7..97ce761c 100644
--- a/examples/tour/src/main.rs
+++ b/examples/tour/src/main.rs
@@ -4,7 +4,7 @@ use iced::widget::{
scrollable, slider, text, text_input, toggler, vertical_space,
};
use iced::widget::{Button, Column, Container, Slider};
-use iced::{Color, Element, Font, Length, Pixels, Sandbox, Settings};
+use iced::{Color, Element, Font, Length, Pixels};
pub fn main() -> iced::Result {
#[cfg(target_arch = "wasm32")]
@@ -16,7 +16,9 @@ pub fn main() -> iced::Result {
#[cfg(not(target_arch = "wasm32"))]
tracing_subscriber::fmt::init();
- Tour::run(Settings::default())
+ iced::application(Tour::title, Tour::update, Tour::view)
+ .centered()
+ .run()
}
pub struct Tour {
@@ -24,11 +26,9 @@ pub struct Tour {
debug: bool,
}
-impl Sandbox for Tour {
- type Message = Message;
-
- fn new() -> Tour {
- Tour {
+impl Tour {
+ fn new() -> Self {
+ Self {
steps: Steps::new(),
debug: false,
}
@@ -90,6 +90,12 @@ impl Sandbox for Tour {
}
}
+impl Default for Tour {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
#[derive(Debug, Clone)]
pub enum Message {
BackPressed,
diff --git a/examples/url_handler/src/main.rs b/examples/url_handler/src/main.rs
index bf570123..540d927e 100644
--- a/examples/url_handler/src/main.rs
+++ b/examples/url_handler/src/main.rs
@@ -1,12 +1,11 @@
use iced::event::{self, Event};
-use iced::executor;
use iced::widget::{container, text};
-use iced::{
- Application, Command, Element, Length, Settings, Subscription, Theme,
-};
+use iced::{Element, Length, Subscription};
pub fn main() -> iced::Result {
- App::run(Settings::default())
+ iced::application("URL Handler - Iced", App::update, App::view)
+ .subscription(App::subscription)
+ .run()
}
#[derive(Debug, Default)]
@@ -19,21 +18,8 @@ enum Message {
EventOccurred(Event),
}
-impl Application for App {
- type Message = Message;
- type Theme = Theme;
- type Executor = executor::Default;
- type Flags = ();
-
- fn new(_flags: ()) -> (App, Command<Message>) {
- (App::default(), Command::none())
- }
-
- fn title(&self) -> String {
- String::from("Url - Iced")
- }
-
- fn update(&mut self, message: Message) -> Command<Message> {
+impl App {
+ fn update(&mut self, message: Message) {
match message {
Message::EventOccurred(event) => {
if let Event::PlatformSpecific(
@@ -45,9 +31,7 @@ impl Application for App {
self.url = Some(url);
}
}
- };
-
- Command::none()
+ }
}
fn subscription(&self) -> Subscription<Message> {
diff --git a/examples/vectorial_text/src/main.rs b/examples/vectorial_text/src/main.rs
index 0b9ea938..37961635 100644
--- a/examples/vectorial_text/src/main.rs
+++ b/examples/vectorial_text/src/main.rs
@@ -3,18 +3,20 @@ use iced::mouse;
use iced::widget::{
canvas, checkbox, column, horizontal_space, row, slider, text,
};
-use iced::{
- Element, Length, Point, Rectangle, Renderer, Sandbox, Settings, Theme,
- Vector,
-};
+use iced::{Element, Length, Point, Rectangle, Renderer, Theme, Vector};
pub fn main() -> iced::Result {
- VectorialText::run(Settings {
- antialiasing: true,
- ..Settings::default()
- })
+ iced::application(
+ "Vectorial Text - Iced",
+ VectorialText::update,
+ VectorialText::view,
+ )
+ .theme(|_| Theme::Dark)
+ .antialiased()
+ .run()
}
+#[derive(Default)]
struct VectorialText {
state: State,
}
@@ -27,19 +29,7 @@ enum Message {
ToggleJapanese(bool),
}
-impl Sandbox for VectorialText {
- type Message = Message;
-
- fn new() -> Self {
- Self {
- state: State::new(),
- }
- }
-
- fn title(&self) -> String {
- String::from("Vectorial Text - Iced")
- }
-
+impl VectorialText {
fn update(&mut self, message: Message) {
match message {
Message::SizeChanged(size) => {
@@ -106,10 +96,6 @@ impl Sandbox for VectorialText {
.padding(20)
.into()
}
-
- fn theme(&self) -> Theme {
- Theme::Dark
- }
}
struct State {
@@ -170,3 +156,9 @@ impl<Message> canvas::Program<Message> for State {
vec![geometry]
}
}
+
+impl Default for State {
+ fn default() -> Self {
+ State::new()
+ }
+}
diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs
index f09ccfbf..36435148 100644
--- a/renderer/src/geometry.rs
+++ b/renderer/src/geometry.rs
@@ -2,7 +2,7 @@ mod cache;
pub use cache::Cache;
-use crate::core::{Point, Rectangle, Size, Transformation, Vector};
+use crate::core::{Point, Radians, Rectangle, Size, Transformation, Vector};
use crate::graphics::geometry::{Fill, Path, Stroke, Text};
use crate::Renderer;
@@ -184,7 +184,7 @@ impl Frame {
/// Applies a rotation in radians to the current transform of the [`Frame`].
#[inline]
- pub fn rotate(&mut self, angle: f32) {
+ pub fn rotate(&mut self, angle: impl Into<Radians>) {
delegate!(self, frame, frame.rotate(angle));
}
diff --git a/runtime/src/command.rs b/runtime/src/command.rs
index f70da915..f7a746fe 100644
--- a/runtime/src/command.rs
+++ b/runtime/src/command.rs
@@ -112,6 +112,12 @@ impl<T> Command<T> {
}
}
+impl<Message> From<()> for Command<Message> {
+ fn from(_value: ()) -> Self {
+ Self::none()
+ }
+}
+
impl<T> fmt::Debug for Command<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Command(command) = self;
diff --git a/src/lib.rs b/src/lib.rs
index c596f2a6..ae6bb344 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -175,6 +175,7 @@ mod error;
mod sandbox;
pub mod application;
+pub mod program;
pub mod settings;
pub mod time;
pub mod window;
@@ -308,6 +309,7 @@ pub use error::Error;
pub use event::Event;
pub use executor::Executor;
pub use font::Font;
+pub use program::Program;
pub use renderer::Renderer;
pub use sandbox::Sandbox;
pub use settings::Settings;
@@ -327,3 +329,49 @@ pub type Element<
///
/// [`Application`]: crate::Application
pub type Result = std::result::Result<(), Error>;
+
+/// Runs a basic iced application with default [`Settings`] given
+/// - its window title,
+/// - its update logic,
+/// - and its view logic.
+///
+/// # Example
+/// ```no_run
+/// use iced::widget::{button, column, text, Column};
+///
+/// pub fn main() -> iced::Result {
+/// iced::run("A counter", update, view)
+/// }
+///
+/// #[derive(Debug, Clone)]
+/// enum Message {
+/// Increment,
+/// }
+///
+/// fn update(value: &mut u64, message: Message) {
+/// match message {
+/// Message::Increment => *value += 1,
+/// }
+/// }
+///
+/// fn view(value: &u64) -> Column<Message> {
+/// column![
+/// text(value),
+/// button("+").on_press(Message::Increment),
+/// ]
+/// }
+/// ```
+pub fn run<State, Message>(
+ title: impl program::Title<State> + 'static,
+ update: impl program::Update<State, Message> + 'static,
+ view: impl for<'a> program::View<'a, State, Message> + 'static,
+) -> Result
+where
+ State: Default + 'static,
+ Message: std::fmt::Debug + Send + 'static,
+{
+ application(title, update, view).run()
+}
+
+#[doc(inline)]
+pub use program::application;
diff --git a/src/program.rs b/src/program.rs
new file mode 100644
index 00000000..c2841763
--- /dev/null
+++ b/src/program.rs
@@ -0,0 +1,687 @@
+//! Create iced applications out of simple functions.
+//!
+//! You can use this API to create and run iced applications
+//! step by step—without coupling your logic to a trait
+//! or a specific type.
+//!
+//! This API is meant to be a more convenient—although less
+//! powerful—alternative to the [`Sandbox`] and [`Application`] traits.
+//!
+//! [`Sandbox`]: crate::Sandbox
+//!
+//! # Example
+//! ```no_run
+//! use iced::widget::{button, column, text, Column};
+//! use iced::Theme;
+//!
+//! pub fn main() -> iced::Result {
+//! iced::application("A counter", update, view)
+//! .theme(|_| Theme::Dark)
+//! .centered()
+//! .run()
+//! }
+//!
+//! #[derive(Debug, Clone)]
+//! enum Message {
+//! Increment,
+//! }
+//!
+//! fn update(value: &mut u64, message: Message) {
+//! match message {
+//! Message::Increment => *value += 1,
+//! }
+//! }
+//!
+//! fn view(value: &u64) -> Column<Message> {
+//! column![
+//! text(value),
+//! button("+").on_press(Message::Increment),
+//! ]
+//! }
+//! ```
+use crate::application::{self, Application};
+use crate::executor::{self, Executor};
+use crate::window;
+use crate::{Command, Element, Font, Result, Settings, Subscription};
+
+use std::borrow::Cow;
+
+/// Creates an iced [`Program`] given its title, update, and view logic.
+///
+/// # Example
+/// ```no_run
+/// use iced::widget::{button, column, text, Column};
+///
+/// pub fn main() -> iced::Result {
+/// iced::application("A counter", update, view).run()
+/// }
+///
+/// #[derive(Debug, Clone)]
+/// enum Message {
+/// Increment,
+/// }
+///
+/// fn update(value: &mut u64, message: Message) {
+/// match message {
+/// Message::Increment => *value += 1,
+/// }
+/// }
+///
+/// fn view(value: &u64) -> Column<Message> {
+/// column![
+/// text(value),
+/// button("+").on_press(Message::Increment),
+/// ]
+/// }
+/// ```
+pub fn application<State, Message>(
+ title: impl Title<State>,
+ update: impl Update<State, Message>,
+ view: impl for<'a> self::View<'a, State, Message>,
+) -> Program<
+ impl Definition<State = State, Message = Message, Theme = crate::Theme>,
+>
+where
+ State: Default + 'static,
+ Message: Send + std::fmt::Debug,
+{
+ use std::marker::PhantomData;
+
+ struct Application<State, Message, Update, View> {
+ update: Update,
+ view: View,
+ _state: PhantomData<State>,
+ _message: PhantomData<Message>,
+ }
+
+ impl<State, Message, Update, View> Definition
+ for Application<State, Message, Update, View>
+ where
+ State: Default,
+ Message: Send + std::fmt::Debug,
+ Update: self::Update<State, Message>,
+ View: for<'a> self::View<'a, State, Message>,
+ {
+ type State = State;
+ type Message = Message;
+ type Theme = crate::Theme;
+ type Executor = executor::Default;
+
+ fn build(&self) -> (Self::State, Command<Self::Message>) {
+ (Self::State::default(), Command::none())
+ }
+
+ fn update(
+ &self,
+ state: &mut Self::State,
+ message: Self::Message,
+ ) -> Command<Self::Message> {
+ self.update.update(state, message).into()
+ }
+
+ fn view<'a>(
+ &self,
+ state: &'a Self::State,
+ ) -> Element<'a, Self::Message, Self::Theme> {
+ self.view.view(state).into()
+ }
+ }
+
+ Program {
+ raw: Application {
+ update,
+ view,
+ _state: PhantomData,
+ _message: PhantomData,
+ },
+ settings: Settings::default(),
+ }
+ .title(title)
+}
+
+/// A fully functioning and configured iced application.
+///
+/// It can be [`run`]!
+///
+/// Create one with the [`application`] helper.
+///
+/// [`run`]: Program::run
+/// [`application`]: self::application()
+#[derive(Debug)]
+pub struct Program<P: Definition> {
+ raw: P,
+ settings: Settings,
+}
+
+impl<P: Definition> Program<P> {
+ /// Runs the [`Program`].
+ pub fn run(self) -> Result
+ where
+ Self: 'static,
+ {
+ struct Instance<P: Definition> {
+ program: P,
+ state: P::State,
+ }
+
+ impl<P: Definition> Application for Instance<P> {
+ type Message = P::Message;
+ type Theme = P::Theme;
+ type Flags = P;
+ type Executor = P::Executor;
+
+ fn new(program: Self::Flags) -> (Self, Command<Self::Message>) {
+ let (state, command) = P::build(&program);
+
+ (Self { program, state }, command)
+ }
+
+ fn title(&self) -> String {
+ self.program.title(&self.state)
+ }
+
+ fn update(
+ &mut self,
+ message: Self::Message,
+ ) -> Command<Self::Message> {
+ self.program.update(&mut self.state, message)
+ }
+
+ fn view(
+ &self,
+ ) -> crate::Element<'_, Self::Message, Self::Theme, crate::Renderer>
+ {
+ self.program.view(&self.state)
+ }
+
+ fn theme(&self) -> Self::Theme {
+ self.program.theme(&self.state)
+ }
+
+ fn subscription(&self) -> Subscription<Self::Message> {
+ self.program.subscription(&self.state)
+ }
+ }
+
+ let Self { raw, settings } = self;
+
+ Instance::run(Settings {
+ flags: raw,
+ id: settings.id,
+ window: settings.window,
+ fonts: settings.fonts,
+ default_font: settings.default_font,
+ default_text_size: settings.default_text_size,
+ antialiasing: settings.antialiasing,
+ })
+ }
+
+ /// Sets the [`Settings`] that will be used to run the [`Program`].
+ pub fn settings(self, settings: Settings) -> Self {
+ Self { settings, ..self }
+ }
+
+ /// Toggles the [`Settings::antialiasing`] to `true` for the [`Program`].
+ pub fn antialiased(self) -> Self {
+ Self {
+ settings: Settings {
+ antialiasing: true,
+ ..self.settings
+ },
+ ..self
+ }
+ }
+
+ /// Sets the default [`Font`] of the [`Program`].
+ pub fn default_font(self, default_font: Font) -> Self {
+ Self {
+ settings: Settings {
+ default_font,
+ ..self.settings
+ },
+ ..self
+ }
+ }
+
+ /// Adds a font to the list of fonts that will be loaded at the start of the [`Program`].
+ pub fn font(mut self, font: impl Into<Cow<'static, [u8]>>) -> Self {
+ self.settings.fonts.push(font.into());
+ self
+ }
+
+ /// Sets the [`window::Settings::position`] to [`window::Position::Centered`] in the [`Program`].
+ pub fn centered(self) -> Self {
+ Self {
+ settings: Settings {
+ window: window::Settings {
+ position: window::Position::Centered,
+ ..self.settings.window
+ },
+ ..self.settings
+ },
+ ..self
+ }
+ }
+
+ /// Sets the [`window::Settings::exit_on_close_request`] to `false` in the [`Program`].
+ pub fn ignore_close_request(self) -> Self {
+ Self {
+ settings: Settings {
+ window: window::Settings {
+ exit_on_close_request: false,
+ ..self.settings.window
+ },
+ ..self.settings
+ },
+ ..self
+ }
+ }
+
+ /// Sets the [`Title`] of the [`Program`].
+ pub(crate) fn title(
+ self,
+ title: impl Title<P::State>,
+ ) -> Program<
+ impl Definition<State = P::State, Message = P::Message, Theme = P::Theme>,
+ > {
+ Program {
+ raw: with_title(self.raw, title),
+ settings: self.settings,
+ }
+ }
+
+ /// Runs the [`Command`] produced by the closure at startup.
+ pub fn load(
+ self,
+ f: impl Fn() -> Command<P::Message>,
+ ) -> Program<
+ impl Definition<State = P::State, Message = P::Message, Theme = P::Theme>,
+ > {
+ Program {
+ raw: with_load(self.raw, f),
+ settings: self.settings,
+ }
+ }
+
+ /// Sets the subscription logic of the [`Program`].
+ pub fn subscription(
+ self,
+ f: impl Fn(&P::State) -> Subscription<P::Message>,
+ ) -> Program<
+ impl Definition<State = P::State, Message = P::Message, Theme = P::Theme>,
+ > {
+ Program {
+ raw: with_subscription(self.raw, f),
+ settings: self.settings,
+ }
+ }
+
+ /// Sets the theme logic of the [`Program`].
+ pub fn theme(
+ self,
+ f: impl Fn(&P::State) -> P::Theme,
+ ) -> Program<
+ impl Definition<State = P::State, Message = P::Message, Theme = P::Theme>,
+ > {
+ Program {
+ raw: with_theme(self.raw, f),
+ settings: self.settings,
+ }
+ }
+}
+
+/// The internal definition of a [`Program`].
+///
+/// You should not need to implement this trait directly. Instead, use the
+/// helper functions available in the [`program`] module and the [`Program`] struct.
+///
+/// [`program`]: crate::program
+#[allow(missing_docs)]
+pub trait Definition: Sized {
+ /// The state of the program.
+ type State;
+
+ /// The message of the program.
+ type Message: Send + std::fmt::Debug;
+
+ /// The theme of the program.
+ type Theme: Default + application::DefaultStyle;
+
+ /// The executor of the program.
+ type Executor: Executor;
+
+ fn build(&self) -> (Self::State, Command<Self::Message>);
+
+ fn update(
+ &self,
+ state: &mut Self::State,
+ message: Self::Message,
+ ) -> Command<Self::Message>;
+
+ fn view<'a>(
+ &self,
+ state: &'a Self::State,
+ ) -> Element<'a, Self::Message, Self::Theme>;
+
+ fn title(&self, _state: &Self::State) -> String {
+ String::from("A cool iced application!")
+ }
+
+ fn subscription(
+ &self,
+ _state: &Self::State,
+ ) -> Subscription<Self::Message> {
+ Subscription::none()
+ }
+
+ fn theme(&self, _state: &Self::State) -> Self::Theme {
+ Self::Theme::default()
+ }
+}
+
+fn with_title<P: Definition>(
+ program: P,
+ title: impl Title<P::State>,
+) -> impl Definition<State = P::State, Message = P::Message, Theme = P::Theme> {
+ struct WithTitle<P, Title> {
+ program: P,
+ title: Title,
+ }
+
+ impl<P, Title> Definition for WithTitle<P, Title>
+ where
+ P: Definition,
+ Title: self::Title<P::State>,
+ {
+ type State = P::State;
+ type Message = P::Message;
+ type Theme = P::Theme;
+ type Executor = P::Executor;
+
+ fn build(&self) -> (Self::State, Command<Self::Message>) {
+ self.program.build()
+ }
+
+ fn title(&self, state: &Self::State) -> String {
+ self.title.title(state)
+ }
+
+ fn update(
+ &self,
+ state: &mut Self::State,
+ message: Self::Message,
+ ) -> Command<Self::Message> {
+ self.program.update(state, message)
+ }
+
+ fn view<'a>(
+ &self,
+ state: &'a Self::State,
+ ) -> Element<'a, Self::Message, Self::Theme> {
+ self.program.view(state)
+ }
+
+ fn theme(&self, state: &Self::State) -> Self::Theme {
+ self.program.theme(state)
+ }
+
+ fn subscription(
+ &self,
+ state: &Self::State,
+ ) -> Subscription<Self::Message> {
+ self.program.subscription(state)
+ }
+ }
+
+ WithTitle { program, title }
+}
+
+fn with_load<P: Definition>(
+ program: P,
+ f: impl Fn() -> Command<P::Message>,
+) -> impl Definition<State = P::State, Message = P::Message, Theme = P::Theme> {
+ struct WithLoad<P, F> {
+ program: P,
+ load: F,
+ }
+
+ impl<P: Definition, F> Definition for WithLoad<P, F>
+ where
+ F: Fn() -> Command<P::Message>,
+ {
+ type State = P::State;
+ type Message = P::Message;
+ type Theme = P::Theme;
+ type Executor = executor::Default;
+
+ fn build(&self) -> (Self::State, Command<Self::Message>) {
+ let (state, command) = self.program.build();
+
+ (state, Command::batch([command, (self.load)()]))
+ }
+
+ fn update(
+ &self,
+ state: &mut Self::State,
+ message: Self::Message,
+ ) -> Command<Self::Message> {
+ self.program.update(state, message)
+ }
+
+ fn view<'a>(
+ &self,
+ state: &'a Self::State,
+ ) -> Element<'a, Self::Message, Self::Theme> {
+ self.program.view(state)
+ }
+
+ fn title(&self, state: &Self::State) -> String {
+ self.program.title(state)
+ }
+
+ fn theme(&self, state: &Self::State) -> Self::Theme {
+ self.program.theme(state)
+ }
+
+ fn subscription(
+ &self,
+ state: &Self::State,
+ ) -> Subscription<Self::Message> {
+ self.program.subscription(state)
+ }
+ }
+
+ WithLoad { program, load: f }
+}
+
+fn with_subscription<P: Definition>(
+ program: P,
+ f: impl Fn(&P::State) -> Subscription<P::Message>,
+) -> impl Definition<State = P::State, Message = P::Message, Theme = P::Theme> {
+ struct WithSubscription<P, F> {
+ program: P,
+ subscription: F,
+ }
+
+ impl<P: Definition, F> Definition for WithSubscription<P, F>
+ where
+ F: Fn(&P::State) -> Subscription<P::Message>,
+ {
+ type State = P::State;
+ type Message = P::Message;
+ type Theme = P::Theme;
+ type Executor = executor::Default;
+
+ fn subscription(
+ &self,
+ state: &Self::State,
+ ) -> Subscription<Self::Message> {
+ (self.subscription)(state)
+ }
+
+ fn build(&self) -> (Self::State, Command<Self::Message>) {
+ self.program.build()
+ }
+
+ fn update(
+ &self,
+ state: &mut Self::State,
+ message: Self::Message,
+ ) -> Command<Self::Message> {
+ self.program.update(state, message)
+ }
+
+ fn view<'a>(
+ &self,
+ state: &'a Self::State,
+ ) -> Element<'a, Self::Message, Self::Theme> {
+ self.program.view(state)
+ }
+
+ fn title(&self, state: &Self::State) -> String {
+ self.program.title(state)
+ }
+
+ fn theme(&self, state: &Self::State) -> Self::Theme {
+ self.program.theme(state)
+ }
+ }
+
+ WithSubscription {
+ program,
+ subscription: f,
+ }
+}
+
+fn with_theme<P: Definition>(
+ program: P,
+ f: impl Fn(&P::State) -> P::Theme,
+) -> impl Definition<State = P::State, Message = P::Message, Theme = P::Theme> {
+ struct WithTheme<P, F> {
+ program: P,
+ theme: F,
+ }
+
+ impl<P: Definition, F> Definition for WithTheme<P, F>
+ where
+ F: Fn(&P::State) -> P::Theme,
+ {
+ type State = P::State;
+ type Message = P::Message;
+ type Theme = P::Theme;
+ type Executor = P::Executor;
+
+ fn theme(&self, state: &Self::State) -> Self::Theme {
+ (self.theme)(state)
+ }
+
+ fn build(&self) -> (Self::State, Command<Self::Message>) {
+ self.program.build()
+ }
+
+ fn title(&self, state: &Self::State) -> String {
+ self.program.title(state)
+ }
+
+ fn update(
+ &self,
+ state: &mut Self::State,
+ message: Self::Message,
+ ) -> Command<Self::Message> {
+ self.program.update(state, message)
+ }
+
+ fn view<'a>(
+ &self,
+ state: &'a Self::State,
+ ) -> Element<'a, Self::Message, Self::Theme> {
+ self.program.view(state)
+ }
+
+ fn subscription(
+ &self,
+ state: &Self::State,
+ ) -> Subscription<Self::Message> {
+ self.program.subscription(state)
+ }
+ }
+
+ WithTheme { program, theme: f }
+}
+
+/// The title logic of some [`Program`].
+///
+/// This trait is implemented both for `&static str` and
+/// any closure `Fn(&State) -> String`.
+///
+/// You can use any of these in [`Program::title`].
+pub trait Title<State> {
+ /// Produces the title of the [`Program`].
+ fn title(&self, state: &State) -> String;
+}
+
+impl<State> Title<State> for &'static str {
+ fn title(&self, _state: &State) -> String {
+ self.to_string()
+ }
+}
+
+impl<T, State> Title<State> for T
+where
+ T: Fn(&State) -> String,
+{
+ fn title(&self, state: &State) -> String {
+ self(state)
+ }
+}
+
+/// The update logic of some [`Program`].
+///
+/// This trait allows [`application`] to take any closure that
+/// returns any `Into<Command<Message>>`.
+///
+/// [`application`]: self::application()
+pub trait Update<State, Message> {
+ /// Processes the message and updates the state of the [`Program`].
+ fn update(
+ &self,
+ state: &mut State,
+ message: Message,
+ ) -> impl Into<Command<Message>>;
+}
+
+impl<T, State, Message, C> Update<State, Message> for T
+where
+ T: Fn(&mut State, Message) -> C,
+ C: Into<Command<Message>>,
+{
+ fn update(
+ &self,
+ state: &mut State,
+ message: Message,
+ ) -> impl Into<Command<Message>> {
+ self(state, message)
+ }
+}
+
+/// The view logic of some [`Program`].
+///
+/// This trait allows [`application`] to take any closure that
+/// returns any `Into<Element<'_, Message>>`.
+///
+/// [`application`]: self::application()
+pub trait View<'a, State, Message> {
+ /// Produces the widget of the [`Program`].
+ fn view(&self, state: &'a State) -> impl Into<Element<'a, Message>>;
+}
+
+impl<'a, T, State, Message, Widget> View<'a, State, Message> for T
+where
+ T: Fn(&'a State) -> Widget,
+ State: 'static,
+ Widget: Into<Element<'a, Message>>,
+{
+ fn view(&self, state: &'a State) -> impl Into<Element<'a, Message>> {
+ self(state)
+ }
+}
diff --git a/src/settings.rs b/src/settings.rs
index d9476b61..92204847 100644
--- a/src/settings.rs
+++ b/src/settings.rs
@@ -6,7 +6,7 @@ use std::borrow::Cow;
/// The settings of an application.
#[derive(Debug, Clone)]
-pub struct Settings<Flags> {
+pub struct Settings<Flags = ()> {
/// The identifier of the application.
///
/// If provided, this identifier may be used to identify the application or
diff --git a/tiny_skia/src/geometry.rs b/tiny_skia/src/geometry.rs
index f7518731..16787f89 100644
--- a/tiny_skia/src/geometry.rs
+++ b/tiny_skia/src/geometry.rs
@@ -1,5 +1,7 @@
use crate::core::text::LineHeight;
-use crate::core::{Pixels, Point, Rectangle, Size, Transformation, Vector};
+use crate::core::{
+ Pixels, Point, Radians, Rectangle, Size, Transformation, Vector,
+};
use crate::graphics::geometry::fill::{self, Fill};
use crate::graphics::geometry::stroke::{self, Stroke};
use crate::graphics::geometry::{Path, Style, Text};
@@ -192,10 +194,10 @@ impl Frame {
self.transform.pre_translate(translation.x, translation.y);
}
- pub fn rotate(&mut self, angle: f32) {
- self.transform = self
- .transform
- .pre_concat(tiny_skia::Transform::from_rotate(angle.to_degrees()));
+ pub fn rotate(&mut self, angle: impl Into<Radians>) {
+ self.transform = self.transform.pre_concat(
+ tiny_skia::Transform::from_rotate(angle.into().0.to_degrees()),
+ );
}
pub fn scale(&mut self, scale: impl Into<f32>) {
diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index 8cfcfff0..f4e0fbda 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -1,6 +1,8 @@
//! Build and draw geometry.
use crate::core::text::LineHeight;
-use crate::core::{Pixels, Point, Rectangle, Size, Transformation, Vector};
+use crate::core::{
+ Pixels, Point, Radians, Rectangle, Size, Transformation, Vector,
+};
use crate::graphics::color;
use crate::graphics::geometry::fill::{self, Fill};
use crate::graphics::geometry::{
@@ -475,12 +477,12 @@ impl Frame {
/// Applies a rotation in radians to the current transform of the [`Frame`].
#[inline]
- pub fn rotate(&mut self, angle: f32) {
+ pub fn rotate(&mut self, angle: impl Into<Radians>) {
self.transforms.current.0 = self
.transforms
.current
.0
- .pre_rotate(lyon::math::Angle::radians(angle));
+ .pre_rotate(lyon::math::Angle::radians(angle.into().0));
}
/// Applies a uniform scaling to the current transform of the [`Frame`].
diff --git a/widget/src/tooltip.rs b/widget/src/tooltip.rs
index 8e11ca98..32c962fc 100644
--- a/widget/src/tooltip.rs
+++ b/widget/src/tooltip.rs
@@ -273,11 +273,10 @@ where
}
/// The position of the tooltip. Defaults to following the cursor.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Position {
- /// The tooltip will follow the cursor.
- FollowCursor,
/// The tooltip will appear on the top of the widget.
+ #[default]
Top,
/// The tooltip will appear on the bottom of the widget.
Bottom,
@@ -285,6 +284,8 @@ pub enum Position {
Left,
/// The tooltip will appear on the right of the widget.
Right,
+ /// The tooltip will follow the cursor.
+ FollowCursor,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]