3 * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
5 * This file is part of gLabels.
7 * gLabels is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * gLabels is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with gLabels. If not, see <http://www.gnu.org/licenses/>.
23 #include "label-text.h"
26 #include <pango/pango.h>
30 #include "font-util.h"
35 /*========================================================*/
36 /* Private macros and constants. */
37 /*========================================================*/
39 #define DEFAULT_FONT_FAMILY "Sans"
40 #define DEFAULT_FONT_SIZE 14.0
41 #define DEFAULT_FONT_WEIGHT PANGO_WEIGHT_NORMAL
42 #define DEFAULT_FONT_ITALIC_FLAG FALSE
43 #define DEFAULT_ALIGN PANGO_ALIGN_LEFT
44 #define DEFAULT_COLOR GL_COLOR (0,0,0)
45 #define DEFAULT_TEXT_LINE_SPACING 1.0
46 #define DEFAULT_AUTO_SHRINK FALSE
48 #define FONT_SCALE (72.0/96.0)
51 /*========================================================*/
53 /*========================================================*/
55 struct _glLabelTextPrivate {
56 GtkTextTagTable *tag_table;
57 GtkTextBuffer *buffer;
61 PangoWeight font_weight;
62 gboolean font_italic_flag;
64 glColorNode *color_node;
68 gboolean size_changed;
74 /*========================================================*/
75 /* Private globals. */
76 /*========================================================*/
79 /*========================================================*/
80 /* Private function prototypes. */
81 /*========================================================*/
83 static void gl_label_text_finalize (GObject *object);
85 static void copy (glLabelObject *dst_object,
86 glLabelObject *src_object);
88 static void buffer_changed_cb (GtkTextBuffer *textbuffer,
91 static void get_size (glLabelObject *object,
95 static void set_font_family (glLabelObject *object,
96 const gchar *font_family);
98 static void set_font_size (glLabelObject *object,
101 static void set_font_weight (glLabelObject *object,
102 PangoWeight font_weight);
104 static void set_font_italic_flag (glLabelObject *object,
105 gboolean font_italic_flag);
107 static void set_text_alignment (glLabelObject *object,
108 PangoAlignment text_alignment);
110 static void set_text_line_spacing (glLabelObject *object,
111 gdouble text_line_spacing);
113 static void set_text_color (glLabelObject *object,
114 glColorNode *text_color_node);
116 static gchar *get_font_family (glLabelObject *object);
118 static gdouble get_font_size (glLabelObject *object);
120 static PangoWeight get_font_weight (glLabelObject *object);
122 static gboolean get_font_italic_flag (glLabelObject *object);
124 static PangoAlignment get_text_alignment (glLabelObject *object);
126 static gdouble get_text_line_spacing (glLabelObject *object);
128 static glColorNode* get_text_color (glLabelObject *object);
130 static void draw_object (glLabelObject *object,
132 gboolean screen_flag,
133 glMergeRecord *record);
135 static void draw_shadow (glLabelObject *object,
137 gboolean screen_flag,
138 glMergeRecord *record);
140 static void draw_text_real (glLabelObject *object,
142 gboolean screen_flag,
143 glMergeRecord *record,
146 static gdouble auto_shrink_font_size (cairo_t *cr,
155 /*****************************************************************************/
156 /* Object infrastructure. */
157 /*****************************************************************************/
158 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT);
161 /*****************************************************************************/
162 /* Class Init Function. */
163 /*****************************************************************************/
165 gl_label_text_class_init (glLabelTextClass *class)
167 GObjectClass *object_class = G_OBJECT_CLASS (class);
168 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
170 gl_label_text_parent_class = g_type_class_peek_parent (class);
172 label_object_class->copy = copy;
174 label_object_class->get_size = get_size;
176 label_object_class->set_font_family = set_font_family;
177 label_object_class->set_font_size = set_font_size;
178 label_object_class->set_font_weight = set_font_weight;
179 label_object_class->set_font_italic_flag = set_font_italic_flag;
180 label_object_class->set_text_alignment = set_text_alignment;
181 label_object_class->set_text_line_spacing = set_text_line_spacing;
182 label_object_class->set_text_color = set_text_color;
183 label_object_class->get_font_family = get_font_family;
184 label_object_class->get_font_size = get_font_size;
185 label_object_class->get_font_weight = get_font_weight;
186 label_object_class->get_font_italic_flag = get_font_italic_flag;
187 label_object_class->get_text_alignment = get_text_alignment;
188 label_object_class->get_text_line_spacing = get_text_line_spacing;
189 label_object_class->get_text_color = get_text_color;
190 label_object_class->draw_object = draw_object;
191 label_object_class->draw_shadow = draw_shadow;
193 object_class->finalize = gl_label_text_finalize;
197 /*****************************************************************************/
198 /* Object Instance Init Function. */
199 /*****************************************************************************/
201 gl_label_text_init (glLabelText *ltext)
203 ltext->priv = g_new0 (glLabelTextPrivate, 1);
205 ltext->priv->tag_table = gtk_text_tag_table_new ();
206 ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
208 ltext->priv->font_family = g_strdup(DEFAULT_FONT_FAMILY);
209 ltext->priv->font_size = DEFAULT_FONT_SIZE;
210 ltext->priv->font_weight = DEFAULT_FONT_WEIGHT;
211 ltext->priv->font_italic_flag = DEFAULT_FONT_ITALIC_FLAG;
212 ltext->priv->align = DEFAULT_ALIGN;
213 ltext->priv->color_node = gl_color_node_new_default ();
214 ltext->priv->color_node->color = DEFAULT_COLOR;
215 ltext->priv->line_spacing = DEFAULT_TEXT_LINE_SPACING;
216 ltext->priv->auto_shrink = DEFAULT_AUTO_SHRINK;
218 ltext->priv->size_changed = TRUE;
220 g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
221 G_CALLBACK(buffer_changed_cb), ltext);
225 /*****************************************************************************/
226 /* Finalize Method. */
227 /*****************************************************************************/
229 gl_label_text_finalize (GObject *object)
231 glLabelText *ltext = GL_LABEL_TEXT (object);
233 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
235 g_object_unref (ltext->priv->tag_table);
236 g_object_unref (ltext->priv->buffer);
237 g_free (ltext->priv->font_family);
238 gl_color_node_free (&(ltext->priv->color_node));
239 g_free (ltext->priv);
241 G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
245 /*****************************************************************************/
246 /** New Object Generator. */
247 /*****************************************************************************/
249 gl_label_text_new (glLabel *label)
253 ltext = g_object_new (gl_label_text_get_type(), NULL);
255 gl_label_object_set_parent (GL_LABEL_OBJECT(ltext), label);
257 return G_OBJECT (ltext);
261 /*****************************************************************************/
262 /* Copy object contents. */
263 /*****************************************************************************/
265 copy (glLabelObject *dst_object,
266 glLabelObject *src_object)
268 glLabelText *ltext = (glLabelText *)src_object;
269 glLabelText *new_ltext = (glLabelText *)dst_object;
271 glColorNode *text_color_node;
273 gl_debug (DEBUG_LABEL, "START");
275 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
276 g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
278 lines = gl_label_text_get_lines (ltext);
279 text_color_node = get_text_color (src_object);
280 gl_label_text_set_lines (new_ltext, lines);
282 new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
283 new_ltext->priv->font_size = ltext->priv->font_size;
284 new_ltext->priv->font_weight = ltext->priv->font_weight;
285 new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
286 set_text_color (dst_object, text_color_node);
287 new_ltext->priv->align = ltext->priv->align;
288 new_ltext->priv->line_spacing = ltext->priv->line_spacing;
289 new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
291 new_ltext->priv->size_changed = ltext->priv->size_changed;
292 new_ltext->priv->w = ltext->priv->w;
293 new_ltext->priv->h = ltext->priv->h;
295 gl_color_node_free (&text_color_node);
296 gl_text_node_lines_free (&lines);
298 gl_debug (DEBUG_LABEL, "END");
302 /*****************************************************************************/
303 /* Set object params. */
304 /*****************************************************************************/
306 gl_label_text_set_lines (glLabelText *ltext,
311 gl_debug (DEBUG_LABEL, "START");
313 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
315 text = gl_text_node_lines_expand (lines, NULL);
316 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
319 ltext->priv->size_changed = TRUE;
321 gl_debug (DEBUG_LABEL, "END");
324 /*****************************************************************************/
325 /* Get object params. */
326 /*****************************************************************************/
328 gl_label_text_get_buffer (glLabelText *ltext)
330 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
332 return ltext->priv->buffer;
337 gl_label_text_get_lines (glLabelText *ltext)
339 GtkTextIter start, end;
343 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
345 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
346 text = gtk_text_buffer_get_text (ltext->priv->buffer,
347 &start, &end, FALSE);
348 lines = gl_text_node_lines_new_from_text (text);
355 /*****************************************************************************/
356 /* Text buffer "changed" callback. */
357 /*****************************************************************************/
359 buffer_changed_cb (GtkTextBuffer *textbuffer,
362 ltext->priv->size_changed = TRUE;
364 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
368 /*****************************************************************************/
369 /* Get object size method. */
370 /*****************************************************************************/
372 get_size (glLabelObject *object,
376 glLabelText *ltext = (glLabelText *)object;
377 PangoFontMap *fontmap;
378 PangoContext *context;
379 cairo_font_options_t *options;
382 PangoFontDescription *desc;
384 gdouble line_spacing;
385 GtkTextIter start, end;
387 gdouble w_parent, h_parent;
390 gl_debug (DEBUG_LABEL, "START");
392 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
394 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
396 if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
402 if (!ltext->priv->size_changed)
409 font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
410 line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
412 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
413 text = gtk_text_buffer_get_text (ltext->priv->buffer,
414 &start, &end, FALSE);
417 fontmap = pango_cairo_font_map_new ();
418 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
419 options = cairo_font_options_create ();
420 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
421 pango_cairo_context_set_font_options (context, options);
422 cairo_font_options_destroy (options);
424 layout = pango_layout_new (context);
426 style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
428 desc = pango_font_description_new ();
429 pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
430 pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
431 pango_font_description_set_style (desc, style);
432 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
433 pango_layout_set_font_description (layout, desc);
434 pango_font_description_free (desc);
436 pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
437 pango_layout_set_text (layout, text, -1);
438 pango_layout_get_size (layout, &iw, &ih);
439 *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
440 *h = ltext->priv->h = ih / PANGO_SCALE;
441 ltext->priv->size_changed = FALSE;
443 g_object_unref (layout);
444 g_object_unref (context);
445 g_object_unref (fontmap);
448 gl_debug (DEBUG_LABEL, "END");
452 /*****************************************************************************/
453 /* Set font family method. */
454 /*****************************************************************************/
456 set_font_family (glLabelObject *object,
457 const gchar *font_family)
459 glLabelText *ltext = (glLabelText *)object;
460 gchar *good_font_family;
462 gl_debug (DEBUG_LABEL, "START");
464 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
465 g_return_if_fail (font_family);
467 good_font_family = gl_font_util_validate_family (font_family);
469 if (ltext->priv->font_family) {
470 if (strcmp (ltext->priv->font_family, good_font_family) == 0) {
471 g_free (good_font_family);
472 gl_debug (DEBUG_LABEL, "END (no change)");
475 g_free (ltext->priv->font_family);
477 ltext->priv->font_family = g_strdup (good_font_family);
478 g_free (good_font_family);
480 gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
482 ltext->priv->size_changed = TRUE;
484 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
486 gl_debug (DEBUG_LABEL, "END");
490 /*****************************************************************************/
491 /* Set font size method. */
492 /*****************************************************************************/
494 set_font_size (glLabelObject *object,
497 glLabelText *ltext = (glLabelText *)object;
499 gl_debug (DEBUG_LABEL, "START");
501 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
503 if (ltext->priv->font_size != font_size) {
505 ltext->priv->size_changed = TRUE;
507 ltext->priv->font_size = font_size;
508 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
512 gl_debug (DEBUG_LABEL, "END");
516 /*****************************************************************************/
517 /* Set font weight method. */
518 /*****************************************************************************/
520 set_font_weight (glLabelObject *object,
521 PangoWeight font_weight)
523 glLabelText *ltext = (glLabelText *)object;
525 gl_debug (DEBUG_LABEL, "START");
527 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
529 if (ltext->priv->font_weight != font_weight) {
531 ltext->priv->size_changed = TRUE;
533 ltext->priv->font_weight = font_weight;
534 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
538 gl_debug (DEBUG_LABEL, "END");
542 /*****************************************************************************/
543 /* Set font italic flag method. */
544 /*****************************************************************************/
546 set_font_italic_flag (glLabelObject *object,
547 gboolean font_italic_flag)
549 glLabelText *ltext = (glLabelText *)object;
551 gl_debug (DEBUG_LABEL, "START");
553 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
555 if (ltext->priv->font_italic_flag != font_italic_flag) {
557 ltext->priv->size_changed = TRUE;
559 ltext->priv->font_italic_flag = font_italic_flag;
560 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
564 gl_debug (DEBUG_LABEL, "END");
568 /*****************************************************************************/
569 /* Set text alignment method. */
570 /*****************************************************************************/
572 set_text_alignment (glLabelObject *object,
573 PangoAlignment text_alignment)
575 glLabelText *ltext = (glLabelText *)object;
577 gl_debug (DEBUG_LABEL, "START");
579 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
581 if (ltext->priv->align != text_alignment) {
583 ltext->priv->size_changed = TRUE;
585 ltext->priv->align = text_alignment;
586 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
590 gl_debug (DEBUG_LABEL, "END");
594 /*****************************************************************************/
595 /* Set text line spacing method. */
596 /*****************************************************************************/
598 set_text_line_spacing (glLabelObject *object,
599 gdouble line_spacing)
601 glLabelText *ltext = (glLabelText *)object;
603 gl_debug (DEBUG_LABEL, "START");
605 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
607 if (ltext->priv->line_spacing != line_spacing) {
609 ltext->priv->size_changed = TRUE;
611 ltext->priv->line_spacing = line_spacing;
612 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
616 gl_debug (DEBUG_LABEL, "END");
620 /*****************************************************************************/
621 /* Set text color method. */
622 /*****************************************************************************/
624 set_text_color (glLabelObject *object,
625 glColorNode *text_color_node)
627 glLabelText *ltext = (glLabelText *)object;
629 gl_debug (DEBUG_LABEL, "START");
631 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
633 if (!gl_color_node_equal (ltext->priv->color_node, text_color_node)) {
635 gl_color_node_free (&(ltext->priv->color_node));
636 ltext->priv->color_node = gl_color_node_dup (text_color_node);
638 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
642 gl_debug (DEBUG_LABEL, "END");
646 /*****************************************************************************/
647 /* Get font family method. */
648 /*****************************************************************************/
650 get_font_family (glLabelObject *object)
652 glLabelText *ltext = (glLabelText *)object;
654 gl_debug (DEBUG_LABEL, "");
656 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
658 return g_strdup (ltext->priv->font_family);
662 /*****************************************************************************/
663 /* Get font size method. */
664 /*****************************************************************************/
666 get_font_size (glLabelObject *object)
668 glLabelText *ltext = (glLabelText *)object;
670 gl_debug (DEBUG_LABEL, "");
672 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
674 return ltext->priv->font_size;
678 /*****************************************************************************/
679 /* Get font weight method. */
680 /*****************************************************************************/
682 get_font_weight (glLabelObject *object)
684 glLabelText *ltext = (glLabelText *)object;
686 gl_debug (DEBUG_LABEL, "");
688 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
690 return ltext->priv->font_weight;
694 /*****************************************************************************/
695 /* Get font italic flag method. */
696 /*****************************************************************************/
698 get_font_italic_flag (glLabelObject *object)
700 glLabelText *ltext = (glLabelText *)object;
702 gl_debug (DEBUG_LABEL, "");
704 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
706 return ltext->priv->font_italic_flag;
710 /*****************************************************************************/
711 /* Get text alignment method. */
712 /*****************************************************************************/
713 static PangoAlignment
714 get_text_alignment (glLabelObject *object)
716 glLabelText *ltext = (glLabelText *)object;
718 gl_debug (DEBUG_LABEL, "");
720 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
722 return ltext->priv->align;
726 /*****************************************************************************/
727 /* Get text line spacing method. */
728 /*****************************************************************************/
730 get_text_line_spacing (glLabelObject *object)
732 glLabelText *ltext = (glLabelText *)object;
734 gl_debug (DEBUG_LABEL, "");
736 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
738 return ltext->priv->line_spacing;
742 /*****************************************************************************/
743 /* Get text color method. */
744 /*****************************************************************************/
746 get_text_color (glLabelObject *object)
748 glLabelText *ltext = (glLabelText *)object;
750 gl_debug (DEBUG_LABEL, "");
752 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
754 return gl_color_node_dup (ltext->priv->color_node);
758 /*****************************************************************************/
759 /* Set auto shrink flag. */
760 /*****************************************************************************/
762 gl_label_text_set_auto_shrink (glLabelText *ltext,
763 gboolean auto_shrink)
765 gl_debug (DEBUG_LABEL, "BEGIN");
767 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
769 if (ltext->priv->auto_shrink != auto_shrink) {
771 ltext->priv->auto_shrink = auto_shrink;
772 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
776 gl_debug (DEBUG_LABEL, "END");
780 /*****************************************************************************/
781 /* Query auto shrink flag. */
782 /*****************************************************************************/
784 gl_label_text_get_auto_shrink (glLabelText *ltext)
786 gl_debug (DEBUG_LABEL, "");
788 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
790 return ltext->priv->auto_shrink;
794 /*****************************************************************************/
795 /* Draw object method. */
796 /*****************************************************************************/
798 draw_object (glLabelObject *object,
800 gboolean screen_flag,
801 glMergeRecord *record)
803 glColorNode *color_node;
806 gl_debug (DEBUG_LABEL, "START");
808 color_node = gl_label_object_get_text_color (object);
809 color = gl_color_node_expand (color_node, record);
810 if (color_node->field_flag && screen_flag)
812 color = GL_COLOR_MERGE_DEFAULT;
814 gl_color_node_free (&color_node);
816 draw_text_real (object, cr, screen_flag, record, color);
818 gl_debug (DEBUG_LABEL, "END");
822 /*****************************************************************************/
823 /* Draw shadow method. */
824 /*****************************************************************************/
826 draw_shadow (glLabelObject *object,
828 gboolean screen_flag,
829 glMergeRecord *record)
831 glColorNode *color_node;
833 glColorNode *shadow_color_node;
834 gdouble shadow_opacity;
837 gl_debug (DEBUG_LABEL, "START");
839 color_node = gl_label_object_get_text_color (object);
840 color = gl_color_node_expand (color_node, record);
841 if (color_node->field_flag && screen_flag)
843 color = GL_COLOR_MERGE_DEFAULT;
845 gl_color_node_free (&color_node);
847 shadow_color_node = gl_label_object_get_shadow_color (object);
848 if (shadow_color_node->field_flag)
850 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
852 shadow_opacity = gl_label_object_get_shadow_opacity (object);
853 shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
854 gl_color_node_free (&shadow_color_node);
856 draw_text_real (object, cr, screen_flag, record, shadow_color);
858 gl_debug (DEBUG_LABEL, "END");
862 /*****************************************************************************/
864 /*****************************************************************************/
866 draw_text_real (glLabelObject *object,
868 gboolean screen_flag,
869 glMergeRecord *record,
873 cairo_matrix_t matrix;
874 gdouble object_w, object_h;
875 gdouble raw_w, raw_h;
880 PangoWeight font_weight;
881 gboolean font_italic_flag;
882 gboolean auto_shrink;
883 gdouble text_line_spacing;
884 PangoAlignment alignment;
887 PangoFontDescription *desc;
888 gdouble scale_x, scale_y;
889 cairo_font_options_t *font_options;
890 PangoContext *context;
893 gl_debug (DEBUG_LABEL, "START");
895 gl_label_object_get_position (object, &x0, &y0);
896 gl_label_object_get_matrix (object, &matrix);
898 gl_label_object_get_size (object, &object_w, &object_h);
899 gl_label_object_get_raw_size (object, &raw_w, &raw_h);
900 lines = gl_label_text_get_lines (GL_LABEL_TEXT (object));
901 font_family = gl_label_object_get_font_family (object);
902 font_size = gl_label_object_get_font_size (object) * FONT_SCALE;
903 font_weight = gl_label_object_get_font_weight (object);
904 font_italic_flag = gl_label_object_get_font_italic_flag (object);
906 alignment = gl_label_object_get_text_alignment (object);
908 gl_label_object_get_text_line_spacing (object);
909 auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
911 text = gl_text_node_lines_expand (lines, record);
913 style = font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
916 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
918 font_size = auto_shrink_font_size (cr,
929 * Workaround for pango Bug#341481.
930 * Render font at device scale and scale font size accordingly.
934 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
935 scale_x = fabs (scale_x);
936 scale_y = fabs (scale_y);
938 cairo_scale (cr, scale_x, scale_y);
940 layout = pango_cairo_create_layout (cr);
942 font_options = cairo_font_options_create ();
943 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
944 context = pango_layout_get_context (layout);
945 pango_cairo_context_set_font_options (context, font_options);
946 cairo_font_options_destroy (font_options);
948 desc = pango_font_description_new ();
949 pango_font_description_set_family (desc, font_family);
950 pango_font_description_set_weight (desc, font_weight);
951 pango_font_description_set_style (desc, style);
952 pango_font_description_set_size (desc, font_size * PANGO_SCALE / scale_x);
953 pango_layout_set_font_description (layout, desc);
954 pango_font_description_free (desc);
956 pango_layout_set_text (layout, text, -1);
957 pango_layout_set_spacing (layout, font_size * (text_line_spacing-1) * PANGO_SCALE / scale_x);
960 pango_layout_set_width (layout, -1);
964 pango_layout_set_width (layout, object_w * PANGO_SCALE / scale_x);
966 pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
967 pango_layout_set_alignment (layout, alignment);
970 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
971 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, 0);
972 pango_cairo_show_layout (cr, layout);
976 g_object_unref (layout);
979 gl_text_node_lines_free (&lines);
980 g_free (font_family);
982 gl_debug (DEBUG_LABEL, "END");
986 /*****************************************************************************/
987 /* Automatically shrink text size to fit within horizontal width. */
988 /*****************************************************************************/
990 auto_shrink_font_size (cairo_t *cr,
999 PangoFontDescription *desc;
1001 gdouble layout_width;
1004 layout = pango_cairo_create_layout (cr);
1006 desc = pango_font_description_new ();
1007 pango_font_description_set_family (desc, family);
1008 pango_font_description_set_weight (desc, weight);
1009 pango_font_description_set_style (desc, style);
1010 pango_font_description_set_size (desc, size * PANGO_SCALE);
1012 pango_layout_set_font_description (layout, desc);
1013 pango_font_description_free (desc);
1015 pango_layout_set_text (layout, text, -1);
1016 pango_layout_set_width (layout, -1);
1017 pango_layout_get_size (layout, &iw, &ih);
1018 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
1020 g_object_unref (layout);
1022 g_print ("Object w = %g, layout w = %g\n", width, layout_width);
1024 if ( layout_width > width )
1027 new_size = size * (width-2*GL_LABEL_TEXT_MARGIN)/layout_width;
1029 /* Round down to nearest 1/2 point */
1030 new_size = (int)(new_size*2.0) / 2.0;
1032 /* don't get ridiculously small. */
1049 * Local Variables: -- emacs
1051 * c-basic-offset: 8 -- emacs
1052 * tab-width: 8 -- emacs
1053 * indent-tabs-mode: nil -- emacs