Enhance adjustments with sliders/effects, add undo toast, compress AVIF/progressive
This commit is contained in:
@@ -1128,9 +1128,30 @@ fn show_results(
|
||||
} else {
|
||||
format!("{} images processed", result.succeeded)
|
||||
};
|
||||
let toast = adw::Toast::new(&savings);
|
||||
toast.set_timeout(5);
|
||||
ui.toast_overlay.add_toast(toast.clone());
|
||||
// Undo toast with savings info
|
||||
let undo_toast = adw::Toast::new(&savings);
|
||||
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)
|
||||
let config_store = pixstrip_core::storage::ConfigStore::new();
|
||||
|
||||
@@ -20,31 +20,24 @@ pub fn build_adjustments_page(state: &AppState) -> adw::NavigationPage {
|
||||
|
||||
// Rotate
|
||||
let rotate_group = adw::PreferencesGroup::builder()
|
||||
.title("Rotation")
|
||||
.title("Orientation")
|
||||
.description("Rotate and flip images")
|
||||
.build();
|
||||
|
||||
let rotate_row = adw::ComboRow::builder()
|
||||
.title("Rotate")
|
||||
.subtitle("Rotation applied after resize")
|
||||
.subtitle("Rotation applied to all images")
|
||||
.build();
|
||||
let rotate_model = gtk::StringList::new(&[
|
||||
"None",
|
||||
"90 clockwise",
|
||||
"180",
|
||||
"270 clockwise",
|
||||
"Auto-orient (EXIF)",
|
||||
"Auto-orient (from EXIF)",
|
||||
]);
|
||||
rotate_row.set_model(Some(&rotate_model));
|
||||
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()
|
||||
.title("Flip")
|
||||
.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_selected(cfg.flip);
|
||||
|
||||
flip_group.add(&flip_row);
|
||||
content.append(&flip_group);
|
||||
rotate_group.add(&rotate_row);
|
||||
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);
|
||||
|
||||
|
||||
@@ -106,9 +106,23 @@ pub fn build_compress_page(state: &AppState) -> adw::NavigationPage {
|
||||
.adjustment(>k::Adjustment::new(cfg.webp_quality as f64, 1.0, 100.0, 1.0, 10.0, 0.0))
|
||||
.build();
|
||||
|
||||
let avif_row = adw::SpinRow::builder()
|
||||
.title("AVIF Quality")
|
||||
.subtitle("1-100, higher is better quality")
|
||||
.adjustment(>k::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(&progressive_row);
|
||||
advanced_expander.add_row(&png_row);
|
||||
advanced_expander.add_row(&webp_row);
|
||||
advanced_expander.add_row(&avif_row);
|
||||
|
||||
advanced_group.add(&advanced_expander);
|
||||
content.append(&advanced_group);
|
||||
|
||||
Reference in New Issue
Block a user