use cgmath::Point2;
use std::{
cell::RefCell,
default::default,
fmt::{Debug, Formatter, Result},
rc::Rc,
};
use stretch::{node::Node, style};
use crate::prelude::Singleton;
use crate::{
foundation::{
properties::ListProperties, Id, ListItemEnterEvent, ListItemLeaveEvent,
ListItemSelectEvent, MouseEvent, Signal,
},
material::Scrollable,
rendering::backend::{WidgetRenderFactory, WidgetRenderHolder},
services::LayoutSystem,
};
use super::{Element, ScrollableElement, WidgetComponent};
pub struct ListElement {
component: Rc<RefCell<WidgetComponent>>,
pub view: ScrollableElement,
pub items: Rc<RefCell<Vec<Id>>>,
pub onselect: Signal<ListItemSelectEvent>,
pub onitementer: Signal<ListItemEnterEvent>,
pub onitemleave: Signal<ListItemLeaveEvent>,
pub renderer: Option<Rc<WidgetRenderHolder<Self>>>,
pub node: Node,
}
impl Debug for ListElement {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("ListElement").finish()
}
}
impl ListElement {
pub fn new(widget: &ListProperties) -> Self {
let node = LayoutSystem::new_node(style::Style { ..default() }, vec![]).unwrap();
let component = WidgetComponent::get(widget.key.id());
let view = ScrollableElement::new(&Scrollable {
..Default::default()
});
Self {
component,
items: Rc::new(RefCell::new(Vec::new())),
onitementer: Signal::new(),
onitemleave: Signal::new(),
onselect: Signal::new(),
view,
renderer: WidgetRenderFactory::global().get::<Self>(),
node,
}
}
pub fn add_item(&self, item: &dyn Element, offset_x: f32, offset_y: f32) {
let childbounds = &self.view.container.children_bounds();
item.set_y_local(item.y_local() + (childbounds.y_local + childbounds.h) + offset_y);
item.set_x_local(item.x_local() + offset_x);
self.view.add(item);
let mut items = self.items.borrow_mut();
items.push(item.id());
}
fn item_mouseenter(&self, event: &MouseEvent, ctrl: Id) {
let items = self.items.borrow();
match items.iter().position(|w| w == &ctrl) {
Some(idx) => self.onitementer.emit(&ListItemEnterEvent {
index: Some(idx),
component: Some(ctrl),
mouse_event: Some(event.clone()),
}),
None => {
log::info!("MouseEnter not found");
}
}
}
fn item_mouseleave(&self, event: &MouseEvent, ctrl: Id) {
let items = self.items.borrow();
match items.iter().position(|w| w == &ctrl) {
Some(idx) => self.onitemleave.emit(&ListItemLeaveEvent {
index: Some(idx),
component: Some(ctrl),
mouse_event: Some(event.clone()),
}),
None => {
log::info!("MouseLeave not found");
}
}
}
fn item_mouseup(&self, event: &MouseEvent, ctrl: Id) {
let items = self.items.borrow();
match items.iter().position(|w| w == &ctrl) {
Some(idx) => self.onselect.emit(&ListItemSelectEvent {
index: Some(idx),
component: Some(ctrl),
mouse_event: Some(event.clone()),
}),
None => {
log::info!("MouseUp not fund");
}
}
}
pub fn clear(&mut self) {
let mut items = self.items.borrow_mut();
while let Some(id) = items.pop() {
}
self.view.refresh_scroll();
self.onselect.emit(&ListItemSelectEvent {
index: None,
component: None,
mouse_event: None,
});
}
}
impl AsRef<RefCell<WidgetComponent>> for ListElement {
fn as_ref(&self) -> &RefCell<WidgetComponent> {
self.component.as_ref()
}
}
impl Element for ListElement {
fn destroy(&self) {
self.onselect.clear();
self.onitementer.clear();
self.onitemleave.clear();
}
fn bounds_changed(&self, dx: f32, dy: f32, dw: f32, dh: f32) {
self.view.set_size(self.w(), self.h());
}
fn node(&self) -> Option<Node> {
Some(self.node)
}
fn relayout(&self, origin: Point2<f32>) {
let update_childs = match LayoutSystem::layout(self.node) {
Ok(layout) => {
let mut comp = self.as_ref().borrow_mut();
comp.x = layout.location.x + origin.x;
comp.y = layout.location.y + origin.y;
comp.w = layout.size.width;
comp.h = layout.size.height;
true
}
Err(e) => {
log::error!("{}", e);
false
}
};
if update_childs {
}
}
}