use std::fmt;
use std::rc::Rc;
use crate::mark::Mark;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Role {
Group,
Text,
Button,
Image,
List,
ListItem,
Table,
Row,
Cell,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Bounds {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}
impl Bounds {
pub fn new(x: f64, y: f64, width: f64, height: f64) -> Self {
Self {
x,
y,
width,
height,
}
}
pub fn center(&self) -> (f64, f64) {
(self.x + self.width / 2.0, self.y + self.height / 2.0)
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct Semantic {
pub role: Role,
pub key: Option<u64>,
pub text: Option<String>,
pub mark: Option<&'static str>,
pub tip: Option<String>,
pub bounds: Option<Bounds>,
pub children: Children,
}
#[derive(Clone, Debug)]
pub enum Children {
Nodes(Vec<Semantic>),
Items(Items),
}
impl Semantic {
pub fn new(role: Role) -> Self {
Self {
role,
key: None,
text: None,
mark: None,
tip: None,
bounds: None,
children: Children::Nodes(Vec::new()),
}
}
pub fn key(self, key: u64) -> Self {
Self {
key: Some(key),
..self
}
}
pub fn text(self, text: impl Into<String>) -> Self {
Self {
text: Some(text.into()),
..self
}
}
pub fn mark(self, mark: impl Mark) -> Self {
Self {
mark: Some(mark.name()),
..self
}
}
pub fn tip(self, tip: impl Into<String>) -> Self {
Self {
tip: Some(tip.into()),
..self
}
}
pub fn bounds(self, bounds: Bounds) -> Self {
Self {
bounds: Some(bounds),
..self
}
}
pub fn children(self, children: impl IntoIterator<Item = Semantic>) -> Self {
Self {
children: Children::Nodes(children.into_iter().collect()),
..self
}
}
pub fn items(self, items: Items) -> Self {
Self {
children: Children::Items(items),
..self
}
}
}
#[derive(Clone)]
pub struct Items {
len: usize,
item: Rc<dyn Fn(usize) -> Semantic>,
show: Rc<dyn Fn(usize)>,
}
impl Items {
pub fn new(
len: usize,
item: impl Fn(usize) -> Semantic + 'static,
show: impl Fn(usize) + 'static,
) -> Self {
Self {
len,
item: Rc::new(item),
show: Rc::new(show),
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn item(&self, index: usize) -> Semantic {
(self.item)(index)
}
pub fn show(&self, index: usize) {
(self.show)(index)
}
}
impl fmt::Debug for Items {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Items").field("len", &self.len).finish_non_exhaustive()
}
}