diff --git a/data/org.gnome.Loupe.gschema.xml.in b/data/org.gnome.Loupe.gschema.xml.in
index 13ac2ea..9a9d1d5 100644
--- a/data/org.gnome.Loupe.gschema.xml.in
+++ b/data/org.gnome.Loupe.gschema.xml.in
@@ -5,5 +5,9 @@
false
Show the image properties sidebar
+
+ true
+ Copy the image to the clipboard after annotation changes
+
diff --git a/src/widgets/image.rs b/src/widgets/image.rs
index 94535f2..d5a0d88 100644
--- a/src/widgets/image.rs
+++ b/src/widgets/image.rs
@@ -459,13 +459,24 @@ impl LpImage {
}
pub fn undo_stroke(&self) {
- self.imp().strokes.borrow_mut().pop();
+ let changed = self.imp().strokes.borrow_mut().pop().is_some();
self.queue_draw();
+ if changed {
+ self.copy_annotated_to_clipboard();
+ }
}
pub fn clear_strokes(&self) {
- self.imp().strokes.borrow_mut().clear();
+ let changed = {
+ let mut strokes = self.imp().strokes.borrow_mut();
+ let changed = !strokes.is_empty();
+ strokes.clear();
+ changed
+ };
self.queue_draw();
+ if changed {
+ self.copy_annotated_to_clipboard();
+ }
}
pub fn has_strokes(&self) -> bool {
@@ -506,4 +517,22 @@ impl LpImage {
renderer.unrealize();
Some(texture)
}
+
+ /// Copy the current image and its annotations after a completed edit.
+ pub fn copy_annotated_to_clipboard(&self) {
+ if !crate::application::LpApplication::default()
+ .settings()
+ .boolean("auto-copy-annotations")
+ {
+ return;
+ }
+ let Some(texture) = self.render_annotated_texture() else {
+ tracing::error!("Failed to render annotated image for clipboard");
+ return;
+ };
+ let content = gdk::ContentProvider::for_value(&texture.to_value());
+ if let Err(err) = self.clipboard().set_content(Some(&content)) {
+ tracing::error!("Failed to copy annotated image: {err}");
+ }
+ }
}
diff --git a/src/widgets/image/input_handling.rs b/src/widgets/image/input_handling.rs
index d9f5e33..38b5142 100644
--- a/src/widgets/image/input_handling.rs
+++ b/src/widgets/image/input_handling.rs
@@ -95,10 +95,16 @@ impl imp::LpImage {
}
}
}
- if let Some(stroke) = cur.and_then(|s| s.into_stroke()) {
+ let changed = if let Some(stroke) = cur.and_then(|s| s.into_stroke()) {
imp.strokes.borrow_mut().push(stroke);
- }
+ true
+ } else {
+ false
+ };
obj.queue_draw();
+ if changed {
+ obj.copy_annotated_to_clipboard();
+ }
}
));
}
diff --git a/src/widgets/image_window.rs b/src/widgets/image_window.rs
index b83d54b..4cf0fd7 100644
--- a/src/widgets/image_window.rs
+++ b/src/widgets/image_window.rs
@@ -133,6 +133,8 @@ mod imp {
pub(super) draw_line_width_btn: TemplateChild,
#[template_child]
pub(super) draw_clear_btn: TemplateChild,
+ #[template_child]
+ pub(super) draw_auto_copy_btn: TemplateChild,
}
#[glib::object_subclass]
@@ -475,6 +477,18 @@ mod imp {
imp.draw_color_btn
.set_rgba(&gdk::RGBA::new(0.96, 0.22, 0.22, 1.0));
+ // Persist automatic clipboard updates as an app preference.
+ let settings = LpApplication::default().settings();
+ imp.draw_auto_copy_btn
+ .set_active(settings.boolean("auto-copy-annotations"));
+ imp.draw_auto_copy_btn.connect_toggled(move |btn| {
+ if let Err(err) =
+ settings.set_boolean("auto-copy-annotations", btn.is_active())
+ {
+ tracing::warn!("Failed to save auto-copy setting: {err}");
+ }
+ });
+
// Connect draw mode button (headerbar toggle)
imp.draw_mode_button.connect_toggled(glib::clone!(
#[weak]
diff --git a/src/widgets/image_window.ui b/src/widgets/image_window.ui
index a9571a2..e6c0ac6 100644
--- a/src/widgets/image_window.ui
+++ b/src/widgets/image_window.ui
@@ -265,6 +265,16 @@
+
+
+
+