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