Code

Merge from fe-moved
[inkscape.git] / src / widgets / sp-color-slider.cpp
1 #define __SP_COLOR_SLIDER_C__
3 /*
4  * A slider with colored background
5  *
6  * Author:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *
10  * Copyright (C) 2001-2002 Lauris Kaplinski
11  *
12  * This code is in public domain
13  */
15 #include <gtk/gtkversion.h>
16 #include <gtk/gtksignal.h>
17 #include "sp-color-scales.h"
19 #define SLIDER_WIDTH 96
20 #define SLIDER_HEIGHT 8
21 #define ARROW_SIZE 7
23 enum {
24         GRABBED,
25         DRAGGED,
26         RELEASED,
27         CHANGED,
28         LAST_SIGNAL
29 };
31 static void sp_color_slider_class_init (SPColorSliderClass *klass);
32 static void sp_color_slider_init (SPColorSlider *slider);
33 static void sp_color_slider_destroy (GtkObject *object);
35 static void sp_color_slider_realize (GtkWidget *widget);
36 static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition);
37 static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
38 /*  static void sp_color_slider_draw (GtkWidget *widget, GdkRectangle *area); */
39 /*  static void sp_color_slider_draw_focus (GtkWidget *widget); */
40 /*  static void sp_color_slider_draw_default (GtkWidget *widget); */
42 static gint sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event);
43 static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event);
44 static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event);
45 static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event);
47 static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider);
48 static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider);
50 static void sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area);
51 static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
52                                                       gint c[], gint dc[], guint b0, guint b1, guint mask);
53 static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
54                                                  guchar *map, gint start, gint step, guint b0, guint b1, guint mask);
56 static GtkWidgetClass *parent_class;
57 static guint slider_signals[LAST_SIGNAL] = {0};
59 GtkType
60 sp_color_slider_get_type (void)
61 {
62         static GtkType type = 0;
63         if (!type) {
64                 GtkTypeInfo info = {
65                         "SPColorSlider",
66                         sizeof (SPColorSlider),
67                         sizeof (SPColorSliderClass),
68                         (GtkClassInitFunc) sp_color_slider_class_init,
69                         (GtkObjectInitFunc) sp_color_slider_init,
70                         NULL, NULL, NULL
71                 };
72                 type = gtk_type_unique (GTK_TYPE_WIDGET, &info);
73         }
74         return type;
75 }
77 static void
78 sp_color_slider_class_init (SPColorSliderClass *klass)
79 {
80         GtkObjectClass *object_class;
81         GtkWidgetClass *widget_class;
83         object_class = (GtkObjectClass *) klass;
84         widget_class = (GtkWidgetClass *) klass;
86         parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET);
88         slider_signals[GRABBED] = gtk_signal_new ("grabbed",
89                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
90                                                   GTK_CLASS_TYPE(object_class),
91                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, grabbed),
92                                                   gtk_marshal_NONE__NONE,
93                                                   GTK_TYPE_NONE, 0);
94         slider_signals[DRAGGED] = gtk_signal_new ("dragged",
95                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
96                                                   GTK_CLASS_TYPE(object_class),
97                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, dragged),
98                                                   gtk_marshal_NONE__NONE,
99                                                   GTK_TYPE_NONE, 0);
100         slider_signals[RELEASED] = gtk_signal_new ("released",
101                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
102                                                   GTK_CLASS_TYPE(object_class),
103                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, released),
104                                                   gtk_marshal_NONE__NONE,
105                                                   GTK_TYPE_NONE, 0);
106         slider_signals[CHANGED] = gtk_signal_new ("changed",
107                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
108                                                   GTK_CLASS_TYPE(object_class),
109                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, changed),
110                                                   gtk_marshal_NONE__NONE,
111                                                   GTK_TYPE_NONE, 0);
113         object_class->destroy = sp_color_slider_destroy;
115         widget_class->realize = sp_color_slider_realize;
116         widget_class->size_request = sp_color_slider_size_request;
117         widget_class->size_allocate = sp_color_slider_size_allocate;
118 /*      widget_class->draw = sp_color_slider_draw; */
119 /*      widget_class->draw_focus = sp_color_slider_draw_focus; */
120 /*      widget_class->draw_default = sp_color_slider_draw_default; */
122         widget_class->expose_event = sp_color_slider_expose;
123         widget_class->button_press_event = sp_color_slider_button_press;
124         widget_class->button_release_event = sp_color_slider_button_release;
125         widget_class->motion_notify_event = sp_color_slider_motion_notify;
128 static void
129 sp_color_slider_init (SPColorSlider *slider)
131         /* We are widget with window */
132         GTK_WIDGET_UNSET_FLAGS (slider, GTK_NO_WINDOW);
134         slider->dragging = FALSE;
136         slider->adjustment = NULL;
137         slider->value = 0.0;
139         slider->c0[0] = 0x00;
140         slider->c0[1] = 0x00;
141         slider->c0[2] = 0x00;
142         slider->c0[3] = 0xff;
144         slider->cm[0] = 0xff;
145         slider->cm[1] = 0x00;
146         slider->cm[2] = 0x00;
147         slider->cm[3] = 0xff;
149         slider->c1[0] = 0xff;
150         slider->c1[1] = 0xff;
151         slider->c1[2] = 0xff;
152         slider->c1[3] = 0xff;
154         slider->b0 = 0x5f;
155         slider->b1 = 0xa0;
156         slider->bmask = 0x08;
158         slider->map = NULL;
161 static void
162 sp_color_slider_destroy (GtkObject *object)
164         SPColorSlider *slider;
166         slider = SP_COLOR_SLIDER (object);
168         if (slider->adjustment) {
169                 gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
170                 gtk_object_unref (GTK_OBJECT (slider->adjustment));
171                 slider->adjustment = NULL;
172         }
174         if (((GtkObjectClass *) (parent_class))->destroy)
175                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
178 static void
179 sp_color_slider_realize (GtkWidget *widget)
181         SPColorSlider *slider;
182         GdkWindowAttr attributes;
183         gint attributes_mask;
185         slider = SP_COLOR_SLIDER (widget);
187         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
189         attributes.window_type = GDK_WINDOW_CHILD;
190         attributes.x = widget->allocation.x;
191         attributes.y = widget->allocation.y;
192         attributes.width = widget->allocation.width;
193         attributes.height = widget->allocation.height;
194         attributes.wclass = GDK_INPUT_OUTPUT;
195         attributes.visual = gdk_rgb_get_visual ();
196         attributes.colormap = gdk_rgb_get_cmap ();
197         attributes.event_mask = gtk_widget_get_events (widget);
198         attributes.event_mask |= (GDK_EXPOSURE_MASK |
199                                   GDK_BUTTON_PRESS_MASK |
200                                   GDK_BUTTON_RELEASE_MASK |
201                                   GDK_POINTER_MOTION_MASK |
202                                   GDK_ENTER_NOTIFY_MASK |
203                                   GDK_LEAVE_NOTIFY_MASK);
204         attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
206         widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
207         gdk_window_set_user_data (widget->window, widget);
209         widget->style = gtk_style_attach (widget->style, widget->window);
212 static void
213 sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition)
215         SPColorSlider *slider;
217         slider = SP_COLOR_SLIDER (widget);
219         requisition->width = SLIDER_WIDTH + widget->style->xthickness * 2;
220         requisition->height = SLIDER_HEIGHT + widget->style->ythickness * 2;
223 static void
224 sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
226         SPColorSlider *slider;
228         slider = SP_COLOR_SLIDER (widget);
230         widget->allocation = *allocation;
232         if (GTK_WIDGET_REALIZED (widget)) {
233                 /* Resize GdkWindow */
234                 gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
235         }
238 static gint
239 sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event)
241         SPColorSlider *slider;
243         slider = SP_COLOR_SLIDER (widget);
245         if (GTK_WIDGET_DRAWABLE (widget)) {
246                 gint width, height;
247                 width = widget->allocation.width;
248                 height = widget->allocation.height;
249                 sp_color_slider_paint (slider, &event->area);
250         }
252         return FALSE;
255 static gint
256 sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event)
258         SPColorSlider *slider;
260         slider = SP_COLOR_SLIDER (widget);
262         if (event->button == 1) {
263                 gint cx, cw;
264                 cx = widget->style->xthickness;
265                 cw = widget->allocation.width - 2 * cx;
266                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[GRABBED]);
267                 slider->dragging = TRUE;
268                 slider->oldvalue = slider->value;
269                 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
270                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
271                 gdk_pointer_grab (widget->window, FALSE,
272                                   (GdkEventMask)(GDK_POINTER_MOTION_MASK |
273                                   GDK_BUTTON_RELEASE_MASK),
274                                   NULL, NULL, event->time);
275         }
277         return FALSE;
280 static gint
281 sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event)
283         SPColorSlider *slider;
285         slider = SP_COLOR_SLIDER (widget);
287         if (event->button == 1) {
288                 gdk_pointer_ungrab (event->time);
289                 slider->dragging = FALSE;
290                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[RELEASED]);
291                 if (slider->value != slider->oldvalue) gtk_signal_emit (GTK_OBJECT (slider), slider_signals[CHANGED]);
292         }
294         return FALSE;
297 static gint
298 sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event)
300         SPColorSlider *slider;
302         slider = SP_COLOR_SLIDER (widget);
304         if (slider->dragging) {
305                 gint cx, cw;
306                 cx = widget->style->xthickness;
307                 cw = widget->allocation.width - 2 * cx;
308                 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
309                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
310         }
312         return FALSE;
315 GtkWidget *
316 sp_color_slider_new (GtkAdjustment *adjustment)
318         SPColorSlider *slider;
320         slider = (SPColorSlider*)gtk_type_new (SP_TYPE_COLOR_SLIDER);
322         sp_color_slider_set_adjustment (slider, adjustment);
324         return GTK_WIDGET (slider);
327 void
328 sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment)
330         g_return_if_fail (slider != NULL);
331         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
333         if (!adjustment) {
334                 adjustment = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.0, 0.0);
335         }
336 #if GTK_CHECK_VERSION (2,14,0)
337     else {
338         gtk_adjustment_set_page_increment(adjustment, 0.0);
339         gtk_adjustment_set_page_size(adjustment, 0.0);
340     }
341 #endif
343         if (slider->adjustment != adjustment) {
344                 if (slider->adjustment) {
345                         gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
346                         gtk_object_unref (GTK_OBJECT (slider->adjustment));
347                 }
349                 slider->adjustment = adjustment;
350                 gtk_object_ref (GTK_OBJECT (adjustment));
351                 gtk_object_sink (GTK_OBJECT (adjustment));
353                 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
354                                     GTK_SIGNAL_FUNC (sp_color_slider_adjustment_changed), slider);
355                 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
356                                     GTK_SIGNAL_FUNC (sp_color_slider_adjustment_value_changed), slider);
358                 slider->value = ColorScales::getScaled( adjustment );
360                 sp_color_slider_adjustment_changed (adjustment, slider);
361         }
364 void
365 sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end)
367         g_return_if_fail (slider != NULL);
368         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
370         // Remove any map, if set
371         slider->map = 0;
373         slider->c0[0] = start >> 24;
374         slider->c0[1] = (start >> 16) & 0xff;
375         slider->c0[2] = (start >> 8) & 0xff;
376         slider->c0[3] = start & 0xff;
378         slider->cm[0] = mid >> 24;
379         slider->cm[1] = (mid >> 16) & 0xff;
380         slider->cm[2] = (mid >> 8) & 0xff;
381         slider->cm[3] = mid & 0xff;
383         slider->c1[0] = end >> 24;
384         slider->c1[1] = (end >> 16) & 0xff;
385         slider->c1[2] = (end >> 8) & 0xff;
386         slider->c1[3] = end & 0xff;
388         gtk_widget_queue_draw (GTK_WIDGET (slider));
391 void
392 sp_color_slider_set_map (SPColorSlider *slider, const guchar *map)
394         g_return_if_fail (slider != NULL);
395         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
397         slider->map = (guchar *) map;
399         gtk_widget_queue_draw (GTK_WIDGET (slider));
402 void
403 sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size)
405         g_return_if_fail (slider != NULL);
406         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
408         slider->b0 = dark;
409         slider->b1 = light;
410         slider->bmask = size;
412         gtk_widget_queue_draw (GTK_WIDGET (slider));
415 static void
416 sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider)
418         gtk_widget_queue_draw (GTK_WIDGET (slider));
421 static void
422 sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
424         GtkWidget *widget;
426         widget = GTK_WIDGET (slider);
428         if (slider->value != ColorScales::getScaled( adjustment )) {
429                 gint cx, cy, cw, ch;
430                 cx = widget->style->xthickness;
431                 cy = widget->style->ythickness;
432                 cw = widget->allocation.width - 2 * cx;
433                 ch = widget->allocation.height - 2 * cy;
434                 if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) {
435                         gint ax, ay;
436                         gfloat value;
437                         value = slider->value;
438                         slider->value = ColorScales::getScaled( adjustment );
439                         ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2);
440                         ay = cy;
441                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
442                         ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2);
443                         ay = cy;
444                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
445                 } else {
446                         slider->value = ColorScales::getScaled( adjustment );
447                 }
448         }
451 static void
452 sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area)
454         GtkWidget *widget;
455         GdkRectangle warea, carea, aarea;
456         GdkRectangle wpaint, cpaint, apaint;
457         const guchar *b;
458         gint w, x, y1, y2;
460         widget = GTK_WIDGET (slider);
462         /* Widget area */
463         warea.x = 0;
464         warea.y = 0;
465         warea.width = widget->allocation.width;
466         warea.height = widget->allocation.height;
468         /* Color gradient area */
469         carea.x = widget->style->xthickness;
470         carea.y = widget->style->ythickness;
471         carea.width = widget->allocation.width - 2 * carea.x;
472         carea.height = widget->allocation.height - 2 * carea.y;
474         /* Arrow area */
475         aarea.x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x);
476         aarea.width = ARROW_SIZE;
477         aarea.y = carea.y;
478         aarea.height = carea.height;
480         /* Actual paintable area */
481         if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return;
483         b = NULL;
485         /* Paintable part of color gradient area */
486         if (gdk_rectangle_intersect (area, &carea, &cpaint)) {
487                 if (slider->map) {
488                         gint s, d;
489                         /* Render map pixelstore */
490                         d = (1024 << 16) / carea.width;
491                         s = (cpaint.x - carea.x) * d;
492                         b = sp_color_slider_render_map (cpaint.x - carea.x, cpaint.y - carea.y, cpaint.width, cpaint.height,
493                                                                                                                                                         slider->map, s, d,
494                                                                                                                                                         slider->b0, slider->b1, slider->bmask);
495                         if (b != NULL) {
496                                 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
497                                                                                                                 cpaint.x, cpaint.y,
498                                                                                                                 cpaint.width, cpaint.height,
499                                                                                                                 GDK_RGB_DITHER_MAX,
500                                                                                                                 (guchar *) b, cpaint.width * 3);
501                         }
503                 } else {
504                         gint c[4], dc[4];
505                         gint i;
506                         /* Render gradient */
508                         // part 1: from c0 to cm
509                         if ((cpaint.x - carea.x) <= carea.width/2) {
510                                 for (i = 0; i < 4; i++) {
511                                         c[i] = slider->c0[i] << 16;
512                                         dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2);
513                                         c[i] += (cpaint.x - carea.x) * dc[i];
514                                 }
515                                 guint wi = MIN(cpaint.x - carea.x + cpaint.width, carea.width/2) - (cpaint.x - carea.x);
516                                 b = sp_color_slider_render_gradient (cpaint.x - carea.x, cpaint.y - carea.y, wi, cpaint.height,
517                                                                                                          c, dc,
518                                                                                                          slider->b0, slider->b1, slider->bmask);
520                                 /* Draw pixelstore */
521                                 if (b != NULL) {
522                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
523                                                                                                                         cpaint.x, cpaint.y,
524                                                                                                                         wi, cpaint.height,
525                                                                                                                         GDK_RGB_DITHER_MAX,
526                                                                                                                         (guchar *) b, wi * 3);
527                                 }
528                         }
530                         // part 2: from cm to c1
531                         if ((cpaint.x - carea.x + cpaint.width) > carea.width/2) {
532                                 for (i = 0; i < 4; i++) {
533                                         c[i] = slider->cm[i] << 16;
534                                         dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2);
535                                         if ((cpaint.x - carea.x) > carea.width/2)
536                                                 c[i] += (cpaint.x - carea.x - carea.width/2) * dc[i];
537                                 }
538                                 guint wi = cpaint.width - MAX(0, (carea.width/2 - (cpaint.x - carea.x)));
539                                 b = sp_color_slider_render_gradient (MAX(cpaint.x - carea.x, carea.width/2), cpaint.y - carea.y, wi, cpaint.height,
540                                                                                                  c, dc,
541                                                                                                  slider->b0, slider->b1, slider->bmask);
543                                 /* Draw pixelstore */
544                                 if (b != NULL) {
545                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
546                                                                                                                         MAX(cpaint.x, carea.width/2 + carea.x), cpaint.y,
547                                                                                                                         wi, cpaint.height,
548                                                                                                                         GDK_RGB_DITHER_MAX,
549                                                                                                                         (guchar *) b, wi * 3);
550                                 }
551                         }
552                 }
553         }
555         /* Draw shadow */
556         gtk_paint_shadow (widget->style, widget->window,
557                           (GtkStateType)widget->state, GTK_SHADOW_IN,
558                           area, widget, "colorslider",
559                           0, 0,
560                           warea.width, warea.height);
563         if (gdk_rectangle_intersect (area, &aarea, &apaint)) {
564                 /* Draw arrow */
565                 gdk_rectangle_intersect (&carea, &apaint, &apaint);
566                 gdk_gc_set_clip_rectangle (widget->style->white_gc, &apaint);
567                 gdk_gc_set_clip_rectangle (widget->style->black_gc, &apaint);
569                 x = aarea.x;
570                 y1 = carea.y;
571                 y2 = aarea.y + aarea.height - 1;
572                 w = aarea.width;
573                 while ( w > 0 )
574                 {
575                         gdk_draw_line (widget->window, widget->style->white_gc, x, y1, x + w - 1, y1 );
576                         gdk_draw_line (widget->window, widget->style->white_gc, x, y2, x + w - 1, y2 );
577                         w -=2;
578                         x++;
579                         if ( w > 0 )
580                         {
581                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y1, x + w - 1, y1 );
582                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y2, x + w - 1, y2 );
583                         }
584                         y1++;
585                         y2--;
586                 }
588                 gdk_gc_set_clip_rectangle (widget->style->white_gc, NULL);
589                 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
590         }
593 /* Colors are << 16 */
595 static const guchar *
596 sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
597                                  gint c[], gint dc[], guint b0, guint b1, guint mask)
599         static guchar *buf = NULL;
600         static gint bs = 0;
601         guchar *dp;
602         gint x, y;
603         guint r, g, b, a;
605         if (buf && (bs < width * height)) {
606                 g_free (buf);
607                 buf = NULL;
608         }
609         if (!buf) {
610                 buf = g_new (guchar, width * height * 3);
611                 bs = width * height;
612         }
614         dp = buf;
615         r = c[0];
616         g = c[1];
617         b = c[2];
618         a = c[3];
619         for (x = x0; x < x0 + width; x++) {
620                 gint cr, cg, cb, ca;
621                 guchar *d;
622                 cr = r >> 16;
623                 cg = g >> 16;
624                 cb = b >> 16;
625                 ca = a >> 16;
626                 d = dp;
627                 for (y = y0; y < y0 + height; y++) {
628                         guint bg, fc;
629                         /* Background value */
630                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
631                         fc = (cr - bg) * ca;
632                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
633                         fc = (cg - bg) * ca;
634                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
635                         fc = (cb - bg) * ca;
636                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
637                         d += 3 * width;
638                 }
639                 r += dc[0];
640                 g += dc[1];
641                 b += dc[2];
642                 a += dc[3];
643                 dp += 3;
644         }
646         return buf;
649 /* Positions are << 16 */
651 static const guchar *
652 sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
653                             guchar *map, gint start, gint step, guint b0, guint b1, guint mask)
655         static guchar *buf = NULL;
656         static gint bs = 0;
657         guchar *dp, *sp;
658         gint x, y;
660         if (buf && (bs < width * height)) {
661                 g_free (buf);
662                 buf = NULL;
663         }
664         if (!buf) {
665                 buf = g_new (guchar, width * height * 3);
666                 bs = width * height;
667         }
669         dp = buf;
670         for (x = x0; x < x0 + width; x++) {
671                 gint cr, cg, cb, ca;
672                 guchar *d;
673                 sp = map + 4 * (start >> 16);
674                 cr = *sp++;
675                 cg = *sp++;
676                 cb = *sp++;
677                 ca = *sp++;
678                 d = dp;
679                 for (y = y0; y < y0 + height; y++) {
680                         guint bg, fc;
681                         /* Background value */
682                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
683                         fc = (cr - bg) * ca;
684                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
685                         fc = (cg - bg) * ca;
686                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
687                         fc = (cb - bg) * ca;
688                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
689                         d += 3 * width;
690                 }
691                 dp += 3;
692                 start += step;
693         }
695         return buf;