Merge pull request #517 from Kaiden42/embedded
iced_web: Add an option to select the element
This commit is contained in:
commit
86f5e56c55
1 changed files with 165 additions and 0 deletions
165
web/src/lib.rs
165
web/src/lib.rs
|
|
@ -244,3 +244,168 @@ where
|
|||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// An interactive embedded web application.
|
||||
///
|
||||
/// This trait is the main entrypoint of Iced. Once implemented, you can run
|
||||
/// your GUI application by simply calling [`run`](#method.run). It will either
|
||||
/// take control of the `<body>' or of an HTML element of the document specified
|
||||
/// by `container_id`.
|
||||
///
|
||||
/// An [`Embedded`](trait.Embedded.html) can execute asynchronous actions
|
||||
/// by returning a [`Command`](struct.Command.html) in some of its methods.
|
||||
pub trait Embedded {
|
||||
/// 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;
|
||||
|
||||
/// The type of __messages__ your [`Embedded`] application will produce.
|
||||
///
|
||||
/// [`Embedded`]: trait.Embedded.html
|
||||
type Message: Send;
|
||||
|
||||
/// The data needed to initialize your [`Embedded`] application.
|
||||
///
|
||||
/// [`Embedded`]: trait.Embedded.html
|
||||
type Flags;
|
||||
|
||||
/// Initializes the [`Embedded`] application.
|
||||
///
|
||||
/// Here is where you should return the initial state of your app.
|
||||
///
|
||||
/// Additionally, you can return a [`Command`](struct.Command.html) if you
|
||||
/// need to perform some async action in the background on startup. This is
|
||||
/// useful if you want to load state from a file, perform an initial HTTP
|
||||
/// request, etc.
|
||||
///
|
||||
/// [`Embedded`]: trait.Embedded.html
|
||||
fn new(flags: Self::Flags) -> (Self, Command<Self::Message>)
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Handles a __message__ and updates the state of the [`Embedded`]
|
||||
/// application.
|
||||
///
|
||||
/// This is where you define your __update logic__. All the __messages__,
|
||||
/// produced by either user interactions or commands, will be handled by
|
||||
/// this method.
|
||||
///
|
||||
/// Any [`Command`] returned will be executed immediately in the background.
|
||||
///
|
||||
/// [`Embedded`]: trait.Embedded.html
|
||||
/// [`Command`]: struct.Command.html
|
||||
fn update(&mut self, message: Self::Message) -> Command<Self::Message>;
|
||||
|
||||
/// Returns the widgets to display in the [`Embedded`] application.
|
||||
///
|
||||
/// These widgets can produce __messages__ based on user interaction.
|
||||
///
|
||||
/// [`Embedded`]: trait.Embedded.html
|
||||
fn view(&mut self) -> Element<'_, Self::Message>;
|
||||
|
||||
/// Returns the event [`Subscription`] for the current state of the embedded
|
||||
/// 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 [`Embedded`] application.
|
||||
///
|
||||
/// [`Embedded`]: trait.Embedded.html
|
||||
fn run(flags: Self::Flags, container_id: Option<String>)
|
||||
where
|
||||
Self: 'static + Sized,
|
||||
{
|
||||
use futures::stream::StreamExt;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::HtmlElement;
|
||||
|
||||
let window = web_sys::window().unwrap();
|
||||
let document = window.document().unwrap();
|
||||
let container: HtmlElement = container_id
|
||||
.map(|id| document.get_element_by_id(&id).unwrap())
|
||||
.map(|container| {
|
||||
container.dyn_ref::<HtmlElement>().unwrap().to_owned()
|
||||
})
|
||||
.unwrap_or_else(|| document.body().unwrap());
|
||||
|
||||
let (sender, receiver) =
|
||||
iced_futures::futures::channel::mpsc::unbounded();
|
||||
|
||||
let mut runtime = iced_futures::Runtime::new(
|
||||
Self::Executor::new().expect("Create executor"),
|
||||
sender.clone(),
|
||||
);
|
||||
|
||||
let (app, command) = runtime.enter(|| Self::new(flags));
|
||||
|
||||
runtime.spawn(command);
|
||||
|
||||
let application = Rc::new(RefCell::new(app));
|
||||
|
||||
let instance = EmbeddedInstance {
|
||||
application: application.clone(),
|
||||
bus: Bus::new(sender),
|
||||
};
|
||||
|
||||
let vdom = dodrio::Vdom::new(&container, instance);
|
||||
|
||||
let event_loop = receiver.for_each(move |message| {
|
||||
let (command, subscription) = runtime.enter(|| {
|
||||
let command = application.borrow_mut().update(message);
|
||||
let subscription = application.borrow().subscription();
|
||||
|
||||
(command, subscription)
|
||||
});
|
||||
|
||||
runtime.spawn(command);
|
||||
runtime.track(subscription);
|
||||
|
||||
vdom.weak().schedule_render();
|
||||
|
||||
futures::future::ready(())
|
||||
});
|
||||
|
||||
wasm_bindgen_futures::spawn_local(event_loop);
|
||||
}
|
||||
}
|
||||
|
||||
struct EmbeddedInstance<A: Embedded> {
|
||||
application: Rc<RefCell<A>>,
|
||||
bus: Bus<A::Message>,
|
||||
}
|
||||
|
||||
impl<'a, A> dodrio::Render<'a> for EmbeddedInstance<A>
|
||||
where
|
||||
A: Embedded,
|
||||
{
|
||||
fn render(
|
||||
&self,
|
||||
context: &mut dodrio::RenderContext<'a>,
|
||||
) -> dodrio::Node<'a> {
|
||||
use dodrio::builder::*;
|
||||
|
||||
let mut ui = self.application.borrow_mut();
|
||||
let element = ui.view();
|
||||
let mut css = Css::new();
|
||||
|
||||
let node = element.widget.node(context.bump, &self.bus, &mut css);
|
||||
|
||||
div(context.bump)
|
||||
.attr("style", "width: 100%; height: 100%")
|
||||
.children(vec![css.node(context.bump), node])
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue