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"
25 #include <glib/gmem.h>
26 #include <glib/gstrfuncs.h>
27 #include <glib/gmessages.h>
28 #include <pango/pango.h>
32 #include "font-util.h"
37 /*========================================================*/
38 /* Private macros and constants. */
39 /*========================================================*/
41 #define DEFAULT_FONT_FAMILY "Sans"
42 #define DEFAULT_FONT_SIZE 14.0
43 #define DEFAULT_FONT_WEIGHT PANGO_WEIGHT_NORMAL
44 #define DEFAULT_FONT_ITALIC_FLAG FALSE
45 #define DEFAULT_ALIGN PANGO_ALIGN_LEFT
46 #define DEFAULT_COLOR GL_COLOR (0,0,0)
47 #define DEFAULT_TEXT_LINE_SPACING 1.0
48 #define DEFAULT_AUTO_SHRINK FALSE
50 #define FONT_SCALE (72.0/96.0)
53 /*========================================================*/
55 /*========================================================*/
57 struct _glLabelTextPrivate {
58 GtkTextTagTable *tag_table;
59 GtkTextBuffer *buffer;
63 PangoWeight font_weight;
64 gboolean font_italic_flag;
66 glColorNode *color_node;
70 gboolean size_changed;
76 /*========================================================*/
77 /* Private globals. */
78 /*========================================================*/
81 /*========================================================*/
82 /* Private function prototypes. */
83 /*========================================================*/
85 static void gl_label_text_finalize (GObject *object);
87 static void copy (glLabelObject *dst_object,
88 glLabelObject *src_object);
90 static void buffer_changed_cb (GtkTextBuffer *textbuffer,
93 static void get_size (glLabelObject *object,
97 static void set_font_family (glLabelObject *object,
98 const gchar *font_family);
100 static void set_font_size (glLabelObject *object,
103 static void set_font_weight (glLabelObject *object,
104 PangoWeight font_weight);
106 static void set_font_italic_flag (glLabelObject *object,
107 gboolean font_italic_flag);
109 static void set_text_alignment (glLabelObject *object,
110 PangoAlignment text_alignment);
112 static void set_text_line_spacing (glLabelObject *object,
113 gdouble text_line_spacing);
115 static void set_text_color (glLabelObject *object,
116 glColorNode *text_color_node);
118 static gchar *get_font_family (glLabelObject *object);
120 static gdouble get_font_size (glLabelObject *object);
122 static PangoWeight get_font_weight (glLabelObject *object);
124 static gboolean get_font_italic_flag (glLabelObject *object);
126 static PangoAlignment get_text_alignment (glLabelObject *object);
128 static gdouble get_text_line_spacing (glLabelObject *object);
130 static glColorNode* get_text_color (glLabelObject *object);
132 static void draw_object (glLabelObject *object,
134 gboolean screen_flag,
135 glMergeRecord *record);
137 static void draw_shadow (glLabelObject *object,
139 gboolean screen_flag,
140 glMergeRecord *record);
142 static void draw_text_real (glLabelObject *object,
144 gboolean screen_flag,
145 glMergeRecord *record,
148 static gdouble auto_shrink_font_size (cairo_t *cr,
157 /*****************************************************************************/
158 /* Object infrastructure. */
159 /*****************************************************************************/
160 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT);
163 /*****************************************************************************/
164 /* Class Init Function. */
165 /*****************************************************************************/
167 gl_label_text_class_init (glLabelTextClass *class)
169 GObjectClass *object_class = G_OBJECT_CLASS (class);
170 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
172 gl_label_text_parent_class = g_type_class_peek_parent (class);
174 label_object_class->copy = copy;
176 label_object_class->get_size = get_size;
178 label_object_class->set_font_family = set_font_family;
179 label_object_class->set_font_size = set_font_size;
180 label_object_class->set_font_weight = set_font_weight;
181 label_object_class->set_font_italic_flag = set_font_italic_flag;
182 label_object_class->set_text_alignment = set_text_alignment;
183 label_object_class->set_text_line_spacing = set_text_line_spacing;
184 label_object_class->set_text_color = set_text_color;
185 label_object_class->get_font_family = get_font_family;
186 label_object_class->get_font_size = get_font_size;
187 label_object_class->get_font_weight = get_font_weight;
188 label_object_class->get_font_italic_flag = get_font_italic_flag;
189 label_object_class->get_text_alignment = get_text_alignment;
190 label_object_class->get_text_line_spacing = get_text_line_spacing;
191 label_object_class->get_text_color = get_text_color;
192 label_object_class->draw_object = draw_object;
193 label_object_class->draw_shadow = draw_shadow;
195 object_class->finalize = gl_label_text_finalize;
199 /*****************************************************************************/
200 /* Object Instance Init Function. */
201 /*****************************************************************************/
203 gl_label_text_init (glLabelText *ltext)
205 ltext->priv = g_new0 (glLabelTextPrivate, 1);
207 ltext->priv->tag_table = gtk_text_tag_table_new ();
208 ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
210 ltext->priv->font_family = g_strdup(DEFAULT_FONT_FAMILY);
211 ltext->priv->font_size = DEFAULT_FONT_SIZE;
212 ltext->priv->font_weight = DEFAULT_FONT_WEIGHT;
213 ltext->priv->font_italic_flag = DEFAULT_FONT_ITALIC_FLAG;
214 ltext->priv->align = DEFAULT_ALIGN;
215 ltext->priv->color_node = gl_color_node_new_default ();
216 ltext->priv->color_node->color = DEFAULT_COLOR;
217 ltext->priv->line_spacing = DEFAULT_TEXT_LINE_SPACING;
218 ltext->priv->auto_shrink = DEFAULT_AUTO_SHRINK;
220 ltext->priv->size_changed = TRUE;
222 g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
223 G_CALLBACK(buffer_changed_cb), ltext);
227 /*****************************************************************************/
228 /* Finalize Method. */
229 /*****************************************************************************/
231 gl_label_text_finalize (GObject *object)
233 glLabelText *ltext = GL_LABEL_TEXT (object);
235 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
237 g_object_unref (ltext->priv->tag_table);
238 g_object_unref (ltext->priv->buffer);
239 g_free (ltext->priv->font_family);
240 gl_color_node_free (&(ltext->priv->color_node));
241 g_free (ltext->priv);
243 G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
247 /*****************************************************************************/
248 /** New Object Generator. */
249 /*****************************************************************************/
251 gl_label_text_new (glLabel *label)
255 ltext = g_object_new (gl_label_text_get_type(), NULL);
257 gl_label_object_set_parent (GL_LABEL_OBJECT(ltext), label);
259 return G_OBJECT (ltext);
263 /*****************************************************************************/
264 /* Copy object contents. */
265 /*****************************************************************************/
267 copy (glLabelObject *dst_object,
268 glLabelObject *src_object)
270 glLabelText *ltext = (glLabelText *)src_object;
271 glLabelText *new_ltext = (glLabelText *)dst_object;
273 glColorNode *text_color_node;
275 gl_debug (DEBUG_LABEL, "START");
277 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
278 g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
280 lines = gl_label_text_get_lines (ltext);
281 text_color_node = get_text_color (src_object);
282 gl_label_text_set_lines (new_ltext, lines);
284 new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
285 new_ltext->priv->font_size = ltext->priv->font_size;
286 new_ltext->priv->font_weight = ltext->priv->font_weight;
287 new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
288 set_text_color (dst_object, text_color_node);
289 new_ltext->priv->align = ltext->priv->align;
290 new_ltext->priv->line_spacing = ltext->priv->line_spacing;
291 new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
293 new_ltext->priv->size_changed = ltext->priv->size_changed;
294 new_ltext->priv->w = ltext->priv->w;
295 new_ltext->priv->h = ltext->priv->h;
297 gl_color_node_free (&text_color_node);
298 gl_text_node_lines_free (&lines);
300 gl_debug (DEBUG_LABEL, "END");
304 /*****************************************************************************/
305 /* Set object params. */
306 /*****************************************************************************/
308 gl_label_text_set_lines (glLabelText *ltext,
313 gl_debug (DEBUG_LABEL, "START");
315 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
317 text = gl_text_node_lines_expand (lines, NULL);
318 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
321 ltext->priv->size_changed = TRUE;
323 gl_debug (DEBUG_LABEL, "END");
326 /*****************************************************************************/
327 /* Get object params. */
328 /*****************************************************************************/
330 gl_label_text_get_buffer (glLabelText *ltext)
332 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
334 return ltext->priv->buffer;
339 gl_label_text_get_lines (glLabelText *ltext)
341 GtkTextIter start, end;
345 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
347 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
348 text = gtk_text_buffer_get_text (ltext->priv->buffer,
349 &start, &end, FALSE);
350 lines = gl_text_node_lines_new_from_text (text);
357 /*****************************************************************************/
358 /* Text buffer "changed" callback. */
359 /*****************************************************************************/
361 buffer_changed_cb (GtkTextBuffer *textbuffer,
364 ltext->priv->size_changed = TRUE;
366 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
370 /*****************************************************************************/
371 /* Get object size method. */
372 /*****************************************************************************/
374 get_size (glLabelObject *object,
378 glLabelText *ltext = (glLabelText *)object;
379 PangoFontMap *fontmap;
380 PangoContext *context;
381 cairo_font_options_t *options;
384 PangoFontDescription *desc;
386 gdouble line_spacing;
387 GtkTextIter start, end;
389 gdouble w_parent, h_parent;
392 gl_debug (DEBUG_LABEL, "START");
394 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
396 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
398 if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
404 if (!ltext->priv->size_changed)
411 font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
412 line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
414 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
415 text = gtk_text_buffer_get_text (ltext->priv->buffer,
416 &start, &end, FALSE);
419 fontmap = pango_cairo_font_map_new ();
420 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
421 options = cairo_font_options_create ();
422 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
423 pango_cairo_context_set_font_options (context, options);
424 cairo_font_options_destroy (options);
426 layout = pango_layout_new (context);
428 style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
430 desc = pango_font_description_new ();
431 pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
432 pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
433 pango_font_description_set_style (desc, style);
434 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
435 pango_layout_set_font_description (layout, desc);
436 pango_font_description_free (desc);
438 pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
439 pango_layout_set_text (layout, text, -1);
440 pango_layout_get_size (layout, &iw, &ih);
441 *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
442 *h = ltext->priv->h = ih / PANGO_SCALE;
443 ltext->priv->size_changed = FALSE;
445 g_object_unref (layout);
446 g_object_unref (context);
447 g_object_unref (fontmap);
450 gl_debug (DEBUG_LABEL, "END");
454 /*****************************************************************************/
455 /* Set font family method. */
456 /*****************************************************************************/
458 set_font_family (glLabelObject *object,
459 const gchar *font_family)
461 glLabelText *ltext = (glLabelText *)object;
462 gchar *good_font_family;
464 gl_debug (DEBUG_LABEL, "START");
466 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
467 g_return_if_fail (font_family);
469 good_font_family = gl_font_util_validate_family (font_family);
471 if (ltext->priv->font_family) {
472 if (strcmp (ltext->priv->font_family, good_font_family) == 0) {
473 g_free (good_font_family);
474 gl_debug (DEBUG_LABEL, "END (no change)");
477 g_free (ltext->priv->font_family);
479 ltext->priv->font_family = g_strdup (good_font_family);
480 g_free (good_font_family);
482 gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
484 ltext->priv->size_changed = TRUE;
486 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
488 gl_debug (DEBUG_LABEL, "END");
492 /*****************************************************************************/
493 /* Set font size method. */
494 /*****************************************************************************/
496 set_font_size (glLabelObject *object,
499 glLabelText *ltext = (glLabelText *)object;
501 gl_debug (DEBUG_LABEL, "START");
503 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
505 if (ltext->priv->font_size != font_size) {
507 ltext->priv->size_changed = TRUE;
509 ltext->priv->font_size = font_size;
510 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
514 gl_debug (DEBUG_LABEL, "END");
518 /*****************************************************************************/
519 /* Set font weight method. */
520 /*****************************************************************************/
522 set_font_weight (glLabelObject *object,
523 PangoWeight font_weight)
525 glLabelText *ltext = (glLabelText *)object;
527 gl_debug (DEBUG_LABEL, "START");
529 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
531 if (ltext->priv->font_weight != font_weight) {
533 ltext->priv->size_changed = TRUE;
535 ltext->priv->font_weight = font_weight;
536 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
540 gl_debug (DEBUG_LABEL, "END");
544 /*****************************************************************************/
545 /* Set font italic flag method. */
546 /*****************************************************************************/
548 set_font_italic_flag (glLabelObject *object,
549 gboolean font_italic_flag)
551 glLabelText *ltext = (glLabelText *)object;
553 gl_debug (DEBUG_LABEL, "START");
555 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
557 if (ltext->priv->font_italic_flag != font_italic_flag) {
559 ltext->priv->size_changed = TRUE;
561 ltext->priv->font_italic_flag = font_italic_flag;
562 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
566 gl_debug (DEBUG_LABEL, "END");
570 /*****************************************************************************/
571 /* Set text alignment method. */
572 /*****************************************************************************/
574 set_text_alignment (glLabelObject *object,
575 PangoAlignment text_alignment)
577 glLabelText *ltext = (glLabelText *)object;
579 gl_debug (DEBUG_LABEL, "START");
581 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
583 if (ltext->priv->align != text_alignment) {
585 ltext->priv->size_changed = TRUE;
587 ltext->priv->align = text_alignment;
588 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
592 gl_debug (DEBUG_LABEL, "END");
596 /*****************************************************************************/
597 /* Set text line spacing method. */
598 /*****************************************************************************/
600 set_text_line_spacing (glLabelObject *object,
601 gdouble line_spacing)
603 glLabelText *ltext = (glLabelText *)object;
605 gl_debug (DEBUG_LABEL, "START");
607 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
609 if (ltext->priv->line_spacing != line_spacing) {
611 ltext->priv->size_changed = TRUE;
613 ltext->priv->line_spacing = line_spacing;
614 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
618 gl_debug (DEBUG_LABEL, "END");
622 /*****************************************************************************/
623 /* Set text color method. */
624 /*****************************************************************************/
626 set_text_color (glLabelObject *object,
627 glColorNode *text_color_node)
629 glLabelText *ltext = (glLabelText *)object;
631 gl_debug (DEBUG_LABEL, "START");
633 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
635 if (!gl_color_node_equal (ltext->priv->color_node, text_color_node)) {
637 gl_color_node_free (&(ltext->priv->color_node));
638 ltext->priv->color_node = gl_color_node_dup (text_color_node);
640 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
644 gl_debug (DEBUG_LABEL, "END");
648 /*****************************************************************************/
649 /* Get font family method. */
650 /*****************************************************************************/
652 get_font_family (glLabelObject *object)
654 glLabelText *ltext = (glLabelText *)object;
656 gl_debug (DEBUG_LABEL, "");
658 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
660 return g_strdup (ltext->priv->font_family);
664 /*****************************************************************************/
665 /* Get font size method. */
666 /*****************************************************************************/
668 get_font_size (glLabelObject *object)
670 glLabelText *ltext = (glLabelText *)object;
672 gl_debug (DEBUG_LABEL, "");
674 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
676 return ltext->priv->font_size;
680 /*****************************************************************************/
681 /* Get font weight method. */
682 /*****************************************************************************/
684 get_font_weight (glLabelObject *object)
686 glLabelText *ltext = (glLabelText *)object;
688 gl_debug (DEBUG_LABEL, "");
690 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
692 return ltext->priv->font_weight;
696 /*****************************************************************************/
697 /* Get font italic flag method. */
698 /*****************************************************************************/
700 get_font_italic_flag (glLabelObject *object)
702 glLabelText *ltext = (glLabelText *)object;
704 gl_debug (DEBUG_LABEL, "");
706 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
708 return ltext->priv->font_italic_flag;
712 /*****************************************************************************/
713 /* Get text alignment method. */
714 /*****************************************************************************/
715 static PangoAlignment
716 get_text_alignment (glLabelObject *object)
718 glLabelText *ltext = (glLabelText *)object;
720 gl_debug (DEBUG_LABEL, "");
722 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
724 return ltext->priv->align;
728 /*****************************************************************************/
729 /* Get text line spacing method. */
730 /*****************************************************************************/
732 get_text_line_spacing (glLabelObject *object)
734 glLabelText *ltext = (glLabelText *)object;
736 gl_debug (DEBUG_LABEL, "");
738 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
740 return ltext->priv->line_spacing;
744 /*****************************************************************************/
745 /* Get text color method. */
746 /*****************************************************************************/
748 get_text_color (glLabelObject *object)
750 glLabelText *ltext = (glLabelText *)object;
752 gl_debug (DEBUG_LABEL, "");
754 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
756 return gl_color_node_dup (ltext->priv->color_node);
760 /*****************************************************************************/
761 /* Set auto shrink flag. */
762 /*****************************************************************************/
764 gl_label_text_set_auto_shrink (glLabelText *ltext,
765 gboolean auto_shrink)
767 gl_debug (DEBUG_LABEL, "BEGIN");
769 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
771 if (ltext->priv->auto_shrink != auto_shrink) {
773 ltext->priv->auto_shrink = auto_shrink;
774 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
778 gl_debug (DEBUG_LABEL, "END");
782 /*****************************************************************************/
783 /* Query auto shrink flag. */
784 /*****************************************************************************/
786 gl_label_text_get_auto_shrink (glLabelText *ltext)
788 gl_debug (DEBUG_LABEL, "");
790 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
792 return ltext->priv->auto_shrink;
796 /*****************************************************************************/
797 /* Draw object method. */
798 /*****************************************************************************/
800 draw_object (glLabelObject *object,
802 gboolean screen_flag,
803 glMergeRecord *record)
805 glColorNode *color_node;
808 gl_debug (DEBUG_LABEL, "START");
810 color_node = gl_label_object_get_text_color (object);
811 color = gl_color_node_expand (color_node, record);
812 if (color_node->field_flag && screen_flag)
814 color = GL_COLOR_MERGE_DEFAULT;
816 gl_color_node_free (&color_node);
818 draw_text_real (object, cr, screen_flag, record, color);
820 gl_debug (DEBUG_LABEL, "END");
824 /*****************************************************************************/
825 /* Draw shadow method. */
826 /*****************************************************************************/
828 draw_shadow (glLabelObject *object,
830 gboolean screen_flag,
831 glMergeRecord *record)
833 glColorNode *color_node;
835 glColorNode *shadow_color_node;
836 gdouble shadow_opacity;
839 gl_debug (DEBUG_LABEL, "START");
841 color_node = gl_label_object_get_text_color (object);
842 color = gl_color_node_expand (color_node, record);
843 if (color_node->field_flag && screen_flag)
845 color = GL_COLOR_MERGE_DEFAULT;
847 gl_color_node_free (&color_node);
849 shadow_color_node = gl_label_object_get_shadow_color (object);
850 if (shadow_color_node->field_flag)
852 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
854 shadow_opacity = gl_label_object_get_shadow_opacity (object);
855 shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
856 gl_color_node_free (&shadow_color_node);
858 draw_text_real (object, cr, screen_flag, record, shadow_color);
860 gl_debug (DEBUG_LABEL, "END");
864 /*****************************************************************************/
866 /*****************************************************************************/
868 draw_text_real (glLabelObject *object,
870 gboolean screen_flag,
871 glMergeRecord *record,
875 cairo_matrix_t matrix;
876 gdouble object_w, object_h;
877 gdouble raw_w, raw_h;
882 PangoWeight font_weight;
883 gboolean font_italic_flag;
884 gboolean auto_shrink;
885 gdouble text_line_spacing;
886 PangoAlignment alignment;
889 PangoFontDescription *desc;
890 gdouble scale_x, scale_y;
891 cairo_font_options_t *font_options;
892 PangoContext *context;
895 gl_debug (DEBUG_LABEL, "START");
897 gl_label_object_get_position (object, &x0, &y0);
898 gl_label_object_get_matrix (object, &matrix);
900 gl_label_object_get_size (object, &object_w, &object_h);
901 gl_label_object_get_raw_size (object, &raw_w, &raw_h);
902 lines = gl_label_text_get_lines (GL_LABEL_TEXT (object));
903 font_family = gl_label_object_get_font_family (object);
904 font_size = gl_label_object_get_font_size (object) * FONT_SCALE;
905 font_weight = gl_label_object_get_font_weight (object);
906 font_italic_flag = gl_label_object_get_font_italic_flag (object);
908 alignment = gl_label_object_get_text_alignment (object);
910 gl_label_object_get_text_line_spacing (object);
911 auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
913 text = gl_text_node_lines_expand (lines, record);
915 style = font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
918 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
920 font_size = auto_shrink_font_size (cr,
931 * Workaround for pango Bug#341481.
932 * Render font at device scale and scale font size accordingly.
936 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
937 scale_x = fabs (scale_x);
938 scale_y = fabs (scale_y);
940 cairo_scale (cr, scale_x, scale_y);
942 layout = pango_cairo_create_layout (cr);
944 font_options = cairo_font_options_create ();
945 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
946 context = pango_layout_get_context (layout);
947 pango_cairo_context_set_font_options (context, font_options);
948 cairo_font_options_destroy (font_options);
950 desc = pango_font_description_new ();
951 pango_font_description_set_family (desc, font_family);
952 pango_font_description_set_weight (desc, font_weight);
953 pango_font_description_set_style (desc, style);
954 pango_font_description_set_size (desc, font_size * PANGO_SCALE / scale_x);
955 pango_layout_set_font_description (layout, desc);
956 pango_font_description_free (desc);
958 pango_layout_set_text (layout, text, -1);
959 pango_layout_set_spacing (layout, font_size * (text_line_spacing-1) * PANGO_SCALE / scale_x);
962 pango_layout_set_width (layout, -1);
966 pango_layout_set_width (layout, object_w * PANGO_SCALE / scale_x);
968 pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
969 pango_layout_set_alignment (layout, alignment);
972 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
973 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, 0);
974 pango_cairo_show_layout (cr, layout);
978 g_object_unref (layout);
981 gl_text_node_lines_free (&lines);
982 g_free (font_family);
984 gl_debug (DEBUG_LABEL, "END");
988 /*****************************************************************************/
989 /* Automatically shrink text size to fit within horizontal width. */
990 /*****************************************************************************/
992 auto_shrink_font_size (cairo_t *cr,
1000 PangoLayout *layout;
1001 PangoFontDescription *desc;
1003 gdouble layout_width;
1006 layout = pango_cairo_create_layout (cr);
1008 desc = pango_font_description_new ();
1009 pango_font_description_set_family (desc, family);
1010 pango_font_description_set_weight (desc, weight);
1011 pango_font_description_set_style (desc, style);
1012 pango_font_description_set_size (desc, size * PANGO_SCALE);
1014 pango_layout_set_font_description (layout, desc);
1015 pango_font_description_free (desc);
1017 pango_layout_set_text (layout, text, -1);
1018 pango_layout_set_width (layout, -1);
1019 pango_layout_get_size (layout, &iw, &ih);
1020 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
1022 g_object_unref (layout);
1024 g_print ("Object w = %g, layout w = %g\n", width, layout_width);
1026 if ( layout_width > width )
1029 new_size = size * (width-2*GL_LABEL_TEXT_MARGIN)/layout_width;
1031 /* Round down to nearest 1/2 point */
1032 new_size = (int)(new_size*2.0) / 2.0;
1034 /* don't get ridiculously small. */
1051 * Local Variables: -- emacs
1053 * c-basic-offset: 8 -- emacs
1054 * tab-width: 8 -- emacs
1055 * indent-tabs-mode: nil -- emacs