use crate::drawing::{Drawable, Plan};
use crate::interacting::{Event, Interactive};
use crate::layouts::{HasPlanner, Layout};
use anyhow::bail;
use skia_safe::{Canvas, Rect};
use std::any::Any;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Edges {
Top,
Left,
Bottom,
Right,
}
#[derive(Clone)]
pub struct EdgeLayoutElement {
pub drawable: Rc<dyn Drawable>,
pub l_edge: Edges,
pub l_margin: f32,
pub t_edge: Edges,
pub t_margin: f32,
pub r_edge: Edges,
pub r_margin: f32,
pub b_edge: Edges,
pub b_margin: f32,
}
pub struct EdgeLayout {
pub childs: RefCell<BTreeMap<String, EdgeLayoutElement>>,
pub planner: RefCell<Option<Rc<dyn Layout>>>,
enabled: RefCell<bool>,
}
impl HasPlanner for EdgeLayout {
fn planner(&self) -> &RefCell<Option<Rc<dyn Layout>>> {
&self.planner
}
fn set_planner(&self, p: Option<Rc<dyn Layout>>) {
*self.planner.borrow_mut() = p;
}
}
impl Drawable for EdgeLayout {
fn draw(&self, canvas: &Canvas) -> anyhow::Result<()> {
for (key, element) in self.childs.borrow().iter() {
if !element.drawable.is_enabled() {
continue;
}
if let Err(e) = element.drawable.draw(canvas) {
println!("EdgeLayout draw error at child {}: {:?}", key, e);
}
}
Ok(())
}
fn get_horizontal_plan(&self) -> Plan {
Plan::FillPositive
}
fn get_vertical_plan(&self) -> Plan {
Plan::FillPositive
}
fn replan(&self) {
for el in self.childs.borrow().values() {
el.drawable.replan();
}
}
fn try_to_interactive(&self) -> Option<&dyn Interactive> {
Some(self)
}
fn is_enabled(&self) -> bool {
*self.enabled.borrow()
}
fn set_enabled(&self, e: bool) {
*self.enabled.borrow_mut() = e
}
fn as_drawable(&self) -> &dyn Drawable {
self
}
}
impl Layout for EdgeLayout {
fn measure_child(&self, c: &dyn Drawable, canvas: &Canvas) -> Rect {
if !c.is_enabled() {
return Rect::new(0.0, 0.0, 0.0, 0.0);
}
let parent_rect = self.get_planned_drawing_area(canvas);
let childs = self.childs.borrow();
let mut target_element = None;
let c_ptr = c as *const dyn Drawable as *const ();
for (_, element) in childs.iter() {
let elem_ptr = &*element.drawable as *const dyn Drawable as *const ();
if std::ptr::eq(c_ptr, elem_ptr) {
target_element = Some(element.clone());
break;
}
}
if let Some(e) = target_element {
let calc_edge = |edge: Edges, margin: f32| -> f32 {
match edge {
Edges::Top => parent_rect.top + margin,
Edges::Bottom => parent_rect.bottom - margin,
Edges::Left => parent_rect.left + margin,
Edges::Right => parent_rect.right - margin,
}
};
Rect {
left: calc_edge(e.l_edge, e.l_margin),
top: calc_edge(e.t_edge, e.t_margin),
right: calc_edge(e.r_edge, e.r_margin),
bottom: calc_edge(e.b_edge, e.b_margin),
}
} else {
Rect::new(0.0, 0.0, 0.0, 0.0)
}
}
fn as_layout(&self) -> &dyn Layout {
self
}
fn foreach_child(&self, f: &mut dyn FnMut(&dyn Drawable)) {
let ch = self.childs.borrow();
for i in ch.iter() {
f(i.1.drawable.as_ref());
}
}
}
impl Interactive for EdgeLayout {
fn handle_and_route(&self, e: &Event, u: &dyn Any) {
self.foreach_child(&mut |x| {
if x.is_enabled()
&& let Some(i) = x.try_to_interactive()
{
i.handle_and_route(e, u);
}
});
}
}
impl EdgeLayout {
pub fn new(is_enabled: bool) -> Rc<Self> {
Rc::new(Self {
childs: RefCell::new(BTreeMap::new()),
planner: RefCell::new(None),
enabled: RefCell::new(is_enabled),
})
}
pub fn add_child(self: Rc<Self>, id: &str, e: EdgeLayoutElement) -> Rc<Self> {
e.drawable.set_planner(Some(self.clone()));
self.childs.borrow_mut().insert(id.to_string(), e);
self
}
pub fn add_child_inplace(self: &Rc<Self>, id: &str, e: EdgeLayoutElement) {
e.drawable.set_planner(Some(self.clone()));
self.childs.borrow_mut().insert(id.to_string(), e);
}
pub fn remove_child(&self, id: &str) {
if let Some(c) = self.lookup_child(id) {
c.drawable.set_planner(None);
self.childs.borrow_mut().remove(id);
}
}
pub fn lookup_child(&self, id: &str) -> Option<EdgeLayoutElement> {
self.childs.borrow().get(id).cloned()
}
#[allow(clippy::too_many_arguments)]
pub fn rewrite_child(
&self,
id: &str,
l_edge: Edges,
l_margin: f32,
t_edge: Edges,
t_margin: f32,
r_edge: Edges,
r_margin: f32,
b_edge: Edges,
b_margin: f32,
) -> anyhow::Result<()> {
if let Some(v) = self.childs.borrow_mut().get_mut(id) {
v.l_edge = l_edge;
v.l_margin = l_margin;
v.t_edge = t_edge;
v.t_margin = t_margin;
v.r_edge = r_edge;
v.r_margin = r_margin;
v.b_edge = b_edge;
v.b_margin = b_margin;
return Ok(());
}
bail!("Id not found")
}
}