Change film editing to use a modal library

This commit is contained in:
pjht 2023-06-14 14:04:20 -05:00
parent 6ea1fca14d
commit a49744a79d
Signed by: pjht
GPG Key ID: CA239FC6934E6F3A
4 changed files with 110 additions and 95 deletions

23
Cargo.lock generated
View File

@ -760,6 +760,15 @@ dependencies = [
"num-traits",
]
[[package]]
name = "egui-modal"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "868331421dda06e5dc8e96b2be78fd01c33a8e5c99ca452369cebecbef7b6639"
dependencies = [
"egui",
]
[[package]]
name = "egui-winit"
version = "0.22.0"
@ -820,6 +829,18 @@ dependencies = [
"serde",
]
[[package]]
name = "enum_dispatch"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11f36e95862220b211a6e2aa5eca09b4fa391b13cd52ceb8035a24bf65a79de2"
dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "enumflags2"
version = "0.7.7"
@ -945,7 +966,9 @@ dependencies = [
"chrono",
"eframe",
"egui-datepicker",
"egui-modal",
"egui_extras",
"enum_dispatch",
"env_logger",
"itertools",
"serde",

View File

@ -9,7 +9,9 @@ edition = "2021"
chrono = { version = "0.4.26", features = ["serde"] }
eframe = { version = "0.22.0", features = ["ron", "persistence"] }
egui-datepicker = { version = "0.3.0", path = "egui-datepicker" }
egui-modal = "0.2.4"
egui_extras = { version = "0.22.0", features = ["datepicker"] }
enum_dispatch = "0.3.11"
env_logger = "0.10.0"
itertools = "0.10.5"
serde = { version = "1.0.163", features = ["derive"] }

View File

@ -1,8 +1,9 @@
use eframe::{
egui::{self, DragValue, Window},
emath::Align2,
egui::{self, DragValue},
epaint::Color32,
};
use egui_modal::Modal;
use enum_dispatch::enum_dispatch;
use stash::Stash;
use crate::{
@ -10,73 +11,51 @@ use crate::{
AppState,
};
enum OperationWindow {
Add(AddFilmWindow),
Edit(EditFilmWindow),
Delete(DeleteFilmWindow),
#[enum_dispatch(OperationWindow)]
enum OperationWindowEnum {
AddFilmWindow,
EditFilmWindow,
DeleteFilmWindow,
}
impl OperationWindow {
fn draw(&mut self, ctx: &egui::Context, app_state: &mut AppState) -> bool {
match self {
OperationWindow::Add(win) => win.draw(ctx, app_state),
OperationWindow::Edit(win) => win.draw(ctx, app_state),
OperationWindow::Delete(win) => win.draw(ctx, app_state),
}
}
}
impl From<DeleteFilmWindow> for OperationWindow {
fn from(v: DeleteFilmWindow) -> Self {
Self::Delete(v)
}
}
impl From<EditFilmWindow> for OperationWindow {
fn from(v: EditFilmWindow) -> Self {
Self::Edit(v)
}
}
impl From<AddFilmWindow> for OperationWindow {
fn from(v: AddFilmWindow) -> Self {
Self::Add(v)
}
#[enum_dispatch]
trait OperationWindow {
fn draw(&mut self, ctx: &egui::Context, app_state: &mut AppState) -> bool;
}
pub struct EditFilmsWindow {
operation_win: Option<OperationWindow>,
operation_win: Option<OperationWindowEnum>,
}
impl EditFilmsWindow {
pub fn new() -> Self {
pub fn new(ctx: &egui::Context) -> Self {
Modal::new(ctx, "edit_films_modal").open();
Self {
operation_win: None,
}
}
pub fn draw(&mut self, ctx: &egui::Context, app_state: &mut AppState) -> bool {
let mut close_unclicked = true;
Window::new("Edit Films")
.open(&mut close_unclicked)
.interactable(self.operation_win.is_none())
.resizable(false)
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
.show(ctx, |ui| {
ui.set_enabled(self.operation_win.is_none());
let modal = Modal::new(ctx, "edit_films_modal");
modal.show(|ui| {
ui.set_enabled(self.operation_win.is_none());
modal.title(ui, "Edit films");
// modal.frame(ui, |ui| {
for (i, film) in app_state.films.iter() {
ui.horizontal(|ui| {
ui.label(film.to_string());
if ui.button("Edit").clicked() {
self.operation_win =
Some(EditFilmWindow::new(i, &app_state.films).into());
Some(EditFilmWindow::new(i, &app_state.films, &ctx).into());
modal.close();
}
let film_used = app_state.rolls.iter().any(|roll| roll.film == i);
if ui
.add_enabled(!film_used, egui::Button::new("Delete"))
.clicked()
{
self.operation_win = Some(DeleteFilmWindow::new(i).into());
self.operation_win = Some(DeleteFilmWindow::new(i, &ctx).into());
modal.close();
}
if film_used {
ui.label("(Used by one or more rolls, cannot delete)");
@ -84,15 +63,21 @@ impl EditFilmsWindow {
});
}
if ui.button("Add").clicked() {
self.operation_win = Some(AddFilmWindow::new().into());
self.operation_win = Some(AddFilmWindow::new(&ctx).into());
modal.close();
}
// });
modal.buttons(ui, |ui| {
modal.button(ui, "Close");
});
});
if let Some(operation_win) = self.operation_win.as_mut() {
if operation_win.draw(ctx, app_state) {
self.operation_win = None;
modal.open();
}
}
!close_unclicked
!modal.is_open() && self.operation_win.is_none()
}
}
@ -103,22 +88,25 @@ struct AddFilmWindow {
}
impl AddFilmWindow {
fn new() -> Self {
fn new(ctx: &egui::Context) -> Self {
Modal::new(ctx, "add_film_modal").open();
Self {
name: String::new(),
iso: 400,
show_name_req_err: false,
}
}
}
impl OperationWindow for AddFilmWindow {
fn draw(&mut self, ctx: &egui::Context, app_state: &mut AppState) -> bool {
let mut close_unclicked = true;
let mut close_window = false;
Window::new("Add Film")
.resizable(false)
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
.open(&mut close_unclicked)
.show(ctx, |ui| {
let modal = Modal::new(ctx, "add_film_modal");
modal.show(|ui| {
modal.title(ui, "Add film");
modal.frame(ui, |ui| {
if self.show_name_req_err {
ui.colored_label(Color32::DARK_RED, "Error: Name required");
}
ui.horizontal(|ui| {
let label = ui.label("Name:");
ui.text_edit_singleline(&mut self.name)
@ -129,20 +117,19 @@ impl AddFilmWindow {
ui.add(DragValue::new(&mut self.iso).clamp_range(1..=u32::MAX))
.labelled_by(label.id);
});
if ui.button("Submit").clicked() {
});
modal.buttons(ui, |ui| {
if modal.button(ui, "Submit").clicked() {
if self.name.is_empty() {
self.show_name_req_err = true;
return;
}
app_state.films.put(Film::new(&self.name, self.iso));
close_window = true;
}
if self.show_name_req_err {
ui.colored_label(Color32::DARK_RED, "Error: Name required");
}
modal.caution_button(ui, "Cancel");
});
!close_unclicked || close_window
});
!modal.is_open()
}
}
@ -154,7 +141,9 @@ struct EditFilmWindow {
}
impl EditFilmWindow {
fn new(film: FilmKey, films: &Stash<Film, FilmKey>) -> Self {
#[must_use]
fn new(film: FilmKey, films: &Stash<Film, FilmKey>, ctx: &egui::Context) -> Self {
Modal::new(ctx, "edit_film_modal").open();
let name = films[film].name.clone();
let iso = films[film].iso;
Self {
@ -164,15 +153,17 @@ impl EditFilmWindow {
show_name_req_err: false,
}
}
}
impl OperationWindow for EditFilmWindow {
fn draw(&mut self, ctx: &egui::Context, app_state: &mut AppState) -> bool {
let mut close_unclicked = true;
let mut close_window = false;
Window::new("Edit Film")
.resizable(false)
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
.open(&mut close_unclicked)
.show(ctx, |ui| {
let modal = Modal::new(ctx, "edit_film_modal");
modal.show(|ui| {
modal.title(ui, "Edit film");
modal.frame(ui, |ui| {
if self.show_name_req_err {
ui.colored_label(Color32::DARK_RED, "Error: Name required");
}
ui.horizontal(|ui| {
let label = ui.label("Name:");
ui.text_edit_singleline(&mut self.name)
@ -183,20 +174,20 @@ impl EditFilmWindow {
ui.add(DragValue::new(&mut self.iso).clamp_range(1..=u32::MAX))
.labelled_by(label.id);
});
if ui.button("Submit").clicked() {
});
modal.buttons(ui, |ui| {
if modal.button(ui, "Submit").clicked() {
if self.name.is_empty() {
self.show_name_req_err = true;
return;
}
app_state.films[self.film] = Film::new(&self.name, self.iso);
app_state.resort_roll_list = true;
close_window = true;
}
if self.show_name_req_err {
ui.colored_label(Color32::DARK_RED, "Error: Name required");
}
modal.caution_button(ui, "Cancel");
});
!close_unclicked || close_window
});
!modal.is_open()
}
}
@ -205,32 +196,31 @@ struct DeleteFilmWindow {
}
impl DeleteFilmWindow {
fn new(film: FilmKey) -> Self {
#[must_use]
fn new(film: FilmKey, ctx: &egui::Context) -> Self {
Modal::new(ctx, "delete_film_modal").open();
Self { film }
}
}
impl OperationWindow for DeleteFilmWindow {
fn draw(&mut self, ctx: &egui::Context, app_state: &mut AppState) -> bool {
let mut close_unclicked = true;
let mut close_window = false;
Window::new("Confirm delete")
.resizable(false)
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
.open(&mut close_unclicked)
.show(ctx, |ui| {
ui.heading(format!(
let modal = Modal::new(ctx, "delete_film_modal");
modal.show(|ui| {
modal.title(ui, "Confirm delete");
modal.frame(ui, |ui| {
modal.body(ui, format!(
"Really delete {}?",
&app_state.films[self.film].name
));
ui.horizontal(|ui| {
if ui.button("Yes").clicked() {
app_state.films.take(self.film);
close_window = true;
}
if ui.button("No").clicked() {
close_window = true;
}
});
});
!close_unclicked || close_window
modal.buttons(ui, |ui| {
if modal.caution_button(ui, "Yes").clicked() {
app_state.films.take(self.film);
};
modal.button(ui, "No");
})
});
!modal.is_open()
}
}

View File

@ -128,7 +128,7 @@ impl eframe::App for MyApp {
.add_enabled(self.edit_films_window.is_none(), Button::new("Edit films"))
.clicked()
{
self.edit_films_window = Some(EditFilmsWindow::new());
self.edit_films_window = Some(EditFilmsWindow::new(&ctx));
}
ui.checkbox(&mut self.show_debug_info, "Show debug info");
});