use freya_engine::prelude::{
Canvas,
FontCollection,
FontMgr,
};
use freya_native_core::{
prelude::NodeImmutable,
tags::TagName,
NodeId,
};
use freya_node_state::{
TransformState,
ViewportState,
};
use torin::{
prelude::{
Area,
AreaModel,
CursorPoint,
LayoutNode,
},
torin::Torin,
};
use super::*;
use crate::dom::DioxusNode;
pub trait ElementUtils {
fn is_point_inside_area(
&self,
point: &CursorPoint,
_node_ref: &DioxusNode,
layout_node: &LayoutNode,
_scale_factor: f32,
) -> bool {
layout_node.area.contains(point.to_f32())
}
fn clip(
&self,
_layout_node: &LayoutNode,
_node_ref: &DioxusNode,
_canvas: &Canvas,
_scale_factor: f32,
) {
}
#[allow(clippy::too_many_arguments)]
fn render(
self,
layout_node: &LayoutNode,
node_ref: &DioxusNode,
canvas: &Canvas,
font_collection: &mut FontCollection,
font_manager: &FontMgr,
default_fonts: &[String],
scale_factor: f32,
);
fn element_drawing_area(
&self,
layout_node: &LayoutNode,
_node_ref: &DioxusNode,
_scale_factor: f32,
) -> Area {
layout_node.visible_area()
}
fn drawing_area_with_viewports(
&self,
layout_node: &LayoutNode,
node_ref: &DioxusNode,
layout: &Torin<NodeId>,
scale_factor: f32,
) -> Option<Area> {
let mut drawing_area = self.drawing_area(layout_node, node_ref, scale_factor);
let node_viewports = node_ref.get::<ViewportState>().unwrap();
for viewport_id in &node_viewports.viewports {
let viewport = layout.get(*viewport_id).unwrap().visible_area();
drawing_area.clip(&viewport);
if !viewport.intersects(&drawing_area) {
return None;
}
}
Some(drawing_area.inflate(1.0, 1.0))
}
fn drawing_area(
&self,
layout_node: &LayoutNode,
node_ref: &DioxusNode,
scale_factor: f32,
) -> Area {
let drawing_area = self.element_drawing_area(layout_node, node_ref, scale_factor);
let transform = node_ref.get::<TransformState>().unwrap();
if !transform.rotations.is_empty() {
let area = layout_node.visible_area();
drawing_area.max_area_when_rotated(area.center())
} else {
drawing_area
}
}
#[inline]
fn element_needs_cached_area(&self, _node_ref: &DioxusNode) -> bool {
false
}
#[inline]
fn needs_cached_area(&self, node_ref: &DioxusNode) -> bool {
let element_check = self.element_needs_cached_area(node_ref);
let transform = node_ref.get::<TransformState>().unwrap();
let rotate_effect = !transform.rotations.is_empty();
element_check || rotate_effect
}
}
pub trait ElementUtilsResolver {
fn utils(&self) -> Option<ElementWithUtils>;
}
impl ElementUtilsResolver for TagName {
#[inline]
fn utils(&self) -> Option<ElementWithUtils> {
match self {
TagName::Rect => Some(ElementWithUtils::Rect(RectElement)),
TagName::Svg => Some(ElementWithUtils::Svg(SvgElement)),
TagName::Paragraph => Some(ElementWithUtils::Paragraph(ParagraphElement)),
TagName::Image => Some(ElementWithUtils::Image(ImageElement)),
TagName::Label => Some(ElementWithUtils::Label(LabelElement)),
_ => None,
}
}
}
pub enum ElementWithUtils {
Rect(RectElement),
Svg(SvgElement),
Paragraph(ParagraphElement),
Image(ImageElement),
Label(LabelElement),
}
impl ElementUtils for ElementWithUtils {
fn clip(
&self,
layout_node: &LayoutNode,
node_ref: &DioxusNode,
canvas: &Canvas,
scale_factor: f32,
) {
match self {
Self::Rect(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
Self::Svg(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
Self::Paragraph(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
Self::Image(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
Self::Label(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
}
}
fn is_point_inside_area(
&self,
point: &CursorPoint,
node_ref: &DioxusNode,
layout_node: &LayoutNode,
scale_factor: f32,
) -> bool {
match self {
Self::Rect(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
Self::Svg(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
Self::Paragraph(el) => {
el.is_point_inside_area(point, node_ref, layout_node, scale_factor)
}
Self::Image(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
Self::Label(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
}
}
fn render(
self,
layout_node: &LayoutNode,
node_ref: &DioxusNode,
canvas: &Canvas,
font_collection: &mut FontCollection,
font_manager: &FontMgr,
default_fonts: &[String],
scale_factor: f32,
) {
match self {
Self::Rect(el) => el.render(
layout_node,
node_ref,
canvas,
font_collection,
font_manager,
default_fonts,
scale_factor,
),
Self::Svg(el) => el.render(
layout_node,
node_ref,
canvas,
font_collection,
font_manager,
default_fonts,
scale_factor,
),
Self::Paragraph(el) => el.render(
layout_node,
node_ref,
canvas,
font_collection,
font_manager,
default_fonts,
scale_factor,
),
Self::Image(el) => el.render(
layout_node,
node_ref,
canvas,
font_collection,
font_manager,
default_fonts,
scale_factor,
),
Self::Label(el) => el.render(
layout_node,
node_ref,
canvas,
font_collection,
font_manager,
default_fonts,
scale_factor,
),
}
}
fn drawing_area(
&self,
layout_node: &LayoutNode,
node_ref: &DioxusNode,
scale_factor: f32,
) -> Area {
match self {
Self::Rect(el) => el.drawing_area(layout_node, node_ref, scale_factor),
Self::Svg(el) => el.drawing_area(layout_node, node_ref, scale_factor),
Self::Paragraph(el) => el.drawing_area(layout_node, node_ref, scale_factor),
Self::Image(el) => el.drawing_area(layout_node, node_ref, scale_factor),
Self::Label(el) => el.drawing_area(layout_node, node_ref, scale_factor),
}
}
fn needs_cached_area(&self, node_ref: &DioxusNode) -> bool {
match self {
Self::Rect(el) => el.needs_cached_area(node_ref),
Self::Svg(el) => el.needs_cached_area(node_ref),
Self::Paragraph(el) => el.needs_cached_area(node_ref),
Self::Image(el) => el.needs_cached_area(node_ref),
Self::Label(el) => el.needs_cached_area(node_ref),
}
}
}