fonts and glowup

This commit is contained in:
2025-07-10 00:25:42 +02:00
parent 5fa8b88373
commit 7e97532442
15 changed files with 252 additions and 54 deletions

164
Cargo.lock generated
View File

@@ -121,6 +121,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]] [[package]]
name = "android_system_properties" name = "android_system_properties"
version = "0.1.5" version = "0.1.5"
@@ -352,7 +358,7 @@ dependencies = [
"bitflags 2.9.1", "bitflags 2.9.1",
"cexpr", "cexpr",
"clang-sys", "clang-sys",
"itertools", "itertools 0.13.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"regex", "regex",
@@ -533,6 +539,20 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]] [[package]]
name = "clang-sys" name = "clang-sys"
version = "1.8.1" version = "1.8.1"
@@ -1548,6 +1568,30 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "iana-time-zone"
version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core 0.61.2",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "iced" name = "iced"
version = "0.13.1" version = "0.13.1"
@@ -1562,6 +1606,23 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "iced_aw"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "582c517a94ce3205da98e9c10b26bb71aa36b7d7d084441d826dc912711d1bac"
dependencies = [
"cfg-if",
"chrono",
"getrandom 0.3.3",
"iced",
"iced_fonts 0.1.1",
"itertools 0.14.0",
"num-format",
"num-traits",
"web-time",
]
[[package]] [[package]]
name = "iced_core" name = "iced_core"
version = "0.13.2" version = "0.13.2"
@@ -1582,6 +1643,25 @@ dependencies = [
"web-time", "web-time",
] ]
[[package]]
name = "iced_fonts"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df7deb0800a850ee25c8a42559f72c0f249e577feb3aad37b9b65dc1e517e52a"
dependencies = [
"iced_core",
]
[[package]]
name = "iced_fonts"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7db9d45e87bc3ac22ff82e2d9dea9139f1c055137f1e0f39df3d68110fcee7a9"
dependencies = [
"iced_core",
"iced_widget",
]
[[package]] [[package]]
name = "iced_futures" name = "iced_futures"
version = "0.13.2" version = "0.13.2"
@@ -1757,6 +1837,15 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itertools"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.15" version = "1.0.15"
@@ -2176,6 +2265,16 @@ dependencies = [
"syn 2.0.101", "syn 2.0.101",
] ]
[[package]]
name = "num-format"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
dependencies = [
"arrayvec",
"itoa",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.19" version = "0.2.19"
@@ -2729,6 +2828,8 @@ name = "polygomusic"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"iced", "iced",
"iced_aw",
"iced_fonts 0.2.1",
"kira", "kira",
"regex", "regex",
"serde", "serde",
@@ -4170,10 +4271,51 @@ version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
dependencies = [ dependencies = [
"windows-result", "windows-result 0.1.2",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-core"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result 0.3.4",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
]
[[package]]
name = "windows-link"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]] [[package]]
name = "windows-result" name = "windows-result"
version = "0.1.2" version = "0.1.2"
@@ -4183,6 +4325,24 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.45.0" version = "0.45.0"

View File

@@ -10,3 +10,5 @@ tokio = {version = "1.45.1", features = ["time"]}
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.140" serde_json = "1.0.140"
regex = "1.11.1" regex = "1.11.1"
iced_aw = {version = "0.12.2", default-features = true}
iced_fonts = "0.2.1"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -8,30 +8,25 @@ mod message;
use message::Message; use message::Message;
mod utils; mod utils;
use utils::str_to_sec; use utils::{is_delta_format_valid, str_to_sec};
use std::fs; use std::fs;
use iced::Element; use iced::widget::{TextInput, column, text};
use iced::{Application, Element, Font, font};
use iced::{ use iced::{
Color, Length, Task, Theme, Color, Length, Task, Theme,
widget::{Column, button, canvas, container, pick_list, row, scrollable, slider}, widget::{Column, button, canvas, container, pick_list, row, scrollable, slider},
}; };
use iced::{
Font,
widget::{
TextInput, column, text,
text_input::{Icon, Side},
},
};
use regex::Regex;
use std::f32::consts::PI; use std::f32::consts::PI;
use std::time::Instant; use std::time::Instant;
use kira::{ use kira::{
AudioManager, AudioManagerSettings, DefaultBackend, sound::static_sound::StaticSoundData, AudioManager, AudioManagerSettings, DefaultBackend, sound::static_sound::StaticSoundData,
}; };
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; use crate::utils::delta_to_string;
fn main() -> iced::Result { fn main() -> iced::Result {
@@ -55,6 +50,8 @@ fn main() -> iced::Result {
}; };
iced::application("My App", MyApp::update, MyApp::view) iced::application("My App", MyApp::update, MyApp::view)
.theme(move |_| polytheme.clone()) .theme(move |_| polytheme.clone())
.font(FONT_BYTES)
.default_font(FONT)
.subscription(MyApp::subscription) .subscription(MyApp::subscription)
.run_with(MyApp::new) .run_with(MyApp::new)
} }
@@ -69,12 +66,16 @@ struct MyApp {
all_saves: Vec<String>, all_saves: Vec<String>,
current_delta: f32, current_delta: f32,
str_music_length: String, str_music_length: String,
str_time: String,
} }
impl MyApp { impl MyApp {
fn new() -> (Self, Task<Message>) { fn new() -> (Self, Task<Message>) {
let manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default()) let manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())
.expect("Error to load AudioManager"); .expect("Error to load AudioManager");
//let font_bytes = include_bytes!("../fonts/");
( (
Self { Self {
time_last_frame: Instant::now(), time_last_frame: Instant::now(),
@@ -86,6 +87,7 @@ impl MyApp {
music: Music::default(), music: Music::default(),
current_delta: 0.0, current_delta: 0.0,
str_music_length: "01:00:00".to_string(), str_music_length: "01:00:00".to_string(),
str_time: "00:00:00".to_string(),
}, },
Task::none(), Task::none(),
) )
@@ -112,6 +114,7 @@ impl MyApp {
self.music self.music
.apply_tick(self.current_delta, time_btw, &mut self.audio_manager); .apply_tick(self.current_delta, time_btw, &mut self.audio_manager);
self.time_last_frame = Instant::now(); self.time_last_frame = Instant::now();
self.str_time = delta_to_string(self.current_delta);
} }
} }
Message::Remove(i) => { Message::Remove(i) => {
@@ -148,27 +151,33 @@ impl MyApp {
} }
Message::ToggleSavePanel => self.show_save_panel = !self.show_save_panel, Message::ToggleSavePanel => self.show_save_panel = !self.show_save_panel,
Message::FileNameChanged(s) => self.music.file_name = s, Message::FileNameChanged(s) => self.music.file_name = s,
Message::LengthChange(s) => self.str_music_length = s, Message::LengthChange(s) => {
if is_delta_format_valid(&s) {
let sec = str_to_sec(&s);
if sec > 0. {
self.music.length = sec;
}
}
self.str_music_length = s;
}
Message::TogglePaused => { Message::TogglePaused => {
self.paused = !self.paused; self.paused = !self.paused;
if !self.paused { if !self.paused {
self.time_last_frame = Instant::now(); self.time_last_frame = Instant::now();
} }
} }
Message::SetMusicLength => {
if self.is_length_valid() {
self.music.length = str_to_sec(&self.str_music_length)
}
}
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 // update the red dot on canvas
if self.paused { self.update_canvas_if_paused();
self.update(Message::TogglePaused); }
self.update(Message::Tick); Message::ChangeDeltaString(s) => {
self.update(Message::TogglePaused); if is_delta_format_valid(&s) {
self.update(Message::ChangeDelta(str_to_sec(&s)));
} }
self.str_time = s;
} }
Message::AddPoint => { Message::AddPoint => {
self.music.add_point(self.current_delta); self.music.add_point(self.current_delta);
@@ -179,6 +188,16 @@ impl MyApp {
Message::ClickedOnTimeLine(f) => { Message::ClickedOnTimeLine(f) => {
self.update(Message::ChangeDelta(f)); self.update(Message::ChangeDelta(f));
} }
Message::SlidePointLeft => {
self.music.slide_to_left(self.current_delta);
self.music.fix_teta(self.current_delta);
self.update_canvas_if_paused();
}
Message::SlidePointRight => {
self.music.slide_to_right(self.current_delta);
self.music.fix_teta(self.current_delta);
self.update_canvas_if_paused();
}
} }
} }
@@ -202,7 +221,7 @@ impl MyApp {
i += 1; i += 1;
column![ column![
row![ row![
text(&polygon.name), text(&polygon.name).font(FONT),
button("Remove").on_press(Message::Remove(i)), button("Remove").on_press(Message::Remove(i)),
pick_list( pick_list(
["Black", "Blue", "Green", "Pink", "Yellow", "Cyan"] ["Black", "Blue", "Green", "Pink", "Yellow", "Cyan"]
@@ -270,24 +289,9 @@ 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(&self.music.file_name).size(32.0), text("Polymusic").size(32.0),
row(save_panel).spacing(20), row(save_panel).spacing(20),
row![ 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), text(txt_nb_rev).size(20),
button("Increment").on_press(Message::ButtonPressedIncrement), button("Increment").on_press(Message::ButtonPressedIncrement),
button("Decrement").on_press(Message::ButtonPressedDecrement), button("Decrement").on_press(Message::ButtonPressedDecrement),
@@ -314,15 +318,19 @@ impl MyApp {
.spacing(20), .spacing(20),
column![ column![
row![ row![
button("Toggle Play").on_press(Message::TogglePaused), button(text(if self.paused { "󰐊" } else { "󰏤" }).size(28))
text(format!( .on_press(Message::TogglePaused),
"{}/{}", TextInput::new("MM:SS:CS", &self.str_time)
delta_to_string(self.current_delta), .on_input(|new_value| Message::ChangeDeltaString(new_value))
delta_to_string(self.music.length) .size(28),
)) text("/").size(30),
.size(20.0), TextInput::new("MM:SS:CS", &self.str_music_length)
button("Add Point").on_press(Message::AddPoint), .on_input(|new_value| Message::LengthChange(new_value))
button("Remove Point").on_press(Message::RemovePoint), .size(28),
button(text("").size(28)).on_press(Message::AddPoint),
button(text("").size(28)).on_press(Message::RemovePoint),
button(text("").size(28)).on_press(Message::SlidePointLeft),
button(text("").size(28)).on_press(Message::SlidePointRight),
] ]
.spacing(20), .spacing(20),
column![ column![
@@ -346,16 +354,20 @@ impl MyApp {
.into() .into()
} }
fn is_length_valid(&self) -> bool {
let re = Regex::new(r"^\d{2}:\d{2}:\d{2}$").unwrap();
re.is_match(self.str_music_length.as_str())
}
fn subscription(&self) -> iced::Subscription<Message> { fn subscription(&self) -> iced::Subscription<Message> {
iced::Subscription::batch([ iced::Subscription::batch([
//window::events().map(|(_id, event)| Message::WindowEvent(event)), //window::events().map(|(_id, event)| Message::WindowEvent(event)),
iced::time::every(std::time::Duration::from_millis(16)).map(|_| Message::Tick), iced::time::every(std::time::Duration::from_millis(16)).map(|_| Message::Tick),
]) ])
} }
fn update_canvas_if_paused(&mut self) {
if self.paused {
self.update(Message::TogglePaused);
self.update(Message::Tick);
self.update(Message::TogglePaused);
}
}
} }
fn load_path_sounds() -> Vec<String> { fn load_path_sounds() -> Vec<String> {

View File

@@ -13,10 +13,12 @@ pub enum Message {
Load, Load,
FileNameChanged(String), FileNameChanged(String),
TogglePaused, TogglePaused,
SetMusicLength,
LengthChange(String), LengthChange(String),
ChangeDelta(f32), ChangeDelta(f32),
AddPoint, AddPoint,
RemovePoint, RemovePoint,
ClickedOnTimeLine(f32), ClickedOnTimeLine(f32),
ChangeDeltaString(String),
SlidePointLeft,
SlidePointRight,
} }

View File

@@ -18,6 +18,7 @@ use iced::widget::canvas::Stroke;
use iced::widget::canvas::Style; use iced::widget::canvas::Style;
use iced::{Color, Rectangle, Renderer, Theme}; use iced::{Color, Rectangle, Renderer, Theme};
use std::f32::consts::PI; use std::f32::consts::PI;
use std::mem::swap;
use std::time::Duration; use std::time::Duration;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Music { pub struct Music {
@@ -156,6 +157,21 @@ impl Music {
pub fn remove_polygon(&mut self, delta: f32, i: usize) { pub fn remove_polygon(&mut self, delta: f32, i: usize) {
self.find_poly_frame(delta).polygons.remove(i); self.find_poly_frame(delta).polygons.remove(i);
} }
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);
}
}
} }
impl canvas::Program<Message> for Music { impl canvas::Program<Message> for Music {
// No internal state // No internal state
@@ -171,7 +187,7 @@ impl canvas::Program<Message> for Music {
) -> Vec<canvas::Geometry> { ) -> Vec<canvas::Geometry> {
let mut geo_small_frame: Vec<Geometry> = vec![]; let mut geo_small_frame: Vec<Geometry> = vec![];
let mut geo_cursor: Vec<Geometry> = vec![]; let mut geo_cursor: Vec<Geometry> = vec![];
let mut frame = canvas::Frame::new(renderer, bounds.size()); let frame = canvas::Frame::new(renderer, bounds.size());
let mut toggle_color = true; let mut toggle_color = true;
let padding = 8.; let padding = 8.;
let w = bounds.width - (padding * 2.); let w = bounds.width - (padding * 2.);

View File

@@ -1,6 +1,12 @@
use crate::Polygon; use crate::Polygon;
use iced::Color; use iced::Color;
use kira::sound::static_sound::StaticSoundData; use kira::sound::static_sound::StaticSoundData;
use regex::Regex;
pub fn is_delta_format_valid(str: &str) -> bool {
let re = Regex::new(r"^\d{1,2}:\d{1,2}:\d{1,2}$").unwrap();
re.is_match(str)
}
pub fn string_to_color<S: AsRef<str>>(s: S) -> Color { pub fn string_to_color<S: AsRef<str>>(s: S) -> Color {
match s.as_ref() { match s.as_ref() {
"Green" => Color::from_rgb(0.0, 1.0, 0.0), "Green" => Color::from_rgb(0.0, 1.0, 0.0),