mod polygon_draw; use std::{fs, io}; use iced::{ Color, Element, Task, Theme, time::{self, Duration}, widget::{Column, button, canvas, column, pick_list, row, slider, text}, }; use polygon_draw::{Polygon, PolygonFrame}; use std::f32::consts::PI; use std::time::Instant; use kira::{ AudioManager, AudioManagerSettings, DefaultBackend, sound::static_sound::StaticSoundData, }; fn main() -> iced::Result { iced::application("My App", MyApp::update, MyApp::view) .theme(|_| Theme::Dark) .subscription(MyApp::subscription) .run_with(MyApp::new) } #[derive(Debug, Clone)] enum Message { ButtonPressedIncrement, ButtonPressedDecrement, Tick, AddPolygon(String), ChangeTeta(usize, f32), Remove(usize), ChangeColor(usize, String), ChangeSound(usize, String), } struct MyApp { poly_frame: PolygonFrame, time_last_frame: Instant, nb_sec_for_rev: u32, audio_manager: AudioManager, default_sound: StaticSoundData, } impl MyApp { fn new() -> (Self, Task) { let manager = AudioManager::::new(AudioManagerSettings::default()) .expect("Error to load AudioManager"); let sound_data = StaticSoundData::from_file("assets/tick.ogg").expect("Fail to load audio"); ( Self { nb_sec_for_rev: 4, time_last_frame: Instant::now(), audio_manager: manager, default_sound: sound_data.clone(), poly_frame: PolygonFrame { teta: 0.0, polygons: vec![ //Polygon::n_gon(0.0, 12), //Polygon::triangle(0.0), ], }, }, Task::none(), ) } fn update(&mut self, message: Message) { match message { Message::ButtonPressedIncrement => self.nb_sec_for_rev += 1, Message::ButtonPressedDecrement => { if self.nb_sec_for_rev > 1 { self.nb_sec_for_rev -= 1; } } Message::AddPolygon(s) => { let mut poly: Polygon; if s.starts_with("Ngon") { if let Ok(sides) = s.trim_start_matches("Ngon").parse::() { poly = Polygon::n_gon(0.0, sides, self.default_sound.clone()); poly.name = format!("Ngon_{}", sides); } else { return; } } else { match s.as_str() { "Segment" => { poly = Polygon::segment(0.0, self.default_sound.clone()); poly.name = "Segment".to_string(); } "Triangle" => { poly = Polygon::triangle(0.0, self.default_sound.clone()); poly.name = "Triangle".to_string(); } "Square" => { poly = Polygon::square(0.0, self.default_sound.clone()); poly.name = "Square".to_string(); } "Nr6In30" => { poly = Polygon::nr_6_in_30(0.0, self.default_sound.clone()); poly.name = "Nr6In30".to_string(); } "Nr7In30" => { poly = Polygon::nr_7_in_30(0.0, self.default_sound.clone()); poly.name = "Nr7In30".to_string(); } "Nr8In30" => { poly = Polygon::nr_8_in_30(0.0, self.default_sound.clone()); poly.name = "Nr8In30".to_string(); } "Nr9In30" => { poly = Polygon::nr_9_in_30(0.0, self.default_sound.clone()); poly.name = "Nr9In30".to_string(); } "Nr8In42" => { poly = Polygon::nr_8_in_42(0.0, self.default_sound.clone()); poly.name = "Nr8In42".to_string(); } "Nr9In42" => { poly = Polygon::nr_9_in_42(0.0, self.default_sound.clone()); poly.name = "Nr9In42".to_string(); } "Nr10aIn42" => { poly = Polygon::nr_10a_in_42(0.0, self.default_sound.clone()); poly.name = "Nr10aIn42".to_string(); } "Nr10bIn42" => { poly = Polygon::nr_10b_in_42(0.0, self.default_sound.clone()); poly.name = "Nr10bIn42".to_string(); } _ => poly = Polygon::n_gon(0.0, 0, self.default_sound.clone()), } } self.poly_frame.polygons.push(poly); } Message::Tick => { let time_btw = Instant::now().duration_since(self.time_last_frame); let teta_temp = self.poly_frame.teta; self.poly_frame.teta += 2.0 * PI * (1.0 / self.nb_sec_for_rev as f32) * (time_btw.as_millis() as f32 / 1_000.0); self.poly_frame.teta %= 2.0 * PI; let sound_to_play = self .poly_frame .all_sound_to_play_btw(teta_temp, self.poly_frame.teta); for sound in sound_to_play { self.audio_manager .play(sound.clone()) .expect("Error to play sound"); } self.time_last_frame = Instant::now(); } Message::Remove(i) => { self.poly_frame.polygons.remove(i - 1); } Message::ChangeTeta(i, teta) => { self.poly_frame.polygons[i].global_teta = teta; } Message::ChangeColor(i, s) => { let c: Color; match s.as_str() { "Green" => c = Color::from_rgb(0.0, 1.0, 0.0), "Blue" => c = Color::from_rgb(0.0, 0.0, 1.0), "Cyan" => c = Color::from_rgb(0.0, 1.0, 1.0), "Yellow" => c = Color::from_rgb(1.0, 1.0, 0.0), "Pink" => c = Color::from_rgb(1.0, 0.0, 1.0), _ => c = Color::BLACK, } self.poly_frame.polygons[i].color = c; } Message::ChangeSound(i, s) => { self.poly_frame.polygons[i].sound = StaticSoundData::from_file(s).expect("Fail to load audio") } } } fn view(&self) -> iced::Element { let txt_nb_rev = format!("Revolution per second : {}", self.nb_sec_for_rev); let mut i = 0; //Create all polygon options let polygon_rows: Vec> = self .poly_frame .polygons .iter() .map(|polygon| { let current_index = i; i += 1; let entries = fs::read_dir("./assets/") .unwrap() .map(|res| res.map(|e| e.path().to_str().unwrap().to_string())) .collect::, io::Error>>() .unwrap(); row![ text(&polygon.name), slider(0.0..=2.0 * PI, polygon.global_teta, move |f| { Message::ChangeTeta(current_index, f) }) .step(PI / 84f32), // 84 | 4 for do PI / 4 button("Remove").on_press(Message::Remove(i)), pick_list( ["Black", "Blue", "Green", "Pink", "Yellow", "Cyan"] .map(|s| s.to_string()) .to_vec(), Some("Color".to_string()), move |s| { Message::ChangeColor(current_index, s) } ), pick_list(entries, Some("Sound".to_string()), move |s| { Message::ChangeSound(current_index, s) }), ] .into() }) .collect(); let ngon_options: Vec = (5..=42).map(|sides| format!("Ngon{}", sides)).collect(); let all_options: Vec = [ "Segment", "Triangle", "Square", "Nr6In30", "Nr7In30", "Nr8In30", "Nr9In30", "Nr8In42", "Nr9In42", "Nr10aIn42", "Nr10bIn42", ] .iter() .map(|s| s.to_string()) .chain(ngon_options.into_iter()) .collect(); let polygon_column = Column::with_children(polygon_rows); column![ text("Polymusic").size(32.0), row![ canvas(&self.poly_frame).height(500).width(500), column![ text(txt_nb_rev), row![ button("Increment").on_press(Message::ButtonPressedIncrement), button("Decrement").on_press(Message::ButtonPressedDecrement), ], text("Polygon options"), pick_list(all_options, Some("Choose polygon".to_string()), |s| { Message::AddPolygon(s) }), polygon_column, ], ] ] .into() } fn subscription(&self) -> iced::Subscription { time::every(Duration::from_millis(16)).map(|_| Message::Tick) } }