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