some more UI
This commit is contained in:
187
src/main.rs
187
src/main.rs
@@ -1,16 +1,18 @@
|
||||
mod omori_locator;
|
||||
mod app_logic;
|
||||
mod config;
|
||||
mod mod_builder;
|
||||
|
||||
use std::{sync::Arc, thread, time::{Duration, SystemTime}};
|
||||
use std::{process::exit, sync::Arc, thread, time::SystemTime, default::Default};
|
||||
|
||||
use app_logic::{AppThread, UiEvent, UiState, UiStateHolder};
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use eframe::egui;
|
||||
use egui::{mutex::{Mutex, RwLock}, Align, Layout, RichText, ThemePreference};
|
||||
use egui_alignments::{center_horizontal, center_vertical, top_horizontal, Aligner};
|
||||
use egui::{mutex::Mutex, Align, Layout, RichText, TextStyle, ThemePreference};
|
||||
use egui_alignments::{center_vertical, top_horizontal};
|
||||
use egui_extras::{Column, TableBuilder};
|
||||
use egui_modal::Modal;
|
||||
use mod_builder::ModConfiguration;
|
||||
use sha2::Digest;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
@@ -30,6 +32,7 @@ fn main() -> anyhow::Result<()> {
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_min_inner_size([640.0, 480.0]),
|
||||
..Default::default()
|
||||
|
||||
};
|
||||
|
||||
let app_state = UiStateHolder {
|
||||
@@ -60,7 +63,9 @@ fn main() -> anyhow::Result<()> {
|
||||
struct Application {
|
||||
state: UiStateHolder,
|
||||
sender: Sender<UiEvent>,
|
||||
key_input: String
|
||||
key_input: String,
|
||||
configuration: ModConfiguration,
|
||||
did_fill_configuration: bool
|
||||
}
|
||||
|
||||
impl Application {
|
||||
@@ -68,7 +73,9 @@ impl Application {
|
||||
Application {
|
||||
sender,
|
||||
state,
|
||||
key_input: "".to_string()
|
||||
key_input: "".to_string(),
|
||||
configuration: Default::default(),
|
||||
did_fill_configuration: false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,10 +83,15 @@ impl Application {
|
||||
const GAME_KEY_HASH: &[u8; 32] = include_bytes!("keyhash");
|
||||
|
||||
impl eframe::App for Application {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
|
||||
exit(0); // TODO: Prompt the user to maybe please consider not actually exiting the app while it's working
|
||||
}
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
let state = self.state.state.lock();
|
||||
let state = state.clone();
|
||||
|
||||
ctx.request_repaint_after_secs(10.0);
|
||||
|
||||
match state {
|
||||
UiState::Loading => {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
@@ -154,7 +166,7 @@ impl eframe::App for Application {
|
||||
invalid_path_modal.button(ui, "OK");
|
||||
});
|
||||
});
|
||||
egui::TopBottomPanel::top("key_prompt_title_bar").show(ctx, |ui| {
|
||||
egui::TopBottomPanel::top("game_prompt_title_bar").show(ctx, |ui| {
|
||||
ui.with_layout(Layout::top_down(Align::Center), |ui| {
|
||||
ui.label(RichText::new("Select your base game").size(32.0));
|
||||
});
|
||||
@@ -200,7 +212,8 @@ impl eframe::App for Application {
|
||||
TableBuilder::new(ui)
|
||||
.striped(true)
|
||||
.column(Column::remainder())
|
||||
.column(Column::auto())
|
||||
.column(Column::auto().at_least(100.0))
|
||||
.sense(egui::Sense::hover() | egui::Sense::click())
|
||||
.body(|body| {
|
||||
body.rows(20.0, others.len(), |mut row| {
|
||||
let item = &others[row.index()];
|
||||
@@ -211,12 +224,25 @@ impl eframe::App for Application {
|
||||
let dt = chrono::Duration::from(chrono::TimeDelta::seconds(dt as i64));
|
||||
|
||||
row.col(|ui| {
|
||||
ui.label(format!("{}", item.0.display()));
|
||||
ui.with_layout(Layout::right_to_left(Align::Center).with_main_align(Align::Min).with_main_justify(true), |ui| {
|
||||
ui.label(format!("{}", item.0.display()));
|
||||
});
|
||||
});
|
||||
|
||||
row.col(|ui| {
|
||||
ui.label(format!("{}", chrono_humanize::HumanTime::from(dt)));
|
||||
ui.with_layout(Layout::right_to_left(Align::Center).with_main_align(Align::Max), |ui| {
|
||||
ui.label(format!("{}", chrono_humanize::HumanTime::from(dt)));
|
||||
});
|
||||
});
|
||||
if row.response().clicked() {
|
||||
if omori_locator::validate_omori_installation(&item.0) {
|
||||
self.sender.send(UiEvent::UsePath(item.0.clone())).expect("Failed to send");
|
||||
} else {
|
||||
invalid_path_modal.open();
|
||||
}
|
||||
}
|
||||
if row.response().hovered() {
|
||||
ctx.set_cursor_icon(egui::CursorIcon::PointingHand);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -226,7 +252,144 @@ impl eframe::App for Application {
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
UiState::PickPlaytest(playtest_history) => {
|
||||
let invalid_path_modal = Modal::new(ctx, "invalid_playtest_modal");
|
||||
invalid_path_modal.show(|ui| {
|
||||
invalid_path_modal.title(ui, "Invalid path");
|
||||
invalid_path_modal.frame(ui, |ui| {
|
||||
invalid_path_modal.body(ui, "Please pick a valid, Oneloader-generated playtest.");
|
||||
});
|
||||
invalid_path_modal.buttons(ui, |ui| {
|
||||
invalid_path_modal.button(ui, "OK");
|
||||
});
|
||||
});
|
||||
egui::TopBottomPanel::top("playtest_prompt_title_bar").show(ctx, |ui| {
|
||||
ui.with_layout(Layout::top_down(Align::Center), |ui| {
|
||||
ui.label(RichText::new("Select your playtest").size(32.0));
|
||||
});
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.with_layout(Layout::right_to_left(Align::Min).with_main_justify(true).with_main_align(Align::Center), |ui| {
|
||||
if ui.button(RichText::new("Pick playtest").size(16.0)).clicked() {
|
||||
match rfd::FileDialog::new().pick_folder() {
|
||||
Some(path) => {
|
||||
if omori_locator::validate_playtest(&path) {
|
||||
self.sender.send(UiEvent::UsePath(path)).expect("Failed to send");
|
||||
} else {
|
||||
invalid_path_modal.open();
|
||||
}
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if playtest_history.len() > 0 {
|
||||
ui.label("History of playtests");
|
||||
ui.separator();
|
||||
TableBuilder::new(ui)
|
||||
.striped(true)
|
||||
.column(Column::remainder())
|
||||
.column(Column::auto().at_least(100.0))
|
||||
.sense(egui::Sense::hover() | egui::Sense::click())
|
||||
.body(|body| {
|
||||
body.rows(20.0, playtest_history.len(), |mut row| {
|
||||
let item = &playtest_history[row.index()];
|
||||
let dt =
|
||||
(item.1 as i64) -
|
||||
(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).expect("Failed to get the time").as_secs() as i64);
|
||||
|
||||
let dt = chrono::Duration::from(chrono::TimeDelta::seconds(dt as i64));
|
||||
|
||||
row.col(|ui| {
|
||||
ui.with_layout(Layout::right_to_left(Align::Center).with_main_align(Align::Min).with_main_justify(true), |ui| {
|
||||
ui.label(format!("{}", item.0.display()));
|
||||
});
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.with_layout(Layout::right_to_left(Align::Center).with_main_align(Align::Max), |ui| {
|
||||
ui.label(format!("{}", chrono_humanize::HumanTime::from(dt)));
|
||||
});
|
||||
});
|
||||
if row.response().clicked() {
|
||||
if omori_locator::validate_playtest(&item.0) {
|
||||
self.sender.send(UiEvent::UsePath(item.0.clone())).expect("Failed to send");
|
||||
} else {
|
||||
invalid_path_modal.open();
|
||||
}
|
||||
}
|
||||
if row.response().hovered() {
|
||||
ctx.set_cursor_icon(egui::CursorIcon::PointingHand);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ui.label("Any playtests you've used before will be remembered here.");
|
||||
}
|
||||
});
|
||||
},
|
||||
UiState::Configure(initial_configuration) => {
|
||||
if !self.did_fill_configuration {
|
||||
self.did_fill_configuration = true;
|
||||
self.configuration = initial_configuration;
|
||||
}
|
||||
|
||||
let mut font = TextStyle::Body.resolve(&ctx.style());
|
||||
font.size = 16.0;
|
||||
|
||||
egui::TopBottomPanel::top("configure_title_bar").show(ctx, |ui| {
|
||||
ui.with_layout(Layout::top_down(Align::Center), |ui| {
|
||||
ui.label(RichText::new("Configure your mod").size(32.0));
|
||||
});
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
top_horizontal(ui, |ui| {
|
||||
TableBuilder::new(ui)
|
||||
.column(Column::auto().at_least(100.0))
|
||||
.column(Column::exact(300.0))
|
||||
.body(|mut body| {
|
||||
body.row(24.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label(RichText::new("Mod ID").size(16.0));
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.add(egui::TextEdit::singleline(&mut self.configuration.mod_id).font(font.clone()));
|
||||
});
|
||||
});
|
||||
body.row(24.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label(RichText::new("Mod Name").size(16.0));
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.add(egui::TextEdit::singleline(&mut self.configuration.mod_name).font(font.clone()));
|
||||
});
|
||||
});
|
||||
body.row(24.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label(RichText::new("Mod Description").size(16.0));
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.add(egui::TextEdit::singleline(&mut self.configuration.mod_description).font(font.clone()));
|
||||
});
|
||||
});
|
||||
body.row(24.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label(RichText::new("Mod Version").size(16.0));
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.add(egui::TextEdit::singleline(&mut self.configuration.mod_version).font(font.clone()));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user