embedded-gui 0.2.0

no_std GUI and HUD primitives for embedded-graphics displays
Documentation
use embedded_graphics_core::{draw_target::DrawTarget, pixelcolor::Rgb565};

use crate::{geometry::Rect, render::RenderCtx};

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct WidgetFlags(u16);

impl WidgetFlags {
    pub const HIDDEN: Self = Self(1 << 0);
    pub const DISABLED: Self = Self(1 << 1);
    pub const CLICKABLE: Self = Self(1 << 2);
    pub const SCROLLABLE: Self = Self(1 << 3);
    pub const FOCUSABLE: Self = Self(1 << 4);
    pub const CLIP_CHILDREN: Self = Self(1 << 5);
    pub const EVENT_BUBBLE: Self = Self(1 << 6);

    pub const fn empty() -> Self {
        Self(0)
    }

    pub const fn bits(self) -> u16 {
        self.0
    }

    pub const fn from_bits(bits: u16) -> Self {
        Self(bits)
    }

    pub const fn contains(self, flag: Self) -> bool {
        self.0 & flag.0 == flag.0
    }

    pub fn insert(&mut self, flag: Self) {
        self.0 |= flag.0;
    }

    pub fn remove(&mut self, flag: Self) {
        self.0 &= !flag.0;
    }

    pub fn set(&mut self, flag: Self, enabled: bool) {
        if enabled {
            self.insert(flag);
        } else {
            self.remove(flag);
        }
    }
}

impl core::ops::BitOr for WidgetFlags {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self::Output {
        Self(self.0 | rhs.0)
    }
}

impl core::ops::BitOrAssign for WidgetFlags {
    fn bitor_assign(&mut self, rhs: Self) {
        self.0 |= rhs.0;
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct WidgetId(pub u16);

impl WidgetId {
    pub const fn new(raw: u16) -> Self {
        Self(raw)
    }

    pub const fn raw(self) -> u16 {
        self.0
    }
}

pub trait StatefulWidget<State> {
    fn render_stateful<D>(
        &self,
        area: Rect,
        state: &mut State,
        ctx: &mut RenderCtx<'_, D>,
    ) -> Result<(), D::Error>
    where
        D: DrawTarget<Color = Rgb565>;
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EventPhase {
    Capture,
    Target,
    Bubble,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EventPolicy {
    Continue,
    Stop,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct EventContext {
    pub target: WidgetId,
    pub current: WidgetId,
    pub phase: EventPhase,
}

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct FocusGroupId(pub u8);

impl FocusGroupId {
    pub const ROOT: Self = Self(0);

    pub const fn new(raw: u8) -> Self {
        Self(raw)
    }

    pub const fn raw(self) -> u8 {
        self.0
    }
}

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct StyleClassId(pub u8);

impl StyleClassId {
    pub const NONE: Self = Self(0);

    pub const fn new(raw: u8) -> Self {
        Self(raw)
    }

    pub const fn raw(self) -> u8 {
        self.0
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MenuContract {
    pub wrap_navigation: bool,
    pub select_opens_dropdown: bool,
    pub back_closes_dropdown: bool,
    pub back_closes_notification_sheet: bool,
    pub select_toggles_feed_expanded: bool,
}

impl Default for MenuContract {
    fn default() -> Self {
        Self {
            wrap_navigation: true,
            select_opens_dropdown: true,
            back_closes_dropdown: true,
            back_closes_notification_sheet: true,
            select_toggles_feed_expanded: true,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PropertyKey {
    Value,
    Min,
    Max,
    Text,
    Progress,
    Selected,
    State,
    Offset,
    Open,
    Expanded,
    Custom(u16),
}

#[derive(Clone, Debug, PartialEq)]
pub enum PropertyValue<'a> {
    Float(f32),
    Int(i32),
    Usize(usize),
    Bool(bool),
    Str(&'a str),
    Char(char),
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PropertyError {
    NotFound,
    ReadOnly,
    TypeMismatch,
}

pub trait Widget {
    fn render_widget_bounds(&self, _bounds: Rect, _style: &crate::style::Style) {}

    fn handle_widget_event(
        &mut self,
        _event: &crate::input::UiEvent,
        _ctx: &mut EventContext,
    ) -> EventPolicy {
        EventPolicy::Continue
    }

    fn get_property(&self, _key: PropertyKey) -> Option<PropertyValue<'_>> {
        None
    }

    fn set_property<'a>(
        &mut self,
        _key: PropertyKey,
        _val: PropertyValue<'a>,
    ) -> Result<(), PropertyError> {
        Err(PropertyError::NotFound)
    }
}