use std::{num::NonZeroU32, ops};
use bitflags::bitflags;
use serde::{Deserialize, Serialize};
use zng_txt::Txt;
use zng_unit::{PxRect, PxSize, PxTransform};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AccessRole {
Button,
CheckBox,
GridCell,
Link,
MenuItem,
MenuItemCheckBox,
MenuItemRadio,
Option,
ProgressBar,
Radio,
ScrollBar,
SearchBox,
Slider,
SpinButton,
Switch,
Tab,
TabPanel,
TextInput,
TreeItem,
ComboBox,
Grid,
ListBox,
Menu,
MenuBar,
RadioGroup,
TabList,
Tree,
TreeGrid,
Application,
Article,
Cell,
Column,
ColumnHeader,
Definition,
Document,
Feed,
Figure,
Group,
Heading,
Image,
List,
ListItem,
Math,
Note,
Row,
RowGroup,
RowHeader,
Separator,
Table,
Term,
ToolBar,
ToolTip,
Banner,
Complementary,
ContentInfo,
Form,
Main,
Navigation,
Region,
Search,
Alert,
Log,
Marquee,
Status,
Timer,
AlertDialog,
Dialog,
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: AccessRole) -> Option<AccessRole>;
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum CurrentKind {
Page,
Step,
Location,
Date,
Time,
Item,
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: CurrentKind) -> Option<CurrentKind>;
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AccessState {
AutoComplete(AutoComplete),
Checked(Option<bool>),
Current(CurrentKind),
Disabled,
ErrorMessage(AccessNodeId),
Expanded(bool),
Popup(Popup),
Invalid(Invalid),
Label(Txt),
Level(NonZeroU32),
Modal,
MultiSelectable,
Orientation(Orientation),
Placeholder(Txt),
ReadOnly,
Required,
Selected,
Sort(SortDirection),
ValueMax(f64),
ValueMin(f64),
Value(f64),
ValueText(Txt),
Live {
indicator: LiveIndicator,
atomic: bool,
busy: bool,
},
ActiveDescendant(AccessNodeId),
ColCount(usize),
ColIndex(usize),
ColSpan(usize),
Controls(Vec<AccessNodeId>),
DescribedBy(Vec<AccessNodeId>),
Details(Vec<AccessNodeId>),
FlowTo(Vec<AccessNodeId>),
LabelledBy(Vec<AccessNodeId>),
LabelledByChild,
Owns(Vec<AccessNodeId>),
ItemIndex(usize),
RowCount(usize),
RowIndex(usize),
RowSpan(usize),
ItemCount(usize),
Lang(unic_langid::LanguageIdentifier),
ScrollHorizontal(f32),
ScrollVertical(f32),
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: AccessState) -> Option<AccessState>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum LiveIndicator {
Assertive,
OnlyFocused,
Polite,
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: LiveIndicator) -> Option<LiveIndicator>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SortDirection {
Ascending,
Descending,
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: SortDirection) -> Option<SortDirection>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Orientation {
Horizontal,
Vertical,
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: Orientation) -> Option<Orientation>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Popup {
Menu,
ListBox,
Tree,
Grid,
Dialog,
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: Popup) -> Option<Popup>;
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AutoComplete: u8 {
const INLINE = 0b01;
const LIST = 0b10;
const BOTH = 0b11;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Invalid: u8 {
const ANY = 0b001;
const GRAMMAR = 0b011;
const SPELLING = 0b101;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AccessNodeId(pub u64);
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: AccessNodeId) -> Option<AccessNodeId>;
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AccessCmd {
Click(bool),
Focus(bool),
FocusNavOrigin,
SetExpanded(bool),
Increment(i32),
SetToolTipVis(bool),
Scroll(ScrollCmd),
ReplaceSelectedText(Txt),
SelectText {
start: (AccessNodeId, usize),
caret: (AccessNodeId, usize),
},
SetString(Txt),
SetNumber(f64),
}
impl AccessCmd {
pub fn name(&self) -> AccessCmdName {
match self {
AccessCmd::Click(_) => AccessCmdName::Click,
AccessCmd::Focus(_) => AccessCmdName::Focus,
AccessCmd::FocusNavOrigin => AccessCmdName::FocusNavOrigin,
AccessCmd::SetExpanded(_) => AccessCmdName::SetExpanded,
AccessCmd::Increment(_) => AccessCmdName::Increment,
AccessCmd::SetToolTipVis(_) => AccessCmdName::SetToolTipVis,
AccessCmd::Scroll(_) => AccessCmdName::Scroll,
AccessCmd::ReplaceSelectedText(_) => AccessCmdName::ReplaceSelectedText,
AccessCmd::SelectText { .. } => AccessCmdName::SelectText,
AccessCmd::SetString(_) => AccessCmdName::SetString,
AccessCmd::SetNumber(_) => AccessCmdName::SetNumber,
}
}
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: AccessCmd) -> Option<AccessCmd>;
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AccessCmdName {
Click,
Focus,
FocusNavOrigin,
SetExpanded,
Increment,
SetToolTipVis,
Scroll,
ReplaceSelectedText,
SelectText,
SetString,
SetNumber,
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: AccessCmdName) -> Option<AccessCmdName>;
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ScrollCmd {
PageUp,
PageDown,
PageLeft,
PageRight,
ScrollTo,
ScrollToRect(PxRect),
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
fn from(some: ScrollCmd) -> Option<ScrollCmd>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccessNode {
pub id: AccessNodeId,
pub role: Option<AccessRole>,
pub commands: Vec<AccessCmdName>,
pub state: Vec<AccessState>,
pub transform: PxTransform,
pub size: PxSize,
pub children: Vec<AccessNodeId>,
pub children_len: u32,
pub descendants_len: u32,
}
impl AccessNode {
pub fn new(id: AccessNodeId, role: Option<AccessRole>) -> Self {
Self {
id,
role,
commands: vec![],
state: vec![],
transform: PxTransform::identity(),
size: PxSize::zero(),
children: vec![],
children_len: 0,
descendants_len: 0,
}
}
pub fn children_count(&self) -> usize {
(self.children_len as usize).max(self.children.len())
}
}
#[derive(Default)]
pub struct AccessTreeBuilder {
nodes: Vec<AccessNode>,
#[cfg(debug_assertions)]
ids: rustc_hash::FxHashSet<AccessNodeId>,
}
impl AccessTreeBuilder {
pub fn push(&mut self, node: AccessNode) -> usize {
#[cfg(debug_assertions)]
if !self.ids.insert(node.id) {
panic!("id `{:?}` already in tree", node.id)
}
let i = self.nodes.len();
self.nodes.push(node);
i
}
pub fn node(&mut self, i: usize) -> &mut AccessNode {
&mut self.nodes[i]
}
pub fn build(self) -> AccessTree {
assert!(!self.nodes.is_empty(), "missing root node");
AccessTree(self.nodes)
}
}
impl ops::Deref for AccessTreeBuilder {
type Target = [AccessNode];
fn deref(&self) -> &Self::Target {
&self.nodes
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccessTree(Vec<AccessNode>);
impl AccessTree {
pub fn root(&self) -> AccessNodeRef {
AccessNodeRef { tree: self, index: 0 }
}
}
impl ops::Deref for AccessTree {
type Target = [AccessNode];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<AccessTree> for Vec<AccessNode> {
fn from(value: AccessTree) -> Self {
value.0
}
}
impl IntoIterator for AccessTree {
type Item = AccessNode;
type IntoIter = std::vec::IntoIter<AccessNode>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
pub struct AccessNodeRef<'a> {
tree: &'a AccessTree,
index: usize,
}
impl<'a> AccessNodeRef<'a> {
pub fn self_and_descendants(&self) -> impl ExactSizeIterator<Item = AccessNodeRef> {
let range = self.index..(self.index + self.descendants_len as usize);
let tree = self.tree;
range.map(move |i| AccessNodeRef { tree, index: i })
}
pub fn descendants(&self) -> impl ExactSizeIterator<Item = AccessNodeRef> {
let mut d = self.self_and_descendants();
d.next();
d
}
pub fn children(&self) -> impl ExactSizeIterator<Item = AccessNodeRef> {
struct ChildrenIter<'a> {
tree: &'a AccessTree,
count: usize,
index: usize,
}
impl<'a> Iterator for ChildrenIter<'a> {
type Item = AccessNodeRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.count > 0 {
let item = AccessNodeRef {
tree: self.tree,
index: self.index,
};
self.count -= 1;
self.index += 1 + item.descendants_len as usize;
Some(item)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.count, Some(self.count))
}
}
impl<'a> ExactSizeIterator for ChildrenIter<'a> {}
ChildrenIter {
tree: self.tree,
count: self.children_len as usize,
index: self.index + 1,
}
}
}
impl<'a> ops::Deref for AccessNodeRef<'a> {
type Target = AccessNode;
fn deref(&self) -> &Self::Target {
&self.tree[self.index]
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccessTreeUpdate {
pub updates: Vec<AccessTree>,
pub full_root: Option<AccessNodeId>,
pub focused: AccessNodeId,
}