Files
pixstrip/pixstrip-gtk/src/steps/step_adjustments.rs

174 lines
5.5 KiB
Rust

use adw::prelude::*;
use crate::app::AppState;
pub fn build_adjustments_page(state: &AppState) -> adw::NavigationPage {
let scrolled = gtk::ScrolledWindow::builder()
.hscrollbar_policy(gtk::PolicyType::Never)
.vexpand(true)
.build();
let content = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.spacing(12)
.margin_top(12)
.margin_bottom(12)
.margin_start(24)
.margin_end(24)
.build();
let cfg = state.job_config.borrow();
// Rotate
let rotate_group = adw::PreferencesGroup::builder()
.title("Orientation")
.description("Rotate and flip images")
.build();
let rotate_row = adw::ComboRow::builder()
.title("Rotate")
.subtitle("Rotation applied to all images")
.build();
let rotate_model = gtk::StringList::new(&[
"None",
"90 clockwise",
"180",
"270 clockwise",
"Auto-orient (from EXIF)",
]);
rotate_row.set_model(Some(&rotate_model));
rotate_row.set_selected(cfg.rotation);
let flip_row = adw::ComboRow::builder()
.title("Flip")
.subtitle("Mirror the image")
.build();
let flip_model = gtk::StringList::new(&["None", "Horizontal", "Vertical"]);
flip_row.set_model(Some(&flip_model));
flip_row.set_selected(cfg.flip);
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);
// Wire signals
{
let jc = state.job_config.clone();
rotate_row.connect_selected_notify(move |row| {
jc.borrow_mut().rotation = row.selected();
});
}
{
let jc = state.job_config.clone();
flip_row.connect_selected_notify(move |row| {
jc.borrow_mut().flip = row.selected();
});
}
scrolled.set_child(Some(&content));
let clamp = adw::Clamp::builder()
.maximum_size(600)
.child(&scrolled)
.build();
adw::NavigationPage::builder()
.title("Adjustments")
.tag("step-adjustments")
.child(&clamp)
.build()
}