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