use crate::mpd_handler::{InfoFromShared, MPDHandler};
use crate::Opt;
use ggez::event::{self, EventHandler};
-use ggez::graphics::{self, Color, DrawParam, Drawable, Text, TextFragment};
+use ggez::graphics::{
+ self, Color, DrawParam, Drawable, Image, Rect, Text, TextFragment, Transform,
+};
use ggez::Context;
use ggez::GameError;
+use image::io::Reader as ImageReader;
+use image::GenericImageView;
+use std::io::Cursor;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, RwLock};
use std::thread;
shared: Option<InfoFromShared>,
password_entered: bool,
dirty_flag: Option<Arc<AtomicBool>>,
+ album_art: Option<Image>,
+ album_art_draw_transform: Option<Transform>,
+ filename_text: Text,
+ artist_text: Text,
+ title_text: Text,
}
impl MPDDisplay {
shared: None,
password_entered: false,
dirty_flag: None,
+ album_art: None,
+ album_art_draw_transform: None,
+ filename_text: Text::new(""),
+ artist_text: Text::new(""),
+ title_text: Text::new(""),
}
}
log("Failed to initialize MPDHandler");
}
}
+
+ fn get_album_art_transform(&mut self, ctx: &mut Context, fill: bool) -> () {
+ if fill {
+ unimplemented!("filled image not implemented");
+ } else {
+ if let Some(image) = &self.album_art {
+ let screen_coords: Rect = graphics::screen_coordinates(ctx);
+ let art_rect: Rect = image.dimensions();
+ let offset_x: f32 = (screen_coords.w.abs() - art_rect.w.abs()) / 2.0f32;
+ let offset_y: f32 = (screen_coords.h.abs() - art_rect.h.abs()) / 2.0f32;
+ self.album_art_draw_transform = Some(Transform::Values {
+ dest: [offset_x, offset_y].into(),
+ rotation: 0.0f32,
+ scale: [1.0f32, 1.0f32].into(),
+ offset: [0.0f32, 0.0f32].into(),
+ });
+ } else {
+ self.album_art_draw_transform = None;
+ }
+ }
+ }
+
+ fn get_image_from_data(
+ &mut self,
+ ctx: &mut Context,
+ data: (Vec<u8>, String),
+ ) -> Result<(), String> {
+ let mut image_format: image::ImageFormat = image::ImageFormat::Png;
+ match data.1.as_str() {
+ "image/png" => image_format = image::ImageFormat::Png,
+ "image/jpg" | "image/jpeg" => image_format = image::ImageFormat::Jpeg,
+ "image/gif" => image_format = image::ImageFormat::Gif,
+ _ => (),
+ }
+ let img = ImageReader::with_format(Cursor::new(data.0), image_format)
+ .decode()
+ .map_err(|e| format!("ERROR: Failed to decode album art image: {}", e))?;
+ let rgba8 = img.to_rgba8();
+ let ggez_img = Image::from_rgba8(
+ ctx,
+ rgba8.width() as u16,
+ rgba8.height() as u16,
+ rgba8.as_raw(),
+ )
+ .map_err(|e| format!("ERROR: Failed to load album art image in ggez Image: {}", e))?;
+
+ self.album_art = Some(ggez_img);
+
+ Ok(())
+ }
}
impl EventHandler for MPDDisplay {
- fn update(&mut self, _ctx: &mut ggez::Context) -> Result<(), GameError> {
+ fn update(&mut self, ctx: &mut ggez::Context) -> Result<(), GameError> {
if !self.is_valid {
return Err(GameError::EventLoopError(
"Failed to initialize MPDHandler".into(),
if let Some(shared) = &self.shared {
if self.notice_text.contents() != shared.error_text {
self.notice_text = Text::new(TextFragment::new(shared.error_text.clone()));
+ self.title_text = Text::new(TextFragment::new(shared.title.clone()));
+ self.artist_text = Text::new(TextFragment::new(shared.artist.clone()));
+ self.filename_text = Text::new(TextFragment::new(shared.filename.clone()));
+ }
+ }
+ let album_art_data_result =
+ MPDHandler::get_art_data(self.mpd_handler.clone().unwrap());
+ if let Ok(art_data) = album_art_data_result {
+ let result = self.get_image_from_data(ctx, art_data);
+ if let Err(e) = result {
+ log(e);
+ self.album_art = None;
+ self.album_art_draw_transform = None;
+ } else {
+ self.get_album_art_transform(ctx, false);
}
+ } else {
+ self.album_art = None;
+ self.album_art_draw_transform = None;
}
}
}
fn draw(&mut self, ctx: &mut ggez::Context) -> Result<(), GameError> {
graphics::clear(ctx, Color::BLACK);
+ if self.album_art.is_some() && self.album_art_draw_transform.is_some() {
+ log("Drawing album_art");
+ self.album_art.as_ref().unwrap().draw(
+ ctx,
+ DrawParam {
+ trans: self.album_art_draw_transform.unwrap(),
+ ..Default::default()
+ },
+ )?;
+ }
+
self.notice_text.draw(ctx, DrawParam::default())?;
graphics::present(ctx)
}
}
}
+
+ fn resize_event(&mut self, ctx: &mut Context, _width: f32, _height: f32) {
+ self.get_album_art_transform(ctx, false);
+ }
}
pub struct MPDHandler {
art_data: Vec<u8>,
art_data_size: usize,
+ art_data_type: String,
current_song_filename: String,
current_song_title: String,
current_song_artist: String,
let s = Arc::new(RwLock::new(Self {
art_data: Vec::new(),
art_data_size: 0,
+ art_data_type: String::new(),
current_song_filename: String::new(),
current_song_title: String::new(),
current_song_artist: String::new(),
Ok(s)
}
- pub fn get_art_data(h: Arc<RwLock<Self>>) -> Result<Vec<u8>, ()> {
+ pub fn get_art_data(h: Arc<RwLock<Self>>) -> Result<(Vec<u8>, String), ()> {
if let Ok(read_lock) = h.try_read() {
if read_lock.art_data.len() == read_lock.art_data_size {
- return Ok(read_lock.art_data.clone());
+ return Ok((read_lock.art_data.clone(), read_lock.art_data_type.clone()));
}
}
'handle_buf: loop {
if write_handle.current_binary_size > 0 {
- if write_handle.current_binary_size < buf_vec.len() {
+ if write_handle.current_binary_size <= buf_vec.len() {
let count = write_handle.current_binary_size;
write_handle.art_data.extend_from_slice(&buf_vec[0..count]);
buf_vec = buf_vec.split_off(count + 1);
write_handle.current_binary_size = 0;
write_handle.poll_state = PollState::None;
- write_handle.dirty_flag.store(true, Ordering::Relaxed);
- log("Got complete album art chunk");
+ log(format!(
+ "Album art recv progress: {}/{}",
+ write_handle.art_data.len(),
+ write_handle.art_data_size
+ ));
} else {
write_handle.art_data.extend_from_slice(&buf_vec);
write_handle.current_binary_size -= buf_vec.len();
write_handle.art_data.len(),
write_handle.art_data_size
));
+ if write_handle.art_data.len() == write_handle.art_data_size {
+ write_handle.dirty_flag.store(true, Ordering::Relaxed);
+ }
break 'handle_buf;
}
}
write_handle.current_song_title = line.split_off(7);
} else if line.starts_with("Artist: ") {
write_handle.current_song_artist = line.split_off(8);
+ } else if line.starts_with("type: ") {
+ write_handle.art_data_type = line.split_off(6);
} else {
log(format!("WARNING: Got unrecognized/ignored line: {}", line));
}