1 /*
2  * glade-gtk-label.c - GladeWidgetAdaptor for GtkLabel
3  *
4  * Copyright (C) 2013 Tristan Van Berkom
5  *
6  * Authors:
7  *      Tristan Van Berkom <tristan.van.berkom@gmail.com>
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as
11  * published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23 
24 #include <config.h>
25 #include <glib/gi18n-lib.h>
26 #include <gladeui/glade.h>
27 
28 #include "glade-label-editor.h"
29 #include "glade-attributes.h"
30 #include "glade-gtk.h"
31 
32 void
glade_gtk_label_post_create(GladeWidgetAdaptor * adaptor,GObject * object,GladeCreateReason reason)33 glade_gtk_label_post_create (GladeWidgetAdaptor * adaptor,
34                              GObject * object, GladeCreateReason reason)
35 {
36   GladeWidget *glabel = glade_widget_get_from_gobject (object);
37 
38   if (reason == GLADE_CREATE_USER)
39     glade_widget_property_set_sensitive (glabel, "mnemonic-widget", FALSE,
40                                          MNEMONIC_INSENSITIVE_MSG);
41 }
42 
43 static void
glade_gtk_label_set_label(GObject * object,const GValue * value)44 glade_gtk_label_set_label (GObject * object, const GValue * value)
45 {
46   GladeWidget *glabel;
47   gboolean use_markup = FALSE, use_underline = FALSE;
48 
49   glabel = glade_widget_get_from_gobject (object);
50   glade_widget_property_get (glabel, "use-markup", &use_markup);
51 
52   if (use_markup)
53     gtk_label_set_markup (GTK_LABEL (object), g_value_get_string (value));
54   else
55     gtk_label_set_text (GTK_LABEL (object), g_value_get_string (value));
56 
57   glade_widget_property_get (glabel, "use-underline", &use_underline);
58   if (use_underline)
59     gtk_label_set_use_underline (GTK_LABEL (object), use_underline);
60 }
61 
62 static void
glade_gtk_label_set_attributes(GObject * object,const GValue * value)63 glade_gtk_label_set_attributes (GObject * object, const GValue * value)
64 {
65   GladeAttribute *gattr;
66   PangoAttribute *attribute;
67   PangoLanguage *language;
68   PangoFontDescription *font_desc;
69   PangoAttrList *attrs = NULL;
70   GdkColor *color;
71   GList *list;
72 
73   for (list = g_value_get_boxed (value); list; list = list->next)
74     {
75       gattr = list->data;
76 
77       attribute = NULL;
78 
79       switch (gattr->type)
80         {
81             /* PangoFontDescription */
82           case PANGO_ATTR_FONT_DESC:
83 	    if ((font_desc =
84 		 pango_font_description_from_string (g_value_get_string (&gattr->value))))
85 	      {
86 		attribute = pango_attr_font_desc_new (font_desc);
87 		pango_font_description_free (font_desc);
88 	      }
89 	    break;
90 
91             /* PangoAttrLanguage */
92           case PANGO_ATTR_LANGUAGE:
93             if ((language =
94                  pango_language_from_string (g_value_get_string (&gattr->value))))
95 	      attribute = pango_attr_language_new (language);
96             break;
97             /* PangoAttrInt */
98           case PANGO_ATTR_STYLE:
99             attribute =
100                 pango_attr_style_new (g_value_get_enum (&(gattr->value)));
101             break;
102           case PANGO_ATTR_WEIGHT:
103             attribute =
104                 pango_attr_weight_new (g_value_get_enum (&(gattr->value)));
105             break;
106           case PANGO_ATTR_VARIANT:
107             attribute =
108                 pango_attr_variant_new (g_value_get_enum (&(gattr->value)));
109             break;
110           case PANGO_ATTR_STRETCH:
111             attribute =
112                 pango_attr_stretch_new (g_value_get_enum (&(gattr->value)));
113             break;
114           case PANGO_ATTR_UNDERLINE:
115             attribute =
116                 pango_attr_underline_new (g_value_get_boolean
117                                           (&(gattr->value)));
118             break;
119           case PANGO_ATTR_STRIKETHROUGH:
120             attribute =
121                 pango_attr_strikethrough_new (g_value_get_boolean
122                                               (&(gattr->value)));
123             break;
124           case PANGO_ATTR_GRAVITY:
125             attribute =
126                 pango_attr_gravity_new (g_value_get_enum (&(gattr->value)));
127             break;
128           case PANGO_ATTR_GRAVITY_HINT:
129             attribute =
130                 pango_attr_gravity_hint_new (g_value_get_enum
131                                              (&(gattr->value)));
132             break;
133 
134             /* PangoAttrString */
135           case PANGO_ATTR_FAMILY:
136             attribute =
137                 pango_attr_family_new (g_value_get_string (&(gattr->value)));
138             break;
139 
140             /* PangoAttrSize */
141           case PANGO_ATTR_SIZE:
142             attribute = pango_attr_size_new (g_value_get_int (&(gattr->value)));
143             break;
144           case PANGO_ATTR_ABSOLUTE_SIZE:
145             attribute =
146                 pango_attr_size_new_absolute (g_value_get_int
147                                               (&(gattr->value)));
148             break;
149 
150             /* PangoAttrColor */
151           case PANGO_ATTR_FOREGROUND:
152             color = g_value_get_boxed (&(gattr->value));
153             attribute =
154                 pango_attr_foreground_new (color->red, color->green,
155                                            color->blue);
156             break;
157           case PANGO_ATTR_BACKGROUND:
158             color = g_value_get_boxed (&(gattr->value));
159             attribute =
160                 pango_attr_background_new (color->red, color->green,
161                                            color->blue);
162             break;
163           case PANGO_ATTR_UNDERLINE_COLOR:
164             color = g_value_get_boxed (&(gattr->value));
165             attribute =
166                 pango_attr_underline_color_new (color->red, color->green,
167                                                 color->blue);
168             break;
169           case PANGO_ATTR_STRIKETHROUGH_COLOR:
170             color = g_value_get_boxed (&(gattr->value));
171             attribute =
172                 pango_attr_strikethrough_color_new (color->red, color->green,
173                                                     color->blue);
174             break;
175 
176             /* PangoAttrShape */
177           case PANGO_ATTR_SHAPE:
178             /* Unsupported for now */
179             break;
180             /* PangoAttrFloat */
181           case PANGO_ATTR_SCALE:
182             attribute =
183                 pango_attr_scale_new (g_value_get_double (&(gattr->value)));
184             break;
185 
186           case PANGO_ATTR_INVALID:
187           case PANGO_ATTR_LETTER_SPACING:
188           case PANGO_ATTR_RISE:
189           case PANGO_ATTR_FALLBACK:
190           default:
191             break;
192         }
193 
194       if (attribute)
195         {
196           if (!attrs)
197             attrs = pango_attr_list_new ();
198           pango_attr_list_insert (attrs, attribute);
199 
200         }
201     }
202 
203   gtk_label_set_attributes (GTK_LABEL (object), attrs);
204 
205   pango_attr_list_unref (attrs);
206 }
207 
208 
209 static void
glade_gtk_label_set_content_mode(GObject * object,const GValue * value)210 glade_gtk_label_set_content_mode (GObject * object, const GValue * value)
211 {
212   GladeLabelContentMode mode = g_value_get_int (value);
213   GladeWidget *glabel;
214 
215   glabel = glade_widget_get_from_gobject (object);
216 
217   glade_widget_property_set_sensitive (glabel, "glade-attributes", FALSE,
218                                        NOT_SELECTED_MSG);
219   glade_widget_property_set_sensitive (glabel, "use-markup", FALSE,
220                                        NOT_SELECTED_MSG);
221   glade_widget_property_set_sensitive (glabel, "pattern", FALSE,
222                                        NOT_SELECTED_MSG);
223 
224   switch (mode)
225     {
226       case GLADE_LABEL_MODE_ATTRIBUTES:
227         glade_widget_property_set_sensitive (glabel, "glade-attributes", TRUE,
228                                              NULL);
229         break;
230       case GLADE_LABEL_MODE_MARKUP:
231         glade_widget_property_set_sensitive (glabel, "use-markup", TRUE, NULL);
232         break;
233       case GLADE_LABEL_MODE_PATTERN:
234         glade_widget_property_set_sensitive (glabel, "pattern", TRUE, NULL);
235         break;
236       default:
237         break;
238     }
239 }
240 
241 static void
glade_gtk_label_update_lines_sensitivity(GObject * object)242 glade_gtk_label_update_lines_sensitivity (GObject * object)
243 {
244   GladeWidget *glabel;
245   PangoEllipsizeMode ellipsize_mode;
246   gint wrap_mode;
247 
248   glabel = glade_widget_get_from_gobject (object);
249 
250   glade_widget_property_get (glabel, "label-wrap-mode", &wrap_mode);
251   glade_widget_property_get (glabel, "ellipsize", &ellipsize_mode);
252 
253   if (wrap_mode == GLADE_LABEL_WRAP_MODE && ellipsize_mode != PANGO_ELLIPSIZE_NONE)
254     glade_widget_property_set_sensitive (glabel, "lines", TRUE, NULL);
255   else
256     glade_widget_property_set_sensitive (glabel, "lines", FALSE,
257                                          _("This property only applies if ellipsize and wrapping are enabled"));
258 }
259 
260 static void
glade_gtk_label_set_wrap_mode(GObject * object,const GValue * value)261 glade_gtk_label_set_wrap_mode (GObject * object, const GValue * value)
262 {
263   GladeLabelWrapMode mode = g_value_get_int (value);
264   GladeWidget *glabel;
265 
266   glabel = glade_widget_get_from_gobject (object);
267 
268   glade_widget_property_set_sensitive (glabel, "single-line-mode", FALSE,
269                                        NOT_SELECTED_MSG);
270   glade_widget_property_set_sensitive (glabel, "wrap-mode", FALSE,
271                                        NOT_SELECTED_MSG);
272 
273   if (mode == GLADE_LABEL_SINGLE_LINE)
274     glade_widget_property_set_sensitive (glabel, "single-line-mode", TRUE,
275                                          NULL);
276   else if (mode == GLADE_LABEL_WRAP_MODE)
277     glade_widget_property_set_sensitive (glabel, "wrap-mode", TRUE, NULL);
278 
279   glade_gtk_label_update_lines_sensitivity (object);
280 }
281 
282 static void
glade_gtk_label_set_use_underline(GObject * object,const GValue * value)283 glade_gtk_label_set_use_underline (GObject * object, const GValue * value)
284 {
285   GladeWidget *glabel;
286 
287   glabel = glade_widget_get_from_gobject (object);
288 
289   if (g_value_get_boolean (value))
290     glade_widget_property_set_sensitive (glabel, "mnemonic-widget", TRUE, NULL);
291   else
292     glade_widget_property_set_sensitive (glabel, "mnemonic-widget", FALSE,
293                                          MNEMONIC_INSENSITIVE_MSG);
294 
295   gtk_label_set_use_underline (GTK_LABEL (object), g_value_get_boolean (value));
296 }
297 
298 void
glade_gtk_label_set_property(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * id,const GValue * value)299 glade_gtk_label_set_property (GladeWidgetAdaptor * adaptor,
300                               GObject * object,
301                               const gchar * id, const GValue * value)
302 {
303   if (!strcmp (id, "label"))
304     glade_gtk_label_set_label (object, value);
305   else if (!strcmp (id, "glade-attributes"))
306     glade_gtk_label_set_attributes (object, value);
307   else if (!strcmp (id, "label-content-mode"))
308     glade_gtk_label_set_content_mode (object, value);
309   else if (!strcmp (id, "label-wrap-mode"))
310     glade_gtk_label_set_wrap_mode (object, value);
311   else if (!strcmp (id, "use-underline"))
312     glade_gtk_label_set_use_underline (object, value);
313   else
314     {
315       if (!strcmp (id, "ellipsize"))
316 	glade_gtk_label_update_lines_sensitivity (object);
317 
318       GWA_GET_CLASS (GTK_TYPE_WIDGET)->set_property (adaptor, object, id, value);
319     }
320 }
321 
322 static void
glade_gtk_parse_attributes(GladeWidget * widget,GladeXmlNode * node)323 glade_gtk_parse_attributes (GladeWidget * widget, GladeXmlNode * node)
324 {
325   PangoAttrType attr_type;
326   GladeXmlNode *prop;
327   GladeAttribute *attr;
328   GList *attrs = NULL;
329   gchar *name, *value;
330 
331   for (prop = glade_xml_node_get_children (node);
332        prop; prop = glade_xml_node_next (prop))
333     {
334       if (!glade_xml_node_verify (prop, GLADE_TAG_ATTRIBUTE))
335         continue;
336 
337       if (!(name = glade_xml_get_property_string_required
338             (prop, GLADE_XML_TAG_NAME, NULL)))
339         continue;
340 
341       if (!(value = glade_xml_get_property_string_required
342             (prop, GLADE_TAG_VALUE, NULL)))
343         {
344           /* for a while, Glade was broken and was storing
345            * attributes in the node contents */
346           if (!(value = glade_xml_get_content (prop)))
347             {
348               g_free (name);
349               continue;
350             }
351         }
352 
353       if ((attr_type =
354            glade_utils_enum_value_from_string (PANGO_TYPE_ATTR_TYPE,
355                                                name)) == 0)
356         continue;
357 
358       /* Parse attribute and add to list */
359       if ((attr = glade_gtk_attribute_from_string (attr_type, value)) != NULL)
360         attrs = g_list_prepend (attrs, attr);
361 
362       /* XXX deal with start/end here ... */
363 
364       g_free (name);
365       g_free (value);
366     }
367 
368   glade_widget_property_set (widget, "glade-attributes",
369                              g_list_reverse (attrs));
370   glade_attr_list_free (attrs);
371 }
372 
373 static void
glade_gtk_label_read_attributes(GladeWidget * widget,GladeXmlNode * node)374 glade_gtk_label_read_attributes (GladeWidget * widget, GladeXmlNode * node)
375 {
376   GladeXmlNode *attrs_node;
377 
378   if ((attrs_node =
379        glade_xml_search_child (node, GLADE_TAG_ATTRIBUTES)) != NULL)
380     {
381       /* Generic attributes parsing */
382       glade_gtk_parse_attributes (widget, attrs_node);
383     }
384 }
385 
386 void
glade_gtk_label_read_widget(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlNode * node)387 glade_gtk_label_read_widget (GladeWidgetAdaptor * adaptor,
388                              GladeWidget * widget, GladeXmlNode * node)
389 {
390   GladeProperty *prop;
391 
392   if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
393 	glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE)))
394     return;
395 
396   /* First chain up and read in all the normal properties.. */
397   GWA_GET_CLASS (GTK_TYPE_WIDGET)->read_widget (adaptor, widget, node);
398 
399   glade_gtk_label_read_attributes (widget, node);
400 
401   /* sync label property after a load... */
402   prop = glade_widget_get_property (widget, "label");
403   glade_gtk_label_set_label (glade_widget_get_object (widget),
404 			     glade_property_inline_value (prop));
405 
406   /* Resolve "label-content-mode" virtual control property  */
407   if (!glade_widget_property_original_default (widget, "use-markup"))
408     glade_widget_property_set (widget, "label-content-mode",
409                                GLADE_LABEL_MODE_MARKUP);
410   else if (!glade_widget_property_original_default (widget, "pattern"))
411     glade_widget_property_set (widget, "label-content-mode",
412                                GLADE_LABEL_MODE_PATTERN);
413   else
414     glade_widget_property_set (widget, "label-content-mode",
415                                GLADE_LABEL_MODE_ATTRIBUTES);
416 
417   /* Resolve "label-wrap-mode" virtual control property  */
418   if (!glade_widget_property_original_default (widget, "single-line-mode"))
419     glade_widget_property_set (widget, "label-wrap-mode",
420                                GLADE_LABEL_SINGLE_LINE);
421   else if (!glade_widget_property_original_default (widget, "wrap"))
422     glade_widget_property_set (widget, "label-wrap-mode",
423                                GLADE_LABEL_WRAP_MODE);
424   else
425     glade_widget_property_set (widget, "label-wrap-mode",
426                                GLADE_LABEL_WRAP_FREE);
427 
428   if (glade_widget_property_original_default (widget, "use-underline"))
429     glade_widget_property_set_sensitive (widget, "mnemonic-widget",
430                                          FALSE, MNEMONIC_INSENSITIVE_MSG);
431 
432 }
433 
434 static void
glade_gtk_label_write_attributes(GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)435 glade_gtk_label_write_attributes (GladeWidget * widget,
436                                   GladeXmlContext * context,
437                                   GladeXmlNode * node)
438 {
439   GladeXmlNode *attr_node;
440   GList *attrs = NULL, *l;
441   GladeAttribute *gattr;
442   gchar *attr_type;
443   gchar *attr_value;
444 
445   if (!glade_widget_property_get (widget, "glade-attributes", &attrs) || !attrs)
446     return;
447 
448   for (l = attrs; l; l = l->next)
449     {
450       gattr = l->data;
451 
452       attr_type =
453           glade_utils_enum_string_from_value (PANGO_TYPE_ATTR_TYPE,
454                                               gattr->type);
455       attr_value = glade_gtk_string_from_attr (gattr);
456 
457       attr_node = glade_xml_node_new (context, GLADE_TAG_ATTRIBUTE);
458       glade_xml_node_append_child (node, attr_node);
459 
460       glade_xml_node_set_property_string (attr_node, GLADE_TAG_NAME, attr_type);
461       glade_xml_node_set_property_string (attr_node, GLADE_TAG_VALUE,
462                                           attr_value);
463     }
464 }
465 
466 void
glade_gtk_label_write_widget(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)467 glade_gtk_label_write_widget (GladeWidgetAdaptor * adaptor,
468                               GladeWidget * widget,
469                               GladeXmlContext * context, GladeXmlNode * node)
470 {
471   GladeXmlNode *attrs_node;
472 
473   if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
474 	glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE)))
475     return;
476 
477   /* First chain up and read in all the normal properties.. */
478   GWA_GET_CLASS (GTK_TYPE_WIDGET)->write_widget (adaptor, widget, context,
479                                                  node);
480 
481   attrs_node = glade_xml_node_new (context, GLADE_TAG_ATTRIBUTES);
482 
483   glade_gtk_label_write_attributes (widget, context, attrs_node);
484 
485   if (!glade_xml_node_get_children (attrs_node))
486     glade_xml_node_delete (attrs_node);
487   else
488     glade_xml_node_append_child (node, attrs_node);
489 
490 }
491 
492 gchar *
glade_gtk_label_string_from_value(GladeWidgetAdaptor * adaptor,GladePropertyClass * klass,const GValue * value)493 glade_gtk_label_string_from_value (GladeWidgetAdaptor * adaptor,
494                                    GladePropertyClass * klass,
495                                    const GValue * value)
496 {
497   GParamSpec          *pspec;
498 
499   pspec = glade_property_class_get_pspec (klass);
500 
501   if (pspec->value_type == GLADE_TYPE_ATTR_GLIST)
502     {
503       GList *l, *list = g_value_get_boxed (value);
504       GString *string = g_string_new ("");
505       gchar *str;
506 
507       for (l = list; l; l = g_list_next (l))
508         {
509           GladeAttribute *attr = l->data;
510 
511           /* Return something usefull at least to for the backend to compare */
512           gchar *attr_str = glade_gtk_string_from_attr (attr);
513           g_string_append_printf (string, "%d=%s ", attr->type, attr_str);
514           g_free (attr_str);
515         }
516       str = string->str;
517       g_string_free (string, FALSE);
518       return str;
519     }
520   else
521     return GWA_GET_CLASS
522         (GTK_TYPE_WIDGET)->string_from_value (adaptor, klass, value);
523 }
524 
525 
526 GladeEditorProperty *
glade_gtk_label_create_eprop(GladeWidgetAdaptor * adaptor,GladePropertyClass * klass,gboolean use_command)527 glade_gtk_label_create_eprop (GladeWidgetAdaptor * adaptor,
528                               GladePropertyClass * klass, gboolean use_command)
529 {
530   GladeEditorProperty *eprop;
531   GParamSpec          *pspec;
532 
533   pspec = glade_property_class_get_pspec (klass);
534 
535   /* chain up.. */
536   if (pspec->value_type == GLADE_TYPE_ATTR_GLIST)
537     {
538       eprop = g_object_new (GLADE_TYPE_EPROP_ATTRS,
539                             "property-class", klass,
540                             "use-command", use_command, NULL);
541     }
542   else
543     eprop = GWA_GET_CLASS
544         (GTK_TYPE_WIDGET)->create_eprop (adaptor, klass, use_command);
545   return eprop;
546 }
547 
548 GladeEditable *
glade_gtk_label_create_editable(GladeWidgetAdaptor * adaptor,GladeEditorPageType type)549 glade_gtk_label_create_editable (GladeWidgetAdaptor * adaptor,
550                                  GladeEditorPageType type)
551 {
552   GladeEditable *editable;
553 
554   if (type == GLADE_PAGE_GENERAL)
555     editable = (GladeEditable *) glade_label_editor_new ();
556   else
557     editable = GWA_GET_CLASS (GTK_TYPE_WIDGET)->create_editable (adaptor, type);
558 
559   return editable;
560 }
561