Code Clone from GitLab Repo
This commit is contained in:
parent
5523202514
commit
4021ebb4a3
7 changed files with 882 additions and 2 deletions
src
457
src/main.rs
Normal file
457
src/main.rs
Normal file
|
@ -0,0 +1,457 @@
|
|||
use std::iter::Enumerate;
|
||||
|
||||
use egui::{widgets, TextStyle};
|
||||
use metadata::{AgeRating, LanguageISO, Metadata};
|
||||
|
||||
use eframe::egui;
|
||||
use parsers::Parsers;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
mod metadata;
|
||||
mod parsers;
|
||||
|
||||
const TEXT_SIZE_SMALL: f32 = 1.0;
|
||||
const TEXT_SIZE_MEDIUM: f32 = 1.2;
|
||||
const TEXT_SIZE_LARGE: f32 = 1.4;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
env_logger::init();
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(1280.0, 720.0)),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"Metadata Generator",
|
||||
options,
|
||||
Box::new(|cc| {
|
||||
cc.egui_ctx.set_pixels_per_point(TEXT_SIZE_MEDIUM);
|
||||
Box::<Generator>::default()
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
struct Generator<'a> {
|
||||
show_all: bool,
|
||||
metadata: Vec<Metadata<'a>>,
|
||||
selected_parser: Parsers,
|
||||
use_file: bool,
|
||||
meta_path: Option<String>,
|
||||
bundle: bool,
|
||||
bundle_source: Option<String>,
|
||||
bundle_path: Option<String>,
|
||||
footer_height: f32,
|
||||
}
|
||||
|
||||
impl Default for Generator<'_> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
show_all: false,
|
||||
metadata: vec![Metadata::default()],
|
||||
selected_parser: Parsers::JNovel,
|
||||
use_file: true,
|
||||
meta_path: None,
|
||||
bundle: false,
|
||||
bundle_source: None,
|
||||
bundle_path: None,
|
||||
footer_height: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for Generator<'_> {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
// Non-Metadata Options
|
||||
egui::SidePanel::right("Options")
|
||||
.resizable(false)
|
||||
.min_width(ctx.screen_rect().width() / 3.0)
|
||||
.max_width(ctx.screen_rect().width() / 3.0)
|
||||
.show(ctx, |panel| {
|
||||
panel.heading("Options");
|
||||
panel.horizontal(|row| {
|
||||
row.label("Parser: ");
|
||||
egui::containers::ComboBox::from_label("")
|
||||
.selected_text(self.selected_parser.to_string())
|
||||
.show_ui(row, |ui| {
|
||||
for rating in Parsers::iter() {
|
||||
let text = rating.to_string().clone();
|
||||
if ui
|
||||
.selectable_value(&mut self.selected_parser, rating, text)
|
||||
.clicked()
|
||||
{
|
||||
match self.selected_parser {
|
||||
Parsers::Fakku | Parsers::Irodori => {
|
||||
self.use_file = false; // TODO change to use Parser default
|
||||
}
|
||||
Parsers::JNovel => {
|
||||
self.use_file = true; // TODO change to use Parser default
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
panel.horizontal(|row| {
|
||||
row.label("Parser Source: ");
|
||||
if row
|
||||
.add(widgets::SelectableLabel::new(self.use_file, "File"))
|
||||
.clicked()
|
||||
{
|
||||
self.use_file = true;
|
||||
}
|
||||
|
||||
if row
|
||||
.add(widgets::SelectableLabel::new(!self.use_file, "URL"))
|
||||
.clicked()
|
||||
{
|
||||
self.use_file = false;
|
||||
}
|
||||
});
|
||||
|
||||
let file_label;
|
||||
if self.use_file {
|
||||
file_label = "File Path";
|
||||
} else {
|
||||
file_label = "URL";
|
||||
}
|
||||
text_input_option(panel, &mut self.meta_path, file_label, self.use_file);
|
||||
|
||||
// TODO this feels wrong, there must be a better way
|
||||
panel.add_space(self.footer_height * 0.1);
|
||||
panel.separator();
|
||||
panel.add_space(self.footer_height * 0.1);
|
||||
|
||||
panel.horizontal(|row| {
|
||||
row.label("Perform Bundle: ");
|
||||
row.add(widgets::Checkbox::new(&mut self.bundle, ""));
|
||||
});
|
||||
|
||||
if self.bundle {
|
||||
text_input_option(panel, &mut self.bundle_source, "Images Folder", true);
|
||||
text_input_option(panel, &mut self.bundle_path, "Output Path", true);
|
||||
}
|
||||
|
||||
panel.add_space(self.footer_height * 2.0);
|
||||
|
||||
panel.horizontal(|elem| {
|
||||
elem.vertical_centered(|centered| {
|
||||
if centered.button("Generate Metadata").clicked() {
|
||||
// Run Metadata Generation
|
||||
// DO NOT SAVE RESULTS YET ONLY POPULATE DATA
|
||||
println!("Ran Generation (not yet)");
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
panel.add_space(panel.available_height() - self.footer_height);
|
||||
|
||||
self.footer_height = panel
|
||||
.horizontal(|row| {
|
||||
let ppp = ctx.pixels_per_point();
|
||||
row.label("Text Size:");
|
||||
if row
|
||||
.add(widgets::RadioButton::new(ppp == TEXT_SIZE_SMALL, "Small"))
|
||||
.clicked()
|
||||
{
|
||||
ctx.set_pixels_per_point(TEXT_SIZE_SMALL);
|
||||
}
|
||||
|
||||
if row
|
||||
.add(widgets::RadioButton::new(ppp == TEXT_SIZE_MEDIUM, "Medium"))
|
||||
.clicked()
|
||||
{
|
||||
ctx.set_pixels_per_point(TEXT_SIZE_MEDIUM);
|
||||
}
|
||||
|
||||
if row
|
||||
.add(widgets::RadioButton::new(ppp == TEXT_SIZE_LARGE, "Large"))
|
||||
.clicked()
|
||||
{
|
||||
ctx.set_pixels_per_point(TEXT_SIZE_LARGE);
|
||||
}
|
||||
})
|
||||
.response
|
||||
.rect
|
||||
.height();
|
||||
});
|
||||
|
||||
// Metadata Options
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("Metadata");
|
||||
|
||||
// Title & Series
|
||||
text_input(ui, &mut self.metadata[0].series, "Series", false);
|
||||
text_input(ui, &mut self.metadata[0].title, "Title", false);
|
||||
|
||||
// Volume and Chapter Info
|
||||
ui.horizontal(|row| {
|
||||
row.label("Volume:");
|
||||
if row.button("-").clicked() {
|
||||
self.metadata[0].volume -= 1;
|
||||
}
|
||||
row.label(format!("{}", self.metadata[0].volume));
|
||||
if row.button("+").clicked() {
|
||||
self.metadata[0].volume += 1;
|
||||
}
|
||||
|
||||
row.label("Chapter:");
|
||||
if row.button("-").clicked() {
|
||||
self.metadata[0].number -= 1;
|
||||
}
|
||||
row.label(format!("{}", self.metadata[0].number));
|
||||
if row.button("+").clicked() {
|
||||
self.metadata[0].number += 1;
|
||||
}
|
||||
});
|
||||
|
||||
ui.horizontal(|row| {
|
||||
row.label("Series Chapter Count:");
|
||||
if row.button("-").clicked() {
|
||||
self.metadata[0].count -= 1;
|
||||
}
|
||||
row.label(format!("{}", self.metadata[0].count));
|
||||
if row.button("+").clicked() {
|
||||
self.metadata[0].count += 1;
|
||||
}
|
||||
});
|
||||
|
||||
// TODO Multiline Summary
|
||||
ui.label("TODO: Summary Edit");
|
||||
if let Some(summary) = &self.metadata[0].summary {
|
||||
ui.label(summary);
|
||||
}
|
||||
|
||||
// Date Inputs
|
||||
let glyph_width = ctx
|
||||
.fonts(|f| -> f32 { f.glyph_width(&TextStyle::Body.resolve(ui.style()), '0') });
|
||||
|
||||
let mut year_text = self.metadata[0].year.to_string();
|
||||
|
||||
ui.horizontal(|row| {
|
||||
row.label("Release Date:");
|
||||
if row
|
||||
.add(
|
||||
widgets::text_edit::TextEdit::singleline(&mut year_text)
|
||||
.desired_width(5.0 * glyph_width),
|
||||
)
|
||||
.changed()
|
||||
{
|
||||
let trimmed = year_text.trim();
|
||||
if trimmed == "0" {
|
||||
self.metadata[0].year = -1;
|
||||
self.metadata[0].month = -1;
|
||||
self.metadata[0].day = -1;
|
||||
} else {
|
||||
self.metadata[0].year =
|
||||
trimmed.parse::<i16>().unwrap_or(self.metadata[0].year);
|
||||
}
|
||||
};
|
||||
|
||||
if self.metadata[0].year >= 1970 {
|
||||
let mut month_text = self.metadata[0].month.to_string();
|
||||
if row
|
||||
.add(
|
||||
widgets::text_edit::TextEdit::singleline(&mut month_text)
|
||||
.desired_width(3.0 * glyph_width),
|
||||
)
|
||||
.changed()
|
||||
{
|
||||
let trimmed = month_text.trim();
|
||||
if trimmed == "0" {
|
||||
self.metadata[0].month = -1;
|
||||
self.metadata[0].day = -1;
|
||||
} else {
|
||||
self.metadata[0].month = month_text
|
||||
.trim()
|
||||
.parse::<i8>()
|
||||
.unwrap_or(self.metadata[0].month);
|
||||
}
|
||||
};
|
||||
|
||||
if self.metadata[0].month >= 0 {
|
||||
let mut day_text = self.metadata[0].day.to_string();
|
||||
if row
|
||||
.add(
|
||||
widgets::text_edit::TextEdit::singleline(&mut day_text)
|
||||
.desired_width(3.0 * glyph_width),
|
||||
)
|
||||
.changed()
|
||||
{
|
||||
let trimmed = day_text.trim();
|
||||
if trimmed == "0" {
|
||||
self.metadata[0].day = -1;
|
||||
} else {
|
||||
self.metadata[0].day = day_text
|
||||
.trim()
|
||||
.parse::<i8>()
|
||||
.unwrap_or(self.metadata[0].day);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// People involved
|
||||
text_input_option(ui, &mut self.metadata[0].writer, "Author", false);
|
||||
text_input_option(ui, &mut self.metadata[0].letterer, "Typesetter", false);
|
||||
text_input_option(ui, &mut self.metadata[0].editor, "Editor", false);
|
||||
text_input_option(ui, &mut self.metadata[0].translator, "Translator", false);
|
||||
text_input_option(ui, &mut self.metadata[0].publisher, "Publisher", false);
|
||||
|
||||
/*
|
||||
tags: Vec<String>,
|
||||
characters: Vec<String>,
|
||||
*/
|
||||
text_input(ui, &mut self.metadata[0].genre, "Genre", false);
|
||||
// TODO tag list (List of bordered labels with plus that opens a new text edit)
|
||||
ui.horizontal(|row| {
|
||||
row.label("Page Count:");
|
||||
if row.button("-").clicked() {
|
||||
self.metadata[0].page_count -= 1;
|
||||
}
|
||||
row.label(format!("{}", self.metadata[0].page_count));
|
||||
if row.button("+").clicked() {
|
||||
self.metadata[0].page_count += 1;
|
||||
}
|
||||
});
|
||||
//text_input(ui, &mut self.metadata[0].page_count, "Page Count", false);
|
||||
|
||||
// Lang Drop Down
|
||||
ui.horizontal(|row| {
|
||||
row.label("Language: ");
|
||||
egui::containers::ComboBox::from_label("a")
|
||||
.selected_text(self.metadata[0].language.to_string())
|
||||
.show_ui(row, |ui| {
|
||||
for language in LanguageISO::iter() {
|
||||
let text = language.to_string().clone();
|
||||
ui.selectable_value(&mut self.metadata[0].language, language, text);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// TODO same as with Tags but for characters
|
||||
|
||||
// Age Rating Drop Down
|
||||
ui.horizontal(|row| {
|
||||
row.label("Age Rating: ");
|
||||
egui::containers::ComboBox::from_label("b")
|
||||
.selected_text(self.metadata[0].age_rating.to_string())
|
||||
.show_ui(row, |ui| {
|
||||
for rating in AgeRating::iter() {
|
||||
let text = rating.to_string().clone();
|
||||
ui.selectable_value(&mut self.metadata[0].age_rating, rating, text);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ui.horizontal(|elem| {
|
||||
elem.vertical_centered(|centered| {
|
||||
if centered.button("Save Metadata").clicked() {
|
||||
// Run Metadata Generation
|
||||
// DO NOT SAVE RESULTS YET ONLY POPULATE DATA
|
||||
self.metadata[0].save_to_xml("/home/neshura/Repositories/manga-hentai-metadata-generator/ComicInfo.xml")
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if self.show_all {
|
||||
ui.label(format!("Not Implemented yet."));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn text_input_option(
|
||||
ui: &mut egui::Ui,
|
||||
option: &mut Option<String>,
|
||||
label: &str,
|
||||
file_picker: bool,
|
||||
) -> egui::InnerResponse<()> {
|
||||
let zero_width =
|
||||
2.0 * ui.fonts(|f| -> f32 { f.glyph_width(&TextStyle::Body.resolve(ui.style()), '0') });
|
||||
|
||||
ui.horizontal(|row| {
|
||||
row.label(format!("{}:", label));
|
||||
if let Some(ref mut text) = option {
|
||||
let dynamic_width = zero_width
|
||||
+ text
|
||||
.chars()
|
||||
.map(|c| {
|
||||
row.fonts(|f| -> f32 {
|
||||
f.glyph_width(&TextStyle::Body.resolve(row.style()), c)
|
||||
})
|
||||
})
|
||||
.sum::<f32>();
|
||||
|
||||
row.add(
|
||||
widgets::text_edit::TextEdit::singleline(text).desired_width(
|
||||
if dynamic_width >= zero_width * 3.0 {
|
||||
dynamic_width
|
||||
} else {
|
||||
zero_width * 3.0
|
||||
},
|
||||
),
|
||||
);
|
||||
if text == "" {
|
||||
*option = None;
|
||||
}
|
||||
} else {
|
||||
let mut init = "".to_string();
|
||||
row.add(
|
||||
widgets::text_edit::TextEdit::singleline(&mut init).desired_width(zero_width * 3.0),
|
||||
);
|
||||
if init != "" {
|
||||
*option = Some(init);
|
||||
}
|
||||
}
|
||||
|
||||
if file_picker {
|
||||
if row.button("...").clicked() {
|
||||
if let Some(path) = rfd::FileDialog::new().pick_file() {
|
||||
*option = Some(path.display().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn text_input(
|
||||
ui: &mut egui::Ui,
|
||||
option: &mut String,
|
||||
label: &str,
|
||||
file_picker: bool,
|
||||
) -> egui::InnerResponse<()> {
|
||||
let zero_width =
|
||||
2.0 * ui.fonts(|f| -> f32 { f.glyph_width(&TextStyle::Body.resolve(ui.style()), '0') });
|
||||
|
||||
ui.horizontal(|row| {
|
||||
row.label(format!("{}:", label));
|
||||
let dynamic_width = zero_width
|
||||
+ option
|
||||
.chars()
|
||||
.map(|c| {
|
||||
row.fonts(|f| -> f32 {
|
||||
f.glyph_width(&TextStyle::Body.resolve(row.style()), c)
|
||||
})
|
||||
})
|
||||
.sum::<f32>();
|
||||
|
||||
row.add(
|
||||
widgets::text_edit::TextEdit::singleline(option).desired_width(
|
||||
if dynamic_width >= zero_width * 3.0 {
|
||||
dynamic_width
|
||||
} else {
|
||||
zero_width * 3.0
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if file_picker {
|
||||
if row.button("...").clicked() {
|
||||
if let Some(path) = rfd::FileDialog::new().pick_file() {
|
||||
*option = path.display().to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
Reference in a new issue