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