Add visual format cards, per-image remove, shortcuts dialog, wire threads
Convert step: replace ComboRow with visual format card grid showing icon, name, and description for each format. Much more beginner-friendly. Images step: add per-image remove button on each file row so users can exclude individual images from the batch. Shortcuts: use adw::Dialog with structured layout since GtkShortcutsWindow is deprecated in GTK 4.18+. Add file management and undo shortcuts. Settings: wire thread count selection to actually save/restore the ThreadCount config value instead of always defaulting to Auto.
This commit is contained in:
@@ -28,7 +28,6 @@ pub fn build_images_page(state: &AppState) -> adw::NavigationPage {
|
||||
&& let Some(path) = file.path()
|
||||
{
|
||||
if path.is_dir() {
|
||||
// Recursively add images from directory
|
||||
let mut files = loaded_files.borrow_mut();
|
||||
add_images_from_dir(&path, &mut files);
|
||||
let count = files.len();
|
||||
@@ -106,11 +105,16 @@ fn update_count_and_list(
|
||||
.sum();
|
||||
let size_str = format_size(total_size);
|
||||
|
||||
// Walk widget tree to find and update components
|
||||
walk_loaded_widgets(widget, count, &size_str, &files);
|
||||
walk_loaded_widgets(widget, count, &size_str, &files, loaded_files);
|
||||
}
|
||||
|
||||
fn walk_loaded_widgets(widget: >k::Widget, count: usize, size_str: &str, files: &[std::path::PathBuf]) {
|
||||
fn walk_loaded_widgets(
|
||||
widget: >k::Widget,
|
||||
count: usize,
|
||||
size_str: &str,
|
||||
files: &[std::path::PathBuf],
|
||||
loaded_files: &std::rc::Rc<std::cell::RefCell<Vec<std::path::PathBuf>>>,
|
||||
) {
|
||||
if let Some(label) = widget.downcast_ref::<gtk::Label>()
|
||||
&& label.css_classes().iter().any(|c| c == "heading")
|
||||
{
|
||||
@@ -123,8 +127,8 @@ fn walk_loaded_widgets(widget: >k::Widget, count: usize, size_str: &str, files
|
||||
while let Some(row) = list_box.first_child() {
|
||||
list_box.remove(&row);
|
||||
}
|
||||
// Add rows for each file
|
||||
for path in files {
|
||||
// Add rows for each file with remove button
|
||||
for (idx, path) in files.iter().enumerate() {
|
||||
let name = path.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.unwrap_or("unknown");
|
||||
@@ -140,13 +144,45 @@ fn walk_loaded_widgets(widget: >k::Widget, count: usize, size_str: &str, files
|
||||
.subtitle(format!("{} - {}", ext, size))
|
||||
.build();
|
||||
row.add_prefix(>k::Image::from_icon_name("image-x-generic-symbolic"));
|
||||
|
||||
// Per-image remove button
|
||||
let remove_btn = gtk::Button::builder()
|
||||
.icon_name("list-remove-symbolic")
|
||||
.tooltip_text("Remove this image from batch")
|
||||
.valign(gtk::Align::Center)
|
||||
.build();
|
||||
remove_btn.add_css_class("flat");
|
||||
{
|
||||
let loaded = loaded_files.clone();
|
||||
let list = list_box.clone();
|
||||
let file_idx = idx;
|
||||
remove_btn.connect_clicked(move |_btn| {
|
||||
let mut files = loaded.borrow_mut();
|
||||
if file_idx < files.len() {
|
||||
files.remove(file_idx);
|
||||
}
|
||||
let count = files.len();
|
||||
drop(files);
|
||||
// Refresh by finding the parent stack
|
||||
if let Some(parent) = list.ancestor(gtk::Stack::static_type())
|
||||
&& let Some(stack) = parent.downcast_ref::<gtk::Stack>()
|
||||
{
|
||||
if count == 0 {
|
||||
stack.set_visible_child_name("empty");
|
||||
} else if let Some(loaded_widget) = stack.child_by_name("loaded") {
|
||||
update_count_and_list(&loaded_widget, &loaded);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
row.add_suffix(&remove_btn);
|
||||
list_box.append(&row);
|
||||
}
|
||||
}
|
||||
// Recurse
|
||||
let mut child = widget.first_child();
|
||||
while let Some(c) = child {
|
||||
walk_loaded_widgets(&c, count, size_str, files);
|
||||
walk_loaded_widgets(&c, count, size_str, files, loaded_files);
|
||||
child = c.next_sibling();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user