Compare commits
3 Commits
7b00d12265
...
ddc2601e79
Author | SHA1 | Date | |
---|---|---|---|
ddc2601e79 | |||
1d2ff0f262 | |||
3e16dbd330 |
43
Cargo.lock
generated
43
Cargo.lock
generated
@ -453,9 +453,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.25"
|
version = "0.4.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fdbc37d37da9e5bce8173f3a41b71d9bf3c674deebbaceacd0ebdabde76efb03"
|
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
"android-tzdata",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
@ -949,6 +949,8 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"itertools",
|
"itertools",
|
||||||
"serde",
|
"serde",
|
||||||
|
"smart-default",
|
||||||
|
"stash",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1997,6 +1999,17 @@ version = "1.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smart-default"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.18",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay-client-toolkit"
|
name = "smithay-client-toolkit"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
@ -2036,6 +2049,17 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stash"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e79601e59056976819e06b2aad284be6edc9b5b27d26808330a1656d6b7dc91a"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"unreachable",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -2278,6 +2302,15 @@ dependencies = [
|
|||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unreachable"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||||
|
dependencies = [
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@ -2301,6 +2334,12 @@ version = "0.9.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "waker-fn"
|
name = "waker-fn"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -6,11 +6,13 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { version = "0.4.25", features = ["serde"] }
|
chrono = { version = "0.4.26", features = ["serde"] }
|
||||||
eframe = { version = "0.22.0", features = ["ron", "persistence"] }
|
eframe = { version = "0.22.0", features = ["ron", "persistence"] }
|
||||||
egui-datepicker = { version = "0.3.0", path = "egui-datepicker" }
|
egui-datepicker = { version = "0.3.0", path = "egui-datepicker" }
|
||||||
egui_extras = { version = "0.22.0", features = ["datepicker"] }
|
egui_extras = { version = "0.22.0", features = ["datepicker"] }
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.10.0"
|
||||||
itertools = "0.10.5"
|
itertools = "0.10.5"
|
||||||
serde = { version = "1.0.163", features = ["derive"] }
|
serde = { version = "1.0.163", features = ["derive"] }
|
||||||
|
smart-default = "0.7.1"
|
||||||
|
stash = { version = "0.1.5", features = ["serialization"] }
|
||||||
toml = "0.7.4"
|
toml = "0.7.4"
|
||||||
|
224
src/edit_films.rs
Normal file
224
src/edit_films.rs
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
use eframe::{
|
||||||
|
egui::{self, DragValue, Window},
|
||||||
|
epaint::Color32,
|
||||||
|
};
|
||||||
|
use stash::Stash;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
film::{Film, FilmKey},
|
||||||
|
AppState,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct EditFilmsWindow {
|
||||||
|
add_film_window: Option<AddFilmWindow>,
|
||||||
|
edit_film_window: Option<EditFilmWindow>,
|
||||||
|
delete_film_window: Option<DeleteFilmWindow>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EditFilmsWindow {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
add_film_window: None,
|
||||||
|
edit_film_window: None,
|
||||||
|
delete_film_window: 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)
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
for (i, film) in app_state.films.iter() {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(film.to_string());
|
||||||
|
if ui
|
||||||
|
.add_enabled(
|
||||||
|
self.edit_film_window.is_none()
|
||||||
|
&& self
|
||||||
|
.delete_film_window
|
||||||
|
.as_ref()
|
||||||
|
.map_or(true, |win| win.film != i),
|
||||||
|
egui::Button::new("Edit"),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
self.edit_film_window = Some(EditFilmWindow::new(i, &app_state.films));
|
||||||
|
}
|
||||||
|
let film_used = app_state.rolls.iter().any(|roll| roll.film == i);
|
||||||
|
if ui
|
||||||
|
.add_enabled(
|
||||||
|
self.delete_film_window.is_none()
|
||||||
|
&& self
|
||||||
|
.edit_film_window
|
||||||
|
.as_ref()
|
||||||
|
.map_or(true, |win| win.film != i)
|
||||||
|
&& !film_used,
|
||||||
|
egui::Button::new("Delete"),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
self.delete_film_window = Some(DeleteFilmWindow::new(i));
|
||||||
|
}
|
||||||
|
if film_used {
|
||||||
|
ui.label("(Used by one or more rolls, cannot delete)");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ui
|
||||||
|
.add_enabled(self.add_film_window.is_none(), egui::Button::new("Add"))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
self.add_film_window = Some(AddFilmWindow::new());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if let Some(add_film_window) = self.add_film_window.as_mut() {
|
||||||
|
if add_film_window.draw(ctx, app_state) {
|
||||||
|
self.add_film_window = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(edit_film_window) = self.edit_film_window.as_mut() {
|
||||||
|
if edit_film_window.draw(ctx, app_state) {
|
||||||
|
self.edit_film_window = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(delete_film_window) = self.delete_film_window.as_mut() {
|
||||||
|
if delete_film_window.draw(ctx, app_state) {
|
||||||
|
self.delete_film_window = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
!close_unclicked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AddFilmWindow {
|
||||||
|
name: String,
|
||||||
|
iso: u32,
|
||||||
|
show_name_req_err: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddFilmWindow {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
name: String::new(),
|
||||||
|
iso: 400,
|
||||||
|
show_name_req_err: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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")
|
||||||
|
.open(&mut close_unclicked)
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
let label = ui.label("Name:");
|
||||||
|
ui.text_edit_singleline(&mut self.name)
|
||||||
|
.labelled_by(label.id);
|
||||||
|
});
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
let label = ui.label("ISO:");
|
||||||
|
ui.add(DragValue::new(&mut self.iso).clamp_range(1..=u32::MAX))
|
||||||
|
.labelled_by(label.id);
|
||||||
|
});
|
||||||
|
if ui.button("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");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
!close_unclicked || close_window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EditFilmWindow {
|
||||||
|
film: FilmKey,
|
||||||
|
name: String,
|
||||||
|
iso: u32,
|
||||||
|
show_name_req_err: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EditFilmWindow {
|
||||||
|
fn new(film: FilmKey, films: &Stash<Film, FilmKey>) -> Self {
|
||||||
|
let name = films[film].name.clone();
|
||||||
|
let iso = films[film].iso;
|
||||||
|
Self {
|
||||||
|
film,
|
||||||
|
name,
|
||||||
|
iso,
|
||||||
|
show_name_req_err: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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")
|
||||||
|
.open(&mut close_unclicked)
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
let label = ui.label("Name:");
|
||||||
|
ui.text_edit_singleline(&mut self.name)
|
||||||
|
.labelled_by(label.id);
|
||||||
|
});
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
let label = ui.label("ISO:");
|
||||||
|
ui.add(DragValue::new(&mut self.iso).clamp_range(1..=u32::MAX))
|
||||||
|
.labelled_by(label.id);
|
||||||
|
});
|
||||||
|
if ui.button("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);
|
||||||
|
close_window = true;
|
||||||
|
}
|
||||||
|
if self.show_name_req_err {
|
||||||
|
ui.colored_label(Color32::DARK_RED, "Error: Name required");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
!close_unclicked || close_window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DeleteFilmWindow {
|
||||||
|
film: FilmKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeleteFilmWindow {
|
||||||
|
fn new(film: FilmKey) -> Self {
|
||||||
|
Self { film }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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")
|
||||||
|
.open(&mut close_unclicked)
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
ui.heading(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
|
||||||
|
}
|
||||||
|
}
|
43
src/film.rs
Normal file
43
src/film.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use smart_default::SmartDefault;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
pub struct FilmKey(usize);
|
||||||
|
|
||||||
|
impl From<usize> for FilmKey {
|
||||||
|
fn from(value: usize) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FilmKey> for usize {
|
||||||
|
fn from(value: FilmKey) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SmartDefault, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Film {
|
||||||
|
#[default = "Unknown"]
|
||||||
|
pub name: String,
|
||||||
|
#[default = 400]
|
||||||
|
pub iso: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Film {
|
||||||
|
pub fn new<T: Into<String>>(name: T, iso: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
iso,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Film {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("{} - ISO {}", &self.name, self.iso))
|
||||||
|
}
|
||||||
|
}
|
47
src/main.rs
47
src/main.rs
@ -1,14 +1,20 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
|
mod edit_films;
|
||||||
|
mod film;
|
||||||
mod new_roll;
|
mod new_roll;
|
||||||
mod roll;
|
mod roll;
|
||||||
mod roll_view;
|
mod roll_view;
|
||||||
|
|
||||||
use eframe::egui;
|
use edit_films::EditFilmsWindow;
|
||||||
|
use eframe::egui::{self, menu, Button};
|
||||||
|
use film::{Film, FilmKey};
|
||||||
use new_roll::NewRollWindow;
|
use new_roll::NewRollWindow;
|
||||||
use roll::Roll;
|
use roll::Roll;
|
||||||
use roll_view::RollViewWindow;
|
use roll_view::RollViewWindow;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use smart_default::SmartDefault;
|
||||||
|
use stash::Stash;
|
||||||
|
|
||||||
fn main() -> Result<(), eframe::Error> {
|
fn main() -> Result<(), eframe::Error> {
|
||||||
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
|
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
|
||||||
@ -23,23 +29,32 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default)]
|
#[derive(Serialize, Deserialize, SmartDefault)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub rolls: Vec<Roll>,
|
pub rolls: Vec<Roll>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub films: Stash<Film, FilmKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
state: AppState,
|
state: AppState,
|
||||||
roll_views: Vec<RollViewWindow>,
|
roll_views: Vec<RollViewWindow>,
|
||||||
new_roll_window: Option<NewRollWindow>,
|
new_roll_window: Option<NewRollWindow>,
|
||||||
|
edit_films_window: Option<EditFilmsWindow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MyApp {
|
impl MyApp {
|
||||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
|
let state = if cc.storage.unwrap().get_string("state").is_none() {
|
||||||
|
AppState::default()
|
||||||
|
} else {
|
||||||
|
eframe::get_value(cc.storage.unwrap(), "state").unwrap()
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
state: eframe::get_value(cc.storage.unwrap(), "state").unwrap_or_default(),
|
state,
|
||||||
roll_views: Vec::new(),
|
roll_views: Vec::new(),
|
||||||
new_roll_window: None,
|
new_roll_window: None,
|
||||||
|
edit_films_window: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,18 +65,31 @@ impl eframe::App for MyApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
|
egui::TopBottomPanel::top("menu_bar_panel").show(ctx, |ui| {
|
||||||
|
menu::bar(ui, |ui| {
|
||||||
|
ui.menu_button("View", |ui| {
|
||||||
|
if ui.add_enabled(self.edit_films_window.is_none(), Button::new("Edit films")).clicked() {
|
||||||
|
self.edit_films_window = Some(EditFilmsWindow::new());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("Film Manager");
|
ui.heading("Film Manager");
|
||||||
ui.label("Rolls:");
|
ui.label("Rolls:");
|
||||||
for (i, roll) in self.state.rolls.iter().enumerate() {
|
for (i, roll) in self.state.rolls.iter().enumerate() {
|
||||||
if ui.button(roll.short_str()).clicked()
|
let has_view = self.roll_views.iter().any(|view| view.roll() == i);
|
||||||
&& self.roll_views.iter().find(|v| v.roll() == i).is_none()
|
if ui.add_enabled(!has_view, Button::new(roll.short_str())).clicked()
|
||||||
|
&& !has_view
|
||||||
{
|
{
|
||||||
self.roll_views.push(RollViewWindow::new(i));
|
self.roll_views.push(RollViewWindow::new(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ui.button("Add").clicked() && self.new_roll_window.is_none() {
|
if ui
|
||||||
self.new_roll_window = Some(NewRollWindow::default());
|
.add_enabled(self.new_roll_window.is_none(), egui::Button::new("Add"))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
self.new_roll_window = Some(NewRollWindow::new(&self.state));
|
||||||
}
|
}
|
||||||
self.roll_views
|
self.roll_views
|
||||||
.retain_mut(|win| !win.draw(ctx, &mut self.state));
|
.retain_mut(|win| !win.draw(ctx, &mut self.state));
|
||||||
@ -70,6 +98,11 @@ impl eframe::App for MyApp {
|
|||||||
self.new_roll_window = None;
|
self.new_roll_window = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(edit_films_window) = self.edit_films_window.as_mut() {
|
||||||
|
if edit_films_window.draw(ctx, &mut self.state) {
|
||||||
|
self.edit_films_window = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,35 @@
|
|||||||
use chrono::{Local, NaiveDate};
|
use chrono::{Local, NaiveDate};
|
||||||
use eframe::{
|
use eframe::{
|
||||||
egui::{self, Window, DragValue},
|
egui::{self, DragValue, Window},
|
||||||
epaint::Color32,
|
epaint::Color32,
|
||||||
};
|
};
|
||||||
use egui_datepicker::DatePicker;
|
use egui_datepicker::DatePicker;
|
||||||
|
|
||||||
use crate::{roll::Roll, AppState};
|
use crate::{film::FilmKey, roll::Roll, AppState};
|
||||||
|
|
||||||
pub struct NewRollWindow {
|
pub struct NewRollWindow {
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
desc: String,
|
desc: String,
|
||||||
date: NaiveDate,
|
date: NaiveDate,
|
||||||
|
film: FilmKey,
|
||||||
exps: u8,
|
exps: u8,
|
||||||
show_id_req_err: bool,
|
show_id_req_err: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NewRollWindow {
|
impl NewRollWindow {
|
||||||
fn default() -> Self {
|
pub fn new(app_state: &AppState) -> Self {
|
||||||
|
let film = if app_state.films.is_empty() {
|
||||||
|
FilmKey::from(0) // Create a dummy key so the error window can be shown
|
||||||
|
} else {
|
||||||
|
app_state.films.iter().next().unwrap().0
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
id: String::new(),
|
id: String::new(),
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
desc: String::new(),
|
desc: String::new(),
|
||||||
date: Local::now().date_naive(),
|
date: Local::now().date_naive(),
|
||||||
|
film,
|
||||||
exps: 24,
|
exps: 24,
|
||||||
show_id_req_err: false,
|
show_id_req_err: false,
|
||||||
}
|
}
|
||||||
@ -33,6 +40,17 @@ impl NewRollWindow {
|
|||||||
pub fn draw(&mut self, ctx: &egui::Context, app_state: &mut AppState) -> bool {
|
pub fn draw(&mut self, ctx: &egui::Context, app_state: &mut AppState) -> bool {
|
||||||
let mut close_unclicked = true;
|
let mut close_unclicked = true;
|
||||||
let mut close_window = false;
|
let mut close_window = false;
|
||||||
|
if app_state.films.is_empty() {
|
||||||
|
Window::new("Error")
|
||||||
|
.open(&mut close_unclicked)
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
ui.heading("No films are available. Please add at least one film.");
|
||||||
|
if ui.button("OK").clicked() {
|
||||||
|
close_window = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return !close_unclicked || close_window;
|
||||||
|
}
|
||||||
Window::new("New Roll")
|
Window::new("New Roll")
|
||||||
.open(&mut close_unclicked)
|
.open(&mut close_unclicked)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
@ -62,6 +80,16 @@ impl NewRollWindow {
|
|||||||
ui.add(DragValue::new(&mut self.exps).clamp_range(1..=50))
|
ui.add(DragValue::new(&mut self.exps).clamp_range(1..=50))
|
||||||
.labelled_by(label.id);
|
.labelled_by(label.id);
|
||||||
});
|
});
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Film: ");
|
||||||
|
egui::ComboBox::from_id_source("new_roll_film")
|
||||||
|
.selected_text(format!("{}", &app_state.films[self.film]))
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
for (i, film) in &app_state.films {
|
||||||
|
ui.selectable_value(&mut self.film, i, film.to_string());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
if ui.button("Submit").clicked() {
|
if ui.button("Submit").clicked() {
|
||||||
if self.id.is_empty() {
|
if self.id.is_empty() {
|
||||||
self.show_id_req_err = true;
|
self.show_id_req_err = true;
|
||||||
@ -71,6 +99,7 @@ impl NewRollWindow {
|
|||||||
self.name.clone(),
|
self.name.clone(),
|
||||||
self.desc.clone(),
|
self.desc.clone(),
|
||||||
self.date,
|
self.date,
|
||||||
|
self.film,
|
||||||
self.exps,
|
self.exps,
|
||||||
));
|
));
|
||||||
close_window = true;
|
close_window = true;
|
||||||
|
16
src/roll.rs
16
src/roll.rs
@ -1,6 +1,8 @@
|
|||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::film::FilmKey;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Exposure {
|
pub struct Exposure {
|
||||||
pub num: u8,
|
pub num: u8,
|
||||||
@ -16,14 +18,21 @@ pub struct Exposure {
|
|||||||
pub struct Roll {
|
pub struct Roll {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[serde(default)]
|
|
||||||
pub desc: String,
|
pub desc: String,
|
||||||
pub date: NaiveDate,
|
pub date: NaiveDate,
|
||||||
|
pub film: FilmKey,
|
||||||
pub exposures: Vec<Exposure>,
|
pub exposures: Vec<Exposure>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Roll {
|
impl Roll {
|
||||||
pub fn new(id: String, name: String, desc: String, date: NaiveDate, num_exposures: u8) -> Self {
|
pub fn new(
|
||||||
|
id: String,
|
||||||
|
name: String,
|
||||||
|
desc: String,
|
||||||
|
date: NaiveDate,
|
||||||
|
film: FilmKey,
|
||||||
|
num_exposures: u8,
|
||||||
|
) -> Self {
|
||||||
let mut exposures = Vec::new();
|
let mut exposures = Vec::new();
|
||||||
for num in 1..=num_exposures {
|
for num in 1..=num_exposures {
|
||||||
exposures.push(Exposure {
|
exposures.push(Exposure {
|
||||||
@ -31,13 +40,14 @@ impl Roll {
|
|||||||
printed: false,
|
printed: false,
|
||||||
damaged: false,
|
damaged: false,
|
||||||
paper: None,
|
paper: None,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
desc,
|
desc,
|
||||||
date,
|
date,
|
||||||
|
film,
|
||||||
exposures,
|
exposures,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use eframe::{
|
use eframe::{
|
||||||
egui::{self, RichText, Window},
|
egui::{self, Button, RichText, Window},
|
||||||
epaint::Color32,
|
epaint::Color32,
|
||||||
};
|
};
|
||||||
use egui_datepicker::DatePicker;
|
use egui_datepicker::DatePicker;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::AppState;
|
use crate::{film::FilmKey, AppState};
|
||||||
|
|
||||||
pub struct RollViewWindow {
|
pub struct RollViewWindow {
|
||||||
roll: usize,
|
roll: usize,
|
||||||
@ -20,6 +20,8 @@ pub struct RollViewWindow {
|
|||||||
edit_desc: String,
|
edit_desc: String,
|
||||||
editing_date: bool,
|
editing_date: bool,
|
||||||
edit_date: NaiveDate,
|
edit_date: NaiveDate,
|
||||||
|
editing_film: bool,
|
||||||
|
edit_film: FilmKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RollViewWindow {
|
impl RollViewWindow {
|
||||||
@ -36,6 +38,8 @@ impl RollViewWindow {
|
|||||||
edit_desc: String::new(),
|
edit_desc: String::new(),
|
||||||
editing_date: false,
|
editing_date: false,
|
||||||
edit_date: NaiveDate::default(),
|
edit_date: NaiveDate::default(),
|
||||||
|
editing_film: false,
|
||||||
|
edit_film: FilmKey::from(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,17 +91,19 @@ impl RollViewWindow {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if self.editing_desc {
|
if self.editing_desc {
|
||||||
let label = ui.horizontal(|ui| {
|
let label = ui
|
||||||
let label = ui.label("Description: ");
|
.horizontal(|ui| {
|
||||||
if ui.button("Done").clicked() {
|
let label = ui.label("Description: ");
|
||||||
roll.desc = self.edit_desc.clone();
|
if ui.button("Done").clicked() {
|
||||||
self.editing_desc = false;
|
roll.desc = self.edit_desc.clone();
|
||||||
}
|
self.editing_desc = false;
|
||||||
if ui.button("Cancel").clicked() {
|
}
|
||||||
self.editing_desc = false;
|
if ui.button("Cancel").clicked() {
|
||||||
}
|
self.editing_desc = false;
|
||||||
label
|
}
|
||||||
}).inner;
|
label
|
||||||
|
})
|
||||||
|
.inner;
|
||||||
ui.text_edit_multiline(&mut self.edit_desc)
|
ui.text_edit_multiline(&mut self.edit_desc)
|
||||||
.labelled_by(label.id);
|
.labelled_by(label.id);
|
||||||
} else {
|
} else {
|
||||||
@ -136,6 +142,31 @@ impl RollViewWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
if self.editing_film {
|
||||||
|
ui.label("Film: ");
|
||||||
|
egui::ComboBox::from_id_source("new_roll_film")
|
||||||
|
.selected_text(format!("{}", app_state.films[self.edit_film]))
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
for (i, film) in &app_state.films {
|
||||||
|
ui.selectable_value(&mut self.edit_film, i, film.to_string());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ui.button("Done").clicked() {
|
||||||
|
roll.film = self.edit_film;
|
||||||
|
self.editing_film = false;
|
||||||
|
}
|
||||||
|
if ui.button("Cancel").clicked() {
|
||||||
|
self.editing_film = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ui.label(format!("Film: {}", &app_state.films[roll.film]));
|
||||||
|
if ui.button("Edit").clicked() {
|
||||||
|
self.editing_film = true;
|
||||||
|
self.edit_film = roll.film;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
ui.label("Exposures:");
|
ui.label("Exposures:");
|
||||||
ui.horizontal_top(|ui| {
|
ui.horizontal_top(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
@ -167,7 +198,10 @@ impl RollViewWindow {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if ui.button("Delete").clicked() {
|
if ui
|
||||||
|
.add_enabled(!self.confirm_delete, Button::new("Delete"))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
self.confirm_delete = true;
|
self.confirm_delete = true;
|
||||||
}
|
}
|
||||||
if self.confirm_delete {
|
if self.confirm_delete {
|
||||||
@ -176,13 +210,15 @@ impl RollViewWindow {
|
|||||||
"Really delete roll {}?",
|
"Really delete roll {}?",
|
||||||
app_state.rolls[self.roll].id
|
app_state.rolls[self.roll].id
|
||||||
));
|
));
|
||||||
if ui.button("No").clicked() {
|
ui.horizontal(|ui| {
|
||||||
self.confirm_delete = false;
|
if ui.button("No").clicked() {
|
||||||
}
|
self.confirm_delete = false;
|
||||||
if ui.button("Yes").clicked() {
|
}
|
||||||
app_state.rolls.remove(self.roll);
|
if ui.button("Yes").clicked() {
|
||||||
close_window = true;
|
app_state.rolls.remove(self.roll);
|
||||||
}
|
close_window = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user