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