use crate::lyrics::LyricEvent; use iced::Command; 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, Command) { 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"); #[cfg(not(debug_assertions))] let cover = cover.blur((cover.width() / 100) as f32); let bg_img = DynamicImage::ImageBgra8(cover.into_bgra8()); let (controls, cmd) = Controls::new(song); let mut editor = Self { lyrics: Lyrics::new(), dimensions: size, cached_resized_bg: None, controls, theme, bg_img, }; editor.notify_resized(size.0, size.1); (editor, cmd) } // 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 handle_lyric_event(&mut self, line_no: usize, kind: LyricEvent) { self.lyrics.handle_event(line_no, kind, || self.controls.position()) } 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(550); 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() } }