bd3589cd3efb9d68acafd35645edb0fca1ba7102
[hildon] / src / hildon-color-chooser-dialog.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
5  *
6  * Author: Kuisma Salonen <kuisma.salonen@nokia.com>
7  * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
8  *
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
12  * the License.
13  *
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.
18  *
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
22  * 02110-1301 USA
23  *
24  */
25
26 /**
27  * SECTION:hildon-color-chooser-dialog
28  * @short_description: A dialog used to select a color from HSV colorspace
29  * @see_also: #HildonColorButton
30  *
31  * HildonColorChooserDialog enables the user to 
32  * select an arbitrary color from a HSV colorspace.
33  * The color is stored in one of the predefined color 
34  * slots and can be reselected later on. 
35  *
36  * Additionally the user can choose one of the standard "factory"
37  * colors.
38  *
39  */
40
41
42 #ifdef                                          HAVE_CONFIG_H
43 #include                                        <config.h>
44 #endif
45
46 #include                                        <memory.h>
47 #include                                        <string.h>
48 #include                                        <libintl.h>
49 #include                                        <gdk/gdk.h>
50 #include                                        <gdk/gdkkeysyms.h>
51 #include                                        <gtk/gtk.h>
52 #include                                        <gconf/gconf-client.h>
53 #include                                        "hildon-color-chooser-dialog.h"
54 #include                                        "hildon-color-chooser.h"
55 #include                                        "hildon-defines.h"
56 #include                                        "hildon-banner.h"
57 #include                                        "hildon-color-chooser-dialog-private.h"
58
59 #define                                         _(String) dgettext("hildon-libs", String)
60
61 static HildonColorChooserDialogClass*           parent_class = NULL;
62
63 /* darkened EGA palette to be used as predefined colors if style doesn't
64    define anything else (darker colors are darkened 0x8000 -> 0x6666) */
65 static GdkColor hardcoded_colors[16] =          {{0, 0x0000, 0x0000, 0x0000},
66                                                  {0, 0x6666, 0x6666, 0x6666},
67                                                  {0, 0x6666, 0x0000, 0x0000},
68                                                  {0, 0x0000, 0x6666, 0x0000},
69                                                  {0, 0x0000, 0x0000, 0x6666},
70                                                  {0, 0x6666, 0x6666, 0x0000},
71                                                  {0, 0x6666, 0x0000, 0x6666},
72                                                  {0, 0x0000, 0x6666, 0x6666},
73                                                  {0, 0xffff, 0xffff, 0xffff},
74                                                  {0, 0xc000, 0xc000, 0xc000},
75                                                  {0, 0xffff, 0x0000, 0x0000},
76                                                  {0, 0x0000, 0xffff, 0x0000},
77                                                  {0, 0x0000, 0x0000, 0xffff},
78                                                  {0, 0xffff, 0xffff, 0x0000},
79                                                  {0, 0xffff, 0x0000, 0xffff},
80                                                  {0, 0x0000, 0xffff, 0xffff}};
81
82 static void
83 hildon_color_chooser_dialog_init                (HildonColorChooserDialog *object);
84
85 static void 
86 hildon_color_chooser_dialog_class_init          (HildonColorChooserDialogClass *klass);
87
88 static void 
89 hildon_color_chooser_dialog_size_request        (GtkWidget *widget, 
90                                                  GtkRequisition *req);
91
92 static void
93 hildon_color_chooser_dialog_size_allocate       (GtkWidget *widget, 
94                                                  GtkAllocation *alloc);
95
96 static void 
97 hildon_color_chooser_dialog_realize             (GtkWidget *widget);
98
99 static void
100 hildon_color_chooser_dialog_unrealize           (GtkWidget *widget);
101
102 static void 
103 hildon_color_chooser_dialog_style_set           (GtkWidget *widget, 
104                                                  GtkStyle *previous_style);
105
106 static void 
107 hildon_color_chooser_dialog_show                (GtkWidget *widget);
108
109 static void 
110 hildon_color_chooser_dialog_show_all            (GtkWidget *widget);
111
112 static gboolean 
113 hildon_color_chooser_dialog_key_press_event     (GtkWidget *widget, 
114                                                  GdkEventKey *event);
115
116 static gboolean 
117 hildon_color_chooser_dialog_key_release_event   (GtkWidget *widget, 
118                                                  GdkEventKey *event);
119
120 static void 
121 hildon_color_chooser_dialog_destroy             (GtkObject *object);
122
123 static gboolean 
124 hildon_color_chooser_dialog_area_expose         (GtkWidget *widget, 
125                                                  GdkEventExpose *event, 
126                                                  gpointer data);
127
128 static gboolean 
129 hildon_color_chooser_dialog_area_button_press   (GtkWidget *widget, 
130                                                  GdkEventButton *event, 
131                                                  gpointer data);
132
133 static void 
134 hildon_color_chooser_dialog_color_changed       (HildonColorChooser *chooser, 
135                                                  gpointer data);
136
137 static void 
138 hildon_color_chooser_dialog_insensitive_press   (GtkWidget *widget, 
139                                                  gpointer data);
140
141 static void 
142 hildon_color_chooser_dialog_refresh_style_info  (HildonColorChooserDialog *dialog);
143
144 static void 
145 hildon_color_chooser_dialog_set_color_num       (HildonColorChooserDialog *dialog, 
146                                                  gint num);
147
148 static void 
149 hildon_color_chooser_dialog_ascii_hex_to_color  (gchar *s, 
150                                                  GdkColor *color);
151
152 static void 
153 hildon_color_chooser_dialog_color_to_ascii_hex  (gchar *s, 
154                                                  GdkColor *color);
155
156 GType G_GNUC_CONST
157 hildon_color_chooser_dialog_get_type            (void)
158 {
159     static GType dialog_type = 0;
160
161     if (!dialog_type) {
162         static const GTypeInfo dialog_info =
163         {
164             sizeof (HildonColorChooserDialogClass),
165             NULL,
166             NULL,
167             (GClassInitFunc) hildon_color_chooser_dialog_class_init,
168             NULL,
169             NULL,
170             sizeof (HildonColorChooserDialog),
171             0,
172             (GInstanceInitFunc) hildon_color_chooser_dialog_init,
173             NULL
174         };
175
176         dialog_type = g_type_register_static (GTK_TYPE_DIALOG, 
177                 "HildonColorChooserDialog", &dialog_info, 0);
178     }
179
180     return dialog_type;
181 }
182
183 static void 
184 hildon_color_chooser_dialog_init                (HildonColorChooserDialog *object)
185 {
186     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (object);
187
188     gtk_dialog_set_has_separator (GTK_DIALOG (object), FALSE);
189     gtk_window_set_title (GTK_WINDOW (object), _("ecdg_ti_colour_selector"));
190
191     g_assert (priv);
192
193     priv->hbox = gtk_hbox_new (FALSE, 0);
194     priv->vbox = gtk_vbox_new (FALSE, 0);
195     priv->chooser = hildon_color_chooser_new ();
196
197     gtk_box_pack_start (GTK_BOX (priv->hbox), priv->chooser, TRUE, TRUE, 0);
198     gtk_box_pack_end (GTK_BOX (priv->hbox), priv->vbox, FALSE, FALSE, 0);
199
200     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (object)->vbox), priv->hbox, TRUE, TRUE, 0);
201
202
203     priv->align_custom = gtk_alignment_new (0.5, 1.0, 0.0, 0.0);
204     priv->align_defined = gtk_alignment_new (0.5, 1.0, 0.0, 0.0);
205
206     priv->area_custom = gtk_drawing_area_new ();
207     priv->area_defined = gtk_drawing_area_new ();
208
209     gtk_container_add (GTK_CONTAINER (priv->align_custom), priv->area_custom);
210     gtk_container_add (GTK_CONTAINER (priv->align_defined), priv->area_defined);
211
212     priv->separator = gtk_hseparator_new ();
213
214     gtk_box_pack_start (GTK_BOX (priv->vbox), priv->align_defined, FALSE, FALSE, 0);
215     gtk_box_pack_start (GTK_BOX (priv->vbox), priv->separator, FALSE, FALSE, 0);
216     gtk_box_pack_start (GTK_BOX (priv->vbox), priv->align_custom, FALSE, FALSE, 0);
217
218     gtk_dialog_add_button (GTK_DIALOG (object), _("ecdg_bd_colour_selector_ok"), GTK_RESPONSE_OK);
219     gtk_dialog_add_button (GTK_DIALOG (object), _("ecdg_bd_colour_selector_cancel"), GTK_RESPONSE_CANCEL);
220     gtk_dialog_set_default_response (GTK_DIALOG (object), GTK_RESPONSE_OK);
221
222     g_signal_connect (G_OBJECT (priv->chooser), 
223             "insensitive-press", G_CALLBACK (hildon_color_chooser_dialog_insensitive_press), object);
224
225     g_signal_connect (G_OBJECT (priv->area_custom), 
226             "expose-event", G_CALLBACK (hildon_color_chooser_dialog_area_expose), object);
227
228     g_signal_connect (G_OBJECT (priv->area_defined), 
229             "expose-event", G_CALLBACK (hildon_color_chooser_dialog_area_expose), object);
230
231     g_signal_connect (G_OBJECT (priv->area_custom), 
232             "button-press-event", G_CALLBACK (hildon_color_chooser_dialog_area_button_press), object);
233
234     g_signal_connect (G_OBJECT (priv->area_defined), 
235             "button-press-event", G_CALLBACK (hildon_color_chooser_dialog_area_button_press), object);
236
237     g_signal_connect (G_OBJECT (priv->chooser), 
238             "color-changed", G_CALLBACK (hildon_color_chooser_dialog_color_changed), object);
239
240     gtk_widget_add_events (priv->area_custom, GDK_BUTTON_PRESS_MASK);
241     gtk_widget_add_events (priv->area_defined, GDK_BUTTON_PRESS_MASK);
242
243     priv->selected = 0;
244     priv->gconf_client = gconf_client_get_default ();
245
246     memset (&priv->style_info, 0, sizeof (HildonColorChooserStyleInfo));
247     
248     priv->colors_custom = NULL;
249     priv->colors_defined = NULL;
250     priv->gc_array = NULL;
251
252     priv->has_style = 0;
253 }
254
255 static void
256 hildon_color_chooser_dialog_class_init          (HildonColorChooserDialogClass *klass)
257 {
258     GtkWidgetClass *widget_klass = GTK_WIDGET_CLASS (klass);
259     GtkObjectClass *object_klass = GTK_OBJECT_CLASS (klass);
260     gchar tmp[32];
261     gint i;
262
263     widget_klass->size_request      = hildon_color_chooser_dialog_size_request;
264     widget_klass->size_allocate     = hildon_color_chooser_dialog_size_allocate;
265     widget_klass->realize           = hildon_color_chooser_dialog_realize;
266     widget_klass->unrealize         = hildon_color_chooser_dialog_unrealize;
267     widget_klass->style_set         = hildon_color_chooser_dialog_style_set;
268     widget_klass->show              = hildon_color_chooser_dialog_show;
269     widget_klass->show_all          = hildon_color_chooser_dialog_show_all;
270     widget_klass->key_press_event   = hildon_color_chooser_dialog_key_press_event;
271     widget_klass->key_release_event = hildon_color_chooser_dialog_key_release_event;
272
273
274     object_klass->destroy           = hildon_color_chooser_dialog_destroy;
275
276     parent_class = g_type_class_peek_parent (klass);
277
278     gtk_widget_class_install_style_property (widget_klass,
279             g_param_spec_boxed ("container_sizes",
280                 "Container sizes",
281                 "Container specific sizes",
282                 GTK_TYPE_BORDER,
283                 G_PARAM_READABLE));
284
285     gtk_widget_class_install_style_property (widget_klass,
286             g_param_spec_boxed ("radio_sizes",
287                 "Color radio sizes",
288                 "Color radio specific sizes",
289                 GTK_TYPE_BORDER,
290                 G_PARAM_READABLE));
291
292     gtk_widget_class_install_style_property (widget_klass,
293             g_param_spec_boxed ("num_buttons",
294                 "Number of buttons",
295                 "Number of color store buttons",
296                 GTK_TYPE_BORDER,
297                 G_PARAM_READABLE));
298
299
300     gtk_widget_class_install_style_property (widget_klass,
301             g_param_spec_boxed ("default_color", "Default color",
302                 "Default color for nonpainted custom colors",
303                 GDK_TYPE_COLOR,
304                 G_PARAM_READABLE));
305
306     for (i = 0; i < 32; i++) {
307         memset (tmp, 0, 32);
308         g_snprintf (tmp, 32, "defined_color%d", i);
309
310         gtk_widget_class_install_style_property (widget_klass,
311                 g_param_spec_boxed (tmp, "Defined color",
312                     "Pre-defined colors for the dialog",
313                     GDK_TYPE_COLOR,
314                     G_PARAM_READABLE));
315     }
316
317     g_type_class_add_private (object_klass, sizeof (HildonColorChooserDialogPrivate));
318 }
319
320 static void 
321 hildon_color_chooser_dialog_size_request        (GtkWidget *widget, 
322                                                  GtkRequisition *req)
323 {
324     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (widget);
325
326     g_assert (priv);
327
328     gtk_container_set_border_width (GTK_CONTAINER (priv->hbox), priv->style_info.cont_sizes.left);
329
330     gtk_box_set_spacing (GTK_BOX (priv->hbox), priv->style_info.cont_sizes.right);
331     gtk_box_set_spacing (GTK_BOX (priv->vbox), priv->style_info.cont_sizes.top);
332     gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (widget)->vbox), priv->style_info.cont_sizes.bottom);
333
334     gtk_widget_set_size_request (priv->area_custom,
335             (priv->style_info.radio_sizes.left + 
336              2 * priv->style_info.radio_sizes.bottom) * 
337             (priv->style_info.num_buttons.top) +
338             (priv->style_info.num_buttons.top-1) *
339             priv->style_info.radio_sizes.top,
340             (priv->style_info.radio_sizes.right + 
341              2 * priv->style_info.radio_sizes.bottom) * 
342             (priv->style_info.num_buttons.bottom) +
343             (priv->style_info.num_buttons.bottom-1) * 
344             priv->style_info.radio_sizes.top);
345
346     gtk_widget_set_size_request (priv->area_defined,
347             (priv->style_info.radio_sizes.left + 
348              2 * priv->style_info.radio_sizes.bottom) * 
349             (priv->style_info.num_buttons.left) +
350             (priv->style_info.num_buttons.left-1) * 
351             priv->style_info.radio_sizes.top,
352             (priv->style_info.radio_sizes.right +  
353              2 * priv->style_info.radio_sizes.bottom) * 
354             (priv->style_info.num_buttons.right) +
355             (priv->style_info.num_buttons.right-1) * 
356             priv->style_info.radio_sizes.top);
357
358     GTK_WIDGET_CLASS (parent_class)->size_request (widget, req);
359 }
360
361 static void 
362 hildon_color_chooser_dialog_size_allocate       (GtkWidget *widget,
363                                                  GtkAllocation *alloc)
364 {
365     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (widget);
366
367     GdkRectangle rect;
368     int i, tmp, tmp2;
369
370     g_assert (priv);
371
372     GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, alloc);
373
374     if (GTK_WIDGET_REALIZED (widget)) {
375         tmp  = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right);
376         tmp2 = (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
377
378         for (i = 0; i < tmp; i++) {
379             rect.x = ((i % priv->style_info.num_buttons.left) * 
380                     (priv->style_info.radio_sizes.left + 
381                      priv->style_info.radio_sizes.top + 
382                      2 * priv->style_info.radio_sizes.bottom)) + 
383                 priv->style_info.radio_sizes.bottom;
384
385             rect.y = ((i / priv->style_info.num_buttons.left) * 
386                     (priv->style_info.radio_sizes.right + 
387                      priv->style_info.radio_sizes.top +
388                      2 * priv->style_info.radio_sizes.bottom)) + 
389                 priv->style_info.radio_sizes.bottom;
390
391             rect.width = priv->style_info.radio_sizes.left;
392             rect.height = priv->style_info.radio_sizes.right;
393
394             gdk_gc_set_clip_rectangle (priv->gc_array[i], &rect);
395         }
396
397         for (i = 0; i < tmp2; i++) {
398             rect.x = ((i % priv->style_info.num_buttons.top) * 
399                     (priv->style_info.radio_sizes.left + 
400                      priv->style_info.radio_sizes.top +
401                      2 * priv->style_info.radio_sizes.bottom)) + 
402                 priv->style_info.radio_sizes.bottom;
403
404             rect.y = ((i / priv->style_info.num_buttons.top) * 
405                     (priv->style_info.radio_sizes.right + 
406                      priv->style_info.radio_sizes.top +
407                      2 * priv->style_info.radio_sizes.bottom)) + priv->style_info.radio_sizes.bottom;
408
409             rect.width = priv->style_info.radio_sizes.left;
410             rect.height = priv->style_info.radio_sizes.right;
411
412             gdk_gc_set_clip_rectangle (priv->gc_array[i + tmp], &rect);
413         }
414     }
415 }
416
417 static void 
418 hildon_color_chooser_dialog_realize             (GtkWidget *widget)
419 {
420     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (widget);
421
422     GdkRectangle rect;
423     int i, tmp, tmp2;
424
425     g_assert (priv);
426     
427     GTK_WIDGET_CLASS(parent_class)->realize (widget);
428
429     tmp = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right) +
430         (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
431
432     for (i = 0; i < tmp; i++) {
433         priv->gc_array[i] = gdk_gc_new (widget->window);
434     }
435
436     tmp  = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right);
437     tmp2 = (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
438
439     for (i = 0; i < tmp; i++) {
440         gdk_gc_set_rgb_fg_color (priv->gc_array[i], &priv->colors_defined[i]);
441
442         rect.x = ((i % priv->style_info.num_buttons.left) * 
443                 (priv->style_info.radio_sizes.left + 
444                  priv->style_info.radio_sizes.top +
445                  2 * priv->style_info.radio_sizes.bottom)) + 
446             priv->style_info.radio_sizes.bottom;
447
448         rect.y = ((i / priv->style_info.num_buttons.left) * 
449                 (priv->style_info.radio_sizes.right + 
450                  priv->style_info.radio_sizes.top +
451                  2 * priv->style_info.radio_sizes.bottom)) + 
452             priv->style_info.radio_sizes.bottom;
453
454         rect.width = priv->style_info.radio_sizes.left;
455         rect.height = priv->style_info.radio_sizes.right;
456
457         gdk_gc_set_clip_rectangle (priv->gc_array[i], &rect);
458     }
459
460     for (i = 0; i < tmp2; i++) {
461         gdk_gc_set_rgb_fg_color (priv->gc_array[i + tmp], &priv->colors_custom[i]);
462
463         rect.x = ((i % priv->style_info.num_buttons.top) * 
464                 (priv->style_info.radio_sizes.left + 
465                  priv->style_info.radio_sizes.top +
466                  2 * priv->style_info.radio_sizes.bottom)) + 
467             priv->style_info.radio_sizes.bottom;
468
469         rect.y = ((i / priv->style_info.num_buttons.top) * 
470                 (priv->style_info.radio_sizes.right + 
471                  priv->style_info.radio_sizes.top +
472                  2 * priv->style_info.radio_sizes.bottom)) + 
473             priv->style_info.radio_sizes.bottom;
474
475         rect.width = priv->style_info.radio_sizes.left;
476         rect.height = priv->style_info.radio_sizes.right;
477
478         gdk_gc_set_clip_rectangle (priv->gc_array[i + tmp], &rect);
479     }
480 }
481
482 static void 
483 hildon_color_chooser_dialog_unrealize           (GtkWidget *widget)
484 {
485     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (widget);
486
487     int i, tmp;
488
489     tmp = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right) +
490         (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
491
492     for (i = 0; i < tmp; i++) {
493         g_object_unref (priv->gc_array[i]);
494     }
495
496     GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
497 }
498
499 static void 
500 hildon_color_chooser_dialog_style_set           (GtkWidget *widget, 
501                                                  GtkStyle *previous_style)
502 {
503     HildonColorChooserDialog *dialog = HILDON_COLOR_CHOOSER_DIALOG (widget);
504     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (widget);
505
506     GdkColor *tmpcolor;
507     gchar tmp[32], key[128], *val;
508     int i, tmpn, setcolor = 0;
509
510     g_assert (priv);
511
512     if (! priv->has_style)
513         setcolor = 1;
514
515     priv->has_style = 1;
516
517     gtk_widget_style_get (widget, "default_color", &tmpcolor, NULL);
518
519     if (tmpcolor) {
520         priv->style_info.default_color = *tmpcolor;
521     } else {
522         priv->style_info.default_color.red   = 0x0000;
523         priv->style_info.default_color.green = 0x0000;
524         priv->style_info.default_color.blue  = 0x0000;
525         priv->style_info.default_color.pixel = 0x00000000;
526     }
527
528     hildon_color_chooser_dialog_refresh_style_info (dialog);
529
530     if (memcmp (&priv->style_info.num_buttons, &priv->style_info.last_num_buttons, sizeof (GtkBorder))) {
531         if (priv->colors_custom) {
532             g_free (priv->colors_custom);
533         } if (priv->colors_defined) {
534             g_free (priv->colors_defined);
535         } if (priv->gc_array) {
536             if (GTK_WIDGET_REALIZED (widget)) {
537                 tmpn = (priv->style_info.last_num_buttons.left * priv->style_info.last_num_buttons.right) +
538                     (priv->style_info.last_num_buttons.top * priv->style_info.last_num_buttons.bottom);
539
540                 for (i = 0; i < tmpn; i++) {
541                     g_object_unref (priv->gc_array[i]);
542                 }
543             }
544
545             g_free (priv->gc_array);
546         }
547
548         priv->colors_custom = (GdkColor *)
549             g_malloc0 (sizeof (GdkColor) * (priv->style_info.num_buttons.top * 
550                         priv->style_info.num_buttons.bottom));
551
552         priv->colors_defined = (GdkColor *)
553             g_malloc0 (sizeof(GdkColor) * (priv->style_info.num_buttons.left * 
554                         priv->style_info.num_buttons.right));
555
556         tmpn = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right) +
557             (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
558
559         priv->gc_array = (GdkGC **) g_malloc0 (sizeof (GdkGC *) * tmpn);
560
561         if (priv->gconf_client) {
562
563             for (i = 0; i < (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom); i++) {
564                 memset (key, 0, 128);
565                 /* FIXME Extremally bad hardcoding */
566                 g_snprintf (key, 128, "/system/osso/af/color_chooser/custom_color%d", i);
567                 val = gconf_client_get_string (priv->gconf_client, key, NULL);
568
569                 if (val) {
570                     hildon_color_chooser_dialog_ascii_hex_to_color (val, &priv->colors_custom[i]);
571                     g_free (val);
572                 } else {
573                     priv->colors_custom[i] = priv->style_info.default_color;
574                 }
575             }
576         } else {
577             for (i = 0; i < (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom); i++) {
578                 priv->colors_custom[i] = priv->style_info.default_color;
579             }
580         }
581     }
582
583     tmpn = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right);
584
585     hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (priv->chooser),
586             (priv->selected < tmpn) ? 
587             &priv->colors_defined[priv->selected] : 
588             &priv->colors_custom[priv->selected - tmpn]);
589
590     for (i = 0; i < (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right); i++) {
591         memset (tmp, 0, 32);
592         g_snprintf (tmp, 32, "defined_color%d", i);
593
594         gtk_widget_style_get (widget, tmp, &tmpcolor, NULL);
595
596         if (tmpcolor) {
597             priv->colors_defined[i] = *tmpcolor;
598         } else {
599             if(i < 16) {
600                 priv->colors_defined[i] = hardcoded_colors[i];
601             } else { /* fallback to prevent segfault */
602                 priv->colors_defined[i].red = 0x0000;
603                 priv->colors_defined[i].green = 0x0000;
604                 priv->colors_defined[i].blue = 0x0000;
605                 priv->colors_defined[i].pixel = 0x00000000;
606             }
607         }
608     }
609
610     if (GTK_WIDGET_REALIZED (widget)) {
611         for (i = 0; i < (priv->style_info.num_buttons.left * 
612                     priv->style_info.num_buttons.right); i++) {
613             gdk_gc_set_rgb_fg_color (priv->gc_array[i], &priv->colors_defined[i]);
614         }
615     }
616
617     if (setcolor)
618         hildon_color_chooser_dialog_set_color (HILDON_COLOR_CHOOSER_DIALOG (dialog), 
619                 &priv->pending_color);
620
621     gtk_widget_queue_resize (widget);
622
623     GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
624 }
625
626 static void 
627 hildon_color_chooser_dialog_show                (GtkWidget *widget)
628 {
629     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (widget);
630
631     g_assert (priv);
632
633     gtk_widget_show (priv->hbox);
634     gtk_widget_show (priv->vbox);
635
636     gtk_widget_show (priv->chooser);
637
638     gtk_widget_show (priv->align_custom);
639     gtk_widget_show (priv->align_defined);
640
641     gtk_widget_show (priv->separator);
642
643     gtk_widget_show (priv->area_custom);
644     gtk_widget_show (priv->area_defined);
645
646     GTK_WIDGET_CLASS (parent_class)->show (widget);
647 }
648
649 /* FIXME WTF this function is even needed here? */
650 static void 
651 hildon_color_chooser_dialog_show_all            (GtkWidget *widget)
652 {
653     hildon_color_chooser_dialog_show (widget);
654 }
655
656 static gboolean 
657 hildon_color_chooser_dialog_key_press_event     (GtkWidget *widget, 
658                                                  GdkEventKey *event)
659 {
660     HildonColorChooserDialog *dialog = HILDON_COLOR_CHOOSER_DIALOG (widget);
661     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (widget);
662     int tmp, tot, sel;
663
664     g_assert (priv);
665
666     if (event->keyval == HILDON_HARDKEY_UP || event->keyval == HILDON_HARDKEY_DOWN ||
667             event->keyval == HILDON_HARDKEY_LEFT || event->keyval == HILDON_HARDKEY_RIGHT) {
668         tmp = (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
669         tot = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right) + tmp;
670
671         switch (event->keyval) {
672
673             case HILDON_HARDKEY_UP:
674                 if(priv->selected >= priv->style_info.num_buttons.top) {
675                     if(priv->selected - priv->style_info.num_buttons.left >= tmp) {
676                         sel = priv->selected - priv->style_info.num_buttons.left;
677                     } else {
678                         sel = priv->selected - priv->style_info.num_buttons.top;
679                     }
680
681                     hildon_color_chooser_dialog_set_color_num (dialog, sel);
682                 }
683                 break;
684
685             case HILDON_HARDKEY_DOWN:
686                 if(priv->selected < tot - priv->style_info.num_buttons.left) {
687                     if(priv->selected < tmp) {
688                         sel = priv->selected + priv->style_info.num_buttons.top;
689                     } else {
690                         sel = priv->selected + priv->style_info.num_buttons.left;
691                     }
692
693                     hildon_color_chooser_dialog_set_color_num (dialog, sel);
694                 }
695                 break;
696
697             case HILDON_HARDKEY_LEFT:
698                 if ((priv->selected < tmp ? 
699                             (priv->selected % priv->style_info.num_buttons.top) : 
700                             ((priv->selected - tmp) % priv->style_info.num_buttons.left)) > 0) {
701                     sel = priv->selected - 1;
702
703                     hildon_color_chooser_dialog_set_color_num (dialog, sel);
704                 }
705                 break;
706
707             case HILDON_HARDKEY_RIGHT:
708                 if ((priv->selected < tmp) ? 
709                         (priv->selected % priv->style_info.num_buttons.top < priv->style_info.num_buttons.top - 1) :
710                         ((priv->selected - tmp) % priv->style_info.num_buttons.left < priv->style_info.num_buttons.left - 1)) {
711                     sel = priv->selected + 1;
712
713                     hildon_color_chooser_dialog_set_color_num (dialog, sel);
714                 }
715                 break;
716
717             default:
718                 break;
719         }
720
721         return FALSE;
722     }
723
724     return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
725 }
726
727 static gboolean
728 hildon_color_chooser_dialog_key_release_event   (GtkWidget *widget, 
729                                                  GdkEventKey *event)
730 {
731     if (event->keyval == HILDON_HARDKEY_UP || 
732         event->keyval == HILDON_HARDKEY_DOWN ||
733         event->keyval == HILDON_HARDKEY_LEFT || 
734         event->keyval == HILDON_HARDKEY_RIGHT) 
735     {
736         return FALSE;
737     }
738
739     return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
740 }
741
742 static void 
743 hildon_color_chooser_dialog_destroy             (GtkObject *object)
744 {
745     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (object);
746
747     gchar key[128], color[13];
748     int i, tmp;
749
750     g_assert (priv);
751
752     if (priv->gconf_client) {
753         memset (color, 0, 13);
754
755         tmp = (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
756
757         for (i = 0; i < tmp; i++) {
758             memset (key, 0, 128);
759             /* FIXME Extremally bad hardcoding */
760             g_snprintf (key, 128, "/system/osso/af/color_chooser/custom_color%d", i);
761             hildon_color_chooser_dialog_color_to_ascii_hex (color, &priv->colors_custom[i]);
762             gconf_client_set_string (priv->gconf_client, key, color, NULL);
763         }
764
765         g_object_unref (priv->gconf_client);
766         priv->gconf_client = NULL;
767     }
768
769     if (priv->gc_array) {
770         g_free (priv->gc_array);
771         priv->gc_array = NULL;
772     } if (priv->colors_defined) {
773         g_free (priv->colors_defined);
774         priv->colors_defined = NULL;
775     } if (priv->colors_custom) {
776         g_free (priv->colors_custom);
777         priv->colors_custom = NULL;
778     }
779
780     GTK_OBJECT_CLASS (parent_class)->destroy (object);
781 }
782
783 void 
784 hildon_color_chooser_dialog_set_color           (HildonColorChooserDialog *dialog, 
785                                                  GdkColor *color)
786 {
787     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (dialog);
788
789     int i, found = -1, tmp, tmp2;
790
791     g_assert (priv);
792
793     if (! priv->has_style) {
794         priv->pending_color = *color;
795         return;
796     }
797
798     tmp  = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right);
799     tmp2 = (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
800
801     for (i = 0; i < tmp; i++) {
802         if (priv->colors_defined[i].red == color->red &&
803                 priv->colors_defined[i].green == color->green &&
804                 priv->colors_defined[i].blue == color->blue) {
805             found = i;
806             break;
807         }
808     }
809
810     if (found == -1) {
811         for (i = 0; i < tmp2; i++) {
812             if (priv->colors_custom[i].red == color->red &&
813                     priv->colors_custom[i].green == color->green &&
814                     priv->colors_custom[i].blue == color->blue) {
815                 found = i + tmp;
816                 break;
817             }
818         }
819     }
820
821     if (found == -1) {
822         priv->colors_custom[tmp2-1] = *color;
823         if (GTK_WIDGET_REALIZED (GTK_WIDGET (dialog))) {
824             gdk_gc_set_rgb_fg_color (priv->gc_array[tmp2-1], color);
825         }
826         hildon_color_chooser_dialog_set_color_num (dialog, tmp2 - 1);
827     } else {
828         hildon_color_chooser_dialog_set_color_num (dialog, found);
829     }
830 }
831
832 static gboolean 
833 hildon_color_chooser_dialog_area_expose         (GtkWidget *widget, 
834                                                  GdkEventExpose *event, 
835                                                  gpointer data)
836 {
837     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (data);
838
839     int i, num_selected, tot_w, tot_h, spacing, brd, x, y;
840     GdkGC **start_gc;
841     int tmp, w, h;
842
843     g_assert (priv);
844
845     tmp = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right);
846
847     if (widget == priv->area_custom) {
848         num_selected = priv->selected - tmp;
849         start_gc = priv->gc_array + tmp;
850         tmp = (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
851         w = priv->style_info.num_buttons.top; 
852         h = priv->style_info.num_buttons.bottom;
853     } else { /* widget == dialog->area_defined */
854         num_selected = priv->selected;
855         start_gc = priv->gc_array;
856         w = priv->style_info.num_buttons.left; 
857         h = priv->style_info.num_buttons.right;
858     }
859
860     spacing = priv->style_info.radio_sizes.top;
861     brd = priv->style_info.radio_sizes.bottom;
862     tot_w = priv->style_info.radio_sizes.left + 2 * brd;
863     tot_h = priv->style_info.radio_sizes.right + 2 * brd;
864
865     for (i = 0; i < tmp; i++) {
866         x = ((i % w) * (tot_w + spacing));
867         y = ((i / w) * (tot_h + spacing));
868
869         gdk_draw_rectangle (widget->window,
870                 widget->style->black_gc,
871                 TRUE,
872                 (i == num_selected) ? x : x + 2,  
873                 (i == num_selected) ? y : y + 2,
874                 (i == num_selected) ? tot_w : tot_w - 4,
875                 (i == num_selected) ? tot_h : tot_h - 4);
876
877         gdk_draw_rectangle(widget->window,
878                 widget->style->white_gc,
879                 TRUE,
880                 x + 3,  
881                 y + 3,
882                 tot_w - 6,
883                 tot_h - 6);
884
885         gdk_draw_rectangle(widget->window,
886                 start_gc [i],
887                 TRUE,
888                 x + 3 + 1,  
889                 y + 3 + 1,
890                 tot_w - 6 - 2,
891                 tot_h - 6 - 2);
892     }
893
894     return FALSE;
895 }
896
897 static gboolean 
898 hildon_color_chooser_dialog_area_button_press   (GtkWidget *widget, 
899                                                  GdkEventButton *event, 
900                                                  gpointer data)
901 {
902     HildonColorChooserDialog *dialog = HILDON_COLOR_CHOOSER_DIALOG (data);
903     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (data);
904
905     int i, hskip, vskip, brd, selection = -1;
906     int x, y, tmp, tmp2, w;
907
908     g_assert (priv);
909
910     x = event->x;
911     y = event->y;
912
913     brd = priv->style_info.radio_sizes.bottom;
914     hskip = priv->style_info.radio_sizes.left + 
915         priv->style_info.radio_sizes.top + 2 * brd;
916     vskip = priv->style_info.radio_sizes.right + 
917         priv->style_info.radio_sizes.top + 2 * brd;
918
919     tmp  = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right);
920     tmp2 = (priv->style_info.num_buttons.top * priv->style_info.num_buttons.bottom);
921
922     if (widget == priv->area_defined) {
923         w = priv->style_info.num_buttons.left;
924
925         for (i = 0; i < tmp; i++) {
926             if (x >= hskip * (i % w) + brd && x < hskip * (i % w) + brd + priv->style_info.radio_sizes.left &&
927                 y >= vskip * (i / w) + brd && y < hskip * (i / w) + brd + priv->style_info.radio_sizes.right) {
928                 selection = i;
929                 break;
930             }
931         }
932     } else {
933         w = priv->style_info.num_buttons.top;
934         for (i = 0; i < tmp2; i++) {
935             if (x >= hskip * (i % w) + brd && x < hskip * (i % w) + brd + priv->style_info.radio_sizes.left &&
936                 y >= vskip * (i / w) + brd && y < hskip * (i / w) + brd + priv->style_info.radio_sizes.right) {
937                 selection = i + tmp;
938                 break;
939             }
940         }
941     }
942
943     if (selection != -1) {
944         hildon_color_chooser_dialog_set_color_num (dialog, selection);
945     }
946
947     return FALSE;
948 }
949
950 static void 
951 hildon_color_chooser_dialog_color_changed       (HildonColorChooser *chooser, 
952                                                  gpointer data)
953 {
954     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (data);
955     char key[128], color_str[13];
956     int tmp;
957     GdkColor *color = g_new (GdkColor, 1);
958
959     g_assert (priv);
960
961     hildon_color_chooser_get_color (chooser, color);
962
963     tmp = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right);
964
965     if (priv->selected >= tmp) {
966         priv->colors_custom[priv->selected - tmp] = *color;
967
968         gdk_gc_set_rgb_fg_color (priv->gc_array[priv->selected], &priv->colors_custom[priv->selected - tmp]);
969         gtk_widget_queue_draw (priv->area_custom);
970
971         if (priv->gconf_client) {
972             memset (key, 0, 128);
973             memset (color_str, 0, 13);
974             /* FIXME Ugly hardcoded stuff! */
975             g_snprintf (key, 128, "/system/osso/af/color_chooser/custom_color%d", priv->selected - tmp);
976             hildon_color_chooser_dialog_color_to_ascii_hex (color_str, &priv->colors_custom[priv->selected - tmp]);
977             gconf_client_set_string (priv->gconf_client, key, color_str, NULL);
978         }
979     }
980 }
981
982 static void 
983 hildon_color_chooser_dialog_insensitive_press   (GtkWidget *widget, 
984                                                  gpointer data)
985 {
986     hildon_banner_show_information (widget, NULL, _("ecdg_ib_colour_selector_predefined"));
987 }
988
989 /* function has size defaults */
990 static void 
991 hildon_color_chooser_dialog_refresh_style_info  (HildonColorChooserDialog *dialog)
992 {
993     GtkBorder *tmp1, *tmp2, *tmp3;
994     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (dialog);
995
996     g_assert (priv);
997
998     gtk_widget_style_get (GTK_WIDGET (dialog), "container_sizes", &tmp1,
999             "radio_sizes", &tmp2, "num_buttons", &tmp3, NULL);
1000
1001     priv->style_info.last_num_buttons = priv->style_info.num_buttons;
1002
1003     if (tmp1) {
1004         priv->style_info.cont_sizes = *tmp1;
1005         g_free (tmp1);
1006     } else {
1007         priv->style_info.cont_sizes.left = 0;
1008         priv->style_info.cont_sizes.right = 8;
1009         priv->style_info.cont_sizes.top = 4;
1010         priv->style_info.cont_sizes.bottom = 0;
1011     }
1012
1013     if (tmp2) {
1014         priv->style_info.radio_sizes = *tmp2;
1015         g_free (tmp2);
1016     } else {
1017         priv->style_info.radio_sizes.left = 16;
1018         priv->style_info.radio_sizes.right = 16;
1019         priv->style_info.radio_sizes.top = 4;
1020         priv->style_info.radio_sizes.bottom = 2;
1021     }
1022
1023     if (tmp3) {
1024         priv->style_info.num_buttons = *tmp3;
1025         g_free (tmp3);
1026     } else {
1027         priv->style_info.num_buttons.left = 8;
1028         priv->style_info.num_buttons.right = 2;
1029         priv->style_info.num_buttons.top = 8;
1030         priv->style_info.num_buttons.bottom = 2;
1031     }
1032 }
1033
1034 static void 
1035 hildon_color_chooser_dialog_set_color_num       (HildonColorChooserDialog *dialog, 
1036                                                  gint num)
1037 {
1038     HildonColorChooserDialogPrivate *priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (dialog);
1039
1040     int tmp;
1041
1042     g_assert (priv);
1043
1044     tmp = (priv->style_info.num_buttons.left * priv->style_info.num_buttons.right);
1045
1046     if (num < tmp) {
1047         gtk_widget_set_sensitive (priv->chooser, FALSE);
1048     } else {
1049         gtk_widget_set_sensitive (priv->chooser, TRUE);
1050     }
1051
1052     priv->selected = num;
1053
1054     gtk_widget_queue_draw (priv->area_custom);
1055     gtk_widget_queue_draw (priv->area_defined);
1056
1057     priv->color = (num < tmp) ? priv->colors_defined[num] : priv->colors_custom[num - tmp];
1058
1059     hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (priv->chooser), 
1060             (num < tmp) ? &priv->colors_defined[num] : &priv->colors_custom[num - tmp]);
1061 }
1062
1063 static void 
1064 hildon_color_chooser_dialog_ascii_hex_to_color  (gchar *s, 
1065                                                  GdkColor *color)
1066 {
1067     int vals[12], i;
1068
1069     for (i = 0; i < 12; i++) {
1070         if (s[i] >= '0' && s[i] <= '9') {
1071             vals[i] = s[i] - 0x30;
1072         } else if (s[i] >= 'a' && s[i] <= 'f') {
1073             vals[i] = s[i] - 0x57;
1074         } else {
1075             vals[i] = 0;
1076         }
1077     }
1078
1079     color->red   = (vals[0] << 12) | (vals[1] <<  8) | (vals[2 ] <<  4) | (vals[3 ]);
1080     color->green = (vals[4] << 12) | (vals[5] <<  8) | (vals[6 ] <<  4) | (vals[7 ]);
1081     color->blue  = (vals[8] << 12) | (vals[9] <<  8) | (vals[10] <<  4) | (vals[11]);
1082 }
1083
1084 static void 
1085 hildon_color_chooser_dialog_color_to_ascii_hex  (gchar *s, 
1086                                                  GdkColor *color)
1087 {
1088     g_snprintf (s, 13, "%x%x%x%x%x%x%x%x%x%x%x%x",
1089          (color->red >> 12) & 0xf, (color->red >>  8) & 0xf,
1090          (color->red >>  4) & 0xf, (color->red      ) & 0xf,
1091          (color->green >> 12) & 0xf, (color->green >>  8) & 0xf,
1092          (color->green >>  4) & 0xf, (color->green      ) & 0xf,
1093          (color->blue >> 12) & 0xf, (color->blue >>  8) & 0xf,
1094          (color->blue >>  4) & 0xf, (color->blue      ) & 0xf);
1095 }
1096
1097 /**
1098  * hildon_color_chooser_dialog_new:
1099  *
1100  * Creates a new color chooser dialog.
1101  *
1102  * Returns: a new color chooser dialog.
1103  */
1104 GtkWidget*
1105 hildon_color_chooser_dialog_new                 (void)
1106 {
1107     return g_object_new (HILDON_TYPE_COLOR_CHOOSER_DIALOG, NULL);
1108 }
1109
1110 /**
1111  * hildon_color_chooser_dialog_get_color:
1112  * @dialog: a #HildonColorChooserDialog
1113  * @color: a color to fill with new value
1114  *
1115  */
1116 void
1117 hildon_color_chooser_dialog_get_color           (HildonColorChooserDialog *dialog, 
1118                                                  GdkColor *color)
1119 {
1120     /* FIXME Should return pending color? */
1121     HildonColorChooserDialogPrivate *priv;
1122
1123     g_return_if_fail (HILDON_IS_COLOR_CHOOSER_DIALOG (dialog));
1124     priv = HILDON_COLOR_CHOOSER_DIALOG_GET_PRIVATE (dialog);
1125     g_assert (priv);
1126
1127     hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER (priv->chooser), color);
1128 }
1129