use std::convert::TryFrom;
use std::fmt;
use std::num::NonZeroU32;
use std::u32;
use crate::geom::{Rect, Size};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct WidgetId(NonZeroU32);
impl WidgetId {
pub(crate) const FIRST: WidgetId = WidgetId(unsafe { NonZeroU32::new_unchecked(1) });
const LAST: WidgetId = WidgetId(unsafe { NonZeroU32::new_unchecked(u32::MAX) });
pub(crate) fn next(self) -> Self {
WidgetId(NonZeroU32::new(self.0.get() + 1).unwrap())
}
}
impl TryFrom<u32> for WidgetId {
type Error = ();
fn try_from(x: u32) -> Result<WidgetId, ()> {
NonZeroU32::new(x).map(|n| WidgetId(n)).ok_or(())
}
}
impl TryFrom<u64> for WidgetId {
type Error = ();
fn try_from(x: u64) -> Result<WidgetId, ()> {
if x <= u32::MAX as u64 {
if let Some(nz) = NonZeroU32::new(x as u32) {
return Ok(WidgetId(nz));
}
}
Err(())
}
}
impl From<WidgetId> for u32 {
#[inline]
fn from(id: WidgetId) -> u32 {
id.0.get()
}
}
impl From<WidgetId> for u64 {
#[inline]
fn from(id: WidgetId) -> u64 {
id.0.get() as u64
}
}
impl Default for WidgetId {
fn default() -> Self {
WidgetId::LAST
}
}
impl fmt::Display for WidgetId {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "#{}", self.0)
}
}
#[test]
fn size_of_option_widget_id() {
use std::mem::size_of;
assert_eq!(size_of::<WidgetId>(), size_of::<Option<WidgetId>>());
}
#[derive(Clone, Default, Debug)]
pub struct CoreData {
pub rect: Rect,
pub id: WidgetId,
pub disabled: bool,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub enum Align {
Begin,
Centre,
End,
Stretch,
}
impl Default for Align {
fn default() -> Self {
Align::Stretch
}
}
#[derive(Clone, Debug, Default)]
pub struct AlignHints {
pub horiz: Option<Align>,
pub vert: Option<Align>,
}
impl AlignHints {
pub const NONE: AlignHints = AlignHints::new(None, None);
pub const fn new(horiz: Option<Align>, vert: Option<Align>) -> Self {
Self { horiz, vert }
}
pub fn complete(&self, horiz: Align, vert: Align, ideal: Size) -> CompleteAlignment {
CompleteAlignment {
halign: self.horiz.unwrap_or(horiz),
valign: self.vert.unwrap_or(vert),
ideal,
}
}
}
pub struct CompleteAlignment {
halign: Align,
valign: Align,
ideal: Size,
}
impl CompleteAlignment {
pub fn apply(&self, rect: Rect) -> Rect {
let ideal = self.ideal;
let mut pos = rect.pos;
let mut size = rect.size;
if self.halign != Align::Stretch && ideal.0 < size.0 {
pos.0 += match self.halign {
Align::Centre => (size.0 - ideal.0) / 2,
Align::End => size.0 - ideal.0,
Align::Begin | Align::Stretch => 0,
} as i32;
size.0 = ideal.0;
}
if self.valign != Align::Stretch && ideal.1 < size.1 {
pos.1 += match self.valign {
Align::Centre => (size.1 - ideal.1) / 2,
Align::End => size.1 - ideal.1,
Align::Begin | Align::Stretch => 0,
} as i32;
size.1 = ideal.1;
}
Rect { pos, size }
}
}
pub trait Directional: Copy + Sized + std::fmt::Debug + 'static {
type Flipped: Directional;
fn as_direction(self) -> Direction;
#[inline]
fn is_vertical(self) -> bool {
((self.as_direction() as u32) & 1) == 1
}
#[inline]
fn is_horizontal(self) -> bool {
((self.as_direction() as u32) & 1) == 0
}
#[inline]
fn is_reversed(self) -> bool {
((self.as_direction() as u32) & 2) == 2
}
}
macro_rules! fixed {
[] => {};
[($d:ident, $df:ident)] => {
#[derive(Copy, Clone, Default, Debug)]
pub struct $d;
impl Directional for $d {
type Flipped = $df;
#[inline]
fn as_direction(self) -> Direction {
Direction::$d
}
}
};
[($d:ident, $df:ident), $(($d1:ident, $d2:ident),)*] => {
fixed![($d, $df)];
fixed![($df, $d)];
fixed![$(($d1, $d2),)*];
};
}
fixed![(Right, Down), (Left, Up),];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum Direction {
Right = 0,
Down = 1,
Left = 2,
Up = 3,
}
impl Directional for Direction {
type Flipped = Self;
#[inline]
fn as_direction(self) -> Direction {
self
}
}