freya-components 0.4.0-alpha.5

Components for Freya apps
Documentation
use freya_core::prelude::*;
use torin::prelude::{
    Area,
    CursorPoint,
    Position,
};

#[derive(Clone)]
struct DraggableCanvasLayout(State<Area>);

#[derive(Clone)]
struct DraggableCanvasRegistry(State<Vec<usize>>);

#[derive(PartialEq)]
pub struct DraggableCanvas {
    children: Vec<Element>,
    layout: LayoutData,
    key: DiffKey,
}

impl KeyExt for DraggableCanvas {
    fn write_key(&mut self) -> &mut DiffKey {
        &mut self.key
    }
}

impl Default for DraggableCanvas {
    fn default() -> Self {
        Self::new()
    }
}

impl DraggableCanvas {
    pub fn new() -> Self {
        Self {
            children: vec![],
            layout: LayoutData::default(),
            key: DiffKey::None,
        }
    }
}

impl LayoutExt for DraggableCanvas {
    fn get_layout(&mut self) -> &mut LayoutData {
        &mut self.layout
    }
}

impl ContainerExt for DraggableCanvas {}

impl ChildrenExt for DraggableCanvas {
    fn get_children(&mut self) -> &mut Vec<Element> {
        &mut self.children
    }
}

impl Render for DraggableCanvas {
    fn render(&self) -> impl IntoElement {
        let mut layout = use_state(Area::default);
        use_provide_context(move || DraggableCanvasLayout(layout));
        use_provide_context(|| DraggableCanvasRegistry(State::create(Vec::new())));
        rect()
            .layout(self.layout.clone())
            .on_sized(move |e: Event<SizedEventData>| layout.set(e.visible_area))
            .children(self.children.clone())
    }
    fn render_key(&self) -> DiffKey {
        self.key.clone().or(self.default_key())
    }
}

#[derive(PartialEq)]
pub struct Draggable {
    initial_position: CursorPoint,
    children: Vec<Element>,
    key: DiffKey,
}

impl Default for Draggable {
    fn default() -> Self {
        Self::new()
    }
}

impl Draggable {
    pub fn new() -> Self {
        Self {
            initial_position: CursorPoint::zero(),
            children: vec![],
            key: DiffKey::None,
        }
    }

    pub fn inital_position(mut self, initial_position: impl Into<CursorPoint>) -> Self {
        self.initial_position = initial_position.into();
        self
    }
}

impl KeyExt for Draggable {
    fn write_key(&mut self) -> &mut DiffKey {
        &mut self.key
    }
}

impl ChildrenExt for Draggable {
    fn get_children(&mut self) -> &mut Vec<Element> {
        &mut self.children
    }
}

impl Render for Draggable {
    fn render(&self) -> impl IntoElement {
        let mut position = use_state(|| self.initial_position);
        let mut dragging_position = use_state::<Option<CursorPoint>>(|| None);
        let DraggableCanvasLayout(layout) = use_consume::<DraggableCanvasLayout>();
        let DraggableCanvasRegistry(mut registry) = use_consume::<DraggableCanvasRegistry>();
        let id = use_id::<DraggableCanvasLayout>();

        use_hook(move || {
            registry.write().push(id);
        });

        use_drop(move || {
            registry.write().retain(|i| *i != id);
        });

        let on_global_mouse_move = move |e: Event<MouseEventData>| {
            if let Some(dragging_position) = dragging_position() {
                position.set(CursorPoint::new(
                    e.global_location.x - dragging_position.x,
                    e.global_location.y - dragging_position.y,
                ));
                e.stop_propagation();
            }
        };

        let on_pointer_down = move |e: Event<PointerEventData>| {
            dragging_position.set(Some(CursorPoint::new(
                e.element_location().x + layout.read().min_x() as f64,
                e.element_location().y + layout.read().min_y() as f64,
            )));
            e.stop_propagation();
            let mut registry = registry.write();
            registry.retain(|i| *i != id);
            registry.insert(0, id);
        };

        let on_capture_global_mouse_up = move |e: Event<MouseEventData>| {
            if dragging_position.read().is_some() {
                e.stop_propagation();
                e.prevent_default();
                dragging_position.set(None);
            }
        };

        let (left, top) = position().to_tuple();

        let layer = registry
            .read()
            .iter()
            .rev()
            .position(|i| *i == id)
            .map(|layer| layer * 1024)
            .unwrap_or_default();

        rect()
            .on_global_mouse_move(on_global_mouse_move)
            .on_pointer_down(on_pointer_down)
            .on_capture_global_mouse_up(on_capture_global_mouse_up)
            .position(Position::new_absolute().left(left as f32).top(top as f32))
            .layer(layer as i16)
            .children(self.children.clone())
    }

    fn render_key(&self) -> DiffKey {
        self.key.clone().or(self.default_key())
    }
}