use crate::message::Message; use crate::polygon_draw::*; use crate::utils::string_to_polygon; use serde::{Deserialize, Serialize}; use kira::{sound::static_sound::StaticSoundData, AudioManager}; use iced::event::Status; use iced::mouse::Cursor; use iced::widget::canvas::{Event, Geometry}; use iced::{keyboard, Vector}; use iced::{ mouse::{self, ScrollDelta}, Size, }; use iced::widget::canvas; use iced::widget::canvas::Stroke; use iced::widget::canvas::Style; use iced::{Color, Rectangle, Renderer, Theme}; use std::f32::consts::PI; use std::mem::swap; use std::time::Duration; #[derive(Serialize, Deserialize)] pub struct Music { pub poly_frame: Vec<(f32, PolygonFrame)>, pub nb_sec_for_rev: f32, pub file_name: String, pub length: f32, #[serde(skip)] teta: f32, #[serde(skip)] pub current_delta: f32, #[serde(skip)] point_removed: Vec<(f32, PolygonFrame)>, } impl Music { fn find_poly_frame(&mut self, delta: f32) -> &mut PolygonFrame { if let Some(i) = self .poly_frame .windows(2) .position(|w| w[0].0 <= delta && delta < w[1].0) { &mut self.poly_frame[i].1 } else { &mut self.poly_frame.last_mut().unwrap().1 } } fn find_index_frame(&mut self, delta: f32) -> usize { if let Some(i) = self .poly_frame .windows(2) .position(|w| w[0].0 <= delta && delta < w[1].0) { i } else { self.poly_frame.len() - 1 } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~PUBLIC~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pub fn current_frame(&self, delta: f32) -> &PolygonFrame { if let Some(i) = self .poly_frame .windows(2) .position(|w| w[0].0 <= delta && delta < w[1].0) { &self.poly_frame[i].1 } else { &self.poly_frame.last().unwrap().1 } } pub fn default() -> Music { Music { poly_frame: vec![(0.0, PolygonFrame::default())], nb_sec_for_rev: 1.0, file_name: "Default File Name".to_string(), length: 60.0, teta: 0., current_delta: 0., point_removed: vec![], } } pub fn update_frame(&mut self) { for (_, p) in &mut self.poly_frame { p.update(); } } pub fn fix_teta(&mut self, delta: f32) { let new_teta = delta % self.nb_sec_for_rev * 2.0 * PI / self.nb_sec_for_rev; self.teta = new_teta; } pub fn apply_tick(&mut self, delta: f32, time_btw: Duration, audio_manager: &mut AudioManager) { let teta_temp = self.teta; self.teta += 2.0 * PI * (1.0 / self.nb_sec_for_rev) * (time_btw.as_millis() as f32 / 1_000.0); self.teta %= 2.0 * PI; let currrent_teta = self.teta; let current_frame = self.find_poly_frame(delta); current_frame.teta = currrent_teta; let sound_to_play = current_frame.all_sound_to_play_btw(teta_temp, current_frame.teta); for sound in sound_to_play { audio_manager .play(sound.clone()) .expect("Error to play sound"); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~SET~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pub fn set_sound( &mut self, delta: f32, index: usize, sound: StaticSoundData, sound_name: String, ) -> String { let current_frame = self.find_poly_frame(delta); current_frame.polygons[index].sound = sound; let out = current_frame.polygons[index].sound_name.clone(); current_frame.polygons[index].sound_name = sound_name; out } pub fn set_teta(&mut self, delta: f32, index: usize, teta: f32) -> f32 { let out = self.find_poly_frame(delta).polygons[index].global_teta; self.find_poly_frame(delta).polygons[index].global_teta = teta; out } pub fn set_color(&mut self, delta: f32, index: usize, color: Color) -> Color { let current_frame = self.find_poly_frame(delta); let out = current_frame.polygons[index].color.clone(); current_frame.polygons[index].color = color; out } pub fn set_color_picker(&mut self, delta: f32, i: usize, b: bool) { let current_frame = self.find_poly_frame(delta); current_frame.polygons[i].show_color_picker = b; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ADD/REMOVE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pub fn add_point(&mut self, delta: f32) { let pos = self .poly_frame .binary_search_by(|(d, _)| d.partial_cmp(&delta).unwrap()) .unwrap_or_else(|e| e); self.poly_frame .insert(pos, (delta, self.current_frame(delta).clone())); } pub fn add_point_old(&mut self) { if let Some(pair) = self.point_removed.pop() { let pos = self .poly_frame .binary_search_by(|(d, _)| d.partial_cmp(&pair.0).unwrap()) .unwrap_or_else(|e| e); self.poly_frame.insert(pos, pair); } } pub fn remove_point(&mut self, delta: f32) { let i = self.find_index_frame(delta); if i != 0 { self.point_removed.push(self.poly_frame[i].clone()); self.poly_frame.remove(i); } } pub fn add_polygon(&mut self, delta: f32, polygon_name: String) { let current_frame = self.find_poly_frame(delta); let mut poly = string_to_polygon(polygon_name); poly.update(); current_frame.polygons.push(poly); } pub fn add_polygon_from(&mut self, delta: f32, polygon: Polygon) { let current_frame = self.find_poly_frame(delta); current_frame.polygons.push(polygon); } pub fn remove_polygon(&mut self, delta: f32, i: usize) -> Polygon { let pf = self.find_poly_frame(delta); let mut i = i; if i == usize::MAX { i = pf.polygons.len() - 1 } let out = pf.polygons[i].clone(); pf.polygons.remove(i); out } pub fn slide_to_left(&mut self, delta: f32) { let i = self.find_index_frame(delta); if i > 0 { let (left, right) = self.poly_frame.split_at_mut(i); swap(&mut left[i - 1].1, &mut right[0].1); } } pub fn slide_to_right(&mut self, delta: f32) { let i = self.find_index_frame(delta); if i < self.poly_frame.len() - 1 { let (left, right) = self.poly_frame.split_at_mut(i + 1); swap(&mut left[i].1, &mut right[0].1); } } } #[derive(Default, Debug)] pub struct StateMusic { mouse_left: bool, ctrl: bool, zoom: f32, offset: f32, } impl canvas::Program for Music { // No internal state type State = StateMusic; fn draw( &self, state: &Self::State, renderer: &Renderer, _theme: &Theme, bounds: Rectangle, _cursor: mouse::Cursor, ) -> Vec { let mut geo_small_frame: Vec = vec![]; let mut geo_cursor: Vec = vec![]; let frame = canvas::Frame::new(renderer, bounds.size()); let global_width = bounds.width * state.zoom; let mut toggle_color = true; let padding = 8.; let w = global_width - (padding * 2.); for (delta, polyframe) in &self.poly_frame { let x = delta / self.length * w + 8. - state.offset; let mut back_frame = canvas::Frame::new( renderer, Size { width: global_width.clamp(0.0, bounds.width), height: bounds.height, }, ); back_frame.fill_rectangle( iced::Point { x: x, y: 0.0 }, Size { width: global_width, height: bounds.height, }, if toggle_color { Color::from_rgb8(27, 60, 83) } else { Color::from_rgb8(69, 104, 130) }, ); geo_small_frame.push(back_frame.into_geometry()); toggle_color = !toggle_color; let mut small_frame = canvas::Frame::new( renderer, Size { width: global_width.clamp(0.0, bounds.width), height: bounds.height, }, ); small_frame.translate(Vector { x: x + (bounds.height / 10.), y: (bounds.height / 10.), }); polyframe.draw_in_frame( &mut small_frame, Size { width: (8. * bounds.height) / 10., height: (8. * bounds.height) / 10., }, ); geo_small_frame.push(small_frame.into_geometry()); } let x = self.current_delta / self.length * w + 8. - state.offset; let mut frame_cursor = canvas::Frame::new(renderer, bounds.size()); frame_cursor.stroke_rectangle( iced::Point::new(x, 0.), iced::Size { width: 0., height: bounds.height, }, Stroke { width: 4.0, style: Style::Solid(Color::from_rgba(1.0, 0.0, 0.0, 1.)), ..Stroke::default() }, ); frame_cursor.stroke_rectangle( iced::Point { x: -state.offset, y: 0.0, }, iced::Size { width: global_width, height: bounds.height, }, Stroke { width: 16.0, style: Style::Solid(Color::from_rgb8(207, 74, 28)), ..Stroke::default() }, ); geo_cursor.push(frame_cursor.into_geometry()); //vec_geo.push(frame.into_geometry()); // Then, we produce the geometry let mut out = vec![frame.into_geometry()]; out.append(&mut geo_small_frame); out.append(&mut geo_cursor); out } fn update( &self, state: &mut Self::State, event: Event, bounds: Rectangle, cursor: Cursor, ) -> (Status, Option) { //eprintln!("event = {:?}", event); if let Event::Keyboard(keyboard_event) = &event { match keyboard_event { keyboard::Event::ModifiersChanged(m) => { state.ctrl = m.control(); } _ => (), } } if let Event::Mouse(mouse_event) = event { match mouse_event { mouse::Event::ButtonPressed(mouse::Button::Left) => { state.mouse_left = true; if let Some(position) = cursor.position_in(bounds) { let pos_x = (position.x + state.offset - 8.0) / (bounds.width * state.zoom - 16.); let delta = (pos_x * self.length).clamp(0., self.length); return ( Status::Captured, Some(crate::message::Message::ClickedOnTimeLine(delta)), ); } } mouse::Event::ButtonReleased(mouse::Button::Left) => state.mouse_left = false, mouse::Event::CursorMoved { position: _ } => { if let Some(position) = cursor.position_in(bounds) && state.mouse_left { let pos_x = (position.x + state.offset - 8.0) / (bounds.width * state.zoom - 16.); let delta = (pos_x * self.length).clamp(0., self.length); return (Status::Captured, Some(Message::ClickedOnTimeLine(delta))); } } mouse::Event::WheelScrolled { delta: d } => { if state.ctrl { match d { ScrollDelta::Lines { x: _, y } => { let before = bounds.width * state.zoom; state.zoom += y / 10.; state.offset = state.offset * (bounds.width * state.zoom) / before; } ScrollDelta::Pixels { x: _, y } => { let before = bounds.width * state.zoom; state.zoom += y / 10.; state.offset = state.offset * (bounds.width * state.zoom) / before; } } } else { match d { ScrollDelta::Lines { x: _, y } => { state.offset -= y * 32. * state.zoom; } ScrollDelta::Pixels { x: _, y } => { state.offset -= y * 32. * state.zoom; } } } } _ => {} } } state.zoom = state.zoom.clamp(1.0, 10.); if state.offset + bounds.width >= bounds.width * state.zoom { state.offset = bounds.width * state.zoom - bounds.width } if state.offset <= 0. { state.offset = 0. } (Status::Ignored, None) } }