summaryrefslogtreecommitdiffstats
path: root/lazy
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2021-11-07 18:15:01 +0700
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2021-11-29 15:04:12 +0700
commitbffa7203dfd333b699bc29a22c74fb602eea4ea1 (patch)
tree6e9315aa6bcb52cf0b95a0698c88b7aecde79186 /lazy
parentd9f970ffd5af6dafb5e696ad317d9ea7b997eb4b (diff)
downloadiced-bffa7203dfd333b699bc29a22c74fb602eea4ea1.tar.gz
iced-bffa7203dfd333b699bc29a22c74fb602eea4ea1.tar.bz2
iced-bffa7203dfd333b699bc29a22c74fb602eea4ea1.zip
Create `iced_lazy` and draft `Component` trait
Diffstat (limited to 'lazy')
-rw-r--r--lazy/Cargo.toml11
-rw-r--r--lazy/src/component.rs181
-rw-r--r--lazy/src/lib.rs3
3 files changed, 195 insertions, 0 deletions
diff --git a/lazy/Cargo.toml b/lazy/Cargo.toml
new file mode 100644
index 00000000..b840de50
--- /dev/null
+++ b/lazy/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "iced_lazy"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+ouroboros = "0.13"
+
+[dependencies.iced_native]
+version = "0.4"
+path = "../native"
diff --git a/lazy/src/component.rs b/lazy/src/component.rs
new file mode 100644
index 00000000..3296533e
--- /dev/null
+++ b/lazy/src/component.rs
@@ -0,0 +1,181 @@
+use iced_native::event;
+use iced_native::layout::{self, Layout};
+use iced_native::mouse;
+use iced_native::overlay;
+use iced_native::renderer;
+use iced_native::{
+ Clipboard, Element, Hasher, Length, Point, Rectangle, Widget,
+};
+
+use ouroboros::self_referencing;
+use std::marker::PhantomData;
+
+pub fn view<'a, Event, Message, Renderer>(
+ component: &'a mut dyn Component<Message, Renderer, Event = Event>,
+) -> Element<'a, Message, Renderer>
+where
+ Renderer: iced_native::Renderer,
+{
+ Element::new(Instance {
+ state: Some(
+ StateBuilder {
+ component,
+ cache_builder: |state| Cache {
+ element: state.view(),
+ message: PhantomData,
+ },
+ }
+ .build(),
+ ),
+ })
+}
+
+pub trait Component<Message, Renderer> {
+ type Event;
+
+ fn update(&mut self, event: Self::Event) -> Option<Message>;
+
+ fn view(&mut self) -> Element<Self::Event, Renderer>;
+}
+
+struct Instance<'a, Message, Renderer, Event> {
+ state: Option<State<'a, Message, Renderer, Event>>,
+}
+
+#[self_referencing]
+struct State<'a, Message, Renderer, Event> {
+ component: &'a mut dyn Component<Message, Renderer, Event = Event>,
+
+ #[borrows(mut component)]
+ #[covariant]
+ cache: Cache<'this, Message, Renderer, Event>,
+}
+
+struct Cache<'a, Message, Renderer, Event> {
+ element: Element<'a, Event, Renderer>,
+ message: PhantomData<Message>,
+}
+
+impl<'a, Message, Renderer, Event> Widget<Message, Renderer>
+ for Instance<'a, Message, Renderer, Event>
+where
+ Renderer: iced_native::Renderer,
+{
+ fn width(&self) -> Length {
+ self.state.as_ref().unwrap().borrow_cache().element.width()
+ }
+
+ fn height(&self) -> Length {
+ self.state.as_ref().unwrap().borrow_cache().element.width()
+ }
+
+ fn layout(
+ &self,
+ renderer: &Renderer,
+ limits: &layout::Limits,
+ ) -> layout::Node {
+ self.state
+ .as_ref()
+ .unwrap()
+ .borrow_cache()
+ .element
+ .layout(renderer, limits)
+ }
+
+ fn on_event(
+ &mut self,
+ event: iced_native::Event,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ renderer: &Renderer,
+ clipboard: &mut dyn Clipboard,
+ messages: &mut Vec<Message>,
+ ) -> event::Status {
+ let mut local_messages = Vec::new();
+
+ let event_status =
+ self.state.as_mut().unwrap().with_cache_mut(|cache| {
+ cache.element.on_event(
+ event,
+ layout,
+ cursor_position,
+ renderer,
+ clipboard,
+ &mut local_messages,
+ )
+ });
+
+ if !local_messages.is_empty() {
+ let component = self.state.take().unwrap().into_heads().component;
+
+ messages.extend(
+ local_messages
+ .into_iter()
+ .filter_map(|message| component.update(message)),
+ );
+
+ self.state = Some(
+ StateBuilder {
+ component,
+ cache_builder: |state| Cache {
+ element: state.view(),
+ message: PhantomData,
+ },
+ }
+ .build(),
+ );
+
+ // TODO: Invalidate layout (!)
+ }
+
+ event_status
+ }
+
+ fn draw(
+ &self,
+ renderer: &mut Renderer,
+ style: &renderer::Style,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ ) {
+ self.state.as_ref().unwrap().borrow_cache().element.draw(
+ renderer,
+ style,
+ layout,
+ cursor_position,
+ viewport,
+ )
+ }
+
+ fn hash_layout(&self, state: &mut Hasher) {
+ self.state
+ .as_ref()
+ .unwrap()
+ .borrow_cache()
+ .element
+ .hash_layout(state)
+ }
+
+ fn mouse_interaction(
+ &self,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ ) -> mouse::Interaction {
+ self.state
+ .as_ref()
+ .unwrap()
+ .borrow_cache()
+ .element
+ .mouse_interaction(layout, cursor_position, viewport)
+ }
+
+ fn overlay(
+ &mut self,
+ _layout: Layout<'_>,
+ ) -> Option<overlay::Element<'_, Message, Renderer>> {
+ // TODO: Rethink overlay composability
+ None
+ }
+}
diff --git a/lazy/src/lib.rs b/lazy/src/lib.rs
new file mode 100644
index 00000000..42e5f587
--- /dev/null
+++ b/lazy/src/lib.rs
@@ -0,0 +1,3 @@
+pub mod component;
+
+pub use component::Component;