use freya_core::prelude::*;
use torin::prelude::{
Area,
Position,
};
#[derive(PartialEq, Clone, Copy, Debug, Default)]
pub enum AttachedPosition {
Top,
#[default]
Bottom,
Left,
Right,
}
#[derive(PartialEq)]
pub struct Attached {
inner: Element,
children: Vec<Element>,
position: AttachedPosition,
key: DiffKey,
}
impl KeyExt for Attached {
fn write_key(&mut self) -> &mut DiffKey {
&mut self.key
}
}
impl ChildrenExt for Attached {
fn get_children(&mut self) -> &mut Vec<Element> {
&mut self.children
}
}
impl Attached {
pub fn new(inner: impl IntoElement) -> Self {
Self {
inner: inner.into_element(),
children: vec![],
position: AttachedPosition::Bottom,
key: DiffKey::None,
}
}
pub fn position(mut self, position: AttachedPosition) -> Self {
self.position = position;
self
}
pub fn top(self) -> Self {
self.position(AttachedPosition::Top)
}
pub fn bottom(self) -> Self {
self.position(AttachedPosition::Bottom)
}
pub fn left(self) -> Self {
self.position(AttachedPosition::Left)
}
pub fn right(self) -> Self {
self.position(AttachedPosition::Right)
}
}
impl Component for Attached {
fn render(&self) -> impl IntoElement {
let mut inner_area: State<Option<Area>> = use_state(|| None);
let mut attached_area: State<Option<Area>> = use_state(|| None);
let inner = *inner_area.read();
let attached = *attached_area.read();
let is_measured = inner.is_some() && attached.is_some();
let inner_width = inner.map(|a| a.width()).unwrap_or_default();
let inner_height = inner.map(|a| a.height()).unwrap_or_default();
let attached_width = attached.map(|a| a.width()).unwrap_or_default();
let attached_height = attached.map(|a| a.height()).unwrap_or_default();
let position = match self.position {
AttachedPosition::Top => Position::new_absolute()
.top(-attached_height)
.left((inner_width - attached_width) / 2.),
AttachedPosition::Bottom => Position::new_absolute()
.top(inner_height)
.left((inner_width - attached_width) / 2.),
AttachedPosition::Left => Position::new_absolute()
.top((inner_height - attached_height) / 2.)
.left(-attached_width),
AttachedPosition::Right => Position::new_absolute()
.top((inner_height - attached_height) / 2.)
.left(inner_width),
};
rect()
.on_sized(move |e: Event<SizedEventData>| inner_area.set(Some(e.area)))
.child(self.inner.clone())
.maybe_child((!self.children.is_empty()).then(|| {
rect()
.on_sized(move |e: Event<SizedEventData>| attached_area.set(Some(e.area)))
.position(position)
.layer(Layer::Overlay)
.opacity(if is_measured { 1. } else { 0. })
.children(self.children.clone())
}))
}
fn render_key(&self) -> DiffKey {
self.key.clone().or(self.default_key())
}
}