//! Containers that say what the things inside them are. //! //! Each is a [`Container`] with two answers changed: the name a theme matches //! and the accessibility role. They hold no selection and no children of their //! own kind — a tab strip does not own which tab is showing, any more than a //! radio group owns which radio is chosen. Mutual exclusion stays a fact about //! the application's data; what these add is the announcement, which is the //! part a `container` and a theme rule could never have supplied. use guiduck_scene::Fragment; use guiduck_scene::geom::Size; use super::{Container, Widget}; use crate::dirty::Dirt; use crate::style::ComputedStyle; /// Define a container that differs only in its name and its role. macro_rules! role_container { ($(#[$meta:meta])* $name:ident, $type_name:literal, $role:expr) => { $(#[$meta])* #[derive(Default)] pub struct $name(Container); impl $name { pub fn new() -> Self { Self::default() } } impl Widget for $name { fn paint(&mut self, fragment: &mut Fragment, size: Size) { self.0.paint(fragment, size); } fn role(&self) -> accesskit::Role { $role } fn take_dirt(&mut self) -> Dirt { self.0.take_dirt() } fn type_name(&self) -> &'static str { $type_name } fn apply_style(&mut self, style: &ComputedStyle) { self.0.apply_style(style); } } }; } role_container!( /// The strip a set of `tab`s sits in. TabList, "tab-list", accesskit::Role::TabList ); role_container!( /// A list of `list-item`s. /// /// Selection lives in the application's data and reaches each item through /// its `:selected` binding, so this holds nothing. What it adds is that a /// screen reader is told these rows are a list and how many there are — /// which a `container` full of rows cannot say. ListBox, "list", accesskit::Role::ListBox ); #[cfg(test)] mod tests;