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