Code

Use subdirectories with icon sizes.
[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"
18 #include "preferences.h"
20 #define SLIDER_WIDTH 96
21 #define SLIDER_HEIGHT 8
22 #define ARROW_SIZE 7
24 enum {
25         GRABBED,
26         DRAGGED,
27         RELEASED,
28         CHANGED,
29         LAST_SIGNAL
30 };
32 static void sp_color_slider_class_init (SPColorSliderClass *klass);
33 static void sp_color_slider_init (SPColorSlider *slider);
34 static void sp_color_slider_destroy (GtkObject *object);
36 static void sp_color_slider_realize (GtkWidget *widget);
37 static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition);
38 static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
39 /*  static void sp_color_slider_draw (GtkWidget *widget, GdkRectangle *area); */
40 /*  static void sp_color_slider_draw_focus (GtkWidget *widget); */
41 /*  static void sp_color_slider_draw_default (GtkWidget *widget); */
43 static gint sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event);
44 static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event);
45 static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event);
46 static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event);
48 static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider);
49 static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider);
51 static void sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area);
52 static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
53                                                       gint c[], gint dc[], guint b0, guint b1, guint mask);
54 static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
55                                                  guchar *map, gint start, gint step, guint b0, guint b1, guint mask);
57 static GtkWidgetClass *parent_class;
58 static guint slider_signals[LAST_SIGNAL] = {0};
60 GtkType
61 sp_color_slider_get_type (void)
62 {
63     //TODO: switch to GObject
64     // GtkType and such calls were deprecated a while back with the
65     // introduction of GObject as a separate layer, with GType instead. --JonCruz
67         static GtkType type = 0;
68         if (!type) {
69                 GtkTypeInfo info = {
70                         (gchar*) "SPColorSlider",
71                         sizeof (SPColorSlider),
72                         sizeof (SPColorSliderClass),
73                         (GtkClassInitFunc) sp_color_slider_class_init,
74                         (GtkObjectInitFunc) sp_color_slider_init,
75                         NULL, NULL, NULL
76                 };
77                 type = gtk_type_unique (GTK_TYPE_WIDGET, &info);
78         }
79         return type;
80 }
82 static void
83 sp_color_slider_class_init (SPColorSliderClass *klass)
84 {
85         GtkObjectClass *object_class;
86         GtkWidgetClass *widget_class;
88         object_class = (GtkObjectClass *) klass;
89         widget_class = (GtkWidgetClass *) klass;
91         parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET);
93         slider_signals[GRABBED] = gtk_signal_new ("grabbed",
94                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
95                                                   GTK_CLASS_TYPE(object_class),
96                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, grabbed),
97                                                   gtk_marshal_NONE__NONE,
98                                                   GTK_TYPE_NONE, 0);
99         slider_signals[DRAGGED] = gtk_signal_new ("dragged",
100                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
101                                                   GTK_CLASS_TYPE(object_class),
102                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, dragged),
103                                                   gtk_marshal_NONE__NONE,
104                                                   GTK_TYPE_NONE, 0);
105         slider_signals[RELEASED] = gtk_signal_new ("released",
106                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
107                                                   GTK_CLASS_TYPE(object_class),
108                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, released),
109                                                   gtk_marshal_NONE__NONE,
110                                                   GTK_TYPE_NONE, 0);
111         slider_signals[CHANGED] = gtk_signal_new ("changed",
112                                                   (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
113                                                   GTK_CLASS_TYPE(object_class),
114                                                   GTK_SIGNAL_OFFSET (SPColorSliderClass, changed),
115                                                   gtk_marshal_NONE__NONE,
116                                                   GTK_TYPE_NONE, 0);
118         object_class->destroy = sp_color_slider_destroy;
120         widget_class->realize = sp_color_slider_realize;
121         widget_class->size_request = sp_color_slider_size_request;
122         widget_class->size_allocate = sp_color_slider_size_allocate;
123 /*      widget_class->draw = sp_color_slider_draw; */
124 /*      widget_class->draw_focus = sp_color_slider_draw_focus; */
125 /*      widget_class->draw_default = sp_color_slider_draw_default; */
127         widget_class->expose_event = sp_color_slider_expose;
128         widget_class->button_press_event = sp_color_slider_button_press;
129         widget_class->button_release_event = sp_color_slider_button_release;
130         widget_class->motion_notify_event = sp_color_slider_motion_notify;
133 static void
134 sp_color_slider_init (SPColorSlider *slider)
136         /* We are widget with window */
137         GTK_WIDGET_UNSET_FLAGS (slider, GTK_NO_WINDOW);
139         slider->dragging = FALSE;
141         slider->adjustment = NULL;
142         slider->value = 0.0;
144         slider->c0[0] = 0x00;
145         slider->c0[1] = 0x00;
146         slider->c0[2] = 0x00;
147         slider->c0[3] = 0xff;
149         slider->cm[0] = 0xff;
150         slider->cm[1] = 0x00;
151         slider->cm[2] = 0x00;
152         slider->cm[3] = 0xff;
154         slider->c1[0] = 0xff;
155         slider->c1[1] = 0xff;
156         slider->c1[2] = 0xff;
157         slider->c1[3] = 0xff;
159         slider->b0 = 0x5f;
160         slider->b1 = 0xa0;
161         slider->bmask = 0x08;
163         slider->map = NULL;
166 static void
167 sp_color_slider_destroy (GtkObject *object)
169         SPColorSlider *slider;
171         slider = SP_COLOR_SLIDER (object);
173         if (slider->adjustment) {
174                 gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
175                 gtk_object_unref (GTK_OBJECT (slider->adjustment));
176                 slider->adjustment = NULL;
177         }
179         if (((GtkObjectClass *) (parent_class))->destroy)
180                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
183 static void
184 sp_color_slider_realize (GtkWidget *widget)
186         SPColorSlider *slider;
187         GdkWindowAttr attributes;
188         gint attributes_mask;
190         slider = SP_COLOR_SLIDER (widget);
192         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
194         attributes.window_type = GDK_WINDOW_CHILD;
195         attributes.x = widget->allocation.x;
196         attributes.y = widget->allocation.y;
197         attributes.width = widget->allocation.width;
198         attributes.height = widget->allocation.height;
199         attributes.wclass = GDK_INPUT_OUTPUT;
200         attributes.visual = gdk_rgb_get_visual ();
201         attributes.colormap = gdk_rgb_get_cmap ();
202         attributes.event_mask = gtk_widget_get_events (widget);
203         attributes.event_mask |= (GDK_EXPOSURE_MASK |
204                                   GDK_BUTTON_PRESS_MASK |
205                                   GDK_BUTTON_RELEASE_MASK |
206                                   GDK_POINTER_MOTION_MASK |
207                                   GDK_ENTER_NOTIFY_MASK |
208                                   GDK_LEAVE_NOTIFY_MASK);
209         attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
211         widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
212         gdk_window_set_user_data (widget->window, widget);
214         widget->style = gtk_style_attach (widget->style, widget->window);
217 static void
218 sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition)
220         SPColorSlider *slider;
222         slider = SP_COLOR_SLIDER (widget);
224         requisition->width = SLIDER_WIDTH + widget->style->xthickness * 2;
225         requisition->height = SLIDER_HEIGHT + widget->style->ythickness * 2;
228 static void
229 sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
231         SPColorSlider *slider;
233         slider = SP_COLOR_SLIDER (widget);
235         widget->allocation = *allocation;
237         if (GTK_WIDGET_REALIZED (widget)) {
238                 /* Resize GdkWindow */
239                 gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
240         }
243 static gint
244 sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event)
246         SPColorSlider *slider;
248         slider = SP_COLOR_SLIDER (widget);
250         if (GTK_WIDGET_DRAWABLE (widget)) {
251                 gint width, height;
252                 width = widget->allocation.width;
253                 height = widget->allocation.height;
254                 sp_color_slider_paint (slider, &event->area);
255         }
257         return FALSE;
260 static gint
261 sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event)
263         SPColorSlider *slider;
265         slider = SP_COLOR_SLIDER (widget);
267         if (event->button == 1) {
268                 gint cx, cw;
269                 cx = widget->style->xthickness;
270                 cw = widget->allocation.width - 2 * cx;
271                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[GRABBED]);
272                 slider->dragging = TRUE;
273                 slider->oldvalue = slider->value;
274                 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
275                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
276                 gdk_pointer_grab (widget->window, FALSE,
277                                   (GdkEventMask)(GDK_POINTER_MOTION_MASK |
278                                   GDK_BUTTON_RELEASE_MASK),
279                                   NULL, NULL, event->time);
280         }
282         return FALSE;
285 static gint
286 sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event)
288         SPColorSlider *slider;
290         slider = SP_COLOR_SLIDER (widget);
292         if (event->button == 1) {
293                 gdk_pointer_ungrab (event->time);
294                 slider->dragging = FALSE;
295                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[RELEASED]);
296                 if (slider->value != slider->oldvalue) gtk_signal_emit (GTK_OBJECT (slider), slider_signals[CHANGED]);
297         }
299         return FALSE;
302 static gint
303 sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event)
305         SPColorSlider *slider;
307         slider = SP_COLOR_SLIDER (widget);
309         if (slider->dragging) {
310                 gint cx, cw;
311                 cx = widget->style->xthickness;
312                 cw = widget->allocation.width - 2 * cx;
313                 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
314                 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
315         }
317         return FALSE;
320 GtkWidget *
321 sp_color_slider_new (GtkAdjustment *adjustment)
323         SPColorSlider *slider;
325         slider = (SPColorSlider*)gtk_type_new (SP_TYPE_COLOR_SLIDER);
327         sp_color_slider_set_adjustment (slider, adjustment);
329         return GTK_WIDGET (slider);
332 void
333 sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment)
335         g_return_if_fail (slider != NULL);
336         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
338         if (!adjustment) {
339                 adjustment = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.0, 0.0);
340         }
341 #if GTK_CHECK_VERSION (2,14,0)
342     else {
343         gtk_adjustment_set_page_increment(adjustment, 0.0);
344         gtk_adjustment_set_page_size(adjustment, 0.0);
345     }
346 #endif
348         if (slider->adjustment != adjustment) {
349                 if (slider->adjustment) {
350                         gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
351                         gtk_object_unref (GTK_OBJECT (slider->adjustment));
352                 }
354                 slider->adjustment = adjustment;
355                 gtk_object_ref (GTK_OBJECT (adjustment));
356                 gtk_object_sink (GTK_OBJECT (adjustment));
358                 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
359                                     GTK_SIGNAL_FUNC (sp_color_slider_adjustment_changed), slider);
360                 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
361                                     GTK_SIGNAL_FUNC (sp_color_slider_adjustment_value_changed), slider);
363                 slider->value = ColorScales::getScaled( adjustment );
365                 sp_color_slider_adjustment_changed (adjustment, slider);
366         }
369 void
370 sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end)
372         g_return_if_fail (slider != NULL);
373         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
375         // Remove any map, if set
376         slider->map = 0;
378         slider->c0[0] = start >> 24;
379         slider->c0[1] = (start >> 16) & 0xff;
380         slider->c0[2] = (start >> 8) & 0xff;
381         slider->c0[3] = start & 0xff;
383         slider->cm[0] = mid >> 24;
384         slider->cm[1] = (mid >> 16) & 0xff;
385         slider->cm[2] = (mid >> 8) & 0xff;
386         slider->cm[3] = mid & 0xff;
388         slider->c1[0] = end >> 24;
389         slider->c1[1] = (end >> 16) & 0xff;
390         slider->c1[2] = (end >> 8) & 0xff;
391         slider->c1[3] = end & 0xff;
393         gtk_widget_queue_draw (GTK_WIDGET (slider));
396 void
397 sp_color_slider_set_map (SPColorSlider *slider, const guchar *map)
399         g_return_if_fail (slider != NULL);
400         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
402         slider->map = (guchar *) map;
404         gtk_widget_queue_draw (GTK_WIDGET (slider));
407 void
408 sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size)
410         g_return_if_fail (slider != NULL);
411         g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
413         slider->b0 = dark;
414         slider->b1 = light;
415         slider->bmask = size;
417         gtk_widget_queue_draw (GTK_WIDGET (slider));
420 static void
421 sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider)
423         gtk_widget_queue_draw (GTK_WIDGET (slider));
426 static void
427 sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
429         GtkWidget *widget;
431         widget = GTK_WIDGET (slider);
433         if (slider->value != ColorScales::getScaled( adjustment )) {
434                 gint cx, cy, cw, ch;
435                 cx = widget->style->xthickness;
436                 cy = widget->style->ythickness;
437                 cw = widget->allocation.width - 2 * cx;
438                 ch = widget->allocation.height - 2 * cy;
439                 if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) {
440                         gint ax, ay;
441                         gfloat value;
442                         value = slider->value;
443                         slider->value = ColorScales::getScaled( adjustment );
444                         ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2);
445                         ay = cy;
446                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
447                         ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2);
448                         ay = cy;
449                         gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
450                 } else {
451                         slider->value = ColorScales::getScaled( adjustment );
452                 }
453         }
456 static void
457 sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area)
459         GtkWidget *widget;
460         GdkRectangle warea, carea, aarea;
461         GdkRectangle wpaint, cpaint, apaint;
462         const guchar *b;
463         gint w, x, y1, y2;
464         gboolean colorsOnTop = Inkscape::Preferences::get()->getBool("/options/workarounds/colorsontop", false);
466         widget = GTK_WIDGET (slider);
468         /* Widget area */
469         warea.x = 0;
470         warea.y = 0;
471         warea.width = widget->allocation.width;
472         warea.height = widget->allocation.height;
474         /* Color gradient area */
475         carea.x = widget->style->xthickness;
476         carea.y = widget->style->ythickness;
477         carea.width = widget->allocation.width - 2 * carea.x;
478         carea.height = widget->allocation.height - 2 * carea.y;
480         /* Arrow area */
481         aarea.x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x);
482         aarea.width = ARROW_SIZE;
483         aarea.y = carea.y;
484         aarea.height = carea.height;
486         /* Actual paintable area */
487         if (!gdk_rectangle_intersect (area, &warea, &wpaint)) {
488           return;
489         }
491         b = NULL;
493         // Draw shadow
494         if (colorsOnTop) {
495             gtk_paint_shadow( widget->style, widget->window,
496                               (GtkStateType)widget->state, GTK_SHADOW_IN,
497                               area, widget, "colorslider",
498                               0, 0,
499                               warea.width, warea.height);
500         }
502         /* Paintable part of color gradient area */
503         if (gdk_rectangle_intersect (area, &carea, &cpaint)) {
504                 if (slider->map) {
505                         gint s, d;
506                         /* Render map pixelstore */
507                         d = (1024 << 16) / carea.width;
508                         s = (cpaint.x - carea.x) * d;
509                         b = sp_color_slider_render_map (cpaint.x - carea.x, cpaint.y - carea.y, cpaint.width, cpaint.height,
510                                                                                                                                                         slider->map, s, d,
511                                                                                                                                                         slider->b0, slider->b1, slider->bmask);
512                         if (b != NULL) {
513                                 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
514                                                                                                                 cpaint.x, cpaint.y,
515                                                                                                                 cpaint.width, cpaint.height,
516                                                                                                                 GDK_RGB_DITHER_MAX,
517                                                                                                                 (guchar *) b, cpaint.width * 3);
518                         }
520                 } else {
521                         gint c[4], dc[4];
522                         gint i;
523                         /* Render gradient */
525                         // part 1: from c0 to cm
526                         if ((cpaint.x - carea.x) <= carea.width/2) {
527                                 for (i = 0; i < 4; i++) {
528                                         c[i] = slider->c0[i] << 16;
529                                         dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2);
530                                         c[i] += (cpaint.x - carea.x) * dc[i];
531                                 }
532                                 guint wi = MIN(cpaint.x - carea.x + cpaint.width, carea.width/2) - (cpaint.x - carea.x);
533                                 b = sp_color_slider_render_gradient (cpaint.x - carea.x, cpaint.y - carea.y, wi, cpaint.height,
534                                                                                                          c, dc,
535                                                                                                          slider->b0, slider->b1, slider->bmask);
537                                 /* Draw pixelstore */
538                                 if (b != NULL) {
539                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
540                                                                                                                         cpaint.x, cpaint.y,
541                                                                                                                         wi, cpaint.height,
542                                                                                                                         GDK_RGB_DITHER_MAX,
543                                                                                                                         (guchar *) b, wi * 3);
544                                 }
545                         }
547                         // part 2: from cm to c1
548                         if ((cpaint.x - carea.x + cpaint.width) > carea.width/2) {
549                                 for (i = 0; i < 4; i++) {
550                                         c[i] = slider->cm[i] << 16;
551                                         dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2);
552                                         if ((cpaint.x - carea.x) > carea.width/2)
553                                                 c[i] += (cpaint.x - carea.x - carea.width/2) * dc[i];
554                                 }
555                                 guint wi = cpaint.width - MAX(0, (carea.width/2 - (cpaint.x - carea.x)));
556                                 b = sp_color_slider_render_gradient (MAX(cpaint.x - carea.x, carea.width/2), cpaint.y - carea.y, wi, cpaint.height,
557                                                                                                  c, dc,
558                                                                                                  slider->b0, slider->b1, slider->bmask);
560                                 /* Draw pixelstore */
561                                 if (b != NULL) {
562                                         gdk_draw_rgb_image (widget->window, widget->style->black_gc,
563                                                                                                                         MAX(cpaint.x, carea.width/2 + carea.x), cpaint.y,
564                                                                                                                         wi, cpaint.height,
565                                                                                                                         GDK_RGB_DITHER_MAX,
566                                                                                                                         (guchar *) b, wi * 3);
567                                 }
568                         }
569                 }
570         }
572         /* Draw shadow */
573         if (!colorsOnTop) {
574             gtk_paint_shadow( widget->style, widget->window,
575                               (GtkStateType)widget->state, GTK_SHADOW_IN,
576                               area, widget, "colorslider",
577                               0, 0,
578                               warea.width, warea.height);
579         }
582         if (gdk_rectangle_intersect (area, &aarea, &apaint)) {
583                 /* Draw arrow */
584                 gdk_rectangle_intersect (&carea, &apaint, &apaint);
585                 gdk_gc_set_clip_rectangle (widget->style->white_gc, &apaint);
586                 gdk_gc_set_clip_rectangle (widget->style->black_gc, &apaint);
588                 x = aarea.x;
589                 y1 = carea.y;
590                 y2 = aarea.y + aarea.height - 1;
591                 w = aarea.width;
592                 while ( w > 0 )
593                 {
594                         gdk_draw_line (widget->window, widget->style->white_gc, x, y1, x + w - 1, y1 );
595                         gdk_draw_line (widget->window, widget->style->white_gc, x, y2, x + w - 1, y2 );
596                         w -=2;
597                         x++;
598                         if ( w > 0 )
599                         {
600                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y1, x + w - 1, y1 );
601                                 gdk_draw_line (widget->window, widget->style->black_gc, x, y2, x + w - 1, y2 );
602                         }
603                         y1++;
604                         y2--;
605                 }
607                 gdk_gc_set_clip_rectangle (widget->style->white_gc, NULL);
608                 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
609         }
612 /* Colors are << 16 */
614 static const guchar *
615 sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
616                                  gint c[], gint dc[], guint b0, guint b1, guint mask)
618         static guchar *buf = NULL;
619         static gint bs = 0;
620         guchar *dp;
621         gint x, y;
622         guint r, g, b, a;
624         if (buf && (bs < width * height)) {
625                 g_free (buf);
626                 buf = NULL;
627         }
628         if (!buf) {
629                 buf = g_new (guchar, width * height * 3);
630                 bs = width * height;
631         }
633         dp = buf;
634         r = c[0];
635         g = c[1];
636         b = c[2];
637         a = c[3];
638         for (x = x0; x < x0 + width; x++) {
639                 gint cr, cg, cb, ca;
640                 guchar *d;
641                 cr = r >> 16;
642                 cg = g >> 16;
643                 cb = b >> 16;
644                 ca = a >> 16;
645                 d = dp;
646                 for (y = y0; y < y0 + height; y++) {
647                         guint bg, fc;
648                         /* Background value */
649                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
650                         fc = (cr - bg) * ca;
651                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
652                         fc = (cg - bg) * ca;
653                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
654                         fc = (cb - bg) * ca;
655                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
656                         d += 3 * width;
657                 }
658                 r += dc[0];
659                 g += dc[1];
660                 b += dc[2];
661                 a += dc[3];
662                 dp += 3;
663         }
665         return buf;
668 /* Positions are << 16 */
670 static const guchar *
671 sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
672                             guchar *map, gint start, gint step, guint b0, guint b1, guint mask)
674         static guchar *buf = NULL;
675         static gint bs = 0;
676         guchar *dp, *sp;
677         gint x, y;
679         if (buf && (bs < width * height)) {
680                 g_free (buf);
681                 buf = NULL;
682         }
683         if (!buf) {
684                 buf = g_new (guchar, width * height * 3);
685                 bs = width * height;
686         }
688         dp = buf;
689         for (x = x0; x < x0 + width; x++) {
690                 gint cr, cg, cb, ca;
691                 guchar *d;
692                 sp = map + 4 * (start >> 16);
693                 cr = *sp++;
694                 cg = *sp++;
695                 cb = *sp++;
696                 ca = *sp++;
697                 d = dp;
698                 for (y = y0; y < y0 + height; y++) {
699                         guint bg, fc;
700                         /* Background value */
701                         bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
702                         fc = (cr - bg) * ca;
703                         d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
704                         fc = (cg - bg) * ca;
705                         d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
706                         fc = (cb - bg) * ca;
707                         d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
708                         d += 3 * width;
709                 }
710                 dp += 3;
711                 start += step;
712         }
714         return buf;