freya_core/
element.rs

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}