mod polygon_draw; 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), } 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; 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() } _ => 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; } } } 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; row![ text(&polygon.name), slider( 0.0..=2.0 * std::f32::consts::PI, polygon.global_teta, move |f| { Message::ChangeTeta(current_index, f) } ) .step(2.0 * PI / 42f32), 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) } ), ] .into() }) .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( ["Segment", "Triangle", "Square"] .map(|s| s.to_string()) .to_vec(), Some("Chose polygon".to_string()), |s| { Message::AddPolygon(s) } ), polygon_column, ], ] ] .into() } fn subscription(&self) -> iced::Subscription { time::every(Duration::from_millis(16)).map(|_| Message::Tick) } }