diff options
-rw-r--r-- | examples/events/src/main.rs | 7 | ||||
-rw-r--r-- | examples/exit/src/main.rs | 8 | ||||
-rw-r--r-- | examples/pokedex/src/main.rs | 18 | ||||
-rw-r--r-- | examples/screenshot/src/main.rs | 20 | ||||
-rw-r--r-- | examples/scrollable/src/main.rs | 30 | ||||
-rw-r--r-- | examples/system_information/src/main.rs | 26 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/program.rs | 88 |
8 files changed, 122 insertions, 77 deletions
diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs index 4ac57fc6..6eb11cb8 100644 --- a/examples/events/src/main.rs +++ b/examples/events/src/main.rs @@ -5,8 +5,7 @@ use iced::window; use iced::{Alignment, Command, Element, Length, Subscription}; pub fn main() -> iced::Result { - iced::application(Events::new, Events::update, Events::view) - .title("Events - Iced") + iced::application("Events - Iced", Events::update, Events::view) .subscription(Events::subscription) .ignore_close_request() .run() @@ -26,10 +25,6 @@ enum Message { } impl Events { - fn new() -> (Events, Command<Message>) { - (Events::default(), Command::none()) - } - 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 dc78b0bb..4948bd0f 100644 --- a/examples/exit/src/main.rs +++ b/examples/exit/src/main.rs @@ -3,9 +3,7 @@ use iced::window; use iced::{Alignment, Command, Element, Length}; pub fn main() -> iced::Result { - iced::application(Exit::new, Exit::update, Exit::view) - .title("Exit - Iced") - .run() + iced::application("Exit - Iced", Exit::update, Exit::view).run() } #[derive(Default)] @@ -20,10 +18,6 @@ enum Message { } impl Exit { - fn new() -> (Self, Command<Message>) { - (Self::default(), Command::none()) - } - fn update(&mut self, message: Message) -> Command<Message> { match message { Message::Confirm => window::close(window::Id::MAIN), diff --git a/examples/pokedex/src/main.rs b/examples/pokedex/src/main.rs index 099cc710..882a195d 100644 --- a/examples/pokedex/src/main.rs +++ b/examples/pokedex/src/main.rs @@ -3,15 +3,18 @@ use iced::widget::{self, column, container, image, row, text}; use iced::{Alignment, Command, Element, Length}; pub fn main() -> iced::Result { - iced::application(Pokedex::new, Pokedex::update, Pokedex::view) - .title(Pokedex::title) + iced::application(Pokedex::title, Pokedex::update, Pokedex::view) + .load(Pokedex::load) .run() } -#[derive(Debug)] +#[derive(Debug, Default)] enum Pokedex { + #[default] Loading, - Loaded { pokemon: Pokemon }, + Loaded { + pokemon: Pokemon, + }, Errored, } @@ -22,11 +25,8 @@ enum Message { } impl Pokedex { - fn new() -> (Self, Command<Message>) { - ( - Pokedex::Loading, - Command::perform(Pokemon::search(), Message::PokemonFound), - ) + fn load() -> Command<Message> { + Command::perform(Pokemon::search(), Message::PokemonFound) } fn title(&self) -> String { diff --git a/examples/screenshot/src/main.rs b/examples/screenshot/src/main.rs index 3f955228..296a7f54 100644 --- a/examples/screenshot/src/main.rs +++ b/examples/screenshot/src/main.rs @@ -13,12 +13,12 @@ use ::image::ColorType; fn main() -> iced::Result { tracing_subscriber::fmt::init(); - iced::application(Example::new, Example::update, Example::view) + iced::application("Screenshot - Iced", Example::update, Example::view) .subscription(Example::subscription) - .title("Screenshot - Iced") .run() } +#[derive(Default)] struct Example { screenshot: Option<Screenshot>, saved_png_path: Option<Result<String, PngError>>, @@ -44,22 +44,6 @@ enum Message { } impl Example { - fn new() -> (Self, Command<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 update(&mut self, message: Message) -> Command<Message> { match message { Message::Screenshot => { diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs index 3e1b0408..a6f3c689 100644 --- a/examples/scrollable/src/main.rs +++ b/examples/scrollable/src/main.rs @@ -11,12 +11,11 @@ static SCROLLABLE_ID: Lazy<scrollable::Id> = Lazy::new(scrollable::Id::unique); pub fn main() -> iced::Result { iced::application( - ScrollableDemo::new, + "Scrollable - Iced", ScrollableDemo::update, ScrollableDemo::view, ) .theme(ScrollableDemo::theme) - .title("Scrollable - Iced") .run() } @@ -49,18 +48,15 @@ enum Message { } impl ScrollableDemo { - fn new() -> (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 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> { @@ -339,6 +335,12 @@ impl ScrollableDemo { } } +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/system_information/src/main.rs b/examples/system_information/src/main.rs index 079c2c46..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::{system, Command, Element, Length}; -use bytesize::ByteSize; - pub fn main() -> iced::Result { - iced::application(Example::new, Example::update, Example::view) - .title("System Information - Iced") - .run() + 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)] @@ -23,13 +28,6 @@ enum Message { } impl Example { - fn new() -> (Self, Command<Message>) { - ( - Self::Loading, - system::fetch_information(Message::InformationReceived), - ) - } - fn update(&mut self, message: Message) -> Command<Message> { match message { Message::Refresh => { @@ -46,6 +44,8 @@ impl Example { } fn view(&self) -> Element<Message> { + use bytesize::ByteSize; + let content: Element<_> = match self { Example::Loading => text("Loading...").size(40).into(), Example::Loaded { information } => { @@ -362,7 +362,7 @@ pub type Result = std::result::Result<(), Error>; /// } /// ``` pub fn run<State, Message>( - title: &'static str, + title: impl program::Title<State> + 'static, update: impl Fn(&mut State, Message) + 'static, view: impl for<'a> program::View<'a, State, Message> + 'static, ) -> Result diff --git a/src/program.rs b/src/program.rs index 3a16ea29..746f8f29 100644 --- a/src/program.rs +++ b/src/program.rs @@ -143,31 +143,30 @@ where /// Creates a [`Program`] that can leverage the [`Command`] API for /// concurrent operations. pub fn application<State, Message>( - new: impl Fn() -> (State, Command<Message>), + title: impl Title<State>, update: impl Fn(&mut State, Message) -> Command<Message>, view: impl for<'a> self::View<'a, State, Message>, ) -> Program< impl Definition<State = State, Message = Message, Theme = crate::Theme>, > where - State: 'static, + State: Default + 'static, Message: Send + std::fmt::Debug, { use std::marker::PhantomData; - struct Application<State, Message, New, Update, View> { - new: New, + struct Application<State, Message, Update, View> { update: Update, view: View, _state: PhantomData<State>, _message: PhantomData<Message>, } - impl<State, Message, New, Update, View> Definition - for Application<State, Message, New, Update, View> + impl<State, Message, Update, View> Definition + for Application<State, Message, Update, View> where + State: Default, Message: Send + std::fmt::Debug, - New: Fn() -> (State, Command<Message>), Update: Fn(&mut State, Message) -> Command<Message>, View: for<'a> self::View<'a, State, Message>, { @@ -177,7 +176,7 @@ where type Executor = executor::Default; fn build(&self) -> (Self::State, Command<Self::Message>) { - (self.new)() + (Self::State::default(), Command::none()) } fn update( @@ -198,7 +197,6 @@ where Program { raw: Application { - new, update, view, _state: PhantomData, @@ -206,6 +204,7 @@ where }, settings: Settings::default(), } + .title(title) } /// A fully functioning and configured iced application. @@ -367,6 +366,19 @@ impl<P: Definition> Program<P> { } } + /// 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, @@ -500,6 +512,64 @@ fn with_title<P: Definition>( 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>, |