131 lines
3.7 KiB
Rust
131 lines
3.7 KiB
Rust
use iced::{Element, Length, advanced::Widget};
|
|
use std::sync::Arc;
|
|
|
|
use crate::shared_string::SharedString;
|
|
|
|
#[derive(Clone)]
|
|
pub struct BlurHash {
|
|
hash: SharedString,
|
|
handle: Arc<iced::advanced::image::Handle>,
|
|
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<str>) -> 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<Length>) -> Self {
|
|
self.width = width.into();
|
|
self
|
|
}
|
|
|
|
pub fn height(mut self, height: impl Into<Length>) -> Self {
|
|
self.height = height.into();
|
|
self
|
|
}
|
|
|
|
pub fn punch(mut self, punch: f32) -> Self {
|
|
self.punch = punch;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for BlurHash
|
|
where
|
|
Renderer: iced::advanced::image::Renderer<Handle = iced::advanced::image::Handle>,
|
|
{
|
|
fn size(&self) -> iced::Size<iced::Length> {
|
|
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<BlurHash> for iced::Element<'a, Message, Theme, Renderer>
|
|
where
|
|
Renderer: iced::advanced::image::Renderer<Handle = iced::advanced::image::Handle>,
|
|
{
|
|
fn from(blur_hash: BlurHash) -> Element<'a, Message, Theme, Renderer> {
|
|
iced::Element::new(blur_hash)
|
|
}
|
|
}
|