Add rename template presets and watermark color picker
- Rename step: quick-fill buttons for common patterns (Date+Name, EXIF Date+Name, Sequential, Dimensions, Camera+Date, Web-safe) - Watermark step: color picker in advanced options using ColorDialogButton - Add watermark_color field to JobConfig, wire through to core
This commit is contained in:
@@ -65,6 +65,7 @@ pub struct JobConfig {
|
|||||||
pub watermark_position: u32,
|
pub watermark_position: u32,
|
||||||
pub watermark_opacity: f32,
|
pub watermark_opacity: f32,
|
||||||
pub watermark_font_size: f32,
|
pub watermark_font_size: f32,
|
||||||
|
pub watermark_color: [u8; 4],
|
||||||
pub watermark_use_image: bool,
|
pub watermark_use_image: bool,
|
||||||
// Rename
|
// Rename
|
||||||
pub rename_enabled: bool,
|
pub rename_enabled: bool,
|
||||||
@@ -312,6 +313,7 @@ fn build_ui(app: &adw::Application) {
|
|||||||
watermark_position: 8, // BottomRight
|
watermark_position: 8, // BottomRight
|
||||||
watermark_opacity: 0.5,
|
watermark_opacity: 0.5,
|
||||||
watermark_font_size: 24.0,
|
watermark_font_size: 24.0,
|
||||||
|
watermark_color: [255, 255, 255, 255],
|
||||||
watermark_use_image: false,
|
watermark_use_image: false,
|
||||||
rename_enabled: if remember { sess_state.rename_enabled.unwrap_or(false) } else { false },
|
rename_enabled: if remember { sess_state.rename_enabled.unwrap_or(false) } else { false },
|
||||||
rename_prefix: String::new(),
|
rename_prefix: String::new(),
|
||||||
@@ -1495,7 +1497,7 @@ fn run_processing(_window: &adw::ApplicationWindow, ui: &WizardUi) {
|
|||||||
position,
|
position,
|
||||||
font_size: cfg.watermark_font_size,
|
font_size: cfg.watermark_font_size,
|
||||||
opacity: cfg.watermark_opacity,
|
opacity: cfg.watermark_opacity,
|
||||||
color: [255, 255, 255, 255],
|
color: cfg.watermark_color,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2348,7 +2350,7 @@ fn build_preset_from_config(cfg: &JobConfig, name: &str) -> pixstrip_core::prese
|
|||||||
position,
|
position,
|
||||||
font_size: cfg.watermark_font_size,
|
font_size: cfg.watermark_font_size,
|
||||||
opacity: cfg.watermark_opacity,
|
opacity: cfg.watermark_opacity,
|
||||||
color: [255, 255, 255, 255],
|
color: cfg.watermark_color,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -101,6 +101,44 @@ pub fn build_rename_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
.text(&cfg.rename_template)
|
.text(&cfg.rename_template)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// Preset template quick-fill buttons
|
||||||
|
let presets_flow = gtk::FlowBox::builder()
|
||||||
|
.selection_mode(gtk::SelectionMode::None)
|
||||||
|
.max_children_per_line(4)
|
||||||
|
.min_children_per_line(2)
|
||||||
|
.row_spacing(4)
|
||||||
|
.column_spacing(4)
|
||||||
|
.margin_top(4)
|
||||||
|
.margin_bottom(8)
|
||||||
|
.margin_start(12)
|
||||||
|
.margin_end(12)
|
||||||
|
.homogeneous(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let preset_templates = [
|
||||||
|
("Date + Name", "{date}_{name}"),
|
||||||
|
("EXIF Date + Name", "{exif_date}_{name}"),
|
||||||
|
("Sequential", "{name}_{counter:4}"),
|
||||||
|
("Dimensions", "{name}_{width}x{height}"),
|
||||||
|
("Camera + Date", "{camera}_{exif_date}_{counter:3}"),
|
||||||
|
("Web-safe", "{name}_web"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (label, template) in &preset_templates {
|
||||||
|
let btn = gtk::Button::builder()
|
||||||
|
.label(*label)
|
||||||
|
.tooltip_text(*template)
|
||||||
|
.build();
|
||||||
|
btn.add_css_class("pill");
|
||||||
|
|
||||||
|
let tr = template_row.clone();
|
||||||
|
let tmpl = template.to_string();
|
||||||
|
btn.connect_clicked(move |_| {
|
||||||
|
tr.set_text(&tmpl);
|
||||||
|
});
|
||||||
|
presets_flow.append(&btn);
|
||||||
|
}
|
||||||
|
|
||||||
let help_label = gtk::Label::builder()
|
let help_label = gtk::Label::builder()
|
||||||
.label(
|
.label(
|
||||||
"Available variables:\n\
|
"Available variables:\n\
|
||||||
@@ -145,6 +183,7 @@ pub fn build_rename_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
regex_group.add(&replace_row);
|
regex_group.add(&replace_row);
|
||||||
|
|
||||||
advanced_group.add(&template_row);
|
advanced_group.add(&template_row);
|
||||||
|
advanced_group.add(&presets_flow);
|
||||||
advanced_group.add(&help_label);
|
advanced_group.add(&help_label);
|
||||||
advanced_group.add(&case_row);
|
advanced_group.add(&case_row);
|
||||||
content.append(&advanced_group);
|
content.append(&advanced_group);
|
||||||
|
|||||||
@@ -315,6 +315,29 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
.expanded(state.detailed_mode)
|
.expanded(state.detailed_mode)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// Text color picker
|
||||||
|
let color_row = adw::ActionRow::builder()
|
||||||
|
.title("Text Color")
|
||||||
|
.subtitle("Color of the watermark text")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let initial_color = gtk::gdk::RGBA::new(
|
||||||
|
cfg.watermark_color[0] as f32 / 255.0,
|
||||||
|
cfg.watermark_color[1] as f32 / 255.0,
|
||||||
|
cfg.watermark_color[2] as f32 / 255.0,
|
||||||
|
cfg.watermark_color[3] as f32 / 255.0,
|
||||||
|
);
|
||||||
|
let color_dialog = gtk::ColorDialog::builder()
|
||||||
|
.with_alpha(true)
|
||||||
|
.title("Watermark Text Color")
|
||||||
|
.build();
|
||||||
|
let color_button = gtk::ColorDialogButton::builder()
|
||||||
|
.dialog(&color_dialog)
|
||||||
|
.rgba(&initial_color)
|
||||||
|
.valign(gtk::Align::Center)
|
||||||
|
.build();
|
||||||
|
color_row.add_suffix(&color_button);
|
||||||
|
|
||||||
let opacity_row = adw::SpinRow::builder()
|
let opacity_row = adw::SpinRow::builder()
|
||||||
.title("Opacity")
|
.title("Opacity")
|
||||||
.subtitle("0.0 (invisible) to 1.0 (fully opaque)")
|
.subtitle("0.0 (invisible) to 1.0 (fully opaque)")
|
||||||
@@ -347,6 +370,7 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
.adjustment(>k::Adjustment::new(20.0, 1.0, 100.0, 1.0, 5.0, 0.0))
|
.adjustment(>k::Adjustment::new(20.0, 1.0, 100.0, 1.0, 5.0, 0.0))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
advanced_expander.add_row(&color_row);
|
||||||
advanced_expander.add_row(&opacity_row);
|
advanced_expander.add_row(&opacity_row);
|
||||||
advanced_expander.add_row(&rotation_row);
|
advanced_expander.add_row(&rotation_row);
|
||||||
advanced_expander.add_row(&tiled_row);
|
advanced_expander.add_row(&tiled_row);
|
||||||
@@ -424,6 +448,19 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage {
|
|||||||
jc.borrow_mut().watermark_opacity = val;
|
jc.borrow_mut().watermark_opacity = val;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Wire color picker
|
||||||
|
{
|
||||||
|
let jc = state.job_config.clone();
|
||||||
|
color_button.connect_rgba_notify(move |btn| {
|
||||||
|
let c = btn.rgba();
|
||||||
|
jc.borrow_mut().watermark_color = [
|
||||||
|
(c.red() * 255.0) as u8,
|
||||||
|
(c.green() * 255.0) as u8,
|
||||||
|
(c.blue() * 255.0) as u8,
|
||||||
|
(c.alpha() * 255.0) as u8,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
// Wire image chooser button
|
// Wire image chooser button
|
||||||
{
|
{
|
||||||
let jc = state.job_config.clone();
|
let jc = state.job_config.clone();
|
||||||
|
|||||||
Reference in New Issue
Block a user