use densa_core::Rect;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum Role {
#[default]
Group,
Window,
Label,
Button,
TextInput,
ScrollView,
Splitter,
TabList,
Tab,
TabPanel,
Table,
Row,
ColumnHeader,
Cell,
Image,
MenuBar,
Menu,
MenuItem,
MenuItemCheckBox,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum AccessAction {
Click,
Focus,
SetValue,
ScrollUp,
ScrollDown,
ScrollLeft,
ScrollRight,
ScrollIntoView,
}
impl AccessAction {
const ALL: [Self; 8] = [
Self::Click,
Self::Focus,
Self::SetValue,
Self::ScrollUp,
Self::ScrollDown,
Self::ScrollLeft,
Self::ScrollRight,
Self::ScrollIntoView,
];
fn bit(self) -> u16 {
1 << (self as u16)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct AccessRequest<'a> {
pub action: AccessAction,
pub part: Option<u32>,
pub value: Option<&'a str>,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct AccessNode {
role: Role,
label: Option<String>,
value: Option<String>,
bounds: Rect,
actions: u16,
selected: Option<bool>,
checked: Option<bool>,
expanded: Option<bool>,
disabled: bool,
clips: bool,
placeholder: Option<String>,
focused_part: Option<u32>,
parts: Vec<(u32, AccessNode)>,
children: Vec<AccessId>,
}
impl AccessNode {
pub fn new(role: Role) -> Self {
Self {
role,
..Self::default()
}
}
pub fn set_role(&mut self, role: Role) {
self.role = role;
}
pub fn set_label(&mut self, label: impl Into<String>) {
self.label = Some(label.into());
}
pub fn set_value(&mut self, value: impl Into<String>) {
self.value = Some(value.into());
}
pub fn set_bounds(&mut self, bounds: Rect) {
self.bounds = bounds;
}
pub fn add_action(&mut self, action: AccessAction) {
self.actions |= action.bit();
}
pub fn set_selected(&mut self, selected: bool) {
self.selected = Some(selected);
}
pub fn set_checked(&mut self, checked: bool) {
self.checked = Some(checked);
}
pub fn set_expanded(&mut self, expanded: bool) {
self.expanded = Some(expanded);
}
pub fn checked(&self) -> Option<bool> {
self.checked
}
pub fn expanded(&self) -> Option<bool> {
self.expanded
}
pub fn set_disabled(&mut self, disabled: bool) {
self.disabled = disabled;
}
pub fn set_focused_part(&mut self, part: u32) {
self.focused_part = Some(part);
}
pub fn focused_part(&self) -> Option<u32> {
self.focused_part
}
pub fn push_part(&mut self, part: u32, node: AccessNode) {
self.parts.push((part, node));
}
pub fn role(&self) -> Role {
self.role
}
pub fn label(&self) -> Option<&str> {
self.label.as_deref()
}
pub fn value(&self) -> Option<&str> {
self.value.as_deref()
}
pub fn bounds(&self) -> Rect {
self.bounds
}
pub fn has_action(&self, action: AccessAction) -> bool {
self.actions & action.bit() != 0
}
pub fn actions(&self) -> impl Iterator<Item = AccessAction> + '_ {
AccessAction::ALL
.into_iter()
.filter(|a| self.has_action(*a))
}
pub fn selected(&self) -> Option<bool> {
self.selected
}
pub fn is_disabled(&self) -> bool {
self.disabled
}
pub fn clips_children(&self) -> bool {
self.clips
}
pub fn set_clips_children(&mut self, clips: bool) {
self.clips = clips;
}
pub fn set_placeholder(&mut self, placeholder: impl Into<String>) {
self.placeholder = Some(placeholder.into());
}
pub fn placeholder(&self) -> Option<&str> {
self.placeholder.as_deref()
}
pub fn children(&self) -> &[AccessId] {
&self.children
}
pub(crate) fn take_parts(&mut self) -> Vec<(u32, AccessNode)> {
std::mem::take(&mut self.parts)
}
pub(crate) fn push_child(&mut self, child: AccessId) {
self.children.push(child);
}
}
pub const MAX_PART: u32 = (1 << PART_BITS) - 2;
const PART_BITS: u32 = 24;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AccessId(u64);
impl AccessId {
pub(crate) fn widget(serial: u64) -> Self {
Self(serial << PART_BITS)
}
#[must_use]
pub fn part(self, part: u32) -> Self {
if part > MAX_PART {
return self;
}
Self(self.0 & !Self::PART_MASK | u64::from(part + 1))
}
const PART_MASK: u64 = (1 << PART_BITS) - 1;
pub fn to_raw(self) -> u64 {
self.0
}
pub fn from_raw(raw: u64) -> Self {
Self(raw)
}
pub(crate) fn split(self) -> (u64, Option<u32>) {
let part = (self.0 & Self::PART_MASK) as u32;
(self.0 >> PART_BITS, part.checked_sub(1))
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct AccessTree {
pub(crate) nodes: Vec<(AccessId, AccessNode)>,
pub(crate) root: AccessId,
pub(crate) focus: AccessId,
}
impl AccessTree {
pub fn nodes(&self) -> &[(AccessId, AccessNode)] {
&self.nodes
}
pub fn root(&self) -> AccessId {
self.root
}
pub fn focus(&self) -> AccessId {
self.focus
}
pub fn node(&self, id: AccessId) -> Option<&AccessNode> {
self.nodes.iter().find(|(i, _)| *i == id).map(|(_, n)| n)
}
}