Code

Store a global list of existing perspectives; for each perspective hold a list of...
[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         slider->c0[0] = start >> 24;
364         slider->c0[1] = (start >> 16) & 0xff;
365         slider->c0[2] = (start >> 8) & 0xff;
366         slider->c0[3] = start & 0xff;
368         slider->cm[0] = mid >> 24;
369         slider->cm[1] = (mid >> 16) & 0xff;
370         slider->cm[2] = (mid >> 8) & 0xff;
371         slider->cm[3] = mid & 0xff;
373         slider->c1[0] = end >> 24;
374         slider->c1[1] = (end >> 16) & 0xff;
375         slider->c1[2] = (end >> 8) & 0xff;
376         slider->c1[3] = end & 0xff;
378         gtk_widget_queue_draw (GTK_WIDGET (slider));
381 void
382 sp_color_slider_set_map (SPColorSlider *slider, const guchar *map)
384         g_return_if_fail (slider != NULL);
385         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
387         slider->map = (guchar *) map;
389         gtk_widget_queue_draw (GTK_WIDGET (slider));
392 void
393 sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size)
395         g_return_if_fail (slider != NULL);
396         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
398         slider->b0 = dark;
399         slider->b1 = light;
400         slider->bmask = size;
402         gtk_widget_queue_draw (GTK_WIDGET (slider));
405 static void
406 sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
408         gtk_widget_queue_draw (GTK_WIDGET (slider));
411 static void
412 sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
414         GtkWidget *widget;
416         widget = GTK_WIDGET (slider);
418         if (slider->value != ColorScales::getScaled( adjustment )) {
419                 gint cx, cy, cw, ch;
420                 cx = widget->style->xthickness;
421                 cy = widget->style->ythickness;
422                 cw = widget->allocation.width - 2 * cx;
423                 ch = widget->allocation.height - 2 * cy;
424                 if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) {
425                         gint ax, ay;
426                         gfloat value;
427                         value = slider->value;
428                         slider->value = ColorScales::getScaled( adjustment );
429                         ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2);
430                         ay = cy;
431                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
432                         ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2);
433                         ay = cy;
434                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
435                 } else {
436                         slider->value = ColorScales::getScaled( adjustment );
437                 }
438         }
441 static void
442 sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area)
444         GtkWidget *widget;
445         GdkRectangle warea, carea, aarea;
446         GdkRectangle wpaint, cpaint, apaint;
447         const guchar *b;
448         gint w, x, y1, y2;
450         widget = GTK_WIDGET (slider);
452         /* Widget area */
453         warea.x = 0;
454         warea.y = 0;
455         warea.width = widget->allocation.width;
456         warea.height = widget->allocation.height;
458         /* Color gradient area */
459         carea.x = widget->style->xthickness;
460         carea.y = widget->style->ythickness;
461         carea.width = widget->allocation.width - 2 * carea.x;
462         carea.height = widget->allocation.height - 2 * carea.y;
464         /* Arrow area */
465         aarea.x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x);
466         aarea.width = ARROW_SIZE;
467         aarea.y = carea.y;
468         aarea.height = carea.height;
470         /* Actual paintable area */
471         if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return;
473         b = NULL;
475         /* Paintable part of color gradient area */
476         if (gdk_rectangle_intersect (area, &carea, &cpaint)) {
477                 if (slider->map) {
478                         gint s, d;
479                         /* Render map pixelstore */
480                         d = (1024 << 16) / carea.width;
481                         s = (cpaint.x - carea.x) * d;
482                         b = sp_color_slider_render_map (cpaint.x - carea.x, cpaint.y - carea.y, cpaint.width, cpaint.height,
483                                                                                                                                                         slider->map, s, d,
484                                                                                                                                                         slider->b0, slider->b1, slider->bmask);
485                         if (b != NULL) {
486                                 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
487                                                                                                                 cpaint.x, cpaint.y,
488                                                                                                                 cpaint.width, cpaint.height,
489                                                                                                                 GDK_RGB_DITHER_MAX,
490                                                                                                                 (guchar *) b, cpaint.width * 3);
491                         }
493                 } else {
494                         gint c[4], dc[4];
495                         gint i;
496                         /* Render gradient */
498                         // part 1: from c0 to cm
499                         if ((cpaint.x - carea.x) <= carea.width/2) {
500                                 for (i = 0; i < 4; i++) {
501                                         c[i] = slider->c0[i] << 16;
502                                         dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2);
503                                         c[i] += (cpaint.x - carea.x) * dc[i];
504                                 }
505                                 guint wi = MIN(cpaint.x - carea.x + cpaint.width, carea.width/2) - (cpaint.x - carea.x);
506                                 b = sp_color_slider_render_gradient (cpaint.x - carea.x, cpaint.y - carea.y, wi, cpaint.height,
507                                                                                                          c, dc,
508                                                                                                          slider->b0, slider->b1, slider->bmask);
510                                 /* Draw pixelstore */
511                                 if (b != NULL) {
512                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
513                                                                                                                         cpaint.x, cpaint.y,
514                                                                                                                         wi, cpaint.height,
515                                                                                                                         GDK_RGB_DITHER_MAX,
516                                                                                                                         (guchar *) b, wi * 3);
517                                 }
518                         }
520                         // part 2: from cm to c1
521                         if ((cpaint.x - carea.x + cpaint.width) > carea.width/2) {
522                                 for (i = 0; i < 4; i++) {
523                                         c[i] = slider->cm[i] << 16;
524                                         dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2);
525                                         if ((cpaint.x - carea.x) > carea.width/2)
526                                                 c[i] += (cpaint.x - carea.x - carea.width/2) * dc[i];
527                                 }
528                                 guint wi = cpaint.width - MAX(0, (carea.width/2 - (cpaint.x - carea.x)));
529                                 b = sp_color_slider_render_gradient (MAX(cpaint.x - carea.x, carea.width/2), cpaint.y - carea.y, wi, cpaint.height,
530                                                                                                  c, dc,
531                                                                                                  slider->b0, slider->b1, slider->bmask);
533                                 /* Draw pixelstore */
534                                 if (b != NULL) {
535                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
536                                                                                                                         MAX(cpaint.x, carea.width/2 + carea.x), cpaint.y,
537                                                                                                                         wi, cpaint.height,
538                                                                                                                         GDK_RGB_DITHER_MAX,
539                                                                                                                         (guchar *) b, wi * 3);
540                                 }
541                         }
542                 }
543         }
545         /* Draw shadow */
546         gtk_paint_shadow (widget->style, widget->window,
547                           (GtkStateType)widget->state, GTK_SHADOW_IN,
548                           area, widget, "colorslider",
549                           0, 0,
550                           warea.width, warea.height);
553         if (gdk_rectangle_intersect (area, &aarea, &apaint)) {
554                 /* Draw arrow */
555                 gdk_rectangle_intersect (&carea, &apaint, &apaint);
556                 gdk_gc_set_clip_rectangle (widget->style->white_gc, &apaint);
557                 gdk_gc_set_clip_rectangle (widget->style->black_gc, &apaint);
559                 x = aarea.x;
560                 y1 = carea.y;
561                 y2 = aarea.y + aarea.height - 1;
562                 w = aarea.width;
563                 while ( w > 0 )
564                 {
565                         gdk_draw_line (widget->window, widget->style->white_gc, x, y1, x + w - 1, y1 );
566                         gdk_draw_line (widget->window, widget->style->white_gc, x, y2, x + w - 1, y2 );
567                         w -=2;
568                         x++;
569                         if ( w > 0 )
570                         {
571                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y1, x + w - 1, y1 );
572                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y2, x + w - 1, y2 );
573                         }
574                         y1++;
575                         y2--;
576                 }
578                 gdk_gc_set_clip_rectangle (widget->style->white_gc, NULL);
579                 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
580         }
583 /* Colors are << 16 */
585 static const guchar *
586 sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
587                                  gint c[], gint dc[], guint b0, guint b1, guint mask)
589         static guchar *buf = NULL;
590         static gint bs = 0;
591         guchar *dp;
592         gint x, y;
593         guint r, g, b, a;
595         if (buf && (bs < width * height)) {
596                 g_free (buf);
597                 buf = NULL;
598         }
599         if (!buf) {
600                 buf = g_new (guchar, width * height * 3);
601                 bs = width * height;
602         }
604         dp = buf;
605         r = c[0];
606         g = c[1];
607         b = c[2];
608         a = c[3];
609         for (x = x0; x < x0 + width; x++) {
610                 gint cr, cg, cb, ca;
611                 guchar *d;
612                 cr = r >> 16;
613                 cg = g >> 16;
614                 cb = b >> 16;
615                 ca = a >> 16;
616                 d = dp;
617                 for (y = y0; y < y0 + height; y++) {
618                         guint bg, fc;
619                         /* Background value */
620                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
621                         fc = (cr - bg) * ca;
622                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
623                         fc = (cg - bg) * ca;
624                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
625                         fc = (cb - bg) * ca;
626                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
627                         d += 3 * width;
628                 }
629                 r += dc[0];
630                 g += dc[1];
631                 b += dc[2];
632                 a += dc[3];
633                 dp += 3;
634         }
636         return buf;
639 /* Positions are << 16 */
641 static const guchar *
642 sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
643                             guchar *map, gint start, gint step, guint b0, guint b1, guint mask)
645         static guchar *buf = NULL;
646         static gint bs = 0;
647         guchar *dp, *sp;
648         gint x, y;
650         if (buf && (bs < width * height)) {
651                 g_free (buf);
652                 buf = NULL;
653         }
654         if (!buf) {
655                 buf = g_new (guchar, width * height * 3);
656                 bs = width * height;
657         }
659         dp = buf;
660         for (x = x0; x < x0 + width; x++) {
661                 gint cr, cg, cb, ca;
662                 guchar *d;
663                 sp = map + 4 * (start >> 16);
664                 cr = *sp++;
665                 cg = *sp++;
666                 cb = *sp++;
667                 ca = *sp++;
668                 d = dp;
669                 for (y = y0; y < y0 + height; y++) {
670                         guint bg, fc;
671                         /* Background value */
672                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
673                         fc = (cr - bg) * ca;
674                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
675                         fc = (cg - bg) * ca;
676                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
677                         fc = (cb - bg) * ca;
678                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
679                         d += 3 * width;
680                 }
681                 dp += 3;
682                 start += step;
683         }
685         return buf;