From 9b2a6ffde36c769442e6945597c042ab2c8d9446 Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Sat, 1 Jan 2022 22:08:00 -0500 Subject: [PATCH] Add images on the size --- Cargo.lock | 1 + Cargo.toml | 2 +- src/app.rs | 14 ++++++- src/lyrics.rs | 34 +++++++++++++---- src/main.rs | 1 + src/peripheries.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 src/peripheries.rs diff --git a/Cargo.lock b/Cargo.lock index 2531375..edd83b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1569,6 +1569,7 @@ dependencies = [ "guillotiere", "iced_graphics", "iced_native", + "image", "log", "raw-window-handle 0.3.4", "wgpu", diff --git a/Cargo.toml b/Cargo.toml index cbf8c8c..df197df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ version = "0.4.0" [dependencies.iced] # Display windows & graphics -features = ["canvas"] +features = ["canvas", "image"] version = "0.3.0" [dependencies.iced_futures] diff --git a/src/app.rs b/src/app.rs index b0bc0d4..032c9af 100644 --- a/src/app.rs +++ b/src/app.rs @@ -19,6 +19,7 @@ use iced_native::event::Event; pub struct DelyriumApp { lyrics_component: Option, file_selector: FileSelector, + size: (u32, u32), } #[derive(Clone, Debug)] @@ -32,6 +33,7 @@ pub enum Message { Tick, PromptForFile, FileOpened(PathBuf), + Resized(u32, u32), Null, } @@ -45,6 +47,7 @@ impl Application for DelyriumApp { DelyriumApp { lyrics_component: None, file_selector: FileSelector::default(), + size: (0, 0), }, Command::none(), ) @@ -86,7 +89,7 @@ impl Application for DelyriumApp { Message::FileOpened(path) => { println!("File opened! {}", path.display()); let song = load_song(&path).unwrap().format; - self.lyrics_component = Some(Lyrics::new(song)); + self.lyrics_component = Some(Lyrics::new(song, self.size)); }, Message::PromptForFile => { let task = async { @@ -103,6 +106,12 @@ impl Application for DelyriumApp { }; command = Some(task.into()); }, + Message::Resized(w, h) => { + self.size = (w, h); + if let Some(lyrics) = self.lyrics_component.as_mut() { + lyrics.notify_resized(w, h); + } + } Message::Null => { }, } @@ -134,6 +143,9 @@ impl Application for DelyriumApp { Event::Window(window::Event::FileDropped(path)) => { Some(Message::FileOpened(path)) }, + Event::Window(window::Event::Resized{width,height}) => { + Some(Message::Resized(width,height)) + }, _ => { None } } }); diff --git a/src/lyrics.rs b/src/lyrics.rs index 20bd8b2..7b63566 100644 --- a/src/lyrics.rs +++ b/src/lyrics.rs @@ -1,3 +1,4 @@ +use std::sync::Arc; use iced::Container; use iced::Row; use crate::palette::Palette; @@ -5,6 +6,7 @@ use crate::load_song::extract_cover; use iced::Element; use crate::styles::Theme; use crate::app::Message; +use crate::peripheries::Periphery; use iced::Align; use iced::Length; @@ -13,31 +15,42 @@ use iced::widget::scrollable::{self, Scrollable}; use symphonia::core::formats::FormatReader; +use image::GenericImageView; + pub struct Lyrics { lines: Vec, scroll_state: scrollable::State, theme: Theme, song: Box, + left_peri: Periphery, + rite_peri: Periphery, } impl Lyrics { - pub fn new(mut song: Box) -> Self { + pub fn new(mut song: Box, size: (u32, u32)) -> Self { let mut lyric = Lyric::new(); lyric.select(); let cover = extract_cover(song.as_mut()); - let theme = cover.map(|cover| { - Theme::from_palette( - Palette::generate(&cover) - ) - }).unwrap_or_else(|| Theme::default()); + let theme = cover.as_ref() + .map(|cover| { + Theme::from_palette( + Palette::generate(&cover) + ) + }).unwrap_or_else(|| Theme::default()); + + let cover = cover.expect("TODO"); + let cover = Arc::new(cover.blur((cover.width() / 50) as f32)); + + let left_peri = Periphery::new(cover.clone(), true, size); + let rite_peri = Periphery::new(cover, false, size); Lyrics { lines: vec![lyric], scroll_state: scrollable::State::new(), - song, theme, + song, theme, left_peri, rite_peri, } } @@ -85,6 +98,11 @@ impl Lyrics { .deselect(); } + pub fn notify_resized(&mut self, w: u32, h: u32) { + self.left_peri.notify_resized(w, h); + self.rite_peri.notify_resized(w, h); + } + pub fn insert_line(&mut self, index: usize, content: Option) -> &mut Lyric { self.lines.insert(index, match content { Some(content) => Lyric::new_with_value(content), @@ -114,7 +132,9 @@ impl Lyrics { Container::new( Row::new() + .push(self.left_peri.view()) .push(lyrics) + .push(self.rite_peri.view()) ) .align_y(Align::Center) .style(self.theme) diff --git a/src/main.rs b/src/main.rs index c11d553..d85a39f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod lyrics; mod styles; mod file_select; mod load_song; +mod peripheries; fn main() { app::DelyriumApp::run(Settings::default()).unwrap(); diff --git a/src/peripheries.rs b/src/peripheries.rs new file mode 100644 index 0000000..9a02250 --- /dev/null +++ b/src/peripheries.rs @@ -0,0 +1,92 @@ +use image::imageops::crop_imm; +use image::ImageBuffer; +use image::Bgra; +use iced::Length; +use iced::Element; +use crate::app::Message; +use std::sync::Arc; +use iced::Image; +use image::imageops::FilterType; +use image::DynamicImage; +use image::GenericImageView; +use iced::widget::image::Handle; + + +#[derive(Clone, Debug)] +pub struct Periphery { + left: bool, + source_image: Arc, + upscaled: (u32, ImageBuffer, Vec>), + image: Handle, + w: u16, + h: u16, +} + +impl Periphery { + + pub fn new(source_image: Arc, left: bool, (w, h): (u32, u32)) -> Self { + let mut p = Periphery { + image: Handle::from_pixels(0, 0, Vec::new()), + upscaled: (0, ImageBuffer::, Vec>::from_raw(0, 0, Vec::new()).unwrap()), + w: 0, h: 0, + left, source_image + }; + p.notify_resized(w, h); + p + } + + pub fn notify_resized(&mut self, w: u32, h: u32) { + let body_width = (w / 5).max(450); + let w = w.saturating_sub(body_width) / 2; + self.w = w as u16; + self.h = h as u16; + + if w == 0 { + return; + } + + let h_scale_needed = w as f32 / self.source_image.width() as f32; + let v_scale_needed = h as f32 / self.source_image.height() as f32; + let scale = f32::max(h_scale_needed, v_scale_needed); + + let nh = (scale * (self.source_image.height() as f32)).ceil() as u32; + let nw = (scale * (self.source_image.width() as f32)).ceil() as u32; + self.upscaled = ( + w, + self.source_image.resize(nw, nh, FilterType::Nearest) + .into_bgra8() + ); + + let ratio = w as f32 / h as f32; + let source_ratio = self.source_image.width() as f32 / self.source_image.height() as f32; + + let (nw, nh) = if ratio < source_ratio { + ( + (self.upscaled.1.height() as f32 * ratio) as u32, + self.upscaled.1.height() + ) + } else { + ( + self.upscaled.1.width(), + (self.upscaled.1.width() as f32 / ratio) as u32 + ) + }; + + let h_shift_mul = if self.left { -1 } else { 1 }; + let image = crop_imm( + &self.upscaled.1, + (((self.upscaled.1.width() / 2) as i32 + h_shift_mul * (nw as i32)).max(0) as u32).min(self.upscaled.1.width() - nw), + self.upscaled.1.height().saturating_sub(nh) / 2, + w, h, + ); + + self.image = Handle::from_pixels(image.width(), image.height(), image.to_image().into_raw()); + } + + pub fn view(&mut self) -> Element { + Image::new(self.image.clone()) + .width(Length::Units(self.w)) + .height(Length::Units(self.h)) + .into() + } +}