Enhance adjustments with sliders/effects, add undo toast, compress AVIF/progressive
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
.adjustment(>k::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(>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(&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);
|
||||||
|
|||||||
Reference in New Issue
Block a user