1use std::{
2 any::Any,
3 borrow::Cow,
4 cell::RefCell,
5 collections::HashMap,
6 rc::Rc,
7};
8
9use freya_core::{
10 integration::*,
11 prelude::*,
12};
13use freya_engine::prelude::{
14 ClipOp,
15 Paint,
16 PaintStyle,
17 SkRect,
18};
19pub use plotters;
20pub use skia_plotters_backend::*;
21
22type Callback = Rc<RefCell<dyn FnMut(&mut RenderContext)>>;
23
24pub struct RenderCallback(Callback);
25
26impl RenderCallback {
27 pub fn new(callback: impl FnMut(&mut RenderContext) + 'static) -> Self {
28 Self(Rc::new(RefCell::new(callback)))
29 }
30
31 pub fn call(&self, data: &mut RenderContext) {
32 (self.0.borrow_mut())(data)
33 }
34}
35
36impl Clone for RenderCallback {
37 fn clone(&self) -> Self {
38 Self(self.0.clone())
39 }
40}
41
42impl PartialEq for RenderCallback {
43 fn eq(&self, _other: &Self) -> bool {
44 true
45 }
46}
47
48impl<H: FnMut(&mut RenderContext) + 'static> From<H> for RenderCallback {
49 fn from(value: H) -> Self {
50 RenderCallback::new(value)
51 }
52}
53
54#[derive(PartialEq, Clone)]
55pub struct PlotElement {
56 pub layout: LayoutData,
57 pub event_handlers: FxHashMap<EventName, EventHandlerType>,
58 pub effect: Option<EffectData>,
59 pub on_render: RenderCallback,
60}
61
62impl PlotElement {}
63
64impl ElementExt for PlotElement {
65 fn changed(&self, other: &Rc<dyn ElementExt>) -> bool {
66 let Some(rect) = (other.as_ref() as &dyn Any).downcast_ref::<Self>() else {
67 return false;
68 };
69
70 self != rect
71 }
72
73 fn diff(&self, other: &Rc<dyn ElementExt>) -> DiffModifies {
74 let Some(rect) = (other.as_ref() as &dyn Any).downcast_ref::<Self>() else {
75 return DiffModifies::all();
76 };
77
78 let mut diff = DiffModifies::empty();
79
80 if self.effect != rect.effect {
81 diff.insert(DiffModifies::EFFECT);
82 }
83
84 if !self.layout.layout.self_layout_eq(&rect.layout.layout) {
85 diff.insert(DiffModifies::STYLE);
86 diff.insert(DiffModifies::LAYOUT);
87 }
88
89 if !self.layout.layout.inner_layout_eq(&rect.layout.layout) {
90 diff.insert(DiffModifies::STYLE);
91 diff.insert(DiffModifies::INNER_LAYOUT);
92 }
93
94 if self.event_handlers != rect.event_handlers {
95 diff.insert(DiffModifies::EVENT_HANDLERS);
96 }
97
98 if self.on_render != rect.on_render {
99 diff.insert(DiffModifies::STYLE);
100 }
101
102 diff
103 }
104
105 fn layout(&'_ self) -> Cow<'_, LayoutData> {
106 Cow::Borrowed(&self.layout)
107 }
108
109 fn effect(&'_ self) -> Option<Cow<'_, EffectData>> {
110 self.effect.as_ref().map(Cow::Borrowed)
111 }
112
113 fn style(&'_ self) -> Cow<'_, StyleState> {
114 Cow::Owned(StyleState::default())
115 }
116
117 fn text_style(&'_ self) -> Cow<'_, TextStyleData> {
118 Cow::Owned(TextStyleData::default())
119 }
120
121 fn accessibility(&'_ self) -> Cow<'_, AccessibilityData> {
122 Cow::Owned(AccessibilityData::default())
123 }
124
125 fn events_handlers(&'_ self) -> Option<Cow<'_, FxHashMap<EventName, EventHandlerType>>> {
126 Some(Cow::Borrowed(&self.event_handlers))
127 }
128
129 fn clip(&self, context: ClipContext) {
130 let area = context.visible_area;
131
132 context.canvas.clip_rect(
133 SkRect::new(area.min_x(), area.min_y(), area.max_x(), area.max_y()),
134 ClipOp::Intersect,
135 true,
136 );
137 }
138
139 fn render(&self, mut context: RenderContext) {
140 let style = self.style();
141 let area = context.layout_node.area;
142
143 let mut paint = Paint::default();
144 paint.set_anti_alias(true);
145 paint.set_style(PaintStyle::Fill);
146 style.background.apply_to_paint(&mut paint, area);
147
148 context.canvas.draw_rect(
149 SkRect::new(area.min_x(), area.min_y(), area.max_x(), area.max_y()),
150 &paint,
151 );
152
153 context
154 .canvas
155 .scale((context.scale_factor as f32, context.scale_factor as f32));
156 context.canvas.translate((area.min_x(), area.min_y()));
157 self.on_render.call(&mut context);
158 context.canvas.restore();
159 }
160}
161
162pub struct Plot {
163 element: PlotElement,
164 elements: Vec<Element>,
165 key: DiffKey,
166}
167
168impl ChildrenExt for Plot {
169 fn get_children(&mut self) -> &mut Vec<Element> {
170 &mut self.elements
171 }
172}
173
174impl KeyExt for Plot {
175 fn write_key(&mut self) -> &mut DiffKey {
176 &mut self.key
177 }
178}
179
180impl EventHandlersExt for Plot {
181 fn get_event_handlers(&mut self) -> &mut FxHashMap<EventName, EventHandlerType> {
182 &mut self.element.event_handlers
183 }
184}
185
186impl MaybeExt for Plot {}
187
188impl From<Plot> for Element {
189 fn from(value: Plot) -> Self {
190 Element::Element {
191 key: value.key,
192 element: Rc::new(value.element),
193 elements: value.elements,
194 }
195 }
196}
197
198pub fn plot(on_render: RenderCallback) -> Plot {
199 Plot::new(on_render)
200}
201
202impl Plot {
203 pub fn new(on_render: RenderCallback) -> Self {
204 Self {
205 element: PlotElement {
206 on_render,
207 layout: LayoutData::default(),
208 event_handlers: HashMap::default(),
209 effect: None,
210 },
211 elements: Vec::default(),
212 key: DiffKey::None,
213 }
214 }
215
216 pub fn try_downcast(element: &dyn ElementExt) -> Option<PlotElement> {
217 (element as &dyn Any).downcast_ref::<PlotElement>().cloned()
218 }
219}
220
221impl LayoutExt for Plot {
222 fn get_layout(&mut self) -> &mut LayoutData {
223 &mut self.element.layout
224 }
225}
226
227impl ContainerExt for Plot {}
228
229impl ContainerWithContentExt for Plot {}