freya_hooks/
use_canvas.rs

1use std::sync::{
2    Arc,
3    Mutex,
4};
5
6use dioxus_core::AttributeValue;
7use dioxus_hooks::{
8    use_memo,
9    use_reactive,
10    Dependency,
11};
12use dioxus_signals::{
13    Memo,
14    Readable,
15};
16use freya_core::custom_attributes::{
17    CanvasReference,
18    CanvasRunner,
19    CanvasRunnerContext,
20    CustomAttributeValues,
21};
22
23/// Holds a rendering hook callback that allows to render to the Canvas.
24#[derive(PartialEq, Clone)]
25pub struct UseCanvas {
26    runner: Memo<UseCanvasRunner>,
27}
28
29#[derive(Clone)]
30pub struct UseCanvasRunner(pub Arc<Mutex<CanvasRunner>>);
31
32impl PartialEq for UseCanvasRunner {
33    fn eq(&self, other: &Self) -> bool {
34        Arc::ptr_eq(&self.0, &other.0)
35    }
36}
37
38impl UseCanvas {
39    pub fn attribute(&self) -> AttributeValue {
40        AttributeValue::any_value(CustomAttributeValues::Canvas(CanvasReference {
41            runner: self.runner.read().0.clone(),
42        }))
43    }
44}
45
46/// Register a rendering hook to gain access to the Canvas.
47/// Reactivity managed through signals.
48///
49/// ## Usage
50/// ```rust,no_run
51/// # use freya::prelude::*;
52/// fn app() -> Element {
53///     let (reference, size) = use_node_signal();
54///     let mut value = use_signal(|| 0);
55///     let platform = use_platform();
56///
57///     let canvas = use_canvas(move || {
58///         let curr = value();
59///         platform.invalidate_drawing_area(size.peek().area);
60///         platform.request_animation_frame();
61///         move |ctx| {
62///             // Draw using the canvas !
63///             // use `curr`
64///         }
65///     });
66///
67///     rsx!(rect {
68///         onclick: move |_| {
69///             value += 1;
70///         },
71///         canvas_reference: canvas.attribute(),
72///         reference,
73///         width: "fill",
74///         height: "fill",
75///     })
76/// }
77/// ```
78pub fn use_canvas<T: FnMut(&mut CanvasRunnerContext) + Sync + Send + 'static>(
79    mut renderer_cb: impl FnMut() -> T + 'static,
80) -> UseCanvas {
81    let runner = use_memo(move || UseCanvasRunner(Arc::new(Mutex::new(renderer_cb()))));
82
83    UseCanvas { runner }
84}
85
86/// Register a rendering hook to gain access to the Canvas.
87/// Reactivity managed with manual dependencies.
88///
89/// ## Usage
90/// ```rust,no_run
91/// # use freya::prelude::*;
92/// fn app() -> Element {
93///     let (reference, size) = use_node_signal();
94///     let mut value = use_signal(|| 0);
95///     let platform = use_platform();
96///
97///     let canvas = use_canvas_with_deps(&value(), move |curr| {
98///         platform.invalidate_drawing_area(size.peek().area);
99///         platform.request_animation_frame();
100///         move |ctx| {
101///             // Draw using the canvas !
102///             // use `curr`
103///         }
104///     });
105///
106///     rsx!(rect {
107///         onclick: move |_| {
108///             value += 1;
109///         },
110///         canvas_reference: canvas.attribute(),
111///         reference,
112///         width: "fill",
113///         height: "fill",
114///     })
115/// }
116/// ```
117pub fn use_canvas_with_deps<
118    D: Dependency,
119    T: FnMut(&mut CanvasRunnerContext) + Sync + Send + 'static,
120>(
121    dependencies: D,
122    mut renderer_cb: impl FnMut(D::Out) -> T + 'static,
123) -> UseCanvas
124where
125    D::Out: 'static,
126{
127    let runner = use_memo(use_reactive(dependencies, move |dependencies| {
128        UseCanvasRunner(Arc::new(Mutex::new(renderer_cb(dependencies))))
129    }));
130
131    UseCanvas { runner }
132}