carbide_controls 0.70.1

A set of control widgets for the carbide core crate
Documentation
use carbide_core::widget::*;
use carbide_core::event_handler::{MouseEvent, KeyboardEvent};
use carbide_core::input::MouseButton;
use carbide_core::input::Key;
use carbide_core::state::state::State;

#[event(handle_keyboard_event, handle_mouse_event)]
#[derive(Clone, Widget)]
pub struct PlainButton<GS> where GS: GlobalState {
    id: Id,
    child: Box<dyn Widget<GS>>,
    position: Point,
    dimension: Dimensions,
    on_click: Option<fn(myself: &mut Self, env: &mut Environment<GS>, global_state: &mut GS)>,
    #[state] is_hovered: Box<dyn State<bool, GS>>,
    #[state] is_pressed: Box<dyn State<bool, GS>>,
}

impl<GS: GlobalState> PlainButton<GS> {
    pub fn on_click(mut self, fire: fn(myself: &mut Self, env: &mut Environment<GS>, global_state: &mut GS)) -> Box<Self> {
        self.on_click = Some(fire);
        Box::new(self)
    }

    pub fn hover(mut self, is_hovered: Box<dyn State<bool, GS>>) -> Box<Self> {
        self.is_hovered = is_hovered;
        Box::new(self)
    }

    pub fn pressed(mut self, pressed: Box<dyn State<bool, GS>>) -> Box<Self> {
        self.is_pressed = pressed;
        Box::new(self)
    }

    pub fn new(child: Box<dyn Widget<GS>>) -> Box<Self> {
        Box::new(PlainButton {
            id: Id::new_v4(),
            child,
            position: [0.0,0.0],
            dimension: [0.0,0.0],
            on_click: None,
            is_hovered: false.into(),
            is_pressed: false.into()
        })
    }

    fn handle_mouse_event(&mut self, event: &MouseEvent, _: &bool, env: &mut Environment<GS>, global_state: &mut GS) {
        match event {
            MouseEvent::Press(MouseButton::Left, mouse_position, _) => {
                if self.is_inside(*mouse_position) {
                    *self.is_pressed.get_value_mut(global_state) = true;
                }
            }
            MouseEvent::Release(MouseButton::Left, mouse_position, _) => {
                if self.is_inside(*mouse_position) {
                    *self.is_pressed.get_value_mut(global_state) = false;
                }
            }
            MouseEvent::Move { to, .. } => {
                if *self.is_hovered.get_value(global_state) {
                   if !self.is_inside(*to) {
                       *self.is_hovered.get_value_mut(global_state) = false;
                       *self.is_pressed.get_value_mut(global_state) = false;
                   }
                } else {
                    if self.is_inside(*to) {
                        *self.is_hovered.get_value_mut(global_state) = true;
                    }
                }
            }
            MouseEvent::Click(MouseButton::Left, mouse_position, _) |
            MouseEvent::NClick(MouseButton::Left, mouse_position, _, _) => {
                if self.is_inside(*mouse_position) {
                    if let Some(action) = self.on_click {
                        action(self, env, global_state);
                    }
                }
            }
            _ => ()
        }
    }

    fn handle_keyboard_event(&mut self, event: &KeyboardEvent, env: &mut Environment<GS>, global_state: &mut GS) {
        match event {
            KeyboardEvent::Click(Key::Return, _) => {
                if let Some(action) = self.on_click {
                    action(self, env, global_state);
                }
            }
            _ => ()
        }
    }
}

impl<GS: GlobalState> CommonWidget<GS> for PlainButton<GS> {
    fn get_id(&self) -> Id {
        self.id
    }

    fn get_flag(&self) -> Flags {
        Flags::EMPTY
    }

    fn get_children(&self) -> WidgetIter<GS> {
        if self.child.get_flag() == Flags::PROXY {
            self.child.get_children()
        } else {
            WidgetIter::single(&self.child)
        }
    }

    fn get_children_mut(&mut self) -> WidgetIterMut<GS> {
        if self.child.get_flag() == Flags::PROXY {
            self.child.get_children_mut()
        } else {
            WidgetIterMut::single(&mut self.child)
        }
    }

    fn get_proxied_children(&mut self) -> WidgetIterMut<GS> {
        WidgetIterMut::single(&mut self.child)
    }

    fn get_position(&self) -> Point {
        self.position
    }

    fn set_position(&mut self, position: Dimensions) {
        self.position = position;
    }

    fn get_dimension(&self) -> Dimensions {
        self.dimension
    }

    fn set_dimension(&mut self, dimensions: Dimensions) {
        self.dimension = dimensions
    }
}

impl<GS: GlobalState> ChildRender for PlainButton<GS> {}

impl<GS: GlobalState> Layout<GS> for PlainButton<GS> {
    fn flexibility(&self) -> u32 {
        10
    }

    fn calculate_size(&mut self, requested_size: [f64; 2], env: &Environment<GS>) -> [f64; 2] {
        if let Some(child) = self.get_children_mut().next() {
            child.calculate_size(requested_size, env);
        }

        self.set_dimension(requested_size);

        requested_size
    }

    fn position_children(&mut self) {
        let positioning = BasicLayouter::Center.position();
        let position = self.get_position();
        let dimension = self.get_dimension();

        if let Some(child) = self.get_children_mut().next() {
            positioning(position, dimension, child);
            child.position_children();
        }
    }
}


impl<GS: GlobalState> WidgetExt<GS> for PlainButton<GS> {}