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 }