diff options
Diffstat (limited to 'src/widgets/gradient-image.cpp')
| -rw-r--r-- | src/widgets/gradient-image.cpp | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/src/widgets/gradient-image.cpp b/src/widgets/gradient-image.cpp new file mode 100644 index 000000000..38300426d --- /dev/null +++ b/src/widgets/gradient-image.cpp @@ -0,0 +1,277 @@ +#define __SP_GRADIENT_IMAGE_C__ + +/* + * A simple gradient preview + * + * Author: + * Lauris Kaplinski <lauris@kaplinski.com> + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * Copyright (C) 2001 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <libnr/nr-pixblock-pattern.h> +#include "macros.h" +#include "../display/nr-plain-stuff.h" +#include "../display/nr-plain-stuff-gdk.h" +#include "gradient-image.h" +#include "sp-gradient-fns.h" + +#define VBLOCK 16 + +static void sp_gradient_image_class_init (SPGradientImageClass *klass); +static void sp_gradient_image_init (SPGradientImage *image); +static void sp_gradient_image_destroy (GtkObject *object); + +static void sp_gradient_image_realize (GtkWidget *widget); +static void sp_gradient_image_unrealize (GtkWidget *widget); +static void sp_gradient_image_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void sp_gradient_image_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gint sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event); + +static void sp_gradient_image_gradient_release (SPGradient *gr, SPGradientImage *im); +static void sp_gradient_image_gradient_modified (SPGradient *gr, guint flags, SPGradientImage *im); +static void sp_gradient_image_update (SPGradientImage *img); + +static GtkWidgetClass *parent_class; + +GtkType +sp_gradient_image_get_type (void) +{ + static GtkType type = 0; + if (!type) { + GtkTypeInfo info = { + "SPGradientImage", + sizeof (SPGradientImage), + sizeof (SPGradientImageClass), + (GtkClassInitFunc) sp_gradient_image_class_init, + (GtkObjectInitFunc) sp_gradient_image_init, + NULL, NULL, NULL + }; + type = gtk_type_unique (GTK_TYPE_WIDGET, &info); + } + return type; +} + +static void +sp_gradient_image_class_init (SPGradientImageClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass *) klass; + widget_class = (GtkWidgetClass *) klass; + + parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET); + + object_class->destroy = sp_gradient_image_destroy; + + widget_class->realize = sp_gradient_image_realize; + widget_class->unrealize = sp_gradient_image_unrealize; + widget_class->size_request = sp_gradient_image_size_request; + widget_class->size_allocate = sp_gradient_image_size_allocate; + widget_class->expose_event = sp_gradient_image_expose; +} + +static void +sp_gradient_image_init (SPGradientImage *image) +{ + GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW); + + image->gradient = NULL; + image->px = NULL; +} + +static void +sp_gradient_image_destroy (GtkObject *object) +{ + SPGradientImage *image; + + image = SP_GRADIENT_IMAGE (object); + + if (image->gradient) { + sp_signal_disconnect_by_data (image->gradient, image); + image->gradient = NULL; + } + + if (((GtkObjectClass *) (parent_class))->destroy) + (* ((GtkObjectClass *) (parent_class))->destroy) (object); +} + +static void +sp_gradient_image_realize (GtkWidget *widget) +{ + SPGradientImage *image; + + image = SP_GRADIENT_IMAGE (widget); + + if (((GtkWidgetClass *) parent_class)->realize) + (* ((GtkWidgetClass *) parent_class)->realize) (widget); + + g_assert (!image->px); + image->px = g_new (guchar, 3 * VBLOCK * widget->allocation.width); + sp_gradient_image_update (image); +} + +static void +sp_gradient_image_unrealize (GtkWidget *widget) +{ + SPGradientImage *image; + + image = SP_GRADIENT_IMAGE (widget); + + if (((GtkWidgetClass *) parent_class)->unrealize) + (* ((GtkWidgetClass *) parent_class)->unrealize) (widget); + + g_assert (image->px); + g_free (image->px); + image->px = NULL; +} + +static void +sp_gradient_image_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + SPGradientImage *slider; + + slider = SP_GRADIENT_IMAGE (widget); + + requisition->width = 64; + requisition->height = 16; +} + +static void +sp_gradient_image_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + SPGradientImage *image; + + image = SP_GRADIENT_IMAGE (widget); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) { + g_free (image->px); + image->px = g_new (guchar, 3 * VBLOCK * allocation->width); + } + + sp_gradient_image_update (image); +} + +static gint +sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event) +{ + SPGradientImage *image; + + image = SP_GRADIENT_IMAGE (widget); + + if (GTK_WIDGET_DRAWABLE (widget)) { + gint x0, y0, x1, y1; + x0 = MAX (event->area.x, widget->allocation.x); + y0 = MAX (event->area.y, widget->allocation.y); + x1 = MIN (event->area.x + event->area.width, widget->allocation.x + widget->allocation.width); + y1 = MIN (event->area.y + event->area.height, widget->allocation.y + widget->allocation.height); + if ((x1 > x0) && (y1 > y0)) { + if (image->px) { + if (image->gradient) { + gint y; + guchar *p; + p = image->px + 3 * (x0 - widget->allocation.x); + for (y = y0; y < y1; y += VBLOCK) { + gdk_draw_rgb_image (widget->window, widget->style->black_gc, + x0, y, + (x1 - x0), MIN (VBLOCK, y1 - y), + GDK_RGB_DITHER_MAX, + p, widget->allocation.width * 3); + } + } else { + nr_gdk_draw_gray_garbage (widget->window, widget->style->black_gc, + x0, y0, + x1 - x0, y1 - y0); + } + } else { + gdk_draw_rectangle (widget->window, widget->style->black_gc, + x0, y0, + (x1 - x0), (y1 - x0), + TRUE); + } + } + } + + return TRUE; +} + +GtkWidget * +sp_gradient_image_new (SPGradient *gradient) +{ + SPGradientImage *image; + + image = (SPGradientImage*)gtk_type_new (SP_TYPE_GRADIENT_IMAGE); + + sp_gradient_image_set_gradient (image, gradient); + + return (GtkWidget *) image; +} + +void +sp_gradient_image_set_gradient (SPGradientImage *image, SPGradient *gradient) +{ + if (image->gradient) { + sp_signal_disconnect_by_data (image->gradient, image); + } + + image->gradient = gradient; + + if (gradient) { + g_signal_connect (G_OBJECT (gradient), "release", G_CALLBACK (sp_gradient_image_gradient_release), image); + g_signal_connect (G_OBJECT (gradient), "modified", G_CALLBACK (sp_gradient_image_gradient_modified), image); + } + + sp_gradient_image_update (image); +} + +static void +sp_gradient_image_gradient_release (SPGradient *gradient, SPGradientImage *image) +{ + if (image->gradient) { + sp_signal_disconnect_by_data (image->gradient, image); + } + + image->gradient = NULL; + + sp_gradient_image_update (image); +} + +static void +sp_gradient_image_gradient_modified (SPGradient *gradient, guint flags, SPGradientImage *image) +{ + sp_gradient_image_update (image); +} + +static void +sp_gradient_image_update (SPGradientImage *image) +{ + GtkAllocation *allocation; + + if (!image->px) return; + + allocation = &((GtkWidget *) image)->allocation; + + if (image->gradient) { + nr_render_checkerboard_rgb (image->px, allocation->width, VBLOCK, 3 * allocation->width, 0, 0); + sp_gradient_render_vector_block_rgb (image->gradient, + image->px, allocation->width, VBLOCK, 3 * allocation->width, + 0, allocation->width, TRUE); + } else { + NRPixBlock pb; + nr_pixblock_setup_extern (&pb, NR_PIXBLOCK_MODE_R8G8B8, + 0, 0, allocation->width, VBLOCK, + image->px, 3 * allocation->width, TRUE, FALSE); + nr_pixblock_render_gray_noise (&pb, NULL); + nr_pixblock_release (&pb); + } + + if (GTK_WIDGET_DRAWABLE (image)) { + gtk_widget_queue_draw (GTK_WIDGET (image)); + } +} |
