vizualizer of different polygon frame
This commit is contained in:
103
src/main.rs
103
src/main.rs
@@ -12,12 +12,17 @@ use std::fs;
|
|||||||
|
|
||||||
use iced::{Element, window};
|
use iced::{Element, window};
|
||||||
use iced::{
|
use iced::{
|
||||||
Length, Task, Theme,
|
Font,
|
||||||
|
font::Family,
|
||||||
widget::{
|
widget::{
|
||||||
Column, TextInput, button, canvas, column, container, pick_list, row, scrollable, slider,
|
TextInput, column, text, text_input,
|
||||||
text,
|
text_input::{Icon, Side},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use iced::{
|
||||||
|
Length, Task, Theme,
|
||||||
|
widget::{Column, button, canvas, container, pick_list, row, scrollable, slider},
|
||||||
|
};
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
@@ -37,7 +42,6 @@ fn main() -> iced::Result {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
WindowEvent(window::Event),
|
|
||||||
ButtonPressedIncrement,
|
ButtonPressedIncrement,
|
||||||
ButtonPressedDecrement,
|
ButtonPressedDecrement,
|
||||||
Tick,
|
Tick,
|
||||||
@@ -89,9 +93,6 @@ impl MyApp {
|
|||||||
}
|
}
|
||||||
fn update(&mut self, message: Message) {
|
fn update(&mut self, message: Message) {
|
||||||
match message {
|
match message {
|
||||||
Message::WindowEvent(window::Event::Resized(size)) => {
|
|
||||||
println!("Resize detected: {}x{}", size.width, size.height);
|
|
||||||
}
|
|
||||||
Message::ButtonPressedIncrement => self.music.nb_sec_for_rev += 0.5,
|
Message::ButtonPressedIncrement => self.music.nb_sec_for_rev += 0.5,
|
||||||
Message::ButtonPressedDecrement => {
|
Message::ButtonPressedDecrement => {
|
||||||
if self.music.nb_sec_for_rev > 0.5 {
|
if self.music.nb_sec_for_rev > 0.5 {
|
||||||
@@ -102,7 +103,11 @@ impl MyApp {
|
|||||||
self.music.add_polygon(self.current_delta, s);
|
self.music.add_polygon(self.current_delta, s);
|
||||||
}
|
}
|
||||||
Message::Tick => {
|
Message::Tick => {
|
||||||
|
if self.current_delta >= self.music.length {
|
||||||
|
self.paused = true
|
||||||
|
}
|
||||||
if !self.paused {
|
if !self.paused {
|
||||||
|
self.music.current_delta = self.current_delta;
|
||||||
let time_btw = Instant::now().duration_since(self.time_last_frame);
|
let time_btw = Instant::now().duration_since(self.time_last_frame);
|
||||||
self.current_delta += time_btw.as_millis() as f32 / 1000.0;
|
self.current_delta += time_btw.as_millis() as f32 / 1000.0;
|
||||||
self.music
|
self.music
|
||||||
@@ -126,10 +131,11 @@ impl MyApp {
|
|||||||
}
|
}
|
||||||
Message::Save => {
|
Message::Save => {
|
||||||
let json = serde_json::to_string_pretty(&self.music).unwrap();
|
let json = serde_json::to_string_pretty(&self.music).unwrap();
|
||||||
fs::write(format!("./saves/{0}", &self.music.file_name), json).unwrap();
|
fs::write(format!("./saves/{0}.pmx", &self.music.file_name), json).unwrap();
|
||||||
|
self.all_saves = load_path_saves();
|
||||||
}
|
}
|
||||||
Message::Load => {
|
Message::Load => {
|
||||||
let json = fs::read_to_string(format!("./saves/{0}", &self.music.file_name));
|
let json = fs::read_to_string(format!("./saves/{0}.pmx", &self.music.file_name));
|
||||||
match json {
|
match json {
|
||||||
Ok(j) => {
|
Ok(j) => {
|
||||||
let decoded: Music = serde_json::from_str(&j).unwrap();
|
let decoded: Music = serde_json::from_str(&j).unwrap();
|
||||||
@@ -158,16 +164,22 @@ impl MyApp {
|
|||||||
Message::ChangeDelta(f) => {
|
Message::ChangeDelta(f) => {
|
||||||
self.current_delta = f;
|
self.current_delta = f;
|
||||||
self.music.fix_teta(self.current_delta);
|
self.music.fix_teta(self.current_delta);
|
||||||
|
// update the red dot on canvas
|
||||||
|
if self.paused {
|
||||||
|
self.update(Message::TogglePaused);
|
||||||
|
self.update(Message::Tick);
|
||||||
|
self.update(Message::TogglePaused);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> iced::Element<Message> {
|
fn view(&self) -> iced::Element<Message> {
|
||||||
let txt_nb_rev = format!(
|
let txt_nb_rev = if self.music.nb_sec_for_rev % 1. != 0.0 {
|
||||||
"Number of second for revolution : {}",
|
format!("{} sec/revolution", self.music.nb_sec_for_rev)
|
||||||
self.music.nb_sec_for_rev
|
} else {
|
||||||
);
|
format!("{}.0 sec/revolution", self.music.nb_sec_for_rev)
|
||||||
|
};
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let entries = self.all_sounds.clone();
|
let entries = self.all_sounds.clone();
|
||||||
@@ -250,8 +262,29 @@ impl MyApp {
|
|||||||
save_panel.push(button("Load").on_press(Message::Load).into());
|
save_panel.push(button("Load").on_press(Message::Load).into());
|
||||||
}
|
}
|
||||||
column![
|
column![
|
||||||
text("Polymusic").size(32.0),
|
text(&self.music.file_name).size(32.0),
|
||||||
row(save_panel).spacing(20),
|
row(save_panel).spacing(20),
|
||||||
|
row![
|
||||||
|
text("Music Length").size(20),
|
||||||
|
TextInput::new("MM:SS:CS", &self.str_music_length)
|
||||||
|
.on_input(|new_value| Message::LengthChange(new_value))
|
||||||
|
.icon(Icon {
|
||||||
|
font: Font::DEFAULT,
|
||||||
|
code_point: if self.is_length_valid() {
|
||||||
|
'\u{2705}'
|
||||||
|
} else {
|
||||||
|
'\u{274C}'
|
||||||
|
},
|
||||||
|
size: None,
|
||||||
|
spacing: 10.,
|
||||||
|
side: Side::Left,
|
||||||
|
}),
|
||||||
|
button("Valid").on_press(Message::SetMusicLength),
|
||||||
|
text(txt_nb_rev).size(20),
|
||||||
|
button("Increment").on_press(Message::ButtonPressedIncrement),
|
||||||
|
button("Decrement").on_press(Message::ButtonPressedDecrement),
|
||||||
|
]
|
||||||
|
.spacing(20),
|
||||||
row![
|
row![
|
||||||
container(
|
container(
|
||||||
canvas(self.music.current_frame(self.current_delta))
|
canvas(self.music.current_frame(self.current_delta))
|
||||||
@@ -259,11 +292,6 @@ impl MyApp {
|
|||||||
.width(Length::FillPortion(1))
|
.width(Length::FillPortion(1))
|
||||||
),
|
),
|
||||||
column![
|
column![
|
||||||
text(txt_nb_rev),
|
|
||||||
row![
|
|
||||||
button("Increment").on_press(Message::ButtonPressedIncrement),
|
|
||||||
button("Decrement").on_press(Message::ButtonPressedDecrement),
|
|
||||||
],
|
|
||||||
text("Polygon options"),
|
text("Polygon options"),
|
||||||
pick_list(all_options, Some("Choose polygon".to_string()), |s| {
|
pick_list(all_options, Some("Choose polygon".to_string()), |s| {
|
||||||
Message::AddPolygon(s)
|
Message::AddPolygon(s)
|
||||||
@@ -277,7 +305,6 @@ impl MyApp {
|
|||||||
.height(Length::FillPortion(2))
|
.height(Length::FillPortion(2))
|
||||||
.spacing(20),
|
.spacing(20),
|
||||||
column![
|
column![
|
||||||
text("TimeLine"),
|
|
||||||
row![
|
row![
|
||||||
button("Toggle Play").on_press(Message::TogglePaused),
|
button("Toggle Play").on_press(Message::TogglePaused),
|
||||||
text(format!(
|
text(format!(
|
||||||
@@ -285,17 +312,19 @@ impl MyApp {
|
|||||||
delta_to_string(self.current_delta),
|
delta_to_string(self.current_delta),
|
||||||
delta_to_string(self.music.length)
|
delta_to_string(self.music.length)
|
||||||
))
|
))
|
||||||
],
|
.size(20.0)
|
||||||
row![
|
]
|
||||||
text("Music Length"),
|
.spacing(20),
|
||||||
TextInput::new("MM:SS:CS", &self.str_music_length)
|
column![
|
||||||
.on_input(|new_value| Message::LengthChange(new_value)),
|
slider(0.0..=self.music.length, self.current_delta, move |f| {
|
||||||
button("Valid").on_press(Message::SetMusicLength),
|
Message::ChangeDelta(f)
|
||||||
],
|
})
|
||||||
slider(0.0..=self.music.length, self.current_delta, move |f| {
|
.step(&self.music.length / 10_000.),
|
||||||
Message::ChangeDelta(f)
|
canvas(&self.music)
|
||||||
})
|
.height(Length::FillPortion(1))
|
||||||
.step(&self.music.length / 10_000.),
|
.width(Length::FillPortion(1))
|
||||||
|
]
|
||||||
|
.spacing(0),
|
||||||
]
|
]
|
||||||
.height(Length::FillPortion(1))
|
.height(Length::FillPortion(1))
|
||||||
.width(Length::FillPortion(1)),
|
.width(Length::FillPortion(1)),
|
||||||
@@ -332,6 +361,14 @@ fn load_path_saves() -> Vec<String> {
|
|||||||
fs::read_dir("./saves")
|
fs::read_dir("./saves")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.filter_map(|res| res.ok())
|
.filter_map(|res| res.ok())
|
||||||
.map(|e| e.path().file_name().unwrap().to_str().unwrap().to_string())
|
.map(|e| {
|
||||||
|
e.path()
|
||||||
|
.file_name()
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.trim_end_matches(".pmx")
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
75
src/music.rs
75
src/music.rs
@@ -1,19 +1,28 @@
|
|||||||
use crate::utils::string_to_polygon;
|
use crate::utils::string_to_polygon;
|
||||||
use crate::{polygon_draw::*, utils::string_to_color};
|
use crate::{polygon_draw::*, utils::string_to_color};
|
||||||
|
use iced::Length::Fill;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use kira::{AudioManager, sound::static_sound::StaticSoundData};
|
use kira::{AudioManager, sound::static_sound::StaticSoundData};
|
||||||
|
|
||||||
|
use iced::mouse;
|
||||||
|
use iced::widget::canvas;
|
||||||
|
use iced::widget::canvas::Stroke;
|
||||||
|
use iced::widget::canvas::Style;
|
||||||
|
use iced::{Color, Rectangle, Renderer, Theme};
|
||||||
|
use iced::{Vector, color};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Music {
|
pub struct Music {
|
||||||
pub poly_frame: Vec<(f32, PolygonFrame)>,
|
pub poly_frame: Vec<(f32, PolygonFrame)>,
|
||||||
pub nb_sec_for_rev: f32,
|
pub nb_sec_for_rev: f32,
|
||||||
pub file_name: String,
|
pub file_name: String,
|
||||||
pub length: f32,
|
pub length: f32,
|
||||||
|
#[serde(skip)]
|
||||||
teta: f32,
|
teta: f32,
|
||||||
|
#[serde(skip)]
|
||||||
|
pub current_delta: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Music {
|
impl Music {
|
||||||
@@ -21,7 +30,7 @@ impl Music {
|
|||||||
if let Some(i) = self
|
if let Some(i) = self
|
||||||
.poly_frame
|
.poly_frame
|
||||||
.windows(2)
|
.windows(2)
|
||||||
.position(|w| w[0].0 < delta && delta < w[1].0)
|
.position(|w| w[0].0 <= delta && delta < w[1].0)
|
||||||
{
|
{
|
||||||
&mut self.poly_frame[i].1
|
&mut self.poly_frame[i].1
|
||||||
} else {
|
} else {
|
||||||
@@ -33,7 +42,7 @@ impl Music {
|
|||||||
if let Some(i) = self
|
if let Some(i) = self
|
||||||
.poly_frame
|
.poly_frame
|
||||||
.windows(2)
|
.windows(2)
|
||||||
.position(|w| w[0].0 < delta && delta < w[1].0)
|
.position(|w| w[0].0 <= delta && delta < w[1].0)
|
||||||
{
|
{
|
||||||
&self.poly_frame[i].1
|
&self.poly_frame[i].1
|
||||||
} else {
|
} else {
|
||||||
@@ -48,9 +57,10 @@ impl Music {
|
|||||||
(10.0, PolygonFrame::default()),
|
(10.0, PolygonFrame::default()),
|
||||||
],
|
],
|
||||||
nb_sec_for_rev: 1.0,
|
nb_sec_for_rev: 1.0,
|
||||||
file_name: "Polymusic.json".to_string(),
|
file_name: "Default Name".to_string(),
|
||||||
length: 60.0,
|
length: 60.0,
|
||||||
teta: 0.,
|
teta: 0.,
|
||||||
|
current_delta: 0.,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,3 +126,60 @@ impl Music {
|
|||||||
self.find_poly_frame(delta).polygons.remove(i);
|
self.find_poly_frame(delta).polygons.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<Message> canvas::Program<Message> for Music {
|
||||||
|
// No internal state
|
||||||
|
type State = ();
|
||||||
|
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
_state: &(),
|
||||||
|
renderer: &Renderer,
|
||||||
|
_theme: &Theme,
|
||||||
|
bounds: Rectangle,
|
||||||
|
_cursor: mouse::Cursor,
|
||||||
|
) -> Vec<canvas::Geometry> {
|
||||||
|
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
||||||
|
let radius = frame.size().width.min(frame.size().height) / 2.0 - 32.0;
|
||||||
|
let mut toggle_color = true;
|
||||||
|
let padding = 8.;
|
||||||
|
let w = bounds.width - (padding * 2.);
|
||||||
|
for (delta, _) in &self.poly_frame {
|
||||||
|
let x = delta / self.length * w + padding;
|
||||||
|
frame.fill_rectangle(
|
||||||
|
iced::Point { x: x, y: 0.0 },
|
||||||
|
frame.size(),
|
||||||
|
if toggle_color {
|
||||||
|
Color::from_rgb(0.3, 0.3, 0.3)
|
||||||
|
} else {
|
||||||
|
Color::from_rgb(0.1, 0.1, 0.1)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
toggle_color = !toggle_color;
|
||||||
|
}
|
||||||
|
frame.stroke_rectangle(
|
||||||
|
iced::Point { x: 0.0, y: 0.0 },
|
||||||
|
frame.size(),
|
||||||
|
Stroke {
|
||||||
|
width: 16.0,
|
||||||
|
..Stroke::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let x = self.current_delta / self.length * w + padding;
|
||||||
|
frame.stroke_rectangle(
|
||||||
|
iced::Point::new(x, 0.),
|
||||||
|
iced::Size {
|
||||||
|
width: 0.,
|
||||||
|
height: bounds.height,
|
||||||
|
},
|
||||||
|
Stroke {
|
||||||
|
width: 4.0,
|
||||||
|
style: Style::Solid(Color::from_rgb(1.0, 0.0, 0.0)),
|
||||||
|
..Stroke::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Then, we produce the geometry
|
||||||
|
vec![frame.into_geometry()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user