diff --git a/ChangeLog b/ChangeLog index 6820c38ae4..c34962132e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2001-02-07 Michael Natterer + + * app/gimppreview.[ch]: allocate less temp_bufs by removing the + "create_preview" virtual function and adding a "render" one. + + Implementations have to call the new public function + gimp_preview_render_and_flush() to render their temp_bufs. + This way, e.g. the GimpPatternPreview can render the preview + directly from the pattern's mask. + + * app/gimpdrawablepreview.c + * app/gimpimagepreview.c + * app/gimppatternpreview.c: changed accordingly. + + * app/gimpbrushpreview.[ch]: same as above and added BrushPipe + popup animation. + 2001-02-07 Michael Natterer * app/gimppreview.[ch] diff --git a/app/gimpbrushpreview.c b/app/gimpbrushpreview.c index fa1a6b05e7..426b1fa39e 100644 --- a/app/gimpbrushpreview.c +++ b/app/gimpbrushpreview.c @@ -34,9 +34,12 @@ static void gimp_brush_preview_class_init (GimpBrushPreviewClass *klass); static void gimp_brush_preview_init (GimpBrushPreview *preview); -static TempBuf * gimp_brush_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_brush_preview_create_popup (GimpPreview *preview); -static gboolean gimp_brush_preview_needs_popup (GimpPreview *preview); +static void gimp_brush_preview_destroy (GtkObject *object); +static void gimp_brush_preview_render (GimpPreview *preview); +static GtkWidget * gimp_brush_preview_create_popup (GimpPreview *preview); +static gboolean gimp_brush_preview_needs_popup (GimpPreview *preview); + +static gboolean gimp_brush_preview_render_timeout_func (GimpBrushPreview *preview); static GimpPreviewClass *parent_class = NULL; @@ -78,14 +81,37 @@ gimp_brush_preview_class_init (GimpBrushPreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); - preview_class->create_preview = gimp_brush_preview_create_preview; + object_class->destroy = gimp_brush_preview_destroy; + + preview_class->render = gimp_brush_preview_render; preview_class->create_popup = gimp_brush_preview_create_popup; preview_class->needs_popup = gimp_brush_preview_needs_popup; } static void -gimp_brush_preview_init (GimpBrushPreview *preview) +gimp_brush_preview_init (GimpBrushPreview *brush_preview) { + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; +} + +static void +gimp_brush_preview_destroy (GtkObject *object) +{ + GimpBrushPreview *brush_preview; + + brush_preview = GIMP_BRUSH_PREVIEW (object); + + if (brush_preview->pipe_timeout_id) + { + g_source_remove (brush_preview->pipe_timeout_id); + + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + GTK_OBJECT_CLASS (parent_class)->destroy (object); } #define indicator_width 7 @@ -95,20 +121,30 @@ gimp_brush_preview_init (GimpBrushPreview *preview) #define BLK { 0, 0, 0 } #define RED { 255, 127, 127 } -static TempBuf * -gimp_brush_preview_create_preview (GimpPreview *preview) +static void +gimp_brush_preview_render (GimpPreview *preview) { - GimpBrush *brush; - TempBuf *temp_buf; - gint width; - gint height; - gint brush_width; - gint brush_height; - guchar *buf; - guchar *b; - gint x, y; - gint offset_x; - gint offset_y; + GimpBrushPreview *brush_preview; + GimpBrush *brush; + TempBuf *temp_buf; + gint width; + gint height; + gint brush_width; + gint brush_height; + guchar *buf; + guchar *b; + gint x, y; + gint offset_x; + gint offset_y; + + brush_preview = GIMP_BRUSH_PREVIEW (preview); + + if (brush_preview->pipe_timeout_id) + { + g_source_remove (brush_preview->pipe_timeout_id); + + brush_preview->pipe_timeout_id = 0; + } brush = GIMP_BRUSH (preview->viewable); brush_width = brush->mask->width; @@ -118,10 +154,38 @@ gimp_brush_preview_create_preview (GimpPreview *preview) height = GTK_WIDGET (preview)->requisition.height; temp_buf = gimp_viewable_get_new_preview (preview->viewable, - width, height); + width, + height); if (preview->is_popup) - return temp_buf; + { + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + if (GIMP_IS_BRUSH_PIPE (brush)) + { + if (width != brush_width || + height != brush_height) + { + g_warning ("%s(): non-fullsize pipe popups are not supported yet.", + G_GNUC_FUNCTION); + return; + } + + brush_preview->pipe_animation_index = 0; + brush_preview->pipe_timeout_id = + g_timeout_add (300, + (GSourceFunc) gimp_brush_preview_render_timeout_func, + brush_preview); + } + + return; + } buf = temp_buf_data (temp_buf); @@ -213,7 +277,13 @@ gimp_brush_preview_create_preview (GimpPreview *preview) #undef BLK #undef RED - return temp_buf; + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); } static GtkWidget * @@ -255,3 +325,54 @@ gimp_brush_preview_needs_popup (GimpPreview *preview) return FALSE; } + +static gboolean +gimp_brush_preview_render_timeout_func (GimpBrushPreview *brush_preview) +{ + GimpPreview *preview; + GimpBrushPipe *brush_pipe; + GimpBrush *brush; + TempBuf *temp_buf; + gint width; + gint height; + gint brush_width; + gint brush_height; + + preview = GIMP_PREVIEW (brush_preview); + + if (! preview->viewable) + { + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; + + return FALSE; + } + + brush_pipe = GIMP_BRUSH_PIPE (preview->viewable); + brush_width = brush->mask->width; + brush_height = brush->mask->height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + brush_preview->pipe_animation_index++; + + if (brush_preview->pipe_animation_index >= brush_pipe->nbrushes) + brush_preview->pipe_animation_index = 0; + + brush = GIMP_BRUSH (brush_pipe->brushes[brush_preview->pipe_animation_index]); + + temp_buf = gimp_viewable_get_new_preview (GIMP_VIEWABLE (brush), + width, + height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + return TRUE; +} diff --git a/app/gimpbrushpreview.h b/app/gimpbrushpreview.h index e2f08d44eb..dce102a208 100644 --- a/app/gimpbrushpreview.h +++ b/app/gimpbrushpreview.h @@ -42,7 +42,10 @@ typedef struct _GimpBrushPreviewClass GimpBrushPreviewClass; struct _GimpBrushPreview { - GimpPreview parent_instance; + GimpPreview parent_instance; + + guint pipe_timeout_id; + gint pipe_animation_index; }; struct _GimpBrushPreviewClass diff --git a/app/gimpdrawablepreview.c b/app/gimpdrawablepreview.c index 468b607793..294fd4ff64 100644 --- a/app/gimpdrawablepreview.c +++ b/app/gimpdrawablepreview.c @@ -31,8 +31,8 @@ static void gimp_drawable_preview_class_init (GimpDrawablePreviewClass *klass); static void gimp_drawable_preview_init (GimpDrawablePreview *preview); -static TempBuf * gimp_drawable_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_drawable_preview_create_popup (GimpPreview *preview); +static void gimp_drawable_preview_render (GimpPreview *preview); +static GtkWidget * gimp_drawable_preview_create_popup (GimpPreview *preview); static GimpPreviewClass *parent_class = NULL; @@ -80,8 +80,8 @@ gimp_drawable_preview_init (GimpDrawablePreview *preview) { } -static TempBuf * -gimp_drawable_preview_create_preview (GimpPreview *preview) +static void +gimp_drawable_preview_render (GimpPreview *preview) { } diff --git a/app/gimpimagepreview.c b/app/gimpimagepreview.c index 261a141098..7cb0e919e8 100644 --- a/app/gimpimagepreview.c +++ b/app/gimpimagepreview.c @@ -36,14 +36,14 @@ static void gimp_image_preview_class_init (GimpImagePreviewClass *klass); static void gimp_image_preview_init (GimpImagePreview *preview); -static TempBuf * gimp_image_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_image_preview_create_popup (GimpPreview *preview); -static void gimp_image_preview_calc_size (GimpImage *gimage, - gint width, - gint height, - gint *return_width, - gint *return_height, - gboolean *scaling_up); +static void gimp_image_preview_render (GimpPreview *preview); +static GtkWidget * gimp_image_preview_create_popup (GimpPreview *preview); +static void gimp_image_preview_calc_size (GimpImage *gimage, + gint width, + gint height, + gint *return_width, + gint *return_height, + gboolean *scaling_up); static GimpPreviewClass *parent_class = NULL; @@ -85,8 +85,8 @@ gimp_image_preview_class_init (GimpImagePreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); - preview_class->create_preview = gimp_image_preview_create_preview; - preview_class->create_popup = gimp_image_preview_create_popup; + preview_class->render = gimp_image_preview_render; + preview_class->create_popup = gimp_image_preview_create_popup; } static void @@ -94,8 +94,8 @@ gimp_image_preview_init (GimpImagePreview *preview) { } -static TempBuf * -gimp_image_preview_create_preview (GimpPreview *preview) +static void +gimp_image_preview_render (GimpPreview *preview) { GimpImage *gimage; gint width; @@ -103,7 +103,7 @@ gimp_image_preview_create_preview (GimpPreview *preview) gint preview_width; gint preview_height; gboolean scaling_up; - TempBuf *return_buf; + TempBuf *render_buf; gimage = GIMP_IMAGE (preview->viewable); @@ -124,43 +124,59 @@ gimp_image_preview_create_preview (GimpPreview *preview) temp_buf = gimp_viewable_get_new_preview (preview->viewable, gimage->width, gimage->height); - return_buf = temp_buf_scale (temp_buf, preview_width, preview_height); + render_buf = temp_buf_scale (temp_buf, preview_width, preview_height); temp_buf_free (temp_buf); } else { - return_buf = gimp_viewable_get_new_preview (preview->viewable, + render_buf = gimp_viewable_get_new_preview (preview->viewable, preview_width, preview_height); } - if (preview_width < width) return_buf->x = (width - preview_width) / 2; - if (preview_height < height) return_buf->y = (height - preview_height) / 2; + if (preview_width < width) render_buf->x = (width - preview_width) / 2; + if (preview_height < height) render_buf->y = (height - preview_height) / 2; - if (return_buf->x || return_buf->y) + if (render_buf->x || render_buf->y) { TempBuf *temp_buf; guchar white[4] = { 255, 255, 255, 255 }; temp_buf = temp_buf_new (width, height, - return_buf->bytes, + render_buf->bytes, 0, 0, white); - temp_buf_copy_area (return_buf, temp_buf, + temp_buf_copy_area (render_buf, temp_buf, 0, 0, - return_buf->width, - return_buf->height, - return_buf->x, - return_buf->y); + render_buf->width, + render_buf->height, + render_buf->x, + render_buf->y); - temp_buf_free (return_buf); + temp_buf_free (render_buf); - return temp_buf; + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + return; } - return return_buf; + gimp_preview_render_and_flush (preview, + render_buf, + width, + height, + -1); + + temp_buf_free (render_buf); + + return; } static GtkWidget * diff --git a/app/gimppatternpreview.c b/app/gimppatternpreview.c index d0ec8d8ff1..7f0c7fad32 100644 --- a/app/gimppatternpreview.c +++ b/app/gimppatternpreview.c @@ -33,6 +33,7 @@ static void gimp_pattern_preview_class_init (GimpPatternPreviewClass *klass); static void gimp_pattern_preview_init (GimpPatternPreview *preview); +static void gimp_pattern_preview_render (GimpPreview *preview); static GtkWidget * gimp_pattern_preview_create_popup (GimpPreview *preview); static gboolean gimp_pattern_preview_needs_popup (GimpPreview *preview); @@ -76,6 +77,7 @@ gimp_pattern_preview_class_init (GimpPatternPreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); + preview_class->render = gimp_pattern_preview_render; preview_class->create_popup = gimp_pattern_preview_create_popup; preview_class->needs_popup = gimp_pattern_preview_needs_popup; } @@ -85,6 +87,58 @@ gimp_pattern_preview_init (GimpPatternPreview *preview) { } +static void +gimp_pattern_preview_render (GimpPreview *preview) +{ + GimpPattern *pattern; + TempBuf *temp_buf; + gint width; + gint height; + gint pattern_width; + gint pattern_height; + + pattern = GIMP_PATTERN (preview->viewable); + pattern_width = pattern->mask->width; + pattern_height = pattern->mask->height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + if (width == pattern_width && + height == pattern_height) + { + gimp_preview_render_and_flush (preview, + pattern->mask, + width, + height, + -1); + + return; + } + else if (width <= pattern_width && + height <= pattern_height) + { + gimp_preview_render_and_flush (preview, + pattern->mask, + width, + height, + -1); + + return; + } + + temp_buf = gimp_viewable_get_new_preview (preview->viewable, + width, height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); +} + static GtkWidget * gimp_pattern_preview_create_popup (GimpPreview *preview) { diff --git a/app/gimppreview.c b/app/gimppreview.c index d05ce15ec4..854e0e1c3c 100644 --- a/app/gimppreview.c +++ b/app/gimppreview.c @@ -56,7 +56,7 @@ enum { CLICKED, - CREATE_PREVIEW, + RENDER, CREATE_POPUP, NEEDS_POPUP, LAST_SIGNAL @@ -77,8 +77,8 @@ static gint gimp_preview_enter_notify_event (GtkWidget *widget, static gint gimp_preview_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event); -static TempBuf * gimp_preview_create_preview (GimpPreview *preview); -static TempBuf * gimp_preview_real_create_preview (GimpPreview *preview); +static void gimp_preview_render (GimpPreview *preview); +static void gimp_preview_real_render (GimpPreview *preview); static GtkWidget * gimp_preview_create_popup (GimpPreview *preview); static GtkWidget * gimp_preview_real_create_popup (GimpPreview *preview); static gboolean gimp_preview_needs_popup (GimpPreview *preview); @@ -142,14 +142,14 @@ gimp_preview_class_init (GimpPreviewClass *klass) gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); - preview_signals[CREATE_PREVIEW] = - gtk_signal_new ("create_preview", + preview_signals[RENDER] = + gtk_signal_new ("render", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET (GimpPreviewClass, - create_preview), - gimp_marshal_POINTER__NONE, - GTK_TYPE_POINTER, 0); + render), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); preview_signals[CREATE_POPUP] = gtk_signal_new ("create_popup", @@ -179,10 +179,10 @@ gimp_preview_class_init (GimpPreviewClass *klass) widget_class->enter_notify_event = gimp_preview_enter_notify_event; widget_class->leave_notify_event = gimp_preview_leave_notify_event; - klass->clicked = NULL; - klass->create_preview = gimp_preview_real_create_preview; - klass->create_popup = gimp_preview_real_create_popup; - klass->needs_popup = gimp_preview_real_needs_popup; + klass->clicked = NULL; + klass->render = gimp_preview_real_render; + klass->create_popup = gimp_preview_real_create_popup; + klass->needs_popup = gimp_preview_real_needs_popup; } static void @@ -386,24 +386,31 @@ gimp_preview_leave_notify_event (GtkWidget *widget, return FALSE; } -static TempBuf * -gimp_preview_create_preview (GimpPreview *preview) +static void +gimp_preview_render (GimpPreview *preview) { - TempBuf *temp_buf = NULL; - - gtk_signal_emit (GTK_OBJECT (preview), preview_signals[CREATE_PREVIEW], - &temp_buf); - - return temp_buf; + gtk_signal_emit (GTK_OBJECT (preview), preview_signals[RENDER]); } -static TempBuf * -gimp_preview_real_create_preview (GimpPreview *preview) +static void +gimp_preview_real_render (GimpPreview *preview) { - return + TempBuf *temp_buf; + gint width; + gint height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + temp_buf = gimp_viewable_get_new_preview (preview->viewable, - GTK_WIDGET (preview)->requisition.width, - GTK_WIDGET (preview)->requisition.height); + width, height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); } static GtkWidget * @@ -564,229 +571,223 @@ gimp_preview_paint (GimpPreview *preview) static gboolean gimp_preview_idle_paint (GimpPreview *preview) { - TempBuf *temp_buf; - gint width; - gint height; - gint channel; - preview->idle_id = 0; if (! preview->viewable) return FALSE; - temp_buf = gimp_preview_create_preview (preview); - - width = temp_buf->width; - height = temp_buf->height; - channel = -1; - - /* from layers_dialog.c */ - { - guchar *src, *s; - guchar *cb; - guchar *buf; - gint a; - gint i, j, b; - gint x1, y1, x2, y2; - gint rowstride; - gboolean color_buf; - gboolean color; - gint alpha; - gboolean has_alpha; - gint image_bytes; - gint offset; - - alpha = ALPHA_PIX; - - /* Here are the different cases this functions handles correctly: - * 1) Offset temp_buf which does not necessarily cover full image area - * 2) Color conversion of temp_buf if it is gray and image is color - * 3) Background check buffer for transparent temp_bufs - * 4) Using the optional "channel" argument, one channel can be extracted - * from a multi-channel temp_buf and composited as a grayscale - * Prereqs: - * 1) Grayscale temp_bufs have bytes == {1, 2} - * 2) Color temp_bufs have bytes == {3, 4} - * 3) If image is gray, then temp_buf should have bytes == {1, 2} - */ - color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); - image_bytes = (color_buf) ? 3 : 1; - has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); - rowstride = temp_buf->width * temp_buf->bytes; - - /* Determine if the preview buf supplied is color - * Generally, if the bytes == {3, 4}, this is true. - * However, if the channel argument supplied is not -1, then - * the preview buf is assumed to be gray despite the number of - * channels it contains - */ - color = ((channel == -1) && - (temp_buf->bytes == 3 || temp_buf->bytes == 4)); - - if (has_alpha) - { - buf = render_check_buf; - alpha = ((color) ? ALPHA_PIX : - ((channel != -1) ? (temp_buf->bytes - 1) : - ALPHA_G_PIX)); - } - else - { - buf = render_empty_buf; - } - - x1 = CLAMP (temp_buf->x, 0, width); - y1 = CLAMP (temp_buf->y, 0, height); - x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); - y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); - - src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + - (x1 - temp_buf->x) * temp_buf->bytes); - - /* One last thing for efficiency's sake: */ - if (channel == -1) - channel = 0; - - for (i = 0; i < height; i++) - { - if (i & 0x4) - { - offset = 4; - cb = buf + offset * 3; - } - else - { - offset = 0; - cb = buf; - } - - /* The interesting stuff between leading & trailing - * vertical transparency - */ - if (i >= y1 && i < y2) - { - /* Handle the leading transparency */ - for (j = 0; j < x1; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - /* The stuff in the middle */ - s = src; - for (j = x1; j < x2; j++) - { - if (color) - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[BLUE_PIX])]; - } - else - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[BLUE_PIX])]; - } - } - else - { - render_temp_buf[j * 3 + 0] = s[RED_PIX]; - render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; - render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; - } - } - else - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_dark_check [(a | s[GRAY_PIX + channel])]; - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_light_check [(a | s[GRAY_PIX + channel])]; - } - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; - } - else - { - render_temp_buf[j] = s[GRAY_PIX + channel]; - } - } - } - - s += temp_buf->bytes; - } - - /* Handle the trailing transparency */ - for (j = x2; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - src += rowstride; - } - else - { - for (j = 0; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - } - - gtk_preview_draw_row (GTK_PREVIEW (preview), - render_temp_buf, 0, i, width); - } - } - - temp_buf_free (temp_buf); - - gtk_widget_queue_draw (GTK_WIDGET (preview)); + gimp_preview_render (preview); return FALSE; } + +void +gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel) +{ + guchar *src, *s; + guchar *cb; + guchar *buf; + gint a; + gint i, j, b; + gint x1, y1, x2, y2; + gint rowstride; + gboolean color_buf; + gboolean color; + gint alpha; + gboolean has_alpha; + gint image_bytes; + gint offset; + + alpha = ALPHA_PIX; + + /* Here are the different cases this functions handles correctly: + * 1) Offset temp_buf which does not necessarily cover full image area + * 2) Color conversion of temp_buf if it is gray and image is color + * 3) Background check buffer for transparent temp_bufs + * 4) Using the optional "channel" argument, one channel can be extracted + * from a multi-channel temp_buf and composited as a grayscale + * Prereqs: + * 1) Grayscale temp_bufs have bytes == {1, 2} + * 2) Color temp_bufs have bytes == {3, 4} + * 3) If image is gray, then temp_buf should have bytes == {1, 2} + */ + color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); + image_bytes = (color_buf) ? 3 : 1; + has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); + rowstride = temp_buf->width * temp_buf->bytes; + + /* Determine if the preview buf supplied is color + * Generally, if the bytes == {3, 4}, this is true. + * However, if the channel argument supplied is not -1, then + * the preview buf is assumed to be gray despite the number of + * channels it contains + */ + color = ((channel == -1) && + (temp_buf->bytes == 3 || temp_buf->bytes == 4)); + + if (has_alpha) + { + buf = render_check_buf; + alpha = ((color) ? ALPHA_PIX : + ((channel != -1) ? (temp_buf->bytes - 1) : + ALPHA_G_PIX)); + } + else + { + buf = render_empty_buf; + } + + x1 = CLAMP (temp_buf->x, 0, width); + y1 = CLAMP (temp_buf->y, 0, height); + x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); + y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); + + src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + + (x1 - temp_buf->x) * temp_buf->bytes); + + /* One last thing for efficiency's sake: */ + if (channel == -1) + channel = 0; + + for (i = 0; i < height; i++) + { + if (i & 0x4) + { + offset = 4; + cb = buf + offset * 3; + } + else + { + offset = 0; + cb = buf; + } + + /* The interesting stuff between leading & trailing + * vertical transparency + */ + if (i >= y1 && i < y2) + { + /* Handle the leading transparency */ + for (j = 0; j < x1; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + /* The stuff in the middle */ + s = src; + for (j = x1; j < x2; j++) + { + if (color) + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[BLUE_PIX])]; + } + else + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[BLUE_PIX])]; + } + } + else + { + render_temp_buf[j * 3 + 0] = s[RED_PIX]; + render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; + render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; + } + } + else + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_dark_check [(a | s[GRAY_PIX + channel])]; + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_light_check [(a | s[GRAY_PIX + channel])]; + } + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; + } + else + { + render_temp_buf[j] = s[GRAY_PIX + channel]; + } + } + } + + s += temp_buf->bytes; + } + + /* Handle the trailing transparency */ + for (j = x2; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + src += rowstride; + } + else + { + for (j = 0; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), + render_temp_buf, 0, i, width); + } + + gtk_widget_queue_draw (GTK_WIDGET (preview)); +} diff --git a/app/gimppreview.h b/app/gimppreview.h index e01d170d04..2266688ff7 100644 --- a/app/gimppreview.h +++ b/app/gimppreview.h @@ -61,20 +61,26 @@ struct _GimpPreviewClass { GtkPreviewClass parent_class; - void (* clicked) (GimpPreview *preview); - TempBuf * (* create_preview) (GimpPreview *preview); - GtkWidget * (* create_popup) (GimpPreview *preview); - gboolean (* needs_popup) (GimpPreview *preview); + void (* clicked) (GimpPreview *preview); + void (* render) (GimpPreview *preview); + GtkWidget * (* create_popup) (GimpPreview *preview); + gboolean (* needs_popup) (GimpPreview *preview); }; -GtkType gimp_preview_get_type (void); -GtkWidget * gimp_preview_new (GimpViewable *viewable, - gboolean is_popup, - gint width, - gint height, - gboolean clickable, - gboolean show_popup); +GtkType gimp_preview_get_type (void); +GtkWidget * gimp_preview_new (GimpViewable *viewable, + gboolean is_popup, + gint width, + gint height, + gboolean clickable, + gboolean show_popup); + +void gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel); #ifdef __cplusplus diff --git a/app/widgets/gimpbrushpreview.c b/app/widgets/gimpbrushpreview.c index fa1a6b05e7..426b1fa39e 100644 --- a/app/widgets/gimpbrushpreview.c +++ b/app/widgets/gimpbrushpreview.c @@ -34,9 +34,12 @@ static void gimp_brush_preview_class_init (GimpBrushPreviewClass *klass); static void gimp_brush_preview_init (GimpBrushPreview *preview); -static TempBuf * gimp_brush_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_brush_preview_create_popup (GimpPreview *preview); -static gboolean gimp_brush_preview_needs_popup (GimpPreview *preview); +static void gimp_brush_preview_destroy (GtkObject *object); +static void gimp_brush_preview_render (GimpPreview *preview); +static GtkWidget * gimp_brush_preview_create_popup (GimpPreview *preview); +static gboolean gimp_brush_preview_needs_popup (GimpPreview *preview); + +static gboolean gimp_brush_preview_render_timeout_func (GimpBrushPreview *preview); static GimpPreviewClass *parent_class = NULL; @@ -78,14 +81,37 @@ gimp_brush_preview_class_init (GimpBrushPreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); - preview_class->create_preview = gimp_brush_preview_create_preview; + object_class->destroy = gimp_brush_preview_destroy; + + preview_class->render = gimp_brush_preview_render; preview_class->create_popup = gimp_brush_preview_create_popup; preview_class->needs_popup = gimp_brush_preview_needs_popup; } static void -gimp_brush_preview_init (GimpBrushPreview *preview) +gimp_brush_preview_init (GimpBrushPreview *brush_preview) { + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; +} + +static void +gimp_brush_preview_destroy (GtkObject *object) +{ + GimpBrushPreview *brush_preview; + + brush_preview = GIMP_BRUSH_PREVIEW (object); + + if (brush_preview->pipe_timeout_id) + { + g_source_remove (brush_preview->pipe_timeout_id); + + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + GTK_OBJECT_CLASS (parent_class)->destroy (object); } #define indicator_width 7 @@ -95,20 +121,30 @@ gimp_brush_preview_init (GimpBrushPreview *preview) #define BLK { 0, 0, 0 } #define RED { 255, 127, 127 } -static TempBuf * -gimp_brush_preview_create_preview (GimpPreview *preview) +static void +gimp_brush_preview_render (GimpPreview *preview) { - GimpBrush *brush; - TempBuf *temp_buf; - gint width; - gint height; - gint brush_width; - gint brush_height; - guchar *buf; - guchar *b; - gint x, y; - gint offset_x; - gint offset_y; + GimpBrushPreview *brush_preview; + GimpBrush *brush; + TempBuf *temp_buf; + gint width; + gint height; + gint brush_width; + gint brush_height; + guchar *buf; + guchar *b; + gint x, y; + gint offset_x; + gint offset_y; + + brush_preview = GIMP_BRUSH_PREVIEW (preview); + + if (brush_preview->pipe_timeout_id) + { + g_source_remove (brush_preview->pipe_timeout_id); + + brush_preview->pipe_timeout_id = 0; + } brush = GIMP_BRUSH (preview->viewable); brush_width = brush->mask->width; @@ -118,10 +154,38 @@ gimp_brush_preview_create_preview (GimpPreview *preview) height = GTK_WIDGET (preview)->requisition.height; temp_buf = gimp_viewable_get_new_preview (preview->viewable, - width, height); + width, + height); if (preview->is_popup) - return temp_buf; + { + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + if (GIMP_IS_BRUSH_PIPE (brush)) + { + if (width != brush_width || + height != brush_height) + { + g_warning ("%s(): non-fullsize pipe popups are not supported yet.", + G_GNUC_FUNCTION); + return; + } + + brush_preview->pipe_animation_index = 0; + brush_preview->pipe_timeout_id = + g_timeout_add (300, + (GSourceFunc) gimp_brush_preview_render_timeout_func, + brush_preview); + } + + return; + } buf = temp_buf_data (temp_buf); @@ -213,7 +277,13 @@ gimp_brush_preview_create_preview (GimpPreview *preview) #undef BLK #undef RED - return temp_buf; + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); } static GtkWidget * @@ -255,3 +325,54 @@ gimp_brush_preview_needs_popup (GimpPreview *preview) return FALSE; } + +static gboolean +gimp_brush_preview_render_timeout_func (GimpBrushPreview *brush_preview) +{ + GimpPreview *preview; + GimpBrushPipe *brush_pipe; + GimpBrush *brush; + TempBuf *temp_buf; + gint width; + gint height; + gint brush_width; + gint brush_height; + + preview = GIMP_PREVIEW (brush_preview); + + if (! preview->viewable) + { + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; + + return FALSE; + } + + brush_pipe = GIMP_BRUSH_PIPE (preview->viewable); + brush_width = brush->mask->width; + brush_height = brush->mask->height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + brush_preview->pipe_animation_index++; + + if (brush_preview->pipe_animation_index >= brush_pipe->nbrushes) + brush_preview->pipe_animation_index = 0; + + brush = GIMP_BRUSH (brush_pipe->brushes[brush_preview->pipe_animation_index]); + + temp_buf = gimp_viewable_get_new_preview (GIMP_VIEWABLE (brush), + width, + height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + return TRUE; +} diff --git a/app/widgets/gimpbrushpreview.h b/app/widgets/gimpbrushpreview.h index e2f08d44eb..dce102a208 100644 --- a/app/widgets/gimpbrushpreview.h +++ b/app/widgets/gimpbrushpreview.h @@ -42,7 +42,10 @@ typedef struct _GimpBrushPreviewClass GimpBrushPreviewClass; struct _GimpBrushPreview { - GimpPreview parent_instance; + GimpPreview parent_instance; + + guint pipe_timeout_id; + gint pipe_animation_index; }; struct _GimpBrushPreviewClass diff --git a/app/widgets/gimpdrawablepreview.c b/app/widgets/gimpdrawablepreview.c index 468b607793..294fd4ff64 100644 --- a/app/widgets/gimpdrawablepreview.c +++ b/app/widgets/gimpdrawablepreview.c @@ -31,8 +31,8 @@ static void gimp_drawable_preview_class_init (GimpDrawablePreviewClass *klass); static void gimp_drawable_preview_init (GimpDrawablePreview *preview); -static TempBuf * gimp_drawable_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_drawable_preview_create_popup (GimpPreview *preview); +static void gimp_drawable_preview_render (GimpPreview *preview); +static GtkWidget * gimp_drawable_preview_create_popup (GimpPreview *preview); static GimpPreviewClass *parent_class = NULL; @@ -80,8 +80,8 @@ gimp_drawable_preview_init (GimpDrawablePreview *preview) { } -static TempBuf * -gimp_drawable_preview_create_preview (GimpPreview *preview) +static void +gimp_drawable_preview_render (GimpPreview *preview) { } diff --git a/app/widgets/gimpimagepreview.c b/app/widgets/gimpimagepreview.c index 261a141098..7cb0e919e8 100644 --- a/app/widgets/gimpimagepreview.c +++ b/app/widgets/gimpimagepreview.c @@ -36,14 +36,14 @@ static void gimp_image_preview_class_init (GimpImagePreviewClass *klass); static void gimp_image_preview_init (GimpImagePreview *preview); -static TempBuf * gimp_image_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_image_preview_create_popup (GimpPreview *preview); -static void gimp_image_preview_calc_size (GimpImage *gimage, - gint width, - gint height, - gint *return_width, - gint *return_height, - gboolean *scaling_up); +static void gimp_image_preview_render (GimpPreview *preview); +static GtkWidget * gimp_image_preview_create_popup (GimpPreview *preview); +static void gimp_image_preview_calc_size (GimpImage *gimage, + gint width, + gint height, + gint *return_width, + gint *return_height, + gboolean *scaling_up); static GimpPreviewClass *parent_class = NULL; @@ -85,8 +85,8 @@ gimp_image_preview_class_init (GimpImagePreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); - preview_class->create_preview = gimp_image_preview_create_preview; - preview_class->create_popup = gimp_image_preview_create_popup; + preview_class->render = gimp_image_preview_render; + preview_class->create_popup = gimp_image_preview_create_popup; } static void @@ -94,8 +94,8 @@ gimp_image_preview_init (GimpImagePreview *preview) { } -static TempBuf * -gimp_image_preview_create_preview (GimpPreview *preview) +static void +gimp_image_preview_render (GimpPreview *preview) { GimpImage *gimage; gint width; @@ -103,7 +103,7 @@ gimp_image_preview_create_preview (GimpPreview *preview) gint preview_width; gint preview_height; gboolean scaling_up; - TempBuf *return_buf; + TempBuf *render_buf; gimage = GIMP_IMAGE (preview->viewable); @@ -124,43 +124,59 @@ gimp_image_preview_create_preview (GimpPreview *preview) temp_buf = gimp_viewable_get_new_preview (preview->viewable, gimage->width, gimage->height); - return_buf = temp_buf_scale (temp_buf, preview_width, preview_height); + render_buf = temp_buf_scale (temp_buf, preview_width, preview_height); temp_buf_free (temp_buf); } else { - return_buf = gimp_viewable_get_new_preview (preview->viewable, + render_buf = gimp_viewable_get_new_preview (preview->viewable, preview_width, preview_height); } - if (preview_width < width) return_buf->x = (width - preview_width) / 2; - if (preview_height < height) return_buf->y = (height - preview_height) / 2; + if (preview_width < width) render_buf->x = (width - preview_width) / 2; + if (preview_height < height) render_buf->y = (height - preview_height) / 2; - if (return_buf->x || return_buf->y) + if (render_buf->x || render_buf->y) { TempBuf *temp_buf; guchar white[4] = { 255, 255, 255, 255 }; temp_buf = temp_buf_new (width, height, - return_buf->bytes, + render_buf->bytes, 0, 0, white); - temp_buf_copy_area (return_buf, temp_buf, + temp_buf_copy_area (render_buf, temp_buf, 0, 0, - return_buf->width, - return_buf->height, - return_buf->x, - return_buf->y); + render_buf->width, + render_buf->height, + render_buf->x, + render_buf->y); - temp_buf_free (return_buf); + temp_buf_free (render_buf); - return temp_buf; + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + return; } - return return_buf; + gimp_preview_render_and_flush (preview, + render_buf, + width, + height, + -1); + + temp_buf_free (render_buf); + + return; } static GtkWidget * diff --git a/app/widgets/gimppatternpreview.c b/app/widgets/gimppatternpreview.c index d0ec8d8ff1..7f0c7fad32 100644 --- a/app/widgets/gimppatternpreview.c +++ b/app/widgets/gimppatternpreview.c @@ -33,6 +33,7 @@ static void gimp_pattern_preview_class_init (GimpPatternPreviewClass *klass); static void gimp_pattern_preview_init (GimpPatternPreview *preview); +static void gimp_pattern_preview_render (GimpPreview *preview); static GtkWidget * gimp_pattern_preview_create_popup (GimpPreview *preview); static gboolean gimp_pattern_preview_needs_popup (GimpPreview *preview); @@ -76,6 +77,7 @@ gimp_pattern_preview_class_init (GimpPatternPreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); + preview_class->render = gimp_pattern_preview_render; preview_class->create_popup = gimp_pattern_preview_create_popup; preview_class->needs_popup = gimp_pattern_preview_needs_popup; } @@ -85,6 +87,58 @@ gimp_pattern_preview_init (GimpPatternPreview *preview) { } +static void +gimp_pattern_preview_render (GimpPreview *preview) +{ + GimpPattern *pattern; + TempBuf *temp_buf; + gint width; + gint height; + gint pattern_width; + gint pattern_height; + + pattern = GIMP_PATTERN (preview->viewable); + pattern_width = pattern->mask->width; + pattern_height = pattern->mask->height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + if (width == pattern_width && + height == pattern_height) + { + gimp_preview_render_and_flush (preview, + pattern->mask, + width, + height, + -1); + + return; + } + else if (width <= pattern_width && + height <= pattern_height) + { + gimp_preview_render_and_flush (preview, + pattern->mask, + width, + height, + -1); + + return; + } + + temp_buf = gimp_viewable_get_new_preview (preview->viewable, + width, height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); +} + static GtkWidget * gimp_pattern_preview_create_popup (GimpPreview *preview) { diff --git a/app/widgets/gimppreview.c b/app/widgets/gimppreview.c index d05ce15ec4..854e0e1c3c 100644 --- a/app/widgets/gimppreview.c +++ b/app/widgets/gimppreview.c @@ -56,7 +56,7 @@ enum { CLICKED, - CREATE_PREVIEW, + RENDER, CREATE_POPUP, NEEDS_POPUP, LAST_SIGNAL @@ -77,8 +77,8 @@ static gint gimp_preview_enter_notify_event (GtkWidget *widget, static gint gimp_preview_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event); -static TempBuf * gimp_preview_create_preview (GimpPreview *preview); -static TempBuf * gimp_preview_real_create_preview (GimpPreview *preview); +static void gimp_preview_render (GimpPreview *preview); +static void gimp_preview_real_render (GimpPreview *preview); static GtkWidget * gimp_preview_create_popup (GimpPreview *preview); static GtkWidget * gimp_preview_real_create_popup (GimpPreview *preview); static gboolean gimp_preview_needs_popup (GimpPreview *preview); @@ -142,14 +142,14 @@ gimp_preview_class_init (GimpPreviewClass *klass) gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); - preview_signals[CREATE_PREVIEW] = - gtk_signal_new ("create_preview", + preview_signals[RENDER] = + gtk_signal_new ("render", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET (GimpPreviewClass, - create_preview), - gimp_marshal_POINTER__NONE, - GTK_TYPE_POINTER, 0); + render), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); preview_signals[CREATE_POPUP] = gtk_signal_new ("create_popup", @@ -179,10 +179,10 @@ gimp_preview_class_init (GimpPreviewClass *klass) widget_class->enter_notify_event = gimp_preview_enter_notify_event; widget_class->leave_notify_event = gimp_preview_leave_notify_event; - klass->clicked = NULL; - klass->create_preview = gimp_preview_real_create_preview; - klass->create_popup = gimp_preview_real_create_popup; - klass->needs_popup = gimp_preview_real_needs_popup; + klass->clicked = NULL; + klass->render = gimp_preview_real_render; + klass->create_popup = gimp_preview_real_create_popup; + klass->needs_popup = gimp_preview_real_needs_popup; } static void @@ -386,24 +386,31 @@ gimp_preview_leave_notify_event (GtkWidget *widget, return FALSE; } -static TempBuf * -gimp_preview_create_preview (GimpPreview *preview) +static void +gimp_preview_render (GimpPreview *preview) { - TempBuf *temp_buf = NULL; - - gtk_signal_emit (GTK_OBJECT (preview), preview_signals[CREATE_PREVIEW], - &temp_buf); - - return temp_buf; + gtk_signal_emit (GTK_OBJECT (preview), preview_signals[RENDER]); } -static TempBuf * -gimp_preview_real_create_preview (GimpPreview *preview) +static void +gimp_preview_real_render (GimpPreview *preview) { - return + TempBuf *temp_buf; + gint width; + gint height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + temp_buf = gimp_viewable_get_new_preview (preview->viewable, - GTK_WIDGET (preview)->requisition.width, - GTK_WIDGET (preview)->requisition.height); + width, height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); } static GtkWidget * @@ -564,229 +571,223 @@ gimp_preview_paint (GimpPreview *preview) static gboolean gimp_preview_idle_paint (GimpPreview *preview) { - TempBuf *temp_buf; - gint width; - gint height; - gint channel; - preview->idle_id = 0; if (! preview->viewable) return FALSE; - temp_buf = gimp_preview_create_preview (preview); - - width = temp_buf->width; - height = temp_buf->height; - channel = -1; - - /* from layers_dialog.c */ - { - guchar *src, *s; - guchar *cb; - guchar *buf; - gint a; - gint i, j, b; - gint x1, y1, x2, y2; - gint rowstride; - gboolean color_buf; - gboolean color; - gint alpha; - gboolean has_alpha; - gint image_bytes; - gint offset; - - alpha = ALPHA_PIX; - - /* Here are the different cases this functions handles correctly: - * 1) Offset temp_buf which does not necessarily cover full image area - * 2) Color conversion of temp_buf if it is gray and image is color - * 3) Background check buffer for transparent temp_bufs - * 4) Using the optional "channel" argument, one channel can be extracted - * from a multi-channel temp_buf and composited as a grayscale - * Prereqs: - * 1) Grayscale temp_bufs have bytes == {1, 2} - * 2) Color temp_bufs have bytes == {3, 4} - * 3) If image is gray, then temp_buf should have bytes == {1, 2} - */ - color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); - image_bytes = (color_buf) ? 3 : 1; - has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); - rowstride = temp_buf->width * temp_buf->bytes; - - /* Determine if the preview buf supplied is color - * Generally, if the bytes == {3, 4}, this is true. - * However, if the channel argument supplied is not -1, then - * the preview buf is assumed to be gray despite the number of - * channels it contains - */ - color = ((channel == -1) && - (temp_buf->bytes == 3 || temp_buf->bytes == 4)); - - if (has_alpha) - { - buf = render_check_buf; - alpha = ((color) ? ALPHA_PIX : - ((channel != -1) ? (temp_buf->bytes - 1) : - ALPHA_G_PIX)); - } - else - { - buf = render_empty_buf; - } - - x1 = CLAMP (temp_buf->x, 0, width); - y1 = CLAMP (temp_buf->y, 0, height); - x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); - y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); - - src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + - (x1 - temp_buf->x) * temp_buf->bytes); - - /* One last thing for efficiency's sake: */ - if (channel == -1) - channel = 0; - - for (i = 0; i < height; i++) - { - if (i & 0x4) - { - offset = 4; - cb = buf + offset * 3; - } - else - { - offset = 0; - cb = buf; - } - - /* The interesting stuff between leading & trailing - * vertical transparency - */ - if (i >= y1 && i < y2) - { - /* Handle the leading transparency */ - for (j = 0; j < x1; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - /* The stuff in the middle */ - s = src; - for (j = x1; j < x2; j++) - { - if (color) - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[BLUE_PIX])]; - } - else - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[BLUE_PIX])]; - } - } - else - { - render_temp_buf[j * 3 + 0] = s[RED_PIX]; - render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; - render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; - } - } - else - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_dark_check [(a | s[GRAY_PIX + channel])]; - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_light_check [(a | s[GRAY_PIX + channel])]; - } - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; - } - else - { - render_temp_buf[j] = s[GRAY_PIX + channel]; - } - } - } - - s += temp_buf->bytes; - } - - /* Handle the trailing transparency */ - for (j = x2; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - src += rowstride; - } - else - { - for (j = 0; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - } - - gtk_preview_draw_row (GTK_PREVIEW (preview), - render_temp_buf, 0, i, width); - } - } - - temp_buf_free (temp_buf); - - gtk_widget_queue_draw (GTK_WIDGET (preview)); + gimp_preview_render (preview); return FALSE; } + +void +gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel) +{ + guchar *src, *s; + guchar *cb; + guchar *buf; + gint a; + gint i, j, b; + gint x1, y1, x2, y2; + gint rowstride; + gboolean color_buf; + gboolean color; + gint alpha; + gboolean has_alpha; + gint image_bytes; + gint offset; + + alpha = ALPHA_PIX; + + /* Here are the different cases this functions handles correctly: + * 1) Offset temp_buf which does not necessarily cover full image area + * 2) Color conversion of temp_buf if it is gray and image is color + * 3) Background check buffer for transparent temp_bufs + * 4) Using the optional "channel" argument, one channel can be extracted + * from a multi-channel temp_buf and composited as a grayscale + * Prereqs: + * 1) Grayscale temp_bufs have bytes == {1, 2} + * 2) Color temp_bufs have bytes == {3, 4} + * 3) If image is gray, then temp_buf should have bytes == {1, 2} + */ + color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); + image_bytes = (color_buf) ? 3 : 1; + has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); + rowstride = temp_buf->width * temp_buf->bytes; + + /* Determine if the preview buf supplied is color + * Generally, if the bytes == {3, 4}, this is true. + * However, if the channel argument supplied is not -1, then + * the preview buf is assumed to be gray despite the number of + * channels it contains + */ + color = ((channel == -1) && + (temp_buf->bytes == 3 || temp_buf->bytes == 4)); + + if (has_alpha) + { + buf = render_check_buf; + alpha = ((color) ? ALPHA_PIX : + ((channel != -1) ? (temp_buf->bytes - 1) : + ALPHA_G_PIX)); + } + else + { + buf = render_empty_buf; + } + + x1 = CLAMP (temp_buf->x, 0, width); + y1 = CLAMP (temp_buf->y, 0, height); + x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); + y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); + + src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + + (x1 - temp_buf->x) * temp_buf->bytes); + + /* One last thing for efficiency's sake: */ + if (channel == -1) + channel = 0; + + for (i = 0; i < height; i++) + { + if (i & 0x4) + { + offset = 4; + cb = buf + offset * 3; + } + else + { + offset = 0; + cb = buf; + } + + /* The interesting stuff between leading & trailing + * vertical transparency + */ + if (i >= y1 && i < y2) + { + /* Handle the leading transparency */ + for (j = 0; j < x1; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + /* The stuff in the middle */ + s = src; + for (j = x1; j < x2; j++) + { + if (color) + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[BLUE_PIX])]; + } + else + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[BLUE_PIX])]; + } + } + else + { + render_temp_buf[j * 3 + 0] = s[RED_PIX]; + render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; + render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; + } + } + else + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_dark_check [(a | s[GRAY_PIX + channel])]; + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_light_check [(a | s[GRAY_PIX + channel])]; + } + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; + } + else + { + render_temp_buf[j] = s[GRAY_PIX + channel]; + } + } + } + + s += temp_buf->bytes; + } + + /* Handle the trailing transparency */ + for (j = x2; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + src += rowstride; + } + else + { + for (j = 0; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), + render_temp_buf, 0, i, width); + } + + gtk_widget_queue_draw (GTK_WIDGET (preview)); +} diff --git a/app/widgets/gimppreview.h b/app/widgets/gimppreview.h index e01d170d04..2266688ff7 100644 --- a/app/widgets/gimppreview.h +++ b/app/widgets/gimppreview.h @@ -61,20 +61,26 @@ struct _GimpPreviewClass { GtkPreviewClass parent_class; - void (* clicked) (GimpPreview *preview); - TempBuf * (* create_preview) (GimpPreview *preview); - GtkWidget * (* create_popup) (GimpPreview *preview); - gboolean (* needs_popup) (GimpPreview *preview); + void (* clicked) (GimpPreview *preview); + void (* render) (GimpPreview *preview); + GtkWidget * (* create_popup) (GimpPreview *preview); + gboolean (* needs_popup) (GimpPreview *preview); }; -GtkType gimp_preview_get_type (void); -GtkWidget * gimp_preview_new (GimpViewable *viewable, - gboolean is_popup, - gint width, - gint height, - gboolean clickable, - gboolean show_popup); +GtkType gimp_preview_get_type (void); +GtkWidget * gimp_preview_new (GimpViewable *viewable, + gboolean is_popup, + gint width, + gint height, + gboolean clickable, + gboolean show_popup); + +void gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel); #ifdef __cplusplus diff --git a/app/widgets/gimppreviewrenderer.c b/app/widgets/gimppreviewrenderer.c index d05ce15ec4..854e0e1c3c 100644 --- a/app/widgets/gimppreviewrenderer.c +++ b/app/widgets/gimppreviewrenderer.c @@ -56,7 +56,7 @@ enum { CLICKED, - CREATE_PREVIEW, + RENDER, CREATE_POPUP, NEEDS_POPUP, LAST_SIGNAL @@ -77,8 +77,8 @@ static gint gimp_preview_enter_notify_event (GtkWidget *widget, static gint gimp_preview_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event); -static TempBuf * gimp_preview_create_preview (GimpPreview *preview); -static TempBuf * gimp_preview_real_create_preview (GimpPreview *preview); +static void gimp_preview_render (GimpPreview *preview); +static void gimp_preview_real_render (GimpPreview *preview); static GtkWidget * gimp_preview_create_popup (GimpPreview *preview); static GtkWidget * gimp_preview_real_create_popup (GimpPreview *preview); static gboolean gimp_preview_needs_popup (GimpPreview *preview); @@ -142,14 +142,14 @@ gimp_preview_class_init (GimpPreviewClass *klass) gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); - preview_signals[CREATE_PREVIEW] = - gtk_signal_new ("create_preview", + preview_signals[RENDER] = + gtk_signal_new ("render", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET (GimpPreviewClass, - create_preview), - gimp_marshal_POINTER__NONE, - GTK_TYPE_POINTER, 0); + render), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); preview_signals[CREATE_POPUP] = gtk_signal_new ("create_popup", @@ -179,10 +179,10 @@ gimp_preview_class_init (GimpPreviewClass *klass) widget_class->enter_notify_event = gimp_preview_enter_notify_event; widget_class->leave_notify_event = gimp_preview_leave_notify_event; - klass->clicked = NULL; - klass->create_preview = gimp_preview_real_create_preview; - klass->create_popup = gimp_preview_real_create_popup; - klass->needs_popup = gimp_preview_real_needs_popup; + klass->clicked = NULL; + klass->render = gimp_preview_real_render; + klass->create_popup = gimp_preview_real_create_popup; + klass->needs_popup = gimp_preview_real_needs_popup; } static void @@ -386,24 +386,31 @@ gimp_preview_leave_notify_event (GtkWidget *widget, return FALSE; } -static TempBuf * -gimp_preview_create_preview (GimpPreview *preview) +static void +gimp_preview_render (GimpPreview *preview) { - TempBuf *temp_buf = NULL; - - gtk_signal_emit (GTK_OBJECT (preview), preview_signals[CREATE_PREVIEW], - &temp_buf); - - return temp_buf; + gtk_signal_emit (GTK_OBJECT (preview), preview_signals[RENDER]); } -static TempBuf * -gimp_preview_real_create_preview (GimpPreview *preview) +static void +gimp_preview_real_render (GimpPreview *preview) { - return + TempBuf *temp_buf; + gint width; + gint height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + temp_buf = gimp_viewable_get_new_preview (preview->viewable, - GTK_WIDGET (preview)->requisition.width, - GTK_WIDGET (preview)->requisition.height); + width, height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); } static GtkWidget * @@ -564,229 +571,223 @@ gimp_preview_paint (GimpPreview *preview) static gboolean gimp_preview_idle_paint (GimpPreview *preview) { - TempBuf *temp_buf; - gint width; - gint height; - gint channel; - preview->idle_id = 0; if (! preview->viewable) return FALSE; - temp_buf = gimp_preview_create_preview (preview); - - width = temp_buf->width; - height = temp_buf->height; - channel = -1; - - /* from layers_dialog.c */ - { - guchar *src, *s; - guchar *cb; - guchar *buf; - gint a; - gint i, j, b; - gint x1, y1, x2, y2; - gint rowstride; - gboolean color_buf; - gboolean color; - gint alpha; - gboolean has_alpha; - gint image_bytes; - gint offset; - - alpha = ALPHA_PIX; - - /* Here are the different cases this functions handles correctly: - * 1) Offset temp_buf which does not necessarily cover full image area - * 2) Color conversion of temp_buf if it is gray and image is color - * 3) Background check buffer for transparent temp_bufs - * 4) Using the optional "channel" argument, one channel can be extracted - * from a multi-channel temp_buf and composited as a grayscale - * Prereqs: - * 1) Grayscale temp_bufs have bytes == {1, 2} - * 2) Color temp_bufs have bytes == {3, 4} - * 3) If image is gray, then temp_buf should have bytes == {1, 2} - */ - color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); - image_bytes = (color_buf) ? 3 : 1; - has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); - rowstride = temp_buf->width * temp_buf->bytes; - - /* Determine if the preview buf supplied is color - * Generally, if the bytes == {3, 4}, this is true. - * However, if the channel argument supplied is not -1, then - * the preview buf is assumed to be gray despite the number of - * channels it contains - */ - color = ((channel == -1) && - (temp_buf->bytes == 3 || temp_buf->bytes == 4)); - - if (has_alpha) - { - buf = render_check_buf; - alpha = ((color) ? ALPHA_PIX : - ((channel != -1) ? (temp_buf->bytes - 1) : - ALPHA_G_PIX)); - } - else - { - buf = render_empty_buf; - } - - x1 = CLAMP (temp_buf->x, 0, width); - y1 = CLAMP (temp_buf->y, 0, height); - x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); - y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); - - src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + - (x1 - temp_buf->x) * temp_buf->bytes); - - /* One last thing for efficiency's sake: */ - if (channel == -1) - channel = 0; - - for (i = 0; i < height; i++) - { - if (i & 0x4) - { - offset = 4; - cb = buf + offset * 3; - } - else - { - offset = 0; - cb = buf; - } - - /* The interesting stuff between leading & trailing - * vertical transparency - */ - if (i >= y1 && i < y2) - { - /* Handle the leading transparency */ - for (j = 0; j < x1; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - /* The stuff in the middle */ - s = src; - for (j = x1; j < x2; j++) - { - if (color) - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[BLUE_PIX])]; - } - else - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[BLUE_PIX])]; - } - } - else - { - render_temp_buf[j * 3 + 0] = s[RED_PIX]; - render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; - render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; - } - } - else - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_dark_check [(a | s[GRAY_PIX + channel])]; - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_light_check [(a | s[GRAY_PIX + channel])]; - } - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; - } - else - { - render_temp_buf[j] = s[GRAY_PIX + channel]; - } - } - } - - s += temp_buf->bytes; - } - - /* Handle the trailing transparency */ - for (j = x2; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - src += rowstride; - } - else - { - for (j = 0; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - } - - gtk_preview_draw_row (GTK_PREVIEW (preview), - render_temp_buf, 0, i, width); - } - } - - temp_buf_free (temp_buf); - - gtk_widget_queue_draw (GTK_WIDGET (preview)); + gimp_preview_render (preview); return FALSE; } + +void +gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel) +{ + guchar *src, *s; + guchar *cb; + guchar *buf; + gint a; + gint i, j, b; + gint x1, y1, x2, y2; + gint rowstride; + gboolean color_buf; + gboolean color; + gint alpha; + gboolean has_alpha; + gint image_bytes; + gint offset; + + alpha = ALPHA_PIX; + + /* Here are the different cases this functions handles correctly: + * 1) Offset temp_buf which does not necessarily cover full image area + * 2) Color conversion of temp_buf if it is gray and image is color + * 3) Background check buffer for transparent temp_bufs + * 4) Using the optional "channel" argument, one channel can be extracted + * from a multi-channel temp_buf and composited as a grayscale + * Prereqs: + * 1) Grayscale temp_bufs have bytes == {1, 2} + * 2) Color temp_bufs have bytes == {3, 4} + * 3) If image is gray, then temp_buf should have bytes == {1, 2} + */ + color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); + image_bytes = (color_buf) ? 3 : 1; + has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); + rowstride = temp_buf->width * temp_buf->bytes; + + /* Determine if the preview buf supplied is color + * Generally, if the bytes == {3, 4}, this is true. + * However, if the channel argument supplied is not -1, then + * the preview buf is assumed to be gray despite the number of + * channels it contains + */ + color = ((channel == -1) && + (temp_buf->bytes == 3 || temp_buf->bytes == 4)); + + if (has_alpha) + { + buf = render_check_buf; + alpha = ((color) ? ALPHA_PIX : + ((channel != -1) ? (temp_buf->bytes - 1) : + ALPHA_G_PIX)); + } + else + { + buf = render_empty_buf; + } + + x1 = CLAMP (temp_buf->x, 0, width); + y1 = CLAMP (temp_buf->y, 0, height); + x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); + y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); + + src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + + (x1 - temp_buf->x) * temp_buf->bytes); + + /* One last thing for efficiency's sake: */ + if (channel == -1) + channel = 0; + + for (i = 0; i < height; i++) + { + if (i & 0x4) + { + offset = 4; + cb = buf + offset * 3; + } + else + { + offset = 0; + cb = buf; + } + + /* The interesting stuff between leading & trailing + * vertical transparency + */ + if (i >= y1 && i < y2) + { + /* Handle the leading transparency */ + for (j = 0; j < x1; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + /* The stuff in the middle */ + s = src; + for (j = x1; j < x2; j++) + { + if (color) + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[BLUE_PIX])]; + } + else + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[BLUE_PIX])]; + } + } + else + { + render_temp_buf[j * 3 + 0] = s[RED_PIX]; + render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; + render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; + } + } + else + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_dark_check [(a | s[GRAY_PIX + channel])]; + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_light_check [(a | s[GRAY_PIX + channel])]; + } + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; + } + else + { + render_temp_buf[j] = s[GRAY_PIX + channel]; + } + } + } + + s += temp_buf->bytes; + } + + /* Handle the trailing transparency */ + for (j = x2; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + src += rowstride; + } + else + { + for (j = 0; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), + render_temp_buf, 0, i, width); + } + + gtk_widget_queue_draw (GTK_WIDGET (preview)); +} diff --git a/app/widgets/gimppreviewrenderer.h b/app/widgets/gimppreviewrenderer.h index e01d170d04..2266688ff7 100644 --- a/app/widgets/gimppreviewrenderer.h +++ b/app/widgets/gimppreviewrenderer.h @@ -61,20 +61,26 @@ struct _GimpPreviewClass { GtkPreviewClass parent_class; - void (* clicked) (GimpPreview *preview); - TempBuf * (* create_preview) (GimpPreview *preview); - GtkWidget * (* create_popup) (GimpPreview *preview); - gboolean (* needs_popup) (GimpPreview *preview); + void (* clicked) (GimpPreview *preview); + void (* render) (GimpPreview *preview); + GtkWidget * (* create_popup) (GimpPreview *preview); + gboolean (* needs_popup) (GimpPreview *preview); }; -GtkType gimp_preview_get_type (void); -GtkWidget * gimp_preview_new (GimpViewable *viewable, - gboolean is_popup, - gint width, - gint height, - gboolean clickable, - gboolean show_popup); +GtkType gimp_preview_get_type (void); +GtkWidget * gimp_preview_new (GimpViewable *viewable, + gboolean is_popup, + gint width, + gint height, + gboolean clickable, + gboolean show_popup); + +void gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel); #ifdef __cplusplus diff --git a/app/widgets/gimppreviewrendererbrush.c b/app/widgets/gimppreviewrendererbrush.c index fa1a6b05e7..426b1fa39e 100644 --- a/app/widgets/gimppreviewrendererbrush.c +++ b/app/widgets/gimppreviewrendererbrush.c @@ -34,9 +34,12 @@ static void gimp_brush_preview_class_init (GimpBrushPreviewClass *klass); static void gimp_brush_preview_init (GimpBrushPreview *preview); -static TempBuf * gimp_brush_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_brush_preview_create_popup (GimpPreview *preview); -static gboolean gimp_brush_preview_needs_popup (GimpPreview *preview); +static void gimp_brush_preview_destroy (GtkObject *object); +static void gimp_brush_preview_render (GimpPreview *preview); +static GtkWidget * gimp_brush_preview_create_popup (GimpPreview *preview); +static gboolean gimp_brush_preview_needs_popup (GimpPreview *preview); + +static gboolean gimp_brush_preview_render_timeout_func (GimpBrushPreview *preview); static GimpPreviewClass *parent_class = NULL; @@ -78,14 +81,37 @@ gimp_brush_preview_class_init (GimpBrushPreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); - preview_class->create_preview = gimp_brush_preview_create_preview; + object_class->destroy = gimp_brush_preview_destroy; + + preview_class->render = gimp_brush_preview_render; preview_class->create_popup = gimp_brush_preview_create_popup; preview_class->needs_popup = gimp_brush_preview_needs_popup; } static void -gimp_brush_preview_init (GimpBrushPreview *preview) +gimp_brush_preview_init (GimpBrushPreview *brush_preview) { + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; +} + +static void +gimp_brush_preview_destroy (GtkObject *object) +{ + GimpBrushPreview *brush_preview; + + brush_preview = GIMP_BRUSH_PREVIEW (object); + + if (brush_preview->pipe_timeout_id) + { + g_source_remove (brush_preview->pipe_timeout_id); + + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + GTK_OBJECT_CLASS (parent_class)->destroy (object); } #define indicator_width 7 @@ -95,20 +121,30 @@ gimp_brush_preview_init (GimpBrushPreview *preview) #define BLK { 0, 0, 0 } #define RED { 255, 127, 127 } -static TempBuf * -gimp_brush_preview_create_preview (GimpPreview *preview) +static void +gimp_brush_preview_render (GimpPreview *preview) { - GimpBrush *brush; - TempBuf *temp_buf; - gint width; - gint height; - gint brush_width; - gint brush_height; - guchar *buf; - guchar *b; - gint x, y; - gint offset_x; - gint offset_y; + GimpBrushPreview *brush_preview; + GimpBrush *brush; + TempBuf *temp_buf; + gint width; + gint height; + gint brush_width; + gint brush_height; + guchar *buf; + guchar *b; + gint x, y; + gint offset_x; + gint offset_y; + + brush_preview = GIMP_BRUSH_PREVIEW (preview); + + if (brush_preview->pipe_timeout_id) + { + g_source_remove (brush_preview->pipe_timeout_id); + + brush_preview->pipe_timeout_id = 0; + } brush = GIMP_BRUSH (preview->viewable); brush_width = brush->mask->width; @@ -118,10 +154,38 @@ gimp_brush_preview_create_preview (GimpPreview *preview) height = GTK_WIDGET (preview)->requisition.height; temp_buf = gimp_viewable_get_new_preview (preview->viewable, - width, height); + width, + height); if (preview->is_popup) - return temp_buf; + { + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + if (GIMP_IS_BRUSH_PIPE (brush)) + { + if (width != brush_width || + height != brush_height) + { + g_warning ("%s(): non-fullsize pipe popups are not supported yet.", + G_GNUC_FUNCTION); + return; + } + + brush_preview->pipe_animation_index = 0; + brush_preview->pipe_timeout_id = + g_timeout_add (300, + (GSourceFunc) gimp_brush_preview_render_timeout_func, + brush_preview); + } + + return; + } buf = temp_buf_data (temp_buf); @@ -213,7 +277,13 @@ gimp_brush_preview_create_preview (GimpPreview *preview) #undef BLK #undef RED - return temp_buf; + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); } static GtkWidget * @@ -255,3 +325,54 @@ gimp_brush_preview_needs_popup (GimpPreview *preview) return FALSE; } + +static gboolean +gimp_brush_preview_render_timeout_func (GimpBrushPreview *brush_preview) +{ + GimpPreview *preview; + GimpBrushPipe *brush_pipe; + GimpBrush *brush; + TempBuf *temp_buf; + gint width; + gint height; + gint brush_width; + gint brush_height; + + preview = GIMP_PREVIEW (brush_preview); + + if (! preview->viewable) + { + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; + + return FALSE; + } + + brush_pipe = GIMP_BRUSH_PIPE (preview->viewable); + brush_width = brush->mask->width; + brush_height = brush->mask->height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + brush_preview->pipe_animation_index++; + + if (brush_preview->pipe_animation_index >= brush_pipe->nbrushes) + brush_preview->pipe_animation_index = 0; + + brush = GIMP_BRUSH (brush_pipe->brushes[brush_preview->pipe_animation_index]); + + temp_buf = gimp_viewable_get_new_preview (GIMP_VIEWABLE (brush), + width, + height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + return TRUE; +} diff --git a/app/widgets/gimppreviewrendererbrush.h b/app/widgets/gimppreviewrendererbrush.h index e2f08d44eb..dce102a208 100644 --- a/app/widgets/gimppreviewrendererbrush.h +++ b/app/widgets/gimppreviewrendererbrush.h @@ -42,7 +42,10 @@ typedef struct _GimpBrushPreviewClass GimpBrushPreviewClass; struct _GimpBrushPreview { - GimpPreview parent_instance; + GimpPreview parent_instance; + + guint pipe_timeout_id; + gint pipe_animation_index; }; struct _GimpBrushPreviewClass diff --git a/app/widgets/gimppreviewrendererdrawable.c b/app/widgets/gimppreviewrendererdrawable.c index 468b607793..294fd4ff64 100644 --- a/app/widgets/gimppreviewrendererdrawable.c +++ b/app/widgets/gimppreviewrendererdrawable.c @@ -31,8 +31,8 @@ static void gimp_drawable_preview_class_init (GimpDrawablePreviewClass *klass); static void gimp_drawable_preview_init (GimpDrawablePreview *preview); -static TempBuf * gimp_drawable_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_drawable_preview_create_popup (GimpPreview *preview); +static void gimp_drawable_preview_render (GimpPreview *preview); +static GtkWidget * gimp_drawable_preview_create_popup (GimpPreview *preview); static GimpPreviewClass *parent_class = NULL; @@ -80,8 +80,8 @@ gimp_drawable_preview_init (GimpDrawablePreview *preview) { } -static TempBuf * -gimp_drawable_preview_create_preview (GimpPreview *preview) +static void +gimp_drawable_preview_render (GimpPreview *preview) { } diff --git a/app/widgets/gimppreviewrendererimage.c b/app/widgets/gimppreviewrendererimage.c index 261a141098..7cb0e919e8 100644 --- a/app/widgets/gimppreviewrendererimage.c +++ b/app/widgets/gimppreviewrendererimage.c @@ -36,14 +36,14 @@ static void gimp_image_preview_class_init (GimpImagePreviewClass *klass); static void gimp_image_preview_init (GimpImagePreview *preview); -static TempBuf * gimp_image_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_image_preview_create_popup (GimpPreview *preview); -static void gimp_image_preview_calc_size (GimpImage *gimage, - gint width, - gint height, - gint *return_width, - gint *return_height, - gboolean *scaling_up); +static void gimp_image_preview_render (GimpPreview *preview); +static GtkWidget * gimp_image_preview_create_popup (GimpPreview *preview); +static void gimp_image_preview_calc_size (GimpImage *gimage, + gint width, + gint height, + gint *return_width, + gint *return_height, + gboolean *scaling_up); static GimpPreviewClass *parent_class = NULL; @@ -85,8 +85,8 @@ gimp_image_preview_class_init (GimpImagePreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); - preview_class->create_preview = gimp_image_preview_create_preview; - preview_class->create_popup = gimp_image_preview_create_popup; + preview_class->render = gimp_image_preview_render; + preview_class->create_popup = gimp_image_preview_create_popup; } static void @@ -94,8 +94,8 @@ gimp_image_preview_init (GimpImagePreview *preview) { } -static TempBuf * -gimp_image_preview_create_preview (GimpPreview *preview) +static void +gimp_image_preview_render (GimpPreview *preview) { GimpImage *gimage; gint width; @@ -103,7 +103,7 @@ gimp_image_preview_create_preview (GimpPreview *preview) gint preview_width; gint preview_height; gboolean scaling_up; - TempBuf *return_buf; + TempBuf *render_buf; gimage = GIMP_IMAGE (preview->viewable); @@ -124,43 +124,59 @@ gimp_image_preview_create_preview (GimpPreview *preview) temp_buf = gimp_viewable_get_new_preview (preview->viewable, gimage->width, gimage->height); - return_buf = temp_buf_scale (temp_buf, preview_width, preview_height); + render_buf = temp_buf_scale (temp_buf, preview_width, preview_height); temp_buf_free (temp_buf); } else { - return_buf = gimp_viewable_get_new_preview (preview->viewable, + render_buf = gimp_viewable_get_new_preview (preview->viewable, preview_width, preview_height); } - if (preview_width < width) return_buf->x = (width - preview_width) / 2; - if (preview_height < height) return_buf->y = (height - preview_height) / 2; + if (preview_width < width) render_buf->x = (width - preview_width) / 2; + if (preview_height < height) render_buf->y = (height - preview_height) / 2; - if (return_buf->x || return_buf->y) + if (render_buf->x || render_buf->y) { TempBuf *temp_buf; guchar white[4] = { 255, 255, 255, 255 }; temp_buf = temp_buf_new (width, height, - return_buf->bytes, + render_buf->bytes, 0, 0, white); - temp_buf_copy_area (return_buf, temp_buf, + temp_buf_copy_area (render_buf, temp_buf, 0, 0, - return_buf->width, - return_buf->height, - return_buf->x, - return_buf->y); + render_buf->width, + render_buf->height, + render_buf->x, + render_buf->y); - temp_buf_free (return_buf); + temp_buf_free (render_buf); - return temp_buf; + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + return; } - return return_buf; + gimp_preview_render_and_flush (preview, + render_buf, + width, + height, + -1); + + temp_buf_free (render_buf); + + return; } static GtkWidget * diff --git a/app/widgets/gimpview.c b/app/widgets/gimpview.c index d05ce15ec4..854e0e1c3c 100644 --- a/app/widgets/gimpview.c +++ b/app/widgets/gimpview.c @@ -56,7 +56,7 @@ enum { CLICKED, - CREATE_PREVIEW, + RENDER, CREATE_POPUP, NEEDS_POPUP, LAST_SIGNAL @@ -77,8 +77,8 @@ static gint gimp_preview_enter_notify_event (GtkWidget *widget, static gint gimp_preview_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event); -static TempBuf * gimp_preview_create_preview (GimpPreview *preview); -static TempBuf * gimp_preview_real_create_preview (GimpPreview *preview); +static void gimp_preview_render (GimpPreview *preview); +static void gimp_preview_real_render (GimpPreview *preview); static GtkWidget * gimp_preview_create_popup (GimpPreview *preview); static GtkWidget * gimp_preview_real_create_popup (GimpPreview *preview); static gboolean gimp_preview_needs_popup (GimpPreview *preview); @@ -142,14 +142,14 @@ gimp_preview_class_init (GimpPreviewClass *klass) gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); - preview_signals[CREATE_PREVIEW] = - gtk_signal_new ("create_preview", + preview_signals[RENDER] = + gtk_signal_new ("render", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET (GimpPreviewClass, - create_preview), - gimp_marshal_POINTER__NONE, - GTK_TYPE_POINTER, 0); + render), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); preview_signals[CREATE_POPUP] = gtk_signal_new ("create_popup", @@ -179,10 +179,10 @@ gimp_preview_class_init (GimpPreviewClass *klass) widget_class->enter_notify_event = gimp_preview_enter_notify_event; widget_class->leave_notify_event = gimp_preview_leave_notify_event; - klass->clicked = NULL; - klass->create_preview = gimp_preview_real_create_preview; - klass->create_popup = gimp_preview_real_create_popup; - klass->needs_popup = gimp_preview_real_needs_popup; + klass->clicked = NULL; + klass->render = gimp_preview_real_render; + klass->create_popup = gimp_preview_real_create_popup; + klass->needs_popup = gimp_preview_real_needs_popup; } static void @@ -386,24 +386,31 @@ gimp_preview_leave_notify_event (GtkWidget *widget, return FALSE; } -static TempBuf * -gimp_preview_create_preview (GimpPreview *preview) +static void +gimp_preview_render (GimpPreview *preview) { - TempBuf *temp_buf = NULL; - - gtk_signal_emit (GTK_OBJECT (preview), preview_signals[CREATE_PREVIEW], - &temp_buf); - - return temp_buf; + gtk_signal_emit (GTK_OBJECT (preview), preview_signals[RENDER]); } -static TempBuf * -gimp_preview_real_create_preview (GimpPreview *preview) +static void +gimp_preview_real_render (GimpPreview *preview) { - return + TempBuf *temp_buf; + gint width; + gint height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + temp_buf = gimp_viewable_get_new_preview (preview->viewable, - GTK_WIDGET (preview)->requisition.width, - GTK_WIDGET (preview)->requisition.height); + width, height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); } static GtkWidget * @@ -564,229 +571,223 @@ gimp_preview_paint (GimpPreview *preview) static gboolean gimp_preview_idle_paint (GimpPreview *preview) { - TempBuf *temp_buf; - gint width; - gint height; - gint channel; - preview->idle_id = 0; if (! preview->viewable) return FALSE; - temp_buf = gimp_preview_create_preview (preview); - - width = temp_buf->width; - height = temp_buf->height; - channel = -1; - - /* from layers_dialog.c */ - { - guchar *src, *s; - guchar *cb; - guchar *buf; - gint a; - gint i, j, b; - gint x1, y1, x2, y2; - gint rowstride; - gboolean color_buf; - gboolean color; - gint alpha; - gboolean has_alpha; - gint image_bytes; - gint offset; - - alpha = ALPHA_PIX; - - /* Here are the different cases this functions handles correctly: - * 1) Offset temp_buf which does not necessarily cover full image area - * 2) Color conversion of temp_buf if it is gray and image is color - * 3) Background check buffer for transparent temp_bufs - * 4) Using the optional "channel" argument, one channel can be extracted - * from a multi-channel temp_buf and composited as a grayscale - * Prereqs: - * 1) Grayscale temp_bufs have bytes == {1, 2} - * 2) Color temp_bufs have bytes == {3, 4} - * 3) If image is gray, then temp_buf should have bytes == {1, 2} - */ - color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); - image_bytes = (color_buf) ? 3 : 1; - has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); - rowstride = temp_buf->width * temp_buf->bytes; - - /* Determine if the preview buf supplied is color - * Generally, if the bytes == {3, 4}, this is true. - * However, if the channel argument supplied is not -1, then - * the preview buf is assumed to be gray despite the number of - * channels it contains - */ - color = ((channel == -1) && - (temp_buf->bytes == 3 || temp_buf->bytes == 4)); - - if (has_alpha) - { - buf = render_check_buf; - alpha = ((color) ? ALPHA_PIX : - ((channel != -1) ? (temp_buf->bytes - 1) : - ALPHA_G_PIX)); - } - else - { - buf = render_empty_buf; - } - - x1 = CLAMP (temp_buf->x, 0, width); - y1 = CLAMP (temp_buf->y, 0, height); - x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); - y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); - - src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + - (x1 - temp_buf->x) * temp_buf->bytes); - - /* One last thing for efficiency's sake: */ - if (channel == -1) - channel = 0; - - for (i = 0; i < height; i++) - { - if (i & 0x4) - { - offset = 4; - cb = buf + offset * 3; - } - else - { - offset = 0; - cb = buf; - } - - /* The interesting stuff between leading & trailing - * vertical transparency - */ - if (i >= y1 && i < y2) - { - /* Handle the leading transparency */ - for (j = 0; j < x1; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - /* The stuff in the middle */ - s = src; - for (j = x1; j < x2; j++) - { - if (color) - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[BLUE_PIX])]; - } - else - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[BLUE_PIX])]; - } - } - else - { - render_temp_buf[j * 3 + 0] = s[RED_PIX]; - render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; - render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; - } - } - else - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_dark_check [(a | s[GRAY_PIX + channel])]; - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_light_check [(a | s[GRAY_PIX + channel])]; - } - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; - } - else - { - render_temp_buf[j] = s[GRAY_PIX + channel]; - } - } - } - - s += temp_buf->bytes; - } - - /* Handle the trailing transparency */ - for (j = x2; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - src += rowstride; - } - else - { - for (j = 0; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - } - - gtk_preview_draw_row (GTK_PREVIEW (preview), - render_temp_buf, 0, i, width); - } - } - - temp_buf_free (temp_buf); - - gtk_widget_queue_draw (GTK_WIDGET (preview)); + gimp_preview_render (preview); return FALSE; } + +void +gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel) +{ + guchar *src, *s; + guchar *cb; + guchar *buf; + gint a; + gint i, j, b; + gint x1, y1, x2, y2; + gint rowstride; + gboolean color_buf; + gboolean color; + gint alpha; + gboolean has_alpha; + gint image_bytes; + gint offset; + + alpha = ALPHA_PIX; + + /* Here are the different cases this functions handles correctly: + * 1) Offset temp_buf which does not necessarily cover full image area + * 2) Color conversion of temp_buf if it is gray and image is color + * 3) Background check buffer for transparent temp_bufs + * 4) Using the optional "channel" argument, one channel can be extracted + * from a multi-channel temp_buf and composited as a grayscale + * Prereqs: + * 1) Grayscale temp_bufs have bytes == {1, 2} + * 2) Color temp_bufs have bytes == {3, 4} + * 3) If image is gray, then temp_buf should have bytes == {1, 2} + */ + color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); + image_bytes = (color_buf) ? 3 : 1; + has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); + rowstride = temp_buf->width * temp_buf->bytes; + + /* Determine if the preview buf supplied is color + * Generally, if the bytes == {3, 4}, this is true. + * However, if the channel argument supplied is not -1, then + * the preview buf is assumed to be gray despite the number of + * channels it contains + */ + color = ((channel == -1) && + (temp_buf->bytes == 3 || temp_buf->bytes == 4)); + + if (has_alpha) + { + buf = render_check_buf; + alpha = ((color) ? ALPHA_PIX : + ((channel != -1) ? (temp_buf->bytes - 1) : + ALPHA_G_PIX)); + } + else + { + buf = render_empty_buf; + } + + x1 = CLAMP (temp_buf->x, 0, width); + y1 = CLAMP (temp_buf->y, 0, height); + x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); + y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); + + src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + + (x1 - temp_buf->x) * temp_buf->bytes); + + /* One last thing for efficiency's sake: */ + if (channel == -1) + channel = 0; + + for (i = 0; i < height; i++) + { + if (i & 0x4) + { + offset = 4; + cb = buf + offset * 3; + } + else + { + offset = 0; + cb = buf; + } + + /* The interesting stuff between leading & trailing + * vertical transparency + */ + if (i >= y1 && i < y2) + { + /* Handle the leading transparency */ + for (j = 0; j < x1; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + /* The stuff in the middle */ + s = src; + for (j = x1; j < x2; j++) + { + if (color) + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[BLUE_PIX])]; + } + else + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[BLUE_PIX])]; + } + } + else + { + render_temp_buf[j * 3 + 0] = s[RED_PIX]; + render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; + render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; + } + } + else + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_dark_check [(a | s[GRAY_PIX + channel])]; + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_light_check [(a | s[GRAY_PIX + channel])]; + } + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; + } + else + { + render_temp_buf[j] = s[GRAY_PIX + channel]; + } + } + } + + s += temp_buf->bytes; + } + + /* Handle the trailing transparency */ + for (j = x2; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + src += rowstride; + } + else + { + for (j = 0; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), + render_temp_buf, 0, i, width); + } + + gtk_widget_queue_draw (GTK_WIDGET (preview)); +} diff --git a/app/widgets/gimpview.h b/app/widgets/gimpview.h index e01d170d04..2266688ff7 100644 --- a/app/widgets/gimpview.h +++ b/app/widgets/gimpview.h @@ -61,20 +61,26 @@ struct _GimpPreviewClass { GtkPreviewClass parent_class; - void (* clicked) (GimpPreview *preview); - TempBuf * (* create_preview) (GimpPreview *preview); - GtkWidget * (* create_popup) (GimpPreview *preview); - gboolean (* needs_popup) (GimpPreview *preview); + void (* clicked) (GimpPreview *preview); + void (* render) (GimpPreview *preview); + GtkWidget * (* create_popup) (GimpPreview *preview); + gboolean (* needs_popup) (GimpPreview *preview); }; -GtkType gimp_preview_get_type (void); -GtkWidget * gimp_preview_new (GimpViewable *viewable, - gboolean is_popup, - gint width, - gint height, - gboolean clickable, - gboolean show_popup); +GtkType gimp_preview_get_type (void); +GtkWidget * gimp_preview_new (GimpViewable *viewable, + gboolean is_popup, + gint width, + gint height, + gboolean clickable, + gboolean show_popup); + +void gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel); #ifdef __cplusplus diff --git a/app/widgets/gimpviewrenderer.c b/app/widgets/gimpviewrenderer.c index d05ce15ec4..854e0e1c3c 100644 --- a/app/widgets/gimpviewrenderer.c +++ b/app/widgets/gimpviewrenderer.c @@ -56,7 +56,7 @@ enum { CLICKED, - CREATE_PREVIEW, + RENDER, CREATE_POPUP, NEEDS_POPUP, LAST_SIGNAL @@ -77,8 +77,8 @@ static gint gimp_preview_enter_notify_event (GtkWidget *widget, static gint gimp_preview_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event); -static TempBuf * gimp_preview_create_preview (GimpPreview *preview); -static TempBuf * gimp_preview_real_create_preview (GimpPreview *preview); +static void gimp_preview_render (GimpPreview *preview); +static void gimp_preview_real_render (GimpPreview *preview); static GtkWidget * gimp_preview_create_popup (GimpPreview *preview); static GtkWidget * gimp_preview_real_create_popup (GimpPreview *preview); static gboolean gimp_preview_needs_popup (GimpPreview *preview); @@ -142,14 +142,14 @@ gimp_preview_class_init (GimpPreviewClass *klass) gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); - preview_signals[CREATE_PREVIEW] = - gtk_signal_new ("create_preview", + preview_signals[RENDER] = + gtk_signal_new ("render", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET (GimpPreviewClass, - create_preview), - gimp_marshal_POINTER__NONE, - GTK_TYPE_POINTER, 0); + render), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); preview_signals[CREATE_POPUP] = gtk_signal_new ("create_popup", @@ -179,10 +179,10 @@ gimp_preview_class_init (GimpPreviewClass *klass) widget_class->enter_notify_event = gimp_preview_enter_notify_event; widget_class->leave_notify_event = gimp_preview_leave_notify_event; - klass->clicked = NULL; - klass->create_preview = gimp_preview_real_create_preview; - klass->create_popup = gimp_preview_real_create_popup; - klass->needs_popup = gimp_preview_real_needs_popup; + klass->clicked = NULL; + klass->render = gimp_preview_real_render; + klass->create_popup = gimp_preview_real_create_popup; + klass->needs_popup = gimp_preview_real_needs_popup; } static void @@ -386,24 +386,31 @@ gimp_preview_leave_notify_event (GtkWidget *widget, return FALSE; } -static TempBuf * -gimp_preview_create_preview (GimpPreview *preview) +static void +gimp_preview_render (GimpPreview *preview) { - TempBuf *temp_buf = NULL; - - gtk_signal_emit (GTK_OBJECT (preview), preview_signals[CREATE_PREVIEW], - &temp_buf); - - return temp_buf; + gtk_signal_emit (GTK_OBJECT (preview), preview_signals[RENDER]); } -static TempBuf * -gimp_preview_real_create_preview (GimpPreview *preview) +static void +gimp_preview_real_render (GimpPreview *preview) { - return + TempBuf *temp_buf; + gint width; + gint height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + temp_buf = gimp_viewable_get_new_preview (preview->viewable, - GTK_WIDGET (preview)->requisition.width, - GTK_WIDGET (preview)->requisition.height); + width, height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); } static GtkWidget * @@ -564,229 +571,223 @@ gimp_preview_paint (GimpPreview *preview) static gboolean gimp_preview_idle_paint (GimpPreview *preview) { - TempBuf *temp_buf; - gint width; - gint height; - gint channel; - preview->idle_id = 0; if (! preview->viewable) return FALSE; - temp_buf = gimp_preview_create_preview (preview); - - width = temp_buf->width; - height = temp_buf->height; - channel = -1; - - /* from layers_dialog.c */ - { - guchar *src, *s; - guchar *cb; - guchar *buf; - gint a; - gint i, j, b; - gint x1, y1, x2, y2; - gint rowstride; - gboolean color_buf; - gboolean color; - gint alpha; - gboolean has_alpha; - gint image_bytes; - gint offset; - - alpha = ALPHA_PIX; - - /* Here are the different cases this functions handles correctly: - * 1) Offset temp_buf which does not necessarily cover full image area - * 2) Color conversion of temp_buf if it is gray and image is color - * 3) Background check buffer for transparent temp_bufs - * 4) Using the optional "channel" argument, one channel can be extracted - * from a multi-channel temp_buf and composited as a grayscale - * Prereqs: - * 1) Grayscale temp_bufs have bytes == {1, 2} - * 2) Color temp_bufs have bytes == {3, 4} - * 3) If image is gray, then temp_buf should have bytes == {1, 2} - */ - color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); - image_bytes = (color_buf) ? 3 : 1; - has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); - rowstride = temp_buf->width * temp_buf->bytes; - - /* Determine if the preview buf supplied is color - * Generally, if the bytes == {3, 4}, this is true. - * However, if the channel argument supplied is not -1, then - * the preview buf is assumed to be gray despite the number of - * channels it contains - */ - color = ((channel == -1) && - (temp_buf->bytes == 3 || temp_buf->bytes == 4)); - - if (has_alpha) - { - buf = render_check_buf; - alpha = ((color) ? ALPHA_PIX : - ((channel != -1) ? (temp_buf->bytes - 1) : - ALPHA_G_PIX)); - } - else - { - buf = render_empty_buf; - } - - x1 = CLAMP (temp_buf->x, 0, width); - y1 = CLAMP (temp_buf->y, 0, height); - x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); - y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); - - src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + - (x1 - temp_buf->x) * temp_buf->bytes); - - /* One last thing for efficiency's sake: */ - if (channel == -1) - channel = 0; - - for (i = 0; i < height; i++) - { - if (i & 0x4) - { - offset = 4; - cb = buf + offset * 3; - } - else - { - offset = 0; - cb = buf; - } - - /* The interesting stuff between leading & trailing - * vertical transparency - */ - if (i >= y1 && i < y2) - { - /* Handle the leading transparency */ - for (j = 0; j < x1; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - /* The stuff in the middle */ - s = src; - for (j = x1; j < x2; j++) - { - if (color) - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[BLUE_PIX])]; - } - else - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[RED_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GREEN_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[BLUE_PIX])]; - } - } - else - { - render_temp_buf[j * 3 + 0] = s[RED_PIX]; - render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; - render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; - } - } - else - { - if (has_alpha) - { - a = s[alpha] << 8; - - if ((j + offset) & 0x4) - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_dark_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_dark_check [(a | s[GRAY_PIX + channel])]; - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 1] = - render_blend_light_check [(a | s[GRAY_PIX])]; - render_temp_buf[j * 3 + 2] = - render_blend_light_check [(a | s[GRAY_PIX])]; - } - else - { - render_temp_buf[j] = - render_blend_light_check [(a | s[GRAY_PIX + channel])]; - } - } - } - else - { - if (color_buf) - { - render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; - render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; - } - else - { - render_temp_buf[j] = s[GRAY_PIX + channel]; - } - } - } - - s += temp_buf->bytes; - } - - /* Handle the trailing transparency */ - for (j = x2; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - - src += rowstride; - } - else - { - for (j = 0; j < width; j++) - for (b = 0; b < image_bytes; b++) - render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; - } - - gtk_preview_draw_row (GTK_PREVIEW (preview), - render_temp_buf, 0, i, width); - } - } - - temp_buf_free (temp_buf); - - gtk_widget_queue_draw (GTK_WIDGET (preview)); + gimp_preview_render (preview); return FALSE; } + +void +gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel) +{ + guchar *src, *s; + guchar *cb; + guchar *buf; + gint a; + gint i, j, b; + gint x1, y1, x2, y2; + gint rowstride; + gboolean color_buf; + gboolean color; + gint alpha; + gboolean has_alpha; + gint image_bytes; + gint offset; + + alpha = ALPHA_PIX; + + /* Here are the different cases this functions handles correctly: + * 1) Offset temp_buf which does not necessarily cover full image area + * 2) Color conversion of temp_buf if it is gray and image is color + * 3) Background check buffer for transparent temp_bufs + * 4) Using the optional "channel" argument, one channel can be extracted + * from a multi-channel temp_buf and composited as a grayscale + * Prereqs: + * 1) Grayscale temp_bufs have bytes == {1, 2} + * 2) Color temp_bufs have bytes == {3, 4} + * 3) If image is gray, then temp_buf should have bytes == {1, 2} + */ + color_buf = (GTK_PREVIEW (preview)->type == GTK_PREVIEW_COLOR); + image_bytes = (color_buf) ? 3 : 1; + has_alpha = (temp_buf->bytes == 2 || temp_buf->bytes == 4); + rowstride = temp_buf->width * temp_buf->bytes; + + /* Determine if the preview buf supplied is color + * Generally, if the bytes == {3, 4}, this is true. + * However, if the channel argument supplied is not -1, then + * the preview buf is assumed to be gray despite the number of + * channels it contains + */ + color = ((channel == -1) && + (temp_buf->bytes == 3 || temp_buf->bytes == 4)); + + if (has_alpha) + { + buf = render_check_buf; + alpha = ((color) ? ALPHA_PIX : + ((channel != -1) ? (temp_buf->bytes - 1) : + ALPHA_G_PIX)); + } + else + { + buf = render_empty_buf; + } + + x1 = CLAMP (temp_buf->x, 0, width); + y1 = CLAMP (temp_buf->y, 0, height); + x2 = CLAMP (temp_buf->x + temp_buf->width, 0, width); + y2 = CLAMP (temp_buf->y + temp_buf->height, 0, height); + + src = temp_buf_data (temp_buf) + ((y1 - temp_buf->y) * rowstride + + (x1 - temp_buf->x) * temp_buf->bytes); + + /* One last thing for efficiency's sake: */ + if (channel == -1) + channel = 0; + + for (i = 0; i < height; i++) + { + if (i & 0x4) + { + offset = 4; + cb = buf + offset * 3; + } + else + { + offset = 0; + cb = buf; + } + + /* The interesting stuff between leading & trailing + * vertical transparency + */ + if (i >= y1 && i < y2) + { + /* Handle the leading transparency */ + for (j = 0; j < x1; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + /* The stuff in the middle */ + s = src; + for (j = x1; j < x2; j++) + { + if (color) + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[BLUE_PIX])]; + } + else + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[RED_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GREEN_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[BLUE_PIX])]; + } + } + else + { + render_temp_buf[j * 3 + 0] = s[RED_PIX]; + render_temp_buf[j * 3 + 1] = s[GREEN_PIX]; + render_temp_buf[j * 3 + 2] = s[BLUE_PIX]; + } + } + else + { + if (has_alpha) + { + a = s[alpha] << 8; + + if ((j + offset) & 0x4) + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_dark_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_dark_check [(a | s[GRAY_PIX + channel])]; + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 1] = + render_blend_light_check [(a | s[GRAY_PIX])]; + render_temp_buf[j * 3 + 2] = + render_blend_light_check [(a | s[GRAY_PIX])]; + } + else + { + render_temp_buf[j] = + render_blend_light_check [(a | s[GRAY_PIX + channel])]; + } + } + } + else + { + if (color_buf) + { + render_temp_buf[j * 3 + 0] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 1] = s[GRAY_PIX]; + render_temp_buf[j * 3 + 2] = s[GRAY_PIX]; + } + else + { + render_temp_buf[j] = s[GRAY_PIX + channel]; + } + } + } + + s += temp_buf->bytes; + } + + /* Handle the trailing transparency */ + for (j = x2; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + + src += rowstride; + } + else + { + for (j = 0; j < width; j++) + for (b = 0; b < image_bytes; b++) + render_temp_buf[j * image_bytes + b] = cb[j * 3 + b]; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), + render_temp_buf, 0, i, width); + } + + gtk_widget_queue_draw (GTK_WIDGET (preview)); +} diff --git a/app/widgets/gimpviewrenderer.h b/app/widgets/gimpviewrenderer.h index e01d170d04..2266688ff7 100644 --- a/app/widgets/gimpviewrenderer.h +++ b/app/widgets/gimpviewrenderer.h @@ -61,20 +61,26 @@ struct _GimpPreviewClass { GtkPreviewClass parent_class; - void (* clicked) (GimpPreview *preview); - TempBuf * (* create_preview) (GimpPreview *preview); - GtkWidget * (* create_popup) (GimpPreview *preview); - gboolean (* needs_popup) (GimpPreview *preview); + void (* clicked) (GimpPreview *preview); + void (* render) (GimpPreview *preview); + GtkWidget * (* create_popup) (GimpPreview *preview); + gboolean (* needs_popup) (GimpPreview *preview); }; -GtkType gimp_preview_get_type (void); -GtkWidget * gimp_preview_new (GimpViewable *viewable, - gboolean is_popup, - gint width, - gint height, - gboolean clickable, - gboolean show_popup); +GtkType gimp_preview_get_type (void); +GtkWidget * gimp_preview_new (GimpViewable *viewable, + gboolean is_popup, + gint width, + gint height, + gboolean clickable, + gboolean show_popup); + +void gimp_preview_render_and_flush (GimpPreview *preview, + TempBuf *temp_buf, + gint width, + gint height, + gint channel); #ifdef __cplusplus diff --git a/app/widgets/gimpviewrendererbrush.c b/app/widgets/gimpviewrendererbrush.c index fa1a6b05e7..426b1fa39e 100644 --- a/app/widgets/gimpviewrendererbrush.c +++ b/app/widgets/gimpviewrendererbrush.c @@ -34,9 +34,12 @@ static void gimp_brush_preview_class_init (GimpBrushPreviewClass *klass); static void gimp_brush_preview_init (GimpBrushPreview *preview); -static TempBuf * gimp_brush_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_brush_preview_create_popup (GimpPreview *preview); -static gboolean gimp_brush_preview_needs_popup (GimpPreview *preview); +static void gimp_brush_preview_destroy (GtkObject *object); +static void gimp_brush_preview_render (GimpPreview *preview); +static GtkWidget * gimp_brush_preview_create_popup (GimpPreview *preview); +static gboolean gimp_brush_preview_needs_popup (GimpPreview *preview); + +static gboolean gimp_brush_preview_render_timeout_func (GimpBrushPreview *preview); static GimpPreviewClass *parent_class = NULL; @@ -78,14 +81,37 @@ gimp_brush_preview_class_init (GimpBrushPreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); - preview_class->create_preview = gimp_brush_preview_create_preview; + object_class->destroy = gimp_brush_preview_destroy; + + preview_class->render = gimp_brush_preview_render; preview_class->create_popup = gimp_brush_preview_create_popup; preview_class->needs_popup = gimp_brush_preview_needs_popup; } static void -gimp_brush_preview_init (GimpBrushPreview *preview) +gimp_brush_preview_init (GimpBrushPreview *brush_preview) { + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; +} + +static void +gimp_brush_preview_destroy (GtkObject *object) +{ + GimpBrushPreview *brush_preview; + + brush_preview = GIMP_BRUSH_PREVIEW (object); + + if (brush_preview->pipe_timeout_id) + { + g_source_remove (brush_preview->pipe_timeout_id); + + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + GTK_OBJECT_CLASS (parent_class)->destroy (object); } #define indicator_width 7 @@ -95,20 +121,30 @@ gimp_brush_preview_init (GimpBrushPreview *preview) #define BLK { 0, 0, 0 } #define RED { 255, 127, 127 } -static TempBuf * -gimp_brush_preview_create_preview (GimpPreview *preview) +static void +gimp_brush_preview_render (GimpPreview *preview) { - GimpBrush *brush; - TempBuf *temp_buf; - gint width; - gint height; - gint brush_width; - gint brush_height; - guchar *buf; - guchar *b; - gint x, y; - gint offset_x; - gint offset_y; + GimpBrushPreview *brush_preview; + GimpBrush *brush; + TempBuf *temp_buf; + gint width; + gint height; + gint brush_width; + gint brush_height; + guchar *buf; + guchar *b; + gint x, y; + gint offset_x; + gint offset_y; + + brush_preview = GIMP_BRUSH_PREVIEW (preview); + + if (brush_preview->pipe_timeout_id) + { + g_source_remove (brush_preview->pipe_timeout_id); + + brush_preview->pipe_timeout_id = 0; + } brush = GIMP_BRUSH (preview->viewable); brush_width = brush->mask->width; @@ -118,10 +154,38 @@ gimp_brush_preview_create_preview (GimpPreview *preview) height = GTK_WIDGET (preview)->requisition.height; temp_buf = gimp_viewable_get_new_preview (preview->viewable, - width, height); + width, + height); if (preview->is_popup) - return temp_buf; + { + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + if (GIMP_IS_BRUSH_PIPE (brush)) + { + if (width != brush_width || + height != brush_height) + { + g_warning ("%s(): non-fullsize pipe popups are not supported yet.", + G_GNUC_FUNCTION); + return; + } + + brush_preview->pipe_animation_index = 0; + brush_preview->pipe_timeout_id = + g_timeout_add (300, + (GSourceFunc) gimp_brush_preview_render_timeout_func, + brush_preview); + } + + return; + } buf = temp_buf_data (temp_buf); @@ -213,7 +277,13 @@ gimp_brush_preview_create_preview (GimpPreview *preview) #undef BLK #undef RED - return temp_buf; + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); } static GtkWidget * @@ -255,3 +325,54 @@ gimp_brush_preview_needs_popup (GimpPreview *preview) return FALSE; } + +static gboolean +gimp_brush_preview_render_timeout_func (GimpBrushPreview *brush_preview) +{ + GimpPreview *preview; + GimpBrushPipe *brush_pipe; + GimpBrush *brush; + TempBuf *temp_buf; + gint width; + gint height; + gint brush_width; + gint brush_height; + + preview = GIMP_PREVIEW (brush_preview); + + if (! preview->viewable) + { + brush_preview->pipe_timeout_id = 0; + brush_preview->pipe_animation_index = 0; + + return FALSE; + } + + brush_pipe = GIMP_BRUSH_PIPE (preview->viewable); + brush_width = brush->mask->width; + brush_height = brush->mask->height; + + width = GTK_WIDGET (preview)->requisition.width; + height = GTK_WIDGET (preview)->requisition.height; + + brush_preview->pipe_animation_index++; + + if (brush_preview->pipe_animation_index >= brush_pipe->nbrushes) + brush_preview->pipe_animation_index = 0; + + brush = GIMP_BRUSH (brush_pipe->brushes[brush_preview->pipe_animation_index]); + + temp_buf = gimp_viewable_get_new_preview (GIMP_VIEWABLE (brush), + width, + height); + + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + return TRUE; +} diff --git a/app/widgets/gimpviewrendererbrush.h b/app/widgets/gimpviewrendererbrush.h index e2f08d44eb..dce102a208 100644 --- a/app/widgets/gimpviewrendererbrush.h +++ b/app/widgets/gimpviewrendererbrush.h @@ -42,7 +42,10 @@ typedef struct _GimpBrushPreviewClass GimpBrushPreviewClass; struct _GimpBrushPreview { - GimpPreview parent_instance; + GimpPreview parent_instance; + + guint pipe_timeout_id; + gint pipe_animation_index; }; struct _GimpBrushPreviewClass diff --git a/app/widgets/gimpviewrendererdrawable.c b/app/widgets/gimpviewrendererdrawable.c index 468b607793..294fd4ff64 100644 --- a/app/widgets/gimpviewrendererdrawable.c +++ b/app/widgets/gimpviewrendererdrawable.c @@ -31,8 +31,8 @@ static void gimp_drawable_preview_class_init (GimpDrawablePreviewClass *klass); static void gimp_drawable_preview_init (GimpDrawablePreview *preview); -static TempBuf * gimp_drawable_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_drawable_preview_create_popup (GimpPreview *preview); +static void gimp_drawable_preview_render (GimpPreview *preview); +static GtkWidget * gimp_drawable_preview_create_popup (GimpPreview *preview); static GimpPreviewClass *parent_class = NULL; @@ -80,8 +80,8 @@ gimp_drawable_preview_init (GimpDrawablePreview *preview) { } -static TempBuf * -gimp_drawable_preview_create_preview (GimpPreview *preview) +static void +gimp_drawable_preview_render (GimpPreview *preview) { } diff --git a/app/widgets/gimpviewrendererimage.c b/app/widgets/gimpviewrendererimage.c index 261a141098..7cb0e919e8 100644 --- a/app/widgets/gimpviewrendererimage.c +++ b/app/widgets/gimpviewrendererimage.c @@ -36,14 +36,14 @@ static void gimp_image_preview_class_init (GimpImagePreviewClass *klass); static void gimp_image_preview_init (GimpImagePreview *preview); -static TempBuf * gimp_image_preview_create_preview (GimpPreview *preview); -static GtkWidget * gimp_image_preview_create_popup (GimpPreview *preview); -static void gimp_image_preview_calc_size (GimpImage *gimage, - gint width, - gint height, - gint *return_width, - gint *return_height, - gboolean *scaling_up); +static void gimp_image_preview_render (GimpPreview *preview); +static GtkWidget * gimp_image_preview_create_popup (GimpPreview *preview); +static void gimp_image_preview_calc_size (GimpImage *gimage, + gint width, + gint height, + gint *return_width, + gint *return_height, + gboolean *scaling_up); static GimpPreviewClass *parent_class = NULL; @@ -85,8 +85,8 @@ gimp_image_preview_class_init (GimpImagePreviewClass *klass) parent_class = gtk_type_class (GIMP_TYPE_PREVIEW); - preview_class->create_preview = gimp_image_preview_create_preview; - preview_class->create_popup = gimp_image_preview_create_popup; + preview_class->render = gimp_image_preview_render; + preview_class->create_popup = gimp_image_preview_create_popup; } static void @@ -94,8 +94,8 @@ gimp_image_preview_init (GimpImagePreview *preview) { } -static TempBuf * -gimp_image_preview_create_preview (GimpPreview *preview) +static void +gimp_image_preview_render (GimpPreview *preview) { GimpImage *gimage; gint width; @@ -103,7 +103,7 @@ gimp_image_preview_create_preview (GimpPreview *preview) gint preview_width; gint preview_height; gboolean scaling_up; - TempBuf *return_buf; + TempBuf *render_buf; gimage = GIMP_IMAGE (preview->viewable); @@ -124,43 +124,59 @@ gimp_image_preview_create_preview (GimpPreview *preview) temp_buf = gimp_viewable_get_new_preview (preview->viewable, gimage->width, gimage->height); - return_buf = temp_buf_scale (temp_buf, preview_width, preview_height); + render_buf = temp_buf_scale (temp_buf, preview_width, preview_height); temp_buf_free (temp_buf); } else { - return_buf = gimp_viewable_get_new_preview (preview->viewable, + render_buf = gimp_viewable_get_new_preview (preview->viewable, preview_width, preview_height); } - if (preview_width < width) return_buf->x = (width - preview_width) / 2; - if (preview_height < height) return_buf->y = (height - preview_height) / 2; + if (preview_width < width) render_buf->x = (width - preview_width) / 2; + if (preview_height < height) render_buf->y = (height - preview_height) / 2; - if (return_buf->x || return_buf->y) + if (render_buf->x || render_buf->y) { TempBuf *temp_buf; guchar white[4] = { 255, 255, 255, 255 }; temp_buf = temp_buf_new (width, height, - return_buf->bytes, + render_buf->bytes, 0, 0, white); - temp_buf_copy_area (return_buf, temp_buf, + temp_buf_copy_area (render_buf, temp_buf, 0, 0, - return_buf->width, - return_buf->height, - return_buf->x, - return_buf->y); + render_buf->width, + render_buf->height, + render_buf->x, + render_buf->y); - temp_buf_free (return_buf); + temp_buf_free (render_buf); - return temp_buf; + gimp_preview_render_and_flush (preview, + temp_buf, + width, + height, + -1); + + temp_buf_free (temp_buf); + + return; } - return return_buf; + gimp_preview_render_and_flush (preview, + render_buf, + width, + height, + -1); + + temp_buf_free (render_buf); + + return; } static GtkWidget *