1use std::{
2 any::Any,
3 borrow::Cow,
4 fmt::Debug,
5 rc::Rc,
6};
7
8use freya_engine::prelude::{
9 Canvas,
10 FontCollection,
11 FontMgr,
12};
13use rustc_hash::FxHashMap;
14use torin::prelude::{
15 Area,
16 LayoutNode,
17 Size2D,
18};
19
20use crate::{
21 data::{
22 AccessibilityData,
23 EffectData,
24 LayoutData,
25 StyleState,
26 TextStyleData,
27 TextStyleState,
28 },
29 diff_key::DiffKey,
30 event_handler::EventHandler,
31 events::{
32 data::{
33 Event,
34 KeyboardEventData,
35 MouseEventData,
36 PointerEventData,
37 SizedEventData,
38 TouchEventData,
39 WheelEventData,
40 },
41 name::EventName,
42 },
43 helpers::from_fn_standalone_borrowed_keyed,
44 layers::Layer,
45 node_id::NodeId,
46 prelude::{
47 FileEventData,
48 ImePreeditEventData,
49 },
50 text_cache::TextCache,
51 tree::{
52 DiffModifies,
53 Tree,
54 },
55};
56
57pub trait ElementExt: Any {
58 fn into_element(self) -> Element
59 where
60 Self: Sized + Into<Element>,
61 {
62 self.into()
63 }
64
65 fn changed(&self, _other: &Rc<dyn ElementExt>) -> bool {
66 false
67 }
68
69 fn diff(&self, _other: &Rc<dyn ElementExt>) -> DiffModifies {
70 DiffModifies::empty()
71 }
72
73 fn layout(&'_ self) -> Cow<'_, LayoutData> {
74 Cow::Owned(Default::default())
75 }
76
77 fn accessibility(&'_ self) -> Cow<'_, AccessibilityData> {
78 Cow::Owned(Default::default())
79 }
80
81 fn effect(&'_ self) -> Option<Cow<'_, EffectData>> {
82 None
83 }
84
85 fn style(&'_ self) -> Cow<'_, StyleState> {
86 Cow::Owned(Default::default())
87 }
88
89 fn text_style(&'_ self) -> Cow<'_, TextStyleData> {
90 Cow::Owned(Default::default())
91 }
92
93 fn layer(&self) -> Layer {
94 Layer::default()
95 }
96
97 fn events_handlers(&'_ self) -> Option<Cow<'_, FxHashMap<EventName, EventHandlerType>>> {
98 None
99 }
100
101 fn measure(&self, _context: LayoutContext) -> Option<(Size2D, Rc<dyn Any>)> {
102 None
103 }
104
105 fn should_hook_measurement(&self) -> bool {
106 false
107 }
108
109 fn should_measure_inner_children(&self) -> bool {
110 true
111 }
112
113 fn is_point_inside(&self, context: EventMeasurementContext) -> bool {
114 context
115 .layout_node
116 .visible_area()
117 .contains(context.cursor.to_f32())
118 }
119
120 fn clip(&self, _context: ClipContext) {}
121
122 fn render(&self, _context: RenderContext) {}
123}
124
125#[allow(dead_code)]
126pub struct LayoutContext<'a> {
127 pub node_id: NodeId,
128 pub torin_node: &'a torin::node::Node,
129 pub area_size: &'a Size2D,
130 pub font_collection: &'a FontCollection,
131 pub font_manager: &'a FontMgr,
132 pub text_style_state: &'a TextStyleState,
133 pub fallback_fonts: &'a [Cow<'static, str>],
134 pub scale_factor: f64,
135 pub text_cache: &'a mut TextCache,
136}
137
138#[allow(dead_code)]
139pub struct RenderContext<'a> {
140 pub font_collection: &'a mut FontCollection,
141 pub canvas: &'a Canvas,
142 pub layout_node: &'a LayoutNode,
143 pub text_style_state: &'a TextStyleState,
144 pub tree: &'a Tree,
145 pub scale_factor: f64,
146}
147
148pub struct EventMeasurementContext<'a> {
149 pub cursor: ragnarok::CursorPoint,
150 pub layout_node: &'a LayoutNode,
151 pub scale_factor: f64,
152}
153
154pub struct ClipContext<'a> {
155 pub canvas: &'a Canvas,
156 pub visible_area: &'a Area,
157 pub scale_factor: f64,
158}
159
160impl<T: Any + PartialEq> ComponentProps for T {
161 fn changed(&self, other: &dyn ComponentProps) -> bool {
162 let other = (other as &dyn Any).downcast_ref::<T>().unwrap();
163 self != other
164 }
165}
166
167pub trait ComponentProps: Any {
168 fn changed(&self, other: &dyn ComponentProps) -> bool;
169}
170
171#[derive(Clone)]
172pub enum Element {
173 Component {
174 key: DiffKey,
175
176 comp: Rc<dyn Fn(Rc<dyn ComponentProps>) -> Element>,
177
178 props: Rc<dyn ComponentProps>,
179 },
180 Element {
181 key: DiffKey,
182 element: Rc<dyn ElementExt>,
183 elements: Vec<Element>,
184 },
185}
186
187impl Debug for Element {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 match self {
190 Self::Element { key, elements, .. } => {
191 f.write_str(&format!("Element {{ key: {:?} }}", key))?;
192 elements.fmt(f)
193 }
194 Self::Component { key, .. } => f.write_str(&format!("Component {{ key: {:?} }}", key)),
195 }
196 }
197}
198
199pub trait IntoElement {
200 fn into_element(self) -> Element;
201}
202
203impl<T: Into<Element>> IntoElement for T {
204 fn into_element(self) -> Element {
205 self.into()
206 }
207}
208
209#[derive(Clone)]
210pub struct FpRender {
211 render: Rc<dyn Fn() -> Element + 'static>,
212}
213
214impl FpRender {
215 pub fn from_render(render: impl Render + 'static) -> Self {
216 Self {
217 render: Rc::new(move || render.render().into_element()),
218 }
219 }
220}
221
222impl PartialEq for FpRender {
223 fn eq(&self, _other: &Self) -> bool {
224 true
225 }
226}
227
228impl<F, E> From<F> for FpRender
229where
230 F: Fn() -> E + 'static,
231 E: IntoElement,
232{
233 fn from(render: F) -> Self {
234 FpRender {
235 render: Rc::new(move || render().into_element()),
236 }
237 }
238}
239
240impl Render for FpRender {
241 fn render(&self) -> impl IntoElement {
242 (self.render)()
243 }
244}
245
246pub trait Render: RenderKey + 'static {
247 fn render(&self) -> impl IntoElement;
248
249 fn render_key(&self) -> DiffKey {
250 self.default_key()
251 }
252}
253
254pub trait RenderOwned: RenderKey + 'static {
255 fn render(self) -> impl IntoElement;
256
257 fn render_key(&self) -> DiffKey {
258 self.default_key()
259 }
260}
261
262pub trait RenderKey {
263 fn default_key(&self) -> DiffKey;
264}
265
266impl<T> Render for T
267where
268 T: RenderOwned + Clone,
269{
270 fn render(&self) -> impl IntoElement {
271 <Self as RenderOwned>::render(self.clone())
272 }
273 fn render_key(&self) -> DiffKey {
274 <Self as RenderOwned>::render_key(self)
275 }
276}
277
278impl<T> RenderKey for T
279where
280 T: Render,
281{
282 fn default_key(&self) -> DiffKey {
283 DiffKey::U64(Self::render as *const () as u64)
284 }
285}
286
287impl<T: Render + PartialEq> From<T> for Element {
288 fn from(value: T) -> Self {
289 from_fn_standalone_borrowed_keyed(value.render_key(), value, |v| v.render().into_element())
290 }
291}
292
293impl PartialEq for Element {
294 fn eq(&self, other: &Self) -> bool {
295 match (self, other) {
296 (
297 Self::Component {
298 key: key1,
299 props: props1,
300 ..
301 },
302 Self::Component {
303 key: key2,
304 props: props2,
305 ..
306 },
307 ) => key1 == key2 && !props1.changed(props2.as_ref()),
308 (
309 Self::Element {
310 key: key1,
311 element: element1,
312 elements: elements1,
313 },
314 Self::Element {
315 key: key2,
316 element: element2,
317 elements: elements2,
318 },
319 ) => key1 == key2 && !element1.changed(element2) && elements1 == elements2,
320 _ => false,
321 }
322 }
323}
324
325#[derive(Clone, PartialEq)]
326pub enum EventHandlerType {
327 Mouse(EventHandler<Event<MouseEventData>>),
328 Keyboard(EventHandler<Event<KeyboardEventData>>),
329 Sized(EventHandler<Event<SizedEventData>>),
330 Wheel(EventHandler<Event<WheelEventData>>),
331 Touch(EventHandler<Event<TouchEventData>>),
332 Pointer(EventHandler<Event<PointerEventData>>),
333 ImePreedit(EventHandler<Event<ImePreeditEventData>>),
334 File(EventHandler<Event<FileEventData>>),
335}