0f792edff3bd43f1a13579e59811ea725a15c07c
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 static GtkType type = 0;
63 if (!type) {
64 GtkTypeInfo info = {
65 "SPColorSlider",
66 sizeof (SPColorSlider),
67 sizeof (SPColorSliderClass),
68 (GtkClassInitFunc) sp_color_slider_class_init,
69 (GtkObjectInitFunc) sp_color_slider_init,
70 NULL, NULL, NULL
71 };
72 type = gtk_type_unique (GTK_TYPE_WIDGET, &info);
73 }
74 return type;
75 }
77 static void
78 sp_color_slider_class_init (SPColorSliderClass *klass)
79 {
80 GtkObjectClass *object_class;
81 GtkWidgetClass *widget_class;
83 object_class = (GtkObjectClass *) klass;
84 widget_class = (GtkWidgetClass *) klass;
86 parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET);
88 slider_signals[GRABBED] = gtk_signal_new ("grabbed",
89 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
90 GTK_CLASS_TYPE(object_class),
91 GTK_SIGNAL_OFFSET (SPColorSliderClass, grabbed),
92 gtk_marshal_NONE__NONE,
93 GTK_TYPE_NONE, 0);
94 slider_signals[DRAGGED] = gtk_signal_new ("dragged",
95 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
96 GTK_CLASS_TYPE(object_class),
97 GTK_SIGNAL_OFFSET (SPColorSliderClass, dragged),
98 gtk_marshal_NONE__NONE,
99 GTK_TYPE_NONE, 0);
100 slider_signals[RELEASED] = gtk_signal_new ("released",
101 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
102 GTK_CLASS_TYPE(object_class),
103 GTK_SIGNAL_OFFSET (SPColorSliderClass, released),
104 gtk_marshal_NONE__NONE,
105 GTK_TYPE_NONE, 0);
106 slider_signals[CHANGED] = gtk_signal_new ("changed",
107 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
108 GTK_CLASS_TYPE(object_class),
109 GTK_SIGNAL_OFFSET (SPColorSliderClass, changed),
110 gtk_marshal_NONE__NONE,
111 GTK_TYPE_NONE, 0);
113 object_class->destroy = sp_color_slider_destroy;
115 widget_class->realize = sp_color_slider_realize;
116 widget_class->size_request = sp_color_slider_size_request;
117 widget_class->size_allocate = sp_color_slider_size_allocate;
118 /* widget_class->draw = sp_color_slider_draw; */
119 /* widget_class->draw_focus = sp_color_slider_draw_focus; */
120 /* widget_class->draw_default = sp_color_slider_draw_default; */
122 widget_class->expose_event = sp_color_slider_expose;
123 widget_class->button_press_event = sp_color_slider_button_press;
124 widget_class->button_release_event = sp_color_slider_button_release;
125 widget_class->motion_notify_event = sp_color_slider_motion_notify;
126 }
128 static void
129 sp_color_slider_init (SPColorSlider *slider)
130 {
131 /* We are widget with window */
132 GTK_WIDGET_UNSET_FLAGS (slider, GTK_NO_WINDOW);
134 slider->dragging = FALSE;
136 slider->adjustment = NULL;
137 slider->value = 0.0;
139 slider->c0[0] = 0x00;
140 slider->c0[1] = 0x00;
141 slider->c0[2] = 0x00;
142 slider->c0[3] = 0xff;
144 slider->cm[0] = 0xff;
145 slider->cm[1] = 0x00;
146 slider->cm[2] = 0x00;
147 slider->cm[3] = 0xff;
149 slider->c1[0] = 0xff;
150 slider->c1[1] = 0xff;
151 slider->c1[2] = 0xff;
152 slider->c1[3] = 0xff;
154 slider->b0 = 0x5f;
155 slider->b1 = 0xa0;
156 slider->bmask = 0x08;
158 slider->map = NULL;
159 }
161 static void
162 sp_color_slider_destroy (GtkObject *object)
163 {
164 SPColorSlider *slider;
166 slider = SP_COLOR_SLIDER (object);
168 if (slider->adjustment) {
169 gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
170 gtk_object_unref (GTK_OBJECT (slider->adjustment));
171 slider->adjustment = NULL;
172 }
174 if (((GtkObjectClass *) (parent_class))->destroy)
175 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
176 }
178 static void
179 sp_color_slider_realize (GtkWidget *widget)
180 {
181 SPColorSlider *slider;
182 GdkWindowAttr attributes;
183 gint attributes_mask;
185 slider = SP_COLOR_SLIDER (widget);
187 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
189 attributes.window_type = GDK_WINDOW_CHILD;
190 attributes.x = widget->allocation.x;
191 attributes.y = widget->allocation.y;
192 attributes.width = widget->allocation.width;
193 attributes.height = widget->allocation.height;
194 attributes.wclass = GDK_INPUT_OUTPUT;
195 attributes.visual = gdk_rgb_get_visual ();
196 attributes.colormap = gdk_rgb_get_cmap ();
197 attributes.event_mask = gtk_widget_get_events (widget);
198 attributes.event_mask |= (GDK_EXPOSURE_MASK |
199 GDK_BUTTON_PRESS_MASK |
200 GDK_BUTTON_RELEASE_MASK |
201 GDK_POINTER_MOTION_MASK |
202 GDK_ENTER_NOTIFY_MASK |
203 GDK_LEAVE_NOTIFY_MASK);
204 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
206 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
207 gdk_window_set_user_data (widget->window, widget);
209 widget->style = gtk_style_attach (widget->style, widget->window);
210 }
212 static void
213 sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition)
214 {
215 SPColorSlider *slider;
217 slider = SP_COLOR_SLIDER (widget);
219 requisition->width = SLIDER_WIDTH + widget->style->xthickness * 2;
220 requisition->height = SLIDER_HEIGHT + widget->style->ythickness * 2;
221 }
223 static void
224 sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
225 {
226 SPColorSlider *slider;
228 slider = SP_COLOR_SLIDER (widget);
230 widget->allocation = *allocation;
232 if (GTK_WIDGET_REALIZED (widget)) {
233 /* Resize GdkWindow */
234 gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
235 }
236 }
238 static gint
239 sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event)
240 {
241 SPColorSlider *slider;
243 slider = SP_COLOR_SLIDER (widget);
245 if (GTK_WIDGET_DRAWABLE (widget)) {
246 gint width, height;
247 width = widget->allocation.width;
248 height = widget->allocation.height;
249 sp_color_slider_paint (slider, &event->area);
250 }
252 return FALSE;
253 }
255 static gint
256 sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event)
257 {
258 SPColorSlider *slider;
260 slider = SP_COLOR_SLIDER (widget);
262 if (event->button == 1) {
263 gint cx, cw;
264 cx = widget->style->xthickness;
265 cw = widget->allocation.width - 2 * cx;
266 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[GRABBED]);
267 slider->dragging = TRUE;
268 slider->oldvalue = slider->value;
269 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
270 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
271 gdk_pointer_grab (widget->window, FALSE,
272 (GdkEventMask)(GDK_POINTER_MOTION_MASK |
273 GDK_BUTTON_RELEASE_MASK),
274 NULL, NULL, event->time);
275 }
277 return FALSE;
278 }
280 static gint
281 sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event)
282 {
283 SPColorSlider *slider;
285 slider = SP_COLOR_SLIDER (widget);
287 if (event->button == 1) {
288 gdk_pointer_ungrab (event->time);
289 slider->dragging = FALSE;
290 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[RELEASED]);
291 if (slider->value != slider->oldvalue) gtk_signal_emit (GTK_OBJECT (slider), slider_signals[CHANGED]);
292 }
294 return FALSE;
295 }
297 static gint
298 sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event)
299 {
300 SPColorSlider *slider;
302 slider = SP_COLOR_SLIDER (widget);
304 if (slider->dragging) {
305 gint cx, cw;
306 cx = widget->style->xthickness;
307 cw = widget->allocation.width - 2 * cx;
308 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
309 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
310 }
312 return FALSE;
313 }
315 GtkWidget *
316 sp_color_slider_new (GtkAdjustment *adjustment)
317 {
318 SPColorSlider *slider;
320 slider = (SPColorSlider*)gtk_type_new (SP_TYPE_COLOR_SLIDER);
322 sp_color_slider_set_adjustment (slider, adjustment);
324 return GTK_WIDGET (slider);
325 }
327 void
328 sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment)
329 {
330 g_return_if_fail (slider != NULL);
331 g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
333 if (!adjustment) {
334 adjustment = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.0, 0.0);
335 }
336 #if GTK_CHECK_VERSION (2,14,0)
337 else {
338 gtk_adjustment_set_page_increment(adjustment, 0.0);
339 gtk_adjustment_set_page_size(adjustment, 0.0);
340 }
341 #endif
343 if (slider->adjustment != adjustment) {
344 if (slider->adjustment) {
345 gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
346 gtk_object_unref (GTK_OBJECT (slider->adjustment));
347 }
349 slider->adjustment = adjustment;
350 gtk_object_ref (GTK_OBJECT (adjustment));
351 gtk_object_sink (GTK_OBJECT (adjustment));
353 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
354 GTK_SIGNAL_FUNC (sp_color_slider_adjustment_changed), slider);
355 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
356 GTK_SIGNAL_FUNC (sp_color_slider_adjustment_value_changed), slider);
358 slider->value = ColorScales::getScaled( adjustment );
360 sp_color_slider_adjustment_changed (adjustment, slider);
361 }
362 }
364 void
365 sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end)
366 {
367 g_return_if_fail (slider != NULL);
368 g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
370 // Remove any map, if set
371 slider->map = 0;
373 slider->c0[0] = start >> 24;
374 slider->c0[1] = (start >> 16) & 0xff;
375 slider->c0[2] = (start >> 8) & 0xff;
376 slider->c0[3] = start & 0xff;
378 slider->cm[0] = mid >> 24;
379 slider->cm[1] = (mid >> 16) & 0xff;
380 slider->cm[2] = (mid >> 8) & 0xff;
381 slider->cm[3] = mid & 0xff;
383 slider->c1[0] = end >> 24;
384 slider->c1[1] = (end >> 16) & 0xff;
385 slider->c1[2] = (end >> 8) & 0xff;
386 slider->c1[3] = end & 0xff;
388 gtk_widget_queue_draw (GTK_WIDGET (slider));
389 }
391 void
392 sp_color_slider_set_map (SPColorSlider *slider, const guchar *map)
393 {
394 g_return_if_fail (slider != NULL);
395 g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
397 slider->map = (guchar *) map;
399 gtk_widget_queue_draw (GTK_WIDGET (slider));
400 }
402 void
403 sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size)
404 {
405 g_return_if_fail (slider != NULL);
406 g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
408 slider->b0 = dark;
409 slider->b1 = light;
410 slider->bmask = size;
412 gtk_widget_queue_draw (GTK_WIDGET (slider));
413 }
415 static void
416 sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider)
417 {
418 gtk_widget_queue_draw (GTK_WIDGET (slider));
419 }
421 static void
422 sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
423 {
424 GtkWidget *widget;
426 widget = GTK_WIDGET (slider);
428 if (slider->value != ColorScales::getScaled( adjustment )) {
429 gint cx, cy, cw, ch;
430 cx = widget->style->xthickness;
431 cy = widget->style->ythickness;
432 cw = widget->allocation.width - 2 * cx;
433 ch = widget->allocation.height - 2 * cy;
434 if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) {
435 gint ax, ay;
436 gfloat value;
437 value = slider->value;
438 slider->value = ColorScales::getScaled( adjustment );
439 ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2);
440 ay = cy;
441 gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
442 ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2);
443 ay = cy;
444 gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
445 } else {
446 slider->value = ColorScales::getScaled( adjustment );
447 }
448 }
449 }
451 static void
452 sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area)
453 {
454 GtkWidget *widget;
455 GdkRectangle warea, carea, aarea;
456 GdkRectangle wpaint, cpaint, apaint;
457 const guchar *b;
458 gint w, x, y1, y2;
460 widget = GTK_WIDGET (slider);
462 /* Widget area */
463 warea.x = 0;
464 warea.y = 0;
465 warea.width = widget->allocation.width;
466 warea.height = widget->allocation.height;
468 /* Color gradient area */
469 carea.x = widget->style->xthickness;
470 carea.y = widget->style->ythickness;
471 carea.width = widget->allocation.width - 2 * carea.x;
472 carea.height = widget->allocation.height - 2 * carea.y;
474 /* Arrow area */
475 aarea.x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x);
476 aarea.width = ARROW_SIZE;
477 aarea.y = carea.y;
478 aarea.height = carea.height;
480 /* Actual paintable area */
481 if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return;
483 b = NULL;
485 /* Paintable part of color gradient area */
486 if (gdk_rectangle_intersect (area, &carea, &cpaint)) {
487 if (slider->map) {
488 gint s, d;
489 /* Render map pixelstore */
490 d = (1024 << 16) / carea.width;
491 s = (cpaint.x - carea.x) * d;
492 b = sp_color_slider_render_map (cpaint.x - carea.x, cpaint.y - carea.y, cpaint.width, cpaint.height,
493 slider->map, s, d,
494 slider->b0, slider->b1, slider->bmask);
495 if (b != NULL) {
496 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
497 cpaint.x, cpaint.y,
498 cpaint.width, cpaint.height,
499 GDK_RGB_DITHER_MAX,
500 (guchar *) b, cpaint.width * 3);
501 }
503 } else {
504 gint c[4], dc[4];
505 gint i;
506 /* Render gradient */
508 // part 1: from c0 to cm
509 if ((cpaint.x - carea.x) <= carea.width/2) {
510 for (i = 0; i < 4; i++) {
511 c[i] = slider->c0[i] << 16;
512 dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2);
513 c[i] += (cpaint.x - carea.x) * dc[i];
514 }
515 guint wi = MIN(cpaint.x - carea.x + cpaint.width, carea.width/2) - (cpaint.x - carea.x);
516 b = sp_color_slider_render_gradient (cpaint.x - carea.x, cpaint.y - carea.y, wi, cpaint.height,
517 c, dc,
518 slider->b0, slider->b1, slider->bmask);
520 /* Draw pixelstore */
521 if (b != NULL) {
522 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
523 cpaint.x, cpaint.y,
524 wi, cpaint.height,
525 GDK_RGB_DITHER_MAX,
526 (guchar *) b, wi * 3);
527 }
528 }
530 // part 2: from cm to c1
531 if ((cpaint.x - carea.x + cpaint.width) > carea.width/2) {
532 for (i = 0; i < 4; i++) {
533 c[i] = slider->cm[i] << 16;
534 dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2);
535 if ((cpaint.x - carea.x) > carea.width/2)
536 c[i] += (cpaint.x - carea.x - carea.width/2) * dc[i];
537 }
538 guint wi = cpaint.width - MAX(0, (carea.width/2 - (cpaint.x - carea.x)));
539 b = sp_color_slider_render_gradient (MAX(cpaint.x - carea.x, carea.width/2), cpaint.y - carea.y, wi, cpaint.height,
540 c, dc,
541 slider->b0, slider->b1, slider->bmask);
543 /* Draw pixelstore */
544 if (b != NULL) {
545 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
546 MAX(cpaint.x, carea.width/2 + carea.x), cpaint.y,
547 wi, cpaint.height,
548 GDK_RGB_DITHER_MAX,
549 (guchar *) b, wi * 3);
550 }
551 }
552 }
553 }
555 /* Draw shadow */
556 gtk_paint_shadow (widget->style, widget->window,
557 (GtkStateType)widget->state, GTK_SHADOW_IN,
558 area, widget, "colorslider",
559 0, 0,
560 warea.width, warea.height);
563 if (gdk_rectangle_intersect (area, &aarea, &apaint)) {
564 /* Draw arrow */
565 gdk_rectangle_intersect (&carea, &apaint, &apaint);
566 gdk_gc_set_clip_rectangle (widget->style->white_gc, &apaint);
567 gdk_gc_set_clip_rectangle (widget->style->black_gc, &apaint);
569 x = aarea.x;
570 y1 = carea.y;
571 y2 = aarea.y + aarea.height - 1;
572 w = aarea.width;
573 while ( w > 0 )
574 {
575 gdk_draw_line (widget->window, widget->style->white_gc, x, y1, x + w - 1, y1 );
576 gdk_draw_line (widget->window, widget->style->white_gc, x, y2, x + w - 1, y2 );
577 w -=2;
578 x++;
579 if ( w > 0 )
580 {
581 gdk_draw_line (widget->window, widget->style->black_gc, x, y1, x + w - 1, y1 );
582 gdk_draw_line (widget->window, widget->style->black_gc, x, y2, x + w - 1, y2 );
583 }
584 y1++;
585 y2--;
586 }
588 gdk_gc_set_clip_rectangle (widget->style->white_gc, NULL);
589 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
590 }
591 }
593 /* Colors are << 16 */
595 static const guchar *
596 sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
597 gint c[], gint dc[], guint b0, guint b1, guint mask)
598 {
599 static guchar *buf = NULL;
600 static gint bs = 0;
601 guchar *dp;
602 gint x, y;
603 guint r, g, b, a;
605 if (buf && (bs < width * height)) {
606 g_free (buf);
607 buf = NULL;
608 }
609 if (!buf) {
610 buf = g_new (guchar, width * height * 3);
611 bs = width * height;
612 }
614 dp = buf;
615 r = c[0];
616 g = c[1];
617 b = c[2];
618 a = c[3];
619 for (x = x0; x < x0 + width; x++) {
620 gint cr, cg, cb, ca;
621 guchar *d;
622 cr = r >> 16;
623 cg = g >> 16;
624 cb = b >> 16;
625 ca = a >> 16;
626 d = dp;
627 for (y = y0; y < y0 + height; y++) {
628 guint bg, fc;
629 /* Background value */
630 bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
631 fc = (cr - bg) * ca;
632 d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
633 fc = (cg - bg) * ca;
634 d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
635 fc = (cb - bg) * ca;
636 d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
637 d += 3 * width;
638 }
639 r += dc[0];
640 g += dc[1];
641 b += dc[2];
642 a += dc[3];
643 dp += 3;
644 }
646 return buf;
647 }
649 /* Positions are << 16 */
651 static const guchar *
652 sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
653 guchar *map, gint start, gint step, guint b0, guint b1, guint mask)
654 {
655 static guchar *buf = NULL;
656 static gint bs = 0;
657 guchar *dp, *sp;
658 gint x, y;
660 if (buf && (bs < width * height)) {
661 g_free (buf);
662 buf = NULL;
663 }
664 if (!buf) {
665 buf = g_new (guchar, width * height * 3);
666 bs = width * height;
667 }
669 dp = buf;
670 for (x = x0; x < x0 + width; x++) {
671 gint cr, cg, cb, ca;
672 guchar *d;
673 sp = map + 4 * (start >> 16);
674 cr = *sp++;
675 cg = *sp++;
676 cb = *sp++;
677 ca = *sp++;
678 d = dp;
679 for (y = y0; y < y0 + height; y++) {
680 guint bg, fc;
681 /* Background value */
682 bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
683 fc = (cr - bg) * ca;
684 d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
685 fc = (cg - bg) * ca;
686 d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
687 fc = (cb - bg) * ca;
688 d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
689 d += 3 * width;
690 }
691 dp += 3;
692 start += step;
693 }
695 return buf;
696 }