use iced::{Element, Length, advanced::Widget}; use std::sync::Arc; use crate::shared_string::SharedString; #[derive(Clone)] pub struct BlurHash { hash: SharedString, handle: Arc, width: iced::Length, height: iced::Length, punch: f32, } impl core::fmt::Debug for BlurHash { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("BlurHash") .field("hash", &self.hash) .field("width", &self.width) .field("height", &self.height) .field("punch", &self.punch) .finish() } } impl BlurHash { pub fn recompute(&mut self, width: u32, height: u32, punch: f32) { let pixels = blurhash::decode(&self.hash, width, height, punch) .unwrap_or_else(|_| vec![0; (width * height * 4) as usize]); let handle = iced::advanced::image::Handle::from_rgba(width, height, pixels); self.handle = Arc::new(handle); } pub fn new(hash: impl AsRef) -> Self { let hash = SharedString::from(hash.as_ref().to_string()); let pixels = blurhash::decode(&hash, 32, 32, 1.0).unwrap_or_else(|_| vec![0; 32 * 32 * 4]); let handle = iced::advanced::image::Handle::from_rgba(32, 32, pixels); let handle = Arc::new(handle); BlurHash { hash, handle, width: 32.into(), height: 32.into(), punch: 1.0, } } pub fn width(mut self, width: impl Into) -> Self { self.width = width.into(); self } pub fn height(mut self, height: impl Into) -> Self { self.height = height.into(); self } pub fn punch(mut self, punch: f32) -> Self { self.punch = punch; self } } impl Widget for BlurHash where Renderer: iced::advanced::image::Renderer, { fn size(&self) -> iced::Size { iced::Size { width: self.width, height: self.height, } } fn layout( &mut self, _tree: &mut iced::advanced::widget::Tree, renderer: &Renderer, limits: &iced::advanced::layout::Limits, ) -> iced::advanced::layout::Node { let layout = iced::widget::image::layout( renderer, limits, &self.handle, self.width, self.height, None, iced::ContentFit::default(), iced::Rotation::default(), false, ); let height = layout.bounds().height; let width = layout.bounds().width; self.recompute(width as u32, height as u32, self.punch); layout } fn draw( &self, _state: &iced::advanced::widget::Tree, renderer: &mut Renderer, _theme: &Theme, _style: &iced::advanced::renderer::Style, layout: iced::advanced::Layout<'_>, _cursor: iced::advanced::mouse::Cursor, _viewport: &iced::Rectangle, ) { iced::widget::image::draw( renderer, layout, &self.handle, None, iced::border::Radius::default(), iced::ContentFit::default(), iced::widget::image::FilterMethod::default(), iced::Rotation::default(), 1.0, 1.0, ); } } impl<'a, Message, Theme, Renderer> From for iced::Element<'a, Message, Theme, Renderer> where Renderer: iced::advanced::image::Renderer, { fn from(blur_hash: BlurHash) -> Element<'a, Message, Theme, Renderer> { iced::Element::new(blur_hash) } }