Add Adjustments, Watermark, Rename wizard steps; expand to 10-step wizard

- New step_adjustments: rotation (5 options) and flip (3 options)
- New step_watermark: text/image watermark with position, opacity, font size
- New step_rename: prefix/suffix/counter with live preview and template engine
- Updated step_metadata: added Custom mode with per-category checkboxes
  (GPS, camera, software, timestamps, copyright) with show/hide toggle
- Expanded JobConfig with all operation fields (watermark, rename, metadata custom)
- Updated wizard from 7 to 10 steps in correct pipeline order
- Fixed page index references from 6 to 9 for output step
- Added MetadataMode::Custom handling in preset builder and output summary
This commit is contained in:
2026-03-06 12:15:02 +02:00
parent a7f1df2ba5
commit 8154324929
7 changed files with 796 additions and 12 deletions

View File

@@ -69,11 +69,71 @@ pub fn build_metadata_page(state: &AppState) -> adw::NavigationPage {
keep_all_row.add_suffix(&keep_all_check);
keep_all_row.set_activatable_widget(Some(&keep_all_check));
let custom_row = adw::ActionRow::builder()
.title("Custom")
.subtitle("Choose exactly which metadata categories to strip")
.activatable(true)
.build();
custom_row.add_prefix(&gtk::Image::from_icon_name("emblem-system-symbolic"));
let custom_check = gtk::CheckButton::new();
custom_check.set_group(Some(&strip_all_check));
custom_check.set_active(cfg.metadata_mode == MetadataMode::Custom);
custom_row.add_suffix(&custom_check);
custom_row.set_activatable_widget(Some(&custom_check));
presets_group.add(&strip_all_row);
presets_group.add(&privacy_row);
presets_group.add(&keep_all_row);
presets_group.add(&custom_row);
content.append(&presets_group);
// Custom category checkboxes
let custom_group = adw::PreferencesGroup::builder()
.title("Custom Categories")
.description("Select which metadata categories to strip")
.build();
let gps_row = adw::SwitchRow::builder()
.title("GPS / Location")
.subtitle("GPS coordinates, location name, altitude")
.active(cfg.strip_gps)
.build();
let camera_row = adw::SwitchRow::builder()
.title("Camera Info")
.subtitle("Camera model, serial number, lens data")
.active(cfg.strip_camera)
.build();
let software_row = adw::SwitchRow::builder()
.title("Software")
.subtitle("Editing software, processing history")
.active(cfg.strip_software)
.build();
let timestamps_row = adw::SwitchRow::builder()
.title("Timestamps")
.subtitle("Date taken, date modified, date digitized")
.active(cfg.strip_timestamps)
.build();
let copyright_row = adw::SwitchRow::builder()
.title("Copyright / Author")
.subtitle("Copyright notice, artist name, credits")
.active(cfg.strip_copyright)
.build();
custom_group.add(&gps_row);
custom_group.add(&camera_row);
custom_group.add(&software_row);
custom_group.add(&timestamps_row);
custom_group.add(&copyright_row);
// Only show custom group when Custom mode is selected
custom_group.set_visible(cfg.metadata_mode == MetadataMode::Custom);
content.append(&custom_group);
drop(cfg);
// Wire signals
@@ -85,28 +145,76 @@ pub fn build_metadata_page(state: &AppState) -> adw::NavigationPage {
}
{
let jc = state.job_config.clone();
let cg = custom_group.clone();
strip_all_check.connect_toggled(move |check| {
if check.is_active() {
jc.borrow_mut().metadata_mode = MetadataMode::StripAll;
cg.set_visible(false);
}
});
}
{
let jc = state.job_config.clone();
let cg = custom_group.clone();
privacy_check.connect_toggled(move |check| {
if check.is_active() {
jc.borrow_mut().metadata_mode = MetadataMode::Privacy;
cg.set_visible(false);
}
});
}
{
let jc = state.job_config.clone();
let cg = custom_group.clone();
keep_all_check.connect_toggled(move |check| {
if check.is_active() {
jc.borrow_mut().metadata_mode = MetadataMode::KeepAll;
cg.set_visible(false);
}
});
}
{
let jc = state.job_config.clone();
let cg = custom_group;
custom_check.connect_toggled(move |check| {
if check.is_active() {
jc.borrow_mut().metadata_mode = MetadataMode::Custom;
cg.set_visible(true);
}
});
}
// Wire custom category toggles
{
let jc = state.job_config.clone();
gps_row.connect_active_notify(move |row| {
jc.borrow_mut().strip_gps = row.is_active();
});
}
{
let jc = state.job_config.clone();
camera_row.connect_active_notify(move |row| {
jc.borrow_mut().strip_camera = row.is_active();
});
}
{
let jc = state.job_config.clone();
software_row.connect_active_notify(move |row| {
jc.borrow_mut().strip_software = row.is_active();
});
}
{
let jc = state.job_config.clone();
timestamps_row.connect_active_notify(move |row| {
jc.borrow_mut().strip_timestamps = row.is_active();
});
}
{
let jc = state.job_config.clone();
copyright_row.connect_active_notify(move |row| {
jc.borrow_mut().strip_copyright = row.is_active();
});
}
scrolled.set_child(Some(&content));