widgem 0.0.1

A lightweight cross-platform desktop widget toolkit
Documentation
use {crate::system::address, anyhow::Result, log::warn, std::fmt::Debug, thiserror::Error};

mod address;
pub mod button;
pub mod column;
mod common;
mod ext;
mod id;
pub mod image;
pub mod label;
pub mod menu;
pub mod padding_box;
pub mod root;
pub mod row;
pub mod scroll_area;
pub mod scroll_bar;
pub mod stack;
pub mod text_input;
mod widget_trait;
pub mod window;

pub use self::{
    address::WidgetAddress,
    common::{EventFilterFn, WidgetBase, WidgetBaseOf, WidgetCreationContext, WidgetGeometry},
    ext::WidgetExt,
    id::{RawWidgetId, WidgetId},
    widget_trait::Widget,
};

#[derive(Debug, Error)]
#[error("widget not found")]
pub struct WidgetNotFound;

pub fn get_widget_by_address_mut<'a>(
    root_widget: &'a mut dyn Widget,
    address: &WidgetAddress,
) -> Result<&'a mut dyn Widget, WidgetNotFound> {
    let root_address = root_widget.base().address();

    if !address.starts_with(root_address) {
        warn!("get_widget_by_address_mut: address is not within root widget");
        return Err(WidgetNotFound);
    }
    let root_address_len = root_address.path.len();
    let mut current_widget = root_widget;
    for (key, _id) in &address.path[root_address_len..] {
        current_widget = current_widget
            .base_mut()
            .children
            .get_mut(key)
            .ok_or(WidgetNotFound)?
            .as_mut();
    }
    Ok(current_widget)
}

pub fn get_widget_by_id_mut(
    root_widget: &mut dyn Widget,
    id: RawWidgetId,
) -> Result<&mut dyn Widget, WidgetNotFound> {
    let address = address(id).ok_or(WidgetNotFound)?;
    get_widget_by_address_mut(root_widget, &address)
}

pub fn invalidate_size_hint_cache(widget: &mut dyn Widget, pending: &[WidgetAddress]) {
    let common = widget.base_mut();
    for pending_addr in pending {
        if pending_addr.starts_with(common.address()) {
            common.clear_size_hint_cache();
            for child in common.children.values_mut() {
                invalidate_size_hint_cache(child.as_mut(), pending);
            }
            return;
        }
    }
}

#[macro_export]
macro_rules! impl_widget_base {
    () => {
        fn type_name() -> &'static str {
            std::any::type_name::<Self>()
        }

        fn base(&self) -> &$crate::WidgetBase {
            self.base.untyped()
        }

        fn base_mut(&mut self) -> &mut $crate::WidgetBase {
            self.base.untyped_mut()
        }
    };
}