2 * This file is part of hildon-libs
4 * Copyright (C) 2005, 2006 Nokia Corporation.
6 * Author: Kuisma Salonen <kuisma.salonen@nokia.com>
7 * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; version 2.1 of
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28 #include <hildon-widgets/hildon-color-chooser.h>
31 const char *parent_name = "HildonColorChooser";
32 const char *plugin_name = "HSV color chooser";
34 GType export_type(void);
38 HildonColorChooser parent;
43 unsigned short currhue;
44 unsigned short currsat;
45 unsigned short currval;
51 GdkWindow *event_window;
55 unsigned short last_expose_hue;
57 GTimeVal last_expose_time;
61 } HildonColorChooserHSV;
64 HildonColorChooserClass parent;
65 } HildonColorChooserHSVClass;
68 #define HILDON_COLOR_CHOOSER_HSV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), export_type(), HildonColorChooserHSV))
69 #define HILDON_COLOR_CHOOSER_HSV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), export_type(), HildonColorChooserHSVClass))
72 static HildonColorChooserClass *parent_class = NULL;
75 /* "crosshair" is hardcoded for now */
76 static gchar crosshair[64] = { 0, 0, 0, 2, 2, 0, 0, 0,
77 0, 2, 2, 3, 3, 2, 2, 0,
78 0, 2, 3, 0, 0, 3, 2, 0,
79 2, 3, 0, 0, 0, 0, 3, 2,
80 2, 3, 0, 0, 0, 0, 3, 2,
81 0, 2, 3, 0, 0, 3, 2, 0,
82 0, 2, 2, 3, 3, 2, 2, 0,
83 0, 0, 0, 2, 2, 0, 0, 0};
86 static void hildon_color_chooser_hsv_init(HildonColorChooserHSV *sel);
87 static void hildon_color_chooser_hsv_class_init(HildonColorChooserHSVClass *klass);
89 static void hildon_color_chooser_hsv_destroy(GtkObject *obj);
91 static void hildon_color_chooser_hsv_size_request(GtkWidget *widget, GtkRequisition *req);
92 static void hildon_color_chooser_hsv_size_allocate(GtkWidget *widget, GtkAllocation *alloc);
94 static void hildon_color_chooser_hsv_realize(GtkWidget *widget);
96 static void hildon_color_chooser_hsv_map(GtkWidget *widget);
97 static void hildon_color_chooser_hsv_unmap(GtkWidget *widget);
99 static gboolean hildon_color_chooser_hsv_expose(GtkWidget *widget, GdkEventExpose *event);
101 static gboolean hildon_color_chooser_button_press(GtkWidget *widget, GdkEventButton *event);
102 static gboolean hildon_color_chooser_button_release(GtkWidget *widget, GdkEventButton *event);
103 static gboolean hildon_color_chooser_pointer_motion(GtkWidget *widget, GdkEventMotion *event);
105 static void hildon_color_chooser_hsv_set_color(HildonColorChooser *sel, GdkColor *color);
108 static void internal_get_border(GtkWidget *w, char *name, GtkBorder *b);
109 static void _internal_init_borders(GtkWidget *w, GtkBorder *inner, GtkBorder *outer);
111 static void internal_invoke_color_changed(HildonColorChooserHSV *sel);
114 inline void inline_clip_to_alloc(void *s, GtkAllocation *a);
116 inline void inline_sub_times(GTimeVal *result, GTimeVal *greater, GTimeVal *lesser);
118 inline void inline_limited_expose(HildonColorChooserHSV *sel);
120 inline void inline_draw_hue_bar(GtkWidget *widget, int x, int y, int w, int h, int sy, int sh);
121 inline void inline_draw_hue_bar_dimmed(GtkWidget *widget, int x, int y, int w, int h, int sy, int sh);
123 inline void inline_draw_sv_plane(HildonColorChooserHSV *sel, int x, int y, int w, int h);
124 inline void inline_draw_sv_plane_dimmed(HildonColorChooserHSV *sel, int x, int y, int w, int h);
126 inline void inline_draw_crosshair(unsigned char *buf, int x, int y, int w, int h);
129 inline void inline_h2rgb(unsigned short hue, unsigned long *rgb);
132 static gboolean hildon_color_chooser_hsv_expose_timer(gpointer data);
137 static GType chooser_type = 0;
140 static const GTypeInfo chooser_info =
142 sizeof (HildonColorChooserHSVClass),
145 (GClassInitFunc) hildon_color_chooser_hsv_class_init,
148 sizeof (HildonColorChooserHSV),
150 (GInstanceInitFunc) hildon_color_chooser_hsv_init,
154 chooser_type = g_type_register_static (HILDON_TYPE_COLOR_CHOOSER,
155 "HildonColorChooserHSV",
162 static void hildon_color_chooser_hsv_init(HildonColorChooserHSV *sel)
164 GTK_WIDGET_SET_FLAGS (sel, GTK_NO_WINDOW);
172 sel->mousein = FALSE;
175 g_get_current_time(&sel->expose_info.last_expose_time);
177 sel->expose_info.last_expose_hue = sel->currhue;
178 sel->expose_info.expose_queued = 0;
181 static void hildon_color_chooser_hsv_class_init(HildonColorChooserHSVClass *klass)
183 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
184 GtkObjectClass *object_class = GTK_OBJECT_CLASS(klass);
186 HildonColorChooserClass *selection_class = HILDON_COLOR_CHOOSER_CLASS(klass);
189 parent_class = g_type_class_peek_parent(klass);
192 object_class->destroy = hildon_color_chooser_hsv_destroy;
195 widget_class->size_request = hildon_color_chooser_hsv_size_request;
196 widget_class->size_allocate = hildon_color_chooser_hsv_size_allocate;
198 widget_class->realize = hildon_color_chooser_hsv_realize;
200 widget_class->map = hildon_color_chooser_hsv_map;
201 widget_class->unmap = hildon_color_chooser_hsv_unmap;
203 widget_class->expose_event = hildon_color_chooser_hsv_expose;
205 widget_class->button_press_event = hildon_color_chooser_button_press;
206 widget_class->button_release_event = hildon_color_chooser_button_release;
207 widget_class->motion_notify_event = hildon_color_chooser_pointer_motion;
210 selection_class->set_color = hildon_color_chooser_hsv_set_color;
213 gtk_widget_class_install_style_property(widget_class,
214 g_param_spec_boxed("inner_size",
216 "Sizes of SV plane, H bar and spacing",
219 gtk_widget_class_install_style_property(widget_class,
220 g_param_spec_boxed("graphic_border",
222 "Size of graphical border",
228 static void hildon_color_chooser_hsv_destroy(GtkObject *obj)
230 GTK_OBJECT_CLASS(parent_class)->destroy(obj);
234 static void hildon_color_chooser_hsv_size_request(GtkWidget *widget, GtkRequisition *req)
236 GtkBorder inner, outer;
239 _internal_init_borders(widget, &inner, &outer);
242 req->width = inner.left + inner.top + inner.bottom + outer.left + outer.right;
243 req->height = inner.right + outer.top + outer.bottom;
246 static void hildon_color_chooser_hsv_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
248 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(widget);
249 GtkBorder outer, inner;
252 widget->allocation = *alloc;
255 _internal_init_borders(widget, &inner, &outer);
258 sel->hba.height = alloc->height - outer.top - outer.bottom;
259 sel->hba.y = alloc->y + outer.top;
260 sel->hba.width = inner.top;
261 sel->hba.x = alloc->x + alloc->width - outer.right - inner.top;
263 sel->spa.x = alloc->x + outer.left;
264 sel->spa.y = alloc->y + outer.top;
265 sel->spa.height = alloc->height - outer.top - outer.bottom;
266 sel->spa.width = alloc->width - outer.left - outer.right - inner.top - inner.bottom;
269 if(GTK_WIDGET_REALIZED(widget)) {
270 gdk_window_move_resize(sel->event_window, widget->allocation.x, widget->allocation.y, widget->allocation.width, widget->allocation.height);
275 static void hildon_color_chooser_hsv_realize(GtkWidget *widget)
277 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(widget);
278 GdkWindowAttr attributes;
279 gint attributes_mask;
281 attributes.x = widget->allocation.x;
282 attributes.y = widget->allocation.y;
283 attributes.width = widget->allocation.width;
284 attributes.height = widget->allocation.height;
285 attributes.wclass = GDK_INPUT_ONLY;
286 attributes.window_type = GDK_WINDOW_CHILD;
287 attributes.event_mask = gtk_widget_get_events(widget) | GDK_BUTTON_PRESS_MASK |
288 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
289 GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK |
290 GDK_BUTTON1_MOTION_MASK;
291 attributes.visual = gtk_widget_get_visual(widget);
292 attributes.colormap = gtk_widget_get_colormap(widget);
294 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_WMCLASS;
295 sel->event_window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
298 gdk_window_set_user_data(sel->event_window, widget);
301 widget->window = gtk_widget_get_parent_window(widget);
304 widget->style = gtk_style_attach(widget->style, widget->window);
307 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
311 static void hildon_color_chooser_hsv_map(GtkWidget *widget)
313 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(widget);
316 GTK_WIDGET_CLASS(parent_class)->map(widget);
318 if(sel->event_window) {
319 gdk_window_show(sel->event_window);
323 static void hildon_color_chooser_hsv_unmap(GtkWidget *widget)
325 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(widget);
328 if(sel->event_window) {
329 gdk_window_hide(sel->event_window);
332 GTK_WIDGET_CLASS(parent_class)->unmap(widget);
336 inline void inline_clip_to_alloc(void *s, GtkAllocation *a)
344 area->w -= a->x - area->x;
346 } if(area->y < a->y) {
347 area->h -= a->y - area->y;
350 if(area->x + area->w > a->x + a->width) area->w = a->width - (area->x - a->x);
351 if(area->y + area->h > a->y + a->height) area->h = a->height - (area->y - a->y);
354 static gboolean hildon_color_chooser_hsv_expose(GtkWidget *widget, GdkEventExpose *event)
356 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(widget);
357 GtkBorder graphical_border;
363 if(!GTK_WIDGET_REALIZED(widget)) {
368 internal_get_border(widget, "graphic_border", &graphical_border);
371 if(event->area.width || event->area.height) {
372 if(graphical_border.top) {
373 gtk_paint_box(gtk_widget_get_style(widget), widget->window, GTK_WIDGET_STATE(widget),
374 GTK_SHADOW_NONE, &event->area, widget, "border-top",
375 sel->hba.x - graphical_border.left, sel->hba.y - graphical_border.top,
376 sel->hba.width + graphical_border.left + graphical_border.right,
377 graphical_border.top);
378 gtk_paint_box(gtk_widget_get_style(widget), widget->window, GTK_WIDGET_STATE(widget),
379 GTK_SHADOW_NONE, &event->area, widget, "border-top",
380 sel->spa.x - graphical_border.left, sel->spa.y - graphical_border.top,
381 sel->spa.width + graphical_border.left + graphical_border.right,
382 graphical_border.top);
385 if(graphical_border.bottom) {
386 gtk_paint_box(gtk_widget_get_style(widget), widget->window, GTK_WIDGET_STATE(widget),
387 GTK_SHADOW_NONE, &event->area, widget, "border-bottom",
388 sel->hba.x - graphical_border.left, sel->hba.y + sel->hba.height,
389 sel->hba.width + graphical_border.left + graphical_border.right,
390 graphical_border.bottom);
391 gtk_paint_box(gtk_widget_get_style(widget), widget->window, GTK_WIDGET_STATE(widget),
392 GTK_SHADOW_NONE, &event->area, widget, "border-bottom",
393 sel->spa.x - graphical_border.left, sel->spa.y + sel->spa.height,
394 sel->spa.width + graphical_border.left + graphical_border.right,
395 graphical_border.bottom);
398 if(graphical_border.left) {
399 gtk_paint_box(gtk_widget_get_style(widget), widget->window, GTK_WIDGET_STATE(widget),
400 GTK_SHADOW_NONE, &event->area, widget, "border-left",
401 sel->hba.x - graphical_border.left, sel->hba.y,
402 graphical_border.left, sel->hba.height);
403 gtk_paint_box(gtk_widget_get_style(widget), widget->window, GTK_WIDGET_STATE(widget),
404 GTK_SHADOW_NONE, &event->area, widget, "border-left",
405 sel->spa.x - graphical_border.left, sel->spa.y,
406 graphical_border.left, sel->spa.height);
409 if(graphical_border.right) {
410 gtk_paint_box(gtk_widget_get_style(widget), widget->window, GTK_WIDGET_STATE(widget),
411 GTK_SHADOW_NONE, &event->area, widget, "border-right",
412 sel->hba.x + sel->hba.width, sel->hba.y,
413 graphical_border.right, sel->hba.height);
414 gtk_paint_box(gtk_widget_get_style(widget), widget->window, GTK_WIDGET_STATE(widget),
415 GTK_SHADOW_NONE, &event->area, widget, "border-right",
416 sel->spa.x + sel->spa.width, sel->spa.y,
417 graphical_border.right, sel->spa.height);
422 if(sel->expose_info.expose_queued) {
423 if(GTK_WIDGET_SENSITIVE(widget)) {
424 inline_draw_hue_bar(widget, sel->hba.x, sel->hba.y, sel->hba.width, sel->hba.height, sel->hba.y, sel->hba.height);
426 inline_draw_sv_plane(sel, sel->spa.x, sel->spa.y, sel->spa.width, sel->spa.height);
428 inline_draw_hue_bar_dimmed(widget, sel->hba.x, sel->hba.y, sel->hba.width, sel->hba.height, sel->hba.y, sel->hba.height);
430 inline_draw_sv_plane_dimmed(sel, sel->spa.x, sel->spa.y, sel->spa.width, sel->spa.height);
434 sel->expose_info.expose_queued = 0;
436 g_get_current_time(&sel->expose_info.last_expose_time);
438 /* clip hue bar region */
439 area.x = event->area.x;
440 area.y = event->area.y;
441 area.w = event->area.width;
442 area.h = event->area.height;
444 inline_clip_to_alloc(&area, &sel->hba);
446 if(GTK_WIDGET_SENSITIVE(widget)) {
447 inline_draw_hue_bar(widget, area.x, area.y, area.w, area.h, sel->hba.y, sel->hba.height);
449 inline_draw_hue_bar_dimmed(widget, area.x, area.y, area.w, area.h, sel->hba.y, sel->hba.height);
453 area.x = event->area.x;
454 area.y = event->area.y;
455 area.w = event->area.width;
456 area.h = event->area.height;
458 inline_clip_to_alloc(&area, &sel->spa);
460 if(GTK_WIDGET_SENSITIVE(widget)) {
461 inline_draw_sv_plane(sel, area.x, area.y, area.w, area.h);
463 inline_draw_sv_plane_dimmed(sel, area.x, area.y, area.w, area.h);
472 inline void inline_sub_times(GTimeVal *result, GTimeVal *greater, GTimeVal *lesser)
474 result->tv_sec = greater->tv_sec - lesser->tv_sec;
475 result->tv_usec = greater->tv_usec - lesser->tv_usec;
477 if(result->tv_usec < 0) {
479 result->tv_usec += 1000000;
483 #define EXPOSE_INTERVAL 50000
484 inline void inline_limited_expose(HildonColorChooserHSV *sel)
486 GTimeVal curr_time, result;
487 GdkEventExpose event;
490 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sel))) {
495 if(sel->currhue == sel->expose_info.last_expose_hue) {
496 return; /* no need to redraw */
500 sel->expose_info.last_expose_hue = sel->currhue;
503 g_get_current_time(&curr_time);
505 inline_sub_times(&result, &curr_time, &sel->expose_info.last_expose_time);
507 if(result.tv_sec != 0 || result.tv_usec >= EXPOSE_INTERVAL) {
508 sel->expose_info.expose_queued = 1;
511 event.type = GDK_EXPOSE;
512 event.area.width = 0;
513 event.area.height = 0;
514 event.window = GTK_WIDGET(sel)->window;
516 gtk_widget_send_expose(GTK_WIDGET(sel), (GdkEvent *)&event);
518 gtk_widget_queue_draw(GTK_WIDGET(sel));
520 } else if(!sel->expose_info.expose_queued) {
521 sel->expose_info.expose_queued = 1;
524 g_timeout_add((EXPOSE_INTERVAL - result.tv_usec)/1000, hildon_color_chooser_hsv_expose_timer, sel);
528 static gboolean hildon_color_chooser_button_press(GtkWidget *widget, GdkEventButton *event)
530 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(widget);
534 x = (int)event->x + widget->allocation.x;
535 y = (int)event->y + widget->allocation.y;
538 if(x >= sel->spa.x && x <= sel->spa.x + sel->spa.width &&
539 y >= sel->spa.y && y <= sel->spa.y + sel->spa.height) {
540 tmp = y - sel->spa.y;
541 sel->currsat = tmp * 0xffff / sel->spa.height;
542 tmp = x - sel->spa.x;
543 sel->currval = tmp * 0xffff / sel->spa.width;
545 internal_invoke_color_changed(sel);
546 gtk_widget_queue_draw(widget);
551 gtk_grab_add(widget);
552 } else if(x >= sel->hba.x && x <= sel->hba.x + sel->hba.width &&
553 y >= sel->hba.y && y <= sel->hba.y + sel->hba.height) {
554 tmp = y - sel->hba.y;
555 sel->currhue = tmp * 0xffff / sel->hba.height;
557 internal_invoke_color_changed(sel);
558 inline_limited_expose(sel);
563 gtk_grab_add(widget);
570 static gboolean hildon_color_chooser_button_release(GtkWidget *widget, GdkEventButton *event)
572 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(widget);
575 if(sel->mousestate) {
576 gtk_grab_remove(widget);
581 sel->mousein = FALSE;
587 static gboolean hildon_color_chooser_pointer_motion(GtkWidget *widget, GdkEventMotion *event)
589 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(widget);
590 GdkModifierType mods;
594 if (event->is_hint || (event->window != widget->window))
595 gdk_window_get_pointer (widget->window, &x, &y, &mods);
598 if(sel->mousestate == 1) {
599 if(x >= sel->spa.x && x <= sel->spa.x + sel->spa.width &&
600 y >= sel->spa.y && y <= sel->spa.y + sel->spa.height) {
601 sel->currsat = (((long)(y - sel->spa.y)) * 0xffff)/sel->spa.height;
602 sel->currval = (((long)(x - sel->spa.x)) * 0xffff)/sel->spa.width;
604 internal_invoke_color_changed(sel);
605 gtk_widget_queue_draw(widget);
606 } else if(sel->mousein == TRUE) {
608 } else if(sel->mousestate == 2) {
609 if(x >= sel->hba.x && x <= sel->hba.x + sel->hba.width &&
610 y >= sel->hba.y && y <= sel->hba.y + sel->hba.height) {
611 tmp = y - sel->hba.y;
613 tmp /= sel->hba.height;
615 if(tmp != sel->currhue) {
618 internal_invoke_color_changed(sel);
619 inline_limited_expose(sel);
621 } else if(sel->mousein == TRUE) {
629 static void internal_get_border(GtkWidget *w, char *name, GtkBorder *b)
633 gtk_widget_style_get(w, name, &tb, NULL);
647 static void _internal_init_borders(GtkWidget *w, GtkBorder *inner, GtkBorder *outer)
652 internal_get_border(w, "outer_border", outer);
655 gtk_widget_style_get(w, "inner_size", &tb, NULL);
667 if(inner->left < 2) inner->left = 2;
668 if(inner->right < 2) inner->right = 2;
669 if(inner->top < 2) inner->top = 2;
672 /* calculate RGB color & emit signal */
673 static void internal_invoke_color_changed(HildonColorChooserHSV *sel)
675 HildonColorChooser *parent_sel = HILDON_COLOR_CHOOSER(sel);
676 GdkVisual *system_visual = gdk_visual_get_system();
677 unsigned long rgb[3], rgb2[3];
680 inline_h2rgb(sel->currhue, rgb);
682 rgb2[0] = 0xffffff - rgb[0];
683 rgb2[1] = 0xffffff - rgb[1];
684 rgb2[2] = 0xffffff - rgb[2];
687 parent_sel->color.red = ((rgb[0] >> 8) + ((rgb2[0] >> 8) * (0xffff - sel->currsat) / 0xffff)) * sel->currval / 0xffff;
688 parent_sel->color.green = ((rgb[1] >> 8) + ((rgb2[1] >> 8) * (0xffff - sel->currsat) / 0xffff)) * sel->currval / 0xffff;
689 parent_sel->color.blue = ((rgb[2] >> 8) + ((rgb2[2] >> 8) * (0xffff - sel->currsat) / 0xffff)) * sel->currval / 0xffff;
691 parent_sel->color.pixel = ((parent_sel->color.red >> (16 - system_visual->red_prec)) << system_visual->red_shift) |
692 ((parent_sel->color.green >> (16 - system_visual->green_prec)) << system_visual->green_shift) |
693 ((parent_sel->color.blue >> (16 - system_visual->blue_prec)) << system_visual->blue_shift);
696 hildon_color_chooser_emit_color_changed(HILDON_COLOR_CHOOSER(sel));
699 /* do the RGB -> HSV conversion here, not so time critical */
700 static void hildon_color_chooser_hsv_set_color(HildonColorChooser *sel, GdkColor *color)
702 HildonColorChooserHSV *sel_hsv = HILDON_COLOR_CHOOSER_HSV(sel);
703 unsigned short hue, sat, val;
704 unsigned long min, max;
705 signed long tmp, diff;
708 min = MIN(MIN(color->red, color->green), color->blue);
709 max = MAX(MAX(color->red, color->green), color->blue);
715 if(val > 0 && diff != 0) {
716 sat = (diff * 0x0000ffff) / max;
718 if(color->red == max) {
719 tmp = (signed)color->green - (signed)color->blue;
726 } else if(color->green == max) {
727 hue = (((signed long)color->blue - (signed long)color->red)*10922 / diff) + 21844;
729 hue = (((signed long)color->red - (signed long)color->green)*10922 / diff) + 43688;
737 sel_hsv->currhue = hue;
738 sel_hsv->currsat = sat;
739 sel_hsv->currval = val;
742 inline_limited_expose(sel_hsv);
746 #define FULL_COLOR 0x00ffffff
747 inline void inline_h2rgb(unsigned short hue, unsigned long *rgb)
749 unsigned short hue_rotation, hue_value;
751 hue_rotation = hue / 10922;
752 hue_value = hue % 10922;
755 switch(hue_rotation) {
759 rgb[1] = hue_value * 6*256;
763 rgb[0] = FULL_COLOR - (hue_value * 6*256);
770 rgb[2] = hue_value * 6*256;
774 rgb[1] = FULL_COLOR - (hue_value * 6*256);
778 rgb[0] = hue_value * 6*256;
785 rgb[2] = FULL_COLOR - (hue_value * 6*256);
795 #define FULL_COLOR8 0xff
796 static void intern_h2rgb8(unsigned short hue, unsigned char *rgb)
798 unsigned short hue_rotation, hue_value;
801 hue_rotation = hue / 42;
802 hue_value = hue % 42;
805 switch(hue_rotation) {
808 rgb[0] = FULL_COLOR8;
809 rgb[1] = hue_value * 6;
813 rgb[0] = FULL_COLOR8 - (hue_value * 6);
814 rgb[1] = FULL_COLOR8;
819 rgb[1] = FULL_COLOR8;
820 rgb[2] = hue_value * 6;
824 rgb[1] = FULL_COLOR8 - (hue_value * 6);
825 rgb[2] = FULL_COLOR8;
828 rgb[0] = hue_value * 6;
830 rgb[2] = FULL_COLOR8;
833 rgb[0] = FULL_COLOR8;
835 rgb[2] = FULL_COLOR8 - (hue_value * 6);
846 /* optimization: do not ask hue for each round but have bilinear vectors */
847 /* rethink: benefits from handling data 8 bit? (no shift round) */
848 inline void inline_draw_hue_bar(GtkWidget *widget, int x, int y, int w, int h, int sy, int sh)
850 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(widget);
851 unsigned short hvec, hcurr;
852 unsigned char *buf, *ptr, tmp[3];
856 if(w <= 0 || h <= 0) {
861 buf = (unsigned char *)g_malloc(w*h*3);
864 hcurr = hvec * (y - sy);
869 for(i = 0; i < h; i++) {
870 intern_h2rgb8(hcurr, tmp);
872 for(j = 0; j < w; j++) {
883 gdk_draw_rgb_image(widget->parent->window, widget->style->fg_gc[0], x, y, w, h, GDK_RGB_DITHER_NONE, buf, w*3);
885 tmpy = sel->hba.y + (sel->currhue * sel->hba.height / 0xffff);
886 gdk_draw_line(widget->parent->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], sel->hba.x, tmpy, sel->hba.x + sel->hba.width - 1, tmpy);
888 if((((sel->currhue * sel->hba.height) & 0xffff) > 0x8000) && (tmpy < (sel->hba.y + sel->hba.height))) {
889 gdk_draw_line(widget->parent->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], sel->hba.x, tmpy+1, sel->hba.x + sel->hba.width - 1, tmpy+1);
890 } else if(tmpy > sel->hba.y) {
891 gdk_draw_line(widget->parent->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], sel->hba.x, tmpy-1, sel->hba.x + sel->hba.width - 1, tmpy-1);
898 inline void inline_draw_hue_bar_dimmed(GtkWidget *widget, int x, int y, int w, int h, int sy, int sh)
900 unsigned short hvec, hcurr, avg;
901 unsigned char *buf, *ptr, tmp[3];
905 if(w <= 0 || h <= 0) {
910 buf = (unsigned char *)g_malloc(w*h*3);
913 hcurr = hvec * (y - sy);
918 for(i = 0; i < h; i++) {
919 intern_h2rgb8(hcurr, tmp);
921 for(j = 0; j < w; j++) {
922 avg = ((unsigned short)tmp[0]*3 + (unsigned short)tmp[1]*2 + (unsigned short)tmp[2])/6;
933 gdk_draw_rgb_image(widget->parent->window, widget->style->fg_gc[0], x, y, w, h, GDK_RGB_DITHER_NONE, buf, w*3);
940 inline void inline_draw_crosshair(unsigned char *buf, int x, int y, int w, int h)
944 /* bad "clipping", clip the loop to save cpu */
945 for(i = 0; i < 8; i++) {
946 for(j = 0; j < 8; j++) {
947 sx = j + x; sy = i + y;
949 if(sx >= 0 && sx < w && sy >= 0 && sx < h) {
950 if(crosshair[j + 8*i]) {
951 if(crosshair[j + 8*i] & 0x1) {
952 buf[(sx)*3+(sy)*w*3+0] = 255;
953 buf[(sx)*3+(sy)*w*3+1] = 255;
954 buf[(sx)*3+(sy)*w*3+2] = 255;
956 buf[(sx)*3+(sy)*w*3+0] = 0;
957 buf[(sx)*3+(sy)*w*3+1] = 0;
958 buf[(sx)*3+(sy)*w*3+2] = 0;
967 inline void inline_draw_sv_plane(HildonColorChooserHSV *sel, int x, int y, int w, int h)
969 GtkWidget *widget = GTK_WIDGET(sel);
970 unsigned char *buf, *ptr;
971 unsigned long rgbx[3] = { 0x00ffffff, 0x00ffffff, 0x00ffffff }, rgbtmp[3];
973 int tmp = sel->spa.width*sel->spa.height, i, j;
976 if(w <= 0 || h <= 0) {
981 buf = (unsigned char *)g_malloc(w*h*3);
986 inline_h2rgb(sel->currhue, rgbtmp);
988 rgby[0] = rgbtmp[0] - rgbx[0];
989 rgby[1] = rgbtmp[1] - rgbx[1];
990 rgby[2] = rgbtmp[2] - rgbx[2];
992 rgbx[0] /= sel->spa.width;
993 rgbx[1] /= sel->spa.width;
994 rgbx[2] /= sel->spa.width;
1001 rgbx[0] += (y - sel->spa.y)*rgby[0];
1002 rgbx[1] += (y - sel->spa.y)*rgby[1];
1003 rgbx[2] += (y - sel->spa.y)*rgby[2];
1006 for(i = 0; i < h; i++) {
1007 rgbtmp[0] = rgbx[0] * (x - sel->spa.x);
1008 rgbtmp[1] = rgbx[1] * (x - sel->spa.x);
1009 rgbtmp[2] = rgbx[2] * (x - sel->spa.x);
1011 for(j = 0; j < w; j++) {
1012 ptr[0] = rgbtmp[0] >> 16;
1013 ptr[1] = rgbtmp[1] >> 16;
1014 ptr[2] = rgbtmp[2] >> 16;
1015 rgbtmp[0] += rgbx[0];
1016 rgbtmp[1] += rgbx[1];
1017 rgbtmp[2] += rgbx[2];
1027 inline_draw_crosshair(buf, (sel->spa.width * sel->currval / 0xffff) - x + sel->spa.x - 4, (sel->spa.height * sel->currsat / 0xffff) - y + sel->spa.y - 4, w, h);
1030 gdk_draw_rgb_image(widget->parent->window, widget->style->fg_gc[0], x, y, w, h, GDK_RGB_DITHER_NONE, buf, w*3);
1036 inline void inline_draw_sv_plane_dimmed(HildonColorChooserHSV *sel, int x, int y, int w, int h)
1038 GtkWidget *widget = GTK_WIDGET(sel);
1039 unsigned char *buf, *ptr;
1040 unsigned long rgbx[3] = { 0x00ffffff, 0x00ffffff, 0x00ffffff }, rgbtmp[3];
1042 signed long rgby[3];
1043 int tmp = sel->spa.width*sel->spa.height, i, j;
1046 if(w <= 0 || h <= 0) {
1051 buf = (unsigned char *)g_malloc(w*h*3);
1056 /* possibe optimization: as we are drawing grayscale plane, there might
1057 be some simpler algorithm to do this*/
1058 rgbtmp[0] = 0x00ffffff;
1059 rgbtmp[1] = 0x00000000;
1060 rgbtmp[2] = 0x00000000;
1062 rgby[0] = rgbtmp[0] - rgbx[0];
1063 rgby[1] = rgbtmp[1] - rgbx[1];
1064 rgby[2] = rgbtmp[2] - rgbx[2];
1066 rgbx[0] /= sel->spa.width;
1067 rgbx[1] /= sel->spa.width;
1068 rgbx[2] /= sel->spa.width;
1075 rgbx[0] += (y - sel->spa.y)*rgby[0];
1076 rgbx[1] += (y - sel->spa.y)*rgby[1];
1077 rgbx[2] += (y - sel->spa.y)*rgby[2];
1080 for(i = 0; i < h; i++) {
1081 rgbtmp[0] = rgbx[0] * (x - sel->spa.x);
1082 rgbtmp[1] = rgbx[1] * (x - sel->spa.x);
1083 rgbtmp[2] = rgbx[2] * (x - sel->spa.x);
1085 for(j = 0; j < w; j++) {
1086 avg = (rgbtmp[0] + rgbtmp[1] + rgbtmp[2])/3;
1091 rgbtmp[0] += rgbx[0];
1092 rgbtmp[1] += rgbx[1];
1093 rgbtmp[2] += rgbx[2];
1103 gdk_draw_rgb_image(widget->parent->window, widget->style->fg_gc[0], x, y, w, h, GDK_RGB_DITHER_NONE, buf, w*3);
1110 static gboolean hildon_color_chooser_hsv_expose_timer(gpointer data)
1112 HildonColorChooserHSV *sel = HILDON_COLOR_CHOOSER_HSV(data);
1115 if(sel->expose_info.expose_queued) {
1116 gtk_widget_queue_draw(GTK_WIDGET(data));