Code

Don't force focus on the canvas when the desktop is given
[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/gtksignal.h>
16 #include "sp-color-scales.h"
18 #define SLIDER_WIDTH 96
19 #define SLIDER_HEIGHT 8
20 #define ARROW_SIZE 7
22 enum {
23         GRABBED,
24         DRAGGED,
25         RELEASED,
26         CHANGED,
27         LAST_SIGNAL
28 };
30 static void sp_color_slider_class_init (SPColorSliderClass *klass);
31 static void sp_color_slider_init (SPColorSlider *slider);
32 static void sp_color_slider_destroy (GtkObject *object);
34 static void sp_color_slider_realize (GtkWidget *widget);
35 static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition);
36 static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
37 /*  static void sp_color_slider_draw (GtkWidget *widget, GdkRectangle *area); */
38 /*  static void sp_color_slider_draw_focus (GtkWidget *widget); */
39 /*  static void sp_color_slider_draw_default (GtkWidget *widget); */
41 static gint sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event);
42 static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event);
43 static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event);
44 static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event);
46 static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider);
47 static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider);
49 static void sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area);
50 static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
51                                                       gint c[], gint dc[], guint b0, guint b1, guint mask);
52 static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
53                                                  guchar *map, gint start, gint step, guint b0, guint b1, guint mask);
55 static GtkWidgetClass *parent_class;
56 static guint slider_signals[LAST_SIGNAL] = {0};
58 GtkType
59 sp_color_slider_get_type (void)
60 {
61         static GtkType type = 0;
62         if (!type) {
63                 GtkTypeInfo info = {
64                         "SPColorSlider",
65                         sizeof (SPColorSlider),
66                         sizeof (SPColorSliderClass),
67                         (GtkClassInitFunc) sp_color_slider_class_init,
68                         (GtkObjectInitFunc) sp_color_slider_init,
69                         NULL, NULL, NULL
70                 };
71                 type = gtk_type_unique (GTK_TYPE_WIDGET, &info);
72         }
73         return type;
74 }
76 static void
77 sp_color_slider_class_init (SPColorSliderClass *klass)
78 {
79         GtkObjectClass *object_class;
80         GtkWidgetClass *widget_class;
82         object_class = (GtkObjectClass *) klass;
83         widget_class = (GtkWidgetClass *) klass;
85         parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET);
87         slider_signals[GRABBED] = gtk_signal_new ("grabbed",
88                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
89                                                   GTK_CLASS_TYPE(object_class),
90                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, grabbed),
91                                                   gtk_marshal_NONE__NONE,
92                                                   GTK_TYPE_NONE, 0);
93         slider_signals[DRAGGED] = gtk_signal_new ("dragged",
94                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
95                                                   GTK_CLASS_TYPE(object_class),
96                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, dragged),
97                                                   gtk_marshal_NONE__NONE,
98                                                   GTK_TYPE_NONE, 0);
99         slider_signals[RELEASED] = gtk_signal_new ("released",
100                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
101                                                   GTK_CLASS_TYPE(object_class),
102                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, released),
103                                                   gtk_marshal_NONE__NONE,
104                                                   GTK_TYPE_NONE, 0);
105         slider_signals[CHANGED] = gtk_signal_new ("changed",
106                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
107                                                   GTK_CLASS_TYPE(object_class),
108                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, changed),
109                                                   gtk_marshal_NONE__NONE,
110                                                   GTK_TYPE_NONE, 0);
112         object_class->destroy = sp_color_slider_destroy;
114         widget_class->realize = sp_color_slider_realize;
115         widget_class->size_request = sp_color_slider_size_request;
116         widget_class->size_allocate = sp_color_slider_size_allocate;
117 /*      widget_class->draw = sp_color_slider_draw; */
118 /*      widget_class->draw_focus = sp_color_slider_draw_focus; */
119 /*      widget_class->draw_default = sp_color_slider_draw_default; */
121         widget_class->expose_event = sp_color_slider_expose;
122         widget_class->button_press_event = sp_color_slider_button_press;
123         widget_class->button_release_event = sp_color_slider_button_release;
124         widget_class->motion_notify_event = sp_color_slider_motion_notify;
127 static void
128 sp_color_slider_init (SPColorSlider *slider)
130         /* We are widget with window */
131         GTK_WIDGET_UNSET_FLAGS (slider, GTK_NO_WINDOW);
133         slider->dragging = FALSE;
135         slider->adjustment = NULL;
136         slider->value = 0.0;
138         slider->c0[0] = 0x00;
139         slider->c0[1] = 0x00;
140         slider->c0[2] = 0x00;
141         slider->c0[3] = 0xff;
143         slider->cm[0] = 0xff;
144         slider->cm[1] = 0x00;
145         slider->cm[2] = 0x00;
146         slider->cm[3] = 0xff;
148         slider->c1[0] = 0xff;
149         slider->c1[1] = 0xff;
150         slider->c1[2] = 0xff;
151         slider->c1[3] = 0xff;
153         slider->b0 = 0x5f;
154         slider->b1 = 0xa0;
155         slider->bmask = 0x08;
157         slider->map = NULL;
160 static void
161 sp_color_slider_destroy (GtkObject *object)
163         SPColorSlider *slider;
165         slider = SP_COLOR_SLIDER (object);
167         if (slider->adjustment) {
168                 gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
169                 gtk_object_unref (GTK_OBJECT (slider->adjustment));
170                 slider->adjustment = NULL;
171         }
173         if (((GtkObjectClass *) (parent_class))->destroy)
174                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
177 static void
178 sp_color_slider_realize (GtkWidget *widget)
180         SPColorSlider *slider;
181         GdkWindowAttr attributes;
182         gint attributes_mask;
184         slider = SP_COLOR_SLIDER (widget);
186         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
188         attributes.window_type = GDK_WINDOW_CHILD;
189         attributes.x = widget->allocation.x;
190         attributes.y = widget->allocation.y;
191         attributes.width = widget->allocation.width;
192         attributes.height = widget->allocation.height;
193         attributes.wclass = GDK_INPUT_OUTPUT;
194         attributes.visual = gdk_rgb_get_visual ();
195         attributes.colormap = gdk_rgb_get_cmap ();
196         attributes.event_mask = gtk_widget_get_events (widget);
197         attributes.event_mask |= (GDK_EXPOSURE_MASK |
198                                   GDK_BUTTON_PRESS_MASK |
199                                   GDK_BUTTON_RELEASE_MASK |
200                                   GDK_POINTER_MOTION_MASK |
201                                   GDK_ENTER_NOTIFY_MASK |
202                                   GDK_LEAVE_NOTIFY_MASK);
203         attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
205         widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
206         gdk_window_set_user_data (widget->window, widget);
208         widget->style = gtk_style_attach (widget->style, widget->window);
211 static void
212 sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition)
214         SPColorSlider *slider;
216         slider = SP_COLOR_SLIDER (widget);
218         requisition->width = SLIDER_WIDTH + widget->style->xthickness * 2;
219         requisition->height = SLIDER_HEIGHT + widget->style->ythickness * 2;
222 static void
223 sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
225         SPColorSlider *slider;
227         slider = SP_COLOR_SLIDER (widget);
229         widget->allocation = *allocation;
231         if (GTK_WIDGET_REALIZED (widget)) {
232                 /* Resize GdkWindow */
233                 gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
234         }
237 static gint
238 sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event)
240         SPColorSlider *slider;
242         slider = SP_COLOR_SLIDER (widget);
244         if (GTK_WIDGET_DRAWABLE (widget)) {
245                 gint width, height;
246                 width = widget->allocation.width;
247                 height = widget->allocation.height;
248                 sp_color_slider_paint (slider, &event->area);
249         }
251         return FALSE;
254 static gint
255 sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event)
257         SPColorSlider *slider;
259         slider = SP_COLOR_SLIDER (widget);
261         if (event->button == 1) {
262                 gint cx, cw;
263                 cx = widget->style->xthickness;
264                 cw = widget->allocation.width - 2 * cx;
265                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[GRABBED]);
266                 slider->dragging = TRUE;
267                 slider->oldvalue = slider->value;
268                 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
269                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
270                 gdk_pointer_grab (widget->window, FALSE,
271                                   (GdkEventMask)(GDK_POINTER_MOTION_MASK |
272                                   GDK_BUTTON_RELEASE_MASK),
273                                   NULL, NULL, event->time);
274         }
276         return FALSE;
279 static gint
280 sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event)
282         SPColorSlider *slider;
284         slider = SP_COLOR_SLIDER (widget);
286         if (event->button == 1) {
287                 gdk_pointer_ungrab (event->time);
288                 slider->dragging = FALSE;
289                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[RELEASED]);
290                 if (slider->value != slider->oldvalue) gtk_signal_emit (GTK_OBJECT (slider), slider_signals[CHANGED]);
291         }
293         return FALSE;
296 static gint
297 sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event)
299         SPColorSlider *slider;
301         slider = SP_COLOR_SLIDER (widget);
303         if (slider->dragging) {
304                 gint cx, cw;
305                 cx = widget->style->xthickness;
306                 cw = widget->allocation.width - 2 * cx;
307                 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
308                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
309         }
311         return FALSE;
314 GtkWidget *
315 sp_color_slider_new (GtkAdjustment *adjustment)
317         SPColorSlider *slider;
319         slider = (SPColorSlider*)gtk_type_new (SP_TYPE_COLOR_SLIDER);
321         sp_color_slider_set_adjustment (slider, adjustment);
323         return GTK_WIDGET (slider);
326 void
327 sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment)
329         g_return_if_fail (slider != NULL);
330         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
332         if (!adjustment) {
333                 adjustment = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.1, 0.1);
334         }
336         if (slider->adjustment != adjustment) {
337                 if (slider->adjustment) {
338                         gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
339                         gtk_object_unref (GTK_OBJECT (slider->adjustment));
340                 }
342                 slider->adjustment = adjustment;
343                 gtk_object_ref (GTK_OBJECT (adjustment));
344                 gtk_object_sink (GTK_OBJECT (adjustment));
346                 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
347                                     GTK_SIGNAL_FUNC (sp_color_slider_adjustment_changed), slider);
348                 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
349                                     GTK_SIGNAL_FUNC (sp_color_slider_adjustment_value_changed), slider);
351                 slider->value = ColorScales::getScaled( adjustment );
353                 sp_color_slider_adjustment_changed (adjustment, slider);
354         }
357 void
358 sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end)
360         g_return_if_fail (slider != NULL);
361         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
363         // Remove any map, if set
364         slider->map = 0;
366         slider->c0[0] = start >> 24;
367         slider->c0[1] = (start >> 16) & 0xff;
368         slider->c0[2] = (start >> 8) & 0xff;
369         slider->c0[3] = start & 0xff;
371         slider->cm[0] = mid >> 24;
372         slider->cm[1] = (mid >> 16) & 0xff;
373         slider->cm[2] = (mid >> 8) & 0xff;
374         slider->cm[3] = mid & 0xff;
376         slider->c1[0] = end >> 24;
377         slider->c1[1] = (end >> 16) & 0xff;
378         slider->c1[2] = (end >> 8) & 0xff;
379         slider->c1[3] = end & 0xff;
381         gtk_widget_queue_draw (GTK_WIDGET (slider));
384 void
385 sp_color_slider_set_map (SPColorSlider *slider, const guchar *map)
387         g_return_if_fail (slider != NULL);
388         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
390         slider->map = (guchar *) map;
392         gtk_widget_queue_draw (GTK_WIDGET (slider));
395 void
396 sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size)
398         g_return_if_fail (slider != NULL);
399         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
401         slider->b0 = dark;
402         slider->b1 = light;
403         slider->bmask = size;
405         gtk_widget_queue_draw (GTK_WIDGET (slider));
408 static void
409 sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider)
411         gtk_widget_queue_draw (GTK_WIDGET (slider));
414 static void
415 sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
417         GtkWidget *widget;
419         widget = GTK_WIDGET (slider);
421         if (slider->value != ColorScales::getScaled( adjustment )) {
422                 gint cx, cy, cw, ch;
423                 cx = widget->style->xthickness;
424                 cy = widget->style->ythickness;
425                 cw = widget->allocation.width - 2 * cx;
426                 ch = widget->allocation.height - 2 * cy;
427                 if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) {
428                         gint ax, ay;
429                         gfloat value;
430                         value = slider->value;
431                         slider->value = ColorScales::getScaled( adjustment );
432                         ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2);
433                         ay = cy;
434                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
435                         ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2);
436                         ay = cy;
437                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
438                 } else {
439                         slider->value = ColorScales::getScaled( adjustment );
440                 }
441         }
444 static void
445 sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area)
447         GtkWidget *widget;
448         GdkRectangle warea, carea, aarea;
449         GdkRectangle wpaint, cpaint, apaint;
450         const guchar *b;
451         gint w, x, y1, y2;
453         widget = GTK_WIDGET (slider);
455         /* Widget area */
456         warea.x = 0;
457         warea.y = 0;
458         warea.width = widget->allocation.width;
459         warea.height = widget->allocation.height;
461         /* Color gradient area */
462         carea.x = widget->style->xthickness;
463         carea.y = widget->style->ythickness;
464         carea.width = widget->allocation.width - 2 * carea.x;
465         carea.height = widget->allocation.height - 2 * carea.y;
467         /* Arrow area */
468         aarea.x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x);
469         aarea.width = ARROW_SIZE;
470         aarea.y = carea.y;
471         aarea.height = carea.height;
473         /* Actual paintable area */
474         if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return;
476         b = NULL;
478         /* Paintable part of color gradient area */
479         if (gdk_rectangle_intersect (area, &carea, &cpaint)) {
480                 if (slider->map) {
481                         gint s, d;
482                         /* Render map pixelstore */
483                         d = (1024 << 16) / carea.width;
484                         s = (cpaint.x - carea.x) * d;
485                         b = sp_color_slider_render_map (cpaint.x - carea.x, cpaint.y - carea.y, cpaint.width, cpaint.height,
486                                                                                                                                                         slider->map, s, d,
487                                                                                                                                                         slider->b0, slider->b1, slider->bmask);
488                         if (b != NULL) {
489                                 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
490                                                                                                                 cpaint.x, cpaint.y,
491                                                                                                                 cpaint.width, cpaint.height,
492                                                                                                                 GDK_RGB_DITHER_MAX,
493                                                                                                                 (guchar *) b, cpaint.width * 3);
494                         }
496                 } else {
497                         gint c[4], dc[4];
498                         gint i;
499                         /* Render gradient */
501                         // part 1: from c0 to cm
502                         if ((cpaint.x - carea.x) <= carea.width/2) {
503                                 for (i = 0; i < 4; i++) {
504                                         c[i] = slider->c0[i] << 16;
505                                         dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2);
506                                         c[i] += (cpaint.x - carea.x) * dc[i];
507                                 }
508                                 guint wi = MIN(cpaint.x - carea.x + cpaint.width, carea.width/2) - (cpaint.x - carea.x);
509                                 b = sp_color_slider_render_gradient (cpaint.x - carea.x, cpaint.y - carea.y, wi, cpaint.height,
510                                                                                                          c, dc,
511                                                                                                          slider->b0, slider->b1, slider->bmask);
513                                 /* Draw pixelstore */
514                                 if (b != NULL) {
515                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
516                                                                                                                         cpaint.x, cpaint.y,
517                                                                                                                         wi, cpaint.height,
518                                                                                                                         GDK_RGB_DITHER_MAX,
519                                                                                                                         (guchar *) b, wi * 3);
520                                 }
521                         }
523                         // part 2: from cm to c1
524                         if ((cpaint.x - carea.x + cpaint.width) > carea.width/2) {
525                                 for (i = 0; i < 4; i++) {
526                                         c[i] = slider->cm[i] << 16;
527                                         dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2);
528                                         if ((cpaint.x - carea.x) > carea.width/2)
529                                                 c[i] += (cpaint.x - carea.x - carea.width/2) * dc[i];
530                                 }
531                                 guint wi = cpaint.width - MAX(0, (carea.width/2 - (cpaint.x - carea.x)));
532                                 b = sp_color_slider_render_gradient (MAX(cpaint.x - carea.x, carea.width/2), cpaint.y - carea.y, wi, cpaint.height,
533                                                                                                  c, dc,
534                                                                                                  slider->b0, slider->b1, slider->bmask);
536                                 /* Draw pixelstore */
537                                 if (b != NULL) {
538                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
539                                                                                                                         MAX(cpaint.x, carea.width/2 + carea.x), cpaint.y,
540                                                                                                                         wi, cpaint.height,
541                                                                                                                         GDK_RGB_DITHER_MAX,
542                                                                                                                         (guchar *) b, wi * 3);
543                                 }
544                         }
545                 }
546         }
548         /* Draw shadow */
549         gtk_paint_shadow (widget->style, widget->window,
550                           (GtkStateType)widget->state, GTK_SHADOW_IN,
551                           area, widget, "colorslider",
552                           0, 0,
553                           warea.width, warea.height);
556         if (gdk_rectangle_intersect (area, &aarea, &apaint)) {
557                 /* Draw arrow */
558                 gdk_rectangle_intersect (&carea, &apaint, &apaint);
559                 gdk_gc_set_clip_rectangle (widget->style->white_gc, &apaint);
560                 gdk_gc_set_clip_rectangle (widget->style->black_gc, &apaint);
562                 x = aarea.x;
563                 y1 = carea.y;
564                 y2 = aarea.y + aarea.height - 1;
565                 w = aarea.width;
566                 while ( w > 0 )
567                 {
568                         gdk_draw_line (widget->window, widget->style->white_gc, x, y1, x + w - 1, y1 );
569                         gdk_draw_line (widget->window, widget->style->white_gc, x, y2, x + w - 1, y2 );
570                         w -=2;
571                         x++;
572                         if ( w > 0 )
573                         {
574                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y1, x + w - 1, y1 );
575                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y2, x + w - 1, y2 );
576                         }
577                         y1++;
578                         y2--;
579                 }
581                 gdk_gc_set_clip_rectangle (widget->style->white_gc, NULL);
582                 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
583         }
586 /* Colors are << 16 */
588 static const guchar *
589 sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
590                                  gint c[], gint dc[], guint b0, guint b1, guint mask)
592         static guchar *buf = NULL;
593         static gint bs = 0;
594         guchar *dp;
595         gint x, y;
596         guint r, g, b, a;
598         if (buf && (bs < width * height)) {
599                 g_free (buf);
600                 buf = NULL;
601         }
602         if (!buf) {
603                 buf = g_new (guchar, width * height * 3);
604                 bs = width * height;
605         }
607         dp = buf;
608         r = c[0];
609         g = c[1];
610         b = c[2];
611         a = c[3];
612         for (x = x0; x < x0 + width; x++) {
613                 gint cr, cg, cb, ca;
614                 guchar *d;
615                 cr = r >> 16;
616                 cg = g >> 16;
617                 cb = b >> 16;
618                 ca = a >> 16;
619                 d = dp;
620                 for (y = y0; y < y0 + height; y++) {
621                         guint bg, fc;
622                         /* Background value */
623                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
624                         fc = (cr - bg) * ca;
625                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
626                         fc = (cg - bg) * ca;
627                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
628                         fc = (cb - bg) * ca;
629                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
630                         d += 3 * width;
631                 }
632                 r += dc[0];
633                 g += dc[1];
634                 b += dc[2];
635                 a += dc[3];
636                 dp += 3;
637         }
639         return buf;
642 /* Positions are << 16 */
644 static const guchar *
645 sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
646                             guchar *map, gint start, gint step, guint b0, guint b1, guint mask)
648         static guchar *buf = NULL;
649         static gint bs = 0;
650         guchar *dp, *sp;
651         gint x, y;
653         if (buf && (bs < width * height)) {
654                 g_free (buf);
655                 buf = NULL;
656         }
657         if (!buf) {
658                 buf = g_new (guchar, width * height * 3);
659                 bs = width * height;
660         }
662         dp = buf;
663         for (x = x0; x < x0 + width; x++) {
664                 gint cr, cg, cb, ca;
665                 guchar *d;
666                 sp = map + 4 * (start >> 16);
667                 cr = *sp++;
668                 cg = *sp++;
669                 cb = *sp++;
670                 ca = *sp++;
671                 d = dp;
672                 for (y = y0; y < y0 + height; y++) {
673                         guint bg, fc;
674                         /* Background value */
675                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
676                         fc = (cr - bg) * ca;
677                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
678                         fc = (cg - bg) * ca;
679                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
680                         fc = (cb - bg) * ca;
681                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
682                         d += 3 * width;
683                 }
684                 dp += 3;
685                 start += step;
686         }
688         return buf;