From 260eb03c4005f478783ed65bb05c81c02ffd6165 Mon Sep 17 00:00:00 2001 From: Dukantic Date: Sat, 19 Jul 2025 01:18:34 +0200 Subject: [PATCH] load menu and save carfully --- ] | 242 +++++++++++++++++++++++++++++++++++++++++++++ src/gui.rs | 264 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 252 +++++++++++++--------------------------------- src/message.rs | 5 +- src/music.rs | 4 +- 5 files changed, 582 insertions(+), 185 deletions(-) create mode 100644 ] create mode 100644 src/gui.rs diff --git a/] b/] new file mode 100644 index 0000000..22ff1ff --- /dev/null +++ b/] @@ -0,0 +1,242 @@ +use crate::message::Message; + +use iced::Font; +use iced::alignment::{Horizontal, Vertical}; +use iced::daemon::DefaultStyle; +use iced::font::Style; +use iced::widget::text::default; + +use iced::theme::Palette; +use iced::widget::Button; +use iced::widget::{TextInput, column, text}; +use iced::{ + Alignment, Color, Event, Length, Padding, Task, + event::{self, Status}, + keyboard::{Key, key::Named}, + widget::{Column, button, canvas, container, pick_list, row, scrollable, slider}, +}; +use iced::{Element, Theme, theme}; +use iced_aw::menu::{self, Item}; +use iced_aw::menu_bar; +use iced_aw::widget::color_picker; +use iced_aw::widget::menu::Menu; + +use std::f32::consts::PI; +use std::time::Instant; + +use crate::MyApp; + +pub fn music_view(app: &MyApp) -> iced::Element { + let mut i = 0; + let entries = app.all_sounds.clone(); + //Create all polygon options + let polygon_rows: Vec> = app + .music + .current_frame(app.current_delta) + .polygons + .iter() + .map(|polygon| { + let current_index = i; + let but = button(text("").size(20).center()).on_press(Message::SubmitColor(i)); + let c = column![ + row![ + text(&polygon.name).size(24), + button(text("").size(20)).on_press(Message::Remove(i)), + color_picker( + polygon.show_color_picker, + polygon.color, + but, + Message::CancelColor(i), + move |color| Message::ChooseColor(i, color) + ), + pick_list(entries.clone(), Some(&polygon.sound_name), move |s| { + Message::ChangeSound(current_index, s) + }) + .text_size(20), + ] + .spacing(20), + row![ + TextInput::new("90", &polygon.global_teta.to_degrees().floor().to_string()) + .on_input(move |new_value| Message::ChangeDegree(current_index, new_value)) + .width(Length::FillPortion(1)), + row![ + slider(0.0..=2.0 * PI, polygon.global_teta, move |f| { + Message::ChangeTeta(current_index, f) + }) + .step(2. * PI / 10_000.) + .width(Length::FillPortion(9)) + ] + .padding(Padding::from(16)), + ] + .spacing(5), + ] + .spacing(10) + .into(); + i += 1; + c + }) + .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) + .collect(); + + let polygon_column = scrollable(Column::with_children(polygon_rows).spacing(24)); + + let menu_tpl_1 = |items| Menu::new(items).max_width(200.0).offset(15.0).spacing(5.0); + let save_menu = menu_tpl_1(vec![ + Item::new(button("Save File").on_press(Message::Save)), + Item::new(button("Load Menu").on_press(Message::GoToLoadView).style( + |theme: &Theme, status| { + let palette = theme.extended_palette(); + + match status { + button::Status::Active => { + if !app.already_save { + button::Style::default().with_background(palette.danger.strong.color) + } else { + button::primary(theme, status) + } + } + _ => button::primary(theme, status), + } + }, + )), + Item::new("CTRL+F for quit without save."), + ]); + column![ + menu_bar!((text("File").size(20), save_menu)( + text("Shortcuts").size(20), + menu_tpl_1(vec![Item::new("󰐊 SPACE"), Item::new("󰆓 CTRL+S")]) + )) + .draw_path(menu::DrawPath::Backdrop) + .spacing(20), + text(&app.music.file_name) + .width(Length::FillPortion(1)) + .size(32), + row![ + container( + canvas(app.music.current_frame(app.current_delta)) + .height(Length::FillPortion(1)) + .width(Length::FillPortion(1)) + ), + column![ + text("Polygon options").size(26), + pick_list(all_options, Some("Choose polygon".to_string()), |s| { + Message::AddPolygon(s) + }) + .text_size(18), + polygon_column, + ] + .spacing(10) + .height(Length::FillPortion(1)) + .width(Length::FillPortion(2)), + ] + .height(Length::FillPortion(2)) + .spacing(20), + column![ + row![ + button(text(if app.paused { "󰐊" } else { "󰏤" }).size(28).center()) + .on_press(if app.can_unpaused { + Message::TogglePaused + } else { + Message::None + }) + .width(Length::FillPortion(1)), + row![ + TextInput::new("MM:SS:CS", &app.str_time) + .on_input(|new_value| Message::ChangeDeltaString(new_value)) + .size(28), + text("/").size(30), + TextInput::new("MM:SS:CS", &app.str_music_length) + .on_input(|new_value| Message::LengthChange(new_value)) + .size(28), + ] + .width(Length::FillPortion(10)), + TextInput::new("1.0", &format!("{:.1} sec/rev", &app.music.nb_sec_for_rev)) + .on_input(|new_value| Message::ChangeNbPerSec(new_value)) + .size(28) + .width(Length::FillPortion(2)), + button(text("").size(28).center()) + .on_press(Message::SlidePointLeft) + .width(Length::FillPortion(1)), + button(text("").size(28).center()) + .on_press(Message::AddPoint) + .width(Length::FillPortion(1)), + button(text("").size(28).center()) + .on_press(Message::SlidePointRight) + .width(Length::FillPortion(1)), + button(text("").size(28).center()) + .on_press(Message::RemovePoint) + .width(Length::FillPortion(1)), + ] + .spacing(20), + column![ + /* + slider(0.0..=app.music.length, self.current_delta, move |f| { + Message::ChangeDelta(f) + }) + .step(&app.music.length / 10_000.),*/ + canvas(&app.music) + .height(Length::FillPortion(1)) + .width(Length::FillPortion(1)) + ] + .spacing(0), + ] + .spacing(20) + .height(Length::FillPortion(1)) + .width(Length::FillPortion(1)), + ] + .spacing(25) + .padding(25) + .into() +} + +pub fn load_file_view(app: &MyApp) -> iced::Element { + row![ + column![ + TextInput::new("Name File", &app.file_name_to_creat) + .on_input(|new_value| Message::SetFileNameCreat(new_value)), + button("Create File").on_press(Message::CreatFile), + text(if app.show_warning_message_creat { + "Warning: File already exists. Delete it or change the file name!" + } else { + "" + }) + .style(|theme: &Theme| { + let palette = theme.extended_palette(); + + text::Style { + color: Some(palette.danger.strong.color), + } + },) + ] + .align_x(Horizontal::Center) + .width(Length::F), + column![ + pick_list( + app.all_saves.clone(), + Some(&app.music.file_name), + move |s| Message::FileNameChanged(s), + ), + button("Load File").on_press(Message::Load), + ] + .align_x(Horizontal::Center) + ] + .align_y(Vertical::Center) + .into() +} diff --git a/src/gui.rs b/src/gui.rs new file mode 100644 index 0000000..287db4c --- /dev/null +++ b/src/gui.rs @@ -0,0 +1,264 @@ +use crate::message::Message; + +use iced::Font; +use iced::alignment::{Horizontal, Vertical}; +use iced::daemon::DefaultStyle; +use iced::font::Style; +use iced::widget::text::default; + +use iced::theme::Palette; +use iced::widget::Button; +use iced::widget::{TextInput, column, text}; +use iced::{ + Alignment, Color, Event, Length, Padding, Task, + event::{self, Status}, + keyboard::{Key, key::Named}, + widget::{Column, Container, button, canvas, container, pick_list, row, scrollable, slider}, +}; +use iced::{Element, Theme, theme}; +use iced_aw::menu::{self, Item}; +use iced_aw::menu_bar; +use iced_aw::widget::color_picker; +use iced_aw::widget::menu::Menu; + +use std::f32::consts::PI; +use std::time::Instant; + +use crate::MyApp; + +pub fn music_view(app: &MyApp) -> iced::Element { + let mut i = 0; + let entries = app.all_sounds.clone(); + //Create all polygon options + let polygon_rows: Vec> = app + .music + .current_frame(app.current_delta) + .polygons + .iter() + .map(|polygon| { + let current_index = i; + let but = button(text("").size(20).center()).on_press(Message::SubmitColor(i)); + let c = column![ + row![ + text(&polygon.name).size(24), + button(text("").size(20)).on_press(Message::Remove(i)), + color_picker( + polygon.show_color_picker, + polygon.color, + but, + Message::CancelColor(i), + move |color| Message::ChooseColor(i, color) + ), + pick_list(entries.clone(), Some(&polygon.sound_name), move |s| { + Message::ChangeSound(current_index, s) + }) + .text_size(20), + ] + .spacing(20), + row![ + TextInput::new("90", &polygon.global_teta.to_degrees().floor().to_string()) + .on_input(move |new_value| Message::ChangeDegree(current_index, new_value)) + .width(Length::FillPortion(1)), + row![ + slider(0.0..=2.0 * PI, polygon.global_teta, move |f| { + Message::ChangeTeta(current_index, f) + }) + .step(2. * PI / 10_000.) + .width(Length::FillPortion(9)) + ] + .padding(Padding::from(16)), + ] + .spacing(5), + ] + .spacing(10) + .into(); + i += 1; + c + }) + .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) + .collect(); + + let polygon_column = scrollable(Column::with_children(polygon_rows).spacing(24)); + + let menu_tpl_1 = |items| Menu::new(items).max_width(200.0).offset(15.0).spacing(5.0); + let save_menu = menu_tpl_1(vec![ + Item::new(button("Save File").on_press(Message::Save)), + Item::new(button("Load Menu").on_press(Message::GoToLoadView).style( + |theme: &Theme, status| { + let palette = theme.extended_palette(); + + match status { + button::Status::Active => { + if !app.already_save { + button::Style::default().with_background(palette.danger.strong.color) + } else { + button::primary(theme, status) + } + } + _ => button::primary(theme, status), + } + }, + )), + Item::new("CTRL+F for quit without save."), + ]); + column![ + menu_bar!((text("File").size(20), save_menu)( + text("Shortcuts").size(20), + menu_tpl_1(vec![ + Item::new("󰐊 SPACE"), + Item::new("󰆓 CTRL+S"), + Item::new("Start ") + ]) + )) + .draw_path(menu::DrawPath::Backdrop) + .spacing(20), + text(&app.music.file_name) + .width(Length::FillPortion(1)) + .size(32), + row![ + container( + canvas(app.music.current_frame(app.current_delta)) + .height(Length::FillPortion(1)) + .width(Length::FillPortion(1)) + ), + column![ + text("Polygon options").size(26), + pick_list(all_options, Some("Choose polygon".to_string()), |s| { + Message::AddPolygon(s) + }) + .text_size(18), + polygon_column, + ] + .spacing(10) + .height(Length::FillPortion(1)) + .width(Length::FillPortion(2)), + ] + .height(Length::FillPortion(2)) + .spacing(20), + column![ + row![ + button(text(if app.paused { "󰐊" } else { "󰏤" }).size(28).center()) + .on_press(if app.can_unpaused { + Message::TogglePaused + } else { + Message::None + }) + .width(Length::FillPortion(1)), + row![ + TextInput::new("MM:SS:CS", &app.str_time) + .on_input(|new_value| Message::ChangeDeltaString(new_value)) + .size(28), + text("/").size(30), + TextInput::new("MM:SS:CS", &app.str_music_length) + .on_input(|new_value| Message::LengthChange(new_value)) + .size(28), + ] + .width(Length::FillPortion(10)), + TextInput::new("1.0", &format!("{:.1} sec/rev", &app.music.nb_sec_for_rev)) + .on_input(|new_value| Message::ChangeNbPerSec(new_value)) + .size(28) + .width(Length::FillPortion(2)), + button(text("").size(28).center()) + .on_press(Message::SlidePointLeft) + .width(Length::FillPortion(1)), + button(text("").size(28).center()) + .on_press(Message::AddPoint) + .width(Length::FillPortion(1)), + button(text("").size(28).center()) + .on_press(Message::SlidePointRight) + .width(Length::FillPortion(1)), + button(text("").size(28).center()) + .on_press(Message::RemovePoint) + .width(Length::FillPortion(1)), + ] + .spacing(20), + column![ + /* + slider(0.0..=app.music.length, self.current_delta, move |f| { + Message::ChangeDelta(f) + }) + .step(&app.music.length / 10_000.),*/ + canvas(&app.music) + .height(Length::FillPortion(1)) + .width(Length::FillPortion(1)) + ] + .spacing(0), + ] + .spacing(20) + .height(Length::FillPortion(1)) + .width(Length::FillPortion(1)), + ] + .spacing(25) + .padding(25) + .into() +} + +pub fn load_file_view(app: &MyApp) -> iced::Element { + Container::new( + column![ + text("Polymusic").size(42), + row![ + column![ + TextInput::new("Name File", &app.file_name_to_creat) + .on_input(|new_value| Message::SetFileNameCreat(new_value)), + button("Create File").on_press(Message::CreatFile), + text(if app.show_warning_message_creat { + "Warning: File already exists. Delete it or change the file name!" + } else { + "" + }) + .style(|theme: &Theme| { + let palette = theme.extended_palette(); + + text::Style { + color: Some(palette.danger.strong.color), + } + },) + ] + .spacing(10) + .width(200) + .height(200) + .align_x(Horizontal::Center), + column![ + pick_list( + app.all_saves.clone(), + Some(&app.music.file_name), + move |s| Message::FileNameChanged(s), + ), + button("Load File").on_press(Message::Load), + text("") + ] + .spacing(10) + .width(200) + .height(200) + .align_x(Horizontal::Center) + ] + .spacing(32) + .align_y(Vertical::Center), + ] + .spacing(64) + .align_x(Horizontal::Center), + ) + .width(Length::Fill) + .height(Length::Fill) + .center_x(Length::Fill) + .center_y(Length::Fill) + .into() +} diff --git a/src/main.rs b/src/main.rs index b37523a..4c7a59f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,10 +9,13 @@ mod message; use message::Message; mod utils; -use utils::{is_delta_format_valid, str_to_sec}; +use utils::{delta_to_string, is_delta_format_valid, str_to_sec}; use std::fs; +mod gui; +use gui::{load_file_view, music_view}; + use iced::Font; use iced::widget::{TextInput, column, text}; use iced::{ @@ -36,7 +39,6 @@ use kira::{ const FONT_BYTES: &[u8] = include_bytes!("../fonts/EnvyCodeRNerdFontMono-Regular.ttf"); const FONT: Font = Font::with_name("EnvyCodeR Nerd Font Mono"); -use crate::utils::delta_to_string; fn main() -> iced::Result { let polytheme: Theme = { let back = Color::from_rgb8(39, 63, 79); @@ -69,7 +71,6 @@ fn main() -> iced::Result { struct MyApp { music: Music, time_last_frame: Instant, - show_save_panel: bool, paused: bool, audio_manager: AudioManager, all_sounds: Vec, @@ -78,6 +79,10 @@ struct MyApp { str_music_length: String, str_time: String, can_unpaused: bool, + already_save: bool, + mode_file_load: bool, + file_name_to_creat: String, + show_warning_message_creat: bool, } impl MyApp { @@ -91,7 +96,6 @@ impl MyApp { Self { time_last_frame: Instant::now(), audio_manager: manager, - show_save_panel: false, paused: true, all_sounds: load_path_sounds(), all_saves: load_path_saves(), @@ -100,6 +104,10 @@ impl MyApp { str_music_length: "01:00:00".to_string(), str_time: "00:00:00".to_string(), can_unpaused: true, + already_save: true, + mode_file_load: true, + file_name_to_creat: "Default File Name".to_string(), + show_warning_message_creat: false, }, Task::none(), ) @@ -108,6 +116,7 @@ impl MyApp { match message { Message::AddPolygon(s) => { self.music.add_polygon(self.current_delta, s); + self.already_save = false; } Message::Tick => { if self.current_delta >= self.music.length { @@ -125,21 +134,24 @@ impl MyApp { } Message::Remove(i) => { self.music.remove_polygon(self.current_delta, i); + self.already_save = false; } Message::ChangeTeta(i, teta) => { self.music.set_teta(self.current_delta, i, teta); + self.already_save = false; } Message::ChangeSound(i, s) => { let sound = StaticSoundData::from_file(format!("./assets/{s}")) .expect("Fail to load audio"); self.music.set_sound(self.current_delta, i, sound, s); + self.already_save = false; } Message::Save => { - dbg!("Save file"); let json = serde_json::to_string_pretty(&self.music).unwrap(); fs::write(format!("./saves/{0}.pmx", &self.music.file_name), json).unwrap(); self.all_saves = load_path_saves(); + self.already_save = true; } Message::Load => { let json = fs::read_to_string(format!("./saves/{0}.pmx", &self.music.file_name)); @@ -148,19 +160,31 @@ impl MyApp { let decoded: Music = serde_json::from_str(&j).unwrap(); self.music = decoded; self.music.update_frame(); + self.mode_file_load = false; } Err(e) => { eprintln!("Error, no saves with this name to load, {e} "); } } } - Message::ToggleSavePanel => self.show_save_panel = !self.show_save_panel, + Message::SetFileNameCreat(s) => self.file_name_to_creat = s, + Message::CreatFile => { + if self.all_saves.contains(&self.file_name_to_creat) { + self.show_warning_message_creat = true; + } else { + self.mode_file_load = false; + self.music = Music::default(); + self.music.file_name = self.file_name_to_creat.clone(); + self.update(Message::Save); + } + } Message::FileNameChanged(s) => self.music.file_name = s, Message::LengthChange(s) => { if is_delta_format_valid(&s) { let sec = str_to_sec(&s); if sec > 0. { self.music.length = sec; + self.already_save = false; } } self.str_music_length = s; @@ -173,6 +197,7 @@ impl MyApp { } Message::ChangeDelta(f) => { + self.already_save = false; self.current_delta = f; self.music.fix_teta(self.current_delta); // update the red dot on canvas @@ -180,25 +205,30 @@ impl MyApp { } Message::ChangeDeltaString(s) => { if is_delta_format_valid(&s) { + self.already_save = false; self.update(Message::ChangeDelta(str_to_sec(&s))); } self.str_time = s; } Message::AddPoint => { + self.already_save = false; self.music.add_point(self.current_delta); } Message::RemovePoint => { + self.already_save = false; self.music.remove_point(self.current_delta); } Message::ClickedOnTimeLine(f) => { self.update(Message::ChangeDelta(f)); } Message::SlidePointLeft => { + self.already_save = false; self.music.slide_to_left(self.current_delta); self.music.fix_teta(self.current_delta); self.update_canvas_if_paused(); } Message::SlidePointRight => { + self.already_save = false; self.music.slide_to_right(self.current_delta); self.music.fix_teta(self.current_delta); self.update_canvas_if_paused(); @@ -211,7 +241,8 @@ impl MyApp { match mut_s.parse::() { Ok(val) => { if val >= 0. && val <= 360. { - self.update(Message::ChangeTeta(i, (val).to_radians())) + self.update(Message::ChangeTeta(i, (val).to_radians())); + self.already_save = false; } } Err(_) => {} @@ -224,7 +255,8 @@ impl MyApp { Ok(val) => { let val = (val * 10.).floor() / 10.; if val >= 1. && val < 1000. { - self.music.nb_sec_for_rev = val + self.music.nb_sec_for_rev = val; + self.already_save = false; } } Err(_) => {} @@ -246,184 +278,29 @@ impl MyApp { self.music.set_color(self.current_delta, i, color); self.music.set_color_picker(self.current_delta, i, false); self.can_unpaused = true; + self.already_save = false; } Message::None => {} + Message::GoToLoadView => { + if self.already_save { + self.paused = true; + self.file_name_to_creat = "Default File Name".to_string(); + self.show_warning_message_creat = false; + self.mode_file_load = true + } + } + Message::ForceToQuit => { + self.already_save = true; + } } } fn view(&self) -> iced::Element { - let mut i = 0; - let entries = self.all_sounds.clone(); - //Create all polygon options - let polygon_rows: Vec> = self - .music - .current_frame(self.current_delta) - .polygons - .iter() - .map(|polygon| { - let current_index = i; - let but = button(text("").size(20).center()).on_press(Message::SubmitColor(i)); - let c = column![ - row![ - text(&polygon.name).size(24), - button(text("").size(20)).on_press(Message::Remove(i)), - color_picker( - polygon.show_color_picker, - polygon.color, - but, - Message::CancelColor(i), - move |color| Message::ChooseColor(i, color) - ), - pick_list(entries.clone(), Some(&polygon.sound_name), move |s| { - Message::ChangeSound(current_index, s) - }) - .text_size(20), - ] - .spacing(20), - row![ - TextInput::new("90", &polygon.global_teta.to_degrees().floor().to_string()) - .on_input(move |new_value| Message::ChangeDegree( - current_index, - new_value - )) - .width(Length::FillPortion(1)), - row![ - slider(0.0..=2.0 * PI, polygon.global_teta, move |f| { - Message::ChangeTeta(current_index, f) - }) - .step(2. * PI / 10_000.) - .width(Length::FillPortion(9)) - ] - .padding(Padding::from(16)), - ] - .spacing(5), - ] - .spacing(10) - .into(); - i += 1; - c - }) - .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) - .collect(); - - let polygon_column = scrollable(Column::with_children(polygon_rows).spacing(24)); - - let menu_tpl_1 = |items| Menu::new(items).max_width(100.0).offset(15.0).spacing(5.0); - let save_menu = menu_tpl_1(vec![ - Item::new(button("Save").on_press(Message::Save)), - Item::new(button("Load").on_press(Message::Load)), - ]); - column![ - menu_bar!((text("File").size(20), save_menu)( - text("Shortcut").size(20), - menu_tpl_1(vec![Item::new("󰐊 SPACE"), Item::new("󰆓 CTRL+S")]) - )) - .draw_path(menu::DrawPath::Backdrop) - .spacing(20), - row!( - TextInput::new("Name File", &self.music.file_name) - .on_input(|new_value| Message::FileNameChanged(new_value)) - .width(Length::FillPortion(1)), - pick_list( - self.all_saves.clone(), - Some(&self.music.file_name), - move |s| Message::FileNameChanged(s), - ) - .width(Length::FillPortion(1)), - ), - row![ - container( - canvas(self.music.current_frame(self.current_delta)) - .height(Length::FillPortion(1)) - .width(Length::FillPortion(1)) - ), - column![ - text("Polygon options").size(26), - pick_list(all_options, Some("Choose polygon".to_string()), |s| { - Message::AddPolygon(s) - }) - .text_size(18), - polygon_column, - ] - .spacing(10) - .height(Length::FillPortion(1)) - .width(Length::FillPortion(2)), - ] - .height(Length::FillPortion(2)) - .spacing(20), - column![ - row![ - button(text(if self.paused { "󰐊" } else { "󰏤" }).size(28).center()) - .on_press(if self.can_unpaused { - Message::TogglePaused - } else { - Message::None - }) - .width(Length::FillPortion(1)), - row![ - TextInput::new("MM:SS:CS", &self.str_time) - .on_input(|new_value| Message::ChangeDeltaString(new_value)) - .size(28), - text("/").size(30), - TextInput::new("MM:SS:CS", &self.str_music_length) - .on_input(|new_value| Message::LengthChange(new_value)) - .size(28), - ] - .width(Length::FillPortion(10)), - TextInput::new("1.0", &format!("{:.1} sec/rev", &self.music.nb_sec_for_rev)) - .on_input(|new_value| Message::ChangeNbPerSec(new_value)) - .size(28) - .width(Length::FillPortion(2)), - button(text("").size(28).center()) - .on_press(Message::SlidePointLeft) - .width(Length::FillPortion(1)), - button(text("").size(28).center()) - .on_press(Message::AddPoint) - .width(Length::FillPortion(1)), - button(text("").size(28).center()) - .on_press(Message::SlidePointRight) - .width(Length::FillPortion(1)), - button(text("").size(28).center()) - .on_press(Message::RemovePoint) - .width(Length::FillPortion(1)), - ] - .spacing(20), - column![ - /* - slider(0.0..=self.music.length, self.current_delta, move |f| { - Message::ChangeDelta(f) - }) - .step(&self.music.length / 10_000.),*/ - canvas(&self.music) - .height(Length::FillPortion(1)) - .width(Length::FillPortion(1)) - ] - .spacing(0), - ] - .spacing(20) - .height(Length::FillPortion(1)) - .width(Length::FillPortion(1)), - ] - .spacing(25) - .padding(25) - .into() + if !self.mode_file_load { + music_view(self) + } else { + load_file_view(self) + } } fn subscription(&self) -> iced::Subscription { @@ -450,6 +327,15 @@ impl MyApp { }), Status::Ignored, ) => Some(Message::ChangeDelta(0.0)), + ( + Event::Keyboard(iced::keyboard::Event::KeyPressed { + key: Key::Character(c), + modifiers: Modifiers::CTRL, + .. + }), + Status::Ignored, + ) if c.as_ref() == "f" => Some(Message::ForceToQuit), + _ => None, }); if self.paused { @@ -483,7 +369,7 @@ fn load_path_sounds() -> Vec { fn load_path_saves() -> Vec { fs::create_dir_all("./saves").expect("fail to creat 'saves' !"); - fs::read_dir("./saves") + let mut saves: Vec = fs::read_dir("./saves") .unwrap() .filter_map(|res| res.ok()) .map(|e| { @@ -495,5 +381,7 @@ fn load_path_saves() -> Vec { .trim_end_matches(".pmx") .to_string() }) - .collect() + .collect(); + saves.sort(); + saves } diff --git a/src/message.rs b/src/message.rs index 4a5e200..7fbfd3f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -3,13 +3,16 @@ use iced::Color; #[derive(Debug, Clone)] pub enum Message { None, + CreatFile, + SetFileNameCreat(String), + GoToLoadView, + ForceToQuit, ChangeNbPerSec(String), Tick, AddPolygon(String), ChangeTeta(usize, f32), Remove(usize), ChangeSound(usize, String), - ToggleSavePanel, Save, Load, FileNameChanged(String), diff --git a/src/music.rs b/src/music.rs index f93a963..cba07ba 100644 --- a/src/music.rs +++ b/src/music.rs @@ -1,6 +1,6 @@ use crate::message::Message; -use crate::utils::string_to_polygon; use crate::polygon_draw::*; +use crate::utils::string_to_polygon; use serde::{Deserialize, Serialize}; use kira::{AudioManager, sound::static_sound::StaticSoundData}; @@ -70,7 +70,7 @@ impl Music { Music { poly_frame: vec![(0.0, PolygonFrame::default())], nb_sec_for_rev: 1.0, - file_name: "Default Name".to_string(), + file_name: "Default File Name".to_string(), length: 60.0, teta: 0., current_delta: 0.,