- Images step: folder drag-and-drop with recursive image scanning, per-file list with format and size info, total file size in header, supported formats label in empty state - Compress step: per-format quality controls moved into AdwExpanderRow, improved quality level descriptions - Output step: dynamic image count with total size from loaded_files, initial overwrite behavior from config - Workflow step: properly handle MetadataConfig::Custom in preset import, mapping all custom metadata fields to JobConfig
183 lines
5.9 KiB
Rust
183 lines
5.9 KiB
Rust
use adw::prelude::*;
|
|
use crate::app::AppState;
|
|
use pixstrip_core::types::QualityPreset;
|
|
|
|
pub fn build_compress_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();
|
|
|
|
// Enable toggle
|
|
let enable_row = adw::SwitchRow::builder()
|
|
.title("Enable Compression")
|
|
.subtitle("Reduce file size with quality control")
|
|
.active(cfg.compress_enabled)
|
|
.build();
|
|
|
|
let enable_group = adw::PreferencesGroup::new();
|
|
enable_group.add(&enable_row);
|
|
content.append(&enable_group);
|
|
|
|
// Quality slider
|
|
let quality_group = adw::PreferencesGroup::builder()
|
|
.title("Quality Level")
|
|
.description("Higher quality means larger files. This sets the overall quality target.")
|
|
.build();
|
|
|
|
let initial_val = match cfg.quality_preset {
|
|
QualityPreset::WebOptimized => 1.0,
|
|
QualityPreset::Low => 2.0,
|
|
QualityPreset::Medium => 3.0,
|
|
QualityPreset::High => 4.0,
|
|
QualityPreset::Maximum => 5.0,
|
|
};
|
|
|
|
let quality_scale = gtk::Scale::builder()
|
|
.orientation(gtk::Orientation::Horizontal)
|
|
.adjustment(>k::Adjustment::new(initial_val, 1.0, 5.0, 1.0, 1.0, 0.0))
|
|
.draw_value(false)
|
|
.hexpand(true)
|
|
.build();
|
|
quality_scale.set_round_digits(0);
|
|
|
|
quality_scale.add_mark(1.0, gtk::PositionType::Bottom, Some("Web"));
|
|
quality_scale.add_mark(2.0, gtk::PositionType::Bottom, Some("Low"));
|
|
quality_scale.add_mark(3.0, gtk::PositionType::Bottom, Some("Medium"));
|
|
quality_scale.add_mark(4.0, gtk::PositionType::Bottom, Some("High"));
|
|
quality_scale.add_mark(5.0, gtk::PositionType::Bottom, Some("Maximum"));
|
|
|
|
let quality_label = gtk::Label::builder()
|
|
.label(quality_description(initial_val as u32))
|
|
.css_classes(["dim-label"])
|
|
.margin_top(4)
|
|
.build();
|
|
|
|
let quality_box = gtk::Box::builder()
|
|
.orientation(gtk::Orientation::Vertical)
|
|
.spacing(4)
|
|
.margin_top(8)
|
|
.margin_bottom(8)
|
|
.margin_start(12)
|
|
.margin_end(12)
|
|
.build();
|
|
quality_box.append(&quality_scale);
|
|
quality_box.append(&quality_label);
|
|
|
|
quality_group.add(&quality_box);
|
|
content.append(&quality_group);
|
|
|
|
// Advanced options in expander
|
|
let advanced_group = adw::PreferencesGroup::builder()
|
|
.title("Advanced Options")
|
|
.build();
|
|
|
|
let advanced_expander = adw::ExpanderRow::builder()
|
|
.title("Per-Format Quality")
|
|
.subtitle("Fine-tune quality for each format individually")
|
|
.build();
|
|
|
|
let jpeg_row = adw::SpinRow::builder()
|
|
.title("JPEG Quality")
|
|
.subtitle("1-100, higher is better quality")
|
|
.adjustment(>k::Adjustment::new(cfg.jpeg_quality as f64, 1.0, 100.0, 1.0, 10.0, 0.0))
|
|
.build();
|
|
|
|
let png_row = adw::SpinRow::builder()
|
|
.title("PNG Compression Level")
|
|
.subtitle("1-6, higher is slower but smaller")
|
|
.adjustment(>k::Adjustment::new(cfg.png_level as f64, 1.0, 6.0, 1.0, 1.0, 0.0))
|
|
.build();
|
|
|
|
let webp_row = adw::SpinRow::builder()
|
|
.title("WebP Quality")
|
|
.subtitle("1-100, higher is better quality")
|
|
.adjustment(>k::Adjustment::new(cfg.webp_quality as f64, 1.0, 100.0, 1.0, 10.0, 0.0))
|
|
.build();
|
|
|
|
advanced_expander.add_row(&jpeg_row);
|
|
advanced_expander.add_row(&png_row);
|
|
advanced_expander.add_row(&webp_row);
|
|
|
|
advanced_group.add(&advanced_expander);
|
|
content.append(&advanced_group);
|
|
|
|
drop(cfg);
|
|
|
|
// Wire signals
|
|
{
|
|
let jc = state.job_config.clone();
|
|
enable_row.connect_active_notify(move |row| {
|
|
jc.borrow_mut().compress_enabled = row.is_active();
|
|
});
|
|
}
|
|
{
|
|
let jc = state.job_config.clone();
|
|
let label = quality_label;
|
|
quality_scale.connect_value_changed(move |scale| {
|
|
let val = scale.value().round() as u32;
|
|
let mut c = jc.borrow_mut();
|
|
c.quality_preset = match val {
|
|
1 => QualityPreset::WebOptimized,
|
|
2 => QualityPreset::Low,
|
|
3 => QualityPreset::Medium,
|
|
4 => QualityPreset::High,
|
|
_ => QualityPreset::Maximum,
|
|
};
|
|
label.set_label(&quality_description(val));
|
|
});
|
|
}
|
|
{
|
|
let jc = state.job_config.clone();
|
|
jpeg_row.connect_value_notify(move |row| {
|
|
jc.borrow_mut().jpeg_quality = row.value() as u8;
|
|
});
|
|
}
|
|
{
|
|
let jc = state.job_config.clone();
|
|
png_row.connect_value_notify(move |row| {
|
|
jc.borrow_mut().png_level = row.value() as u8;
|
|
});
|
|
}
|
|
{
|
|
let jc = state.job_config.clone();
|
|
webp_row.connect_value_notify(move |row| {
|
|
jc.borrow_mut().webp_quality = row.value() as u8;
|
|
});
|
|
}
|
|
|
|
scrolled.set_child(Some(&content));
|
|
|
|
let clamp = adw::Clamp::builder()
|
|
.maximum_size(600)
|
|
.child(&scrolled)
|
|
.build();
|
|
|
|
adw::NavigationPage::builder()
|
|
.title("Compress")
|
|
.tag("step-compress")
|
|
.child(&clamp)
|
|
.build()
|
|
}
|
|
|
|
fn quality_description(val: u32) -> String {
|
|
match val {
|
|
1 => "Web Optimized - smallest files, noticeable quality loss. Best for thumbnails.".into(),
|
|
2 => "Low - small files, some quality loss. Good for email attachments.".into(),
|
|
3 => "Medium - good balance of quality and size. Recommended for most uses.".into(),
|
|
4 => "High - large files, minimal quality loss. Good for printing.".into(),
|
|
_ => "Maximum - largest files, best possible quality. Archival use.".into(),
|
|
}
|
|
}
|