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);
101 }
103 static void
104 sp_gradient_image_realize (GtkWidget *widget)
105 {
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);
116 }
118 static void
119 sp_gradient_image_unrealize (GtkWidget *widget)
120 {
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;
131 }
133 static void
134 sp_gradient_image_size_request (GtkWidget *widget, GtkRequisition *requisition)
135 {
136 SPGradientImage *slider;
138 slider = SP_GRADIENT_IMAGE (widget);
140 requisition->width = 64;
141 requisition->height = 16;
142 }
144 static void
145 sp_gradient_image_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
146 {
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);
159 }
161 static gint
162 sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event)
163 {
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;
202 }
204 GtkWidget *
205 sp_gradient_image_new (SPGradient *gradient)
206 {
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;
214 }
216 void
217 sp_gradient_image_set_gradient (SPGradientImage *image, SPGradient *gradient)
218 {
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);
231 }
233 static void
234 sp_gradient_image_gradient_release (SPGradient *gradient, SPGradientImage *image)
235 {
236 if (image->gradient) {
237 sp_signal_disconnect_by_data (image->gradient, image);
238 }
240 image->gradient = NULL;
242 sp_gradient_image_update (image);
243 }
245 static void
246 sp_gradient_image_gradient_modified (SPGradient *gradient, guint flags, SPGradientImage *image)
247 {
248 sp_gradient_image_update (image);
249 }
251 static void
252 sp_gradient_image_update (SPGradientImage *image)
253 {
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 }
277 }