76ef13a8dac8396b44e837902497431a7a934217
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/gtksignal.h>
16 #include "sp-color-scales.h"
18 #define SLIDER_WIDTH 96
19 #define SLIDER_HEIGHT 8
20 #define ARROW_SIZE 7
22 enum {
23 GRABBED,
24 DRAGGED,
25 RELEASED,
26 CHANGED,
27 LAST_SIGNAL
28 };
30 static void sp_color_slider_class_init (SPColorSliderClass *klass);
31 static void sp_color_slider_init (SPColorSlider *slider);
32 static void sp_color_slider_destroy (GtkObject *object);
34 static void sp_color_slider_realize (GtkWidget *widget);
35 static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition);
36 static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
37 /* static void sp_color_slider_draw (GtkWidget *widget, GdkRectangle *area); */
38 /* static void sp_color_slider_draw_focus (GtkWidget *widget); */
39 /* static void sp_color_slider_draw_default (GtkWidget *widget); */
41 static gint sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event);
42 static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event);
43 static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event);
44 static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event);
46 static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider);
47 static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider);
49 static void sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area);
50 static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
51 gint c[], gint dc[], guint b0, guint b1, guint mask);
52 static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
53 guchar *map, gint start, gint step, guint b0, guint b1, guint mask);
55 static GtkWidgetClass *parent_class;
56 static guint slider_signals[LAST_SIGNAL] = {0};
58 GtkType
59 sp_color_slider_get_type (void)
60 {
61 static GtkType type = 0;
62 if (!type) {
63 GtkTypeInfo info = {
64 "SPColorSlider",
65 sizeof (SPColorSlider),
66 sizeof (SPColorSliderClass),
67 (GtkClassInitFunc) sp_color_slider_class_init,
68 (GtkObjectInitFunc) sp_color_slider_init,
69 NULL, NULL, NULL
70 };
71 type = gtk_type_unique (GTK_TYPE_WIDGET, &info);
72 }
73 return type;
74 }
76 static void
77 sp_color_slider_class_init (SPColorSliderClass *klass)
78 {
79 GtkObjectClass *object_class;
80 GtkWidgetClass *widget_class;
82 object_class = (GtkObjectClass *) klass;
83 widget_class = (GtkWidgetClass *) klass;
85 parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET);
87 slider_signals[GRABBED] = gtk_signal_new ("grabbed",
88 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
89 GTK_CLASS_TYPE(object_class),
90 GTK_SIGNAL_OFFSET (SPColorSliderClass, grabbed),
91 gtk_marshal_NONE__NONE,
92 GTK_TYPE_NONE, 0);
93 slider_signals[DRAGGED] = gtk_signal_new ("dragged",
94 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
95 GTK_CLASS_TYPE(object_class),
96 GTK_SIGNAL_OFFSET (SPColorSliderClass, dragged),
97 gtk_marshal_NONE__NONE,
98 GTK_TYPE_NONE, 0);
99 slider_signals[RELEASED] = gtk_signal_new ("released",
100 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
101 GTK_CLASS_TYPE(object_class),
102 GTK_SIGNAL_OFFSET (SPColorSliderClass, released),
103 gtk_marshal_NONE__NONE,
104 GTK_TYPE_NONE, 0);
105 slider_signals[CHANGED] = gtk_signal_new ("changed",
106 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
107 GTK_CLASS_TYPE(object_class),
108 GTK_SIGNAL_OFFSET (SPColorSliderClass, changed),
109 gtk_marshal_NONE__NONE,
110 GTK_TYPE_NONE, 0);
112 object_class->destroy = sp_color_slider_destroy;
114 widget_class->realize = sp_color_slider_realize;
115 widget_class->size_request = sp_color_slider_size_request;
116 widget_class->size_allocate = sp_color_slider_size_allocate;
117 /* widget_class->draw = sp_color_slider_draw; */
118 /* widget_class->draw_focus = sp_color_slider_draw_focus; */
119 /* widget_class->draw_default = sp_color_slider_draw_default; */
121 widget_class->expose_event = sp_color_slider_expose;
122 widget_class->button_press_event = sp_color_slider_button_press;
123 widget_class->button_release_event = sp_color_slider_button_release;
124 widget_class->motion_notify_event = sp_color_slider_motion_notify;
125 }
127 static void
128 sp_color_slider_init (SPColorSlider *slider)
129 {
130 /* We are widget with window */
131 GTK_WIDGET_UNSET_FLAGS (slider, GTK_NO_WINDOW);
133 slider->dragging = FALSE;
135 slider->adjustment = NULL;
136 slider->value = 0.0;
138 slider->c0[0] = 0x00;
139 slider->c0[1] = 0x00;
140 slider->c0[2] = 0x00;
141 slider->c0[3] = 0xff;
143 slider->cm[0] = 0xff;
144 slider->cm[1] = 0x00;
145 slider->cm[2] = 0x00;
146 slider->cm[3] = 0xff;
148 slider->c1[0] = 0xff;
149 slider->c1[1] = 0xff;
150 slider->c1[2] = 0xff;
151 slider->c1[3] = 0xff;
153 slider->b0 = 0x5f;
154 slider->b1 = 0xa0;
155 slider->bmask = 0x08;
157 slider->map = NULL;
158 }
160 static void
161 sp_color_slider_destroy (GtkObject *object)
162 {
163 SPColorSlider *slider;
165 slider = SP_COLOR_SLIDER (object);
167 if (slider->adjustment) {
168 gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
169 gtk_object_unref (GTK_OBJECT (slider->adjustment));
170 slider->adjustment = NULL;
171 }
173 if (((GtkObjectClass *) (parent_class))->destroy)
174 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
175 }
177 static void
178 sp_color_slider_realize (GtkWidget *widget)
179 {
180 SPColorSlider *slider;
181 GdkWindowAttr attributes;
182 gint attributes_mask;
184 slider = SP_COLOR_SLIDER (widget);
186 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
188 attributes.window_type = GDK_WINDOW_CHILD;
189 attributes.x = widget->allocation.x;
190 attributes.y = widget->allocation.y;
191 attributes.width = widget->allocation.width;
192 attributes.height = widget->allocation.height;
193 attributes.wclass = GDK_INPUT_OUTPUT;
194 attributes.visual = gdk_rgb_get_visual ();
195 attributes.colormap = gdk_rgb_get_cmap ();
196 attributes.event_mask = gtk_widget_get_events (widget);
197 attributes.event_mask |= (GDK_EXPOSURE_MASK |
198 GDK_BUTTON_PRESS_MASK |
199 GDK_BUTTON_RELEASE_MASK |
200 GDK_POINTER_MOTION_MASK |
201 GDK_ENTER_NOTIFY_MASK |
202 GDK_LEAVE_NOTIFY_MASK);
203 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
205 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
206 gdk_window_set_user_data (widget->window, widget);
208 widget->style = gtk_style_attach (widget->style, widget->window);
209 }
211 static void
212 sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition)
213 {
214 SPColorSlider *slider;
216 slider = SP_COLOR_SLIDER (widget);
218 requisition->width = SLIDER_WIDTH + widget->style->xthickness * 2;
219 requisition->height = SLIDER_HEIGHT + widget->style->ythickness * 2;
220 }
222 static void
223 sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
224 {
225 SPColorSlider *slider;
227 slider = SP_COLOR_SLIDER (widget);
229 widget->allocation = *allocation;
231 if (GTK_WIDGET_REALIZED (widget)) {
232 /* Resize GdkWindow */
233 gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
234 }
235 }
237 static gint
238 sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event)
239 {
240 SPColorSlider *slider;
242 slider = SP_COLOR_SLIDER (widget);
244 if (GTK_WIDGET_DRAWABLE (widget)) {
245 gint width, height;
246 width = widget->allocation.width;
247 height = widget->allocation.height;
248 sp_color_slider_paint (slider, &event->area);
249 }
251 return FALSE;
252 }
254 static gint
255 sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event)
256 {
257 SPColorSlider *slider;
259 slider = SP_COLOR_SLIDER (widget);
261 if (event->button == 1) {
262 gint cx, cw;
263 cx = widget->style->xthickness;
264 cw = widget->allocation.width - 2 * cx;
265 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[GRABBED]);
266 slider->dragging = TRUE;
267 slider->oldvalue = slider->value;
268 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
269 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
270 gdk_pointer_grab (widget->window, FALSE,
271 (GdkEventMask)(GDK_POINTER_MOTION_MASK |
272 GDK_BUTTON_RELEASE_MASK),
273 NULL, NULL, event->time);
274 }
276 return FALSE;
277 }
279 static gint
280 sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event)
281 {
282 SPColorSlider *slider;
284 slider = SP_COLOR_SLIDER (widget);
286 if (event->button == 1) {
287 gdk_pointer_ungrab (event->time);
288 slider->dragging = FALSE;
289 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[RELEASED]);
290 if (slider->value != slider->oldvalue) gtk_signal_emit (GTK_OBJECT (slider), slider_signals[CHANGED]);
291 }
293 return FALSE;
294 }
296 static gint
297 sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event)
298 {
299 SPColorSlider *slider;
301 slider = SP_COLOR_SLIDER (widget);
303 if (slider->dragging) {
304 gint cx, cw;
305 cx = widget->style->xthickness;
306 cw = widget->allocation.width - 2 * cx;
307 ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) );
308 gtk_signal_emit (GTK_OBJECT (slider), slider_signals[DRAGGED]);
309 }
311 return FALSE;
312 }
314 GtkWidget *
315 sp_color_slider_new (GtkAdjustment *adjustment)
316 {
317 SPColorSlider *slider;
319 slider = (SPColorSlider*)gtk_type_new (SP_TYPE_COLOR_SLIDER);
321 sp_color_slider_set_adjustment (slider, adjustment);
323 return GTK_WIDGET (slider);
324 }
326 void
327 sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment)
328 {
329 g_return_if_fail (slider != NULL);
330 g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
332 if (!adjustment) {
333 adjustment = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.1, 0.1);
334 }
336 if (slider->adjustment != adjustment) {
337 if (slider->adjustment) {
338 gtk_signal_disconnect_by_data (GTK_OBJECT (slider->adjustment), slider);
339 gtk_object_unref (GTK_OBJECT (slider->adjustment));
340 }
342 slider->adjustment = adjustment;
343 gtk_object_ref (GTK_OBJECT (adjustment));
344 gtk_object_sink (GTK_OBJECT (adjustment));
346 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
347 GTK_SIGNAL_FUNC (sp_color_slider_adjustment_changed), slider);
348 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
349 GTK_SIGNAL_FUNC (sp_color_slider_adjustment_value_changed), slider);
351 slider->value = ColorScales::getScaled( adjustment );
353 sp_color_slider_adjustment_changed (adjustment, slider);
354 }
355 }
357 void
358 sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end)
359 {
360 g_return_if_fail (slider != NULL);
361 g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
363 slider->c0[0] = start >> 24;
364 slider->c0[1] = (start >> 16) & 0xff;
365 slider->c0[2] = (start >> 8) & 0xff;
366 slider->c0[3] = start & 0xff;
368 slider->cm[0] = mid >> 24;
369 slider->cm[1] = (mid >> 16) & 0xff;
370 slider->cm[2] = (mid >> 8) & 0xff;
371 slider->cm[3] = mid & 0xff;
373 slider->c1[0] = end >> 24;
374 slider->c1[1] = (end >> 16) & 0xff;
375 slider->c1[2] = (end >> 8) & 0xff;
376 slider->c1[3] = end & 0xff;
378 gtk_widget_queue_draw (GTK_WIDGET (slider));
379 }
381 void
382 sp_color_slider_set_map (SPColorSlider *slider, const guchar *map)
383 {
384 g_return_if_fail (slider != NULL);
385 g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
387 slider->map = (guchar *) map;
389 gtk_widget_queue_draw (GTK_WIDGET (slider));
390 }
392 void
393 sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size)
394 {
395 g_return_if_fail (slider != NULL);
396 g_return_if_fail (SP_IS_COLOR_SLIDER (slider));
398 slider->b0 = dark;
399 slider->b1 = light;
400 slider->bmask = size;
402 gtk_widget_queue_draw (GTK_WIDGET (slider));
403 }
405 static void
406 sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
407 {
408 gtk_widget_queue_draw (GTK_WIDGET (slider));
409 }
411 static void
412 sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider)
413 {
414 GtkWidget *widget;
416 widget = GTK_WIDGET (slider);
418 if (slider->value != ColorScales::getScaled( adjustment )) {
419 gint cx, cy, cw, ch;
420 cx = widget->style->xthickness;
421 cy = widget->style->ythickness;
422 cw = widget->allocation.width - 2 * cx;
423 ch = widget->allocation.height - 2 * cy;
424 if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) {
425 gint ax, ay;
426 gfloat value;
427 value = slider->value;
428 slider->value = ColorScales::getScaled( adjustment );
429 ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2);
430 ay = cy;
431 gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
432 ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2);
433 ay = cy;
434 gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch);
435 } else {
436 slider->value = ColorScales::getScaled( adjustment );
437 }
438 }
439 }
441 static void
442 sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area)
443 {
444 GtkWidget *widget;
445 GdkRectangle warea, carea, aarea;
446 GdkRectangle wpaint, cpaint, apaint;
447 const guchar *b;
448 gint w, x, y1, y2;
450 widget = GTK_WIDGET (slider);
452 /* Widget area */
453 warea.x = 0;
454 warea.y = 0;
455 warea.width = widget->allocation.width;
456 warea.height = widget->allocation.height;
458 /* Color gradient area */
459 carea.x = widget->style->xthickness;
460 carea.y = widget->style->ythickness;
461 carea.width = widget->allocation.width - 2 * carea.x;
462 carea.height = widget->allocation.height - 2 * carea.y;
464 /* Arrow area */
465 aarea.x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x);
466 aarea.width = ARROW_SIZE;
467 aarea.y = carea.y;
468 aarea.height = carea.height;
470 /* Actual paintable area */
471 if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return;
473 b = NULL;
475 /* Paintable part of color gradient area */
476 if (gdk_rectangle_intersect (area, &carea, &cpaint)) {
477 if (slider->map) {
478 gint s, d;
479 /* Render map pixelstore */
480 d = (1024 << 16) / carea.width;
481 s = (cpaint.x - carea.x) * d;
482 b = sp_color_slider_render_map (cpaint.x - carea.x, cpaint.y - carea.y, cpaint.width, cpaint.height,
483 slider->map, s, d,
484 slider->b0, slider->b1, slider->bmask);
485 if (b != NULL) {
486 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
487 cpaint.x, cpaint.y,
488 cpaint.width, cpaint.height,
489 GDK_RGB_DITHER_MAX,
490 (guchar *) b, cpaint.width * 3);
491 }
493 } else {
494 gint c[4], dc[4];
495 gint i;
496 /* Render gradient */
498 // part 1: from c0 to cm
499 if ((cpaint.x - carea.x) <= carea.width/2) {
500 for (i = 0; i < 4; i++) {
501 c[i] = slider->c0[i] << 16;
502 dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2);
503 c[i] += (cpaint.x - carea.x) * dc[i];
504 }
505 guint wi = MIN(cpaint.x - carea.x + cpaint.width, carea.width/2) - (cpaint.x - carea.x);
506 b = sp_color_slider_render_gradient (cpaint.x - carea.x, cpaint.y - carea.y, wi, cpaint.height,
507 c, dc,
508 slider->b0, slider->b1, slider->bmask);
510 /* Draw pixelstore */
511 if (b != NULL) {
512 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
513 cpaint.x, cpaint.y,
514 wi, cpaint.height,
515 GDK_RGB_DITHER_MAX,
516 (guchar *) b, wi * 3);
517 }
518 }
520 // part 2: from cm to c1
521 if ((cpaint.x - carea.x + cpaint.width) > carea.width/2) {
522 for (i = 0; i < 4; i++) {
523 c[i] = slider->cm[i] << 16;
524 dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2);
525 if ((cpaint.x - carea.x) > carea.width/2)
526 c[i] += (cpaint.x - carea.x - carea.width/2) * dc[i];
527 }
528 guint wi = cpaint.width - MAX(0, (carea.width/2 - (cpaint.x - carea.x)));
529 b = sp_color_slider_render_gradient (MAX(cpaint.x - carea.x, carea.width/2), cpaint.y - carea.y, wi, cpaint.height,
530 c, dc,
531 slider->b0, slider->b1, slider->bmask);
533 /* Draw pixelstore */
534 if (b != NULL) {
535 gdk_draw_rgb_image (widget->window, widget->style->black_gc,
536 MAX(cpaint.x, carea.width/2 + carea.x), cpaint.y,
537 wi, cpaint.height,
538 GDK_RGB_DITHER_MAX,
539 (guchar *) b, wi * 3);
540 }
541 }
542 }
543 }
545 /* Draw shadow */
546 gtk_paint_shadow (widget->style, widget->window,
547 (GtkStateType)widget->state, GTK_SHADOW_IN,
548 area, widget, "colorslider",
549 0, 0,
550 warea.width, warea.height);
553 if (gdk_rectangle_intersect (area, &aarea, &apaint)) {
554 /* Draw arrow */
555 gdk_rectangle_intersect (&carea, &apaint, &apaint);
556 gdk_gc_set_clip_rectangle (widget->style->white_gc, &apaint);
557 gdk_gc_set_clip_rectangle (widget->style->black_gc, &apaint);
559 x = aarea.x;
560 y1 = carea.y;
561 y2 = aarea.y + aarea.height - 1;
562 w = aarea.width;
563 while ( w > 0 )
564 {
565 gdk_draw_line (widget->window, widget->style->white_gc, x, y1, x + w - 1, y1 );
566 gdk_draw_line (widget->window, widget->style->white_gc, x, y2, x + w - 1, y2 );
567 w -=2;
568 x++;
569 if ( w > 0 )
570 {
571 gdk_draw_line (widget->window, widget->style->black_gc, x, y1, x + w - 1, y1 );
572 gdk_draw_line (widget->window, widget->style->black_gc, x, y2, x + w - 1, y2 );
573 }
574 y1++;
575 y2--;
576 }
578 gdk_gc_set_clip_rectangle (widget->style->white_gc, NULL);
579 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
580 }
581 }
583 /* Colors are << 16 */
585 static const guchar *
586 sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height,
587 gint c[], gint dc[], guint b0, guint b1, guint mask)
588 {
589 static guchar *buf = NULL;
590 static gint bs = 0;
591 guchar *dp;
592 gint x, y;
593 guint r, g, b, a;
595 if (buf && (bs < width * height)) {
596 g_free (buf);
597 buf = NULL;
598 }
599 if (!buf) {
600 buf = g_new (guchar, width * height * 3);
601 bs = width * height;
602 }
604 dp = buf;
605 r = c[0];
606 g = c[1];
607 b = c[2];
608 a = c[3];
609 for (x = x0; x < x0 + width; x++) {
610 gint cr, cg, cb, ca;
611 guchar *d;
612 cr = r >> 16;
613 cg = g >> 16;
614 cb = b >> 16;
615 ca = a >> 16;
616 d = dp;
617 for (y = y0; y < y0 + height; y++) {
618 guint bg, fc;
619 /* Background value */
620 bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
621 fc = (cr - bg) * ca;
622 d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
623 fc = (cg - bg) * ca;
624 d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
625 fc = (cb - bg) * ca;
626 d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
627 d += 3 * width;
628 }
629 r += dc[0];
630 g += dc[1];
631 b += dc[2];
632 a += dc[3];
633 dp += 3;
634 }
636 return buf;
637 }
639 /* Positions are << 16 */
641 static const guchar *
642 sp_color_slider_render_map (gint x0, gint y0, gint width, gint height,
643 guchar *map, gint start, gint step, guint b0, guint b1, guint mask)
644 {
645 static guchar *buf = NULL;
646 static gint bs = 0;
647 guchar *dp, *sp;
648 gint x, y;
650 if (buf && (bs < width * height)) {
651 g_free (buf);
652 buf = NULL;
653 }
654 if (!buf) {
655 buf = g_new (guchar, width * height * 3);
656 bs = width * height;
657 }
659 dp = buf;
660 for (x = x0; x < x0 + width; x++) {
661 gint cr, cg, cb, ca;
662 guchar *d;
663 sp = map + 4 * (start >> 16);
664 cr = *sp++;
665 cg = *sp++;
666 cb = *sp++;
667 ca = *sp++;
668 d = dp;
669 for (y = y0; y < y0 + height; y++) {
670 guint bg, fc;
671 /* Background value */
672 bg = ((x & mask) ^ (y & mask)) ? b0 : b1;
673 fc = (cr - bg) * ca;
674 d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
675 fc = (cg - bg) * ca;
676 d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
677 fc = (cb - bg) * ca;
678 d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8);
679 d += 3 * width;
680 }
681 dp += 3;
682 start += step;
683 }
685 return buf;
686 }