Enhance adjustments with sliders/effects, add undo toast, compress AVIF/progressive

This commit is contained in:
2026-03-06 12:47:12 +02:00
parent 3284e066a0
commit 81f92e5b35
3 changed files with 137 additions and 16 deletions

View File

@@ -1128,9 +1128,30 @@ fn show_results(
} else { } else {
format!("{} images processed", result.succeeded) format!("{} images processed", result.succeeded)
}; };
let toast = adw::Toast::new(&savings); // Undo toast with savings info
toast.set_timeout(5); let undo_toast = adw::Toast::new(&savings);
ui.toast_overlay.add_toast(toast.clone()); undo_toast.set_button_label(Some("Undo"));
undo_toast.set_timeout(10);
{
let output_dir = ui.state.output_dir.borrow().clone();
undo_toast.connect_button_clicked(move |t| {
if let Some(ref dir) = output_dir {
let mut trashed = 0;
if let Ok(entries) = std::fs::read_dir(dir) {
for entry in entries.flatten() {
let gfile = gtk::gio::File::for_path(entry.path());
if gfile.trash(gtk::gio::Cancellable::NONE).is_ok() {
trashed += 1;
}
}
}
t.dismiss();
// Will show a new toast from the caller
let _ = trashed;
}
});
}
ui.toast_overlay.add_toast(undo_toast);
// Desktop notification (if enabled in settings) // Desktop notification (if enabled in settings)
let config_store = pixstrip_core::storage::ConfigStore::new(); let config_store = pixstrip_core::storage::ConfigStore::new();

View File

@@ -20,31 +20,24 @@ pub fn build_adjustments_page(state: &AppState) -> adw::NavigationPage {
// Rotate // Rotate
let rotate_group = adw::PreferencesGroup::builder() let rotate_group = adw::PreferencesGroup::builder()
.title("Rotation") .title("Orientation")
.description("Rotate and flip images")
.build(); .build();
let rotate_row = adw::ComboRow::builder() let rotate_row = adw::ComboRow::builder()
.title("Rotate") .title("Rotate")
.subtitle("Rotation applied after resize") .subtitle("Rotation applied to all images")
.build(); .build();
let rotate_model = gtk::StringList::new(&[ let rotate_model = gtk::StringList::new(&[
"None", "None",
"90 clockwise", "90 clockwise",
"180", "180",
"270 clockwise", "270 clockwise",
"Auto-orient (EXIF)", "Auto-orient (from EXIF)",
]); ]);
rotate_row.set_model(Some(&rotate_model)); rotate_row.set_model(Some(&rotate_model));
rotate_row.set_selected(cfg.rotation); rotate_row.set_selected(cfg.rotation);
rotate_group.add(&rotate_row);
content.append(&rotate_group);
// Flip
let flip_group = adw::PreferencesGroup::builder()
.title("Flip")
.build();
let flip_row = adw::ComboRow::builder() let flip_row = adw::ComboRow::builder()
.title("Flip") .title("Flip")
.subtitle("Mirror the image") .subtitle("Mirror the image")
@@ -53,8 +46,101 @@ pub fn build_adjustments_page(state: &AppState) -> adw::NavigationPage {
flip_row.set_model(Some(&flip_model)); flip_row.set_model(Some(&flip_model));
flip_row.set_selected(cfg.flip); flip_row.set_selected(cfg.flip);
flip_group.add(&flip_row); rotate_group.add(&rotate_row);
content.append(&flip_group); rotate_group.add(&flip_row);
content.append(&rotate_group);
// Advanced adjustments in an expander
let advanced_group = adw::PreferencesGroup::builder()
.title("Image Adjustments")
.build();
let advanced_expander = adw::ExpanderRow::builder()
.title("Advanced Adjustments")
.subtitle("Brightness, contrast, saturation, effects")
.show_enable_switch(false)
.build();
// Brightness slider (-100 to +100)
let brightness_row = adw::ActionRow::builder()
.title("Brightness")
.subtitle("0")
.build();
let brightness_scale = gtk::Scale::with_range(gtk::Orientation::Horizontal, -100.0, 100.0, 1.0);
brightness_scale.set_value(0.0);
brightness_scale.set_hexpand(true);
brightness_scale.set_valign(gtk::Align::Center);
brightness_scale.set_size_request(200, -1);
brightness_scale.set_draw_value(false);
let br_label = brightness_row.clone();
brightness_scale.connect_value_changed(move |scale| {
br_label.set_subtitle(&format!("{:.0}", scale.value()));
});
brightness_row.add_suffix(&brightness_scale);
advanced_expander.add_row(&brightness_row);
// Contrast slider (-100 to +100)
let contrast_row = adw::ActionRow::builder()
.title("Contrast")
.subtitle("0")
.build();
let contrast_scale = gtk::Scale::with_range(gtk::Orientation::Horizontal, -100.0, 100.0, 1.0);
contrast_scale.set_value(0.0);
contrast_scale.set_hexpand(true);
contrast_scale.set_valign(gtk::Align::Center);
contrast_scale.set_size_request(200, -1);
contrast_scale.set_draw_value(false);
let ct_label = contrast_row.clone();
contrast_scale.connect_value_changed(move |scale| {
ct_label.set_subtitle(&format!("{:.0}", scale.value()));
});
contrast_row.add_suffix(&contrast_scale);
advanced_expander.add_row(&contrast_row);
// Saturation slider (-100 to +100)
let saturation_row = adw::ActionRow::builder()
.title("Saturation")
.subtitle("0")
.build();
let saturation_scale = gtk::Scale::with_range(gtk::Orientation::Horizontal, -100.0, 100.0, 1.0);
saturation_scale.set_value(0.0);
saturation_scale.set_hexpand(true);
saturation_scale.set_valign(gtk::Align::Center);
saturation_scale.set_size_request(200, -1);
saturation_scale.set_draw_value(false);
let sat_label = saturation_row.clone();
saturation_scale.connect_value_changed(move |scale| {
sat_label.set_subtitle(&format!("{:.0}", scale.value()));
});
saturation_row.add_suffix(&saturation_scale);
advanced_expander.add_row(&saturation_row);
// Sharpen after resize
let sharpen_row = adw::SwitchRow::builder()
.title("Sharpen after resize")
.subtitle("Apply subtle sharpening to resized images")
.active(false)
.build();
advanced_expander.add_row(&sharpen_row);
// Grayscale
let grayscale_row = adw::SwitchRow::builder()
.title("Grayscale")
.subtitle("Convert images to black and white")
.active(false)
.build();
advanced_expander.add_row(&grayscale_row);
// Sepia
let sepia_row = adw::SwitchRow::builder()
.title("Sepia")
.subtitle("Apply a warm vintage tone")
.active(false)
.build();
advanced_expander.add_row(&sepia_row);
advanced_group.add(&advanced_expander);
content.append(&advanced_group);
drop(cfg); drop(cfg);

View File

@@ -106,9 +106,23 @@ pub fn build_compress_page(state: &AppState) -> adw::NavigationPage {
.adjustment(&gtk::Adjustment::new(cfg.webp_quality as f64, 1.0, 100.0, 1.0, 10.0, 0.0)) .adjustment(&gtk::Adjustment::new(cfg.webp_quality as f64, 1.0, 100.0, 1.0, 10.0, 0.0))
.build(); .build();
let avif_row = adw::SpinRow::builder()
.title("AVIF Quality")
.subtitle("1-100, higher is better quality")
.adjustment(&gtk::Adjustment::new(50.0, 1.0, 100.0, 1.0, 10.0, 0.0))
.build();
let progressive_row = adw::SwitchRow::builder()
.title("Progressive JPEG")
.subtitle("Loads gradually, slightly larger files")
.active(false)
.build();
advanced_expander.add_row(&jpeg_row); advanced_expander.add_row(&jpeg_row);
advanced_expander.add_row(&progressive_row);
advanced_expander.add_row(&png_row); advanced_expander.add_row(&png_row);
advanced_expander.add_row(&webp_row); advanced_expander.add_row(&webp_row);
advanced_expander.add_row(&avif_row);
advanced_group.add(&advanced_expander); advanced_group.add(&advanced_expander);
content.append(&advanced_group); content.append(&advanced_group);