Code

fix pasting style after copying a text span
[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     //TODO: switch to GObject
63     // GtkType and such calls were deprecated a while back with the
64     // introduction of GObject as a separate layer, with GType instead. --JonCruz
66         static GtkType type = 0;
67         if (!type) {
68                 GtkTypeInfo info = {
69                         (gchar*) "SPColorSlider",
70                         sizeof (SPColorSlider),
71                         sizeof (SPColorSliderClass),
72                         (GtkClassInitFunc) sp_color_slider_class_init,
73                         (GtkObjectInitFunc) sp_color_slider_init,
74                         NULL, NULL, NULL
75                 };
76                 type = gtk_type_unique (GTK_TYPE_WIDGET, &info);
77         }
78         return type;
79 }
81 static void
82 sp_color_slider_class_init (SPColorSliderClass *klass)
83 {
84         GtkObjectClass *object_class;
85         GtkWidgetClass *widget_class;
87         object_class = (GtkObjectClass *) klass;
88         widget_class = (GtkWidgetClass *) klass;
90         parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET);
92         slider_signals[GRABBED] = gtk_signal_new ("grabbed",
93                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
94                                                   GTK_CLASS_TYPE(object_class),
95                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, grabbed),
96                                                   gtk_marshal_NONE__NONE,
97                                                   GTK_TYPE_NONE, 0);
98         slider_signals[DRAGGED] = gtk_signal_new ("dragged",
99                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
100                                                   GTK_CLASS_TYPE(object_class),
101                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, dragged),
102                                                   gtk_marshal_NONE__NONE,
103                                                   GTK_TYPE_NONE, 0);
104         slider_signals[RELEASED] = gtk_signal_new ("released",
105                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
106                                                   GTK_CLASS_TYPE(object_class),
107                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, released),
108                                                   gtk_marshal_NONE__NONE,
109                                                   GTK_TYPE_NONE, 0);
110         slider_signals[CHANGED] = gtk_signal_new ("changed",
111                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
112                                                   GTK_CLASS_TYPE(object_class),
113                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, changed),
114                                                   gtk_marshal_NONE__NONE,
115                                                   GTK_TYPE_NONE, 0);
117         object_class->destroy = sp_color_slider_destroy;
119         widget_class->realize = sp_color_slider_realize;
120         widget_class->size_request = sp_color_slider_size_request;
121         widget_class->size_allocate = sp_color_slider_size_allocate;
122 /*      widget_class->draw = sp_color_slider_draw; */
123 /*      widget_class->draw_focus = sp_color_slider_draw_focus; */
124 /*      widget_class->draw_default = sp_color_slider_draw_default; */
126         widget_class->expose_event = sp_color_slider_expose;
127         widget_class->button_press_event = sp_color_slider_button_press;
128         widget_class->button_release_event = sp_color_slider_button_release;
129         widget_class->motion_notify_event = sp_color_slider_motion_notify;
132 static void
133 sp_color_slider_init (SPColorSlider *slider)
135         /* We are widget with window */
136         GTK_WIDGET_UNSET_FLAGS (slider, GTK_NO_WINDOW);
138         slider->dragging = FALSE;
140         slider->adjustment = NULL;
141         slider->value = 0.0;
143         slider->c0[0] = 0x00;
144         slider->c0[1] = 0x00;
145         slider->c0[2] = 0x00;
146         slider->c0[3] = 0xff;
148         slider->cm[0] = 0xff;
149         slider->cm[1] = 0x00;
150         slider->cm[2] = 0x00;
151         slider->cm[3] = 0xff;
153         slider->c1[0] = 0xff;
154         slider->c1[1] = 0xff;
155         slider->c1[2] = 0xff;
156         slider->c1[3] = 0xff;
158         slider->b0 = 0x5f;
159         slider->b1 = 0xa0;
160         slider->bmask = 0x08;
162         slider->map = NULL;
165 static void
166 sp_color_slider_destroy (GtkObject *object)
168         SPColorSlider *slider;
170         slider = SP_COLOR_SLIDER (object);
172         if (slider->adjustment) {
173                 gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
174                 gtk_object_unref (GTK_OBJECT (slider->adjustment));
175                 slider->adjustment = NULL;
176         }
178         if (((GtkObjectClass *) (parent_class))->destroy)
179                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
182 static void
183 sp_color_slider_realize (GtkWidget *widget)
185         SPColorSlider *slider;
186         GdkWindowAttr attributes;
187         gint attributes_mask;
189         slider = SP_COLOR_SLIDER (widget);
191         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
193         attributes.window_type = GDK_WINDOW_CHILD;
194         attributes.x = widget->allocation.x;
195         attributes.y = widget->allocation.y;
196         attributes.width = widget->allocation.width;
197         attributes.height = widget->allocation.height;
198         attributes.wclass = GDK_INPUT_OUTPUT;
199         attributes.visual = gdk_rgb_get_visual ();
200         attributes.colormap = gdk_rgb_get_cmap ();
201         attributes.event_mask = gtk_widget_get_events (widget);
202         attributes.event_mask |= (GDK_EXPOSURE_MASK |
203                                   GDK_BUTTON_PRESS_MASK |
204                                   GDK_BUTTON_RELEASE_MASK |
205                                   GDK_POINTER_MOTION_MASK |
206                                   GDK_ENTER_NOTIFY_MASK |
207                                   GDK_LEAVE_NOTIFY_MASK);
208         attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
210         widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
211         gdk_window_set_user_data (widget->window, widget);
213         widget->style = gtk_style_attach (widget->style, widget->window);
216 static void
217 sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition)
219         SPColorSlider *slider;
221         slider = SP_COLOR_SLIDER (widget);
223         requisition->width = SLIDER_WIDTH + widget->style->xthickness * 2;
224         requisition->height = SLIDER_HEIGHT + widget->style->ythickness * 2;
227 static void
228 sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
230         SPColorSlider *slider;
232         slider = SP_COLOR_SLIDER (widget);
234         widget->allocation = *allocation;
236         if (GTK_WIDGET_REALIZED (widget)) {
237                 /* Resize GdkWindow */
238                 gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
239         }
242 static gint
243 sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event)
245         SPColorSlider *slider;
247         slider = SP_COLOR_SLIDER (widget);
249         if (GTK_WIDGET_DRAWABLE (widget)) {
250                 gint width, height;
251                 width = widget->allocation.width;
252                 height = widget->allocation.height;
253                 sp_color_slider_paint (slider, &event->area);
254         }
256         return FALSE;
259 static gint
260 sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event)
262         SPColorSlider *slider;
264         slider = SP_COLOR_SLIDER (widget);
266         if (event->button == 1) {
267                 gint cx, cw;
268                 cx = widget->style->xthickness;
269                 cw = widget->allocation.width - 2 * cx;
270                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[GRABBED]);
271                 slider->dragging = TRUE;
272                 slider->oldvalue = slider->value;
273                 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
274                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
275                 gdk_pointer_grab (widget->window, FALSE,
276                                   (GdkEventMask)(GDK_POINTER_MOTION_MASK |
277                                   GDK_BUTTON_RELEASE_MASK),
278                                   NULL, NULL, event->time);
279         }
281         return FALSE;
284 static gint
285 sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event)
287         SPColorSlider *slider;
289         slider = SP_COLOR_SLIDER (widget);
291         if (event->button == 1) {
292                 gdk_pointer_ungrab (event->time);
293                 slider->dragging = FALSE;
294                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[RELEASED]);
295                 if (slider->value != slider->oldvalue) gtk_signal_emit (GTK_OBJECT (slider), slider_signals[CHANGED]);
296         }
298         return FALSE;
301 static gint
302 sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event)
304         SPColorSlider *slider;
306         slider = SP_COLOR_SLIDER (widget);
308         if (slider->dragging) {
309                 gint cx, cw;
310                 cx = widget->style->xthickness;
311                 cw = widget->allocation.width - 2 * cx;
312                 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
313                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
314         }
316         return FALSE;
319 GtkWidget *
320 sp_color_slider_new (GtkAdjustment *adjustment)
322         SPColorSlider *slider;
324         slider = (SPColorSlider*)gtk_type_new (SP_TYPE_COLOR_SLIDER);
326         sp_color_slider_set_adjustment (slider, adjustment);
328         return GTK_WIDGET (slider);
331 void
332 sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment)
334         g_return_if_fail (slider != NULL);
335         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
337         if (!adjustment) {
338                 adjustment = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.0, 0.0);
339         }
340 #if GTK_CHECK_VERSION (2,14,0)
341     else {
342         gtk_adjustment_set_page_increment(adjustment, 0.0);
343         gtk_adjustment_set_page_size(adjustment, 0.0);
344     }
345 #endif
347         if (slider->adjustment != adjustment) {
348                 if (slider->adjustment) {
349                         gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
350                         gtk_object_unref (GTK_OBJECT (slider->adjustment));
351                 }
353                 slider->adjustment = adjustment;
354                 gtk_object_ref (GTK_OBJECT (adjustment));
355                 gtk_object_sink (GTK_OBJECT (adjustment));
357                 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
358                                     GTK_SIGNAL_FUNC (sp_color_slider_adjustment_changed), slider);
359                 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
360                                     GTK_SIGNAL_FUNC (sp_color_slider_adjustment_value_changed), slider);
362                 slider->value = ColorScales::getScaled( adjustment );
364                 sp_color_slider_adjustment_changed (adjustment, slider);
365         }
368 void
369 sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end)
371         g_return_if_fail (slider != NULL);
372         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
374         // Remove any map, if set
375         slider->map = 0;
377         slider->c0[0] = start >> 24;
378         slider->c0[1] = (start >> 16) & 0xff;
379         slider->c0[2] = (start >> 8) & 0xff;
380         slider->c0[3] = start & 0xff;
382         slider->cm[0] = mid >> 24;
383         slider->cm[1] = (mid >> 16) & 0xff;
384         slider->cm[2] = (mid >> 8) & 0xff;
385         slider->cm[3] = mid & 0xff;
387         slider->c1[0] = end >> 24;
388         slider->c1[1] = (end >> 16) & 0xff;
389         slider->c1[2] = (end >> 8) & 0xff;
390         slider->c1[3] = end & 0xff;
392         gtk_widget_queue_draw (GTK_WIDGET (slider));
395 void
396 sp_color_slider_set_map (SPColorSlider *slider, const guchar *map)
398         g_return_if_fail (slider != NULL);
399         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
401         slider->map = (guchar *) map;
403         gtk_widget_queue_draw (GTK_WIDGET (slider));
406 void
407 sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size)
409         g_return_if_fail (slider != NULL);
410         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
412         slider->b0 = dark;
413         slider->b1 = light;
414         slider->bmask = size;
416         gtk_widget_queue_draw (GTK_WIDGET (slider));
419 static void
420 sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider)
422         gtk_widget_queue_draw (GTK_WIDGET (slider));
425 static void
426 sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
428         GtkWidget *widget;
430         widget = GTK_WIDGET (slider);
432         if (slider->value != ColorScales::getScaled( adjustment )) {
433                 gint cx, cy, cw, ch;
434                 cx = widget->style->xthickness;
435                 cy = widget->style->ythickness;
436                 cw = widget->allocation.width - 2 * cx;
437                 ch = widget->allocation.height - 2 * cy;
438                 if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) {
439                         gint ax, ay;
440                         gfloat value;
441                         value = slider->value;
442                         slider->value = ColorScales::getScaled( adjustment );
443                         ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2);
444                         ay = cy;
445                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
446                         ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2);
447                         ay = cy;
448                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
449                 } else {
450                         slider->value = ColorScales::getScaled( adjustment );
451                 }
452         }
455 static void
456 sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area)
458         GtkWidget *widget;
459         GdkRectangle warea, carea, aarea;
460         GdkRectangle wpaint, cpaint, apaint;
461         const guchar *b;
462         gint w, x, y1, y2;
464         widget = GTK_WIDGET (slider);
466         /* Widget area */
467         warea.x = 0;
468         warea.y = 0;
469         warea.width = widget->allocation.width;
470         warea.height = widget->allocation.height;
472         /* Color gradient area */
473         carea.x = widget->style->xthickness;
474         carea.y = widget->style->ythickness;
475         carea.width = widget->allocation.width - 2 * carea.x;
476         carea.height = widget->allocation.height - 2 * carea.y;
478         /* Arrow area */
479         aarea.x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x);
480         aarea.width = ARROW_SIZE;
481         aarea.y = carea.y;
482         aarea.height = carea.height;
484         /* Actual paintable area */
485         if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return;
487         b = NULL;
489         /* Paintable part of color gradient area */
490         if (gdk_rectangle_intersect (area, &carea, &cpaint)) {
491                 if (slider->map) {
492                         gint s, d;
493                         /* Render map pixelstore */
494                         d = (1024 << 16) / carea.width;
495                         s = (cpaint.x - carea.x) * d;
496                         b = sp_color_slider_render_map (cpaint.x - carea.x, cpaint.y - carea.y, cpaint.width, cpaint.height,
497                                                                                                                                                         slider->map, s, d,
498                                                                                                                                                         slider->b0, slider->b1, slider->bmask);
499                         if (b != NULL) {
500                                 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
501                                                                                                                 cpaint.x, cpaint.y,
502                                                                                                                 cpaint.width, cpaint.height,
503                                                                                                                 GDK_RGB_DITHER_MAX,
504                                                                                                                 (guchar *) b, cpaint.width * 3);
505                         }
507                 } else {
508                         gint c[4], dc[4];
509                         gint i;
510                         /* Render gradient */
512                         // part 1: from c0 to cm
513                         if ((cpaint.x - carea.x) <= carea.width/2) {
514                                 for (i = 0; i < 4; i++) {
515                                         c[i] = slider->c0[i] << 16;
516                                         dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2);
517                                         c[i] += (cpaint.x - carea.x) * dc[i];
518                                 }
519                                 guint wi = MIN(cpaint.x - carea.x + cpaint.width, carea.width/2) - (cpaint.x - carea.x);
520                                 b = sp_color_slider_render_gradient (cpaint.x - carea.x, cpaint.y - carea.y, wi, cpaint.height,
521                                                                                                          c, dc,
522                                                                                                          slider->b0, slider->b1, slider->bmask);
524                                 /* Draw pixelstore */
525                                 if (b != NULL) {
526                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
527                                                                                                                         cpaint.x, cpaint.y,
528                                                                                                                         wi, cpaint.height,
529                                                                                                                         GDK_RGB_DITHER_MAX,
530                                                                                                                         (guchar *) b, wi * 3);
531                                 }
532                         }
534                         // part 2: from cm to c1
535                         if ((cpaint.x - carea.x + cpaint.width) > carea.width/2) {
536                                 for (i = 0; i < 4; i++) {
537                                         c[i] = slider->cm[i] << 16;
538                                         dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2);
539                                         if ((cpaint.x - carea.x) > carea.width/2)
540                                                 c[i] += (cpaint.x - carea.x - carea.width/2) * dc[i];
541                                 }
542                                 guint wi = cpaint.width - MAX(0, (carea.width/2 - (cpaint.x - carea.x)));
543                                 b = sp_color_slider_render_gradient (MAX(cpaint.x - carea.x, carea.width/2), cpaint.y - carea.y, wi, cpaint.height,
544                                                                                                  c, dc,
545                                                                                                  slider->b0, slider->b1, slider->bmask);
547                                 /* Draw pixelstore */
548                                 if (b != NULL) {
549                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
550                                                                                                                         MAX(cpaint.x, carea.width/2 + carea.x), cpaint.y,
551                                                                                                                         wi, cpaint.height,
552                                                                                                                         GDK_RGB_DITHER_MAX,
553                                                                                                                         (guchar *) b, wi * 3);
554                                 }
555                         }
556                 }
557         }
559         /* Draw shadow */
560         gtk_paint_shadow (widget->style, widget->window,
561                           (GtkStateType)widget->state, GTK_SHADOW_IN,
562                           area, widget, "colorslider",
563                           0, 0,
564                           warea.width, warea.height);
567         if (gdk_rectangle_intersect (area, &aarea, &apaint)) {
568                 /* Draw arrow */
569                 gdk_rectangle_intersect (&carea, &apaint, &apaint);
570                 gdk_gc_set_clip_rectangle (widget->style->white_gc, &apaint);
571                 gdk_gc_set_clip_rectangle (widget->style->black_gc, &apaint);
573                 x = aarea.x;
574                 y1 = carea.y;
575                 y2 = aarea.y + aarea.height - 1;
576                 w = aarea.width;
577                 while ( w > 0 )
578                 {
579                         gdk_draw_line (widget->window, widget->style->white_gc, x, y1, x + w - 1, y1 );
580                         gdk_draw_line (widget->window, widget->style->white_gc, x, y2, x + w - 1, y2 );
581                         w -=2;
582                         x++;
583                         if ( w > 0 )
584                         {
585                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y1, x + w - 1, y1 );
586                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y2, x + w - 1, y2 );
587                         }
588                         y1++;
589                         y2--;
590                 }
592                 gdk_gc_set_clip_rectangle (widget->style->white_gc, NULL);
593                 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
594         }
597 /* Colors are << 16 */
599 static const guchar *
600 sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
601                                  gint c[], gint dc[], guint b0, guint b1, guint mask)
603         static guchar *buf = NULL;
604         static gint bs = 0;
605         guchar *dp;
606         gint x, y;
607         guint r, g, b, a;
609         if (buf && (bs < width * height)) {
610                 g_free (buf);
611                 buf = NULL;
612         }
613         if (!buf) {
614                 buf = g_new (guchar, width * height * 3);
615                 bs = width * height;
616         }
618         dp = buf;
619         r = c[0];
620         g = c[1];
621         b = c[2];
622         a = c[3];
623         for (x = x0; x < x0 + width; x++) {
624                 gint cr, cg, cb, ca;
625                 guchar *d;
626                 cr = r >> 16;
627                 cg = g >> 16;
628                 cb = b >> 16;
629                 ca = a >> 16;
630                 d = dp;
631                 for (y = y0; y < y0 + height; y++) {
632                         guint bg, fc;
633                         /* Background value */
634                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
635                         fc = (cr - bg) * ca;
636                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
637                         fc = (cg - bg) * ca;
638                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
639                         fc = (cb - bg) * ca;
640                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
641                         d += 3 * width;
642                 }
643                 r += dc[0];
644                 g += dc[1];
645                 b += dc[2];
646                 a += dc[3];
647                 dp += 3;
648         }
650         return buf;
653 /* Positions are << 16 */
655 static const guchar *
656 sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
657                             guchar *map, gint start, gint step, guint b0, guint b1, guint mask)
659         static guchar *buf = NULL;
660         static gint bs = 0;
661         guchar *dp, *sp;
662         gint x, y;
664         if (buf && (bs < width * height)) {
665                 g_free (buf);
666                 buf = NULL;
667         }
668         if (!buf) {
669                 buf = g_new (guchar, width * height * 3);
670                 bs = width * height;
671         }
673         dp = buf;
674         for (x = x0; x < x0 + width; x++) {
675                 gint cr, cg, cb, ca;
676                 guchar *d;
677                 sp = map + 4 * (start >> 16);
678                 cr = *sp++;
679                 cg = *sp++;
680                 cb = *sp++;
681                 ca = *sp++;
682                 d = dp;
683                 for (y = y0; y < y0 + height; y++) {
684                         guint bg, fc;
685                         /* Background value */
686                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
687                         fc = (cr - bg) * ca;
688                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
689                         fc = (cg - bg) * ca;
690                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
691                         fc = (cb - bg) * ca;
692                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
693                         d += 3 * width;
694                 }
695                 dp += 3;
696                 start += step;
697         }
699         return buf;