2020-03-08 06:42:21 +11:00
use crate ::platform_impl ::PlatformIcon ;
use std ::{ error ::Error , fmt , io , mem } ;
2018-05-08 07:36:21 +10:00
#[ repr(C) ]
#[ derive(Debug) ]
pub ( crate ) struct Pixel {
pub ( crate ) r : u8 ,
pub ( crate ) g : u8 ,
pub ( crate ) b : u8 ,
pub ( crate ) a : u8 ,
}
pub ( crate ) const PIXEL_SIZE : usize = mem ::size_of ::< Pixel > ( ) ;
2020-03-08 06:42:21 +11:00
#[ derive(Debug) ]
2018-05-08 07:36:21 +10:00
/// An error produced when using `Icon::from_rgba` with invalid arguments.
pub enum BadIcon {
/// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
/// safely interpreted as 32bpp RGBA pixels.
2019-06-22 01:33:15 +10:00
ByteCountNotDivisibleBy4 { byte_count : usize } ,
2018-05-08 07:36:21 +10:00
/// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
/// At least one of your arguments is incorrect.
DimensionsVsPixelCount {
width : u32 ,
height : u32 ,
width_x_height : usize ,
pixel_count : usize ,
} ,
2020-03-08 06:42:21 +11:00
/// Produced when underlying OS functionality failed to create the icon
OsError ( io ::Error ) ,
2018-05-08 07:36:21 +10:00
}
impl fmt ::Display for BadIcon {
2019-07-10 07:49:07 +10:00
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
2020-01-10 16:29:31 +11:00
match self {
BadIcon ::ByteCountNotDivisibleBy4 { byte_count } = > write! ( f ,
2018-05-08 07:36:21 +10:00
" The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels. " ,
byte_count ,
) ,
2020-01-10 16:29:31 +11:00
BadIcon ::DimensionsVsPixelCount {
2018-05-08 07:36:21 +10:00
width ,
height ,
width_x_height ,
pixel_count ,
2020-01-10 16:29:31 +11:00
} = > write! ( f ,
2018-05-08 07:36:21 +10:00
" The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}. " ,
width , height , pixel_count , width_x_height ,
) ,
2020-03-08 06:42:21 +11:00
BadIcon ::OsError ( e ) = > write! ( f , " OS error when instantiating the icon: {:?} " , e ) ,
2020-01-10 16:29:31 +11:00
}
2018-05-08 07:36:21 +10:00
}
}
impl Error for BadIcon {
2020-01-10 16:29:31 +11:00
fn source ( & self ) -> Option < & ( dyn Error + 'static ) > {
2018-05-08 07:36:21 +10:00
Some ( self )
}
}
#[ derive(Debug, Clone, PartialEq, Eq) ]
2020-03-08 06:42:21 +11:00
pub ( crate ) struct RgbaIcon {
2018-05-08 07:36:21 +10:00
pub ( crate ) rgba : Vec < u8 > ,
pub ( crate ) width : u32 ,
pub ( crate ) height : u32 ,
}
2020-03-08 06:42:21 +11:00
/// For platforms which don't have window icons (e.g. web)
#[ derive(Debug, Clone, PartialEq, Eq) ]
pub ( crate ) struct NoIcon ;
#[ allow(dead_code) ] // These are not used on every platform
mod constructors {
use super ::* ;
impl RgbaIcon {
/// Creates an `Icon` from 32bpp RGBA data.
///
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
pub fn from_rgba ( rgba : Vec < u8 > , width : u32 , height : u32 ) -> Result < Self , BadIcon > {
if rgba . len ( ) % PIXEL_SIZE ! = 0 {
return Err ( BadIcon ::ByteCountNotDivisibleBy4 {
byte_count : rgba . len ( ) ,
} ) ;
}
let pixel_count = rgba . len ( ) / PIXEL_SIZE ;
if pixel_count ! = ( width * height ) as usize {
Err ( BadIcon ::DimensionsVsPixelCount {
width ,
height ,
width_x_height : ( width * height ) as usize ,
pixel_count ,
} )
} else {
Ok ( RgbaIcon {
rgba ,
width ,
height ,
} )
}
}
}
impl NoIcon {
pub fn from_rgba ( rgba : Vec < u8 > , width : u32 , height : u32 ) -> Result < Self , BadIcon > {
// Create the rgba icon anyway to validate the input
let _ = RgbaIcon ::from_rgba ( rgba , width , height ) ? ;
Ok ( NoIcon )
}
}
}
/// An icon used for the window titlebar, taskbar, etc.
#[ derive(Clone) ]
pub struct Icon {
pub ( crate ) inner : PlatformIcon ,
}
impl fmt ::Debug for Icon {
fn fmt ( & self , formatter : & mut fmt ::Formatter < '_ > ) -> Result < ( ) , fmt ::Error > {
fmt ::Debug ::fmt ( & self . inner , formatter )
}
}
2018-05-08 07:36:21 +10:00
impl Icon {
/// Creates an `Icon` from 32bpp RGBA data.
///
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
pub fn from_rgba ( rgba : Vec < u8 > , width : u32 , height : u32 ) -> Result < Self , BadIcon > {
2020-03-08 06:42:21 +11:00
Ok ( Icon {
inner : PlatformIcon ::from_rgba ( rgba , width , height ) ? ,
} )
2018-05-08 07:36:21 +10:00
}
}