Remove Sandbox trait 🎉

This commit is contained in:
Héctor Ramón Jiménez 2024-03-17 13:46:52 +01:00
parent 9152904af1
commit 846d76cd3f
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
13 changed files with 169 additions and 240 deletions

View file

@ -10,7 +10,7 @@ pub fn main() -> iced::Result {
iced::application("Arc - Iced", Arc::update, Arc::view) iced::application("Arc - Iced", Arc::update, Arc::view)
.subscription(Arc::subscription) .subscription(Arc::subscription)
.theme(|_| Theme::Dark) .theme(|_| Theme::Dark)
.antialiased() .antialiasing(true)
.run() .run()
} }

View file

@ -4,7 +4,7 @@ use iced::{Alignment, Element, Length};
pub fn main() -> iced::Result { pub fn main() -> iced::Result {
iced::application("Bezier Tool - Iced", Example::update, Example::view) iced::application("Bezier Tool - Iced", Example::update, Example::view)
.antialiased() .antialiasing(true)
.run() .run()
} }

View file

@ -11,7 +11,7 @@ pub fn main() -> iced::Result {
iced::application("Clock - Iced", Clock::update, Clock::view) iced::application("Clock - Iced", Clock::update, Clock::view)
.subscription(Clock::subscription) .subscription(Clock::subscription)
.theme(Clock::theme) .theme(Clock::theme)
.antialiased() .antialiasing(true)
.run() .run()
} }

View file

@ -20,7 +20,7 @@ pub fn main() -> iced::Result {
) )
.theme(ColorPalette::theme) .theme(ColorPalette::theme)
.default_font(Font::MONOSPACE) .default_font(Font::MONOSPACE)
.antialiased() .antialiasing(true)
.run() .run()
} }

View file

@ -7,7 +7,7 @@ use iced::{Alignment, Command, Element, Length, Subscription};
pub fn main() -> iced::Result { pub fn main() -> iced::Result {
iced::application("Events - Iced", Events::update, Events::view) iced::application("Events - Iced", Events::update, Events::view)
.subscription(Events::subscription) .subscription(Events::subscription)
.ignore_close_request() .exit_on_close_request(false)
.run() .run()
} }

View file

@ -1,22 +1,17 @@
use iced::application; use iced::application;
use iced::gradient;
use iced::widget::{ use iced::widget::{
checkbox, column, container, horizontal_space, row, slider, text, checkbox, column, container, horizontal_space, row, slider, text,
}; };
use iced::{gradient, window}; use iced::{Alignment, Color, Element, Length, Radians, Theme};
use iced::{
Alignment, Color, Element, Length, Radians, Sandbox, Settings, Theme,
};
pub fn main() -> iced::Result { pub fn main() -> iced::Result {
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
Gradient::run(Settings { iced::application("Gradient - Iced", Gradient::update, Gradient::view)
window: window::Settings { .style(Gradient::style)
transparent: true, .transparent(true)
..Default::default() .run()
},
..Default::default()
})
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -35,9 +30,7 @@ enum Message {
TransparentToggled(bool), TransparentToggled(bool),
} }
impl Sandbox for Gradient { impl Gradient {
type Message = Message;
fn new() -> Self { fn new() -> Self {
Self { Self {
start: Color::WHITE, start: Color::WHITE,
@ -47,10 +40,6 @@ impl Sandbox for Gradient {
} }
} }
fn title(&self) -> String {
String::from("Gradient")
}
fn update(&mut self, message: Message) { fn update(&mut self, message: Message) {
match message { match message {
Message::StartChanged(color) => self.start = color, Message::StartChanged(color) => self.start = color,
@ -118,6 +107,12 @@ impl Sandbox for Gradient {
} }
} }
impl Default for Gradient {
fn default() -> Self {
Self::new()
}
}
fn color_picker(label: &str, color: Color) -> Element<'_, Color> { fn color_picker(label: &str, color: Color) -> Element<'_, Color> {
row![ row![
text(label).width(64), text(label).width(64),

View file

@ -16,7 +16,7 @@ pub fn main() -> iced::Result {
LoadingSpinners::update, LoadingSpinners::update,
LoadingSpinners::view, LoadingSpinners::view,
) )
.antialiased() .antialiasing(true)
.run() .run()
} }

View file

@ -14,7 +14,7 @@ pub fn main() -> iced::Result {
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
iced::application("Multitouch - Iced", Multitouch::update, Multitouch::view) iced::application("Multitouch - Iced", Multitouch::update, Multitouch::view)
.antialiased() .antialiasing(true)
.centered() .centered()
.run() .run()
} }

View file

@ -13,7 +13,7 @@ fn main() -> iced::Result {
SierpinskiEmulator::update, SierpinskiEmulator::update,
SierpinskiEmulator::view, SierpinskiEmulator::view,
) )
.antialiased() .antialiasing(true)
.run() .run()
} }

View file

@ -12,7 +12,7 @@ pub fn main() -> iced::Result {
VectorialText::view, VectorialText::view,
) )
.theme(|_| Theme::Dark) .theme(|_| Theme::Dark)
.antialiased() .antialiasing(true)
.run() .run()
} }

View file

@ -172,7 +172,6 @@ pub use iced_futures::futures;
pub use iced_highlighter as highlighter; pub use iced_highlighter as highlighter;
mod error; mod error;
mod sandbox;
pub mod application; pub mod application;
pub mod program; pub mod program;
@ -311,7 +310,6 @@ pub use executor::Executor;
pub use font::Font; pub use font::Font;
pub use program::Program; pub use program::Program;
pub use renderer::Renderer; pub use renderer::Renderer;
pub use sandbox::Sandbox;
pub use settings::Settings; pub use settings::Settings;
pub use subscription::Subscription; pub use subscription::Subscription;

View file

@ -194,12 +194,16 @@ impl<P: Definition> Program<P> {
self.program.view(&self.state) self.program.view(&self.state)
} }
fn subscription(&self) -> Subscription<Self::Message> {
self.program.subscription(&self.state)
}
fn theme(&self) -> Self::Theme { fn theme(&self) -> Self::Theme {
self.program.theme(&self.state) self.program.theme(&self.state)
} }
fn subscription(&self) -> Subscription<Self::Message> { fn style(&self, theme: &Self::Theme) -> application::Appearance {
self.program.subscription(&self.state) self.program.style(&self.state, theme)
} }
} }
@ -221,11 +225,11 @@ impl<P: Definition> Program<P> {
Self { settings, ..self } Self { settings, ..self }
} }
/// Toggles the [`Settings::antialiasing`] to `true` for the [`Program`]. /// Sets the [`Settings::antialiasing`] of the [`Program`].
pub fn antialiased(self) -> Self { pub fn antialiasing(self, antialiasing: bool) -> Self {
Self { Self {
settings: Settings { settings: Settings {
antialiasing: true, antialiasing,
..self.settings ..self.settings
}, },
..self ..self
@ -263,12 +267,26 @@ impl<P: Definition> Program<P> {
} }
} }
/// Sets the [`window::Settings::exit_on_close_request`] to `false` in the [`Program`]. /// Sets the [`window::Settings::exit_on_close_request`] of the [`Program`].
pub fn ignore_close_request(self) -> Self { pub fn exit_on_close_request(self, exit_on_close_request: bool) -> Self {
Self { Self {
settings: Settings { settings: Settings {
window: window::Settings { window: window::Settings {
exit_on_close_request: false, exit_on_close_request,
..self.settings.window
},
..self.settings
},
..self
}
}
/// Sets the [`window::Settings::transparent`] of the [`Program`].
pub fn transparent(self, transparent: bool) -> Self {
Self {
settings: Settings {
window: window::Settings {
transparent,
..self.settings.window ..self.settings.window
}, },
..self.settings ..self.settings
@ -328,6 +346,19 @@ impl<P: Definition> Program<P> {
settings: self.settings, settings: self.settings,
} }
} }
/// Sets the style logic of the [`Program`].
pub fn style(
self,
f: impl Fn(&P::State, &P::Theme) -> application::Appearance,
) -> Program<
impl Definition<State = P::State, Message = P::Message, Theme = P::Theme>,
> {
Program {
raw: with_style(self.raw, f),
settings: self.settings,
}
}
} }
/// The internal definition of a [`Program`]. /// The internal definition of a [`Program`].
@ -377,6 +408,14 @@ pub trait Definition: Sized {
fn theme(&self, _state: &Self::State) -> Self::Theme { fn theme(&self, _state: &Self::State) -> Self::Theme {
Self::Theme::default() Self::Theme::default()
} }
fn style(
&self,
_state: &Self::State,
theme: &Self::Theme,
) -> application::Appearance {
application::DefaultStyle::default_style(theme)
}
} }
fn with_title<P: Definition>( fn with_title<P: Definition>(
@ -431,6 +470,14 @@ fn with_title<P: Definition>(
) -> Subscription<Self::Message> { ) -> Subscription<Self::Message> {
self.program.subscription(state) self.program.subscription(state)
} }
fn style(
&self,
state: &Self::State,
theme: &Self::Theme,
) -> application::Appearance {
self.program.style(state, theme)
}
} }
WithTitle { program, title } WithTitle { program, title }
@ -479,16 +526,24 @@ fn with_load<P: Definition>(
self.program.title(state) self.program.title(state)
} }
fn theme(&self, state: &Self::State) -> Self::Theme {
self.program.theme(state)
}
fn subscription( fn subscription(
&self, &self,
state: &Self::State, state: &Self::State,
) -> Subscription<Self::Message> { ) -> Subscription<Self::Message> {
self.program.subscription(state) self.program.subscription(state)
} }
fn theme(&self, state: &Self::State) -> Self::Theme {
self.program.theme(state)
}
fn style(
&self,
state: &Self::State,
theme: &Self::Theme,
) -> application::Appearance {
self.program.style(state, theme)
}
} }
WithLoad { program, load: f } WithLoad { program, load: f }
@ -545,6 +600,14 @@ fn with_subscription<P: Definition>(
fn theme(&self, state: &Self::State) -> Self::Theme { fn theme(&self, state: &Self::State) -> Self::Theme {
self.program.theme(state) self.program.theme(state)
} }
fn style(
&self,
state: &Self::State,
theme: &Self::Theme,
) -> application::Appearance {
self.program.style(state, theme)
}
} }
WithSubscription { WithSubscription {
@ -604,11 +667,83 @@ fn with_theme<P: Definition>(
) -> Subscription<Self::Message> { ) -> Subscription<Self::Message> {
self.program.subscription(state) self.program.subscription(state)
} }
fn style(
&self,
state: &Self::State,
theme: &Self::Theme,
) -> application::Appearance {
self.program.style(state, theme)
}
} }
WithTheme { program, theme: f } WithTheme { program, theme: f }
} }
fn with_style<P: Definition>(
program: P,
f: impl Fn(&P::State, &P::Theme) -> application::Appearance,
) -> impl Definition<State = P::State, Message = P::Message, Theme = P::Theme> {
struct WithStyle<P, F> {
program: P,
style: F,
}
impl<P: Definition, F> Definition for WithStyle<P, F>
where
F: Fn(&P::State, &P::Theme) -> application::Appearance,
{
type State = P::State;
type Message = P::Message;
type Theme = P::Theme;
type Executor = P::Executor;
fn style(
&self,
state: &Self::State,
theme: &Self::Theme,
) -> application::Appearance {
(self.style)(state, theme)
}
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)
}
fn theme(&self, state: &Self::State) -> Self::Theme {
self.program.theme(state)
}
}
WithStyle { program, style: f }
}
/// The title logic of some [`Program`]. /// The title logic of some [`Program`].
/// ///
/// This trait is implemented both for `&static str` and /// This trait is implemented both for `&static str` and

View file

@ -1,199 +0,0 @@
use crate::application::{self, Application};
use crate::{Command, Element, Error, Settings, Subscription, Theme};
/// A sandboxed [`Application`].
///
/// If you are a just getting started with the library, this trait offers a
/// simpler interface than [`Application`].
///
/// Unlike an [`Application`], a [`Sandbox`] cannot run any asynchronous
/// actions or be initialized with some external flags. However, both traits
/// are very similar and upgrading from a [`Sandbox`] is very straightforward.
///
/// Therefore, it is recommended to always start by implementing this trait and
/// upgrade only once necessary.
///
/// # Examples
/// [The repository has a bunch of examples] that use the [`Sandbox`] trait:
///
/// - [`bezier_tool`], a Paint-like tool for drawing Bézier curves using the
/// [`Canvas widget`].
/// - [`counter`], the classic counter example explained in [the overview].
/// - [`custom_widget`], a demonstration of how to build a custom widget that
/// draws a circle.
/// - [`geometry`], a custom widget showcasing how to draw geometry with the
/// `Mesh2D` primitive in [`iced_wgpu`].
/// - [`pane_grid`], a grid of panes that can be split, resized, and
/// reorganized.
/// - [`progress_bar`], a simple progress bar that can be filled by using a
/// slider.
/// - [`styling`], an example showcasing custom styling with a light and dark
/// theme.
/// - [`svg`], an application that renders the [Ghostscript Tiger] by leveraging
/// the [`Svg` widget].
/// - [`tour`], a simple UI tour that can run both on native platforms and the
/// web!
///
/// [The repository has a bunch of examples]: https://github.com/iced-rs/iced/tree/0.12/examples
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.12/examples/bezier_tool
/// [`counter`]: https://github.com/iced-rs/iced/tree/0.12/examples/counter
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.12/examples/custom_widget
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.12/examples/geometry
/// [`pane_grid`]: https://github.com/iced-rs/iced/tree/0.12/examples/pane_grid
/// [`progress_bar`]: https://github.com/iced-rs/iced/tree/0.12/examples/progress_bar
/// [`styling`]: https://github.com/iced-rs/iced/tree/0.12/examples/styling
/// [`svg`]: https://github.com/iced-rs/iced/tree/0.12/examples/svg
/// [`tour`]: https://github.com/iced-rs/iced/tree/0.12/examples/tour
/// [`Canvas widget`]: crate::widget::Canvas
/// [the overview]: index.html#overview
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.12/wgpu
/// [`Svg` widget]: crate::widget::Svg
/// [Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg
///
/// ## A simple "Hello, world!"
///
/// If you just want to get started, here is a simple [`Sandbox`] that
/// says "Hello, world!":
///
/// ```no_run
/// use iced::{Element, Sandbox, Settings};
///
/// pub fn main() -> iced::Result {
/// Hello::run(Settings::default())
/// }
///
/// struct Hello;
///
/// impl Sandbox for Hello {
/// type Message = ();
///
/// fn new() -> Hello {
/// Hello
/// }
///
/// fn title(&self) -> String {
/// String::from("A cool application")
/// }
///
/// fn update(&mut self, _message: Self::Message) {
/// // This application has no interactions
/// }
///
/// fn view(&self) -> Element<Self::Message> {
/// "Hello, world!".into()
/// }
/// }
/// ```
pub trait Sandbox {
/// The type of __messages__ your [`Sandbox`] will produce.
type Message: std::fmt::Debug + Send;
/// Initializes the [`Sandbox`].
///
/// Here is where you should return the initial state of your app.
fn new() -> Self;
/// Returns the current title of the [`Sandbox`].
///
/// This title can be dynamic! The runtime will automatically update the
/// title of your application when necessary.
fn title(&self) -> String;
/// Handles a __message__ and updates the state of the [`Sandbox`].
///
/// This is where you define your __update logic__. All the __messages__,
/// produced by user interactions, will be handled by this method.
fn update(&mut self, message: Self::Message);
/// Returns the widgets to display in the [`Sandbox`].
///
/// These widgets can produce __messages__ based on user interaction.
fn view(&self) -> Element<'_, Self::Message>;
/// Returns the current [`Theme`] of the [`Sandbox`].
///
/// If you want to use your own custom theme type, you will have to use an
/// [`Application`].
///
/// By default, it returns [`Theme::default`].
fn theme(&self) -> Theme {
Theme::default()
}
/// Returns the current [`application::Appearance`].
fn style(&self, theme: &Theme) -> application::Appearance {
use application::DefaultStyle;
theme.default_style()
}
/// Returns the scale factor of the [`Sandbox`].
///
/// It can be used to dynamically control the size of the UI at runtime
/// (i.e. zooming).
///
/// For instance, a scale factor of `2.0` will make widgets twice as big,
/// while a scale factor of `0.5` will shrink them to half their size.
///
/// By default, it returns `1.0`.
fn scale_factor(&self) -> f64 {
1.0
}
/// Runs the [`Sandbox`].
///
/// On native platforms, this method will take control of the current thread
/// and __will NOT return__.
///
/// It should probably be that last thing you call in your `main` function.
fn run(settings: Settings<()>) -> Result<(), Error>
where
Self: 'static + Sized,
{
<Self as Application>::run(settings)
}
}
impl<T> Application for T
where
T: Sandbox,
{
type Executor = iced_futures::backend::null::Executor;
type Flags = ();
type Message = T::Message;
type Theme = Theme;
fn new(_flags: ()) -> (Self, Command<T::Message>) {
(T::new(), Command::none())
}
fn title(&self) -> String {
T::title(self)
}
fn update(&mut self, message: T::Message) -> Command<T::Message> {
T::update(self, message);
Command::none()
}
fn view(&self) -> Element<'_, T::Message> {
T::view(self)
}
fn theme(&self) -> Self::Theme {
T::theme(self)
}
fn style(&self, theme: &Theme) -> application::Appearance {
T::style(self, theme)
}
fn subscription(&self) -> Subscription<T::Message> {
Subscription::none()
}
fn scale_factor(&self) -> f64 {
T::scale_factor(self)
}
}