Cleanup font selection dialog,
[hildon] / hildon-widgets / hildon-font-selection-dialog.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Luc Pionchon <luc.pionchon@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <gtk/gtkstock.h>
29 #include <gtk/gtkcombobox.h>
30 #include <gtk/gtktogglebutton.h>
31 #include <gtk/gtkcheckbutton.h>
32 #include <gtk/gtklabel.h>
33 #include <gtk/gtkvbox.h>
34 #include <gtk/gtkliststore.h>
35 #include <gtk/gtknotebook.h>
36 #include <gtk/gtk.h>
37 #include <glib.h>
38 #include <gdk/gdkkeysyms.h>
39
40 #include "hildon-font-selection-dialog.h"
41 #include <hildon-widgets/hildon-caption.h>
42 #include <hildon-widgets/hildon-color-selector.h>
43 #include <hildon-widgets/hildon-color-button.h>
44
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48
49 #include <libintl.h>
50 #define _(String) dgettext(PACKAGE, String)
51
52 #define SUPERSCRIPT_RISE 3333
53 #define SUBSCRIPT_LOW -3333
54 #define ON_BIT 0x01
55 #define OFF_BIT 0x02
56 #define REFERENCE_LINE "Reference: " /*localized string?*/
57
58 /*
59  * These are what we use as the standard font sizes, for the size list.
60  */
61 static const guint16 font_sizes[] = 
62 {
63   6, 8, 10, 12, 16, 24, 32
64 };
65
66 #define HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(obj) \
67 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
68                               HILDON_TYPE_FONT_SELECTION_DIALOG, \
69                               HildonFontSelectionDialogPrivate))
70
71 /*None of designed api function works, so now it all comes down to 
72  *use properties to achieve what we are supposed to achieve*/
73 enum
74 {
75   PROP_FAMILY = 1,
76   PROP_FAMILY_SET,
77   PROP_SIZE,
78   PROP_SIZE_SET,
79   PROP_COLOR,
80   PROP_COLOR_SET,
81   PROP_BOLD,
82   PROP_BOLD_SET,
83   PROP_ITALIC,
84   PROP_ITALIC_SET,
85   PROP_UNDERLINE,
86   PROP_UNDERLINE_SET,
87   PROP_STRIKETHROUGH,
88   PROP_STRIKETHROUGH_SET,
89   PROP_POSITION,
90   PROP_POSITION_SET,
91   PROP_PREVIEW_TEXT
92 };
93
94 typedef struct
95 _HildonFontSelectionDialogPrivate HildonFontSelectionDialogPrivate;
96
97 struct _HildonFontSelectionDialogPrivate 
98 {  
99   GtkNotebook *notebook;
100
101   gchar *preview_text;
102
103   /*Tab one*/
104   GtkWidget *cbx_font_type;
105   GtkWidget *cbx_font_size;
106   GtkWidget *font_color_button;
107
108   /*Tab two*/
109   GtkWidget *chk_bold;
110   GtkWidget *chk_italic;
111   GtkWidget *chk_underline;
112
113   /*Tab three*/
114   GtkWidget *chk_strikethrough;
115   GtkWidget *cbx_positioning;
116
117   /*Every family*/
118   PangoFontFamily **families;
119   gint n_families;
120
121   /*color_set is used to show whether the color is inconsistent
122    * The handler id is used to block the signal emission
123    * when we change the color setting*/
124   
125   gboolean color_set;
126   gulong color_modified_signal_handler;
127 };
128
129 /*combo box active row indicator -2--inconsistent, -1--undefined 
130  * please make sure that you use settings_init settings_apply
131  * and settings_destroy, dont even try to touch this structure 
132  * without using the three above interface functions, of course
133  * if you know what you are doing, do as you please ;-)*/
134 typedef struct
135 {
136   HildonFontSelectionDialog
137                *fsd; /*pointer to our font selection dialog*/
138   
139   gint         family; /*combo box indicator*/
140   gint         size; /*combo box indicator*/
141   GdkColor     *color; /*free after read the setting*/
142   gboolean     color_inconsist;
143   gint         weight; /*bit mask*/
144   gint         style;  /*bit mask*/
145   gint         underline; /*bit mask*/
146   gint         strikethrough; /*bit mask*/
147   gint         position; /*combo box indicator*/
148
149 }HildonFontSelectionDialogSettings;
150
151 static gboolean
152               hildon_font_selection_dialog_preview_key_press
153                                              (GtkWidget * widget,
154                                               GdkEventKey * event,
155                                               gpointer data);
156
157 /*Some tools from gtk_font_selection*/
158 static int    cmp_families                   (const void *a, const void *b);
159
160 static void   hildon_font_selection_dialog_show_preview
161                                              (HildonFontSelectionDialog 
162                                               *fontsel);
163                                              
164 static PangoAttrList*
165               hildon_font_selection_dialog_create_attrlist
166                                              (HildonFontSelectionDialog 
167                                               *fontsel, guint start_index,
168                                               guint len);
169
170 static void   hildon_font_selection_dialog_show_available_positionings
171                                              (HildonFontSelectionDialogPrivate
172                                               *priv);
173                                                  
174 static void   hildon_font_selection_dialog_show_available_fonts
175                                              (HildonFontSelectionDialog
176                                               *fontsel);
177                                                  
178 static void   hildon_font_selection_dialog_show_available_sizes
179                                              (HildonFontSelectionDialogPrivate
180                                               *priv);
181
182 static void   hildon_font_selection_dialog_class_init
183                                              (HildonFontSelectionDialogClass 
184                                               *klass);
185                                                  
186 static void   hildon_font_selection_dialog_init
187                                              (HildonFontSelectionDialog 
188                                               *fontseldiag);
189
190 static void   hildon_font_selection_dialog_finalize
191                                              (GObject * object);
192
193 static void   hildon_font_selection_dialog_construct_notebook  
194                                              (HildonFontSelectionDialog
195                                               *fontsel);
196                                              
197 static void   color_modified_cb              (HildonColorButton *button,
198                                               GParamSpec *pspec,
199                                               gpointer data);
200
201 static void   check_tags                     (gpointer data,
202                                               gpointer user_data);
203
204 static void   settings_init                  (HildonFontSelectionDialogSettings
205                                               *setttings,
206                                               HildonFontSelectionDialog
207                                               *fsd);
208
209 static void   settings_apply                 (HildonFontSelectionDialogSettings
210                                               *setttings);
211
212 static void   settings_destroy               (HildonFontSelectionDialogSettings
213                                               *setttings);
214
215 static void   bit_mask_toggle                (gint mask, GtkToggleButton*
216                                               button, GObject *object, 
217                                               const gchar *prop, 
218                                               const gchar *prop_set);
219
220 static void   combo_active                   (gint active, GtkComboBox *box,
221                                               GObject *object, 
222                                               const gchar *prop,
223                                               const gchar *prop_set);
224
225 static void   add_preview_text_attr          (PangoAttrList *list, 
226                                               PangoAttribute *attr, 
227                                               guint start, 
228                                               guint len);
229
230 static void   toggle_clicked                 (GtkButton *button, 
231                                               gpointer data);
232         
233                                              
234                                              
235 static GtkDialogClass *font_selection_dialog_parent_class = NULL;
236
237 GType hildon_font_selection_dialog_get_type(void)
238 {
239   static GType font_selection_dialog_type = 0;
240
241   if (!font_selection_dialog_type) {
242     static const GTypeInfo fontsel_diag_info = {
243       sizeof(HildonFontSelectionDialogClass),
244       NULL,       /* base_init */
245       NULL,       /* base_finalize */
246       (GClassInitFunc) hildon_font_selection_dialog_class_init,
247       NULL,       /* class_finalize */
248       NULL,       /* class_data */
249       sizeof(HildonFontSelectionDialog),
250       0,  /* n_preallocs */
251       (GInstanceInitFunc) hildon_font_selection_dialog_init,
252     };
253
254     font_selection_dialog_type =
255       g_type_register_static(GTK_TYPE_DIALOG,
256                              "HildonFontSelectionDialog",
257                              &fontsel_diag_info, 0);
258   }
259
260   return font_selection_dialog_type;
261 }
262
263 static void
264 hildon_font_selection_dialog_get_property (GObject      *object,
265                                            guint         prop_id,
266                                            GValue       *value,
267                                            GParamSpec   *pspec)
268 {
269   gint i;
270   GdkColor *color = NULL;
271   
272   HildonFontSelectionDialogPrivate *priv =
273     HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(
274         HILDON_FONT_SELECTION_DIALOG(object));
275   
276   
277   switch (prop_id)
278     {
279     case PROP_FAMILY:
280       i = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->cbx_font_type));
281       if(i >= 0 && i < priv->n_families)
282         g_value_set_string(value, 
283                            pango_font_family_get_name(priv->families[i]));
284       else
285         g_value_set_string(value, "Nokia Sans");
286       break;
287       
288     case PROP_FAMILY_SET:
289       i = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->cbx_font_type));
290       if(i >= 0 && i < priv->n_families)
291         g_value_set_boolean(value, TRUE);
292       else
293         g_value_set_boolean(value, FALSE);
294       break;
295       
296     case PROP_SIZE:
297       i = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->cbx_font_size));
298       if(i >= 0 && i < G_N_ELEMENTS(font_sizes))
299         g_value_set_int(value, font_sizes[i]);
300       else
301         g_value_set_int(value, 16);
302       break;
303       
304     case PROP_SIZE_SET:
305       i = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->cbx_font_size));
306       if(i >= 0 && i < G_N_ELEMENTS(font_sizes))
307         g_value_set_boolean(value, TRUE);
308       else
309         g_value_set_boolean(value, FALSE);
310       break;
311
312     case PROP_COLOR:
313       color = hildon_color_button_get_color
314         (HILDON_COLOR_BUTTON(priv->font_color_button));
315       g_value_set_boxed(value, (gconstpointer) color);
316       if(color != NULL)
317         gdk_color_free(color);
318       break;
319       
320     case PROP_COLOR_SET:
321       g_value_set_boolean(value, priv->color_set);
322       break;
323
324     case PROP_BOLD:
325       g_value_set_boolean(value, 
326         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->chk_bold)));
327       break;
328
329     case PROP_BOLD_SET:
330       g_value_set_boolean(value,
331         !gtk_toggle_button_get_inconsistent
332         (GTK_TOGGLE_BUTTON(priv->chk_bold)));
333       break;
334       
335     case PROP_ITALIC:
336       g_value_set_boolean(value, 
337         gtk_toggle_button_get_active
338         (GTK_TOGGLE_BUTTON(priv->chk_italic)));
339       break;
340
341     case PROP_ITALIC_SET:
342       g_value_set_boolean(value,
343         !gtk_toggle_button_get_inconsistent
344         (GTK_TOGGLE_BUTTON(priv->chk_italic)));
345       break;
346       
347     case PROP_UNDERLINE:
348       g_value_set_boolean(value, 
349         gtk_toggle_button_get_active
350         (GTK_TOGGLE_BUTTON(priv->chk_underline)));
351       break;
352
353     case PROP_UNDERLINE_SET:
354       g_value_set_boolean(value,
355         !gtk_toggle_button_get_inconsistent
356         (GTK_TOGGLE_BUTTON(priv->chk_underline)));
357       break;
358       
359     case PROP_STRIKETHROUGH:
360       g_value_set_boolean(value, 
361         gtk_toggle_button_get_active
362         (GTK_TOGGLE_BUTTON(priv->chk_strikethrough)));
363       break;
364
365     case PROP_STRIKETHROUGH_SET:
366       g_value_set_boolean(value,
367         !gtk_toggle_button_get_inconsistent
368         (GTK_TOGGLE_BUTTON(priv->chk_strikethrough)));
369       break;
370
371     case PROP_POSITION:
372       i = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->cbx_positioning));
373       if(i == 1)/*super*/
374         g_value_set_int(value, 1);
375       else if(i == 2)/*sub*/
376         g_value_set_int(value, -1);
377       else
378         g_value_set_int(value, 0);
379       break;
380       
381     case PROP_POSITION_SET:
382       i = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->cbx_positioning));
383       if(i >= 0 && i < 3)
384         g_value_set_boolean(value, TRUE);
385       else
386         g_value_set_boolean(value, FALSE);
387       break;
388     
389     case PROP_PREVIEW_TEXT:
390         g_value_set_string(value,
391                 hildon_font_selection_dialog_get_preview_text(
392                     HILDON_FONT_SELECTION_DIALOG(object)));
393       break;
394     
395     default:
396       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
397       break;
398     }
399 }
400
401 static void 
402 hildon_font_selection_dialog_set_property (GObject         *object,
403                                            guint            prop_id,
404                                            const GValue    *value,
405                                            GParamSpec      *pspec)
406 {
407   gint i, size;
408   const gchar *str;
409   gboolean b;
410   GdkColor *color = NULL;
411   GdkColor black;
412   
413   HildonFontSelectionDialogPrivate *priv =
414     HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(
415         HILDON_FONT_SELECTION_DIALOG(object));
416   black.red = black.green = black.blue = 0;
417   
418   switch (prop_id)
419     {
420     case PROP_FAMILY:
421       str = g_value_get_string(value);
422       for(i = 0; i < priv->n_families; i++)
423         {
424           if(strcmp(str, pango_font_family_get_name(priv->families[i]))
425              == 0)
426             {
427               gtk_combo_box_set_active(GTK_COMBO_BOX(priv->cbx_font_type), i);
428               break;
429             }
430         }
431       break;
432       
433     case PROP_FAMILY_SET:
434       b = g_value_get_boolean(value);
435       if(!b)
436         gtk_combo_box_set_active(GTK_COMBO_BOX(priv->cbx_font_type), -1);
437       break;
438     
439     case PROP_SIZE:
440       size = g_value_get_int(value);
441       for(i = 0; i < G_N_ELEMENTS(font_sizes); i++)
442         {
443           if(size == font_sizes[i])
444             {
445               gtk_combo_box_set_active(GTK_COMBO_BOX(priv->cbx_font_size), i);
446               break;
447             }
448         }
449       break;
450       
451     case PROP_SIZE_SET:
452       b = g_value_get_boolean(value);
453       if(!b)
454         gtk_combo_box_set_active(GTK_COMBO_BOX(priv->cbx_font_size), -1);
455       break;
456
457     case PROP_COLOR:
458       color = (GdkColor *) g_value_get_boxed(value);
459       if(color != NULL)
460         hildon_color_button_set_color(HILDON_COLOR_BUTTON
461                                       (priv->font_color_button),
462                                       color);
463       else
464         hildon_color_button_set_color(HILDON_COLOR_BUTTON
465                                       (priv->font_color_button),
466                                       &black);
467       break;
468
469     case PROP_COLOR_SET:
470       priv->color_set = g_value_get_boolean(value);
471       if(!priv->color_set)
472         {
473           /*set color to black, but block our signal handler*/
474           g_signal_handler_block((gpointer) priv->font_color_button,
475                                  priv->color_modified_signal_handler);
476           
477           hildon_color_button_set_color(HILDON_COLOR_BUTTON
478                                         (priv->font_color_button), 
479                                         &black);
480           
481           g_signal_handler_unblock((gpointer) priv->font_color_button,
482                                  priv->color_modified_signal_handler);
483         }
484       break;
485
486     case PROP_BOLD:
487       /*this call will make sure that we dont get extra clicked signal*/
488       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(priv->chk_bold),
489                                          FALSE);
490       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->chk_bold),
491                                    g_value_get_boolean(value));
492       break;
493
494     case PROP_BOLD_SET:
495       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(priv->chk_bold),
496                                          !g_value_get_boolean(value));
497       break;
498       
499     case PROP_ITALIC:
500       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(priv->chk_italic),
501                                          FALSE);
502       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->chk_italic),
503                                    g_value_get_boolean(value));
504       break;
505
506     case PROP_ITALIC_SET:
507       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(priv->chk_italic),
508                                          !g_value_get_boolean(value));
509       break;
510       
511     case PROP_UNDERLINE:
512       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON
513                                          (priv->chk_underline),
514                                          FALSE);
515       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->chk_underline),
516                                    g_value_get_boolean(value));
517       break;
518
519     case PROP_UNDERLINE_SET:
520       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(priv->chk_underline),
521                                          !g_value_get_boolean(value));
522       break;
523   
524     case PROP_STRIKETHROUGH:
525       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON
526                                          (priv->chk_strikethrough),
527                                          FALSE);
528       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->chk_strikethrough),
529                                    g_value_get_boolean(value));
530       break;
531
532     case PROP_STRIKETHROUGH_SET:
533       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON
534                                          (priv->chk_strikethrough),
535                                          !g_value_get_boolean(value));
536       break;
537
538     case PROP_POSITION:
539       i = g_value_get_int(value);
540       if( i == 1 )
541         gtk_combo_box_set_active(GTK_COMBO_BOX(priv->cbx_positioning), 1);
542       else if(i == -1)
543         gtk_combo_box_set_active(GTK_COMBO_BOX(priv->cbx_positioning), 2);
544       else
545         gtk_combo_box_set_active(GTK_COMBO_BOX(priv->cbx_positioning), 0);
546       break;
547       
548     case PROP_POSITION_SET:
549       b = g_value_get_boolean(value);
550       if(!b)
551         gtk_combo_box_set_active(GTK_COMBO_BOX(priv->cbx_positioning), -1);
552       break;
553
554     case PROP_PREVIEW_TEXT:
555       hildon_font_selection_dialog_set_preview_text(
556               HILDON_FONT_SELECTION_DIALOG(object),
557               g_value_get_string(value));
558       break;
559     
560     default:
561       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
562       break;
563     }
564 }
565
566 static void
567 hildon_font_selection_dialog_class_init(HildonFontSelectionDialogClass *
568                                         klass)
569 {
570   GObjectClass *gobject_class;
571
572   font_selection_dialog_parent_class = g_type_class_peek_parent(klass);
573   gobject_class = G_OBJECT_CLASS(klass);
574   gobject_class->finalize = hildon_font_selection_dialog_finalize;
575   gobject_class->get_property = hildon_font_selection_dialog_get_property;
576   gobject_class->set_property = hildon_font_selection_dialog_set_property;
577
578   /* Install property to the class */
579   g_object_class_install_property(gobject_class, PROP_FAMILY,
580                                   g_param_spec_string("family",
581                                   "Font family", "String defines"
582                                   " the font family", "Nokia Sans",
583                                   G_PARAM_READWRITE));
584   
585   g_object_class_install_property(gobject_class, PROP_FAMILY_SET,
586                                   g_param_spec_boolean ("family-set",
587                                   "family inconsistent state",
588                                   "Whether the family property"
589                                   " is inconsistent", FALSE,
590                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
591   
592   g_object_class_install_property(gobject_class, PROP_SIZE,
593                                    g_param_spec_int ("size",
594                                    "Font size",
595                                    "Font size in Pt",
596                                    6, 32, 16,
597                                    G_PARAM_READWRITE));
598   
599   g_object_class_install_property(gobject_class, PROP_SIZE_SET,
600                                   g_param_spec_boolean ("size-set",
601                                   "size inconsistent state",
602                                   "Whether the size property"
603                                   " is inconsistent", FALSE,
604                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
605   
606   g_object_class_install_property(gobject_class, PROP_COLOR,
607                                   g_param_spec_boxed ("color",
608                                   "text color",
609                                   "gdk color for the text",
610                                   GDK_TYPE_COLOR,
611                                   G_PARAM_READWRITE));
612
613   g_object_class_install_property(gobject_class, PROP_COLOR_SET,
614                                   g_param_spec_boolean ("color-set",
615                                   "color inconsistent state",
616                                   "Whether the color property"
617                                   " is inconsistent", FALSE,
618                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
619
620   g_object_class_install_property(gobject_class, PROP_BOLD,
621                                   g_param_spec_boolean ("bold",
622                                   "text weight",
623                                   "Whether the text is bold",
624                                   FALSE,
625                                   G_PARAM_READWRITE));
626   
627   g_object_class_install_property(gobject_class, PROP_BOLD_SET,
628                                   g_param_spec_boolean ("bold-set",
629                                   "bold inconsistent state",
630                                   "Whether the bold"
631                                   " is inconsistent", FALSE,
632                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
633   
634   g_object_class_install_property(gobject_class, PROP_ITALIC,
635                                   g_param_spec_boolean ("italic",
636                                   "text style",
637                                   "Whether the text is italic",
638                                   FALSE,
639                                   G_PARAM_READWRITE));
640   
641   g_object_class_install_property(gobject_class, PROP_ITALIC_SET,
642                                   g_param_spec_boolean ("italic-set",
643                                   "italic inconsistent state",
644                                   "Whether the italic"
645                                   " is inconsistent", FALSE,
646                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
647   
648   g_object_class_install_property(gobject_class, PROP_UNDERLINE,
649                                   g_param_spec_boolean ("underline",
650                                   "text underline",
651                                   "Whether the text is underlined",
652                                   FALSE,
653                                   G_PARAM_READWRITE));
654   
655   g_object_class_install_property(gobject_class, PROP_UNDERLINE_SET,
656                                   g_param_spec_boolean ("underline-set",
657                                   "underline inconsistent state",
658                                   "Whether the underline"
659                                   " is inconsistent", FALSE,
660                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
661   
662   g_object_class_install_property(gobject_class, PROP_STRIKETHROUGH,
663                                   g_param_spec_boolean ("strikethrough",
664                                   "strikethroughed text",
665                                   "Whether the text is strikethroughed",
666                                   FALSE,
667                                   G_PARAM_READWRITE));
668   
669   g_object_class_install_property(gobject_class, PROP_STRIKETHROUGH_SET,
670                                   g_param_spec_boolean ("strikethrough-set",
671                                   "strikethrough inconsistent state",
672                                   "Whether the strikethrough"
673                                   " is inconsistent", FALSE,
674                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
675   
676   g_object_class_install_property(gobject_class, PROP_POSITION,
677                                    g_param_spec_int ("position",
678                                    "Font position",
679                                    "Font position super or subscript",
680                                    -1, 1, 0,
681                                    G_PARAM_READWRITE));
682   
683   g_object_class_install_property(gobject_class, PROP_POSITION_SET,
684                                   g_param_spec_boolean ("position-set",
685                                   "position inconsistent state",
686                                   "Whether the position"
687                                   " is inconsistent", FALSE,
688                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
689   
690   g_object_class_install_property(gobject_class, PROP_PREVIEW_TEXT,
691                                   g_param_spec_string("preview-text",
692                                   "Preview Text", 
693                                   "the text in preview dialog, which does" 
694                                   "not include the reference text",
695                                   "",
696                                   G_PARAM_READWRITE));
697   
698
699   g_type_class_add_private(klass,
700                            sizeof(struct _HildonFontSelectionDialogPrivate));
701 }
702
703
704 static void 
705 hildon_font_selection_dialog_init(HildonFontSelectionDialog *fontseldiag)
706 {
707   HildonFontSelectionDialogPrivate *priv =
708     HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(fontseldiag);
709   GtkWidget *preview_button;
710   
711   priv->notebook = GTK_NOTEBOOK(gtk_notebook_new());
712
713   hildon_font_selection_dialog_construct_notebook(fontseldiag);
714   
715   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fontseldiag)->vbox),
716                      GTK_WIDGET(priv->notebook), TRUE, TRUE, 0);
717   
718   /* Add dialog buttons */
719   gtk_dialog_add_button(GTK_DIALOG(fontseldiag),
720                         _("ecdg_bd_font_dialog_ok"),
721                         GTK_RESPONSE_OK);
722   
723   preview_button = gtk_button_new_with_label(_("ecdg_bd_font_dialog_preview"));
724   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fontseldiag)->action_area), 
725                      preview_button, FALSE, TRUE, 0);
726   g_signal_connect_swapped(preview_button, "clicked",
727                            G_CALLBACK
728                            (hildon_font_selection_dialog_show_preview),
729                            fontseldiag);
730   gtk_widget_show(preview_button);
731
732   gtk_dialog_add_button(GTK_DIALOG(fontseldiag),
733                         _("ecdg_bd_font_dialog_cancel"),
734                         GTK_RESPONSE_CANCEL);
735
736   /*Set default preview text*/
737   priv->preview_text = g_strdup(_("ecdg_fi_preview_font_preview_text"));
738
739   gtk_window_set_title(GTK_WINDOW(fontseldiag), _("ecdg_ti_font"));
740   /*here is the line to make sure that notebook has the default focus*/
741   gtk_container_set_focus_child(GTK_CONTAINER(GTK_DIALOG(fontseldiag)->vbox),
742                                 GTK_WIDGET(priv->notebook));
743 }
744
745 static void 
746 hildon_font_selection_dialog_construct_notebook (HildonFontSelectionDialog
747                                                  *fontsel)
748 {
749   gint i;
750   GtkWidget *vbox_tab[3];
751   GtkWidget *font_color_box;
752   GtkWidget *caption_control;
753   GtkSizeGroup *group;
754   
755   HildonFontSelectionDialogPrivate *priv =
756     HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(fontsel);
757
758   for (i = 0; i < 3; i++)
759     vbox_tab[i] = gtk_vbox_new(TRUE, 0);
760
761   group =
762     GTK_SIZE_GROUP(gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL));
763   
764   /* Build the first page of the GtkNotebook: font style */
765   priv->cbx_font_type = gtk_combo_box_new_text();
766   hildon_font_selection_dialog_show_available_fonts(fontsel);
767   caption_control = hildon_caption_new(group,
768                                        _("ecdg_fi_font_font"),
769                                        priv->cbx_font_type,
770                                        NULL,
771                                        HILDON_CAPTION_OPTIONAL);
772   gtk_box_pack_start(GTK_BOX(vbox_tab[0]), caption_control,
773                      FALSE, FALSE, 0);
774
775   priv->cbx_font_size = gtk_combo_box_new_text();
776   hildon_font_selection_dialog_show_available_sizes(priv);
777   caption_control = hildon_caption_new(group,
778                                        _("ecdg_fi_font_size"),
779                                        priv->cbx_font_size,
780                                        NULL,
781                                        HILDON_CAPTION_OPTIONAL);
782   gtk_box_pack_start(GTK_BOX(vbox_tab[0]), caption_control,
783                      FALSE, FALSE, 0);
784
785   font_color_box = gtk_hbox_new(FALSE, 0);
786   priv->font_color_button = hildon_color_button_new();
787   priv->color_set = FALSE;
788   priv->color_modified_signal_handler = 
789     g_signal_connect(G_OBJECT(priv->font_color_button), "notify::color",
790                      G_CALLBACK(color_modified_cb), (gpointer) priv);
791   gtk_box_pack_start(GTK_BOX(font_color_box),
792                      priv->font_color_button, FALSE, FALSE, 0);
793   
794   /*dummy widget for packing purpose only*/
795   gtk_box_pack_start(GTK_BOX(font_color_box), gtk_label_new(""),
796                      TRUE, TRUE, 0);
797   
798   caption_control =
799     hildon_caption_new(group, _("ecdg_fi_font_color_selector"),
800                        font_color_box,
801                        NULL, HILDON_CAPTION_OPTIONAL);
802   
803   gtk_box_pack_start(GTK_BOX(vbox_tab[0]), caption_control,
804                      FALSE, FALSE, 0);
805
806   /* Build the second page of the GtkNotebook: font formatting */ 
807   priv->chk_bold = gtk_check_button_new();
808   caption_control = hildon_caption_new(group,
809                                        _("ecdg_fi_font_bold"),
810                                        priv->chk_bold,
811                                        NULL,
812                                        HILDON_CAPTION_OPTIONAL);
813   gtk_box_pack_start(GTK_BOX(vbox_tab[1]), caption_control,
814                      FALSE, FALSE, 0);
815   g_signal_connect(G_OBJECT(priv->chk_bold), "clicked", 
816                    G_CALLBACK(toggle_clicked), NULL);
817
818   priv->chk_italic = gtk_check_button_new();
819   caption_control =
820     hildon_caption_new(group, _("ecdg_fi_font_italic"),
821                        priv->chk_italic,
822                        NULL, HILDON_CAPTION_OPTIONAL);
823   gtk_box_pack_start(GTK_BOX(vbox_tab[1]), caption_control,
824                      FALSE, FALSE, 0);
825   g_signal_connect(G_OBJECT(priv->chk_italic), "clicked", 
826                    G_CALLBACK(toggle_clicked), NULL);
827
828   priv->chk_underline = gtk_check_button_new();
829   caption_control =
830     hildon_caption_new(group, _("ecdg_fi_font_underline"),
831                        priv->chk_underline, NULL,
832                        HILDON_CAPTION_OPTIONAL);
833   gtk_box_pack_start(GTK_BOX(vbox_tab[1]), caption_control,
834                      FALSE, FALSE, 0);
835   g_signal_connect(G_OBJECT(priv->chk_underline), "clicked", 
836                    G_CALLBACK(toggle_clicked), NULL);
837
838   /* Build the third page of the GtkNotebook: other font properties */
839   priv->chk_strikethrough = gtk_check_button_new();
840   caption_control =
841     hildon_caption_new(group, _("ecdg_fi_font_strikethrough"),
842                        priv->chk_strikethrough, NULL,
843                        HILDON_CAPTION_OPTIONAL);
844   gtk_box_pack_start(GTK_BOX(vbox_tab[2]), caption_control,
845                      FALSE, FALSE, 0);
846   g_signal_connect(G_OBJECT(priv->chk_strikethrough), "clicked", 
847                    G_CALLBACK(toggle_clicked), NULL);
848
849   priv->cbx_positioning = gtk_combo_box_new_text();
850   hildon_font_selection_dialog_show_available_positionings(priv);
851   caption_control =
852     hildon_caption_new(group, _("ecdg_fi_font_special"),
853                        priv->cbx_positioning, NULL,
854                        HILDON_CAPTION_OPTIONAL);
855   gtk_box_pack_start(GTK_BOX(vbox_tab[2]), caption_control,
856                      FALSE, FALSE, 0);
857   
858   /* Populate notebook */
859   gtk_notebook_insert_page(priv->notebook, vbox_tab[0], NULL, 0);
860   gtk_notebook_insert_page(priv->notebook, vbox_tab[1], NULL, 1);
861   gtk_notebook_insert_page(priv->notebook, vbox_tab[2], NULL, 2);
862   gtk_notebook_set_tab_label_text(priv->notebook, vbox_tab[0],
863                                   _("ecdg_ti_font_dialog_style"));
864   gtk_notebook_set_tab_label_text(priv->notebook, vbox_tab[1],
865                                   _("ecdg_ti_font_dialog_format"));
866   gtk_notebook_set_tab_label_text(priv->notebook, vbox_tab[2],
867                                   _("ecdg_ti_font_dialog_other"));
868   
869   gtk_widget_show_all(GTK_WIDGET(priv->notebook));
870 }
871
872 static void 
873 color_modified_cb(HildonColorButton *button, GParamSpec *pspec, gpointer data)
874 {
875   HildonFontSelectionDialogPrivate *priv = 
876     (HildonFontSelectionDialogPrivate *) data;
877
878   priv->color_set = TRUE;
879 }
880
881 static void 
882 hildon_font_selection_dialog_finalize(GObject * object)
883 {
884   HildonFontSelectionDialogPrivate *priv;
885   HildonFontSelectionDialog *fontsel;
886
887   g_assert(HILDON_IS_FONT_SELECTION_DIALOG(object));
888   fontsel = HILDON_FONT_SELECTION_DIALOG(object);
889
890   priv = HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(fontsel);
891   
892   g_free(priv->preview_text);
893   g_free(priv->families);
894
895   if (G_OBJECT_CLASS(font_selection_dialog_parent_class)->finalize)
896     G_OBJECT_CLASS(font_selection_dialog_parent_class)->finalize(object);
897 }
898
899 static int 
900 cmp_families(const void *a, const void *b)
901 {
902   const char *a_name =
903     pango_font_family_get_name(*(PangoFontFamily **) a);
904   const char *b_name =
905     pango_font_family_get_name(*(PangoFontFamily **) b);
906
907   return g_utf8_collate(a_name, b_name);
908 }
909
910 static gboolean
911 hildon_font_selection_dialog_preview_key_press(GtkWidget * widget,
912                                                GdkEventKey * event,
913                                                gpointer data)
914 {
915   g_return_val_if_fail(widget, FALSE);
916   g_return_val_if_fail(event, FALSE);
917
918   if (event->keyval == GDK_Escape) 
919     {
920       gtk_dialog_response(GTK_DIALOG(widget), GTK_RESPONSE_CANCEL);
921       return TRUE;
922     }
923
924   return FALSE;
925 }
926
927 static void
928 add_preview_text_attr(PangoAttrList *list, PangoAttribute *attr, 
929                       guint start, guint len)
930 {
931   attr->start_index = start;
932   attr->end_index = start + len;
933   pango_attr_list_insert(list, attr);
934 }
935
936 static PangoAttrList*
937 hildon_font_selection_dialog_create_attrlist(HildonFontSelectionDialog *
938                                          fontsel, guint start_index, guint len)
939 {
940   PangoAttrList *list;
941   PangoAttribute *attr;
942   gint size, position;
943   gboolean family_set, size_set, color_set, bold, bold_set,
944            italic, italic_set, underline, underline_set,
945            strikethrough, strikethrough_set, position_set;
946   GdkColor *color = NULL;
947   gchar *family = NULL;
948
949   list = pango_attr_list_new();
950  
951   g_object_get(G_OBJECT(fontsel),
952                "family", &family, "family-set", &family_set,
953                "size", &size, "size-set", &size_set,
954                "color", &color, "color-set", &color_set,
955                "bold", &bold, "bold-set", &bold_set,
956                "italic", &italic, "italic-set", &italic_set,
957                "underline", &underline, "underline-set", &underline_set,
958                "strikethrough", &strikethrough, "strikethrough-set", 
959                &strikethrough_set, "position", &position, 
960                "position-set", &position_set, NULL);
961
962   /*family*/
963   if(family_set)
964     {
965       attr = pango_attr_family_new(family);
966       add_preview_text_attr(list, attr, start_index, len);
967     }
968   g_free(family);
969   
970   /*size*/
971   if(size_set)
972     {
973       attr = pango_attr_size_new(size * PANGO_SCALE);
974       add_preview_text_attr(list, attr, start_index, len);
975     }
976   
977   /*color*/
978   if(color_set)
979     {
980       attr = pango_attr_foreground_new(color->red, color->green, color->blue);
981       add_preview_text_attr(list, attr, start_index, len);
982     }
983   
984   if(color != NULL)
985     gdk_color_free(color);
986   
987   /*weight*/
988   if(bold_set)
989     {
990       if(bold)
991         attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
992       else
993         attr = pango_attr_weight_new(PANGO_WEIGHT_NORMAL);
994
995       add_preview_text_attr(list, attr, start_index, len);
996     }
997   
998   /*style*/
999   if(italic_set)
1000     {
1001       if(italic)
1002         attr = pango_attr_style_new(PANGO_STYLE_ITALIC);
1003       else
1004         attr = pango_attr_style_new(PANGO_STYLE_NORMAL);
1005
1006       add_preview_text_attr(list, attr, start_index, len);
1007     }
1008   
1009   /*underline*/
1010   if(underline_set)
1011     {
1012       if(underline)
1013         attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
1014       else
1015         attr = pango_attr_underline_new(PANGO_UNDERLINE_NONE);
1016
1017       add_preview_text_attr(list, attr, start_index, len);
1018     }
1019   
1020   /*strikethrough*/
1021   if(strikethrough_set)
1022     {
1023       if(strikethrough)
1024         attr = pango_attr_strikethrough_new(TRUE);
1025       else
1026         attr = pango_attr_strikethrough_new(FALSE);
1027
1028       add_preview_text_attr(list, attr, start_index, len);
1029     }
1030   
1031   /*position*/
1032   if(position_set)
1033     {
1034       switch(position)
1035         {
1036         case 1: /*super*/
1037           attr = pango_attr_rise_new(SUPERSCRIPT_RISE);
1038           break;
1039         case -1: /*sub*/
1040           attr = pango_attr_rise_new(SUBSCRIPT_LOW);
1041           break;
1042         default: /*normal*/
1043           attr = pango_attr_rise_new(0);
1044           break;
1045         }
1046
1047       add_preview_text_attr(list, attr, start_index, len);
1048     }
1049   
1050   return list;
1051 }
1052
1053 static void
1054 hildon_font_selection_dialog_show_preview(HildonFontSelectionDialog *
1055                                           fontsel)
1056 {
1057   HildonFontSelectionDialogPrivate *priv =
1058     HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(fontsel);
1059   gint size;
1060   gboolean family_set, size_set;
1061   PangoAttribute *attr;
1062   PangoAttrList *list;
1063   GtkWidget *preview_dialog;
1064   GtkWidget *preview_label;
1065   gchar *str = NULL;
1066   
1067   /*Preview dialog init*/
1068   preview_dialog=
1069     gtk_dialog_new_with_buttons(_("ecdg_ti_preview_font"), NULL,
1070                                 GTK_DIALOG_MODAL |
1071                                 GTK_DIALOG_DESTROY_WITH_PARENT |
1072                                 GTK_DIALOG_NO_SEPARATOR,
1073                                 _("ecdg_bd_font_dialog_ok"),
1074                                 GTK_RESPONSE_ACCEPT,
1075                                 NULL);
1076
1077   str = g_strconcat(REFERENCE_LINE, priv->preview_text, 0);
1078   preview_label = gtk_label_new(str);
1079   g_free(str);
1080   str = NULL;
1081
1082   gtk_container_add(GTK_CONTAINER(GTK_DIALOG(preview_dialog)->vbox),
1083                     preview_label);
1084
1085   /* set keypress handler (ESC hardkey) */
1086   g_signal_connect(G_OBJECT(preview_dialog), "key-press-event",
1087                    G_CALLBACK
1088                    (hildon_font_selection_dialog_preview_key_press),
1089                    NULL);
1090
1091   /*Set the font*/
1092   list = hildon_font_selection_dialog_create_attrlist(fontsel, 
1093                                 strlen(REFERENCE_LINE),
1094                                 strlen(priv->preview_text));
1095
1096   g_object_get(G_OBJECT(fontsel), "family", &str, "family-set",
1097                &family_set, "size", &size, "size-set", &size_set,
1098                NULL);
1099   /*make reference text to have the same fontface and size*/
1100   if(family_set)
1101     {
1102       attr = pango_attr_family_new(str);
1103       add_preview_text_attr(list, attr, 0, strlen(REFERENCE_LINE));
1104     }
1105   g_free(str);
1106   
1107   /*size*/
1108   if(size_set)
1109     {
1110       attr = pango_attr_size_new(size * PANGO_SCALE);
1111       add_preview_text_attr(list, attr, 0, strlen(REFERENCE_LINE));
1112     }
1113   
1114   gtk_label_set_attributes(GTK_LABEL(preview_label), list);
1115   pango_attr_list_unref(list);
1116   
1117   /*And show the dialog*/
1118   gtk_window_set_transient_for(GTK_WINDOW(preview_dialog), 
1119                                GTK_WINDOW(fontsel));
1120   gtk_widget_show_all(preview_dialog);
1121   gtk_dialog_run(GTK_DIALOG(preview_dialog));
1122   gtk_widget_destroy(preview_dialog);
1123 }
1124
1125 static void
1126 hildon_font_selection_dialog_show_available_fonts(HildonFontSelectionDialog 
1127                                                   *fontsel)
1128
1129 {
1130   gint i;
1131   
1132   HildonFontSelectionDialogPrivate *priv =
1133     HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(fontsel);
1134
1135   pango_context_list_families(gtk_widget_get_pango_context
1136                               (GTK_WIDGET(fontsel)), &priv->families,
1137                               &priv->n_families);
1138
1139   qsort(priv->families, priv->n_families, sizeof(PangoFontFamily *),
1140         cmp_families);
1141
1142
1143   for (i = 0; i < priv->n_families; i++) 
1144     {
1145       const gchar *name = pango_font_family_get_name(priv->families[i]);
1146
1147       gtk_combo_box_append_text(GTK_COMBO_BOX(priv->cbx_font_type),
1148                                 name);
1149     }
1150 }
1151
1152
1153 static void
1154 hildon_font_selection_dialog_show_available_positionings
1155                                              (HildonFontSelectionDialogPrivate
1156                                               *priv)
1157 {
1158   gtk_combo_box_append_text(GTK_COMBO_BOX(priv->cbx_positioning),
1159                             _("ecdg_va_font_printpos_1"));
1160   gtk_combo_box_append_text(GTK_COMBO_BOX(priv->cbx_positioning),
1161                             _("ecdg_va_font_printpos_2"));
1162   gtk_combo_box_append_text(GTK_COMBO_BOX(priv->cbx_positioning),
1163                             _("ecdg_va_font_printpos_3"));
1164 }
1165
1166 /*Loads the sizes from a pre-allocated table*/
1167 static void
1168 hildon_font_selection_dialog_show_available_sizes
1169                                              (HildonFontSelectionDialogPrivate
1170                                               *priv)
1171 {
1172   gchar *size_str;
1173   gint i;
1174
1175   for (i = 0; i < G_N_ELEMENTS(font_sizes); i++) 
1176     {
1177       size_str = g_strdup_printf ("%i %s",
1178                                   font_sizes[i],
1179                                   _("ecdg_va_font_size_trailer"));
1180
1181       gtk_combo_box_append_text(GTK_COMBO_BOX(priv->cbx_font_size),
1182                                 size_str);
1183       g_free (size_str);
1184     }
1185 }
1186
1187 static
1188 void check_tags(gpointer data, gpointer user_data)
1189 {
1190   gchar *font_family;
1191   GdkColor *fore_color =  NULL;
1192   gint p_size, p_weight, p_style, p_underline, p_rise;
1193   gboolean b_st, ff_s, size_s, fgc_s, w_s, ss_s, u_s, sth_s, r_s;
1194   
1195   GtkTextTag *tag = (GtkTextTag*) data;
1196   HildonFontSelectionDialogSettings *settings = 
1197     (HildonFontSelectionDialogSettings *) user_data;
1198   HildonFontSelectionDialogPrivate *priv = 
1199     HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(settings->fsd);
1200   
1201   /*get all the properties*/
1202   g_object_get(G_OBJECT(tag),
1203                "family", &font_family, "family-set", &ff_s,
1204                "size", &p_size, "size-set", &size_s,
1205                "foreground-gdk", &fore_color, "foreground-set", &fgc_s,
1206                "weight", &p_weight, "weight-set", &w_s,
1207                "style", &p_style, "style-set", &ss_s,
1208                "underline", &p_underline, "underline-set", &u_s,
1209                "strikethrough", &b_st, "strikethrough-set", &sth_s, 
1210                "rise", &p_rise, "rise-set", & r_s,
1211                NULL);
1212   
1213   /* Check that the given values are valid. 
1214    * If not, set the combobox row indicator to 'inconsistent' */
1215   if(ff_s)
1216     {
1217       gint new_f = -1;
1218       gint i;
1219       
1220       for(i = 0; i < priv->n_families; i++)
1221         {
1222           if(strcmp(font_family, 
1223                     pango_font_family_get_name(priv->families[i])) == 0)
1224             {
1225               new_f = i;
1226               break;
1227             }
1228         }
1229       
1230       if(settings->family == -1)
1231         settings->family = new_f;
1232       else if(settings->family != -2 && 
1233               settings->family != new_f)
1234         settings->family = -2;/*inconsist*/
1235
1236       g_free(font_family);
1237     }
1238   
1239   if(size_s)
1240     {
1241       gint new_size = -1;
1242       gint i;
1243       
1244       for(i = 0; i < G_N_ELEMENTS(font_sizes); i++)
1245         {
1246           if(p_size == font_sizes[i] * PANGO_SCALE)
1247             {
1248               new_size = i;
1249               break;
1250             }
1251         }
1252       
1253       if(settings->size == -1)
1254         settings->size = new_size;
1255       else if(settings->size != -2 && 
1256               settings->size != new_size)
1257         settings->size = -2;/*inconsist*/
1258     }
1259   
1260   if(fgc_s && settings->color == NULL 
1261      && !settings->color_inconsist)
1262         settings->color = fore_color;
1263   else if(fore_color != NULL)
1264     {
1265       if(!gdk_color_equal(fore_color, settings->color) 
1266          && fgc_s)
1267         settings->color_inconsist = TRUE;
1268       
1269       gdk_color_free(fore_color);
1270     }
1271
1272   if(w_s)
1273     settings->weight |= p_weight == PANGO_WEIGHT_NORMAL ? OFF_BIT : ON_BIT;
1274   
1275   if(ss_s)
1276     settings->style |= p_style == PANGO_STYLE_NORMAL ? OFF_BIT : ON_BIT;
1277   
1278   if(u_s)
1279     settings->underline |= 
1280       p_underline == PANGO_UNDERLINE_NONE ? OFF_BIT : ON_BIT;
1281   
1282   if(sth_s)
1283     settings->strikethrough |= b_st ? ON_BIT : OFF_BIT;
1284
1285   if(r_s)
1286     {
1287       gint new_rs = -1;
1288       
1289       if(p_rise == 0)
1290         new_rs = 0;/*normal*/
1291       else if (p_rise > 0)
1292         new_rs = 1;/*super*/
1293       else
1294         new_rs = 2;/*sub*/
1295
1296       if(settings->position == -1)
1297         settings->position = new_rs;
1298       else if(settings->position != -2 && 
1299               settings->position != new_rs)
1300         settings->position = -2;/*inconsist*/
1301     }
1302 }
1303
1304 static
1305 void check_attrs(gpointer data, gpointer user_data)
1306 {
1307   PangoAttribute *attr = (PangoAttribute *) data;
1308   HildonFontSelectionDialogSettings *settings = 
1309     (HildonFontSelectionDialogSettings *) user_data;
1310   HildonFontSelectionDialogPrivate *priv = 
1311     HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(settings->fsd);
1312   
1313   gchar *family;
1314   GdkColor color;
1315   gint i;
1316   gint size, weight, style, underline, strikethrough, rise;
1317   gint new_f = -1, new_size = -1, new_rise = -1;
1318
1319   /* Check that the given values are valid.
1320    * If not, set the combobox row indicator to 'inconsistent' */
1321   switch(attr->klass->type)
1322     {
1323     case PANGO_ATTR_FAMILY:
1324       family = ((PangoAttrString *) attr)->value;
1325
1326       for(i = 0; i < priv->n_families; i++)
1327         {
1328           if(strcmp(family, 
1329                     pango_font_family_get_name(priv->families[i])) == 0)
1330             {
1331               new_f = i;
1332               break;
1333             }
1334         }
1335
1336       if(settings->family == -1)
1337         settings->family = new_f;
1338       else if(settings->family != -2 && 
1339               settings->family != new_f)
1340         settings->family = -2;/*inconsist*/
1341       
1342       break;
1343     case PANGO_ATTR_SIZE:
1344       size = ((PangoAttrInt *) attr)->value;
1345       
1346       for(i = 0; i < G_N_ELEMENTS(font_sizes); i++)
1347         {
1348           if(size == font_sizes[i] * PANGO_SCALE)
1349             {
1350               new_size = i;
1351               break;
1352             }
1353         }
1354       
1355       if(settings->size == -1)
1356         settings->size = new_size;
1357       else if(settings->size != -2 && 
1358               settings->size != new_size)
1359         settings->size = -2;/*inconsist*/
1360
1361       break;
1362     case PANGO_ATTR_FOREGROUND:
1363       color.red = ((PangoAttrColor *) attr)->color.red;
1364       color.green = ((PangoAttrColor *) attr)->color.green;
1365       color.blue = ((PangoAttrColor *) attr)->color.blue;
1366
1367       if(!settings->color_inconsist &&  settings->color == NULL)
1368         settings->color = gdk_color_copy(&color);
1369       else if(settings->color != NULL && 
1370               !gdk_color_equal(&color, settings->color))
1371         settings->color_inconsist = TRUE;
1372
1373       break;
1374     case PANGO_ATTR_WEIGHT:
1375       weight = ((PangoAttrInt *) attr)->value;
1376
1377       settings->weight |= weight == PANGO_WEIGHT_NORMAL ? OFF_BIT : ON_BIT;
1378       
1379       break;
1380     case PANGO_ATTR_STYLE:
1381       style = ((PangoAttrInt *) attr)->value;
1382
1383       settings->style |= style == PANGO_STYLE_NORMAL ? OFF_BIT : ON_BIT; 
1384       
1385       break;
1386     case PANGO_ATTR_UNDERLINE:
1387       underline = ((PangoAttrInt *) attr)->value;
1388
1389       settings->underline |= 
1390         underline == PANGO_UNDERLINE_NONE ? OFF_BIT : ON_BIT;
1391   
1392       break;
1393     case PANGO_ATTR_STRIKETHROUGH:
1394       strikethrough = ((PangoAttrInt *) attr)->value;
1395       
1396       settings->strikethrough |= strikethrough ? ON_BIT : OFF_BIT;
1397
1398       break;
1399     case PANGO_ATTR_RISE:
1400       rise = ((PangoAttrInt *) attr)->value;
1401       
1402       if(rise == 0)
1403         new_rise = 0;/*normal*/
1404       else if (rise > 0)
1405         new_rise = 1;/*super*/
1406       else
1407         new_rise = 2;/*sub*/
1408
1409       if(settings->position == -1)
1410         settings->position = new_rise;
1411       else if(settings->position != -2 && 
1412               settings->position != new_rise)
1413         settings->position = -2;/*inconsist*/
1414
1415       break;
1416     default:
1417       break;
1418     }
1419
1420   pango_attribute_destroy(attr);
1421 }
1422
1423 static void
1424 settings_init(HildonFontSelectionDialogSettings *settings,
1425               HildonFontSelectionDialog  *fsd)
1426 {
1427   settings->fsd = fsd;
1428   settings->family = -1;
1429   settings->size = -1;
1430   settings->color = NULL;
1431   settings->color_inconsist = FALSE;
1432   settings->weight = 0;
1433   settings->style = 0;
1434   settings->underline = 0;
1435   settings->strikethrough = 0;
1436   settings->position = -1;
1437 }
1438
1439 static void
1440 bit_mask_toggle(gint mask, GtkToggleButton *button,
1441                 GObject *object, const gchar *prop,
1442                 const gchar *prop_set)
1443 {
1444   
1445   if(mask == 3)
1446     gtk_toggle_button_set_inconsistent(button, TRUE);
1447   else
1448     {
1449       gtk_toggle_button_set_inconsistent(button, FALSE);
1450
1451       if(mask == 1)
1452         gtk_toggle_button_set_active(button, TRUE);
1453       else
1454         gtk_toggle_button_set_active(button, FALSE);
1455
1456       g_object_notify(object, prop);
1457     }
1458
1459   g_object_notify(object, prop_set);
1460 }
1461
1462 static void
1463 combo_active(gint active, GtkComboBox *box, 
1464              GObject *object, const gchar *prop, const gchar *prop_set)
1465 {
1466   /*probaly not the best function, but we need all these
1467    * parameters to keep things together*/
1468  
1469   
1470   if(active >= 0)
1471     {
1472       gtk_combo_box_set_active(box, active);
1473       g_object_notify(object, prop);
1474     }
1475   else
1476     gtk_combo_box_set_active(box, -1);
1477
1478   g_object_notify(object, prop_set);
1479 }
1480
1481 static void
1482 settings_apply(HildonFontSelectionDialogSettings *settings)
1483 {
1484
1485   HildonFontSelectionDialogPrivate *priv = 
1486     HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(settings->fsd);
1487   
1488   /*family*/
1489   combo_active(settings->family, GTK_COMBO_BOX(priv->cbx_font_type),
1490                G_OBJECT(settings->fsd), "family", "family-set");
1491   
1492   /*size*/
1493   combo_active(settings->size, GTK_COMBO_BOX(priv->cbx_font_size),
1494                G_OBJECT(settings->fsd), "size", "size-set");
1495   
1496   /*block our signal handler indicating color has been changed by
1497    * the user before set the color, and unblock it after setting
1498    * is done*/
1499   
1500   if(settings->color == NULL || settings->color_inconsist)
1501     {
1502       GdkColor black;
1503
1504       black.red = black.green = black.blue = 0;
1505       g_signal_handler_block((gpointer) priv->font_color_button,
1506                              priv->color_modified_signal_handler);
1507       
1508       g_object_set(G_OBJECT(settings->fsd), "color", &black, "color-set", 
1509                    FALSE, NULL);
1510
1511       g_signal_handler_unblock((gpointer) priv->font_color_button,
1512                                priv->color_modified_signal_handler);
1513     }
1514   else 
1515       g_object_set(G_OBJECT(settings->fsd), "color", settings->color, NULL);
1516   
1517   /*weight*/
1518   bit_mask_toggle(settings->weight, GTK_TOGGLE_BUTTON(priv->chk_bold),
1519                   G_OBJECT(settings->fsd), "bold", "bold-set");
1520   
1521   /*style*/
1522   bit_mask_toggle(settings->style, GTK_TOGGLE_BUTTON(priv->chk_italic),
1523                   G_OBJECT(settings->fsd), "italic", "italic-set");
1524   
1525   /*underline*/
1526   bit_mask_toggle(settings->underline, 
1527                   GTK_TOGGLE_BUTTON(priv->chk_underline), 
1528                   G_OBJECT(settings->fsd), "underline", "underline-set");
1529   
1530   /*strikethrough*/
1531   bit_mask_toggle(settings->strikethrough, 
1532                   GTK_TOGGLE_BUTTON(priv->chk_strikethrough),
1533                   G_OBJECT(settings->fsd), "strikethrough", 
1534                   "strikethrough-set");
1535
1536   /*position*/
1537   combo_active(settings->position, GTK_COMBO_BOX(priv->cbx_positioning),
1538                G_OBJECT(settings->fsd), "position", "position-set");
1539 }
1540
1541 static void
1542 settings_destroy(HildonFontSelectionDialogSettings *settings)
1543 {
1544   if(settings->color != NULL)
1545     gdk_color_free(settings->color);
1546 }
1547
1548 static void
1549 toggle_clicked(GtkButton *button, gpointer data)
1550 {
1551   GtkToggleButton *t_b = GTK_TOGGLE_BUTTON(button);
1552
1553   /*we have to remove the inconsistent state ourselves*/
1554   if(gtk_toggle_button_get_inconsistent(t_b))
1555     {
1556       gtk_toggle_button_set_inconsistent(t_b, FALSE);
1557       gtk_toggle_button_set_active(t_b, FALSE);
1558     }
1559 }
1560
1561 /*******************/
1562 /*Public functions*/
1563 /*******************/
1564
1565 /**
1566  * hildon_font_selection_dialog_new:
1567  * @parent: the parent window.
1568  * @title: the title of font selection dialog.
1569  *
1570  * If NULL is passed for title, then default title
1571  * "Font" will be used.
1572  *
1573  * Return value: a new #HildonFontSelectionDialog.
1574  */
1575 GtkWidget *
1576 hildon_font_selection_dialog_new(GtkWindow * parent,
1577                                  const gchar * title)
1578 {
1579   HildonFontSelectionDialog *fontseldiag;
1580
1581   fontseldiag = g_object_new(HILDON_TYPE_FONT_SELECTION_DIALOG,
1582                              "has-separator", FALSE, NULL);
1583
1584   if (title)
1585     gtk_window_set_title(GTK_WINDOW(fontseldiag), title);
1586
1587   if (parent)
1588     gtk_window_set_transient_for(GTK_WINDOW(fontseldiag), parent);
1589
1590   return GTK_WIDGET(fontseldiag);
1591 }
1592
1593 /**
1594  * hildon_font_selection_dialog_get_preview_text:
1595  * @fsd: the font selection dialog.
1596  *
1597  * Gets the text in preview dialog, which does not include the 
1598  * reference text. The returned string must be freed by the user.
1599  *
1600  * Returns: a string pointer.
1601  */
1602 gchar *
1603 hildon_font_selection_dialog_get_preview_text(HildonFontSelectionDialog * fsd)
1604 {
1605   HildonFontSelectionDialogPrivate *priv;
1606
1607   g_return_val_if_fail(HILDON_IS_FONT_SELECTION_DIALOG(fsd), FALSE);
1608   priv = HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(fsd);
1609   return g_strdup(priv->preview_text);
1610 }
1611
1612 /**
1613  * hildon_font_selection_dialog_set_preview_text:
1614  * @fsd: the font selection dialog.
1615  * @text: the text to be set to the preview dialog.
1616  *
1617  * The default preview text is
1618  * "The quick brown fox jumped over the lazy dogs"
1619  */
1620 void
1621 hildon_font_selection_dialog_set_preview_text(HildonFontSelectionDialog *
1622                                               fsd, const gchar * text)
1623 {
1624   if (HILDON_IS_FONT_SELECTION_DIALOG(fsd)) ;
1625     {
1626       HildonFontSelectionDialogPrivate *priv =
1627         HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(fsd);
1628       g_free(priv->preview_text);
1629       priv->preview_text = g_strdup(text);
1630       g_object_notify (G_OBJECT (fsd), "preview-text");
1631     }
1632 }
1633
1634 /**
1635  * hildon_font_selection_dialog_get_text_tag:
1636  * @fsd: the font selection dialog.
1637  *
1638  * Get the #GtkTextTag for selections. This function
1639  * is deprecated function. The best way to use
1640  * the text tags is to reuse them as much as possible.
1641  * The recommended way is to get the properties of font
1642  * selection dialog on GTK_RESPONSE_OK, according to
1643  * these property use the tags that you have pre-created.
1644  * 
1645  * Returns: a #GtkTextTag having corresponding properties
1646  * set. 
1647  */ 
1648 GtkTextTag * 
1649 hildon_font_selection_dialog_get_text_tag (HildonFontSelectionDialog *fsd)
1650 {
1651   GtkTextTag *tag;
1652   gint size, position;
1653   gboolean family_set, size_set, color_set, bold, bold_set,
1654            italic, italic_set, underline, underline_set,
1655            strikethrough, strikethrough_set, position_set;
1656   GdkColor *color = NULL;
1657   gchar *family = NULL;
1658
1659   tag = gtk_text_tag_new(NULL);
1660   
1661   g_object_get(G_OBJECT(fsd),
1662                "family", &family, "family-set", &family_set,
1663                "size", &size, "size-set", &size_set,
1664                "color", &color, "color-set", &color_set,
1665                "bold", &bold, "bold-set", &bold_set,
1666                "italic", &italic, "italic-set", &italic_set,
1667                "underline", &underline, "underline-set", &underline_set,
1668                "strikethrough", &strikethrough, "strikethrough-set", 
1669                &strikethrough_set, "position", &position, 
1670                "position-set", &position_set, NULL);
1671   /*family*/
1672   if(family_set)
1673     g_object_set(G_OBJECT(tag), "family",
1674                  family, "family-set", TRUE, NULL);
1675   else
1676     g_object_set(G_OBJECT(tag), "family-set", FALSE, NULL);
1677
1678   g_free(family);
1679   
1680   /*size*/
1681   if(size_set)
1682     g_object_set(G_OBJECT(tag), "size", size * PANGO_SCALE, 
1683                  "size-set", TRUE, NULL);
1684   else
1685     g_object_set(G_OBJECT(tag), "size-set", FALSE, NULL);
1686   
1687   /*color*/
1688   if(color_set)
1689     g_object_set(G_OBJECT(tag), "foreground-gdk", color, 
1690                  "foreground-set", TRUE ,NULL);
1691   else
1692     g_object_set(G_OBJECT(tag), "foreground-set", FALSE, NULL);
1693
1694   if(color != NULL)
1695     gdk_color_free(color);
1696   
1697   /*weight*/
1698   if(bold_set)
1699     {
1700       if(bold)
1701         g_object_set(G_OBJECT(tag), "weight", PANGO_WEIGHT_BOLD, NULL);
1702       else
1703         g_object_set(G_OBJECT(tag), "weight", PANGO_WEIGHT_NORMAL, NULL);
1704         
1705       g_object_set(G_OBJECT(tag), "weight-set", TRUE, NULL);
1706     }
1707   else
1708     g_object_set(G_OBJECT(tag), "weight-set", FALSE, NULL);
1709   
1710   /*style*/
1711   if(italic_set)
1712     {
1713       if(italic)
1714         g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
1715       else
1716         g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_NORMAL, NULL);
1717         
1718       g_object_set(G_OBJECT(tag), "style-set", TRUE, NULL);
1719     }
1720   else
1721     g_object_set(G_OBJECT(tag), "style-set", FALSE, NULL);
1722   
1723   /*underline*/
1724   if(underline_set)
1725     {
1726       if(underline)
1727         g_object_set(G_OBJECT(tag), "underline", PANGO_UNDERLINE_SINGLE, NULL);
1728       else
1729         g_object_set(G_OBJECT(tag), "underline", PANGO_UNDERLINE_NONE, NULL);
1730         
1731       g_object_set(G_OBJECT(tag), "underline-set", TRUE, NULL);
1732     }
1733   else
1734     g_object_set(G_OBJECT(tag), "underline-set", FALSE, NULL);
1735   
1736   /*strikethrough*/
1737   if(strikethrough_set)
1738     {
1739       if(strikethrough)
1740         g_object_set(G_OBJECT(tag), "strikethrough", TRUE, NULL);
1741       else
1742         g_object_set(G_OBJECT(tag), "strikethrough", FALSE, NULL);
1743         
1744       g_object_set(G_OBJECT(tag), "strikethrough-set", TRUE, NULL);
1745     }
1746   else
1747     g_object_set(G_OBJECT(tag), "strikethrough-set", FALSE, NULL);
1748   
1749   /*position*/
1750   if(position_set)
1751     {
1752       switch(position)
1753         {
1754         case 1: /*super*/
1755           g_object_set(G_OBJECT(tag), "rise", SUPERSCRIPT_RISE, NULL);
1756           break;
1757         case -1: /*sub*/
1758           g_object_set(G_OBJECT(tag), "rise", SUBSCRIPT_LOW, NULL);
1759           break;
1760         case 0: /*normal*/
1761           g_object_set(G_OBJECT(tag), "rise", 0, NULL);
1762           break;
1763         }
1764       g_object_set(G_OBJECT(tag), "rise-set", TRUE, NULL);
1765     }
1766   else
1767     g_object_set(G_OBJECT(tag), "rise-set", FALSE, NULL);
1768   
1769   return tag;
1770 }
1771
1772 /** 
1773  * hildon_font_selection_dialog_set_buffer:
1774  * @fsd: the font selection dialog.
1775  * @buffer: a #GtkTextBuffer containing the text to which the selections will 
1776  * be applied. Applying is responsibility of application.
1777  *
1778  * This is deprecated function. GtkTextBuffer is not enough
1779  * to get the attributes of currently selected text. Please 
1780  * inspect the attributes yourself, and set the properties of
1781  * font selection dialog to reflect your inspection.
1782  * 
1783  */
1784 void 
1785 hildon_font_selection_dialog_set_buffer (HildonFontSelectionDialog *fsd,
1786                                          GtkTextBuffer *buffer)
1787 {
1788   GtkTextIter begin, end, iter;
1789   HildonFontSelectionDialogSettings settings;
1790
1791   gtk_text_buffer_get_selection_bounds(buffer, &begin, &end);
1792   
1793   settings_init(&settings, fsd);
1794   
1795   iter = begin;
1796
1797   /* Keep original settings if the selection includes nothing */ 
1798   if(gtk_text_iter_compare(&iter, &end) == 0)
1799     {
1800       GSList *slist;
1801       
1802       slist = gtk_text_iter_get_tags(&iter);
1803       g_slist_foreach(slist, check_tags, (gpointer) &settings);
1804       g_slist_free(slist);
1805     }
1806
1807   /* Apply the user settings to the selected text */
1808   while(gtk_text_iter_compare(&iter, &end) < 0)
1809     {
1810       GSList *slist;
1811       
1812       slist = gtk_text_iter_get_tags(&iter);
1813       g_slist_foreach(slist, check_tags, (gpointer) &settings);
1814       g_slist_free(slist);
1815       
1816       if(!gtk_text_iter_forward_cursor_position(&iter))
1817         break;
1818     }
1819
1820   settings_apply(&settings);
1821   settings_destroy(&settings);
1822 }
1823
1824 /**
1825  * hildon_font_selection_dialog_get_font:
1826  * @fsd: the font selection dialog.
1827  *
1828  * This is a deprecated function, @PangoAttrList needs
1829  * starting index, and end index on construction.
1830  *
1831  * Return value: pointer to @PangoAttrList.
1832  */
1833 PangoAttrList
1834 *hildon_font_selection_dialog_get_font(HildonFontSelectionDialog * fsd)
1835 {
1836   HildonFontSelectionDialogPrivate *priv
1837     = HILDON_FONT_SELECTION_DIALOG_GET_PRIVATE(fsd);
1838   
1839   g_return_val_if_fail(HILDON_IS_FONT_SELECTION_DIALOG(fsd), FALSE);
1840   /*an approve of none working api, should have ask for start_index,
1841    * and length in bytes of the string, currently using preview_text 
1842    * length, KLUDGE!*/
1843   
1844   return hildon_font_selection_dialog_create_attrlist(fsd, 
1845                                 0, strlen(priv->preview_text));
1846 }
1847
1848 /**
1849  * hildon_font_selection_dialog_set_font:
1850  * @fsd: the font selection dialog.
1851  * @list: the pango attribute list.
1852  *
1853  * This is a deprecated function.
1854  * 
1855  * Sets the font to the dialog.
1856  */
1857 void 
1858 hildon_font_selection_dialog_set_font(HildonFontSelectionDialog * fsd,
1859                                       PangoAttrList * list)
1860 {
1861   PangoAttrIterator *iter;
1862   HildonFontSelectionDialogSettings settings;
1863
1864   iter = pango_attr_list_get_iterator(list);
1865   
1866   settings_init(&settings, fsd);
1867   
1868   while(iter != NULL)
1869     {
1870       GSList *slist;
1871       
1872       slist = pango_attr_iterator_get_attrs(iter);
1873       g_slist_foreach(slist, check_attrs, (gpointer) &settings);
1874       g_slist_free(slist);
1875       
1876       if(!pango_attr_iterator_next(iter))
1877         break;
1878     }
1879
1880   pango_attr_iterator_destroy(iter);
1881
1882   settings_apply(&settings);
1883   settings_destroy(&settings);
1884 }