extern crate sdl2; mod smashquery; mod smashrequest; use sdl2::pixels::{Color, PixelFormatEnum}; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::rect::Rect; use sdl2::render::{Canvas, TextureQuery}; use smashrequest::SmashQueue; use std::sync::{Arc, Mutex}; use std::time::Duration; use std::fs; use serde::Deserialize; #[derive(Deserialize,Clone)] pub struct Config { tournament: String, update: Option, fullscreen: Option, smash_key: String, font_size: u16, font_size_departure : u16, margin: u32, tournament_image: Option } struct Line<'a> { height : u32, width : u32, players : String, alt_color : bool, texture : sdl2::render::Texture<'a>, y: u32 } impl Config { fn new() -> Self { Self { tournament: String::new(), update: Some(1),fullscreen:Some(false), smash_key: String::new(), font_size: 30 , font_size_departure : 45, margin: 10,tournament_image: None } } } pub fn render(canvas : &mut Canvas , queues : &Vec,font : &sdl2::ttf::Font<'_, '_> , font_departure : &sdl2::ttf::Font<'_, '_>, config : &Config ){ let texture_creator = canvas.texture_creator(); let mut backline_text = texture_creator.create_texture_streaming(PixelFormatEnum::RGB24, 1, 1).map_err(|e| e.to_string()).unwrap(); //Back line texture backline_text.with_lock(None, |buffer : &mut [u8], pitch: usize| { buffer[1] = 5; buffer[1] = 30; buffer[2] = 66; }).unwrap(); let mut y : u32 = 0; let mut index = 0; let mut lines = Vec::::new(); for sq in queues { let surface: sdl2::surface::Surface<'_> = font.render(sq.name.as_str()).blended(Color::RGBA(255, 255, 0, 255)).map_err(|e| e.to_string()).unwrap(); let text = texture_creator.create_texture_from_surface(&surface).unwrap(); let textq : TextureQuery = text.query(); let _ = canvas.copy(&text, None, Rect::new(0, y.try_into().map_err(|_| 0).unwrap(), textq.width, textq.height)); y += textq.height+config.margin * 2; //compute line for current_match in &sq.matches { index += 1; let switch_col : bool = index%2 == 0; let var_name = format!("{} vs {}", ¤t_match.player1, current_match.player2); let surface = font.render(var_name.as_str()).blended(Color::RGBA(255, 255, 255, 255)).map_err(|e| e.to_string()).unwrap(); let text = texture_creator.create_texture_from_surface(&surface).unwrap(); let textq : TextureQuery = text.query(); let line = Line{ height : textq.height, width : textq.width, players : var_name, texture : texture_creator.create_texture_from_surface(&surface).unwrap(), alt_color : switch_col, y: 0 }; lines.push(line); } let prev_y = y; // background for l in &lines { if l.alt_color { let _ = canvas.copy(&backline_text, None, Rect::new(0, y as i32 - config.margin as i32 , canvas.viewport().width(), l.height + config.margin )); } y += l.height + (config.margin*2); } // depart ! let d_surface = font_departure.render("Départ / Departure").blended(Color::RGBA(130, 218, 255, 255)).map_err(|e| e.to_string()).unwrap(); let d_text = texture_creator.create_texture_from_surface(&d_surface).unwrap(); let d_textq : TextureQuery = d_text.query(); let angle : f64 = f64::from(-90.0); let d_x = canvas.viewport().width() as i32 - (d_textq.width as i32/2) - d_textq.height as i32; let d_y = canvas.viewport().height() as i32 - ( d_textq.width as i32 /2) - d_textq.height as i32; let dst = Rect::new(d_x, d_y,d_textq.width,d_textq.height); let _ = canvas.copy_ex(&d_text, None, dst,angle,None,false,false).unwrap();// d_textq.width, d_textq.height)); // foreground y = prev_y; for l in &lines { let _ = canvas.copy(&l.texture, None, Rect::new(10, y as i32 - config.margin as i32/2 , l.width, l.height)); y += l.height + (config.margin *2) ; } } } pub fn main() -> Result<(), Box> { println!("Read config"); let config_file = fs::read_to_string("config.toml"); let box_config : Box = if config_file.is_ok() { Box::new(toml::from_str(&config_file.unwrap()).unwrap()) } else { Box::new(Config::new()) }; let update_timer = match box_config.update { Some(v) => v, None => 10 } * 1000 ; println!("{}",box_config.tournament); if box_config.tournament.is_empty(){ println!("Empty Tournament , Exiting."); return Ok(()); } let fullscreen = match box_config.fullscreen { Some(v) => v, None => false }; println!("Fullscreen : {}",fullscreen); println!("Done"); let test = Arc::new(Mutex::new(Vec::::new())); let sdl_context = sdl2::init().unwrap(); let video_subsystem = sdl_context.video().unwrap(); let mut build = video_subsystem.window("LaDOSE-SNCF", 1280, 720); if fullscreen { build.fullscreen(); } else { build.position_centered(); } let window = build .build() .unwrap(); let mut canvas: Canvas = window.into_canvas().build().unwrap(); let ttf_context = sdl2::ttf::init().unwrap(); let font : sdl2::ttf::Font<'_, '_> = ttf_context.load_font("font/achemine_bold.ttf", box_config.font_size).unwrap(); let font_departure : sdl2::ttf::Font<'_, '_> = ttf_context.load_font("font/achemine_bold.ttf", box_config.font_size_departure).unwrap(); let timer = sdl_context.timer()?; let test_clone = Arc::clone(&test); let callback = Box::new(|| { println!("Smash!"); let data = smashrequest::get_matches(box_config.tournament.as_str(), box_config.smash_key.as_str()); let mut a = test_clone.lock().unwrap(); a.clone_from(&data); return update_timer }); //callback is called because timer is fucked up ? callback(); let _timer_cb = &timer.add_timer(1,callback); canvas.set_draw_color(Color::RGB(0, 255, 255)); canvas.clear(); canvas.present(); println!("Start Rendering"); let mut event_pump = sdl_context.event_pump().unwrap(); 'running: loop { canvas.set_draw_color(Color::RGB(0,136,206)); canvas.clear(); let test_c = Arc::clone(&test); let a = test_c.lock().unwrap(); //println!("{:?}",&a); render(&mut canvas,&a,&font,&font_departure, &box_config); for event in event_pump.poll_iter() { match event { Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { break 'running Ok(()); }, _ => {} } } canvas.present(); ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); } }