[accounts-dialog] Make crop area more featureful
- From: Matthias Clasen <matthiasc src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [accounts-dialog] Make crop area more featureful
- Date: Tue, 26 Jan 2010 07:11:04 +0000 (UTC)
commit 61551b6da96c90a513e0a8eb6607b098eb6036fd
Author: Matthias Clasen <mclasen redhat com>
Date: Tue Jan 26 02:08:40 2010 -0500
Make crop area more featureful
Copying the unconstrained cropping from Shotwell, and allowing to
set minimal size and aspect ratio.
src/um-crop-area.c | 336 ++++++++++++++++++++++++++++++++++++++----------
src/um-crop-area.h | 15 ++-
src/um-photo-dialog.c | 2 +
3 files changed, 278 insertions(+), 75 deletions(-)
---
diff --git a/src/um-crop-area.c b/src/um-crop-area.c
index 0f67695..2c473a1 100644
--- a/src/um-crop-area.c
+++ b/src/um-crop-area.c
@@ -40,6 +40,9 @@ struct _UmCropAreaPrivate {
gint active_region;
gint last_press_x;
gint last_press_y;
+ gint base_width;
+ gint base_height;
+ gdouble aspect;
};
G_DEFINE_TYPE (UmCropArea, um_crop_area, GTK_TYPE_DRAWING_AREA);
@@ -139,8 +142,8 @@ update_pixbufs (UmCropArea *area)
shift_colors (area->priv->color_shifted, -32, -32, -32, 0);
if (area->priv->scale == 0.0) {
- area->priv->crop.width = 96.0 / scale;
- area->priv->crop.height = 96.0 / scale;
+ area->priv->crop.width = 2 * area->priv->base_width / scale;
+ area->priv->crop.height = 2 * area->priv->base_height / scale;
area->priv->crop.x = (gdk_pixbuf_get_width (area->priv->browse_pixbuf) - area->priv->crop.width) / 2;
area->priv->crop.y = (gdk_pixbuf_get_height (area->priv->browse_pixbuf) - area->priv->crop.height) / 2;
}
@@ -363,10 +366,15 @@ update_cursor (UmCropArea *area,
{
gint cursor_type;
GdkRectangle crop;
+ gint region;
- crop_to_widget (area, &crop);
+ region = area->priv->active_region;
+ if (region == OUTSIDE) {
+ crop_to_widget (area, &crop);
+ region = find_location (&crop, x, y);
+ }
- switch (find_location (&crop, x, y)) {
+ switch (region) {
case OUTSIDE:
cursor_type = GDK_LEFT_PTR;
break;
@@ -407,110 +415,277 @@ update_cursor (UmCropArea *area,
}
}
-static gboolean
+static int
+eval_radial_line (gdouble center_x, gdouble center_y,
+ gdouble bounds_x, gdouble bounds_y,
+ gdouble user_x)
+{
+ gdouble decision_slope;
+ gdouble decision_intercept;
+
+ decision_slope = (bounds_y - center_y) / (bounds_x - center_x);
+ decision_intercept = bounds_y = -(decision_slope * bounds_x);
+
+ return (int) (decision_slope * user_x + decision_intercept);
+}
+
+static gboolean
um_crop_area_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event)
{
+ UmCropArea *area = UM_CROP_AREA (widget);
gint x, y;
- gint x2, y2;
gint delta_x, delta_y;
- gint width, height, d;
+ gint width, height;
+ gint adj_width, adj_height;
+ gint pb_width, pb_height;
GdkRectangle damage;
- GdkRectangle damage2;
- UmCropArea *area = UM_CROP_AREA (widget);
+ gint left, right, top, bottom;
+ gdouble new_width, new_height;
+ gdouble center_x, center_y;
+ gint min_width, min_height;
if (area->priv->browse_pixbuf == NULL)
return FALSE;
+ update_cursor (area, event->x, event->y);
+
crop_to_widget (area, &damage);
+ gtk_widget_queue_draw_area (widget,
+ damage.x - 1, damage.y - 1,
+ damage.width + 2, damage.height + 2);
- width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
- height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
+ pb_width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
+ pb_height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
x = (event->x - area->priv->image.x) / area->priv->scale;
y = (event->y - area->priv->image.y) / area->priv->scale;
- x = CLAMP (x, 0, width);
- y = CLAMP (y, 0, height);
delta_x = x - area->priv->last_press_x;
delta_y = y - area->priv->last_press_y;
area->priv->last_press_x = x;
area->priv->last_press_y = y;
- x2 = area->priv->crop.x + area->priv->crop.width;
- y2 = area->priv->crop.y + area->priv->crop.height;
+ left = area->priv->crop.x;
+ right = area->priv->crop.x + area->priv->crop.width - 1;
+ top = area->priv->crop.y;
+ bottom = area->priv->crop.y + area->priv->crop.height - 1;
+
+ center_x = (left + right) / 2.0;
+ center_y = (top + bottom) / 2.0;
switch (area->priv->active_region) {
case INSIDE:
- area->priv->crop.x = CLAMP (area->priv->crop.x + delta_x, 0, width - area->priv->crop.width);
- area->priv->crop.y = CLAMP (area->priv->crop.y + delta_y, 0, height - area->priv->crop.height);
+ width = right - left + 1;
+ height = bottom - top + 1;
+
+ left += delta_x;
+ right += delta_x;
+ top += delta_y;
+ bottom += delta_y;
+
+ if (left < 0)
+ left = 0;
+ if (top < 0)
+ top = 0;
+ if (right > pb_width)
+ right = pb_width;
+ if (bottom > pb_height)
+ bottom = pb_height;
+
+ adj_width = right - left + 1;
+ adj_height = bottom - top + 1;
+ if (adj_width != width) {
+ if (delta_x < 0)
+ right = left + width - 1;
+ else
+ left = right - width + 1;
+ }
+ if (adj_height != height) {
+ if (delta_y < 0)
+ bottom = top + height - 1;
+ else
+ top = bottom - height + 1;
+ }
+
break;
case TOP_LEFT:
- d = MAX (x2 - x, y2 - y);
- if (d < 48 / area->priv->scale)
- d = 48 / area->priv->scale;
- if (x2 - d < 0)
- d = x2;
- if (y2 - d < 0)
- d = y2;
- area->priv->crop.x = x2 - d;
- area->priv->crop.y = y2 - d;
- area->priv->crop.width = area->priv->crop.height = d;
+ if (area->priv->aspect < 0) {
+ top = y;
+ left = x;
+ }
+ else if (y < eval_radial_line (center_x, center_y, left, top, x)) {
+ top = y;
+ new_width = (bottom - top) * area->priv->aspect;
+ left = right - new_width;
+ }
+ else {
+ left = x;
+ new_height = (right - left) / area->priv->aspect;
+ top = bottom - new_height;
+ }
break;
case TOP:
+ top = y;
+ if (area->priv->aspect > 0) {
+ new_width = (bottom - top) * area->priv->aspect;
+ right = left + new_width;
+ }
+ break;
+
case TOP_RIGHT:
- d = MAX (y2 - y, x - area->priv->crop.x);
- if (d < 48 / area->priv->scale)
- d = 48 / area->priv->scale;
- if (area->priv->crop.x + d > width)
- d = width - area->priv->crop.x;
- if (y2 - d < 0)
- d = y2;
- area->priv->crop.y = y2 - d;
- area->priv->crop.width = area->priv->crop.height = d;
+ if (area->priv->aspect < 0) {
+ top = y;
+ right = x;
+ }
+ else if (y < eval_radial_line (center_x, center_y, right, top, x)) {
+ top = y;
+ new_width = (bottom - top) * area->priv->aspect;
+ right = left + new_width;
+ }
+ else {
+ right = x;
+ new_height = (right - left) / area->priv->aspect;
+ top = bottom - new_height;
+ }
break;
case LEFT:
+ left = x;
+ if (area->priv->aspect > 0) {
+ new_height = (right - left) / area->priv->aspect;
+ bottom = top + new_height;
+ }
+ break;
+
case BOTTOM_LEFT:
- d = MAX (x2 - x, y - area->priv->crop.y);
- if (d < 48 / area->priv->scale)
- d = 48 / area->priv->scale;
- if (area->priv->crop.y + d > height)
- d = height - area->priv->crop.y;
- if (x2 - d < 0)
- d = x2;
- area->priv->crop.x = x2 - d;
- area->priv->crop.width = area->priv->crop.height = d;
+ if (area->priv->aspect < 0) {
+ bottom = y;
+ left = x;
+ }
+ else if (y < eval_radial_line (center_x, center_y, left, bottom, x)) {
+ left = x;
+ new_height = (right - left) / area->priv->aspect;
+ bottom = top + new_height;
+ }
+ else {
+ bottom = y;
+ new_width = (bottom - top) * area->priv->aspect;
+ left = right - new_width;
+ }
break;
case RIGHT:
+ right = x;
+ if (area->priv->aspect > 0) {
+ new_height = (right - left) / area->priv->aspect;
+ bottom = top + new_height;
+ }
+ break;
+
case BOTTOM_RIGHT:
- case BOTTOM:
- area->priv->crop.width = MAX (x - area->priv->crop.x, y - area->priv->crop.y);
- if (area->priv->crop.width < 48 / area->priv->scale)
- area->priv->crop.width = 48 / area->priv->scale;
- if (area->priv->crop.x + area->priv->crop.width > width)
- area->priv->crop.width = width - area->priv->crop.x;
- area->priv->crop.height = area->priv->crop.width;
- if (area->priv->crop.y + area->priv->crop.height > height)
- area->priv->crop.height = height - area->priv->crop.y;
- area->priv->crop.width = area->priv->crop.height;
+ if (area->priv->aspect < 0) {
+ bottom = y;
+ right = x;
+ }
+ else if (y < eval_radial_line (center_x, center_y, right, bottom, x)) {
+ right = x;
+ new_height = (right - left) / area->priv->aspect;
+ bottom = top + new_height;
+ }
+ else {
+ bottom = y;
+ new_width = (bottom - top) * area->priv->aspect;
+ right = left + new_width;
+ }
break;
- case OUTSIDE:
+ case BOTTOM:
+ bottom = y;
+ if (area->priv->aspect > 0) {
+ new_width = (bottom - top) * area->priv->aspect;
+ right= left + new_width;
+ }
break;
- default: ;
+
+ default:
+ return FALSE;
+ }
+
+ min_width = area->priv->base_width / area->priv->scale;
+ min_height = area->priv->base_height / area->priv->scale;
+
+ width = right - left + 1;
+ height = bottom - top + 1;
+ if (area->priv->aspect < 0) {
+ if (left < 0)
+ left = 0;
+ if (top < 0)
+ top = 0;
+ if (right > pb_width)
+ right = pb_width;
+ if (bottom > pb_height)
+ bottom = pb_height;
+
+ width = right - left + 1;
+ height = bottom - top + 1;
+
+ switch (area->priv->active_region) {
+ case LEFT:
+ case TOP_LEFT:
+ case BOTTOM_LEFT:
+ if (width < min_width)
+ left = right - min_width;
+ break;
+ case RIGHT:
+ case TOP_RIGHT:
+ case BOTTOM_RIGHT:
+ if (width < min_width)
+ right = left + min_width;
+ break;
+
+ default: ;
+ }
+
+ switch (area->priv->active_region) {
+ case TOP:
+ case TOP_LEFT:
+ case TOP_RIGHT:
+ if (height < min_height)
+ top = bottom - min_height;
+ break;
+ case BOTTOM:
+ case BOTTOM_LEFT:
+ case BOTTOM_RIGHT:
+ if (height < min_height)
+ bottom = top + min_height;
+ break;
+
+ default: ;
+ }
+ }
+ else {
+ if (left < 0 || top < 0 ||
+ right > pb_width || bottom > pb_height ||
+ width < min_width || height < min_height) {
+ left = area->priv->crop.x;
+ right = area->priv->crop.x + area->priv->crop.width - 1;
+ top = area->priv->crop.y;
+ bottom = area->priv->crop.y + area->priv->crop.height - 1;
+ }
}
- crop_to_widget (area, &damage2);
- gdk_rectangle_union (&damage, &damage2, &damage);
+ area->priv->crop.x = left;
+ area->priv->crop.y = top;
+ area->priv->crop.width = right - left + 1;
+ area->priv->crop.height = bottom - top + 1;
+ crop_to_widget (area, &damage);
gtk_widget_queue_draw_area (widget,
damage.x - 1, damage.y - 1,
damage.width + 2, damage.height + 2);
- update_cursor (area, event->x, event->y);
return FALSE;
}
@@ -611,6 +786,9 @@ um_crop_area_init (UmCropArea *area)
area->priv->image.width = 0;
area->priv->image.height = 0;
area->priv->active_region = OUTSIDE;
+ area->priv->base_width = 48;
+ area->priv->base_height = 48;
+ area->priv->aspect = 1;
}
GtkWidget *
@@ -647,18 +825,11 @@ um_crop_area_set_picture (UmCropArea *area,
height = 0;
}
-#if 0
- gtk_widget_get_allocation (um->browse_drawing_area, &allocation);
- um->priv->crop.width = 96;
- um->priv->crop.height = 96;
- um->priv->crop.x = (allocation.width - um->priv->crop.width) / 2;
- um->priv->crop.y = (allocation.height - um->priv->crop.height) / 2;
-#else
- area->priv->crop.width = 96;
- area->priv->crop.height = 96;
+ area->priv->crop.width = 2 * area->priv->base_width;
+ area->priv->crop.height = 2 * area->priv->base_height;
area->priv->crop.x = (width - area->priv->crop.width) / 2;
area->priv->crop.y = (height - area->priv->crop.height) / 2;
-#endif
+
area->priv->scale = 0.0;
area->priv->image.x = 0;
area->priv->image.y = 0;
@@ -668,3 +839,28 @@ um_crop_area_set_picture (UmCropArea *area,
gtk_widget_queue_draw (GTK_WIDGET (area));
}
+void
+um_crop_area_set_min_size (UmCropArea *area,
+ gint width,
+ gint height)
+{
+ area->priv->base_width = width;
+ area->priv->base_height = height;
+
+ if (area->priv->aspect > 0) {
+ area->priv->aspect = area->priv->base_width / (gdouble)area->priv->base_height;
+ }
+}
+
+void
+um_crop_area_set_constrain_aspect (UmCropArea *area,
+ gboolean constrain)
+{
+ if (constrain) {
+ area->priv->aspect = area->priv->base_width / (gdouble)area->priv->base_height;
+ }
+ else {
+ area->priv->aspect = -1;
+ }
+}
+
diff --git a/src/um-crop-area.h b/src/um-crop-area.h
index 26b82b9..8992957 100644
--- a/src/um-crop-area.h
+++ b/src/um-crop-area.h
@@ -48,12 +48,17 @@ struct _UmCropArea {
UmCropAreaPrivate *priv;
};
-GType um_crop_area_get_type (void) G_GNUC_CONST;
+GType um_crop_area_get_type (void) G_GNUC_CONST;
-GtkWidget *um_crop_area_new (void);
-GdkPixbuf *um_crop_area_get_picture (UmCropArea *area);
-void um_crop_area_set_picture (UmCropArea *area,
- GdkPixbuf *pixbuf);
+GtkWidget *um_crop_area_new (void);
+GdkPixbuf *um_crop_area_get_picture (UmCropArea *area);
+void um_crop_area_set_picture (UmCropArea *area,
+ GdkPixbuf *pixbuf);
+void um_crop_area_set_min_size (UmCropArea *area,
+ gint width,
+ gint height);
+void um_crop_area_set_constrain_aspect (UmCropArea *area,
+ gboolean constrain);
G_END_DECLS
diff --git a/src/um-photo-dialog.c b/src/um-photo-dialog.c
index 4e886be..81a4814 100644
--- a/src/um-photo-dialog.c
+++ b/src/um-photo-dialog.c
@@ -105,6 +105,8 @@ um_photo_dialog_crop (UmPhotoDialog *um,
/* Content */
um->crop_area = um_crop_area_new ();
+ um_crop_area_set_min_size (UM_CROP_AREA (um->crop_area), 48, 48);
+ um_crop_area_set_constrain_aspect (UM_CROP_AREA (um->crop_area), TRUE);
um_crop_area_set_picture (UM_CROP_AREA (um->crop_area), pixbuf);
frame = gtk_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (frame), um->crop_area);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]