Support for logging

This commit is contained in:
Piyush मिश्रः 2022-01-24 11:58:58 +05:30
parent 8a9677f261
commit 4e558d8c6b
9 changed files with 229 additions and 121 deletions

45
Cargo.lock generated
View File

@ -67,6 +67,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "clap"
version = "3.0.5"
@ -402,6 +415,15 @@ version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "matrixmultiply"
version = "0.1.15"
@ -589,9 +611,11 @@ dependencies = [
"image",
"imageproc",
"lazy_static",
"log",
"rusttype",
"serde",
"serde_json",
"simplelog",
]
[[package]]
@ -811,6 +835,17 @@ dependencies = [
"serde",
]
[[package]]
name = "simplelog"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1348164456f72ca0116e4538bdaabb0ddb622c7d9f16387c725af3e96d6001c"
dependencies = [
"chrono",
"log",
"termcolor",
]
[[package]]
name = "strsim"
version = "0.10.0"
@ -854,6 +889,16 @@ dependencies = [
"weezl",
]
[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "ttf-parser"
version = "0.6.2"

View File

@ -7,6 +7,8 @@ edition = "2021"
[dependencies]
clap = { version = "3.0", features = ["derive"] }
log = "0.4"
simplelog = "0.11"
fltk = "1.2"
fltk-theme = "0.4"
image = "0.23"

View File

@ -1,24 +1,33 @@
//! load, save configuration and parse cli args
///! load, save configuration and parse cli args
use crate::{config_picker::ConfigPicker, globals};
use clap::{ArgEnum, Parser};
use fltk::dialog;
use fltk_theme::ThemeType;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, path::PathBuf};
use std::{collections::HashMap, fs::File, path::PathBuf};
lazy_static! {
pub static ref CONFIG_PATH: PathBuf = {
match dirs::config_dir() {
Some(path) => path.join("post_maker.config"),
static ref CONFIG_DIR: PathBuf = {
let dir = match dirs::config_dir() {
Some(path) => path,
None => std::env::current_exe()
.unwrap()
.parent()
.unwrap()
.join("post_maker.config"),
.to_owned(),
}
.join("post_maker");
if !dir.exists() {
if let Err(e) = std::fs::create_dir(&dir) {
dialog::alert_default("Failed to create config dir!");
panic!("Failed to create config dir!\n{:?}", e);
}
}
dir
};
static ref CONFIG_FILE: PathBuf = CONFIG_DIR.join("post_maker.config");
static ref LOG_PATH: PathBuf = CONFIG_DIR.join("post_maker.log");
}
/// Simple program calculate size of stuff in quote image
@ -31,7 +40,7 @@ pub(crate) struct Args {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, ArgEnum)]
pub enum Themes {
pub(crate) enum Themes {
Classic,
/// Windows 7
Aero,
@ -77,24 +86,24 @@ impl Into<ThemeType> for Themes {
/// Configuation file
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigFile {
pub quote_font_ttf: String,
pub subquote_font_ttf: String,
pub subquote2_font_ttf: String,
pub tag_font_ttf: String,
pub tag2_font_ttf: String,
pub quote_font_ratio: f64,
pub subquote_font_ratio: f64,
pub subquote2_font_ratio: f64,
pub tag_font_ratio: f64,
pub tag2_font_ratio: f64,
pub quote_position_ratio: f64,
pub subquote_position_ratio: f64,
pub subquote2_position_ratio: f64,
pub tag_position_ratio: f64,
pub tag2_position_ratio: f64,
pub image_ratio: (f64, f64),
pub color_layer: [u8; 4],
pub(crate) struct ConfigFile {
pub(crate) quote_font_ttf: String,
pub(crate) subquote_font_ttf: String,
pub(crate) subquote2_font_ttf: String,
pub(crate) tag_font_ttf: String,
pub(crate) tag2_font_ttf: String,
pub(crate) quote_font_ratio: f64,
pub(crate) subquote_font_ratio: f64,
pub(crate) subquote2_font_ratio: f64,
pub(crate) tag_font_ratio: f64,
pub(crate) tag2_font_ratio: f64,
pub(crate) quote_position_ratio: f64,
pub(crate) subquote_position_ratio: f64,
pub(crate) subquote2_position_ratio: f64,
pub(crate) tag_position_ratio: f64,
pub(crate) tag2_position_ratio: f64,
pub(crate) image_ratio: (f64, f64),
pub(crate) color_layer: [u8; 4],
}
impl Default for ConfigFile {
@ -112,9 +121,9 @@ impl Default for ConfigFile {
tag2_font_ratio: 150.0,
quote_position_ratio: 0.7,
subquote_position_ratio: 0.8,
subquote2_position_ratio: 0.8,
subquote2_position_ratio: 0.9,
tag_position_ratio: 0.5,
tag2_position_ratio: 0.5,
tag2_position_ratio: 0.95,
image_ratio: (4.0, 5.0),
color_layer: [20, 22, 25, 197],
}
@ -123,8 +132,7 @@ impl Default for ConfigFile {
impl ConfigFile {
pub(crate) fn load() -> Self {
// config_picker::ConfigPicker::new();
if CONFIG_PATH.exists() {
if CONFIG_FILE.exists() {
let map = get_configs();
let map = match map {
@ -160,16 +168,17 @@ impl ConfigFile {
}
pub(crate) fn get_configs() -> Option<HashMap<String, ConfigFile>> {
match std::fs::read_to_string(&*CONFIG_PATH) {
match std::fs::read_to_string(&*CONFIG_FILE) {
Ok(r) => serde_json::from_str::<HashMap<String, ConfigFile>>(&r).ok(),
Err(_) => None,
}
}
pub(crate) fn save_configs(configs: HashMap<String, ConfigFile>) {
if let Err(_) = std::fs::write(&*CONFIG_PATH, serde_json::to_string(&configs).unwrap()) {
if let Err(e) = std::fs::write(&*CONFIG_FILE, serde_json::to_string(&configs).unwrap()) {
dialog::alert_default("Can't write config!");
eprintln!("Can't write config!");
error!("Can't write config!\n{:?}", e);
panic!("Can't write config!\n{:?}", e);
}
}
@ -177,3 +186,16 @@ pub(crate) fn config() -> Args {
let args = Args::parse();
args
}
pub(crate) fn log_file() -> File {
match File::open(&*LOG_PATH) {
Ok(f) => f,
Err(_) => match File::create(&*LOG_PATH) {
Ok(f) => f,
Err(e) => {
dialog::alert_default("Can't open log file!");
panic!("{:?}", e)
}
},
}
}

View File

@ -16,7 +16,7 @@ use std::{
/// Window to crop the existing image
pub(crate) struct CropWindow {
pub win: Window,
pub(crate) win: Window,
apply_btn: Button,
container: Rc<RefCell<Option<ImageContainer>>>,
page: Page,

View File

@ -8,7 +8,7 @@ use crate::{
use fltk::{
app,
button::Button,
enums,
dialog, enums,
frame::Frame,
input::{Input, MultilineInput},
menu,
@ -250,63 +250,70 @@ fn load_image(
let mut use_defaults = true;
if conf.exists() {
let mut prop = properties.write().unwrap();
let read = fs::read_to_string(&conf).unwrap();
if let Ok(saved_prop) = serde_json::from_str::<ImageProperties>(&read) {
utils::set_color_btn_rgba(saved_prop.rgba, layer_rgb);
layer_alpha.set_value(saved_prop.rgba[3] as f64);
quote.set_value(&saved_prop.quote);
subquote.set_value(&saved_prop.subquote);
subquote2.set_value(&saved_prop.subquote2);
tag.set_value(&saved_prop.tag);
tag2.set_value(&saved_prop.tag2);
quote_position.set_range(0.0, prop.original_dimension.1);
quote_position.set_value(saved_prop.quote_position);
subquote_position.set_range(0.0, prop.original_dimension.1);
subquote_position.set_value(saved_prop.subquote_position);
subquote2_position.set_range(0.0, prop.original_dimension.1);
subquote2_position.set_value(saved_prop.subquote2_position);
tag_position.set_range(0.0, prop.original_dimension.1);
tag_position.set_value(saved_prop.tag_position);
tag2_position.set_range(0.0, prop.original_dimension.1);
tag2_position.set_value(saved_prop.tag2_position);
quote_position_slider.set_range(0.0, prop.original_dimension.1);
subquote_position_slider.set_range(0.0, prop.original_dimension.1);
subquote2_position_slider.set_range(0.0, prop.original_dimension.1);
quote_position_slider.set_value(saved_prop.quote_position);
subquote_position_slider.set_value(saved_prop.subquote_position);
subquote2_position_slider.set_value(saved_prop.subquote2_position);
tag_position_slider.set_range(0.0, prop.original_dimension.1);
tag_position_slider.set_value(saved_prop.tag_position);
tag2_position_slider.set_range(0.0, prop.original_dimension.1);
tag2_position_slider.set_value(saved_prop.tag2_position);
dimension.set_label(&format!(
"[{}x{}]",
prop.original_dimension.0, prop.original_dimension.1
));
match fs::read_to_string(&conf) {
Ok(read) => {
if let Ok(saved_prop) = serde_json::from_str::<ImageProperties>(&read) {
utils::set_color_btn_rgba(saved_prop.rgba, layer_rgb);
layer_alpha.set_value(saved_prop.rgba[3] as f64);
quote.set_value(&saved_prop.quote);
subquote.set_value(&saved_prop.subquote);
subquote2.set_value(&saved_prop.subquote2);
tag.set_value(&saved_prop.tag);
tag2.set_value(&saved_prop.tag2);
quote_position.set_range(0.0, prop.original_dimension.1);
quote_position.set_value(saved_prop.quote_position);
subquote_position.set_range(0.0, prop.original_dimension.1);
subquote_position.set_value(saved_prop.subquote_position);
subquote2_position.set_range(0.0, prop.original_dimension.1);
subquote2_position.set_value(saved_prop.subquote2_position);
tag_position.set_range(0.0, prop.original_dimension.1);
tag_position.set_value(saved_prop.tag_position);
tag2_position.set_range(0.0, prop.original_dimension.1);
tag2_position.set_value(saved_prop.tag2_position);
quote_position_slider.set_range(0.0, prop.original_dimension.1);
subquote_position_slider.set_range(0.0, prop.original_dimension.1);
subquote2_position_slider.set_range(0.0, prop.original_dimension.1);
quote_position_slider.set_value(saved_prop.quote_position);
subquote_position_slider.set_value(saved_prop.subquote_position);
subquote2_position_slider.set_value(saved_prop.subquote2_position);
tag_position_slider.set_range(0.0, prop.original_dimension.1);
tag_position_slider.set_value(saved_prop.tag_position);
tag2_position_slider.set_range(0.0, prop.original_dimension.1);
tag2_position_slider.set_value(saved_prop.tag2_position);
dimension.set_label(&format!(
"[{}x{}]",
prop.original_dimension.0, prop.original_dimension.1
));
prop.quote = saved_prop.quote;
prop.subquote = saved_prop.subquote;
prop.subquote2 = saved_prop.subquote2;
prop.tag = saved_prop.tag;
prop.tag2 = saved_prop.tag2;
prop.quote_position = saved_prop.quote_position;
prop.subquote_position = saved_prop.subquote_position;
prop.subquote2_position = saved_prop.subquote2_position;
prop.tag_position = saved_prop.tag_position;
prop.tag2_position = saved_prop.tag2_position;
prop.rgba = saved_prop.rgba;
prop.is_saved = true;
use_defaults = false;
drop(prop);
prop.quote = saved_prop.quote;
prop.subquote = saved_prop.subquote;
prop.subquote2 = saved_prop.subquote2;
prop.tag = saved_prop.tag;
prop.tag2 = saved_prop.tag2;
prop.quote_position = saved_prop.quote_position;
prop.subquote_position = saved_prop.subquote_position;
prop.subquote2_position = saved_prop.subquote2_position;
prop.tag_position = saved_prop.tag_position;
prop.tag2_position = saved_prop.tag2_position;
prop.rgba = saved_prop.rgba;
prop.is_saved = true;
use_defaults = false;
drop(prop);
match crop {
Some((x, y)) => cont.apply_crop_pos(x, y),
None => match saved_prop.crop_position {
Some((x, y)) => cont.apply_crop_pos(x, y),
None => cont.apply_crop(),
},
match crop {
Some((x, y)) => cont.apply_crop_pos(x, y),
None => match saved_prop.crop_position {
Some((x, y)) => cont.apply_crop_pos(x, y),
None => cont.apply_crop(),
},
}
}
}
}
Err(e) => {
dialog::alert_default("Failed to open config file!");
warn!("Failed to open config file!\n{:?}", e);
}
};
}
if use_defaults {

View File

@ -4,10 +4,12 @@ use rusttype::Font;
use std::{ffi::OsString, io::Read, sync::RwLock};
lazy_static! {
pub static ref THEME: config::Themes = config::config().theme.unwrap_or(config::Themes::System);
pub static ref CONFIG_NAME: RwLock<String> = RwLock::new("default".to_owned());
pub static ref CONFIG: RwLock<config::ConfigFile> = RwLock::new(config::ConfigFile::load());
pub static ref FONT_QUOTE: Font<'static> = {
pub(crate) static ref THEME: config::Themes =
config::config().theme.unwrap_or(config::Themes::System);
pub(crate) static ref CONFIG_NAME: RwLock<String> = RwLock::new("default".to_owned());
pub(crate) static ref CONFIG: RwLock<config::ConfigFile> =
RwLock::new(config::ConfigFile::load());
pub(crate) static ref FONT_QUOTE: Font<'static> = {
let mut buffer = Vec::new();
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) {
@ -19,7 +21,7 @@ lazy_static! {
rusttype::Font::try_from_vec(include_bytes!("../ReenieBeanie-Regular.ttf").to_vec())
.unwrap()
};
pub static ref FONT_SUBQUOTE: Font<'static> = {
pub(crate) static ref FONT_SUBQUOTE: Font<'static> = {
let mut buffer = Vec::new();
if let Ok(mut file) = std::fs::File::open(CONFIG.read().unwrap().subquote_font_ttf.as_str())
{
@ -31,7 +33,7 @@ lazy_static! {
}
rusttype::Font::try_from_vec(include_bytes!("../Rajdhani-Regular.ttf").to_vec()).unwrap()
};
pub static ref FONT_SUBQUOTE2: Font<'static> = {
pub(crate) static ref FONT_SUBQUOTE2: Font<'static> = {
let mut buffer = Vec::new();
if let Ok(mut file) =
std::fs::File::open(CONFIG.read().unwrap().subquote2_font_ttf.as_str())
@ -44,7 +46,7 @@ lazy_static! {
}
rusttype::Font::try_from_vec(include_bytes!("../Rajdhani-Regular.ttf").to_vec()).unwrap()
};
pub static ref FONT_TAG: Font<'static> = {
pub(crate) static ref FONT_TAG: Font<'static> = {
let mut buffer = Vec::new();
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) {
@ -55,7 +57,7 @@ lazy_static! {
}
rusttype::Font::try_from_vec(include_bytes!("../Kalam-Regular.ttf").to_vec()).unwrap()
};
pub static ref FONT_TAG2: Font<'static> = {
pub(crate) static ref FONT_TAG2: Font<'static> = {
let mut buffer = Vec::new();
if let Ok(mut file) = std::fs::File::open(&CONFIG.read().unwrap().tag2_font_ttf.as_str()) {
if let Ok(_) = file.read_to_end(&mut buffer) {
@ -66,8 +68,8 @@ lazy_static! {
}
rusttype::Font::try_from_vec(include_bytes!("../Kalam-Regular.ttf").to_vec()).unwrap()
};
pub static ref ICON: OsString = include_str!("../icon.svg").into();
pub static ref RELOAD_ICON: OsString = {
pub(crate) static ref ICON: OsString = include_str!("../icon.svg").into();
pub(crate) static ref RELOAD_ICON: OsString = {
let img = include_str!("../reload.svg");
if *THEME == config::Themes::Dark || *THEME == config::Themes::HighContrast {
return img.replace("fill=\"black\"", "fill=\"white\"").into();

View File

@ -1,5 +1,9 @@
#![windows_subsystem = "windows"]
#[macro_use]
extern crate log;
extern crate simplelog;
mod config;
mod config_picker;
mod config_window;
@ -9,12 +13,13 @@ mod globals;
mod main_window;
mod utils;
// use crop_window::CropWindow;
use fltk::{
app::{channel, App},
dialog,
prelude::*,
};
use fltk_theme::WidgetTheme;
use simplelog::*;
use main_window::MainWindow;
use std::sync::{Arc, RwLock};
@ -27,6 +32,16 @@ pub(crate) enum AppMessage {
fn main() {
let app = App::default();
WidgetTheme::new(globals::THEME.clone().into()).apply();
if let Err(e) = CombinedLogger::init(vec![WriteLogger::new(
LevelFilter::Info,
Config::default(),
config::log_file(),
)]) {
dialog::alert_default("Failed to start logger");
panic!("Failed to start logger\n{:?}", e);
}
lazy_static::initialize(&globals::CONFIG);
let draw_buff: Arc<RwLock<Option<Vec<u8>>>> = Arc::new(RwLock::new(None));

View File

@ -396,8 +396,9 @@ impl MainWindow {
}
let expost_dir = path.join("export");
if !expost_dir.exists() {
if let Err(_) = fs::create_dir(expost_dir) {
fltk::dialog::alert_default("Failed: create export folder!");
if let Err(e) = fs::create_dir(expost_dir) {
fltk::dialog::alert_default("Failed to create export folder!");
warn!("Failed to create export folder!\n{:?}", e);
return;
}
}

View File

@ -59,9 +59,10 @@ impl ImageContainer {
pub(crate) fn new(path: &PathBuf, properties: Arc<RwLock<ImageProperties>>) -> Self {
let img = match image::open(path) {
Ok(i) => i,
Err(_) => {
Err(e) => {
dialog::alert_default("Failed to open image!");
panic!("Failed to open image");
error!("Failed to open image\n{:?}", e);
panic!("Failed to open image\n{:?}", e);
}
};
@ -181,8 +182,9 @@ impl ImageContainer {
let mut prop = prop.clone();
prop.path = None;
if fs::write(&path_conf, serde_json::to_string(&prop).unwrap()).is_err() {
if let Err(e) = fs::write(&path_conf, serde_json::to_string(&prop).unwrap()) {
dialog::alert_default("Failed to save conf!");
warn!("Failed to save conf!\n{:?}", e);
}
let mut img = image::open(&path_original).unwrap();
@ -212,11 +214,9 @@ impl ImageContainer {
prop.original_dimension.1,
);
if img
.save_with_format(&export, image::ImageFormat::Png)
.is_err()
{
if let Err(e) = img.save_with_format(&export, image::ImageFormat::Png) {
dialog::alert_default("Failed to export png!");
warn!("Failed to export png!\n{:?}", e);
}
}
@ -238,14 +238,19 @@ impl ImageContainer {
let path_conf = path.with_extension("conf");
let path_conf_new = new_path.with_extension("conf");
if path.exists() && fs::copy(path, &new_path).is_err() {
dialog::alert_default("Failed to clone image!");
return None;
if path.exists() {
if let Err(e) = fs::copy(path, &new_path) {
dialog::alert_default("Failed to clone image!");
warn!("Failed to clone image!\n{:?}", e);
return None;
}
}
if path_conf.exists() && fs::copy(path_conf, &path_conf_new).is_err() {
dialog::alert_default("Failed to clone image!");
return None;
if path_conf.exists() {
if let Err(e) = fs::copy(path_conf, &path_conf_new) {
dialog::alert_default("Failed to clone image!");
warn!("Failed to clone image!\n{:?}", e);
}
}
Some(new_path)
}
@ -270,16 +275,25 @@ impl ImageContainer {
.unwrap(),
);
if path_original.exists() && fs::remove_file(path_original).is_err() {
dialog::alert_default("Failed to delete image!");
if path_original.exists() {
if let Err(e) = fs::remove_file(path_original) {
dialog::alert_default("Failed to delete image!");
warn!("Failed to delete image!\n{:?}", e);
}
}
if path_conf.exists() && fs::remove_file(path_conf).is_err() {
dialog::alert_default("Failed to delete image conf!");
if path_conf.exists() {
if let Err(e) = fs::remove_file(path_conf) {
dialog::alert_default("Failed to delete image conf!");
warn!("Failed to delete image conf!\n{:?}", e);
}
}
if export.exists() && fs::remove_file(export).is_err() {
dialog::alert_default("Failed to delete exported image!");
if export.exists() {
if let Err(e) = fs::remove_file(export) {
dialog::alert_default("Failed to delete exported image!");
warn!("Failed to delete exported image!\n{:?}", e);
}
}
}
}