[gthumb] rotate image: added ability to rotate dragging the image



commit 2f0cf2e606c9c34137fc5578d12bc521bcb9f483
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Wed May 18 20:41:01 2011 +0200

    rotate image: added ability to rotate dragging the image

 extensions/file_tools/cairo-rotate.c         |   22 ++--
 extensions/file_tools/cairo-rotate.h         |    4 +-
 extensions/file_tools/gth-file-tool-rotate.c |   34 +++++-
 extensions/file_tools/gth-image-rotator.c    |  162 ++++++++++++++++++++++++--
 extensions/file_tools/gth-image-rotator.h    |    6 +-
 5 files changed, 202 insertions(+), 26 deletions(-)
---
diff --git a/extensions/file_tools/cairo-rotate.c b/extensions/file_tools/cairo-rotate.c
index bb78f5b..350c6c1 100644
--- a/extensions/file_tools/cairo-rotate.c
+++ b/extensions/file_tools/cairo-rotate.c
@@ -147,29 +147,29 @@ _cairo_image_surface_rotate_get_cropping_region (cairo_surface_t *image,
 
 
 double
-_cairo_image_surface_rotate_get_align_angle (gboolean vertical,
-					     GdkPoint p1,
-					     GdkPoint p2)
+_cairo_image_surface_rotate_get_align_angle (gboolean  vertical,
+					     GdkPoint *p1,
+					     GdkPoint *p2)
 {
 	double angle;
 
 	if (! vertical) {
-		if (p1.y == p2.y)
+		if (p1->y == p2->y)
 			return 0.0;
 
-		if (p2.x > p1.x)
-			angle = -atan2 (p2.y - p1.y, p2.x - p1.x);
+		if (p2->x > p1->x)
+			angle = -atan2 (p2->y - p1->y, p2->x - p1->x);
 		else
-			angle = -atan2 (p1.y - p2.y, p1.x - p2.x);
+			angle = -atan2 (p1->y - p2->y, p1->x - p2->x);
 	}
 	else {
-		if (p1.x == p2.x)
+		if (p1->x == p2->x)
 			return 0.0;
 
-		if (p2.y > p1.y)
-			angle = atan2 (p2.x - p1.x, p2.y - p1.y);
+		if (p2->y > p1->y)
+			angle = atan2 (p2->x - p1->x, p2->y - p1->y);
 		else
-			angle = atan2 (p1.x - p2.x, p1.y - p2.y);
+			angle = atan2 (p1->x - p2->x, p1->y - p2->y);
 	}
 
 	angle = angle * 180.0 / G_PI;
diff --git a/extensions/file_tools/cairo-rotate.h b/extensions/file_tools/cairo-rotate.h
index 189ee49..a22fda5 100644
--- a/extensions/file_tools/cairo-rotate.h
+++ b/extensions/file_tools/cairo-rotate.h
@@ -38,8 +38,8 @@ void               _cairo_image_surface_rotate_get_cropping_region     (cairo_su
 									double             p2,
 									GdkRectangle      *region);
 double             _cairo_image_surface_rotate_get_align_angle         (gboolean           vertical,
-					   	   	  	  	GdkPoint           p1,
-					   	   	  	  	GdkPoint           p2);
+					   	   	  	  	GdkPoint          *p1,
+					   	   	  	  	GdkPoint          *p2);
 cairo_surface_t *  _cairo_image_surface_rotate                         (cairo_surface_t   *image,
 		    	     	     	     	     	     	        double             angle,
 		    	     	     	     	     	     	        gboolean           high_quality,
diff --git a/extensions/file_tools/gth-file-tool-rotate.c b/extensions/file_tools/gth-file-tool-rotate.c
index ddda9dc..93f9d62 100644
--- a/extensions/file_tools/gth-file-tool-rotate.c
+++ b/extensions/file_tools/gth-file-tool-rotate.c
@@ -173,7 +173,7 @@ alignment_changed_cb (GthImageLineTool  *line_tool,
 	gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), self->priv->rotator);
 
 	gth_image_line_tool_get_points (line_tool, &p1, &p2);
-	angle = _cairo_image_surface_rotate_get_align_angle (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("alignment_parallel_radiobutton"))), p1, p2);
+	angle = _cairo_image_surface_rotate_get_align_angle (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("alignment_parallel_radiobutton"))), &p1, &p2);
 	gtk_adjustment_set_value (self->priv->rotation_angle_adj, angle);
 }
 
@@ -224,6 +224,9 @@ static void
 reset_button_clicked_cb (GtkButton         *button,
 			 GthFileToolRotate *self)
 {
+	gth_image_rotator_set_center (GTH_IMAGE_ROTATOR (self->priv->rotator),
+				      cairo_image_surface_get_width (self->priv->image) / 2,
+				      cairo_image_surface_get_height (self->priv->image) / 2);
 	gtk_adjustment_set_value (self->priv->rotation_angle_adj, 0.0);
 }
 
@@ -346,6 +349,27 @@ resize_combobox_changed_cb (GtkComboBox       *combo_box,
 }
 
 
+static void
+rotator_angle_changed_cb (GthImageRotator   *rotator,
+			  double             angle,
+			  GthFileToolRotate *self)
+{
+	gtk_adjustment_set_value (self->priv->rotation_angle_adj, angle);
+}
+
+
+static void
+rotator_center_changed_cb (GthImageRotator   *rotator,
+		  	   int                x,
+		  	   int                y,
+		  	   GthFileToolRotate *self)
+{
+	gth_image_rotator_set_center (rotator, x, y);
+	update_crop_parameters (self);
+	update_crop_region (self);
+}
+
+
 static GtkWidget *
 gth_file_tool_rotate_get_options (GthFileTool *base)
 {
@@ -495,6 +519,14 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
 			  "changed",
 			  G_CALLBACK (resize_combobox_changed_cb),
 			  self);
+	g_signal_connect (self->priv->rotator,
+			  "angle-changed",
+			  G_CALLBACK (rotator_angle_changed_cb),
+			  self);
+	g_signal_connect (self->priv->rotator,
+			  "center-changed",
+			  G_CALLBACK (rotator_center_changed_cb),
+			  self);
 
 	update_crop_parameters (self);
 	update_crop_region (self);
diff --git a/extensions/file_tools/gth-image-rotator.c b/extensions/file_tools/gth-image-rotator.c
index a3a151e..7a39d27 100644
--- a/extensions/file_tools/gth-image-rotator.c
+++ b/extensions/file_tools/gth-image-rotator.c
@@ -29,11 +29,15 @@
 
 #define MIN4(a,b,c,d) MIN(MIN((a),(b)),MIN((c),(d)))
 #define MAX4(a,b,c,d) MAX(MAX((a),(b)),MAX((c),(d)))
+#define G_2_PI (G_PI * 2)
+#define RAD_TO_DEG(x) ((x) * 180 / G_PI)
+#define DEG_TO_RAD(x) ((x) * G_PI / 180)
 
 
 enum {
 	CHANGED,
 	CENTER_CHANGED,
+	ANGLE_CHANGED,
 	LAST_SIGNAL
 };
 
@@ -65,6 +69,10 @@ struct _GthImageRotatorPrivate {
 	GdkPoint            preview_center;
 	GdkRectangle        clip_area;
 	cairo_matrix_t      matrix;
+	gboolean            dragging;
+	double              angle_before_dragging;
+	GdkPoint            drag_p1;
+	GdkPoint            drag_p2;
 	GthFit              original_fit_mode;
 	gboolean            original_zoom_enabled;
 };
@@ -75,12 +83,17 @@ gth_image_rotator_set_viewer (GthImageViewerTool *base,
 			      GthImageViewer     *viewer)
 {
 	GthImageRotator *self = GTH_IMAGE_ROTATOR (base);
+	GdkCursor       *cursor;
 
 	self->priv->viewer = viewer;
 	self->priv->original_fit_mode = gth_image_viewer_get_fit_mode (GTH_IMAGE_VIEWER (viewer));
 	self->priv->original_zoom_enabled = gth_image_viewer_get_zoom_enabled (GTH_IMAGE_VIEWER (viewer));
 	gth_image_viewer_set_fit_mode (GTH_IMAGE_VIEWER (viewer), GTH_FIT_SIZE_IF_LARGER);
 	gth_image_viewer_set_zoom_enabled (GTH_IMAGE_VIEWER (viewer), FALSE);
+
+	cursor = gdk_cursor_new (GDK_LEFT_PTR);
+	gth_image_viewer_set_cursor (self->priv->viewer, cursor);
+	gdk_cursor_unref (cursor);
 }
 
 
@@ -352,6 +365,22 @@ paint_grid (GthImageRotator *self,
 
 
 static void
+paint_point (GthImageRotator *self,
+	     GdkEventExpose  *event,
+	     cairo_t         *cr,
+	     GdkPoint        *p)
+{
+	double radius = 10.0;
+
+	cairo_move_to (cr, p->x - radius, p->y - radius);
+	cairo_line_to (cr, p->x + radius, p->y + radius);
+	cairo_move_to (cr, p->x - radius, p->y + radius);
+	cairo_line_to (cr, p->x + radius, p->y - radius);
+	cairo_stroke (cr);
+}
+
+
+static void
 gth_image_rotator_expose (GthImageViewerTool *base,
 			  GdkEventExpose     *event,
 			  cairo_t            *cr)
@@ -401,6 +430,22 @@ gth_image_rotator_expose (GthImageViewerTool *base,
 		paint_grid (self, event, cr);
 	}
 
+	if (self->priv->dragging) {
+		GdkPoint center;
+
+		cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT);
+		cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+
+		center.x = self->priv->center.x * self->priv->preview_zoom + self->priv->preview_image_area.x;
+		center.y = self->priv->center.y * self->priv->preview_zoom + self->priv->preview_image_area.y;
+		paint_point (self, event, cr, &center);
+
+		/* used for debugging purposes
+		paint_point (self, event, cr, &self->priv->drag_p1);
+		paint_point (self, event, cr, &self->priv->drag_p2);
+		*/
+	}
+
 	cairo_restore (cr);
 }
 
@@ -409,7 +454,20 @@ static gboolean
 gth_image_rotator_button_release (GthImageViewerTool *base,
 				  GdkEventButton     *event)
 {
-	/* FIXME */
+	GthImageRotator *self = GTH_IMAGE_ROTATOR (base);
+	GdkCursor       *cursor;
+
+	self->priv->dragging = FALSE;
+	self->priv->drag_p1.x = 0;
+	self->priv->drag_p1.y = 0;
+	self->priv->drag_p2.x = 0;
+	self->priv->drag_p2.y = 0;
+
+	cursor = gdk_cursor_new (GDK_LEFT_PTR);
+	gth_image_viewer_set_cursor (self->priv->viewer, cursor);
+	gdk_cursor_unref (cursor);
+
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->viewer));
 
 	return FALSE;
 }
@@ -426,18 +484,89 @@ gth_image_rotator_button_press (GthImageViewerTool *base,
 
 		x = (event->x - self->priv->preview_image_area.x) / self->priv->preview_zoom;
 		y = (event->y - self->priv->preview_image_area.y) / self->priv->preview_zoom;
-		gth_image_rotator_set_center (self, (int) x, (int) y);
+		g_signal_emit (self, signals[CENTER_CHANGED], 0, (int) x, (int) y);
+	}
+
+	if (event->type == GDK_BUTTON_PRESS) {
+		self->priv->dragging = FALSE;
+		self->priv->drag_p1.x = event->x;
+		self->priv->drag_p1.y = event->y;
 	}
 
 	return FALSE;
 }
 
 
+static double
+get_angle (GdkPoint *p1,
+	   GdkPoint *p2)
+{
+	double a = 0.0;
+	int    x, y;
+
+	x = p2->x - p1->x;
+	y = p2->y - p1->y;
+	if (x >= 0) {
+		if  (y >= 0)
+			a = atan2 (y, x);
+		else
+			a = G_2_PI - atan2 (- y, x);
+	}
+	else {
+		if (y >= 0)
+			a = G_PI - atan2 (y, - x);
+		else
+			a = G_PI + atan2 (- y, - x);
+	}
+
+	return a;
+}
+
+
 static gboolean
 gth_image_rotator_motion_notify (GthImageViewerTool *base,
 				 GdkEventMotion     *event)
 {
-	/* FIXME */
+	GthImageRotator *self = GTH_IMAGE_ROTATOR (base);
+
+	if (! self->priv->dragging
+	    && gtk_drag_check_threshold (GTK_WIDGET (self->priv->viewer),
+			    	    	 self->priv->drag_p1.x,
+			    	    	 self->priv->drag_p1.y,
+			    	    	 self->priv->drag_p2.x,
+			    	    	 self->priv->drag_p2.y))
+	{
+		GdkCursor *cursor;
+
+		self->priv->angle_before_dragging = self->priv->angle;
+		self->priv->dragging = TRUE;
+
+		cursor = gdk_cursor_new_from_name (gtk_widget_get_display (GTK_WIDGET (self->priv->viewer)), "grabbing");
+		gth_image_viewer_set_cursor (self->priv->viewer, cursor);
+		if (cursor != NULL)
+			gdk_cursor_unref (cursor);
+	}
+
+	if (self->priv->dragging) {
+		GdkPoint center;
+		double   angle1;
+		double   angle2;
+		double   angle;
+
+		self->priv->drag_p2.x = event->x;
+		self->priv->drag_p2.y = event->y;
+
+		center.x = self->priv->center.x * self->priv->preview_zoom + self->priv->preview_image_area.x;
+		center.y = self->priv->center.y * self->priv->preview_zoom + self->priv->preview_image_area.y;
+
+		angle1 = get_angle (&center, &self->priv->drag_p1);
+		angle2 = get_angle (&center, &self->priv->drag_p2);
+		if (angle2 < angle1 - G_PI)
+			angle2 = G_2_PI + angle2;
+		angle = self->priv->angle_before_dragging + (angle2 - angle1);
+
+		g_signal_emit (self, signals[ANGLE_CHANGED], 0, CLAMP (RAD_TO_DEG (angle), -90.0, 90));
+	}
 
 	return FALSE;
 }
@@ -473,6 +602,7 @@ gth_image_rotator_instance_init (GthImageRotator *self)
 	self->priv->crop_region.y = 0;
 	self->priv->crop_region.width = 0;
 	self->priv->crop_region.height = 0;
+	self->priv->dragging = FALSE;
 }
 
 
@@ -517,9 +647,20 @@ gth_image_rotator_class_init (GthImageRotatorClass *class)
 					 	G_SIGNAL_RUN_LAST,
 					 	G_STRUCT_OFFSET (GthImageRotatorClass, center_changed),
 					 	NULL, NULL,
-					 	g_cclosure_marshal_VOID__VOID,
+					 	gth_marshal_VOID__INT_INT,
+					 	G_TYPE_NONE,
+					 	2,
+					 	G_TYPE_INT,
+					 	G_TYPE_INT);
+	signals[ANGLE_CHANGED] = g_signal_new ("angle-changed",
+					 	G_TYPE_FROM_CLASS (class),
+					 	G_SIGNAL_RUN_LAST,
+					 	G_STRUCT_OFFSET (GthImageRotatorClass, angle_changed),
+					 	NULL, NULL,
+					 	g_cclosure_marshal_VOID__DOUBLE,
 					 	G_TYPE_NONE,
-					 	0);
+					 	1,
+					 	G_TYPE_DOUBLE);
 }
 
 
@@ -596,10 +737,8 @@ gth_image_rotator_set_grid_type (GthImageRotator *self,
                 return;
 
         self->priv->grid_type = grid_type;
-        gtk_widget_queue_draw (GTK_WIDGET (self->priv->viewer));
-        /*g_signal_emit (G_OBJECT (self),
-                       signals[GRID_VISIBILITY_CHANGED],
-                       0);*/
+        if (self->priv->viewer != NULL)
+        	gtk_widget_queue_draw (GTK_WIDGET (self->priv->viewer));
 }
 
 
@@ -622,7 +761,7 @@ gth_image_rotator_set_center (GthImageRotator *self,
 	if (self->priv->viewer != NULL)
 		gtk_widget_queue_draw (GTK_WIDGET (self->priv->viewer));
 
-	g_signal_emit (self, signals[CENTER_CHANGED], 0);
+	g_signal_emit (self, signals[CHANGED], 0);
 }
 
 
@@ -642,10 +781,11 @@ gth_image_rotator_set_angle (GthImageRotator *self,
 {
 	double radiants;
 
-	radiants = angle * M_PI / 180.0;
+	radiants = DEG_TO_RAD (angle);
 	if (radiants == self->priv->angle)
 		return;
 	self->priv->angle = radiants;
+
 	_gth_image_rotator_update_tranformation_matrix (self);
 
 	if (self->priv->viewer != NULL)
diff --git a/extensions/file_tools/gth-image-rotator.h b/extensions/file_tools/gth-image-rotator.h
index b811bc0..b1c1f45 100644
--- a/extensions/file_tools/gth-image-rotator.h
+++ b/extensions/file_tools/gth-image-rotator.h
@@ -58,7 +58,11 @@ struct _GthImageRotatorClass
 	/*< signals >*/
 
 	void (* changed)        (GthImageRotator *rotator);
-	void (* center_changed) (GthImageRotator *rotator);
+	void (* center_changed) (GthImageRotator *rotator,
+				 int              x,
+				 int              y);
+	void (* angle_changed)  (GthImageRotator *rotator,
+				 double           angle);
 };
 
 GType                 gth_image_rotator_get_type        (void);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]