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>
36 /*========================================================*/
37 /* Private macros and constants. */
38 /*========================================================*/
40 #define DEFAULT_FONT_FAMILY "Sans"
41 #define DEFAULT_FONT_SIZE 14.0
42 #define DEFAULT_FONT_WEIGHT PANGO_WEIGHT_NORMAL
43 #define DEFAULT_FONT_ITALIC_FLAG FALSE
44 #define DEFAULT_ALIGN PANGO_ALIGN_LEFT
45 #define DEFAULT_COLOR GL_COLOR (0,0,0)
46 #define DEFAULT_TEXT_LINE_SPACING 1.0
47 #define DEFAULT_AUTO_SHRINK FALSE
49 #define FONT_SCALE (72.0/96.0)
52 /*========================================================*/
54 /*========================================================*/
56 struct _glLabelTextPrivate {
57 GtkTextTagTable *tag_table;
58 GtkTextBuffer *buffer;
62 PangoWeight font_weight;
63 gboolean font_italic_flag;
65 glColorNode *color_node;
69 gboolean size_changed;
75 /*========================================================*/
76 /* Private globals. */
77 /*========================================================*/
80 /*========================================================*/
81 /* Private function prototypes. */
82 /*========================================================*/
84 static void gl_label_text_finalize (GObject *object);
86 static void copy (glLabelObject *dst_object,
87 glLabelObject *src_object);
89 static void buffer_changed_cb (GtkTextBuffer *textbuffer,
92 static void get_size (glLabelObject *object,
96 static void set_font_family (glLabelObject *object,
97 const gchar *font_family);
99 static void set_font_size (glLabelObject *object,
102 static void set_font_weight (glLabelObject *object,
103 PangoWeight font_weight);
105 static void set_font_italic_flag (glLabelObject *object,
106 gboolean font_italic_flag);
108 static void set_text_alignment (glLabelObject *object,
109 PangoAlignment text_alignment);
111 static void set_text_line_spacing (glLabelObject *object,
112 gdouble text_line_spacing);
114 static void set_text_color (glLabelObject *object,
115 glColorNode *text_color_node);
117 static gchar *get_font_family (glLabelObject *object);
119 static gdouble get_font_size (glLabelObject *object);
121 static PangoWeight get_font_weight (glLabelObject *object);
123 static gboolean get_font_italic_flag (glLabelObject *object);
125 static PangoAlignment get_text_alignment (glLabelObject *object);
127 static gdouble get_text_line_spacing (glLabelObject *object);
129 static glColorNode* get_text_color (glLabelObject *object);
131 static void draw_object (glLabelObject *object,
133 gboolean screen_flag,
134 glMergeRecord *record);
136 static void draw_shadow (glLabelObject *object,
138 gboolean screen_flag,
139 glMergeRecord *record);
141 static void draw_text_real (glLabelObject *object,
143 gboolean screen_flag,
144 glMergeRecord *record,
147 static gdouble auto_shrink_font_size (cairo_t *cr,
156 /*****************************************************************************/
157 /* Object infrastructure. */
158 /*****************************************************************************/
159 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT);
162 /*****************************************************************************/
163 /* Class Init Function. */
164 /*****************************************************************************/
166 gl_label_text_class_init (glLabelTextClass *class)
168 GObjectClass *object_class = G_OBJECT_CLASS (class);
169 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
171 gl_label_text_parent_class = g_type_class_peek_parent (class);
173 label_object_class->copy = copy;
175 label_object_class->get_size = get_size;
177 label_object_class->set_font_family = set_font_family;
178 label_object_class->set_font_size = set_font_size;
179 label_object_class->set_font_weight = set_font_weight;
180 label_object_class->set_font_italic_flag = set_font_italic_flag;
181 label_object_class->set_text_alignment = set_text_alignment;
182 label_object_class->set_text_line_spacing = set_text_line_spacing;
183 label_object_class->set_text_color = set_text_color;
184 label_object_class->get_font_family = get_font_family;
185 label_object_class->get_font_size = get_font_size;
186 label_object_class->get_font_weight = get_font_weight;
187 label_object_class->get_font_italic_flag = get_font_italic_flag;
188 label_object_class->get_text_alignment = get_text_alignment;
189 label_object_class->get_text_line_spacing = get_text_line_spacing;
190 label_object_class->get_text_color = get_text_color;
191 label_object_class->draw_object = draw_object;
192 label_object_class->draw_shadow = draw_shadow;
194 object_class->finalize = gl_label_text_finalize;
198 /*****************************************************************************/
199 /* Object Instance Init Function. */
200 /*****************************************************************************/
202 gl_label_text_init (glLabelText *ltext)
204 ltext->priv = g_new0 (glLabelTextPrivate, 1);
206 ltext->priv->tag_table = gtk_text_tag_table_new ();
207 ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
209 ltext->priv->font_family = g_strdup(DEFAULT_FONT_FAMILY);
210 ltext->priv->font_size = DEFAULT_FONT_SIZE;
211 ltext->priv->font_weight = DEFAULT_FONT_WEIGHT;
212 ltext->priv->font_italic_flag = DEFAULT_FONT_ITALIC_FLAG;
213 ltext->priv->align = DEFAULT_ALIGN;
214 ltext->priv->color_node = gl_color_node_new_default ();
215 ltext->priv->color_node->color = DEFAULT_COLOR;
216 ltext->priv->line_spacing = DEFAULT_TEXT_LINE_SPACING;
217 ltext->priv->auto_shrink = DEFAULT_AUTO_SHRINK;
219 ltext->priv->size_changed = TRUE;
221 g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
222 G_CALLBACK(buffer_changed_cb), ltext);
226 /*****************************************************************************/
227 /* Finalize Method. */
228 /*****************************************************************************/
230 gl_label_text_finalize (GObject *object)
232 glLabelText *ltext = GL_LABEL_TEXT (object);
234 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
236 g_object_unref (ltext->priv->tag_table);
237 g_object_unref (ltext->priv->buffer);
238 g_free (ltext->priv->font_family);
239 gl_color_node_free (&(ltext->priv->color_node));
240 g_free (ltext->priv);
242 G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
246 /*****************************************************************************/
247 /** New Object Generator. */
248 /*****************************************************************************/
250 gl_label_text_new (glLabel *label)
254 ltext = g_object_new (gl_label_text_get_type(), NULL);
256 gl_label_object_set_parent (GL_LABEL_OBJECT(ltext), label);
258 return G_OBJECT (ltext);
262 /*****************************************************************************/
263 /* Copy object contents. */
264 /*****************************************************************************/
266 copy (glLabelObject *dst_object,
267 glLabelObject *src_object)
269 glLabelText *ltext = (glLabelText *)src_object;
270 glLabelText *new_ltext = (glLabelText *)dst_object;
272 glColorNode *text_color_node;
274 gl_debug (DEBUG_LABEL, "START");
276 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
277 g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
279 lines = gl_label_text_get_lines (ltext);
280 text_color_node = get_text_color (src_object);
281 gl_label_text_set_lines (new_ltext, lines);
283 new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
284 new_ltext->priv->font_size = ltext->priv->font_size;
285 new_ltext->priv->font_weight = ltext->priv->font_weight;
286 new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
287 set_text_color (dst_object, text_color_node);
288 new_ltext->priv->align = ltext->priv->align;
289 new_ltext->priv->line_spacing = ltext->priv->line_spacing;
290 new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
292 new_ltext->priv->size_changed = ltext->priv->size_changed;
293 new_ltext->priv->w = ltext->priv->w;
294 new_ltext->priv->h = ltext->priv->h;
296 gl_color_node_free (&text_color_node);
297 gl_text_node_lines_free (&lines);
299 gl_debug (DEBUG_LABEL, "END");
303 /*****************************************************************************/
304 /* Set object params. */
305 /*****************************************************************************/
307 gl_label_text_set_lines (glLabelText *ltext,
312 gl_debug (DEBUG_LABEL, "START");
314 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
316 text = gl_text_node_lines_expand (lines, NULL);
317 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
320 ltext->priv->size_changed = TRUE;
322 gl_debug (DEBUG_LABEL, "END");
325 /*****************************************************************************/
326 /* Get object params. */
327 /*****************************************************************************/
329 gl_label_text_get_buffer (glLabelText *ltext)
331 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
333 return ltext->priv->buffer;
338 gl_label_text_get_lines (glLabelText *ltext)
340 GtkTextIter start, end;
344 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
346 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
347 text = gtk_text_buffer_get_text (ltext->priv->buffer,
348 &start, &end, FALSE);
349 lines = gl_text_node_lines_new_from_text (text);
356 /*****************************************************************************/
357 /* Text buffer "changed" callback. */
358 /*****************************************************************************/
360 buffer_changed_cb (GtkTextBuffer *textbuffer,
363 ltext->priv->size_changed = TRUE;
365 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
369 /*****************************************************************************/
370 /* Get object size method. */
371 /*****************************************************************************/
373 get_size (glLabelObject *object,
377 glLabelText *ltext = (glLabelText *)object;
378 PangoFontMap *fontmap;
379 PangoContext *context;
380 cairo_font_options_t *options;
383 PangoFontDescription *desc;
385 gdouble line_spacing;
386 GtkTextIter start, end;
388 gdouble w_parent, h_parent;
391 gl_debug (DEBUG_LABEL, "START");
393 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
395 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
397 if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
403 if (!ltext->priv->size_changed)
410 font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
411 line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
413 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
414 text = gtk_text_buffer_get_text (ltext->priv->buffer,
415 &start, &end, FALSE);
418 fontmap = pango_cairo_font_map_new ();
419 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
420 options = cairo_font_options_create ();
421 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
422 pango_cairo_context_set_font_options (context, options);
423 cairo_font_options_destroy (options);
425 layout = pango_layout_new (context);
427 style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
429 desc = pango_font_description_new ();
430 pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
431 pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
432 pango_font_description_set_style (desc, style);
433 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
434 pango_layout_set_font_description (layout, desc);
435 pango_font_description_free (desc);
437 pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
438 pango_layout_set_text (layout, text, -1);
439 pango_layout_get_size (layout, &iw, &ih);
440 *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
441 *h = ltext->priv->h = ih / PANGO_SCALE;
442 ltext->priv->size_changed = FALSE;
444 g_object_unref (layout);
445 g_object_unref (context);
446 g_object_unref (fontmap);
449 gl_debug (DEBUG_LABEL, "END");
453 /*****************************************************************************/
454 /* Set font family method. */
455 /*****************************************************************************/
457 set_font_family (glLabelObject *object,
458 const gchar *font_family)
460 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 family_names = gl_util_get_font_family_list ();
470 if (g_list_find_custom (family_names, font_family, (GCompareFunc)g_utf8_collate)) {
471 good_font_family = g_strdup (font_family);
473 if (family_names != NULL) {
474 good_font_family = g_strdup (family_names->data); /* 1st entry */
476 good_font_family = g_strdup (font_family);
480 if (ltext->priv->font_family) {
481 if (g_strcasecmp (ltext->priv->font_family, good_font_family) == 0) {
482 g_free (good_font_family);
483 gl_debug (DEBUG_LABEL, "END (no change)");
486 g_free (ltext->priv->font_family);
488 ltext->priv->font_family = g_strdup (good_font_family);
489 g_free (good_font_family);
491 gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
493 ltext->priv->size_changed = TRUE;
495 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
497 gl_debug (DEBUG_LABEL, "END");
501 /*****************************************************************************/
502 /* Set font size method. */
503 /*****************************************************************************/
505 set_font_size (glLabelObject *object,
508 glLabelText *ltext = (glLabelText *)object;
510 gl_debug (DEBUG_LABEL, "START");
512 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
514 if (ltext->priv->font_size != font_size) {
516 ltext->priv->size_changed = TRUE;
518 ltext->priv->font_size = font_size;
519 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
523 gl_debug (DEBUG_LABEL, "END");
527 /*****************************************************************************/
528 /* Set font weight method. */
529 /*****************************************************************************/
531 set_font_weight (glLabelObject *object,
532 PangoWeight font_weight)
534 glLabelText *ltext = (glLabelText *)object;
536 gl_debug (DEBUG_LABEL, "START");
538 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
540 if (ltext->priv->font_weight != font_weight) {
542 ltext->priv->size_changed = TRUE;
544 ltext->priv->font_weight = font_weight;
545 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
549 gl_debug (DEBUG_LABEL, "END");
553 /*****************************************************************************/
554 /* Set font italic flag method. */
555 /*****************************************************************************/
557 set_font_italic_flag (glLabelObject *object,
558 gboolean font_italic_flag)
560 glLabelText *ltext = (glLabelText *)object;
562 gl_debug (DEBUG_LABEL, "START");
564 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
566 if (ltext->priv->font_italic_flag != font_italic_flag) {
568 ltext->priv->size_changed = TRUE;
570 ltext->priv->font_italic_flag = font_italic_flag;
571 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
575 gl_debug (DEBUG_LABEL, "END");
579 /*****************************************************************************/
580 /* Set text alignment method. */
581 /*****************************************************************************/
583 set_text_alignment (glLabelObject *object,
584 PangoAlignment text_alignment)
586 glLabelText *ltext = (glLabelText *)object;
588 gl_debug (DEBUG_LABEL, "START");
590 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
592 if (ltext->priv->align != text_alignment) {
594 ltext->priv->size_changed = TRUE;
596 ltext->priv->align = text_alignment;
597 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
601 gl_debug (DEBUG_LABEL, "END");
605 /*****************************************************************************/
606 /* Set text line spacing method. */
607 /*****************************************************************************/
609 set_text_line_spacing (glLabelObject *object,
610 gdouble line_spacing)
612 glLabelText *ltext = (glLabelText *)object;
614 gl_debug (DEBUG_LABEL, "START");
616 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
618 if (ltext->priv->line_spacing != line_spacing) {
620 ltext->priv->size_changed = TRUE;
622 ltext->priv->line_spacing = line_spacing;
623 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
627 gl_debug (DEBUG_LABEL, "END");
631 /*****************************************************************************/
632 /* Set text color method. */
633 /*****************************************************************************/
635 set_text_color (glLabelObject *object,
636 glColorNode *text_color_node)
638 glLabelText *ltext = (glLabelText *)object;
640 gl_debug (DEBUG_LABEL, "START");
642 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
644 if (!gl_color_node_equal (ltext->priv->color_node, text_color_node)) {
646 gl_color_node_free (&(ltext->priv->color_node));
647 ltext->priv->color_node = gl_color_node_dup (text_color_node);
649 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
653 gl_debug (DEBUG_LABEL, "END");
657 /*****************************************************************************/
658 /* Get font family method. */
659 /*****************************************************************************/
661 get_font_family (glLabelObject *object)
663 glLabelText *ltext = (glLabelText *)object;
665 gl_debug (DEBUG_LABEL, "");
667 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
669 return g_strdup (ltext->priv->font_family);
673 /*****************************************************************************/
674 /* Get font size method. */
675 /*****************************************************************************/
677 get_font_size (glLabelObject *object)
679 glLabelText *ltext = (glLabelText *)object;
681 gl_debug (DEBUG_LABEL, "");
683 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
685 return ltext->priv->font_size;
689 /*****************************************************************************/
690 /* Get font weight method. */
691 /*****************************************************************************/
693 get_font_weight (glLabelObject *object)
695 glLabelText *ltext = (glLabelText *)object;
697 gl_debug (DEBUG_LABEL, "");
699 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
701 return ltext->priv->font_weight;
705 /*****************************************************************************/
706 /* Get font italic flag method. */
707 /*****************************************************************************/
709 get_font_italic_flag (glLabelObject *object)
711 glLabelText *ltext = (glLabelText *)object;
713 gl_debug (DEBUG_LABEL, "");
715 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
717 return ltext->priv->font_italic_flag;
721 /*****************************************************************************/
722 /* Get text alignment method. */
723 /*****************************************************************************/
724 static PangoAlignment
725 get_text_alignment (glLabelObject *object)
727 glLabelText *ltext = (glLabelText *)object;
729 gl_debug (DEBUG_LABEL, "");
731 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
733 return ltext->priv->align;
737 /*****************************************************************************/
738 /* Get text line spacing method. */
739 /*****************************************************************************/
741 get_text_line_spacing (glLabelObject *object)
743 glLabelText *ltext = (glLabelText *)object;
745 gl_debug (DEBUG_LABEL, "");
747 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
749 return ltext->priv->line_spacing;
753 /*****************************************************************************/
754 /* Get text color method. */
755 /*****************************************************************************/
757 get_text_color (glLabelObject *object)
759 glLabelText *ltext = (glLabelText *)object;
761 gl_debug (DEBUG_LABEL, "");
763 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
765 return gl_color_node_dup (ltext->priv->color_node);
769 /*****************************************************************************/
770 /* Set auto shrink flag. */
771 /*****************************************************************************/
773 gl_label_text_set_auto_shrink (glLabelText *ltext,
774 gboolean auto_shrink)
776 gl_debug (DEBUG_LABEL, "BEGIN");
778 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
780 if (ltext->priv->auto_shrink != auto_shrink) {
782 ltext->priv->auto_shrink = auto_shrink;
783 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
787 gl_debug (DEBUG_LABEL, "END");
791 /*****************************************************************************/
792 /* Query auto shrink flag. */
793 /*****************************************************************************/
795 gl_label_text_get_auto_shrink (glLabelText *ltext)
797 gl_debug (DEBUG_LABEL, "");
799 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
801 return ltext->priv->auto_shrink;
805 /*****************************************************************************/
806 /* Draw object method. */
807 /*****************************************************************************/
809 draw_object (glLabelObject *object,
811 gboolean screen_flag,
812 glMergeRecord *record)
814 glColorNode *color_node;
817 gl_debug (DEBUG_LABEL, "START");
819 color_node = gl_label_object_get_text_color (object);
820 color = gl_color_node_expand (color_node, record);
821 if (color_node->field_flag && screen_flag)
823 color = GL_COLOR_MERGE_DEFAULT;
825 gl_color_node_free (&color_node);
827 draw_text_real (object, cr, screen_flag, record, color);
829 gl_debug (DEBUG_LABEL, "END");
833 /*****************************************************************************/
834 /* Draw shadow method. */
835 /*****************************************************************************/
837 draw_shadow (glLabelObject *object,
839 gboolean screen_flag,
840 glMergeRecord *record)
842 glColorNode *color_node;
844 glColorNode *shadow_color_node;
845 gdouble shadow_opacity;
848 gl_debug (DEBUG_LABEL, "START");
850 color_node = gl_label_object_get_text_color (object);
851 color = gl_color_node_expand (color_node, record);
852 if (color_node->field_flag && screen_flag)
854 color = GL_COLOR_MERGE_DEFAULT;
856 gl_color_node_free (&color_node);
858 shadow_color_node = gl_label_object_get_shadow_color (object);
859 if (shadow_color_node->field_flag)
861 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
863 shadow_opacity = gl_label_object_get_shadow_opacity (object);
864 shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
865 gl_color_node_free (&shadow_color_node);
867 draw_text_real (object, cr, screen_flag, record, shadow_color);
869 gl_debug (DEBUG_LABEL, "END");
873 /*****************************************************************************/
875 /*****************************************************************************/
877 draw_text_real (glLabelObject *object,
879 gboolean screen_flag,
880 glMergeRecord *record,
884 cairo_matrix_t matrix;
885 gdouble object_w, object_h;
886 gdouble raw_w, raw_h;
891 PangoWeight font_weight;
892 gboolean font_italic_flag;
893 gboolean auto_shrink;
894 gdouble text_line_spacing;
895 PangoAlignment alignment;
898 PangoFontDescription *desc;
899 gdouble scale_x, scale_y;
900 cairo_font_options_t *font_options;
901 PangoContext *context;
904 gl_debug (DEBUG_LABEL, "START");
906 gl_label_object_get_position (object, &x0, &y0);
907 gl_label_object_get_matrix (object, &matrix);
909 gl_label_object_get_size (object, &object_w, &object_h);
910 gl_label_object_get_raw_size (object, &raw_w, &raw_h);
911 lines = gl_label_text_get_lines (GL_LABEL_TEXT (object));
912 font_family = gl_label_object_get_font_family (object);
913 font_size = gl_label_object_get_font_size (object) * FONT_SCALE;
914 font_weight = gl_label_object_get_font_weight (object);
915 font_italic_flag = gl_label_object_get_font_italic_flag (object);
917 alignment = gl_label_object_get_text_alignment (object);
919 gl_label_object_get_text_line_spacing (object);
920 auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
922 text = gl_text_node_lines_expand (lines, record);
924 style = font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
927 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
929 font_size = auto_shrink_font_size (cr,
940 * Workaround for pango Bug#341481.
941 * Render font at device scale and scale font size accordingly.
945 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
946 scale_x = fabs (scale_x);
947 scale_y = fabs (scale_y);
949 cairo_scale (cr, scale_x, scale_y);
951 layout = pango_cairo_create_layout (cr);
953 font_options = cairo_font_options_create ();
954 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
955 context = pango_layout_get_context (layout);
956 pango_cairo_context_set_font_options (context, font_options);
957 cairo_font_options_destroy (font_options);
959 desc = pango_font_description_new ();
960 pango_font_description_set_family (desc, font_family);
961 pango_font_description_set_weight (desc, font_weight);
962 pango_font_description_set_style (desc, style);
963 pango_font_description_set_size (desc, font_size * PANGO_SCALE / scale_x);
964 pango_layout_set_font_description (layout, desc);
965 pango_font_description_free (desc);
967 pango_layout_set_text (layout, text, -1);
968 pango_layout_set_spacing (layout, font_size * (text_line_spacing-1) * PANGO_SCALE / scale_x);
971 pango_layout_set_width (layout, -1);
975 pango_layout_set_width (layout, object_w * PANGO_SCALE / scale_x);
977 pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
978 pango_layout_set_alignment (layout, alignment);
981 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
982 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, 0);
983 pango_cairo_show_layout (cr, layout);
987 g_object_unref (layout);
990 gl_text_node_lines_free (&lines);
991 g_free (font_family);
993 gl_debug (DEBUG_LABEL, "END");
997 /*****************************************************************************/
998 /* Automatically shrink text size to fit within horizontal width. */
999 /*****************************************************************************/
1001 auto_shrink_font_size (cairo_t *cr,
1009 PangoLayout *layout;
1010 PangoFontDescription *desc;
1012 gdouble layout_width;
1015 layout = pango_cairo_create_layout (cr);
1017 desc = pango_font_description_new ();
1018 pango_font_description_set_family (desc, family);
1019 pango_font_description_set_weight (desc, weight);
1020 pango_font_description_set_style (desc, style);
1021 pango_font_description_set_size (desc, size * PANGO_SCALE);
1023 pango_layout_set_font_description (layout, desc);
1024 pango_font_description_free (desc);
1026 pango_layout_set_text (layout, text, -1);
1027 pango_layout_set_width (layout, -1);
1028 pango_layout_get_size (layout, &iw, &ih);
1029 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
1031 g_object_unref (layout);
1033 g_print ("Object w = %g, layout w = %g\n", width, layout_width);
1035 if ( layout_width > width )
1038 new_size = size * (width-2*GL_LABEL_TEXT_MARGIN)/layout_width;
1040 /* Round down to nearest 1/2 point */
1041 new_size = (int)(new_size*2.0) / 2.0;
1043 /* don't get ridiculously small. */
1060 * Local Variables: -- emacs
1062 * c-basic-offset: 8 -- emacs
1063 * tab-width: 8 -- emacs
1064 * indent-tabs-mode: nil -- emacs