use denise::{Modifiers, PixelFormat, PointerButton, Rect, Role, Theme};
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct DeniseRect {
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32,
}
impl From<Rect> for DeniseRect {
fn from(r: Rect) -> Self {
Self {
x: r.x,
y: r.y,
width: r.width,
height: r.height,
}
}
}
impl From<DeniseRect> for Rect {
fn from(r: DeniseRect) -> Self {
Rect::new(r.x, r.y, r.width, r.height)
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct DeniseFrame {
pub pixels: *mut u32,
pub len: usize,
pub width: u32,
pub height: u32,
pub stride: u32,
pub format: u32,
pub buffer_age: i32,
}
pub const DENISE_FORMAT_ARGB8888: u32 = 0;
pub const DENISE_FORMAT_XRGB8888: u32 = 1;
pub fn pixel_format(value: u32) -> Option<PixelFormat> {
match value {
DENISE_FORMAT_ARGB8888 => Some(PixelFormat::Argb8888),
DENISE_FORMAT_XRGB8888 => Some(PixelFormat::Xrgb8888),
_ => None,
}
}
pub const DENISE_THEME_LIGHT: u32 = 0;
pub const DENISE_THEME_DARK: u32 = 1;
pub const DENISE_THEME_HIGH_CONTRAST: u32 = 2;
pub fn theme(value: u32) -> Option<Theme> {
Theme::BUILT_IN.get(value as usize).copied()
}
pub const DENISE_ROLE_NONE: i32 = -1;
macro_rules! role_table {
($( $c_name:ident = $value:literal => $variant:ident ),* $(,)?) => {
$(
#[doc = concat!("[`Role::", stringify!($variant), "`] as an ABI number.")]
pub const $c_name: i32 = $value;
)*
pub fn role(value: i32) -> Option<Role> {
Some(match value {
$( $value => Role::$variant, )*
_ => return None,
})
}
pub const ROLE_TABLE: &[(&str, i32)] = &[ $( (stringify!($c_name), $value) ),* ];
};
}
role_table! {
DENISE_ROLE_BASE_100 = 0 => Base100,
DENISE_ROLE_BASE_200 = 1 => Base200,
DENISE_ROLE_BASE_300 = 2 => Base300,
DENISE_ROLE_BASE_CONTENT = 3 => BaseContent,
DENISE_ROLE_PRIMARY = 4 => Primary,
DENISE_ROLE_PRIMARY_CONTENT = 5 => PrimaryContent,
DENISE_ROLE_SECONDARY = 6 => Secondary,
DENISE_ROLE_SECONDARY_CONTENT = 7 => SecondaryContent,
DENISE_ROLE_ACCENT = 8 => Accent,
DENISE_ROLE_ACCENT_CONTENT = 9 => AccentContent,
DENISE_ROLE_NEUTRAL = 10 => Neutral,
DENISE_ROLE_NEUTRAL_CONTENT = 11 => NeutralContent,
DENISE_ROLE_INFO = 12 => Info,
DENISE_ROLE_INFO_CONTENT = 13 => InfoContent,
DENISE_ROLE_SUCCESS = 14 => Success,
DENISE_ROLE_SUCCESS_CONTENT = 15 => SuccessContent,
DENISE_ROLE_WARNING = 16 => Warning,
DENISE_ROLE_WARNING_CONTENT = 17 => WarningContent,
DENISE_ROLE_ERROR = 18 => Error,
DENISE_ROLE_ERROR_CONTENT = 19 => ErrorContent,
}
pub const DENISE_BUTTON_LEFT: u32 = 0;
pub const DENISE_BUTTON_RIGHT: u32 = 1;
pub const DENISE_BUTTON_MIDDLE: u32 = 2;
pub const DENISE_BUTTON_OTHER: u32 = 0x100;
pub fn button(value: u32) -> Option<PointerButton> {
Some(match value {
DENISE_BUTTON_LEFT => PointerButton::Left,
DENISE_BUTTON_RIGHT => PointerButton::Right,
DENISE_BUTTON_MIDDLE => PointerButton::Middle,
v if v & DENISE_BUTTON_OTHER != 0 => PointerButton::Other((v & 0xFF) as u16),
_ => return None,
})
}
pub const DENISE_MOD_SHIFT: u32 = 1 << 0;
pub const DENISE_MOD_CTRL: u32 = 1 << 1;
pub const DENISE_MOD_ALT: u32 = 1 << 2;
pub const DENISE_MOD_SUPER: u32 = 1 << 3;
pub fn modifiers(value: u32) -> Modifiers {
let mut out = Modifiers::NONE;
for (bit, modifier) in [
(DENISE_MOD_SHIFT, Modifiers::SHIFT),
(DENISE_MOD_CTRL, Modifiers::CTRL),
(DENISE_MOD_ALT, Modifiers::ALT),
(DENISE_MOD_SUPER, Modifiers::SUPER),
] {
if value & bit != 0 {
out |= modifier;
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_role_number_is_a_distinct_role() {
let mut seen = Vec::new();
for value in 0..Role::COUNT as i32 {
let role = role(value).unwrap_or_else(|| panic!("role {value} unmapped"));
assert!(!seen.contains(&role), "{role:?} appears twice");
seen.push(role);
}
assert_eq!(seen.len(), Role::COUNT);
assert_eq!(role(Role::COUNT as i32), None);
assert_eq!(role(-1), None);
}
#[test]
fn every_theme_number_is_a_distinct_theme() {
for (value, expected) in Theme::BUILT_IN.iter().enumerate() {
assert_eq!(theme(value as u32).as_ref(), Some(expected));
}
assert_eq!(theme(Theme::BUILT_IN.len() as u32), None);
}
#[test]
fn buttons_round_trip_including_the_unnamed_ones() {
assert_eq!(button(DENISE_BUTTON_LEFT), Some(PointerButton::Left));
assert_eq!(button(DENISE_BUTTON_RIGHT), Some(PointerButton::Right));
assert_eq!(button(DENISE_BUTTON_MIDDLE), Some(PointerButton::Middle));
assert_eq!(
button(DENISE_BUTTON_OTHER | 7),
Some(PointerButton::Other(7))
);
assert_eq!(button(3), None);
}
#[test]
fn modifier_bits_match_the_core() {
let all = modifiers(DENISE_MOD_SHIFT | DENISE_MOD_CTRL | DENISE_MOD_ALT | DENISE_MOD_SUPER);
assert!(all.contains(Modifiers::SHIFT | Modifiers::CTRL));
assert!(all.contains(Modifiers::ALT | Modifiers::SUPER));
assert!(modifiers(0).is_empty());
assert!(modifiers(1 << 20).is_empty());
}
#[test]
fn rectangles_survive_the_crossing() {
let rect = Rect::new(-3, 7, 40, 900);
assert_eq!(Rect::from(DeniseRect::from(rect)), rect);
}
}