From cd41400b6f00bf12abd9476f374ec8300e8ea849 Mon Sep 17 00:00:00 2001 From: Max Bradbury Date: Tue, 27 Apr 2021 10:16:25 +0100 Subject: [PATCH] restructure into modules --- src/config.rs | 59 +++++++++++++ src/main.rs | 232 ++------------------------------------------------ src/ui_gtk.rs | 172 +++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+), 225 deletions(-) create mode 100644 src/config.rs create mode 100644 src/ui_gtk.rs diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..bb1e0c5 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,59 @@ +use std::fs::File; +use std::io::{Write, Read}; + +use serde_derive::{Serialize, Deserialize}; + +#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] +pub(crate) struct Config { + pub(crate) position: (i32, i32), + pub(crate) size: (i32, i32), +} + +pub(crate) fn save_config(config: Config) { + let mut config_path = dirs::config_dir() + .expect("Couldn't find user config directory"); + + config_path.push("ruin"); + config_path.push("lull"); + + if !config_path.exists() { + std::fs::create_dir_all(&config_path) + .expect("Couldn't create lull config directory"); + } + + let toml = toml::to_string(&config) + .expect("Couldn't convert config to toml"); + + config_path.push("lull.toml"); + + let mut config_file = File::create(config_path) + .expect("Couldn't create config file"); + + config_file.write(&toml.into_bytes()) + .expect("Couldn't write config file"); +} + +pub(crate) fn load_config() -> Option { + let mut config_path = dirs::config_dir() + .expect("Couldn't find user config directory"); + + config_path.push("ruin"); + config_path.push("lull"); + config_path.push("lull.toml"); + + let file = File::open(config_path); + + if file.is_err() { + return None; + } + + let mut toml = String::new(); + + file.unwrap().read_to_string(&mut toml) + .expect("Couldn't read config file"); + + let config = toml::from_str(&toml) + .expect("Couldn't parse config"); + + Some(config) +} diff --git a/src/main.rs b/src/main.rs index bfc04a5..6f20850 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,72 +1,9 @@ #![windows_subsystem = "windows"] -use gio::prelude::*; -use gtk::prelude::*; -use gtk::Orientation; -use rodio::{Sink, Source}; -use serde_derive::{Serialize, Deserialize}; -use std::env::args; -use std::fs::File; -use std::io::{BufReader, Write, Read}; +mod config; +mod ui_gtk; + use std::path::PathBuf; -use std::process::Command; - -const SPACING: i32 = 16; - -#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] -struct Config { - position: (i32, i32), - size: (i32, i32), -} - -fn save_config(config: Config) { - let mut config_path = dirs::config_dir() - .expect("Couldn't find user config directory"); - - config_path.push("ruin"); - config_path.push("lull"); - - if !config_path.exists() { - std::fs::create_dir_all(&config_path) - .expect("Couldn't create lull config directory"); - } - - let toml = toml::to_string(&config) - .expect("Couldn't convert config to toml"); - - config_path.push("lull.toml"); - - let mut config_file = File::create(config_path) - .expect("Couldn't create config file"); - - config_file.write(&toml.into_bytes()) - .expect("Couldn't write config file"); -} - -fn load_config() -> Option { - let mut config_path = dirs::config_dir() - .expect("Couldn't find user config directory"); - - config_path.push("ruin"); - config_path.push("lull"); - config_path.push("lull.toml"); - - let file = File::open(config_path); - - if file.is_err() { - return None; - } - - let mut toml = String::new(); - - file.unwrap().read_to_string(&mut toml) - .expect("Couldn't read config file"); - - let config = toml::from_str(&toml) - .expect("Couldn't parse config"); - - Some(config) -} #[cfg(target_os = "windows")] fn file_manager() -> &'static str { @@ -78,21 +15,6 @@ fn file_manager() -> &'static str { "xdg-open" } -fn error_popup(message: &str) { - let popup = gtk::Window::new(gtk::WindowType::Toplevel); - popup.set_title("error"); - popup.set_border_width(SPACING as u32); - popup.set_position(gtk::WindowPosition::Center); - popup.set_default_size(256, 64); - popup.set_type_hint(gdk::WindowTypeHint::Dialog); - popup.set_resizable(false); - - let message = gtk::Label::new(Some(message)); - popup.add(&message); - - popup.show_all(); -} - fn get_sounds_dir() -> PathBuf { let mut data_dir = dirs::data_dir().expect("Couldn't find user data directory"); @@ -100,154 +22,14 @@ fn get_sounds_dir() -> PathBuf { data_dir.push("lull"); if !data_dir.exists() { - std::fs::create_dir_all(&data_dir).expect("Couldn't create lull data directory"); + std::fs::create_dir_all(&data_dir) + .expect("Couldn't create lull sounds directory"); } data_dir } -fn build_ui(application: >k::Application) { - let window = gtk::ApplicationWindow::new(application); - - window.set_title("lull"); - window.set_border_width(SPACING as u32); - window.set_position(gtk::WindowPosition::Center); - window.set_default_size(256, 128); - - if let Some(config) = load_config() { - window.move_(config.position.0, config.position.1); - window.resize(config.size.0, config.size.1); - } - - let button_manage_sounds = gtk::Button::with_label("open sounds folder"); - - button_manage_sounds.connect_clicked(|_| { - let mut file_manager = Command::new(file_manager()); - file_manager.arg(get_sounds_dir()); - file_manager.output().unwrap(); - }); - - let sounds_manage = gtk::Box::new(Orientation::Vertical, SPACING); - let columns = gtk::Box::new(Orientation::Horizontal, SPACING); - let column_labels = gtk::Box::new(Orientation::Vertical, SPACING); - let column_sliders = gtk::Box::new(Orientation::Vertical, SPACING); - - columns.set_homogeneous(false); - column_labels.set_homogeneous(true); - column_sliders.set_homogeneous(true); - column_labels.set_property_expand(false); - column_sliders.set_property_expand(true); - column_sliders.set_property_width_request(128); - - window.add(&sounds_manage); - sounds_manage.add(&columns); - sounds_manage.add(&button_manage_sounds); - columns.add(&column_labels); - columns.add(&column_sliders); - - let device = rodio::default_output_device().unwrap(); - - let mut paths = std::fs::read_dir(get_sounds_dir()) - .expect("Couldn't read lull sounds directory") - .map(|res| res.map(|e| e.path())) - .collect::, std::io::Error>>() - .expect("Couldn't read files from lull sounds directory"); - - paths.sort(); - - for path in paths { - let name = path.file_stem().unwrap().to_str().unwrap(); - let extension = path.extension().unwrap().to_str().unwrap(); - - // on Windows the data dir and config dir are the same, - // so avoid parsing the config file as an audio file - if extension == "toml" { - continue; - } - - let file = File::open(&path) - .expect("Couldn't open audio file"); - - let source = rodio::Decoder::new( - BufReader::new(file) - ); - - if source.is_err() { - error_popup(&format!( - "Couldn't parse file {}. \n{}.", - path.to_str().unwrap(), - source.err().unwrap() - )); - continue; - } - - let source = source.unwrap().repeat_infinite(); - - let sink = Sink::new(&device); - sink.append(source); - sink.pause(); - - let label = gtk::Label::new(Some(name)); - label.set_halign(gtk::Align::End); - column_labels.add(&label); - - let adjustment = gtk::Adjustment::new( - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0 - ); - - let slider = gtk::Scale::new( - Orientation::Horizontal, - Some(&adjustment) - ); - - slider.set_draw_value(false); - - slider.connect_value_changed(move |scale| { - let volume = scale.get_value(); - - if volume == 0. { - sink.pause(); - } else { - sink.play(); - sink.set_volume(volume as f32); - } - }); - - column_sliders.add(&slider); - } - - window.show_all(); - - window.connect_delete_event(|window, _event| { - save_config(Config { - position: window.get_position(), - size: window.get_size() - }); - - Inhibit(false) - }); -} - +//#[cfg(not(target_os = "windows"))] fn main() { - #[cfg(target_os = "windows")] { - // instantiate rodio before gtk and don't do anything with it - // this is silly but it's the easiest way to prevent cpal crashing on windows - rodio::default_output_device().unwrap(); - } - - let application = gtk::Application::new( - Some("dev.tinybird.max.lull"), - Default::default() - ).expect("Initialisation failed..."); - - application.connect_activate(|app| { - build_ui(app); - }); - - application.run(&args().collect::>()); + ui_gtk::instantiate(); } diff --git a/src/ui_gtk.rs b/src/ui_gtk.rs new file mode 100644 index 0000000..2c13a9a --- /dev/null +++ b/src/ui_gtk.rs @@ -0,0 +1,172 @@ +use std::env::args; +use std::fs::File; +use std::io::{BufReader}; +use std::process::Command; + +use gio::prelude::*; +use gtk::prelude::*; +use gtk::Orientation; +use rodio::{Sink, Source}; + +const SPACING: i32 = 16; + +fn error_popup(message: &str) { + let popup = gtk::Window::new(gtk::WindowType::Toplevel); + popup.set_title("error"); + popup.set_border_width(SPACING as u32); + popup.set_position(gtk::WindowPosition::Center); + popup.set_default_size(256, 64); + popup.set_type_hint(gdk::WindowTypeHint::Dialog); + popup.set_resizable(false); + + let message = gtk::Label::new(Some(message)); + popup.add(&message); + + popup.show_all(); +} + +fn build_ui(application: >k::Application) { + let window = gtk::ApplicationWindow::new(application); + + window.set_title("lull"); + window.set_border_width(SPACING as u32); + window.set_position(gtk::WindowPosition::Center); + window.set_default_size(256, 128); + + if let Some(config) = crate::config::load_config() { + window.move_(config.position.0, config.position.1); + window.resize(config.size.0, config.size.1); + } + + let button_manage_sounds = gtk::Button::with_label("open sounds folder"); + + button_manage_sounds.connect_clicked(|_| { + let mut file_manager = Command::new(crate::file_manager()); + file_manager.arg(crate::get_sounds_dir()); + file_manager.output().unwrap(); + }); + + let sounds_manage = gtk::Box::new(Orientation::Vertical, SPACING); + let columns = gtk::Box::new(Orientation::Horizontal, SPACING); + let column_labels = gtk::Box::new(Orientation::Vertical, SPACING); + let column_sliders = gtk::Box::new(Orientation::Vertical, SPACING); + + columns.set_homogeneous(false); + column_labels.set_homogeneous(true); + column_sliders.set_homogeneous(true); + column_labels.set_property_expand(false); + column_sliders.set_property_expand(true); + column_sliders.set_property_width_request(128); + + window.add(&sounds_manage); + sounds_manage.add(&columns); + sounds_manage.add(&button_manage_sounds); + columns.add(&column_labels); + columns.add(&column_sliders); + + let device = rodio::default_output_device().unwrap(); + + let mut paths = std::fs::read_dir(crate::get_sounds_dir()) + .expect("Couldn't read lull sounds directory") + .map(|res| res.map(|e| e.path())) + .collect::, std::io::Error>>() + .expect("Couldn't read files from lull sounds directory"); + + paths.sort(); + + for path in paths { + let name = path.file_stem().unwrap().to_str().unwrap(); + let extension = path.extension().unwrap().to_str().unwrap(); + + // on Windows the data dir and config dir are the same, + // so avoid parsing the config file as an audio file + if extension == "toml" { + continue; + } + + let file = File::open(&path) + .expect("Couldn't open audio file"); + + let source = rodio::Decoder::new( + BufReader::new(file) + ); + + if source.is_err() { + error_popup(&format!( + "Couldn't parse file {}. \n{}.", + path.to_str().unwrap(), + source.err().unwrap() + )); + continue; + } + + let source = source.unwrap().repeat_infinite(); + + let sink = Sink::new(&device); + sink.append(source); + sink.pause(); + + let label = gtk::Label::new(Some(name)); + label.set_halign(gtk::Align::End); + column_labels.add(&label); + + let adjustment = gtk::Adjustment::new( + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0 + ); + + let slider = gtk::Scale::new( + Orientation::Horizontal, + Some(&adjustment) + ); + + slider.set_draw_value(false); + + slider.connect_value_changed(move |scale| { + let volume = scale.get_value(); + + if volume == 0. { + sink.pause(); + } else { + sink.play(); + sink.set_volume(volume as f32); + } + }); + + column_sliders.add(&slider); + } + + window.show_all(); + + window.connect_delete_event(|window, _event| { + crate::config::save_config(crate::config::Config { + position: window.get_position(), + size: window.get_size() + }); + + Inhibit(false) + }); +} + +pub(crate) fn instantiate() { + #[cfg(target_os = "windows")] { + // instantiate rodio before gtk and don't do anything with it + // this is silly but it's the easiest way to prevent cpal crashing on windows + rodio::default_output_device().unwrap(); + } + + let application = gtk::Application::new( + Some("dev.tinybird.max.lull"), + Default::default() + ).expect("Initialisation failed..."); + + application.connect_activate(|app| { + build_ui(app); + }); + + application.run(&args().collect::>()); +}