use iced::Image; use iced::image::Handle; use image::DynamicImage; use crate::controls::ControlsEvent; use crate::controls::Controls; use crate::lyrics::Lyric; use crate::lyrics::Lyrics; use crate::app::Message; use iced::Element; use crate::styles::Theme; use iced::Container; use iced::Row; use crate::palette::Palette; use crate::load_song::extract_cover; use iced::Length; use image::imageops::FilterType; use symphonia::core::formats::FormatReader; use image::GenericImageView; pub struct Editor { lyrics: Lyrics, theme: Theme, controls: Controls, bg_img: DynamicImage, cached_resized_bg: Option, dimensions: (u32, u32), } impl Editor { pub fn new(mut song: Box, size: (u32, u32)) -> Self { let cover = extract_cover(song.as_mut()); let theme = cover.as_ref() .map(|cover| { Theme::from_palette( Palette::generate(&cover) ) }).unwrap_or_else(|| Theme::default()); let cover = cover.expect("TODO"); let bg_img = DynamicImage::ImageBgra8( cover.blur((cover.width() / 50) as f32).into_bgra8() ); let controls = Controls::new(song); Self { lyrics: Lyrics::new(), dimensions: size, cached_resized_bg: None, controls, theme, bg_img, } } // TODO: work on untangling this mess pub fn handle_controls_event(&mut self, event: ControlsEvent) { self.controls.handle_event(event) } pub fn insert_text(&mut self, text: String) { self.lyrics.insert_text(text); } pub fn update_line(&mut self, new_content: String, line_no: usize) { self.lyrics.update_line(new_content, line_no); } pub fn advance_line(&mut self, current_line: usize) { self.lyrics.advance_line(current_line); } pub fn current_line_mut(&mut self) -> (usize, &mut Lyric) { self.lyrics.current_line_mut() } pub fn is_animating(&self) -> bool { self.controls.is_playing() } fn calculate_margin_width(&self) -> u32 { let (w, _h) = self.dimensions; let body_size = (w / 5).max(450); w.saturating_sub(body_size) / 2 } pub fn notify_resized(&mut self, w: u32, h: u32) { self.dimensions = (w, h); let (_w, h) = self.dimensions; let margin_w = self.calculate_margin_width(); self.cached_resized_bg = if margin_w != 0 { let resized_bg = self.bg_img.resize_to_fill(margin_w, h, FilterType::Nearest); Some(Handle::from_pixels( resized_bg.width(), resized_bg.height(), resized_bg.into_bgra8().into_raw() )) } else { None }; } pub fn view(&mut self) -> Element { let row = if let Some(margin_bg) = &self.cached_resized_bg { let (w, _h) = self.dimensions; let (img1, img2) = ( Image::new(margin_bg.clone()) .width(Length::Units(w as u16)) .height(Length::Fill), Image::new(margin_bg.clone()) .width(Length::Units(w as u16)) .height(Length::Fill), ); Row::new() .push(img1) .push(self.controls.view_progress(self.theme)) .push(self.lyrics.view(self.theme)) .push(img2) } else { Row::new() .push(self.controls.view_progress(self.theme)) .push(self.lyrics.view(self.theme)) }; Container::new(row) .style(self.theme) .height(Length::Fill) .into() } }