[Rawstudio-commit] r869 - trunk/src

Anders Brander anders at brander.dk
Tue Oct 17 22:55:09 CEST 2006


Author: abrander
Date: 2006-10-17 22:55:09 +0200 (Tue, 17 Oct 2006)
New Revision: 869

Modified:
   trunk/src/drawingarea.c
   trunk/src/gtk-interface.c
   trunk/src/rawstudio.c
   trunk/src/rawstudio.h
   trunk/src/toolbox.c
Log:
Added GUI for crop.

Modified: trunk/src/drawingarea.c
===================================================================
--- trunk/src/drawingarea.c	2006-10-17 20:07:58 UTC (rev 868)
+++ trunk/src/drawingarea.c	2006-10-17 20:55:09 UTC (rev 869)
@@ -23,17 +23,67 @@
 #include "rawstudio.h"
 #include "color.h"
 #include "gtk-interface.h"
+#include "gtk-helper.h"
 #include "conf_interface.h"
+#include "rs-image.h"
 
 static gint start_x, start_y;
+static void draw_region_crop(RS_BLOB *rs, RS_RECT *region);
 static gboolean drawingarea_expose (GtkWidget *widget, GdkEventExpose *event, RS_BLOB *rs);
 static gboolean drawingarea_configure (GtkWidget *widget, GdkEventExpose *event, RS_BLOB *rs);
 static gboolean gui_drawingarea_move_callback(GtkWidget *widget, GdkEventMotion *event, RS_BLOB *rs);
 static gboolean gui_drawingarea_button(GtkWidget *widget, GdkEventButton *event, RS_BLOB *rs);
 
+static GdkPixmap *blitter = NULL;
+
+static void
+draw_region_crop(RS_BLOB *rs, RS_RECT *region)
+{
+	/* FIXME: This is so fucking unbelievable slow! */
+	gdk_draw_drawable(blitter,
+		rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+		rs->preview_backing_crop,
+		rs->preview_exposed->x1, rs->preview_exposed->y1,
+		rs->preview_exposed->x1, rs->preview_exposed->y1,
+		rs->preview_exposed->x2-rs->preview_exposed->x1,
+		rs->preview_exposed->y2-rs->preview_exposed->y1);
+	gdk_draw_drawable(blitter, /* FIXME: backing store may not be ready? */
+		rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+		rs->preview_backing,
+		rs->roi_scaled.x1, rs->roi_scaled.y1,
+		rs->roi_scaled.x1, rs->roi_scaled.y1,
+		rs->roi_scaled.x2-rs->roi_scaled.x1, rs->roi_scaled.y2-rs->roi_scaled.y1);
+	gdk_draw_line(blitter,
+		rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+		rs->roi_scaled.x1, rs->roi_scaled.y1,
+		rs->roi_scaled.x2, rs->roi_scaled.y1);
+	gdk_draw_line(blitter,
+		rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+		rs->roi_scaled.x2, rs->roi_scaled.y1,
+		rs->roi_scaled.x2, rs->roi_scaled.y2);
+	gdk_draw_line(blitter,
+		rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+		rs->roi_scaled.x2, rs->roi_scaled.y2,
+		rs->roi_scaled.x1, rs->roi_scaled.y2);
+	gdk_draw_line(blitter,
+		rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+		rs->roi_scaled.x1, rs->roi_scaled.y2,
+		rs->roi_scaled.x1, rs->roi_scaled.y1);
+	/* blit to screen */
+	gdk_draw_drawable(rs->preview_drawingarea->window,
+		rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+		blitter,
+		rs->preview_exposed->x1, rs->preview_exposed->y1,
+		rs->preview_exposed->x1, rs->preview_exposed->y1,
+		rs->preview_exposed->x2-rs->preview_exposed->x1,
+		rs->preview_exposed->y2-rs->preview_exposed->y1);
+	return;
+}
+
 gboolean
 drawingarea_expose (GtkWidget *widget, GdkEventExpose *event, RS_BLOB *rs)
 {
+	extern gint state;
 	GtkAdjustment *vadj;
 	GtkAdjustment *hadj;
 	vadj = gtk_viewport_get_vadjustment((GtkViewport *) widget->parent->parent);
@@ -42,26 +92,46 @@
 	rs->preview_exposed->y1 = (gint) vadj->value;
 	rs->preview_exposed->x2 = ((gint) hadj->page_size)+rs->preview_exposed->x1;
 	rs->preview_exposed->y2 = ((gint) vadj->page_size)+rs->preview_exposed->y1;
-	if (rs->preview_done)
-		gdk_draw_drawable(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
-			rs->preview_backing,
-			event->area.x, event->area.y,
-			event->area.x, event->area.y,
-			event->area.width, event->area.height);
-	else
-		update_preview_region(rs, rs->preview_exposed);
+	switch (state)
+	{
+		case STATE_NORMAL:
+			if (rs->preview_done)
+				gdk_draw_drawable(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+					rs->preview_backing,
+					event->area.x, event->area.y,
+					event->area.x, event->area.y,
+					event->area.width, event->area.height);
+			else
+				update_preview_region(rs, rs->preview_exposed);
+		default:
+			update_preview_region(rs, rs->preview_exposed);
+			break;
+	}
 	return(TRUE);
 }
 
 gboolean
 drawingarea_configure (GtkWidget *widget, GdkEventExpose *event, RS_BLOB *rs)
 {
+	extern gint state;
 	if (rs->preview_backing)
 		g_object_unref(rs->preview_backing);
 	rs->preview_backing = gdk_pixmap_new(widget->window,
 		widget->allocation.width,
 		widget->allocation.height, -1);
-	update_preview(rs, TRUE); /* evil hack to catch bogus configure events */
+	if (blitter)
+		g_object_unref(blitter);
+	blitter = gdk_pixmap_new(widget->window,
+		widget->allocation.width,
+		widget->allocation.height, -1);
+	if (state==STATE_CROP) /* is this the only state where we can expect configure? */
+	{
+		g_object_unref(rs->preview_backing_crop);
+		rs->preview_backing_crop = gdk_pixmap_new(widget->window,
+			widget->allocation.width,
+			widget->allocation.height, -1);
+	}
+	update_preview(rs, TRUE, FALSE); /* evil hack to catch bogus configure events */
 	return(TRUE);
 }
 
@@ -106,64 +176,283 @@
 }
 
 gboolean
-gui_drawingarea_button(GtkWidget *widget, GdkEventButton *event, RS_BLOB *rs)
+gui_drawingarea_crop_motion_callback(GtkWidget *widget, GdkEventMotion *event, RS_BLOB *rs)
 {
-	static GdkCursor *cursor;
-	static gint operation = OP_NONE;
-	static gint signal;
+	extern gint state;
 	gint x,y;
+	static RS_RECT last = {0,0,0,0};
+	RS_RECT region;
 
 	x = (gint) event->x;
 	y = (gint) event->y;
 
-	if (event->type == GDK_BUTTON_PRESS)
-	{ /* start */
-		switch(event->button)
+	switch (state)
+	{
+		case STATE_CROP_MOVE_N:
+			rs->roi_scaled.y1 = y;
+			break;
+		case STATE_CROP_MOVE_E:
+			rs->roi_scaled.x2 = x;
+			break;
+		case STATE_CROP_MOVE_S:
+			rs->roi_scaled.y2 = y;
+			break;
+		case STATE_CROP_MOVE_W:
+			rs->roi_scaled.x1 = x;
+			break;
+		case STATE_CROP_MOVE_NW:
+			rs->roi_scaled.x1 = x;
+			rs->roi_scaled.y1 = y;
+			break;
+		case STATE_CROP_MOVE_NE:
+			rs->roi_scaled.x2 = x;
+			rs->roi_scaled.y1 = y;
+			break;
+		case STATE_CROP_MOVE_SE:
+			rs->roi_scaled.x2 = x;
+			rs->roi_scaled.y2 = y;
+			break;
+		case STATE_CROP_MOVE_SW:
+			rs->roi_scaled.x1 = x;
+			rs->roi_scaled.y2 = y;
+			break;
+	}
+	if (rs->roi_scaled.x1 < 0)
+		rs->roi_scaled.x1 = 0;
+	if (rs->roi_scaled.x2 < 0)
+		rs->roi_scaled.x2 = 0;
+	if (rs->roi_scaled.y1 < 0)
+		rs->roi_scaled.y1 = 0;
+	if (rs->roi_scaled.y2 < 0)
+		rs->roi_scaled.y2 = 0;
+
+	if (rs->roi_scaled.x1 > rs->photo->preview->w)
+		rs->roi_scaled.x1 = rs->photo->preview->w-1;
+	if (rs->roi_scaled.x2 > rs->photo->preview->w)
+		rs->roi_scaled.x2 = rs->photo->preview->w-1;
+	if (rs->roi_scaled.y1 > rs->photo->preview->h)
+		rs->roi_scaled.y1 = rs->photo->preview->h-1;
+	if (rs->roi_scaled.y2 > rs->photo->preview->h)
+		rs->roi_scaled.y2 = rs->photo->preview->h-1;
+
+	if (rs->roi_scaled.x1 > rs->roi_scaled.x2)
+	{
+		SWAP(rs->roi_scaled.x1, rs->roi_scaled.x2);
+		switch (state)
 		{
-			case 1:
-				rs_set_wb_from_pixels(rs, x, y);
+			case STATE_CROP_MOVE_E:
+				state = STATE_CROP_MOVE_W;
 				break;
-			case 2:
-				if (!gui_is_busy())
-				{
-					operation = OP_MOVE;
-					cursor = gdk_cursor_new(GDK_FLEUR);
-					gdk_window_set_cursor(rs->preview_drawingarea->window, cursor);
-					start_x = (gint) event->x_root;
-					start_y = (gint) event->y_root;
-					signal = g_signal_connect (G_OBJECT (rs->preview_drawingarea), "motion_notify_event",
-						G_CALLBACK (gui_drawingarea_move_callback), rs);
-				}
-				else
-				{
-					operation = OP_BUSY;
-					cursor = gdk_cursor_new(GDK_WATCH);
-					gdk_window_set_cursor(rs->preview_drawingarea->window, cursor);
-				}
+			case STATE_CROP_MOVE_W:
+				state = STATE_CROP_MOVE_E;
 				break;
+			case STATE_CROP_MOVE_NW:
+				state = STATE_CROP_MOVE_NE;
+				break;
+			case STATE_CROP_MOVE_NE:
+				state = STATE_CROP_MOVE_NW;
+				break;
+			case STATE_CROP_MOVE_SW:
+				state = STATE_CROP_MOVE_SE;
+				break;
+			case STATE_CROP_MOVE_SE:
+				state = STATE_CROP_MOVE_SW;
+				break;
 		}
 	}
-	else
-	{ /* end */
-		switch(operation)
+	if (rs->roi_scaled.y1 > rs->roi_scaled.y2)
+	{
+		SWAP(rs->roi_scaled.y1, rs->roi_scaled.y2);
+		switch (state)
 		{
-			case OP_MOVE:
-				g_signal_handler_disconnect(rs->preview_drawingarea, signal);
-				update_preview_region(rs, rs->preview_exposed);
-				gdk_window_set_cursor(rs->preview_drawingarea->window, NULL);
-				gdk_cursor_unref(cursor);
-				operation = OP_NONE;
+			case STATE_CROP_MOVE_N:
+				state = STATE_CROP_MOVE_S;
 				break;
-			case OP_BUSY:
-				gdk_window_set_cursor(rs->preview_drawingarea->window, NULL);
-				gdk_cursor_unref(cursor);
-				operation = OP_NONE;
+			case STATE_CROP_MOVE_S:
+				state = STATE_CROP_MOVE_N;
 				break;
+			case STATE_CROP_MOVE_NW:
+				state = STATE_CROP_MOVE_SW;
+				break;
+			case STATE_CROP_MOVE_NE:
+				state = STATE_CROP_MOVE_SE;
+				break;
+			case STATE_CROP_MOVE_SW:
+				state = STATE_CROP_MOVE_NW;
+				break;
+			case STATE_CROP_MOVE_SE:
+				state = STATE_CROP_MOVE_NE;
+				break;
 		}
 	}
+	region.x1 = (rs->roi_scaled.x1 < last.x1) ? rs->roi_scaled.x1 : last.x1;
+	region.x2 = (rs->roi_scaled.x2 > last.x2) ? rs->roi_scaled.x2 : last.x2;
+	region.y1 = (rs->roi_scaled.y1 < last.y1) ? rs->roi_scaled.y1 : last.y1;
+	region.y2 = (rs->roi_scaled.y2 > last.y2) ? rs->roi_scaled.y2 : last.y2;
+	last.x1 = rs->roi_scaled.x1;
+	last.x2 = rs->roi_scaled.x2;
+	last.y1 = rs->roi_scaled.y1;
+	last.y2 = rs->roi_scaled.y2;
+
+	rs_rect_scale(&rs->roi_scaled, &rs->roi, 1.0/GETVAL(rs->scale));
+	draw_region_crop(rs, &region);
 	return(TRUE);
 }
 
+/* callbacks from popup-menu */
+static void
+gui_drawingarea_popup_crop(GtkMenuItem *menuitem, RS_BLOB *rs)
+{
+	rs_crop_start(rs);
+	return;
+}
+
+static void
+gui_drawingarea_popup_uncrop(GtkMenuItem *menuitem, RS_BLOB *rs)
+{
+	rs_crop_uncrop(rs);
+	return;
+}
+
+gboolean
+gui_drawingarea_button(GtkWidget *widget, GdkEventButton *event, RS_BLOB *rs)
+{
+	extern gint state;
+	static GdkCursor *cursor;
+	static gint operation = OP_NONE;
+	static gint signal;
+	gint x,y;
+
+	x = (gint) event->x;
+	y = (gint) event->y;
+
+	switch (state)
+	{
+		case STATE_NORMAL:
+			if (event->type == GDK_BUTTON_PRESS)
+			{ /* start */
+				switch(event->button)
+				{
+					case 1:
+						rs_set_wb_from_pixels(rs, x, y);
+						break;
+					case 2:
+						if (!gui_is_busy())
+						{
+							operation = OP_MOVE;
+							cursor = gdk_cursor_new(GDK_FLEUR);
+							gdk_window_set_cursor(rs->preview_drawingarea->window, cursor);
+							start_x = (gint) event->x_root;
+							start_y = (gint) event->y_root;
+							signal = g_signal_connect (G_OBJECT (rs->preview_drawingarea), "motion_notify_event",
+								G_CALLBACK (gui_drawingarea_move_callback), rs);
+						}
+						else
+						{
+							operation = OP_BUSY;
+							cursor = gdk_cursor_new(GDK_WATCH);
+							gdk_window_set_cursor(rs->preview_drawingarea->window, cursor);
+						}
+						break;
+					case 3:
+						if (!gui_is_busy())
+						{
+							GtkWidget *i, *menu = gtk_menu_new();
+
+					        i = gtk_menu_item_new_with_label ("Crop");
+        					gtk_widget_show (i);
+							gtk_menu_attach (GTK_MENU (menu), i, 0, 1, 0, 1);
+							g_signal_connect (i, "activate", G_CALLBACK (gui_drawingarea_popup_crop), rs);
+							if (rs->photo->input->parent)
+							{
+						        i = gtk_menu_item_new_with_label ("Uncrop");
+        						gtk_widget_show (i);
+								gtk_menu_attach (GTK_MENU (menu), i, 0, 1, 1, 2);
+								g_signal_connect (i, "activate", G_CALLBACK (gui_drawingarea_popup_uncrop), rs);
+							}
+							gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
+					}
+					break;
+				}
+			}
+			else
+			{ /* end */
+				switch(operation)
+				{
+					case OP_MOVE:
+						g_signal_handler_disconnect(rs->preview_drawingarea, signal);
+						update_preview_region(rs, rs->preview_exposed);
+						gdk_window_set_cursor(rs->preview_drawingarea->window, NULL);
+						gdk_cursor_unref(cursor);
+						operation = OP_NONE;
+						break;
+					case OP_BUSY:
+						gdk_window_set_cursor(rs->preview_drawingarea->window, NULL);
+						gdk_cursor_unref(cursor);
+						operation = OP_NONE;
+						break;
+				}
+			}
+			break;
+		case STATE_CROP:
+			if (event->type == GDK_BUTTON_PRESS)
+				switch(event->button)
+				{
+					case 1:
+						if (abs(x-rs->roi_scaled.x1)<10) /* west block */
+						{
+							if (abs(y-rs->roi_scaled.y1)<10)
+								state = STATE_CROP_MOVE_NW;
+							else if (abs(y-rs->roi_scaled.y2)<10)
+								state = STATE_CROP_MOVE_SW;
+							else if ((y>rs->roi_scaled.y1) && (y<rs->roi_scaled.y2))
+								state = STATE_CROP_MOVE_W;
+						}
+						else if (abs(x-rs->roi_scaled.x2)<10) /* east block */
+						{
+							if (abs(y-rs->roi_scaled.y1)<10)
+								state = STATE_CROP_MOVE_NE;
+							else if (abs(y-rs->roi_scaled.y2)<10)
+								state = STATE_CROP_MOVE_SE;
+							else if ((y>rs->roi_scaled.y1) && (y<rs->roi_scaled.y2))
+								state = STATE_CROP_MOVE_E;
+						}
+						else if ((x>rs->roi_scaled.x1) && (x<rs->roi_scaled.x2)) /* poles */
+						{
+							if (abs(y-rs->roi_scaled.y1)<10)
+								state = STATE_CROP_MOVE_N;
+							else if (abs(y-rs->roi_scaled.y2)<10)
+								state = STATE_CROP_MOVE_S;
+						}							
+						if (state!=STATE_CROP)
+							signal = g_signal_connect (G_OBJECT (rs->preview_drawingarea),
+								"motion_notify_event",
+								G_CALLBACK (gui_drawingarea_crop_motion_callback), rs);
+						break;
+					case 3:
+						/* DO IT */
+							if (((x>rs->roi_scaled.x1) && (x<rs->roi_scaled.x2)) && ((y>rs->roi_scaled.y1) && (y<rs->roi_scaled.y2)))
+								rs_crop_end(rs, TRUE);
+							else
+								rs_crop_end(rs, FALSE);
+							break;
+				}
+			break;
+		case STATE_CROP_MOVE_N:
+		case STATE_CROP_MOVE_E:
+		case STATE_CROP_MOVE_S:
+		case STATE_CROP_MOVE_W:
+		case STATE_CROP_MOVE_NW:
+		case STATE_CROP_MOVE_NE:
+		case STATE_CROP_MOVE_SE:
+		case STATE_CROP_MOVE_SW:
+			g_signal_handler_disconnect(rs->preview_drawingarea, signal);
+			state = STATE_CROP;
+			break;
+	}
+	return(TRUE);
+}
+
 /* hack to resize a bit nicer */
 gboolean
 zoom_to_fit_helper(RS_BLOB *rs)

Modified: trunk/src/gtk-interface.c
===================================================================
--- trunk/src/gtk-interface.c	2006-10-17 20:07:58 UTC (rev 868)
+++ trunk/src/gtk-interface.c	2006-10-17 20:55:09 UTC (rev 869)
@@ -153,7 +153,7 @@
 	if (rs->photo)
 	{
 		rs_settings_to_rs_settings_double(rs->settings[rs->current_setting], rs->photo->settings[rs->photo->current_setting]);
-		update_preview(rs, FALSE);
+		update_preview(rs, FALSE, FALSE);
 		gui_set_values(rs, -1, -1);
 	}
 	return(FALSE);
@@ -165,7 +165,7 @@
 	if (rs->photo)
 	{
 		rs_settings_to_rs_settings_double(rs->settings[rs->current_setting], rs->photo->settings[rs->photo->current_setting]);
-		update_preview(rs, TRUE);
+		update_preview(rs, TRUE, FALSE);
 		gui_set_values(rs, -1, -1);
 	}
 	return(FALSE);
@@ -382,6 +382,7 @@
 			rs_photo_free(rs->photo);
 			rs->photo = NULL;
 			rs_reset(rs);
+			rs_state_reset(rs);
 			photo = filetype->load(name);
 			if (!photo)
 			{
@@ -1602,7 +1603,7 @@
 	rs->in_use = FALSE;
 	rs_settings_reset(rs->settings[rs->current_setting], MASK_ALL);
 	rs->in_use = in_use;
-	update_preview(rs, TRUE);
+	update_preview(rs, TRUE, FALSE);
 	return;
 }
 
@@ -1628,7 +1629,7 @@
 	else
 	  gui_status_push(_("Hiding exposure mask"));
 	rs->show_exposure_overlay = GTK_CHECK_MENU_ITEM(widget)->active;
-	update_preview(rs, FALSE);
+	update_preview(rs, FALSE, FALSE);
 	return;
 }
 
@@ -1648,7 +1649,7 @@
 		rs->settings[rs->photo->current_setting]);
 	photo->filename = NULL;
 	rs_photo_free(photo);
-	update_preview(rs, TRUE);
+	update_preview(rs, TRUE, FALSE);
 	return;
 }
 
@@ -1745,7 +1746,7 @@
 				rs->in_use = FALSE;
 				rs_apply_settings_from_double(rs->settings[rs->photo->current_setting], rs->settings_buffer, mask);
 				rs->in_use = in_use;
-				update_preview(rs, TRUE);
+				update_preview(rs, TRUE, FALSE);
 
 				gui_status_push(_("Pasted settings"));
 			}

Modified: trunk/src/rawstudio.c
===================================================================
--- trunk/src/rawstudio.c	2006-10-17 20:07:58 UTC (rev 868)
+++ trunk/src/rawstudio.c	2006-10-17 20:55:09 UTC (rev 869)
@@ -41,6 +41,7 @@
 #include "rs-render.h"
 #include "rs-arch.h"
 
+gint state;
 static gushort loadtable[65536];
 
 static cmsHPROFILE testProfile = NULL;
@@ -53,7 +54,7 @@
 static cmsHTRANSFORM srgbTransform = NULL;
 
 inline void rs_photo_prepare(RS_PHOTO *photo);
-static void update_scaled(RS_BLOB *rs);
+static void update_scaled(RS_BLOB *rs, gboolean force);
 static inline void rs_render_mask(guchar *pixels, guchar *mask, guint length);
 static gboolean rs_render_idle(RS_BLOB *rs);
 static void rs_render_overlay(RS_PHOTO *photo, gint width, gint height, gushort *in,
@@ -148,15 +149,16 @@
 }
 
 void
-update_scaled(RS_BLOB *rs)
+update_scaled(RS_BLOB *rs, gboolean force)
 {
 	/* scale if needed */
-	if (rs->preview_scale != GETVAL(rs->scale))
+	if ((rs->preview_scale != GETVAL(rs->scale)) || force)
 	{
 		rs->preview_scale = GETVAL(rs->scale);
 		if (rs->photo->scaled)
 			rs_image16_free(rs->photo->scaled);
 		rs->photo->scaled = rs_image16_scale(rs->photo->input, NULL, rs->preview_scale);
+		rs_rect_scale(&rs->roi, &rs->roi_scaled, rs->preview_scale);
 		rs->preview_done = TRUE; /* stop rs_render_idle() */
 	}
 
@@ -200,13 +202,13 @@
 }
 
 void
-update_preview(RS_BLOB *rs, gboolean update_table)
+update_preview(RS_BLOB *rs, gboolean update_table, gboolean update_scale)
 {
 	if(unlikely(!rs->photo)) return;
 
 	if (update_table)
 		rs_render_previewtable(rs->photo->settings[rs->photo->current_setting]->contrast);
-	update_scaled(rs);
+	update_scaled(rs, update_scale);
 	rs_photo_prepare(rs->photo);
 	update_preview_region(rs, rs->preview_exposed);
 
@@ -235,36 +237,97 @@
 {
 	guchar *pixels;
 	gushort *in;
-	gint x1 = region->x1;
-	gint y1 = region->y1;
-	gint x2 = region->x2;
-	gint y2 = region->y2;
-
+	gint w, h;
 	if (unlikely(!rs->in_use)) return;
 
-	_CLAMP(x2, rs->photo->scaled->w);
-	_CLAMP(y2, rs->photo->scaled->h);
+	_CLAMP(region->x2, rs->photo->scaled->w);
+	_CLAMP(region->y2, rs->photo->scaled->h);
+	w = region->x2-region->x1;
+	h = region->y2-region->y1;
 
 	/* evil hack to fix crash after zoom */
-	if (unlikely(y2<y1)) /* FIXME: this is not good */
+	if (unlikely(region->y2 < region->y2)) /* FIXME: this is not good */
 		return;
 
-	pixels = rs->photo->preview->pixels+(y1*rs->photo->preview->rowstride+x1*rs->photo->preview->pixelsize);
-	in = rs->photo->scaled->pixels+(y1*rs->photo->scaled->rowstride+x1*rs->photo->scaled->pixelsize);
+	pixels = rs->photo->preview->pixels+(region->y1*rs->photo->preview->rowstride
+		+ region->x1*rs->photo->preview->pixelsize);
+	in = rs->photo->scaled->pixels+(region->y1*rs->photo->scaled->rowstride
+		+ region->x1*rs->photo->scaled->pixelsize);
 	if (unlikely(rs->show_exposure_overlay))
 	{
-		guchar *mask = rs->photo->mask->pixels+(y1*rs->photo->mask->rowstride+x1*rs->photo->mask->pixelsize);
-		rs_render_overlay(rs->photo, x2-x1, y2-y1, in, rs->photo->scaled->rowstride,
+		guchar *mask = rs->photo->mask->pixels+(region->y1*rs->photo->mask->rowstride
+			+region->x1*rs->photo->mask->pixelsize);
+		rs_render_overlay(rs->photo, w, h, in, rs->photo->scaled->rowstride,
 			rs->photo->scaled->pixelsize, pixels, rs->photo->preview->rowstride,
 			mask, rs->photo->mask->rowstride);
 	}
 	else
-		rs_render(rs->photo, x2-x1, y2-y1, in, rs->photo->scaled->rowstride,
-			rs->photo->scaled->pixelsize, pixels, rs->photo->preview->rowstride, displayTransform);
-	gdk_draw_rgb_image(rs->preview_drawingarea->window,
-		rs->preview_drawingarea->style->fg_gc[GTK_STATE_NORMAL],
-		x1, y1, x2-x1, y2-y1,
-		GDK_RGB_DITHER_NONE, pixels, rs->photo->preview->rowstride);
+		rs_render(rs->photo, w, h, in, rs->photo->scaled->rowstride,
+			rs->photo->scaled->pixelsize, pixels, rs->photo->preview->rowstride,
+			displayTransform);
+
+	if (rs->mark_roi) /* FIXME: This is SLOOOOOOOOOOOW */
+	{
+		gint size = rs->photo->preview->h * rs->photo->preview->rowstride;
+		guchar *buffer;
+		guchar *pixels_roi, *pixels_notroi;
+
+		buffer = g_malloc(size); /* FIXME: renders WAY too much */
+		while(size--) /* render backing store for pixels outside crop */
+			buffer[size] = ((rs->photo->preview->pixels[size]+63)*3)>>3;
+
+		pixels_roi = rs->photo->preview->pixels+(rs->roi_scaled.y1*rs->photo->preview->rowstride
+			+ rs->roi_scaled.x1*rs->photo->preview->pixelsize);
+		pixels_notroi = buffer+(region->y1*rs->photo->preview->rowstride
+			+ region->x1*rs->photo->preview->pixelsize);
+		/* draw all our stuff to backing-store */
+		gdk_draw_rgb_image(rs->preview_backing, /* not ROI */
+			rs->preview_drawingarea->style->fg_gc[GTK_STATE_NORMAL],
+			region->x1, region->y1, w, h,
+			GDK_RGB_DITHER_NONE, pixels_notroi, rs->photo->preview->rowstride);
+		gdk_draw_rgb_image(rs->preview_backing, /* ROI */
+			rs->preview_drawingarea->style->fg_gc[GTK_STATE_NORMAL],
+			rs->roi_scaled.x1, rs->roi_scaled.y1,
+			rs->roi_scaled.x2-rs->roi_scaled.x1,
+			rs->roi_scaled.y2-rs->roi_scaled.y1,
+			GDK_RGB_DITHER_NONE, pixels_roi, rs->photo->preview->rowstride);
+		gdk_draw_line(rs->preview_backing,
+			rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+			rs->roi_scaled.x1, rs->roi_scaled.y1,
+			rs->roi_scaled.x2, rs->roi_scaled.y1);
+		gdk_draw_line(rs->preview_backing,
+			rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+			rs->roi_scaled.x2, rs->roi_scaled.y1,
+			rs->roi_scaled.x2, rs->roi_scaled.y2);
+		gdk_draw_line(rs->preview_backing,
+			rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+			rs->roi_scaled.x2, rs->roi_scaled.y2,
+			rs->roi_scaled.x1, rs->roi_scaled.y2);
+		gdk_draw_line(rs->preview_backing,
+			rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+			rs->roi_scaled.x1, rs->roi_scaled.y2,
+			rs->roi_scaled.x1, rs->roi_scaled.y1);
+		/* blit to screen */
+		gdk_draw_drawable(rs->preview_drawingarea->window,
+			rs->preview_drawingarea->style->fg_gc[GTK_WIDGET_STATE (rs->preview_drawingarea)],
+			rs->preview_backing,
+			region->x1, region->y1,
+			region->x1, region->y1,
+			w, h);
+		/* update backing store for non-ROI */
+		gdk_draw_rgb_image(rs->preview_backing_crop,
+			rs->preview_drawingarea->style->fg_gc[GTK_STATE_NORMAL],
+			region->x1, region->y1, w, h,
+			GDK_RGB_DITHER_NONE, pixels_notroi, rs->photo->preview->rowstride);
+		g_free(buffer);
+	}
+	else
+	{
+		gdk_draw_rgb_image(rs->preview_drawingarea->window,
+			rs->preview_drawingarea->style->fg_gc[GTK_STATE_NORMAL],
+			region->x1, region->y1, w, h,
+			GDK_RGB_DITHER_NONE, pixels, rs->photo->preview->rowstride);
+	}
 	return;
 }
 
@@ -432,7 +495,7 @@
 	for(c=0;c<3;c++)
 		rs_settings_reset(rs->settings[c], MASK_ALL);
 	rs->in_use = in_use;
-	update_preview(rs, TRUE);
+	update_preview(rs, TRUE, FALSE);
 	return;
 }
 
@@ -717,6 +780,7 @@
 	rs->preview_idle_render = FALSE;
 	rs->settings_buffer = NULL;
 	rs->in_use = FALSE;
+	rs->mark_roi = FALSE;
 	rs->show_exposure_overlay = FALSE;
 	rs->photo = NULL;
 	rs->queue = batch_new_queue();
@@ -1206,6 +1270,121 @@
 	return;
 }
 
+void
+rs_rect_scale(RS_RECT *in, RS_RECT *out, gdouble scale)
+{
+	out->x1 = (gint) (((gdouble) in->x1)*scale);
+	out->x2 = (gint) (((gdouble) in->x2)*scale);
+	out->y1 = (gint) (((gdouble) in->y1)*scale);
+	out->y2 = (gint) (((gdouble) in->y2)*scale);
+	return;
+}
+
+void
+rs_roi_orientation(RS_BLOB *rs)
+{
+	gint x1,x2,y1,y2;
+	const gint rot = (rs->photo->orientation&3)%4;
+	x1 = rs->roi.x1;
+	y1 = rs->roi.y1;
+	x2 = rs->roi.x2;
+	y2 = rs->roi.y2;
+
+	/* rotate and flip */
+	switch(rot)
+	{
+		case 1:
+			x1 = rs->roi.y1;
+			y1 = rs->photo->input->h - rs->roi.x1;
+			x2 = rs->roi.y2;
+			y2 = rs->photo->input->h - rs->roi.x2;
+			break;
+		case 2:
+			x1 = rs->photo->input->w - rs->roi.x2;
+			y1 = rs->photo->input->h - rs->roi.y2;
+			x2 = rs->photo->input->w - rs->roi.x1;
+			y2 = rs->photo->input->h - rs->roi.y1;
+			break;
+		case 3:
+			x1 = rs->photo->input->w - rs->roi.y1;
+			y1 = rs->roi.x1;
+			x2 = rs->photo->input->w - rs->roi.y2;
+			y2 = rs->roi.x2;
+			break;
+	}
+
+	if (rs->photo->orientation&4)
+	{
+		y1 = rs->photo->input->h-y1;
+		y2 = rs->photo->input->h-y2;
+	}
+
+	rs->roi.x1 = x1;
+	rs->roi.y1 = y1;
+	rs->roi.x2 = x2;
+	rs->roi.y2 = y2;
+
+	/* normalize */
+	if (rs->roi.x1 > rs->roi.x2)
+		SWAP(rs->roi.x1, rs->roi.x2);
+	if (rs->roi.y1 > rs->roi.y2)
+		SWAP(rs->roi.y1, rs->roi.y2);
+	return;
+}
+
+void
+rs_crop_start(RS_BLOB *rs)
+{
+	rs->roi.x1 = 20;
+	rs->roi.y1 = 20;
+	rs->roi.x2 = rs->photo->input->w-20;
+	rs->roi.y2 = rs->photo->input->h-20;
+	rs_rect_scale(&rs->roi, &rs->roi_scaled, GETVAL(rs->scale));
+
+	rs->preview_backing_crop = gdk_pixmap_new(rs->preview_drawingarea->window,
+		rs->preview_drawingarea->allocation.width,
+		rs->preview_drawingarea->allocation.height, -1);
+
+	rs->mark_roi = TRUE;
+	state = STATE_CROP;
+	update_preview(rs, FALSE, FALSE);
+	return;
+}
+
+void
+rs_crop_end(RS_BLOB *rs, gboolean accept)
+{
+	if (accept)
+	{
+		rs_roi_orientation(rs);
+		rs_image16_crop(&rs->photo->input, &rs->roi);
+	}
+	rs->mark_roi = FALSE;
+	state = STATE_NORMAL;
+	update_preview(rs, FALSE, TRUE);
+	g_object_unref(rs->preview_backing_crop);
+	return;
+}
+
+void
+rs_crop_uncrop(RS_BLOB *rs)
+{
+	rs_image16_uncrop(&rs->photo->input);
+	update_preview(rs, FALSE, TRUE);
+	return;
+}
+
+void
+rs_state_reset(RS_BLOB *rs)
+{
+	switch (state)
+	{
+		case STATE_CROP:
+			rs_crop_end(rs, FALSE);
+			break;
+	}
+}
+
 gchar *
 rs_get_profile(gint type)
 {
@@ -1477,6 +1656,7 @@
 	textdomain(GETTEXT_PACKAGE);
 #endif
 	RS_BLOB *rs;
+	state = STATE_NORMAL;
 	rs_init_filetypes();
 	gtk_init(&argc, &argv);
 	rs = rs_new();

Modified: trunk/src/rawstudio.h
===================================================================
--- trunk/src/rawstudio.h	2006-10-17 20:07:58 UTC (rev 868)
+++ trunk/src/rawstudio.h	2006-10-17 20:55:09 UTC (rev 869)
@@ -47,6 +47,19 @@
 	gtk_adjustment_set_value((GtkAdjustment *) adjustment, value)
 
 enum {
+	STATE_NORMAL,
+	STATE_CROP,
+	STATE_CROP_MOVE_N,
+	STATE_CROP_MOVE_E,
+	STATE_CROP_MOVE_S,
+	STATE_CROP_MOVE_W,
+	STATE_CROP_MOVE_NW,
+	STATE_CROP_MOVE_NE,
+	STATE_CROP_MOVE_SE,
+	STATE_CROP_MOVE_SW,
+};
+
+enum {
 	MASK_EXPOSURE = 1,
 	MASK_SATURATION = 2,
 	MASK_HUE = 4,
@@ -175,10 +188,13 @@
 typedef struct {
 	gboolean in_use;
 	RS_PHOTO *photo;
+	RS_RECT roi;
+	RS_RECT roi_scaled;
 	RS_SETTINGS_DOUBLE *settings_buffer;
 	RS_SETTINGS *settings[3];
 	gint current_setting;
 	GtkObject *scale;
+	gboolean mark_roi;
 	gdouble preview_scale;
 	gboolean zoom_to_fit;
 	RS_RECT *preview_exposed;
@@ -191,6 +207,7 @@
 	gboolean preview_idle_render;
 	gboolean preview_done;
 	GdkPixmap *preview_backing;
+	GdkPixmap *preview_backing_crop;
 	gint preview_idle_render_lastrow;
 	gboolean show_exposure_overlay;
 	GArray *batch_queue;
@@ -225,7 +242,7 @@
 
 void rs_local_cachedir(gboolean new_value);
 void rs_load_gdk(gboolean new_value);
-void update_preview(RS_BLOB *rs, gboolean update_table);
+void update_preview(RS_BLOB *rs, gboolean update_table, gboolean update_scale);
 void update_preview_region(RS_BLOB *rs, RS_RECT *region);
 gboolean rs_run_batch_idle(RS_QUEUE *queue);
 void rs_reset(RS_BLOB *rs);
@@ -253,6 +270,12 @@
 void rs_set_wb(RS_BLOB *rs, gfloat warmth, gfloat tint);
 void rs_render_pixel_to_srgb(RS_BLOB *rs, gint x, gint y, guchar *dest);
 void rs_apply_settings_from_double(RS_SETTINGS *rss, RS_SETTINGS_DOUBLE *rsd, gint mask);
+void rs_rect_scale(RS_RECT *in, RS_RECT *out, gdouble scale);
+void rs_roi_orientation(RS_BLOB *rs);
+void rs_crop_start(RS_BLOB *rs);
+void rs_crop_end(RS_BLOB *rs, gboolean accept);
+void rs_crop_uncrop(RS_BLOB *rs);
+void rs_state_reset(RS_BLOB *rs);
 gchar *rs_get_profile(gint type);
 gboolean rs_cms_is_profile_valid(const gchar *path);
 void rs_cms_prepare_transforms(RS_BLOB *rs);

Modified: trunk/src/toolbox.c
===================================================================
--- trunk/src/toolbox.c	2006-10-17 20:07:58 UTC (rev 868)
+++ trunk/src/toolbox.c	2006-10-17 20:55:09 UTC (rev 869)
@@ -103,35 +103,35 @@
 gui_transform_rot90_clicked(GtkWidget *w, RS_BLOB *rs)
 {
 	ORIENTATION_90(rs->photo->orientation);
-	update_preview(rs, FALSE);
+	update_preview(rs, FALSE, FALSE);
 }
 
 void
 gui_transform_rot180_clicked(GtkWidget *w, RS_BLOB *rs)
 {
 	ORIENTATION_180(rs->photo->orientation);
-	update_preview(rs, FALSE);
+	update_preview(rs, FALSE, FALSE);
 }
 
 void
 gui_transform_rot270_clicked(GtkWidget *w, RS_BLOB *rs)
 {
 	ORIENTATION_270(rs->photo->orientation);
-	update_preview(rs, FALSE);
+	update_preview(rs, FALSE, FALSE);
 }
 
 void
 gui_transform_mirror_clicked(GtkWidget *w, RS_BLOB *rs)
 {
 	ORIENTATION_MIRROR(rs->photo->orientation);
-	update_preview(rs, FALSE);
+	update_preview(rs, FALSE, FALSE);
 }
 
 void
 gui_transform_flip_clicked(GtkWidget *w, RS_BLOB *rs)
 {
 	ORIENTATION_FLIP(rs->photo->orientation);
-	update_preview(rs, FALSE);
+	update_preview(rs, FALSE, FALSE);
 }
 
 GtkWidget *




More information about the Rawstudio-commit mailing list