edit/crop: Apply crop via checkmark overlay

This commit is contained in:
Sophie Herold 2025-01-22 22:19:10 +01:00
parent 40d425ac80
commit 9a5170de34
6 changed files with 62 additions and 26 deletions

View file

@ -46,3 +46,8 @@ lpcrop {
.discarded-area { .discarded-area {
background: var(--discarded-background); background: var(--discarded-background);
} }
.apply-button {
margin-right: 12px;
margin-top: -6px;
}

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 13.398438 2.011719 c -0.394532 0.027343 -0.765626 0.210937 -1.027344 0.507812 l -5.78125 6.609375 l -1.890625 -2.519531 c -0.496094 -0.664063 -1.4375 -0.796875 -2.101563 -0.300781 c -0.316406 0.238281 -0.527344 0.59375 -0.582031 0.988281 c -0.058594 0.394531 0.046875 0.796875 0.285156 1.113281 l 3 4 c 0.273438 0.359375 0.691407 0.582032 1.144531 0.597656 c 0.449219 0.015626 0.886719 -0.171874 1.183594 -0.511718 l 7 -8 c 0.542969 -0.625 0.480469 -1.570313 -0.140625 -2.117188 c -0.300781 -0.261718 -0.691406 -0.394531 -1.089843 -0.367187 z m 0 0" fill="#222222"/></svg>

After

Width:  |  Height:  |  Size: 710 B

View file

@ -71,8 +71,6 @@ mod imp {
image: TemplateChild<LpImage>, image: TemplateChild<LpImage>,
#[template_child] #[template_child]
pub(super) selection: TemplateChild<LpEditCropSelection>, pub(super) selection: TemplateChild<LpEditCropSelection>,
#[template_child]
pub apply_crop: TemplateChild<gtk::Button>,
#[property(get, set, builder(LpAspectRatio::default()))] #[property(get, set, builder(LpAspectRatio::default()))]
aspect_ratio: Cell<LpAspectRatio>, aspect_ratio: Cell<LpAspectRatio>,
@ -229,9 +227,6 @@ mod imp {
self.crop_area_image_coord.replace(crop_area_image_coord); self.crop_area_image_coord.replace(crop_area_image_coord);
} }
let apply_sensitive = self.cropped();
self.apply_crop.set_visible(apply_sensitive);
self.obj().notify_cropped(); self.obj().notify_cropped();
} }

View file

@ -323,18 +323,6 @@
<property name="crop">LpEditCrop</property> <property name="crop">LpEditCrop</property>
</object> </object>
</child> </child>
<child type="overlay">
<object class="GtkButton" id="apply_crop">
<property name="label">Apply</property>
<property name="action-name">edit-crop.apply-crop</property>
<property name="halign">end</property>
<property name="valign">start</property>
<style>
<class name="osd" />
<class name="pill" />
</style>
</object>
</child>
</object> </object>
</property> </property>
</object> </object>

View file

@ -26,7 +26,7 @@ use adw::{glib, gtk};
use super::crop::{LpAspectRatio, LpEditCrop, LpOrientation}; use super::crop::{LpAspectRatio, LpEditCrop, LpOrientation};
const MIN_SELECTION_SIZE: f32 = 50.; const MIN_SELECTION_SIZE: f32 = 80.;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
struct InResize { struct InResize {
@ -155,6 +155,9 @@ mod imp {
#[template_child] #[template_child]
handle_bottom_left: TemplateChild<adw::Bin>, handle_bottom_left: TemplateChild<adw::Bin>,
#[template_child]
apply_button: TemplateChild<gtk::Button>,
#[template_child] #[template_child]
selection_move: TemplateChild<gtk::GestureDrag>, selection_move: TemplateChild<gtk::GestureDrag>,
@ -226,6 +229,7 @@ mod imp {
} }
self.selection.set_cursor_from_name(Some("move")); self.selection.set_cursor_from_name(Some("move"));
self.apply_button.set_cursor_from_name(Some("default"));
obj.crop() obj.crop()
.connect_aspect_ratio_notify(|x| x.selection().imp().on_aspect_ratio_changed()); .connect_aspect_ratio_notify(|x| x.selection().imp().on_aspect_ratio_changed());
@ -256,7 +260,7 @@ mod imp {
let crop_area = imp.crop_area(); let crop_area = imp.crop_area();
imp.selection_in_resize.set(Some(InResize { imp.set_selection_in_resize(Some(InResize {
corner, corner,
initial_selection: crop_area, initial_selection: crop_area,
})); }));
@ -264,7 +268,7 @@ mod imp {
gesture.set_state(gtk::EventSequenceState::Claimed); gesture.set_state(gtk::EventSequenceState::Claimed);
let crop_area = imp.crop_area(); let crop_area = imp.crop_area();
imp.selection_in_move.set(Some(InMove { imp.set_selection_in_move(Some(InMove {
initial_selection: crop_area, initial_selection: crop_area,
})); }));
} else { } else {
@ -315,8 +319,8 @@ mod imp {
#[weak] #[weak]
obj, obj,
move |_, _, _| { move |_, _, _| {
obj.imp().selection_in_resize.set(None); obj.imp().set_selection_in_resize(None);
obj.imp().selection_in_move.set(None); obj.imp().set_selection_in_move(None);
} }
)); ));
} }
@ -683,6 +687,7 @@ mod imp {
self.crop_x.set(x); self.crop_x.set(x);
self.space_top_left.set_width_request(x.round() as i32); self.space_top_left.set_width_request(x.round() as i32);
self.obj().notify_crop_x(); self.obj().notify_crop_x();
self.update_apply_crop_visibility();
} }
/// Set y coordinate of crop selection rectangle origin /// Set y coordinate of crop selection rectangle origin
@ -695,6 +700,7 @@ mod imp {
self.crop_y.set(y); self.crop_y.set(y);
self.space_top_left.set_height_request(y.round() as i32); self.space_top_left.set_height_request(y.round() as i32);
self.obj().notify_crop_y(); self.obj().notify_crop_y();
self.update_apply_crop_visibility();
} }
/// Set width of crop selection rectangle /// Set width of crop selection rectangle
@ -707,6 +713,7 @@ mod imp {
self.crop_width.set(width); self.crop_width.set(width);
self.selection.set_width_request(width.round() as i32); self.selection.set_width_request(width.round() as i32);
self.obj().notify_crop_width(); self.obj().notify_crop_width();
self.update_apply_crop_visibility();
} }
/// Set height of crop selection rectangle /// Set height of crop selection rectangle
@ -719,6 +726,7 @@ mod imp {
self.crop_height.set(height); self.crop_height.set(height);
self.selection.set_height_request(height.round() as i32); self.selection.set_height_request(height.round() as i32);
self.obj().notify_crop_height(); self.obj().notify_crop_height();
self.update_apply_crop_visibility();
} }
/// Width of area in which the crop selection can exist /// Width of area in which the crop selection can exist
@ -728,6 +736,7 @@ mod imp {
fn set_total_width(&self, width: i32) { fn set_total_width(&self, width: i32) {
self.obj().set_width_request(width); self.obj().set_width_request(width);
self.update_apply_crop_visibility();
} }
/// Height of area in which the crop selection can exist /// Height of area in which the crop selection can exist
@ -737,6 +746,7 @@ mod imp {
fn set_total_height(&self, width: i32) { fn set_total_height(&self, width: i32) {
self.obj().set_height_request(width); self.obj().set_height_request(width);
self.update_apply_crop_visibility();
} }
pub(super) fn aspect_ratio_animation(&self) -> &adw::TimedAnimation { pub(super) fn aspect_ratio_animation(&self) -> &adw::TimedAnimation {
@ -751,6 +761,24 @@ mod imp {
.build() .build()
}) })
} }
fn set_selection_in_resize(&self, in_resize: Option<InResize>) {
self.selection_in_resize.replace(in_resize);
self.update_apply_crop_visibility();
}
fn set_selection_in_move(&self, in_move: Option<InMove>) {
self.selection_in_move.replace(in_move);
self.update_apply_crop_visibility();
}
fn update_apply_crop_visibility(&self) {
self.apply_button.set_visible(
self.obj().is_cropped()
&& !self.selection_in_resize.get().is_some()
&& !self.selection_in_move.get().is_some(),
);
}
} }
} }

View file

@ -128,7 +128,7 @@
<property name="hexpand">true</property> <property name="hexpand">true</property>
<layout> <layout>
<property name="row">0</property> <property name="row">0</property>
<property name="column">1</property> <property name="column">2</property>
</layout> </layout>
<style> <style>
<class name="handle" /> <class name="handle" />
@ -136,12 +136,30 @@
</style> </style>
</object> </object>
</child> </child>
<child>
<object class="GtkButton" id="apply_button">
<property name="hexpand">true</property>
<layout>
<property name="row">1</property>
<property name="column">2</property>
</layout>
<property name="action-name">edit-crop.apply-crop</property>
<property name="icon-name">apply-crop</property>
<property name="halign">end</property>
<property name="valign">start</property>
<style>
<class name="circular" />
<class name="osd" />
<class name="apply-button" />
</style>
</object>
</child>
<child> <child>
<object class="AdwBin" id="handle_bottom_left"> <object class="AdwBin" id="handle_bottom_left">
<property name="valign">end</property> <property name="valign">end</property>
<property name="vexpand">true</property> <property name="vexpand">true</property>
<layout> <layout>
<property name="row">1</property> <property name="row">2</property>
<property name="column">0</property> <property name="column">0</property>
</layout> </layout>
<style> <style>
@ -157,8 +175,8 @@
<property name="valign">end</property> <property name="valign">end</property>
<property name="vexpand">true</property> <property name="vexpand">true</property>
<layout> <layout>
<property name="row">1</property> <property name="row">2</property>
<property name="column">1</property> <property name="column">2</property>
</layout> </layout>
<style> <style>
<class name="handle" /> <class name="handle" />