use crate::event::EventContext;
use crate::layout::style::FlexStyle;
use crate::layout::types::FlexAlign;
use crate::view::node::{Listener, ViewNode};
use crate::view::paint::{ImageFit, ImageStyle};
use crate::widget::layout::LayoutAttr;
use crate::widget::{BuildContext, Widget};
use std::rc::Rc;
#[derive(Clone)]
pub struct Image {
data: std::sync::Arc<Vec<u8>>,
style: ImageStyle,
layout: LayoutAttr,
expand: bool,
listeners: Vec<Listener>,
}
impl Image {
pub fn from_rgba(data: Vec<u8>, w: u32, h: u32) -> Self {
Self {
data: std::sync::Arc::new(data),
style: ImageStyle {
width: w,
height: h,
..ImageStyle::default()
},
layout: LayoutAttr::new(),
expand: false,
listeners: Vec::new(),
}
}
pub fn from_arc(data: std::sync::Arc<Vec<u8>>, w: u32, h: u32) -> Self {
Self {
data,
style: ImageStyle {
width: w,
height: h,
..ImageStyle::default()
},
layout: LayoutAttr::new(),
expand: false,
listeners: Vec::new(),
}
}
pub fn width(mut self, w: f32) -> Self {
self.layout = self.layout.width(w);
self
}
pub fn height(mut self, h: f32) -> Self {
self.layout = self.layout.height(h);
self
}
pub fn layout(mut self, l: LayoutAttr) -> Self {
self.layout = l;
self
}
pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> Option<Self> {
let img = image::open(path).ok()?;
Self::from_dynamic(img)
}
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
let img = image::load_from_memory(bytes).ok()?;
Self::from_dynamic(img)
}
fn from_dynamic(img: image::DynamicImage) -> Option<Self> {
let rgba = img.to_rgba8();
let (w, h) = rgba.dimensions();
if w == 0 || h == 0 {
return None;
}
Some(Self::from_rgba(rgba.into_raw(), w, h))
}
pub fn opacity(mut self, o: f32) -> Self {
self.style.opacity = o.clamp(0.0, 1.0);
self
}
pub fn fit(mut self, f: ImageFit) -> Self {
self.style.fit = f;
self
}
pub fn expand(mut self, v: bool) -> Self {
self.expand = v;
self
}
pub fn radius(mut self, r: f32) -> Self {
self.style.border_radius = r;
self
}
pub fn on_click<F: Fn() + 'static>(mut self, f: F) -> Self {
self.listeners.push(Listener::on_click(Rc::new(f)));
self
}
pub fn on_click_with_ctx<F: Fn(&mut EventContext) + 'static>(mut self, f: F) -> Self {
self.listeners.push(Listener::on_click_with_ctx(Rc::new(f)));
self
}
}
impl Widget for Image {
fn build(&self, _ctx: &mut BuildContext) -> ViewNode {
let mut layout = self.layout.apply(FlexStyle::default());
if self.expand {
layout = layout
.flex_grow(1.0)
.flex_basis(0.0)
.align_self(FlexAlign::Stretch)
.min_width(0.0)
.min_height(0.0);
}
ViewNode::Image {
data: std::sync::Arc::clone(&self.data),
style: self.style,
layout,
key: None,
listeners: self.listeners.clone(),
}
}
}