summaryrefslogtreecommitdiffstats
path: root/src/widgets/gradient-image.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/gradient-image.cpp')
-rw-r--r--src/widgets/gradient-image.cpp277
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));
+ }
+}