Skip to content

Commit

Permalink
Create use_layout hook and refactor Canvas (#50)
Browse files Browse the repository at this point in the history
* Create use_layout hook and refactor Canvas

* Pass clippy
  • Loading branch information
matthunz authored Nov 17, 2024
1 parent 36c4f19 commit a264cdd
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 52 deletions.
7 changes: 5 additions & 2 deletions crates/actuate-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,14 +614,17 @@ impl<T> fmt::Display for ContextError<T> {
///
/// # Panics
/// Panics if the context value is not found.
pub fn use_context<T: 'static>(cx: &ScopeData) -> Result<Rc<T>, ContextError<T>> {
pub fn use_context<'a, T: 'static>(cx: ScopeState<'a>) -> Result<&'a T, ContextError<T>> {
let Some(any) = cx.contexts.borrow().values.get(&TypeId::of::<T>()).cloned() else {
return Err(ContextError {
_marker: PhantomData,
});
};

Ok(any.downcast().unwrap())
let value: &T = (*any).downcast_ref().unwrap();
let value: &'a T = unsafe { mem::transmute(value) };

Ok(value)
}

/// Provide a context value of type `T`.
Expand Down
6 changes: 1 addition & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,14 @@ pub struct WindowContext {
is_layout_changed: Cell<bool>,
canvas_update_fns: RefCell<HashMap<NodeId, Box<dyn Fn()>>>,
listeners: Rc<RefCell<HashMap<NodeId, Vec<ListenerFn>>>>,
pending_listeners: Rc<RefCell<Vec<ListenerFn>>>,
base_color: Cell<Color>,
}

#[derive(Data)]
struct RenderRoot<C> {
content: C,
}

unsafe impl<C: Data> Data for RenderRoot<C> {
type Id = RenderRoot<C::Id>;
}

impl<C: Compose> Compose for RenderRoot<C> {
fn compose(cx: Scope<Self>) -> impl Compose {
use_provider(&cx, CanvasContext::default);
Expand Down
49 changes: 9 additions & 40 deletions src/ui/canvas.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use crate::{prelude::*, Draw, LayoutContext, WindowContext};
use crate::{prelude::*, Draw, ListenerFn, WindowContext};
use std::{cell::RefCell, mem, rc::Rc};
use taffy::{Layout, Style};
use vello::{
kurbo::{Affine, Vec2},
Scene,
};

use super::use_layout;

#[derive(Clone, Default)]
pub(crate) struct CanvasContext {
pub(crate) draws: RefCell<Vec<Rc<dyn Draw>>>,
pub(crate) pending_listeners: Rc<RefCell<Vec<ListenerFn>>>,
}

type DrawFn<'a> = Box<dyn Fn(Layout, &mut Scene) + 'a>;
Expand All @@ -31,25 +34,12 @@ impl<'a> Canvas<'a> {
impl Compose for Canvas<'_> {
fn compose(cx: Scope<Self>) -> impl Compose {
let canvas_cx = use_context::<CanvasContext>(&cx).unwrap();
let layout_cx = use_context::<LayoutContext>(&cx).unwrap();
let renderer_cx = use_context::<WindowContext>(&cx).unwrap();

let parent_key = layout_cx.parent_id;
let key = *use_ref(&cx, || {
let key = renderer_cx
.taffy
.borrow_mut()
.new_leaf(cx.me().style.clone())
.unwrap();
renderer_cx
.taffy
.borrow_mut()
.add_child(parent_key, key)
.unwrap();

renderer_cx.is_layout_changed.set(true);

let listeners = mem::take(&mut *renderer_cx.pending_listeners.borrow_mut());
let (key, layout) = use_layout(&cx, cx.me().style.clone());

use_ref(&cx, || {
let listeners = canvas_cx.pending_listeners.borrow().clone();
renderer_cx.listeners.borrow_mut().insert(key, listeners);

let f: Box<dyn Fn()> = Box::new(move || {
Expand All @@ -60,36 +50,15 @@ impl Compose for Canvas<'_> {
let f: Box<dyn Fn()> = unsafe { mem::transmute(f) };

renderer_cx.canvas_update_fns.borrow_mut().insert(key, f);

key
});

// Safety: We must remove `f` here to make the above valid.

let renderer_cx_handle = renderer_cx.clone();
use_drop(&cx, move || {
renderer_cx_handle
.canvas_update_fns
.borrow_mut()
.remove(&key);

renderer_cx_handle.taffy.borrow_mut().remove(key).unwrap();
renderer_cx_handle.listeners.borrow_mut().remove(&key);
renderer_cx.canvas_update_fns.borrow_mut().remove(&key);
});

let last_style = use_ref(&cx, || cx.me().style.clone());
if cx.me().style != *last_style {
renderer_cx.is_layout_changed.set(true);
renderer_cx
.taffy
.borrow_mut()
.set_style(key, cx.me().style.clone())
.unwrap();
}

let scene = use_ref(&cx, || RefCell::new(Scene::new()));

let layout = *renderer_cx.taffy.borrow().layout(key).unwrap();
let mut parent_scene = renderer_cx.scene.borrow_mut();

if cx.is_parent_changed() {
Expand Down
44 changes: 44 additions & 0 deletions src/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::{prelude::*, LayoutContext, WindowContext};

pub(crate) mod canvas;
pub use self::canvas::Canvas;

Expand All @@ -9,3 +11,45 @@ pub use self::text::{use_font, Text};

mod window;
pub use self::window::Window;

/// Use a new layout node.
pub fn use_layout(cx: ScopeState, style: Style) -> (NodeId, Layout) {
let layout_cx = use_context::<LayoutContext>(cx).unwrap();
let renderer_cx = use_context::<WindowContext>(cx).unwrap();

let parent_key = layout_cx.parent_id;
let key = *use_ref(cx, || {
let key = renderer_cx
.taffy
.borrow_mut()
.new_leaf(style.clone())
.unwrap();
renderer_cx
.taffy
.borrow_mut()
.add_child(parent_key, key)
.unwrap();

renderer_cx.is_layout_changed.set(true);

key
});

let last_style = use_ref(cx, || style.clone());
if style != *last_style {
renderer_cx.is_layout_changed.set(true);
renderer_cx
.taffy
.borrow_mut()
.set_style(key, style.clone())
.unwrap();
}

use_drop(cx, move || {
renderer_cx.taffy.borrow_mut().remove(key).unwrap();
renderer_cx.listeners.borrow_mut().remove(&key);
});

let layout = *renderer_cx.taffy.borrow().layout(key).unwrap();
(key, layout)
}
1 change: 0 additions & 1 deletion src/ui/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ impl<C: Compose> Compose for Window<C> {
is_layout_changed: Cell::new(false),
canvas_update_fns: RefCell::default(),
listeners: Rc::default(),
pending_listeners: Rc::default(),
base_color: Cell::new(Color::WHITE),
}
});
Expand Down
14 changes: 10 additions & 4 deletions src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
canvas::CanvasContext,
text::{IntoFontStack, TextContext},
},
Event, WindowContext,
Event,
};
use parley::FontStack;
use std::{cell::RefCell, mem, rc::Rc};
Expand Down Expand Up @@ -136,10 +136,10 @@ unsafe impl<H: Data> Data for OnEvent<H> {

impl<H: Handler> Modify for OnEvent<H> {
fn use_state<'a>(&'a self, cx: ScopeState<'a>) {
let renderer_cx = use_context::<WindowContext>(cx).unwrap();
let canvas_cx = use_context::<CanvasContext>(cx).unwrap();

let state = use_ref(cx, || RefCell::new(self.on_event.borrow_mut().build()));
use_ref(cx, || {
use_provider(cx, || {
// Safety: `f` is removed from `canvas_update_fns` on drop.
let f: Rc<dyn Fn(Event)> = Rc::new(move |msg| {
self.on_event
Expand All @@ -148,7 +148,13 @@ impl<H: Handler> Modify for OnEvent<H> {
});
let f: Rc<dyn Fn(Event)> = unsafe { mem::transmute(f) };

renderer_cx.pending_listeners.borrow_mut().push(f);
let mut pending_listeners = canvas_cx.pending_listeners.borrow().clone();
pending_listeners.push(f);

CanvasContext {
draws: canvas_cx.draws.clone(),
pending_listeners: Rc::new(RefCell::new(pending_listeners)),
}
});
}
}
Expand Down

0 comments on commit a264cdd

Please sign in to comment.