From 9c34ebbff550079920498fb5eddd338a5036534d Mon Sep 17 00:00:00 2001 From: csd4ni3l Date: Thu, 22 Jan 2026 17:51:32 +0100 Subject: [PATCH] move cargo config to the right place, add audio playing (SoundSystem), add better scaling, fix centralpanel initiated before sidepanel, make everything based on height, add file scrolling --- .cargo/config.toml | 3 + Cargo.toml | 4 -- src/main.rs | 134 +++++++++++++++++++++++++++++++++------------ 3 files changed, 102 insertions(+), 39 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..db3c514 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[target.'cfg(target_os = "linux")'] +linker = "clang" +rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"] diff --git a/Cargo.toml b/Cargo.toml index 81e6877..50a069d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,3 @@ features = [ "x11", "bevy_winit", ] - -[target.'cfg(target_os = "linux")'] -linker = "clang" -rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"] diff --git a/src/main.rs b/src/main.rs index 41c2948..67e54b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,26 +3,47 @@ use bevy::{ prelude::*, }; -use std::collections::HashMap; +use std::{collections::HashMap, fs::File, io::BufReader, path::Path}; use serde::{Deserialize, Serialize}; use bevy_egui::{ EguiContextSettings, EguiContexts, EguiPlugin, EguiPrimaryContextPass, EguiStartupSet, egui, }; + +use rodio::{Decoder, OutputStream, OutputStreamBuilder, Sink, mixer::Mixer}; + #[derive(Serialize, Deserialize)] struct JSONData { tabs: Vec, } +struct PlayingSound { + file_path: String, + start_time: f32, +} + +struct SoundSystem { + sink: Sink, + paused: bool +} + #[derive(Resource)] struct AppState { loaded_files: HashMap>, json_data: JSONData, - current_directory: String + current_directory: String, + currently_playing: Vec, + sound_system: SoundSystem } +use std::time::{SystemTime, UNIX_EPOCH}; + fn main() { + let stream_handle = OutputStreamBuilder::open_default_stream().expect("Unable to open default audio device"); + let mixer = stream_handle.mixer(); + let sink = Sink::connect_new(&mixer); + App::new() .insert_resource(ClearColor(Color::BLACK)) .add_plugins( @@ -45,7 +66,12 @@ fn main() { .insert_resource(AppState { loaded_files: HashMap::new(), json_data: JSONData { tabs: Vec::new() }, - current_directory: String::new() + current_directory: String::new(), + currently_playing: Vec::new(), + sound_system: SoundSystem { + sink, + paused: false + } }) .add_systems( PreStartup, @@ -104,21 +130,26 @@ fn setup_camera_system(mut commands: Commands) { } fn update_ui_scale_factor_system( - keyboard_input: Res>, - mut toggle_scale_factor: Local>, egui_context: Single<(&mut EguiContextSettings, &Camera)>, ) { let (mut egui_settings, camera) = egui_context.into_inner(); - if keyboard_input.just_pressed(KeyCode::Slash) || toggle_scale_factor.is_none() { - *toggle_scale_factor = Some(!toggle_scale_factor.unwrap_or(true)); + egui_settings.scale_factor = 1.5 / camera.target_scaling_factor().unwrap_or(1.5); +} - let scale_factor = if toggle_scale_factor.unwrap() { - 1.0 - } else { - 1.0 / camera.target_scaling_factor().unwrap_or(1.0) - }; - egui_settings.scale_factor = scale_factor; - } +fn play_sound(file_path: String, app_state: &mut AppState) { + let file = BufReader::new(File::open(&file_path).unwrap()); + let src = Decoder::new(file).unwrap(); + app_state.sound_system.sink.append(src); + + let start = SystemTime::now(); + let since_the_epoch = start + .duration_since(UNIX_EPOCH) + .expect("time should go forward"); + + app_state.currently_playing.push(PlayingSound { + file_path: file_path.clone(), + start_time: since_the_epoch.as_secs_f32(), + }) } fn ui_system(mut contexts: EguiContexts, mut app_state: ResMut) -> Result { @@ -128,32 +159,16 @@ fn ui_system(mut contexts: EguiContexts, mut app_state: ResMut) -> Res ui.heading("csd4ni3l Soundboard"); }); - egui::CentralPanel::default().show(ctx, |ui| { - ui.label("The app!"); - if app_state.current_directory.chars().count() > 0 { - if let Some(files) = app_state.loaded_files.get(&app_state.current_directory) { - for element in files { - if let Some(filename) = element.split("/").collect::>().last() { - if ui.add_sized( - [ui.available_width(), 40.0], - egui::Button::new(*filename), - ).clicked() { - println!("{:?}", filename); - } - } - } - } - } - }); - egui::SidePanel::right("tools").show(ctx, |ui| { ui.heading("Tools"); ui.separator(); + let available_height = ui.available_height(); + if ui .add_sized( - [ui.available_width(), 40.0], + [ui.available_width(), available_height / 15.0], egui::Button::new("Add folder"), ) .clicked() @@ -177,7 +192,7 @@ fn ui_system(mut contexts: EguiContexts, mut app_state: ResMut) -> Res if ui .add_sized( - [ui.available_width(), 40.0], + [ui.available_width(), available_height / 15.0], egui::Button::new("Reload content"), ) .clicked() @@ -188,7 +203,7 @@ fn ui_system(mut contexts: EguiContexts, mut app_state: ResMut) -> Res if ui .add_sized( - [ui.available_width(), 40.0], + [ui.available_width(), available_height / 15.0], egui::Button::new("Youtube downloader"), ) .clicked() @@ -197,5 +212,54 @@ fn ui_system(mut contexts: EguiContexts, mut app_state: ResMut) -> Res } }); + egui::CentralPanel::default().show(ctx, |ui| { + let available_height = ui.available_height(); + + ui.horizontal(|ui| { + let available_width = ui.available_width(); + let current_directories = app_state.loaded_files.keys().cloned().collect::>(); + for directory in current_directories.clone() { + if ui + .add_sized( + [available_width / current_directories.len() as f32, available_height / 15.0], + egui::Button::new(&directory), + ) + .clicked() + { + app_state.current_directory = directory; + }; + } + }); + ui.add_space(available_height / 50.0); + ui.with_layout(egui::Layout::top_down(egui::Align::Center), |ui| { + ui.label(egui::RichText::new(format!("The current directory is {}", app_state.current_directory)).font(egui::FontId::proportional(20.0))); + }); + ui.add_space(available_height / 50.0); + if app_state.current_directory.chars().count() > 0 { + let files = app_state + .loaded_files + .get(&app_state.current_directory) + .cloned() + .unwrap_or_default(); + + egui::ScrollArea::vertical().show(ui, |ui| { + for element in files { + if let Some(filename) = element.split("/").collect::>().last() { + if ui.add_sized( + [ui.available_width(), available_height / 15.0], + egui::Button::new(*filename), + ).clicked() { + let path = Path::new(&app_state.current_directory) + .join(filename) + .to_string_lossy() + .to_string(); + play_sound(path, &mut app_state); + } + } + } + }); + } + }); + Ok(()) } \ No newline at end of file