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