diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..a24bc2b --- /dev/null +++ b/icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/config.rs b/src/config.rs index 3451846..a14f0f3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,5 @@ -use std::path::Path; - use clap::{ArgEnum, Parser}; +use fltk::dialog; use fltk_theme::ThemeType; use serde::{Deserialize, Serialize}; @@ -100,10 +99,27 @@ impl ConfigFile { let config = Self::default(); if let Err(_) = std::fs::write(&conf, serde_json::to_string(&config).unwrap()) { + dialog::message_default("Can't write config!"); eprintln!("Can't write config!"); } config } + + pub(crate) fn save(&self) { + let conf = match dirs::config_dir() { + Some(path) => path.join("post_maker.config"), + None => std::env::current_exe() + .unwrap() + .parent() + .unwrap() + .join("post_maker.config"), + }; + + if let Err(_) = std::fs::write(&conf, serde_json::to_string(self).unwrap()) { + dialog::message_default("Can't write config!"); + eprintln!("Can't write config!"); + } + } } pub(crate) fn config() -> Args { diff --git a/src/config_window.rs b/src/config_window.rs new file mode 100644 index 0000000..1fad536 --- /dev/null +++ b/src/config_window.rs @@ -0,0 +1,278 @@ +use std::{cell::RefCell, rc::Rc}; + +use fltk::{ + app, + button::Button, + dialog::{self, FileDialogOptions, NativeFileChooser}, + enums::{Align, Font}, + frame::Frame, + group::Flex, + image::SvgImage, + misc::Spinner, + output::Output, + prelude::*, + valuator::ValueInput, + window::Window, +}; + +use crate::{config::ConfigFile, globals}; + +pub(crate) struct ConfigWindow { + pub(crate) win: Window, + pub(crate) quote_font_ttf: Output, + pub(crate) quote_font_ttf_browse: Button, + pub(crate) tag_font_ttf: Output, + pub(crate) tag_font_ttf_browse: Button, + pub(crate) quote_font_ratio: ValueInput, + pub(crate) tag_font_ratio: ValueInput, + pub(crate) layer_red: Spinner, + pub(crate) layer_green: Spinner, + pub(crate) layer_blue: Spinner, + pub(crate) layer_alpha: Spinner, + pub(crate) defaults_btn: Button, + pub(crate) save_btn: Button, + pub(crate) cancel_btn: Button, + did_save: Rc>, +} + +impl ConfigWindow { + pub(crate) fn new() -> Self { + let mut win = Window::new(0, 0, 500, 300, "Config").center_screen(); + if let Ok(image) = SvgImage::from_data(&globals::ICON) { + win.set_icon(Some(image)); + } + + let mut col = Flex::default().with_size(490, 290).with_pos(5, 5).column(); + + let mut quote_font_ttf_grp = Flex::default().row(); + quote_font_ttf_grp.set_size( + &Frame::default() + .with_label("Font for quote (ttf)") + .with_align(Align::Right | Align::Inside), + 160, + ); + let quote_font_ttf = Output::default(); + let quote_font_ttf_browse = Button::default().with_label("Pick"); + quote_font_ttf_grp.set_size("e_font_ttf_browse, 50); + quote_font_ttf_grp.end(); + col.set_size("e_font_ttf_grp, 30); + + let mut tag_font_ttf_grp = Flex::default().row(); + tag_font_ttf_grp.set_size( + &Frame::default() + .with_label("Font for tag (ttf)") + .with_align(Align::Right | Align::Inside), + 160, + ); + let tag_font_ttf = Output::default(); + let tag_font_ttf_browse = Button::default().with_label("Pick"); + tag_font_ttf_grp.set_size(&tag_font_ttf_browse, 50); + tag_font_ttf_grp.end(); + col.set_size(&tag_font_ttf_grp, 30); + + let mut quote_font_ratio_grp = Flex::default().row(); + quote_font_ratio_grp.set_size( + &Frame::default() + .with_label("Quote text size ratio") + .with_align(Align::Right | Align::Inside), + 160, + ); + let quote_font_ratio = ValueInput::default(); + quote_font_ratio_grp.end(); + col.set_size("e_font_ratio_grp, 30); + + let mut grp = Flex::default().row(); + grp.set_size(&Frame::default(), 160); + let mut hint = Frame::default() + .with_label("Font size in image of resolution 4000x5000") + .with_align(Align::Left | Align::Inside); + hint.set_label_font(Font::CourierItalic); + hint.set_label_size(12); + grp.end(); + col.set_size(&grp, 13); + + let mut tag_font_ratio_grp = Flex::default().row(); + tag_font_ratio_grp.set_size( + &Frame::default() + .with_label("Tag text size ratio") + .with_align(Align::Right | Align::Inside), + 160, + ); + let tag_font_ratio = ValueInput::default(); + tag_font_ratio_grp.end(); + col.set_size(&tag_font_ratio_grp, 30); + + let mut grp = Flex::default().row(); + grp.set_size(&Frame::default(), 160); + let mut hint = Frame::default() + .with_label("Font size in image of resolution 4000x5000") + .with_align(Align::Left | Align::Inside); + hint.set_label_font(Font::CourierItalic); + hint.set_label_size(12); + grp.end(); + col.set_size(&grp, 13); + + col.set_size( + &Frame::default().with_label("Default colour shader to use with new images:"), + 30, + ); + + let mut darklayer_grp = Flex::default().row(); + darklayer_grp.set_pad(2); + darklayer_grp.set_size(&Frame::default().with_label("Red"), 30); + let mut layer_red = Spinner::default(); + layer_red.set_range(0.0, 255.0); + // darklayer_flex.set_size(&layer_red, 50); + darklayer_grp.set_size(&Frame::default().with_label("Green"), 40); + let mut layer_green = Spinner::default(); + layer_green.set_range(0.0, 255.0); + // darklayer_flex.set_size(&layer_green, 50); + darklayer_grp.set_size(&Frame::default().with_label("Blue"), 30); + let mut layer_blue = Spinner::default(); + layer_blue.set_range(0.0, 255.0); + // darklayer_flex.set_size(&layer_blue, 50); + darklayer_grp.set_size(&Frame::default().with_label("Alpha"), 40); + let mut layer_alpha = Spinner::default(); + layer_alpha.set_range(0.0, 255.0); + // darklayer_flex.set_size(&layer_alpha, 50); + darklayer_grp.end(); + col.set_size(&darklayer_grp, 30); + + Frame::default(); + + let mut panel_grp = Flex::default().row(); + Frame::default(); + let defaults_btn = Button::default().with_label("Defaults"); + let save_btn = Button::default().with_label("Save"); + let cancel_btn = Button::default().with_label("Cancel"); + panel_grp.set_size(&defaults_btn, 100); + panel_grp.set_size(&save_btn, 100); + panel_grp.set_size(&cancel_btn, 100); + panel_grp.end(); + + col.set_size(&panel_grp, 30); + + col.end(); + win.end(); + win.make_modal(true); + win.make_resizable(true); + + let mut config_window = Self { + win, + quote_font_ttf, + quote_font_ttf_browse, + tag_font_ttf, + tag_font_ttf_browse, + quote_font_ratio, + tag_font_ratio, + layer_red, + layer_green, + layer_blue, + layer_alpha, + defaults_btn, + save_btn, + cancel_btn, + did_save: Rc::new(RefCell::new(false)), + }; + config_window.event(); + + config_window + } + + pub(crate) fn show(&mut self) -> bool { + let glob = globals::CONFIG.read().unwrap(); + self.quote_font_ttf.set_value(glob.quote_font_ttf.as_str()); + self.tag_font_ttf.set_value(glob.tag_font_ttf.as_str()); + self.quote_font_ratio.set_value(glob.quote_font_ratio); + self.tag_font_ratio.set_value(glob.tag_font_ratio); + self.layer_red.set_value(glob.color_layer[0] as f64); + self.layer_green.set_value(glob.color_layer[1] as f64); + self.layer_blue.set_value(glob.color_layer[2] as f64); + self.layer_alpha.set_value(glob.color_layer[3] as f64); + *self.did_save.borrow_mut() = false; + drop(glob); + self.win.show(); + while self.win.shown() { + app::wait(); + } + *self.did_save.borrow() + } + + fn event(&mut self) { + let mut quote_font_ttf = self.quote_font_ttf.clone(); + self.quote_font_ttf_browse.set_callback(move |_| { + let mut chooser = NativeFileChooser::new(fltk::dialog::FileDialogType::BrowseFile); + chooser.set_option(FileDialogOptions::UseFilterExt); + chooser.set_filter("*.ttf"); + chooser.show(); + let path = chooser.filename(); + quote_font_ttf.set_value(path.to_str().unwrap()); + }); + + let mut tag_font_ttf = self.tag_font_ttf.clone(); + self.tag_font_ttf_browse.set_callback(move |_| { + let mut chooser = NativeFileChooser::new(fltk::dialog::FileDialogType::BrowseFile); + chooser.set_option(FileDialogOptions::UseFilterExt); + chooser.set_filter("*.ttf"); + chooser.show(); + let path = chooser.filename(); + tag_font_ttf.set_value(path.to_str().unwrap()); + }); + + let mut win = self.win.clone(); + self.cancel_btn.set_callback(move |_| { + win.hide(); + }); + + let mut quote_font_ttf = self.quote_font_ttf.clone(); + let mut tag_font_ttf = self.tag_font_ttf.clone(); + let mut quote_font_ratio = self.quote_font_ratio.clone(); + let mut tag_font_ratio = self.tag_font_ratio.clone(); + let mut layer_red = self.layer_red.clone(); + let mut layer_green = self.layer_green.clone(); + let mut layer_blue = self.layer_blue.clone(); + let mut layer_alpha = self.layer_alpha.clone(); + self.defaults_btn.set_callback(move |_| { + let conf = ConfigFile::default(); + quote_font_ttf.set_value(&conf.quote_font_ttf); + tag_font_ttf.set_value(&conf.tag_font_ttf); + quote_font_ratio.set_value(conf.quote_font_ratio); + tag_font_ratio.set_value(conf.tag_font_ratio); + layer_red.set_value(conf.color_layer[0] as f64); + layer_green.set_value(conf.color_layer[1] as f64); + layer_blue.set_value(conf.color_layer[2] as f64); + layer_alpha.set_value(conf.color_layer[3] as f64); + }); + + let mut win = self.win.clone(); + let quote_font_ttf = self.quote_font_ttf.clone(); + let tag_font_ttf = self.tag_font_ttf.clone(); + let quote_font_ratio = self.quote_font_ratio.clone(); + let tag_font_ratio = self.tag_font_ratio.clone(); + let layer_red = self.layer_red.clone(); + let layer_green = self.layer_green.clone(); + let layer_blue = self.layer_blue.clone(); + let layer_alpha = self.layer_alpha.clone(); + let did_save = Rc::clone(&self.did_save); + self.save_btn.set_callback(move |_| { + let conf = ConfigFile { + quote_font_ttf: quote_font_ttf.value(), + tag_font_ttf: tag_font_ttf.value(), + quote_font_ratio: quote_font_ratio.value(), + tag_font_ratio: tag_font_ratio.value(), + color_layer: [ + layer_red.value() as u8, + layer_green.value() as u8, + layer_blue.value() as u8, + layer_alpha.value() as u8, + ], + }; + + conf.save(); + *globals::CONFIG.write().unwrap() = conf; + *did_save.borrow_mut() = true; + win.hide(); + dialog::message_default("Re-open Post Maker to see changes!") + }); + } +} diff --git a/src/crop_window.rs b/src/crop_window.rs index b128e1b..4c3ae33 100644 --- a/src/crop_window.rs +++ b/src/crop_window.rs @@ -61,6 +61,7 @@ impl CropWindow { main_flex.end(); win.end(); + win.make_modal(true); win.make_resizable(true); let mut crop_win = Self { @@ -119,7 +120,6 @@ impl CropWindow { self.page.image_view.redraw(); self.win.show(); - self.win.make_modal(true); while self.win.shown() { app::wait(); } diff --git a/src/draw_thread.rs b/src/draw_thread.rs index 79c4279..2c3a251 100644 --- a/src/draw_thread.rs +++ b/src/draw_thread.rs @@ -188,11 +188,13 @@ fn load_image( tag_position.set_range(0.0, prop.original_dimension.1); tag_position.set_value(prop.tag_position); - layer_red.set_value(globals::CONFIG.color_layer[0] as f64); - layer_green.set_value(globals::CONFIG.color_layer[1] as f64); - layer_blue.set_value(globals::CONFIG.color_layer[2] as f64); - layer_alpha.set_value(globals::CONFIG.color_layer[3] as f64); - prop.rgba = globals::CONFIG.color_layer; + let glob = &globals::CONFIG.read().unwrap(); + layer_red.set_value(glob.color_layer[0] as f64); + layer_green.set_value(glob.color_layer[1] as f64); + layer_blue.set_value(glob.color_layer[2] as f64); + layer_alpha.set_value(glob.color_layer[3] as f64); + prop.rgba = glob.color_layer; + drop(glob); match crop { Some((x, y)) => { diff --git a/src/globals.rs b/src/globals.rs index ce20dcc..2944faa 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -1,13 +1,13 @@ use crate::config; use lazy_static::lazy_static; use rusttype::Font; -use std::io::Read; +use std::{io::Read, sync::RwLock}; lazy_static! { - pub static ref CONFIG: config::ConfigFile = config::ConfigFile::load(); + pub static ref CONFIG: RwLock = RwLock::new(config::ConfigFile::load()); pub static ref FONT_QUOTE: Font<'static> = { let mut buffer = Vec::new(); - if let Ok(mut file) = std::fs::File::open(&CONFIG.quote_font_ttf) { + if let Ok(mut file) = std::fs::File::open(CONFIG.read().unwrap().quote_font_ttf.as_str()) { if let Ok(_) = file.read_to_end(&mut buffer) { if let Some(out) = rusttype::Font::try_from_vec(buffer) { return out; @@ -19,7 +19,7 @@ lazy_static! { }; pub static ref FONT_TAG: Font<'static> = { let mut buffer = Vec::new(); - if let Ok(mut file) = std::fs::File::open(&CONFIG.quote_font_ttf) { + if let Ok(mut file) = std::fs::File::open(&CONFIG.read().unwrap().tag_font_ttf.as_str()) { if let Ok(_) = file.read_to_end(&mut buffer) { if let Some(out) = rusttype::Font::try_from_vec(buffer) { return out; @@ -28,4 +28,5 @@ lazy_static! { } rusttype::Font::try_from_vec(include_bytes!("../Kalam-Regular.ttf").to_vec()).unwrap() }; + pub static ref ICON: &'static str = include_str!("../icon.svg"); } diff --git a/src/main.rs b/src/main.rs index 44c1846..c01d656 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod config; +mod config_window; mod crop_window; mod draw_thread; mod globals; diff --git a/src/main_window.rs b/src/main_window.rs index 4ae7028..db720e4 100644 --- a/src/main_window.rs +++ b/src/main_window.rs @@ -1,3 +1,4 @@ +use crate::config_window::ConfigWindow; use crate::crop_window::CropWindow; use crate::draw_thread::*; use crate::utils::ImageProperties; @@ -53,8 +54,6 @@ impl MainWindow { sender: app::Sender, draw_buff: Arc>>, ) -> Self { - let color = [25, 29, 34, 190]; - let mut win = Window::new(0, 0, 1000, 600, "Post Maker").center_screen(); let mut main_flex = Flex::default().size_of_parent().column(); @@ -102,22 +101,18 @@ impl MainWindow { darklayer_flex.set_size(&Frame::default().with_label("Red"), 30); let mut layer_red = Spinner::default(); layer_red.set_range(0.0, 255.0); - layer_red.set_value(color[0] as f64); darklayer_flex.set_size(&layer_red, 50); darklayer_flex.set_size(&Frame::default().with_label("Green"), 40); let mut layer_green = Spinner::default(); layer_green.set_range(0.0, 255.0); - layer_green.set_value(color[1] as f64); darklayer_flex.set_size(&layer_green, 50); darklayer_flex.set_size(&Frame::default().with_label("Blue"), 30); let mut layer_blue = Spinner::default(); layer_blue.set_range(0.0, 255.0); - layer_blue.set_value(color[2] as f64); darklayer_flex.set_size(&layer_blue, 50); darklayer_flex.set_size(&Frame::default().with_label("Alpha"), 40); let mut layer_alpha = Spinner::default(); layer_alpha.set_range(0.0, 255.0); - layer_alpha.set_value(color[3] as f64); darklayer_flex.set_size(&layer_alpha, 50); darklayer_flex.end(); controls_flex.set_size(&darklayer_flex, 30); @@ -262,12 +257,16 @@ impl MainWindow { move |_| sender.send(DrawMessage::Save).unwrap(), ); + let mut config_window = ConfigWindow::new(); + let sender = self.sender.clone(); self.menubar.add( "&Edit/Configure...\t", Shortcut::None, menu::MenuFlag::Normal, - |_| { - println!("wow"); + move |_| { + if config_window.show() { + sender.send(DrawMessage::Recalc).unwrap(); + } }, ); } diff --git a/src/utils.rs b/src/utils.rs index 02f75d9..f158eae 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -394,11 +394,11 @@ pub(crate) fn height_from_width(width: f64) -> f64 { } pub(crate) fn quote_from_height(height: f64) -> f64 { - (height * globals::CONFIG.quote_font_ratio) / 5000.0 + (height * globals::CONFIG.read().unwrap().quote_font_ratio) / 5000.0 } pub(crate) fn tag_from_height(height: f64) -> f64 { - (height * globals::CONFIG.tag_font_ratio) / 5000.0 + (height * globals::CONFIG.read().unwrap().tag_font_ratio) / 5000.0 } pub(crate) fn measure_line(