Add all wizard step UIs: workflow, images, resize, convert, compress, metadata, output
Full Adwaita widget-based layouts for all 7 wizard steps with PreferencesGroups, SwitchRows, SpinRows, ComboRows, FlowBoxes, ExpanderRows for social media presets, quality slider with named marks, metadata radio group, and output configuration.
This commit is contained in:
179
pixstrip-gtk/src/steps/step_workflow.rs
Normal file
179
pixstrip-gtk/src/steps/step_workflow.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
use adw::prelude::*;
|
||||
use pixstrip_core::preset::Preset;
|
||||
|
||||
pub fn build_workflow_page() -> 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();
|
||||
|
||||
// Built-in presets section
|
||||
let builtin_group = adw::PreferencesGroup::builder()
|
||||
.title("Built-in Workflows")
|
||||
.description("Select a preset to get started quickly")
|
||||
.build();
|
||||
|
||||
let builtin_flow = gtk::FlowBox::builder()
|
||||
.selection_mode(gtk::SelectionMode::Single)
|
||||
.max_children_per_line(4)
|
||||
.min_children_per_line(2)
|
||||
.row_spacing(8)
|
||||
.column_spacing(8)
|
||||
.homogeneous(true)
|
||||
.build();
|
||||
|
||||
for preset in Preset::all_builtins() {
|
||||
let card = build_preset_card(&preset);
|
||||
builtin_flow.append(&card);
|
||||
}
|
||||
|
||||
builtin_group.add(&builtin_flow);
|
||||
content.append(&builtin_group);
|
||||
|
||||
// Custom workflow section
|
||||
let custom_group = adw::PreferencesGroup::builder()
|
||||
.title("Custom Workflow")
|
||||
.description("Choose which operations to include")
|
||||
.build();
|
||||
|
||||
let custom_card = build_custom_card();
|
||||
let custom_flow = gtk::FlowBox::builder()
|
||||
.selection_mode(gtk::SelectionMode::None)
|
||||
.max_children_per_line(4)
|
||||
.min_children_per_line(2)
|
||||
.build();
|
||||
custom_flow.append(&custom_card);
|
||||
custom_group.add(&custom_flow);
|
||||
content.append(&custom_group);
|
||||
|
||||
// User presets section (initially empty)
|
||||
let user_group = adw::PreferencesGroup::builder()
|
||||
.title("Your Presets")
|
||||
.description("Import or save your own workflows")
|
||||
.build();
|
||||
|
||||
let import_button = gtk::Button::builder()
|
||||
.label("Import Preset")
|
||||
.icon_name("document-open-symbolic")
|
||||
.build();
|
||||
import_button.add_css_class("flat");
|
||||
user_group.add(&import_button);
|
||||
content.append(&user_group);
|
||||
|
||||
scrolled.set_child(Some(&content));
|
||||
|
||||
let clamp = adw::Clamp::builder()
|
||||
.maximum_size(800)
|
||||
.child(&scrolled)
|
||||
.build();
|
||||
|
||||
adw::NavigationPage::builder()
|
||||
.title("Choose a Workflow")
|
||||
.tag("step-workflow")
|
||||
.child(&clamp)
|
||||
.build()
|
||||
}
|
||||
|
||||
fn build_preset_card(preset: &Preset) -> gtk::Box {
|
||||
let card = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.spacing(8)
|
||||
.halign(gtk::Align::Center)
|
||||
.valign(gtk::Align::Start)
|
||||
.build();
|
||||
card.add_css_class("card");
|
||||
card.set_size_request(180, 120);
|
||||
|
||||
let inner = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.spacing(4)
|
||||
.margin_top(16)
|
||||
.margin_bottom(16)
|
||||
.margin_start(12)
|
||||
.margin_end(12)
|
||||
.halign(gtk::Align::Center)
|
||||
.valign(gtk::Align::Center)
|
||||
.vexpand(true)
|
||||
.build();
|
||||
|
||||
let icon = gtk::Image::builder()
|
||||
.icon_name(&preset.icon)
|
||||
.pixel_size(32)
|
||||
.build();
|
||||
|
||||
let name_label = gtk::Label::builder()
|
||||
.label(&preset.name)
|
||||
.css_classes(["heading"])
|
||||
.build();
|
||||
|
||||
let desc_label = gtk::Label::builder()
|
||||
.label(&preset.description)
|
||||
.css_classes(["caption", "dim-label"])
|
||||
.wrap(true)
|
||||
.justify(gtk::Justification::Center)
|
||||
.max_width_chars(20)
|
||||
.build();
|
||||
|
||||
inner.append(&icon);
|
||||
inner.append(&name_label);
|
||||
inner.append(&desc_label);
|
||||
card.append(&inner);
|
||||
|
||||
card
|
||||
}
|
||||
|
||||
fn build_custom_card() -> gtk::Box {
|
||||
let card = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.spacing(8)
|
||||
.halign(gtk::Align::Center)
|
||||
.valign(gtk::Align::Start)
|
||||
.build();
|
||||
card.add_css_class("card");
|
||||
card.set_size_request(180, 120);
|
||||
|
||||
let inner = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.spacing(4)
|
||||
.margin_top(16)
|
||||
.margin_bottom(16)
|
||||
.margin_start(12)
|
||||
.margin_end(12)
|
||||
.halign(gtk::Align::Center)
|
||||
.valign(gtk::Align::Center)
|
||||
.vexpand(true)
|
||||
.build();
|
||||
|
||||
let icon = gtk::Image::builder()
|
||||
.icon_name("applications-system-symbolic")
|
||||
.pixel_size(32)
|
||||
.build();
|
||||
|
||||
let name_label = gtk::Label::builder()
|
||||
.label("Custom...")
|
||||
.css_classes(["heading"])
|
||||
.build();
|
||||
|
||||
let desc_label = gtk::Label::builder()
|
||||
.label("Pick your own operations")
|
||||
.css_classes(["caption", "dim-label"])
|
||||
.wrap(true)
|
||||
.justify(gtk::Justification::Center)
|
||||
.build();
|
||||
|
||||
inner.append(&icon);
|
||||
inner.append(&name_label);
|
||||
inner.append(&desc_label);
|
||||
card.append(&inner);
|
||||
|
||||
card
|
||||
}
|
||||
Reference in New Issue
Block a user