summaryrefslogtreecommitdiffstats
path: root/web/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'web/src/lib.rs')
-rw-r--r--web/src/lib.rs139
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()
}
}