diff options
Diffstat (limited to 'web/src/lib.rs')
-rw-r--r-- | web/src/lib.rs | 139 |
1 files changed, 83 insertions, 56 deletions
diff --git a/web/src/lib.rs b/web/src/lib.rs index 8239ffc9..258ad9e7 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -54,27 +54,37 @@ #![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] -#![deny(unsafe_code)] -#![deny(rust_2018_idioms)] +#![forbid(unsafe_code)] +#![forbid(rust_2018_idioms)] use dodrio::bumpalo; use std::{cell::RefCell, rc::Rc}; mod bus; mod element; +mod hasher; -pub mod style; +pub mod css; +pub mod subscription; pub mod widget; pub use bus::Bus; +pub use css::Css; pub use dodrio; pub use element::Element; +pub use hasher::Hasher; pub use iced_core::{ - Align, Background, Color, Command, Font, HorizontalAlignment, Length, - VerticalAlignment, + Align, Background, Color, Font, HorizontalAlignment, Length, Point, Size, + Vector, VerticalAlignment, }; -pub use style::Style; +pub use iced_futures::{executor, futures, Command}; +pub use subscription::Subscription; + +#[doc(no_inline)] pub use widget::*; +#[doc(no_inline)] +pub use executor::Executor; + /// An interactive web application. /// /// This trait is the main entrypoint of Iced. Once implemented, you can run @@ -87,7 +97,15 @@ pub trait Application { /// The type of __messages__ your [`Application`] will produce. /// /// [`Application`]: trait.Application.html - type Message: Clone; + type Message: Send; + + /// The [`Executor`] that will run commands and subscriptions. + /// + /// The [`executor::WasmBindgen`] can be a good choice for the Web. + /// + /// [`Executor`]: trait.Executor.html + /// [`executor::Default`]: executor/struct.Default.html + type Executor: Executor; /// Initializes the [`Application`]. /// @@ -130,6 +148,20 @@ pub trait Application { /// [`Application`]: trait.Application.html fn view(&mut self) -> Element<'_, Self::Message>; + /// Returns the event [`Subscription`] for the current state of the + /// application. + /// + /// A [`Subscription`] will be kept alive as long as you keep returning it, + /// and the __messages__ produced will be handled by + /// [`update`](#tymethod.update). + /// + /// By default, this method returns an empty [`Subscription`]. + /// + /// [`Subscription`]: struct.Subscription.html + fn subscription(&self) -> Subscription<Self::Message> { + Subscription::none() + } + /// Runs the [`Application`]. /// /// [`Application`]: trait.Application.html @@ -137,71 +169,66 @@ pub trait Application { where Self: 'static + Sized, { - let (app, command) = Self::new(); - let mut instance = Instance::new(app); + use futures::stream::StreamExt; - instance.spawn(command); + let (app, command) = Self::new(); let window = web_sys::window().unwrap(); - let document = window.document().unwrap(); - document.set_title(&instance.title); - let body = document.body().unwrap(); - let vdom = dodrio::Vdom::new(&body, instance); - vdom.forget(); - } -} + let mut title = app.title(); + document.set_title(&title); -#[derive(Clone)] -struct Instance<Message> { - title: String, - ui: Rc<RefCell<Box<dyn Application<Message = Message>>>>, -} + let (sender, receiver) = + iced_futures::futures::channel::mpsc::unbounded(); -impl<Message> Instance<Message> -where - Message: 'static + Clone, -{ - fn new(ui: impl Application<Message = Message> + 'static) -> Self { - Self { - title: ui.title(), - ui: Rc::new(RefCell::new(Box::new(ui))), - } - } + let mut runtime = iced_futures::Runtime::new( + Self::Executor::new().expect("Create executor"), + sender.clone(), + ); + runtime.spawn(command); - fn update(&mut self, message: Message) { - let command = self.ui.borrow_mut().update(message); - let title = self.ui.borrow().title(); + let application = Rc::new(RefCell::new(app)); - self.spawn(command); + let instance = Instance { + application: application.clone(), + bus: Bus::new(sender), + }; - let window = web_sys::window().unwrap(); - let document = window.document().unwrap(); + let vdom = dodrio::Vdom::new(&body, instance); - if self.title != title { - document.set_title(&title); + let event_loop = receiver.for_each(move |message| { + let command = application.borrow_mut().update(message); + let subscription = application.borrow().subscription(); + let new_title = application.borrow().title(); - self.title = title; - } - } + runtime.spawn(command); + runtime.track(subscription); + + if title != new_title { + document.set_title(&new_title); - fn spawn(&mut self, command: Command<Message>) { - use futures::FutureExt; + title = new_title; + } - for future in command.futures() { - let mut instance = self.clone(); - let future = future.map(move |message| instance.update(message)); + vdom.weak().schedule_render(); - wasm_bindgen_futures::spawn_local(future); - } + futures::future::ready(()) + }); + + wasm_bindgen_futures::spawn_local(event_loop); } } -impl<Message> dodrio::Render for Instance<Message> +struct Instance<A: Application> { + application: Rc<RefCell<A>>, + bus: Bus<A::Message>, +} + +impl<A> dodrio::Render for Instance<A> where - Message: 'static + Clone, + A: Application, { fn render<'a, 'bump>( &'a self, @@ -212,15 +239,15 @@ where { use dodrio::builder::*; - let mut ui = self.ui.borrow_mut(); + let mut ui = self.application.borrow_mut(); let element = ui.view(); - let mut style_sheet = style::Sheet::new(); + let mut css = Css::new(); - let node = element.widget.node(bump, &Bus::new(), &mut style_sheet); + let node = element.widget.node(bump, &self.bus, &mut css); div(bump) .attr("style", "width: 100%; height: 100%") - .children(vec![style_sheet.node(bump), node]) + .children(vec![css.node(bump), node]) .finish() } } |