Add thumbnail selection for compression and watermark previews
This commit is contained in:
@@ -276,6 +276,53 @@ pub fn build_compress_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
preview_group.add(&size_box);
|
preview_group.add(&size_box);
|
||||||
preview_group.add(&preview_frame);
|
preview_group.add(&preview_frame);
|
||||||
|
|
||||||
|
// Thumbnail strip for selecting preview image
|
||||||
|
let thumb_scrolled = gtk::ScrolledWindow::builder()
|
||||||
|
.hscrollbar_policy(gtk::PolicyType::Automatic)
|
||||||
|
.vscrollbar_policy(gtk::PolicyType::Never)
|
||||||
|
.max_content_height(60)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let thumb_box = gtk::Box::builder()
|
||||||
|
.orientation(gtk::Orientation::Horizontal)
|
||||||
|
.spacing(4)
|
||||||
|
.margin_top(4)
|
||||||
|
.margin_bottom(4)
|
||||||
|
.halign(gtk::Align::Center)
|
||||||
|
.build();
|
||||||
|
thumb_scrolled.set_child(Some(&thumb_box));
|
||||||
|
|
||||||
|
let preview_index: Rc<RefCell<usize>> = Rc::new(RefCell::new(0));
|
||||||
|
|
||||||
|
// Populate thumbnails from loaded files
|
||||||
|
{
|
||||||
|
let files = state.loaded_files.borrow();
|
||||||
|
let max_thumbs = files.len().min(10); // Show at most 10 thumbnails
|
||||||
|
for i in 0..max_thumbs {
|
||||||
|
let pic = gtk::Picture::builder()
|
||||||
|
.content_fit(gtk::ContentFit::Cover)
|
||||||
|
.width_request(50)
|
||||||
|
.height_request(50)
|
||||||
|
.build();
|
||||||
|
pic.set_filename(Some(&files[i]));
|
||||||
|
let frame = gtk::Frame::builder()
|
||||||
|
.child(&pic)
|
||||||
|
.build();
|
||||||
|
if i == 0 {
|
||||||
|
frame.add_css_class("accent");
|
||||||
|
}
|
||||||
|
|
||||||
|
let btn = gtk::Button::builder()
|
||||||
|
.child(&frame)
|
||||||
|
.has_frame(false)
|
||||||
|
.tooltip_text(files[i].file_name().and_then(|n| n.to_str()).unwrap_or("image"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
thumb_box.append(&btn);
|
||||||
|
}
|
||||||
|
thumb_scrolled.set_visible(max_thumbs > 1);
|
||||||
|
}
|
||||||
|
|
||||||
// "No image loaded" placeholder
|
// "No image loaded" placeholder
|
||||||
let no_image_label = gtk::Label::builder()
|
let no_image_label = gtk::Label::builder()
|
||||||
.label("Add images first to see compression preview")
|
.label("Add images first to see compression preview")
|
||||||
@@ -284,6 +331,7 @@ pub fn build_compress_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
.margin_top(4)
|
.margin_top(4)
|
||||||
.build();
|
.build();
|
||||||
preview_group.add(&no_image_label);
|
preview_group.add(&no_image_label);
|
||||||
|
preview_group.add(&thumb_scrolled);
|
||||||
|
|
||||||
content.append(&preview_group);
|
content.append(&preview_group);
|
||||||
|
|
||||||
@@ -371,6 +419,7 @@ pub fn build_compress_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
let comp_label = compressed_size_label.clone();
|
let comp_label = compressed_size_label.clone();
|
||||||
let no_img_label = no_image_label.clone();
|
let no_img_label = no_image_label.clone();
|
||||||
let jc = state.job_config.clone();
|
let jc = state.job_config.clone();
|
||||||
|
let pidx = preview_index.clone();
|
||||||
|
|
||||||
Rc::new(move || {
|
Rc::new(move || {
|
||||||
let loaded = files.borrow();
|
let loaded = files.borrow();
|
||||||
@@ -380,8 +429,9 @@ pub fn build_compress_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
}
|
}
|
||||||
no_img_label.set_visible(false);
|
no_img_label.set_visible(false);
|
||||||
|
|
||||||
// Pick the first image as sample
|
// Pick the selected preview image
|
||||||
let sample_path = loaded[0].clone();
|
let idx = *pidx.borrow();
|
||||||
|
let sample_path = loaded.get(idx).cloned().unwrap_or_else(|| loaded[0].clone());
|
||||||
let cfg = jc.borrow();
|
let cfg = jc.borrow();
|
||||||
let preset = cfg.quality_preset;
|
let preset = cfg.quality_preset;
|
||||||
drop(cfg);
|
drop(cfg);
|
||||||
@@ -449,6 +499,42 @@ pub fn build_compress_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Wire thumbnail buttons to switch preview image
|
||||||
|
{
|
||||||
|
let mut child = thumb_box.first_child();
|
||||||
|
let mut idx = 0usize;
|
||||||
|
while let Some(widget) = child {
|
||||||
|
if let Some(btn) = widget.downcast_ref::<gtk::Button>() {
|
||||||
|
let pidx = preview_index.clone();
|
||||||
|
let up = update_preview.clone();
|
||||||
|
let tb = thumb_box.clone();
|
||||||
|
let current_idx = idx;
|
||||||
|
btn.connect_clicked(move |_| {
|
||||||
|
*pidx.borrow_mut() = current_idx;
|
||||||
|
up();
|
||||||
|
// Update highlight on thumbnails
|
||||||
|
let mut c = tb.first_child();
|
||||||
|
let mut j = 0usize;
|
||||||
|
while let Some(w) = c {
|
||||||
|
if let Some(b) = w.downcast_ref::<gtk::Button>() {
|
||||||
|
if let Some(f) = b.child().and_then(|c| c.downcast::<gtk::Frame>().ok()) {
|
||||||
|
if j == current_idx {
|
||||||
|
f.add_css_class("accent");
|
||||||
|
} else {
|
||||||
|
f.remove_css_class("accent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = w.next_sibling();
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
child = widget.next_sibling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Trigger initial preview load
|
// Trigger initial preview load
|
||||||
{
|
{
|
||||||
let up = update_preview.clone();
|
let up = update_preview.clone();
|
||||||
|
|||||||
@@ -237,6 +237,59 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
preview_picture.set_visible(has_files);
|
preview_picture.set_visible(has_files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Thumbnail strip for selecting preview image
|
||||||
|
let wm_thumb_box = gtk::Box::builder()
|
||||||
|
.orientation(gtk::Orientation::Horizontal)
|
||||||
|
.spacing(4)
|
||||||
|
.halign(gtk::Align::Center)
|
||||||
|
.margin_top(4)
|
||||||
|
.build();
|
||||||
|
{
|
||||||
|
let files = state.loaded_files.borrow();
|
||||||
|
let max_thumbs = files.len().min(10);
|
||||||
|
for i in 0..max_thumbs {
|
||||||
|
let pic = gtk::Picture::builder()
|
||||||
|
.content_fit(gtk::ContentFit::Cover)
|
||||||
|
.width_request(40)
|
||||||
|
.height_request(40)
|
||||||
|
.build();
|
||||||
|
pic.set_filename(Some(&files[i]));
|
||||||
|
let frame = gtk::Frame::builder()
|
||||||
|
.child(&pic)
|
||||||
|
.build();
|
||||||
|
if i == 0 { frame.add_css_class("accent"); }
|
||||||
|
|
||||||
|
let btn = gtk::Button::builder()
|
||||||
|
.child(&frame)
|
||||||
|
.has_frame(false)
|
||||||
|
.tooltip_text(files[i].file_name().and_then(|n| n.to_str()).unwrap_or("image"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let pp = preview_picture.clone();
|
||||||
|
let path = files[i].clone();
|
||||||
|
let tb = wm_thumb_box.clone();
|
||||||
|
let current_idx = i;
|
||||||
|
btn.connect_clicked(move |_| {
|
||||||
|
pp.set_filename(Some(&path));
|
||||||
|
let mut c = tb.first_child();
|
||||||
|
let mut j = 0usize;
|
||||||
|
while let Some(w) = c {
|
||||||
|
if let Some(b) = w.downcast_ref::<gtk::Button>() {
|
||||||
|
if let Some(f) = b.child().and_then(|c| c.downcast::<gtk::Frame>().ok()) {
|
||||||
|
if j == current_idx { f.add_css_class("accent"); }
|
||||||
|
else { f.remove_css_class("accent"); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = w.next_sibling();
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wm_thumb_box.append(&btn);
|
||||||
|
}
|
||||||
|
wm_thumb_box.set_visible(max_thumbs > 1);
|
||||||
|
}
|
||||||
|
|
||||||
let preview_stack = gtk::Box::builder()
|
let preview_stack = gtk::Box::builder()
|
||||||
.orientation(gtk::Orientation::Vertical)
|
.orientation(gtk::Orientation::Vertical)
|
||||||
.spacing(4)
|
.spacing(4)
|
||||||
@@ -244,6 +297,7 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
.margin_bottom(8)
|
.margin_bottom(8)
|
||||||
.build();
|
.build();
|
||||||
preview_stack.append(&preview_overlay);
|
preview_stack.append(&preview_overlay);
|
||||||
|
preview_stack.append(&wm_thumb_box);
|
||||||
preview_stack.append(&no_preview_label);
|
preview_stack.append(&no_preview_label);
|
||||||
|
|
||||||
preview_group.add(&preview_stack);
|
preview_group.add(&preview_stack);
|
||||||
|
|||||||
Reference in New Issue
Block a user