mirror of
https://github.com/storytold/lightcraft.git
synced 2026-11-01 05:57:09 -06:00
LR-BEHAV-DIALOGS: the confirm label, the slideshow export body and the contact sheet body stay under the complexity limit
main denies cognitive complexity above 30: ok_label (now with the Export count), slideshow_export_body and contact_sheet_body each split out one part (the fixed labels, the summary line and the size rows). No behavior change.
This commit is contained in:
@@ -329,16 +329,24 @@ fn cancel_label(dlg: &Dialog, sam: &SamState) -> &'static str {
|
||||
|
||||
/// The label of a dialog's confirm button (empty: it has none).
|
||||
fn ok_label(app: &LightcraftApp, dlg: &Dialog, informational: bool, sam: &SamState) -> String {
|
||||
let label = match dlg {
|
||||
Dialog::Import { opts } => {
|
||||
let n = opts.selected_paths().len();
|
||||
let verb = if opts.copy && opts.move_files { "Move" } else { "Import" };
|
||||
return crate::i18n::tr_format!("{verb} {n} Photo{}", if n == 1 { "" } else { "s" }, verb = crate::i18n::tr(verb), n = n);
|
||||
}
|
||||
Dialog::Export { .. } => {
|
||||
let n = app.session.selection.ids.len().max(1);
|
||||
return crate::i18n::tr_format!("{verb} {n} Photo{}", if n == 1 { "" } else { "s" }, verb = crate::i18n::tr("Export"), n = n);
|
||||
}
|
||||
match dlg {
|
||||
Dialog::Import { opts } => photos_ok_label(if opts.copy && opts.move_files { "Move" } else { "Import" }, opts.selected_paths().len()),
|
||||
Dialog::Export { .. } => photos_ok_label("Export", app.session.selection.ids.len().max(1)),
|
||||
Dialog::SamModel { .. } => sam_ok_label(dlg, sam).to_string(),
|
||||
_ => fixed_ok_label(app, dlg, informational).to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// "Import 3 Photos", "Export 1 Photo": a verb and how many photos it acts on.
|
||||
fn photos_ok_label(verb: &str, n: usize) -> String {
|
||||
crate::i18n::tr_format!("{verb} {n} Photo{}", crate::i18n::plural_s(n), verb = crate::i18n::tr(verb), n = n)
|
||||
}
|
||||
|
||||
/// The confirm labels that are one fixed phrase.
|
||||
fn fixed_ok_label(app: &LightcraftApp, dlg: &Dialog, informational: bool) -> &'static str {
|
||||
match dlg {
|
||||
// worded with a count or by the SAM state: `ok_label` builds them
|
||||
Dialog::Import { .. } | Dialog::Export { .. } | Dialog::SamModel { .. } => "",
|
||||
Dialog::LightroomResult { first: Some(_), .. } => "Show in Library",
|
||||
Dialog::ContactSheet { .. } => "Choose PDF…",
|
||||
Dialog::SlideshowExport { .. } => "Export…",
|
||||
@@ -376,7 +384,6 @@ fn ok_label(app: &LightcraftApp, dlg: &Dialog, informational: bool, sam: &SamSta
|
||||
d @ Dialog::LightroomDestination { .. } => crate::lightroom_destination::ok_label(d),
|
||||
Dialog::SynchronizeFolder { .. } if informational => "Close",
|
||||
Dialog::SynchronizeFolder { .. } => "Synchronize",
|
||||
Dialog::SamModel { .. } => return sam_ok_label(dlg, sam).to_string(),
|
||||
Dialog::RenamePerson { from, to, .. } if person_rename_plan(&app.session.catalog, from, to).needs_merge => "Merge",
|
||||
Dialog::RenamePerson { .. } => "Rename",
|
||||
// the dialogs that only show something, or a model file that can't be used
|
||||
@@ -391,8 +398,7 @@ fn ok_label(app: &LightcraftApp, dlg: &Dialog, informational: bool, sam: &SamSta
|
||||
| Dialog::LightroomResult { .. }
|
||||
| Dialog::DenoiseModel { .. }
|
||||
| Dialog::FaceModel { .. } => "Close",
|
||||
};
|
||||
label.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// The label of the SAM 3 dialog's confirm button.
|
||||
@@ -1105,13 +1111,7 @@ fn contact_sheet_body(app: &mut LightcraftApp, ui: &mut egui::Ui, dlg: &mut Dial
|
||||
options.rows = options.rows.clamp(1, 10);
|
||||
let n = app.session.selected().len();
|
||||
let pages = n.div_ceil(options.columns * options.rows);
|
||||
ui.label(crate::i18n::tr_format!(
|
||||
"{n} selected photo{} · {pages} page{}",
|
||||
if n == 1 { "" } else { "s" },
|
||||
if pages == 1 { "" } else { "s" },
|
||||
n = n,
|
||||
pages = pages
|
||||
));
|
||||
ui.label(contact_sheet_summary(n, pages));
|
||||
field(ui, "Paper", |ui| {
|
||||
let c = crate::widgets::combo_box("contactSheetPaper").selected_text(&options.paper).show_ui(ui, |ui| {
|
||||
ui.selectable_value(&mut options.paper, "a4".into(), "A4");
|
||||
@@ -1131,6 +1131,11 @@ fn contact_sheet_body(app: &mut LightcraftApp, ui: &mut egui::Ui, dlg: &mut Dial
|
||||
ui.label(crate::i18n::tr("Choose a PDF destination after confirming. Print the PDF from your viewer."));
|
||||
}
|
||||
|
||||
/// "N selected photos · M pages".
|
||||
fn contact_sheet_summary(n: usize, pages: usize) -> String {
|
||||
crate::i18n::tr_format!("{n} selected photo{} · {pages} page{}", crate::i18n::plural_s(n), crate::i18n::plural_s(pages), n = n, pages = pages)
|
||||
}
|
||||
|
||||
/// The body of the Export dialog.
|
||||
fn export_body(app: &mut LightcraftApp, ui: &mut egui::Ui, t: &Tokens, dlg: &mut Dialog) {
|
||||
let Dialog::Export { opts, full_size, resize, preset_name, limit_kb, dir } = dlg else { return };
|
||||
|
||||
@@ -79,37 +79,13 @@ pub fn poll(app: &mut LightcraftApp, ctx: &egui::Context) {
|
||||
pub(super) fn slideshow_export_body(app: &mut LightcraftApp, ui: &mut egui::Ui, settings: &mut lightcraft_engine::slideshow_export::ExportSettings) {
|
||||
use lightcraft_engine::slideshow_export::{ExportSettings, Format};
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let photos = app.session.visible_cloned().len();
|
||||
let slide = app.session.slideshow.slide_duration;
|
||||
let (intro, ending) = app.session.slide_titles.durations(slide);
|
||||
let titles = usize::from(intro.is_some()) + usize::from(ending.is_some());
|
||||
let seconds = photos as f64 * slide + intro.unwrap_or(0.0) + ending.unwrap_or(0.0);
|
||||
let summary = crate::i18n::tr_format!(
|
||||
"{n} photo{} in view · {slides} slide{} · {time}",
|
||||
if photos == 1 { "" } else { "s" },
|
||||
if photos + titles == 1 { "" } else { "s" },
|
||||
n = photos,
|
||||
slides = photos + titles,
|
||||
time = format!("{}:{:02}", (seconds / 60.0).floor() as u64, (seconds % 60.0).round() as u64)
|
||||
);
|
||||
ui.label(egui::RichText::new(summary).color(t.text_dim));
|
||||
ui.label(egui::RichText::new(slideshow_summary(app)).color(t.text_dim));
|
||||
let before = settings.format;
|
||||
choices(ui, "Format", "slideshowExportFormat", &[(Format::Pdf, "PDF"), (Format::Jpeg, "JPEG"), (Format::Video, "Video")], &mut settings.format);
|
||||
if settings.format != before {
|
||||
*settings = ExportSettings { full_screen: settings.full_screen, ..ExportSettings::for_format(settings.format) };
|
||||
}
|
||||
match settings.format {
|
||||
Format::Video => {
|
||||
choices(ui, "Size", "slideshowExportSize", &[(720, "720p"), (1080, "1080p")], &mut settings.size);
|
||||
choices(ui, "Frame rate", "slideshowExportFps", &[(24, "24 fps"), (30, "30 fps")], &mut settings.fps);
|
||||
let mut webm = settings.container == "webm";
|
||||
choices(ui, "Container", "slideshowExportContainer", &[(false, "MP4"), (true, "WebM")], &mut webm);
|
||||
settings.container = if webm { "webm".into() } else { "mp4".into() };
|
||||
}
|
||||
_ => {
|
||||
choices(ui, "Size", "slideshowExportSize", &[(1024, "1024 px"), (1920, "1920 px"), (3840, "3840 px")], &mut settings.size);
|
||||
}
|
||||
}
|
||||
slideshow_size_rows(ui, settings);
|
||||
field(ui, "Quality", |ui| {
|
||||
let r = ui.add(egui::Slider::new(&mut settings.quality, 1..=100));
|
||||
crate::widgets::register(ui, "slider:slideshowExportQuality", r.rect);
|
||||
@@ -130,6 +106,46 @@ pub(super) fn slideshow_export_body(app: &mut LightcraftApp, ui: &mut egui::Ui,
|
||||
);
|
||||
}
|
||||
|
||||
/// How many photos are in view, how many slides they make with the intro and ending screens, and how long it plays.
|
||||
fn slideshow_counts(app: &mut LightcraftApp) -> (usize, usize, f64) {
|
||||
let photos = app.session.visible_cloned().len();
|
||||
let slide = app.session.slideshow.slide_duration;
|
||||
let (intro, ending) = app.session.slide_titles.durations(slide);
|
||||
let titles = usize::from(intro.is_some()) + usize::from(ending.is_some());
|
||||
(photos, photos + titles, photos as f64 * slide + intro.unwrap_or(0.0) + ending.unwrap_or(0.0))
|
||||
}
|
||||
|
||||
/// "N photos in view · M slides · m:ss".
|
||||
fn slideshow_summary(app: &mut LightcraftApp) -> String {
|
||||
let (photos, slides, seconds) = slideshow_counts(app);
|
||||
let time = format!("{}:{:02}", (seconds / 60.0).floor() as u64, (seconds % 60.0).round() as u64);
|
||||
crate::i18n::tr_format!(
|
||||
"{n} photo{} in view · {slides} slide{} · {time}",
|
||||
crate::i18n::plural_s(photos),
|
||||
crate::i18n::plural_s(slides),
|
||||
n = photos,
|
||||
slides = slides,
|
||||
time = time
|
||||
)
|
||||
}
|
||||
|
||||
/// The size choices of the chosen format, and a video's frame rate and container.
|
||||
fn slideshow_size_rows(ui: &mut egui::Ui, settings: &mut lightcraft_engine::slideshow_export::ExportSettings) {
|
||||
use lightcraft_engine::slideshow_export::Format;
|
||||
match settings.format {
|
||||
Format::Video => {
|
||||
choices(ui, "Size", "slideshowExportSize", &[(720, "720p"), (1080, "1080p")], &mut settings.size);
|
||||
choices(ui, "Frame rate", "slideshowExportFps", &[(24, "24 fps"), (30, "30 fps")], &mut settings.fps);
|
||||
let mut webm = settings.container == "webm";
|
||||
choices(ui, "Container", "slideshowExportContainer", &[(false, "MP4"), (true, "WebM")], &mut webm);
|
||||
settings.container = if webm { "webm".into() } else { "mp4".into() };
|
||||
}
|
||||
_ => {
|
||||
choices(ui, "Size", "slideshowExportSize", &[(1024, "1024 px"), (1920, "1920 px"), (3840, "3840 px")], &mut settings.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user