1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
//! Renderable image buffers. use widget_prelude::*; use base::Downcast; use std::mem; /// An image buffer allocated by IUP. /// /// ##Note: Not a Renderable Widget /// While this type can be dereferenced and converted to `BaseWidget`, it is *not* a renderable /// widget and adding it to a container will have no visual effect. /// /// Instead, it should be set on another widget type that implements the `ImageContainer` trait, /// which will handle the actual rendering. /// /// ##Note: Memory Usage /// This struct should be freed by calling `.destroy()` on it when it is no longer in use. /// Otherwise, it will be freed when `kiss_ui::show_gui()` exits^([citation needed]). /// /// ##Note: Cloning /// Cloning this image does not duplicate its allocation. Thus, destroying one image cloned from /// another will destroy them both. pub struct Image(IUPPtr); impl Image { /// Create a new RGB image buffer from a slice of 3-byte tuples, copying the data into a new /// allocation. /// /// See `transmute_buffer_rgb()` in this module. /// /// ##Panics /// If `width * height` is not equal to `pixels.len()`. pub fn new_rgb(width: u32, height: u32, pixels: &[(u8, u8, u8)]) -> Image { assert_eq!((width * height) as usize, pixels.len()); unsafe { let ptr = ::iup_sys::IupImageRGB(width as i32, height as i32, pixels.as_ptr() as *const u8); Self::from_ptr(ptr) } } /// Create a new RGBA image buffer from a slice of 4-byte tuples, copying the data into a new /// allocation. /// /// See `transmute_buffer_rgba` in this module. /// /// ##Panics /// If `width * height` is not equal to `pixels.len()`. pub fn new_rgba(width: u32, height: u32, pixels: &[(u8, u8, u8, u8)]) -> Image { assert_eq!((width * height) as usize, pixels.len()); unsafe { let ptr = ::iup_sys::IupImageRGBA(width as i32, height as i32, pixels.as_ptr() as *const u8); Self::from_ptr(ptr) } } } impl Destroy for Image {} impl_widget! { Image, ["image", "imagergb", "imagergba"] } /// Cast a slice of bytes to a slice of 3-byte tuples without copying. /// /// Returns `None` if `buf.len()` is not evenly divisible by 3. pub fn transmute_buffer_rgb(buf: &[u8]) -> Option<&[(u8, u8, u8)]> { if buf.len() % 3 == 0 { Some(unsafe { mem::transmute(buf) }) } else { None } } /// Cast a slice of bytes to a slice of 4-byte tuples without copying. /// /// Returns `None` if `buf.len()` is not evenly divisible by 4. pub fn transmute_buffer_rgba(buf: &[u8]) -> Option<&[(u8, u8, u8, u8)]> { if buf.len() % 4 == 0 { Some(unsafe { mem::transmute(buf) }) } else { None } } /// A trait describing an object that can render an image within itself. pub trait ImageContainer: Widget { /// Set the image this widget is to render and return `self` for method chaining. fn set_image(self, image: Image) -> Self { self.set_attr_handle(::attrs::IMAGE, image); self } /// Get a copy of the image set on this widget, if any. fn get_image(&self) -> Option<Image> { use base::BaseWidget; self.get_attr_handle(::attrs::IMAGE) .map(BaseWidget::try_downcast::<Image>) .and_then(Result::ok) } }