diff --git a/pixstrip-gtk/src/steps/step_watermark.rs b/pixstrip-gtk/src/steps/step_watermark.rs index 2aef57a..8310936 100644 --- a/pixstrip-gtk/src/steps/step_watermark.rs +++ b/pixstrip-gtk/src/steps/step_watermark.rs @@ -167,6 +167,88 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage { content.append(&position_group); + // Live preview section + let preview_group = adw::PreferencesGroup::builder() + .title("Preview") + .description("Shows how the watermark will appear on your image") + .build(); + + // Overlay container for image + watermark text + let preview_overlay = gtk::Overlay::builder() + .halign(gtk::Align::Center) + .build(); + + let preview_picture = gtk::Picture::builder() + .content_fit(gtk::ContentFit::Contain) + .width_request(300) + .height_request(200) + .build(); + preview_picture.add_css_class("card"); + preview_overlay.set_child(Some(&preview_picture)); + + // Watermark text label overlay + let watermark_label = gtk::Label::builder() + .label(&cfg.watermark_text) + .css_classes(["heading"]) + .opacity(cfg.watermark_opacity as f64) + .build(); + preview_overlay.add_overlay(&watermark_label); + + // Position the watermark label according to grid position + fn set_watermark_alignment(label: >k::Label, position: u32) { + let (h, v) = match position { + 0 => (gtk::Align::Start, gtk::Align::Start), // Top Left + 1 => (gtk::Align::Center, gtk::Align::Start), // Top Center + 2 => (gtk::Align::End, gtk::Align::Start), // Top Right + 3 => (gtk::Align::Start, gtk::Align::Center), // Middle Left + 4 => (gtk::Align::Center, gtk::Align::Center), // Center + 5 => (gtk::Align::End, gtk::Align::Center), // Middle Right + 6 => (gtk::Align::Start, gtk::Align::End), // Bottom Left + 7 => (gtk::Align::Center, gtk::Align::End), // Bottom Center + _ => (gtk::Align::End, gtk::Align::End), // Bottom Right + }; + label.set_halign(h); + label.set_valign(v); + label.set_margin_start(8); + label.set_margin_end(8); + label.set_margin_top(8); + label.set_margin_bottom(8); + } + set_watermark_alignment(&watermark_label, cfg.watermark_position); + + // Load first image from batch as preview background + { + let files = state.loaded_files.borrow(); + if let Some(first) = files.first() { + preview_picture.set_filename(Some(first)); + } + } + + // "No preview" placeholder + let no_preview_label = gtk::Label::builder() + .label("Add images to see a preview") + .css_classes(["dim-label"]) + .halign(gtk::Align::Center) + .valign(gtk::Align::Center) + .build(); + { + let has_files = !state.loaded_files.borrow().is_empty(); + no_preview_label.set_visible(!has_files); + preview_picture.set_visible(has_files); + } + + let preview_stack = gtk::Box::builder() + .orientation(gtk::Orientation::Vertical) + .spacing(4) + .margin_top(8) + .margin_bottom(8) + .build(); + preview_stack.append(&preview_overlay); + preview_stack.append(&no_preview_label); + + preview_group.add(&preview_stack); + content.append(&preview_group); + // Advanced options let advanced_group = adw::PreferencesGroup::builder() .title("Advanced") @@ -242,8 +324,11 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage { } { let jc = state.job_config.clone(); + let wl = watermark_label.clone(); text_row.connect_changed(move |row| { - jc.borrow_mut().watermark_text = row.text().to_string(); + let text = row.text().to_string(); + wl.set_label(&text); + jc.borrow_mut().watermark_text = text; }); } { @@ -258,10 +343,12 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage { let label = position_label.clone(); let names = position_names; let all_buttons = buttons.clone(); + let wl = watermark_label.clone(); btn.connect_toggled(move |b| { if b.is_active() { jc.borrow_mut().watermark_position = i as u32; label.set_label(names[i]); + set_watermark_alignment(&wl, i as u32); // Update icons for (j, other) in all_buttons.iter().enumerate() { let icon_name = if j == i { @@ -276,8 +363,11 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage { } { let jc = state.job_config.clone(); + let wl = watermark_label.clone(); opacity_row.connect_value_notify(move |row| { - jc.borrow_mut().watermark_opacity = row.value() as f32; + let val = row.value() as f32; + wl.set_opacity(val as f64); + jc.borrow_mut().watermark_opacity = val; }); } // Wire image chooser button