137 lines
3.2 KiB
Rust
137 lines
3.2 KiB
Rust
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<Handle>,
|
|
dimensions: (u32, u32),
|
|
}
|
|
|
|
impl Editor {
|
|
pub fn new(mut song: Box<dyn FormatReader>, size: (u32, u32)) -> (Self, Command<Message>) {
|
|
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)
|
|
}
|
|
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<Message> {
|
|
|
|
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()
|
|
}
|
|
}
|