Code

38300426db84822baa6b0a7fe65257be157f6cea
[inkscape.git] / src / widgets / gradient-image.cpp
1 #define __SP_GRADIENT_IMAGE_C__
3 /*
4  * A simple gradient preview
5  *
6  * Author:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *
9  * Copyright (C) 2001-2002 Lauris Kaplinski
10  * Copyright (C) 2001 Ximian, Inc.
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #include <libnr/nr-pixblock-pattern.h>
16 #include "macros.h"
17 #include "../display/nr-plain-stuff.h"
18 #include "../display/nr-plain-stuff-gdk.h"
19 #include "gradient-image.h"
20 #include "sp-gradient-fns.h"
22 #define VBLOCK 16
24 static void sp_gradient_image_class_init (SPGradientImageClass *klass);
25 static void sp_gradient_image_init (SPGradientImage *image);
26 static void sp_gradient_image_destroy (GtkObject *object);
28 static void sp_gradient_image_realize (GtkWidget *widget);
29 static void sp_gradient_image_unrealize (GtkWidget *widget);
30 static void sp_gradient_image_size_request (GtkWidget *widget, GtkRequisition *requisition);
31 static void sp_gradient_image_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
32 static gint sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event);
34 static void sp_gradient_image_gradient_release (SPGradient *gr, SPGradientImage *im);
35 static void sp_gradient_image_gradient_modified (SPGradient *gr, guint flags, SPGradientImage *im);
36 static void sp_gradient_image_update (SPGradientImage *img);
38 static GtkWidgetClass *parent_class;
40 GtkType
41 sp_gradient_image_get_type (void)
42 {
43         static GtkType type = 0;
44         if (!type) {
45                 GtkTypeInfo info = {
46                         "SPGradientImage",
47                         sizeof (SPGradientImage),
48                         sizeof (SPGradientImageClass),
49                         (GtkClassInitFunc) sp_gradient_image_class_init,
50                         (GtkObjectInitFunc) sp_gradient_image_init,
51                         NULL, NULL, NULL
52                 };
53                 type = gtk_type_unique (GTK_TYPE_WIDGET, &info);
54         }
55         return type;
56 }
58 static void
59 sp_gradient_image_class_init (SPGradientImageClass *klass)
60 {
61         GtkObjectClass *object_class;
62         GtkWidgetClass *widget_class;
64         object_class = (GtkObjectClass *) klass;
65         widget_class = (GtkWidgetClass *) klass;
67         parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET);
69         object_class->destroy = sp_gradient_image_destroy;
71         widget_class->realize = sp_gradient_image_realize;
72         widget_class->unrealize = sp_gradient_image_unrealize;
73         widget_class->size_request = sp_gradient_image_size_request;
74         widget_class->size_allocate = sp_gradient_image_size_allocate;
75         widget_class->expose_event = sp_gradient_image_expose;
76 }
78 static void
79 sp_gradient_image_init (SPGradientImage *image)
80 {
81         GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
83         image->gradient = NULL;
84         image->px = NULL;
85 }
87 static void
88 sp_gradient_image_destroy (GtkObject *object)
89 {
90         SPGradientImage *image;
92         image = SP_GRADIENT_IMAGE (object);
94         if (image->gradient) {
95                 sp_signal_disconnect_by_data (image->gradient, image);
96                 image->gradient = NULL;
97         }
99         if (((GtkObjectClass *) (parent_class))->destroy)
100                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
103 static void
104 sp_gradient_image_realize (GtkWidget *widget)
106         SPGradientImage *image;
108         image = SP_GRADIENT_IMAGE (widget);
110         if (((GtkWidgetClass *) parent_class)->realize)
111                 (* ((GtkWidgetClass *) parent_class)->realize) (widget);
113         g_assert (!image->px);
114         image->px = g_new (guchar, 3 * VBLOCK * widget->allocation.width);
115         sp_gradient_image_update (image);
118 static void
119 sp_gradient_image_unrealize (GtkWidget *widget)
121         SPGradientImage *image;
123         image = SP_GRADIENT_IMAGE (widget);
125         if (((GtkWidgetClass *) parent_class)->unrealize)
126                 (* ((GtkWidgetClass *) parent_class)->unrealize) (widget);
128         g_assert (image->px);
129         g_free (image->px);
130         image->px = NULL;
133 static void
134 sp_gradient_image_size_request (GtkWidget *widget, GtkRequisition *requisition)
136         SPGradientImage *slider;
138         slider = SP_GRADIENT_IMAGE (widget);
140         requisition->width = 64;
141         requisition->height = 16;
144 static void
145 sp_gradient_image_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
147         SPGradientImage *image;
149         image = SP_GRADIENT_IMAGE (widget);
151         widget->allocation = *allocation;
153         if (GTK_WIDGET_REALIZED (widget)) {
154                 g_free (image->px);
155                 image->px = g_new (guchar, 3 * VBLOCK * allocation->width);
156         }
158         sp_gradient_image_update (image);
161 static gint
162 sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event)
164         SPGradientImage *image;
166         image = SP_GRADIENT_IMAGE (widget);
168         if (GTK_WIDGET_DRAWABLE (widget)) {
169                 gint x0, y0, x1, y1;
170                 x0 = MAX (event->area.x, widget->allocation.x);
171                 y0 = MAX (event->area.y, widget->allocation.y);
172                 x1 = MIN (event->area.x + event->area.width, widget->allocation.x + widget->allocation.width);
173                 y1 = MIN (event->area.y + event->area.height, widget->allocation.y + widget->allocation.height);
174                 if ((x1 > x0) && (y1 > y0)) {
175                         if (image->px) {
176                                 if (image->gradient) {
177                                         gint y;
178                                         guchar *p;
179                                         p = image->px + 3 * (x0 - widget->allocation.x);
180                                         for (y = y0; y < y1; y += VBLOCK) {
181                                                 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
182                                                                     x0, y,
183                                                                     (x1 - x0), MIN (VBLOCK, y1 - y),
184                                                                     GDK_RGB_DITHER_MAX,
185                                                                     p, widget->allocation.width * 3);
186                                         }
187                                 } else {
188                                         nr_gdk_draw_gray_garbage (widget->window, widget->style->black_gc,
189                                                                   x0, y0,
190                                                                   x1 - x0, y1 - y0);
191                                 }
192                         } else {
193                                 gdk_draw_rectangle (widget->window, widget->style->black_gc,
194                                                     x0, y0,
195                                                     (x1 - x0), (y1 - x0),
196                                                     TRUE);
197                         }
198                 }
199         }
201         return TRUE;
204 GtkWidget *
205 sp_gradient_image_new (SPGradient *gradient)
207         SPGradientImage *image;
209         image = (SPGradientImage*)gtk_type_new (SP_TYPE_GRADIENT_IMAGE);
211         sp_gradient_image_set_gradient (image, gradient);
213         return (GtkWidget *) image;
216 void
217 sp_gradient_image_set_gradient (SPGradientImage *image, SPGradient *gradient)
219         if (image->gradient) {
220                 sp_signal_disconnect_by_data (image->gradient, image);
221         }
223         image->gradient = gradient;
225         if (gradient) {
226                 g_signal_connect (G_OBJECT (gradient), "release", G_CALLBACK (sp_gradient_image_gradient_release), image);
227                 g_signal_connect (G_OBJECT (gradient), "modified", G_CALLBACK (sp_gradient_image_gradient_modified), image);
228         }
230         sp_gradient_image_update (image);
233 static void
234 sp_gradient_image_gradient_release (SPGradient *gradient, SPGradientImage *image)
236         if (image->gradient) {
237                 sp_signal_disconnect_by_data (image->gradient, image);
238         }
240         image->gradient = NULL;
242         sp_gradient_image_update (image);
245 static void
246 sp_gradient_image_gradient_modified (SPGradient *gradient, guint flags, SPGradientImage *image)
248         sp_gradient_image_update (image);
251 static void
252 sp_gradient_image_update (SPGradientImage *image)
254         GtkAllocation *allocation;
256         if (!image->px) return;
258         allocation = &((GtkWidget *) image)->allocation;
260         if (image->gradient) {
261                 nr_render_checkerboard_rgb (image->px, allocation->width, VBLOCK, 3 * allocation->width, 0, 0);
262                 sp_gradient_render_vector_block_rgb (image->gradient,
263                                                      image->px, allocation->width, VBLOCK, 3 * allocation->width,
264                                                      0, allocation->width, TRUE);
265         } else {
266                 NRPixBlock pb;
267                 nr_pixblock_setup_extern (&pb, NR_PIXBLOCK_MODE_R8G8B8,
268                                           0, 0, allocation->width, VBLOCK,
269                                           image->px, 3 * allocation->width, TRUE, FALSE);
270                 nr_pixblock_render_gray_noise (&pb, NULL);
271                 nr_pixblock_release (&pb);
272         }
274         if (GTK_WIDGET_DRAWABLE (image)) {
275                 gtk_widget_queue_draw (GTK_WIDGET (image));
276         }