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()
|
.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