use std::{
any::Any,
fmt::{Debug, Display},
num::NonZero,
sync::atomic::{AtomicU64, Ordering},
};
use crate::{
event::Ime,
layout::{Affine, Point, Rect, Size, Vector},
window::Cursor,
};
bitflags::bitflags! {
#[must_use]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Update: u8 {
const LAYOUT = 1 << 1;
const DRAW = 1 << 2;
const ANIMATE = 1 << 3;
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct ViewFlags: u8 {
const HOVERED = 1 << 0;
const FOCUSED = 1 << 1;
const ACTIVE = 1 << 2;
const HAS_HOVERED = 1 << 3;
const HAS_FOCUSED = 1 << 4;
const HAS_ACTIVE = 1 << 5;
const FOCUSABLE = 1 << 6;
const IS = Self::HOVERED.bits() | Self::FOCUSED.bits() | Self::ACTIVE.bits();
const HAS = Self::HAS_HOVERED.bits() | Self::HAS_FOCUSED.bits() | Self::HAS_ACTIVE.bits();
}
}
impl ViewFlags {
fn has(self) -> Self {
(self & Self::HAS) | Self::from_bits_retain((self & Self::IS).bits() << 3)
}
}
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ViewId {
id: NonZero<u64>,
}
impl Default for ViewId {
fn default() -> Self {
Self::new()
}
}
impl ViewId {
pub fn new() -> Self {
static NEXT_ID: AtomicU64 = AtomicU64::new(1);
loop {
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
if let Some(id) = NonZero::new(id) {
break Self { id };
};
}
}
pub fn as_u64(&self) -> u64 {
self.id.get()
}
}
impl Debug for ViewId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ViewId(0x{:x})", self.id)
}
}
impl Display for ViewId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "0x{:x}", self.id)
}
}
#[derive(Debug)]
pub struct ViewState {
pub(crate) id: ViewId,
pub(crate) prev_flags: ViewFlags,
pub(crate) flags: ViewFlags,
pub(crate) update: Update,
pub(crate) properties: Properties,
pub(crate) size: Size,
pub(crate) transform: Affine,
pub(crate) cursor: Option<Cursor>,
pub(crate) inherited_cursor: Option<Cursor>,
pub(crate) ime: Option<Ime>,
pub(crate) inherited_ime: Option<Ime>,
}
impl Default for ViewState {
fn default() -> Self {
Self::new(ViewId::new())
}
}
impl ViewState {
pub fn new(id: ViewId) -> Self {
Self {
id,
prev_flags: ViewFlags::default(),
flags: ViewFlags::default(),
update: Update::LAYOUT | Update::DRAW,
properties: Properties::new(),
size: Size::ZERO,
transform: Affine::IDENTITY,
cursor: None,
inherited_cursor: None,
ime: None,
inherited_ime: None,
}
}
pub fn prepare(&mut self) {
self.flags.remove(ViewFlags::HAS);
self.flags |= self.flags.has();
self.inherited_cursor = self.cursor;
self.inherited_ime = self.ime.clone();
}
pub fn propagate(&mut self, child: &mut Self) {
self.update |= child.update;
self.flags |= child.flags.has();
self.inherited_cursor = self.cursor().or(child.cursor());
self.inherited_ime = self.ime().or(child.ime()).cloned();
}
pub fn id(&self) -> ViewId {
self.id
}
pub fn is_hovered(&self) -> bool {
self.flags.contains(ViewFlags::HOVERED)
}
pub fn set_hovered(&mut self, hovered: bool) {
self.flags.set(ViewFlags::HOVERED, hovered);
}
pub fn is_focused(&self) -> bool {
self.flags.contains(ViewFlags::FOCUSED)
}
pub fn set_focused(&mut self, focused: bool) {
self.flags.set(ViewFlags::FOCUSED, focused);
}
pub fn is_active(&self) -> bool {
self.flags.contains(ViewFlags::ACTIVE)
}
pub fn set_active(&mut self, active: bool) {
self.flags.set(ViewFlags::ACTIVE, active);
}
pub fn has_hovered(&self) -> bool {
let flags = self.flags & (ViewFlags::HOVERED | ViewFlags::HAS_HOVERED);
flags != ViewFlags::empty()
}
pub fn has_focused(&self) -> bool {
let flags = self.flags & (ViewFlags::FOCUSED | ViewFlags::HAS_FOCUSED);
flags != ViewFlags::empty()
}
pub fn has_active(&self) -> bool {
let flags = self.flags & (ViewFlags::ACTIVE | ViewFlags::HAS_ACTIVE);
flags != ViewFlags::empty()
}
pub fn is_focusable(&self) -> bool {
self.flags.contains(ViewFlags::FOCUSABLE)
}
pub fn set_focusable(&mut self, focusable: bool) {
self.flags.set(ViewFlags::FOCUSABLE, focusable);
}
pub fn contains_property<T: 'static>(&self) -> bool {
self.properties.contains::<T>()
}
pub fn insert_property<T: 'static>(&mut self, item: T) {
self.properties.insert(item);
}
pub fn remove_property<T: 'static>(&mut self) -> Option<T> {
self.properties.remove::<T>()
}
pub fn get_property<T: 'static>(&self) -> Option<&T> {
self.properties.get()
}
pub fn get_property_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.properties.get_mut()
}
pub fn property_or_insert_with<T: 'static, F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
self.properties.get_or_insert_with(f)
}
pub fn property_or<T: 'static>(&mut self, item: T) -> &mut T {
self.properties.get_or_insert(item)
}
pub fn property_or_default<T: 'static + Default>(&mut self) -> &mut T {
self.properties.get_or_default()
}
pub fn set_size(&mut self, size: Size) {
self.size = size;
}
pub fn size(&self) -> Size {
self.size
}
pub fn rect(&self) -> Rect {
Rect::min_size(Point::ZERO, self.size)
}
pub fn transform(&self) -> Affine {
self.transform
}
pub fn set_transform(&mut self, transform: Affine) {
self.transform = transform;
}
pub fn translate(&mut self, translation: Vector) {
self.transform = Affine::translate(translation);
}
pub fn request_layout(&mut self) {
self.update |= Update::LAYOUT | Update::DRAW;
}
pub fn request_draw(&mut self) {
self.update |= Update::DRAW;
}
pub fn request_animate(&mut self) {
self.update |= Update::ANIMATE;
}
pub fn needs_layout(&self) -> bool {
self.update.contains(Update::LAYOUT)
}
pub fn needs_draw(&self) -> bool {
self.update.contains(Update::DRAW)
}
pub fn needs_animate(&self) -> bool {
self.update.contains(Update::ANIMATE)
}
pub fn mark_layed_out(&mut self) {
self.update.remove(Update::LAYOUT);
}
pub fn mark_drawn(&mut self) {
self.update.remove(Update::DRAW);
}
pub fn mark_animated(&mut self) {
self.update.remove(Update::ANIMATE);
}
pub fn flags(&self) -> ViewFlags {
self.flags
}
pub fn update(&self) -> Update {
self.update
}
pub fn cursor(&self) -> Option<Cursor> {
self.cursor.or(self.inherited_cursor)
}
pub fn set_cursor(&mut self, cursor: Option<Cursor>) {
self.cursor = cursor;
}
pub fn ime(&self) -> Option<&Ime> {
self.ime.as_ref().or(self.inherited_ime.as_ref())
}
pub fn set_ime(&mut self, ime: Option<Ime>) {
self.ime = ime;
}
}
pub(crate) struct Properties {
items: Vec<Box<dyn Any>>,
}
impl Properties {
fn new() -> Self {
Self { items: Vec::new() }
}
fn insert<T: 'static>(&mut self, item: T) {
if let Some(index) = self.get_index::<T>() {
self.items[index] = Box::new(item);
} else {
self.items.push(Box::new(item));
}
}
fn remove<T: 'static>(&mut self) -> Option<T> {
if let Some(index) = self.get_index::<T>() {
Some(*self.items.remove(index).downcast().unwrap())
} else {
None
}
}
fn contains<T: 'static>(&self) -> bool {
self.items.iter().any(|item| item.is::<T>())
}
fn get<T: 'static>(&self) -> Option<&T> {
self.items.iter().find_map(|item| item.downcast_ref())
}
fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.items.iter_mut().find_map(|item| item.downcast_mut())
}
fn get_index<T: 'static>(&self) -> Option<usize> {
self.items.iter().position(|item| item.is::<T>())
}
fn get_or_insert_with<T: 'static, F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
if let Some(index) = self.get_index::<T>() {
self.items[index].downcast_mut().unwrap()
} else {
let item = f();
self.insert(item);
self.items.last_mut().unwrap().downcast_mut().unwrap()
}
}
fn get_or_insert<T: 'static>(&mut self, item: T) -> &mut T {
self.get_or_insert_with(|| item)
}
fn get_or_default<T: 'static + Default>(&mut self) -> &mut T {
self.get_or_insert_with(Default::default)
}
}
impl Debug for Properties {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Properties").finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_propagate() {
assert_eq!(ViewFlags::HOVERED.has(), ViewFlags::HAS_HOVERED);
assert_eq!(ViewFlags::FOCUSED.has(), ViewFlags::HAS_FOCUSED);
assert_eq!(ViewFlags::ACTIVE.has(), ViewFlags::HAS_ACTIVE);
}
}