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;
131 }
133 static void
134 sp_color_slider_init (SPColorSlider *slider)
135 {
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;
164 }
166 static void
167 sp_color_slider_destroy (GtkObject *object)
168 {
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);
181 }
183 static void
184 sp_color_slider_realize (GtkWidget *widget)
185 {
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);
215 }
217 static void
218 sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition)
219 {
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;
226 }
228 static void
229 sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
230 {
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 }
241 }
243 static gint
244 sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event)
245 {
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;
258 }
260 static gint
261 sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event)
262 {
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;
283 }
285 static gint
286 sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event)
287 {
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;
300 }
302 static gint
303 sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event)
304 {
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;
318 }
320 GtkWidget *
321 sp_color_slider_new (GtkAdjustment *adjustment)
322 {
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);
330 }
332 void
333 sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment)
334 {
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 }
367 }
369 void
370 sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end)
371 {
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));
394 }
396 void
397 sp_color_slider_set_map (SPColorSlider *slider, const guchar *map)
398 {
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));
405 }
407 void
408 sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size)
409 {
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));
418 }
420 static void
421 sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider)
422 {
423 gtk_widget_queue_draw (GTK_WIDGET (slider));
424 }
426 static void
427 sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
428 {
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 }
454 }
456 static void
457 sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area)
458 {
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 }
610 }
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)
617 {
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;
666 }
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)
673 {
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;
715 }