altui 0.2.0

A state-driven TUI runtime built on top of altui-core
Documentation
use std::{
    ops::Deref,
    sync::atomic::{AtomicUsize, Ordering},
};

use crate::context::{ACTIVE, HOVER};

// Cannot be initialized as zero
static ID_COUNTER: AtomicUsize = AtomicUsize::new(0);

/// Stable identifier for a view inside the runtime.
///
/// `WidgetId` is the small handle used by `altui` to connect:
///
/// - a view
/// - its [`ViewCtx`](crate::ViewCtx)
/// - the global `hover` / `active` state
///
/// It is returned by the `insert_*_view` methods of
/// [`ViewFactory`](crate::ViewFactory) and can be stored by user code if direct
/// access to a specific view is needed later.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct WidgetId(usize);

impl Default for WidgetId {
    fn default() -> Self {
        WidgetId::next()
    }
}

impl WidgetId {
    /// Reserved "no widget" id.
    pub const ZERO: WidgetId = WidgetId(0);

    /// Generates the next runtime id.
    pub fn next() -> Self {
        WidgetId(ID_COUNTER.fetch_add(1, Ordering::Relaxed))
    }

    /// Creates a custom non-zero id.
    ///
    /// This is mainly useful when integrating external identity schemes.
    pub fn custom(id: impl Into<usize>) -> Self {
        let id = id.into();
        if id == 0 {
            panic!("Id could not be zero!");
        }
        WidgetId(id)
    }

    /// Sets this widget as hovered and clears any active widget.
    ///
    /// This is the id-based counterpart of
    /// [`AppHandler::set_hover`](crate::AppHandler::set_hover).
    pub fn set_hover(&self) {
        HOVER.store(self.0, Ordering::Release);
        ACTIVE.store(0, Ordering::Release);
    }

    /// Returns whether this id is currently hovered.
    pub fn is_hover(&self) -> bool {
        self.0 == HOVER.load(Ordering::Acquire)
    }

    /// Returns whether this id is currently active.
    pub fn is_active(&self) -> bool {
        self.0 == ACTIVE.load(Ordering::Acquire)
    }
}

impl Deref for WidgetId {
    type Target = usize;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}