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