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;
130 }
132 static void
133 sp_color_slider_init (SPColorSlider *slider)
134 {
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;
163 }
165 static void
166 sp_color_slider_destroy (GtkObject *object)
167 {
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);
180 }
182 static void
183 sp_color_slider_realize (GtkWidget *widget)
184 {
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);
214 }
216 static void
217 sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition)
218 {
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;
225 }
227 static void
228 sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
229 {
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 }
240 }
242 static gint
243 sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event)
244 {
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;
257 }
259 static gint
260 sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event)
261 {
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;
282 }
284 static gint
285 sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event)
286 {
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;
299 }
301 static gint
302 sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event)
303 {
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;
317 }
319 GtkWidget *
320 sp_color_slider_new (GtkAdjustment *adjustment)
321 {
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);
329 }
331 void
332 sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment)
333 {
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 }
366 }
368 void
369 sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end)
370 {
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));
393 }
395 void
396 sp_color_slider_set_map (SPColorSlider *slider, const guchar *map)
397 {
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));
404 }
406 void
407 sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size)
408 {
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));
417 }
419 static void
420 sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider)
421 {
422 gtk_widget_queue_draw (GTK_WIDGET (slider));
423 }
425 static void
426 sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
427 {
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 }
453 }
455 static void
456 sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area)
457 {
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 }
595 }
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)
602 {
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;
651 }
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)
658 {
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;
700 }