1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (GLABELS) Label and Business Card Creation program for GNOME
6 * label_text.c: GLabels label text object
8 * Copyright (C) 2001-2007 Jim Evins <evins@snaught.com>.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "label-text.h"
27 #include <glib/gmem.h>
28 #include <glib/gstrfuncs.h>
29 #include <glib/gmessages.h>
30 #include <pango/pango.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)
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;
74 /*========================================================*/
75 /* Private globals. */
76 /*========================================================*/
78 /*========================================================*/
79 /* Private function prototypes. */
80 /*========================================================*/
82 static void gl_label_text_finalize (GObject *object);
84 static void copy (glLabelObject *dst_object,
85 glLabelObject *src_object);
87 static void buffer_changed_cb (GtkTextBuffer *textbuffer,
90 static void get_size (glLabelObject *object,
94 static void set_font_family (glLabelObject *object,
95 const gchar *font_family);
97 static void set_font_size (glLabelObject *object,
100 static void set_font_weight (glLabelObject *object,
101 PangoWeight font_weight);
103 static void set_font_italic_flag (glLabelObject *object,
104 gboolean font_italic_flag);
106 static void set_text_alignment (glLabelObject *object,
107 PangoAlignment text_alignment);
109 static void set_text_line_spacing (glLabelObject *object,
110 gdouble text_line_spacing);
112 static void set_text_color (glLabelObject *object,
113 glColorNode *text_color_node);
115 static gchar *get_font_family (glLabelObject *object);
117 static gdouble get_font_size (glLabelObject *object);
119 static PangoWeight get_font_weight (glLabelObject *object);
121 static gboolean get_font_italic_flag (glLabelObject *object);
123 static PangoAlignment get_text_alignment (glLabelObject *object);
125 static gdouble get_text_line_spacing (glLabelObject *object);
127 static glColorNode* get_text_color (glLabelObject *object);
129 static void draw_object (glLabelObject *object,
131 gboolean screen_flag,
132 glMergeRecord *record);
134 static void draw_shadow (glLabelObject *object,
136 gboolean screen_flag,
137 glMergeRecord *record);
139 static gdouble auto_shrink_font_size (cairo_t *cr,
149 /*****************************************************************************/
150 /* Boilerplate object stuff. */
151 /*****************************************************************************/
152 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT);
155 gl_label_text_class_init (glLabelTextClass *class)
157 GObjectClass *object_class = G_OBJECT_CLASS (class);
158 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
160 gl_label_text_parent_class = g_type_class_peek_parent (class);
162 label_object_class->copy = copy;
164 label_object_class->get_size = get_size;
166 label_object_class->set_font_family = set_font_family;
167 label_object_class->set_font_size = set_font_size;
168 label_object_class->set_font_weight = set_font_weight;
169 label_object_class->set_font_italic_flag = set_font_italic_flag;
170 label_object_class->set_text_alignment = set_text_alignment;
171 label_object_class->set_text_line_spacing = set_text_line_spacing;
172 label_object_class->set_text_color = set_text_color;
173 label_object_class->get_font_family = get_font_family;
174 label_object_class->get_font_size = get_font_size;
175 label_object_class->get_font_weight = get_font_weight;
176 label_object_class->get_font_italic_flag = get_font_italic_flag;
177 label_object_class->get_text_alignment = get_text_alignment;
178 label_object_class->get_text_line_spacing = get_text_line_spacing;
179 label_object_class->get_text_color = get_text_color;
180 label_object_class->draw_object = draw_object;
181 label_object_class->draw_shadow = draw_shadow;
183 object_class->finalize = gl_label_text_finalize;
187 gl_label_text_init (glLabelText *ltext)
189 ltext->priv = g_new0 (glLabelTextPrivate, 1);
191 ltext->priv->tag_table = gtk_text_tag_table_new ();
192 ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
194 ltext->priv->font_family = g_strdup(DEFAULT_FONT_FAMILY);
195 ltext->priv->font_size = DEFAULT_FONT_SIZE;
196 ltext->priv->font_weight = DEFAULT_FONT_WEIGHT;
197 ltext->priv->font_italic_flag = DEFAULT_FONT_ITALIC_FLAG;
198 ltext->priv->align = DEFAULT_ALIGN;
199 ltext->priv->color_node = gl_color_node_new_default ();
200 ltext->priv->color_node->color = DEFAULT_COLOR;
201 ltext->priv->line_spacing = DEFAULT_TEXT_LINE_SPACING;
202 ltext->priv->auto_shrink = DEFAULT_AUTO_SHRINK;
204 ltext->priv->size_changed = TRUE;
206 g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
207 G_CALLBACK(buffer_changed_cb), ltext);
211 gl_label_text_finalize (GObject *object)
213 glLabelText *ltext = GL_LABEL_TEXT (object);
215 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
217 g_object_unref (ltext->priv->tag_table);
218 g_object_unref (ltext->priv->buffer);
219 g_free (ltext->priv->font_family);
220 gl_color_node_free (&(ltext->priv->color_node));
221 g_free (ltext->priv);
223 G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
226 /*****************************************************************************/
227 /* NEW label "text" object. */
228 /*****************************************************************************/
230 gl_label_text_new (glLabel *label)
234 ltext = g_object_new (gl_label_text_get_type(), NULL);
236 gl_label_object_set_parent (GL_LABEL_OBJECT(ltext), label);
238 return G_OBJECT (ltext);
241 /*****************************************************************************/
242 /* Copy object contents. */
243 /*****************************************************************************/
245 copy (glLabelObject *dst_object,
246 glLabelObject *src_object)
248 glLabelText *ltext = (glLabelText *)src_object;
249 glLabelText *new_ltext = (glLabelText *)dst_object;
251 glColorNode *text_color_node;
253 gl_debug (DEBUG_LABEL, "START");
255 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
256 g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
258 lines = gl_label_text_get_lines (ltext);
259 text_color_node = get_text_color (src_object);
260 gl_label_text_set_lines (new_ltext, lines);
262 new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
263 new_ltext->priv->font_size = ltext->priv->font_size;
264 new_ltext->priv->font_weight = ltext->priv->font_weight;
265 new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
266 set_text_color (dst_object, text_color_node);
267 new_ltext->priv->align = ltext->priv->align;
268 new_ltext->priv->line_spacing = ltext->priv->line_spacing;
269 new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
271 new_ltext->priv->size_changed = ltext->priv->size_changed;
272 new_ltext->priv->w = ltext->priv->w;
273 new_ltext->priv->h = ltext->priv->h;
275 gl_color_node_free (&text_color_node);
276 gl_text_node_lines_free (&lines);
278 gl_debug (DEBUG_LABEL, "END");
282 /*****************************************************************************/
283 /* Set object params. */
284 /*****************************************************************************/
286 gl_label_text_set_lines (glLabelText *ltext,
291 gl_debug (DEBUG_LABEL, "START");
293 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
295 text = gl_text_node_lines_expand (lines, NULL);
296 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
299 ltext->priv->size_changed = TRUE;
301 gl_debug (DEBUG_LABEL, "END");
304 /*****************************************************************************/
305 /* Get object params. */
306 /*****************************************************************************/
308 gl_label_text_get_buffer (glLabelText *ltext)
310 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
312 return ltext->priv->buffer;
316 gl_label_text_get_lines (glLabelText *ltext)
318 GtkTextIter start, end;
322 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
324 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
325 text = gtk_text_buffer_get_text (ltext->priv->buffer,
326 &start, &end, FALSE);
327 lines = gl_text_node_lines_new_from_text (text);
333 /*---------------------------------------------------------------------------*/
334 /* PRIVATE. text buffer "changed" callback. */
335 /*---------------------------------------------------------------------------*/
336 void buffer_changed_cb (GtkTextBuffer *textbuffer,
339 ltext->priv->size_changed = TRUE;
341 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
344 /*---------------------------------------------------------------------------*/
345 /* PRIVATE. get object size method. */
346 /*---------------------------------------------------------------------------*/
348 get_size (glLabelObject *object,
352 glLabelText *ltext = (glLabelText *)object;
353 PangoFontMap *fontmap;
354 PangoContext *context;
355 cairo_font_options_t *options;
358 PangoFontDescription *desc;
360 gdouble line_spacing;
361 GtkTextIter start, end;
363 gdouble w_parent, h_parent;
366 gl_debug (DEBUG_LABEL, "START");
368 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
370 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
372 if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
378 if (!ltext->priv->size_changed)
385 font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
386 line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
388 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
389 text = gtk_text_buffer_get_text (ltext->priv->buffer,
390 &start, &end, FALSE);
393 fontmap = pango_cairo_font_map_new ();
394 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
395 options = cairo_font_options_create ();
396 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
397 pango_cairo_context_set_font_options (context, options);
398 cairo_font_options_destroy (options);
400 layout = pango_layout_new (context);
402 style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
404 desc = pango_font_description_new ();
405 pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
406 pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
407 pango_font_description_set_style (desc, style);
408 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
409 pango_layout_set_font_description (layout, desc);
410 pango_font_description_free (desc);
412 pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
413 pango_layout_set_text (layout, text, -1);
414 pango_layout_get_size (layout, &iw, &ih);
415 *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
416 *h = ltext->priv->h = ih / PANGO_SCALE;
417 ltext->priv->size_changed = FALSE;
419 g_object_unref (layout);
420 g_object_unref (context);
421 g_object_unref (fontmap);
424 gl_debug (DEBUG_LABEL, "END");
427 /*---------------------------------------------------------------------------*/
428 /* PRIVATE. set font family method. */
429 /*---------------------------------------------------------------------------*/
431 set_font_family (glLabelObject *object,
432 const gchar *font_family)
434 glLabelText *ltext = (glLabelText *)object;
436 gchar *good_font_family;
438 gl_debug (DEBUG_LABEL, "START");
440 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
441 g_return_if_fail (font_family);
443 family_names = gl_util_get_font_family_list ();
444 if (g_list_find_custom (family_names, font_family, (GCompareFunc)g_utf8_collate)) {
445 good_font_family = g_strdup (font_family);
447 if (family_names != NULL) {
448 good_font_family = g_strdup (family_names->data); /* 1st entry */
450 good_font_family = g_strdup (font_family);
454 if (ltext->priv->font_family) {
455 if (g_strcasecmp (ltext->priv->font_family, good_font_family) == 0) {
456 g_free (good_font_family);
457 gl_debug (DEBUG_LABEL, "END (no change)");
460 g_free (ltext->priv->font_family);
462 ltext->priv->font_family = g_strdup (good_font_family);
463 g_free (good_font_family);
465 gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
467 ltext->priv->size_changed = TRUE;
469 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
471 gl_debug (DEBUG_LABEL, "END");
474 /*---------------------------------------------------------------------------*/
475 /* PRIVATE. set font size method. */
476 /*---------------------------------------------------------------------------*/
478 set_font_size (glLabelObject *object,
481 glLabelText *ltext = (glLabelText *)object;
483 gl_debug (DEBUG_LABEL, "START");
485 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
487 if (ltext->priv->font_size != font_size) {
489 ltext->priv->size_changed = TRUE;
491 ltext->priv->font_size = font_size;
492 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
496 gl_debug (DEBUG_LABEL, "END");
499 /*---------------------------------------------------------------------------*/
500 /* PRIVATE. set font weight method. */
501 /*---------------------------------------------------------------------------*/
503 set_font_weight (glLabelObject *object,
504 PangoWeight font_weight)
506 glLabelText *ltext = (glLabelText *)object;
508 gl_debug (DEBUG_LABEL, "START");
510 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
512 if (ltext->priv->font_weight != font_weight) {
514 ltext->priv->size_changed = TRUE;
516 ltext->priv->font_weight = font_weight;
517 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
521 gl_debug (DEBUG_LABEL, "END");
524 /*---------------------------------------------------------------------------*/
525 /* PRIVATE. set font italic flag method. */
526 /*---------------------------------------------------------------------------*/
528 set_font_italic_flag (glLabelObject *object,
529 gboolean font_italic_flag)
531 glLabelText *ltext = (glLabelText *)object;
533 gl_debug (DEBUG_LABEL, "START");
535 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
537 if (ltext->priv->font_italic_flag != font_italic_flag) {
539 ltext->priv->size_changed = TRUE;
541 ltext->priv->font_italic_flag = font_italic_flag;
542 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
546 gl_debug (DEBUG_LABEL, "END");
549 /*---------------------------------------------------------------------------*/
550 /* PRIVATE. set text alignment method. */
551 /*---------------------------------------------------------------------------*/
553 set_text_alignment (glLabelObject *object,
554 PangoAlignment text_alignment)
556 glLabelText *ltext = (glLabelText *)object;
558 gl_debug (DEBUG_LABEL, "START");
560 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
562 if (ltext->priv->align != text_alignment) {
564 ltext->priv->size_changed = TRUE;
566 ltext->priv->align = text_alignment;
567 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
571 gl_debug (DEBUG_LABEL, "END");
574 /*---------------------------------------------------------------------------*/
575 /* PRIVATE. set text line spacing method. */
576 /*---------------------------------------------------------------------------*/
578 set_text_line_spacing (glLabelObject *object,
579 gdouble line_spacing)
581 glLabelText *ltext = (glLabelText *)object;
583 gl_debug (DEBUG_LABEL, "START");
585 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
587 if (ltext->priv->line_spacing != line_spacing) {
589 ltext->priv->size_changed = TRUE;
591 ltext->priv->line_spacing = line_spacing;
592 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
596 gl_debug (DEBUG_LABEL, "END");
599 /*---------------------------------------------------------------------------*/
600 /* PRIVATE. set text color method. */
601 /*---------------------------------------------------------------------------*/
603 set_text_color (glLabelObject *object,
604 glColorNode *text_color_node)
606 glLabelText *ltext = (glLabelText *)object;
608 gl_debug (DEBUG_LABEL, "START");
610 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
612 if (!gl_color_node_equal (ltext->priv->color_node, text_color_node)) {
614 gl_color_node_free (&(ltext->priv->color_node));
615 ltext->priv->color_node = gl_color_node_dup (text_color_node);
617 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
621 gl_debug (DEBUG_LABEL, "END");
624 /*---------------------------------------------------------------------------*/
625 /* PRIVATE. get font family method. */
626 /*---------------------------------------------------------------------------*/
628 get_font_family (glLabelObject *object)
630 glLabelText *ltext = (glLabelText *)object;
632 gl_debug (DEBUG_LABEL, "");
634 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
636 return g_strdup (ltext->priv->font_family);
639 /*---------------------------------------------------------------------------*/
640 /* PRIVATE. get font size method. */
641 /*---------------------------------------------------------------------------*/
643 get_font_size (glLabelObject *object)
645 glLabelText *ltext = (glLabelText *)object;
647 gl_debug (DEBUG_LABEL, "");
649 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
651 return ltext->priv->font_size;
654 /*---------------------------------------------------------------------------*/
655 /* PRIVATE. get font weight method. */
656 /*---------------------------------------------------------------------------*/
658 get_font_weight (glLabelObject *object)
660 glLabelText *ltext = (glLabelText *)object;
662 gl_debug (DEBUG_LABEL, "");
664 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
666 return ltext->priv->font_weight;
669 /*---------------------------------------------------------------------------*/
670 /* PRIVATE. get font italic flag method. */
671 /*---------------------------------------------------------------------------*/
673 get_font_italic_flag (glLabelObject *object)
675 glLabelText *ltext = (glLabelText *)object;
677 gl_debug (DEBUG_LABEL, "");
679 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
681 return ltext->priv->font_italic_flag;
684 /*---------------------------------------------------------------------------*/
685 /* PRIVATE. get text alignment method. */
686 /*---------------------------------------------------------------------------*/
687 static PangoAlignment
688 get_text_alignment (glLabelObject *object)
690 glLabelText *ltext = (glLabelText *)object;
692 gl_debug (DEBUG_LABEL, "");
694 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
696 return ltext->priv->align;
699 /*---------------------------------------------------------------------------*/
700 /* PRIVATE. get text line spacing method. */
701 /*---------------------------------------------------------------------------*/
703 get_text_line_spacing (glLabelObject *object)
705 glLabelText *ltext = (glLabelText *)object;
707 gl_debug (DEBUG_LABEL, "");
709 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
711 return ltext->priv->line_spacing;
714 /*---------------------------------------------------------------------------*/
715 /* PRIVATE. get text color method. */
716 /*---------------------------------------------------------------------------*/
718 get_text_color (glLabelObject *object)
720 glLabelText *ltext = (glLabelText *)object;
722 gl_debug (DEBUG_LABEL, "");
724 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
726 return gl_color_node_dup (ltext->priv->color_node);
729 /*****************************************************************************/
730 /* Set auto shrink flag. */
731 /*****************************************************************************/
733 gl_label_text_set_auto_shrink (glLabelText *ltext,
734 gboolean auto_shrink)
736 gl_debug (DEBUG_LABEL, "BEGIN");
738 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
740 if (ltext->priv->auto_shrink != auto_shrink) {
742 ltext->priv->auto_shrink = auto_shrink;
743 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
747 gl_debug (DEBUG_LABEL, "END");
750 /*****************************************************************************/
751 /* Query auto shrink flag. */
752 /*****************************************************************************/
754 gl_label_text_get_auto_shrink (glLabelText *ltext)
756 gl_debug (DEBUG_LABEL, "");
758 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
760 return ltext->priv->auto_shrink;
763 /*****************************************************************************/
764 /* Draw object method. */
765 /*****************************************************************************/
767 draw_object (glLabelObject *object,
769 gboolean screen_flag,
770 glMergeRecord *record)
773 cairo_matrix_t matrix;
774 gdouble object_w, object_h;
775 gdouble raw_w, raw_h;
780 PangoWeight font_weight;
781 gboolean font_italic_flag;
782 glColorNode *color_node;
783 gboolean auto_shrink;
785 gdouble text_line_spacing;
786 PangoAlignment alignment;
789 PangoFontDescription *desc;
790 gdouble scale_x, scale_y;
791 cairo_font_options_t *font_options;
792 PangoContext *context;
795 gl_debug (DEBUG_LABEL, "START");
797 gl_label_object_get_position (object, &x0, &y0);
798 gl_label_object_get_matrix (object, &matrix);
800 gl_label_object_get_size (object, &object_w, &object_h);
801 gl_label_object_get_raw_size (object, &raw_w, &raw_h);
802 lines = gl_label_text_get_lines (GL_LABEL_TEXT (object));
803 font_family = gl_label_object_get_font_family (object);
804 font_size = gl_label_object_get_font_size (object) * FONT_SCALE;
805 font_weight = gl_label_object_get_font_weight (object);
806 font_italic_flag = gl_label_object_get_font_italic_flag (object);
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 alignment = gl_label_object_get_text_alignment (object);
818 gl_label_object_get_text_line_spacing (object);
819 auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
821 text = gl_text_node_lines_expand (lines, record);
823 style = font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
826 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
828 font_size = auto_shrink_font_size (cr,
835 g_print ("Autosize new size = %g\n", font_size);
840 * Workaround for pango Bug#341481.
841 * Render font at device scale and scale font size accordingly.
845 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
846 scale_x = fabs (scale_x);
847 scale_y = fabs (scale_y);
849 cairo_scale (cr, scale_x, scale_y);
851 layout = pango_cairo_create_layout (cr);
853 font_options = cairo_font_options_create ();
854 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
855 context = pango_layout_get_context (layout);
856 pango_cairo_context_set_font_options (context, font_options);
857 cairo_font_options_destroy (font_options);
859 desc = pango_font_description_new ();
860 pango_font_description_set_family (desc, font_family);
861 pango_font_description_set_weight (desc, font_weight);
862 pango_font_description_set_style (desc, style);
863 pango_font_description_set_size (desc, font_size * PANGO_SCALE / scale_x);
864 pango_layout_set_font_description (layout, desc);
865 pango_font_description_free (desc);
867 pango_layout_set_text (layout, text, -1);
868 pango_layout_set_spacing (layout, font_size * (text_line_spacing-1) * PANGO_SCALE / scale_x);
871 pango_layout_set_width (layout, -1);
875 pango_layout_set_width (layout, object_w * PANGO_SCALE / scale_x);
877 pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
878 pango_layout_set_alignment (layout, alignment);
881 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
882 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, 0);
883 pango_cairo_show_layout (cr, layout);
887 g_object_unref (layout);
890 gl_text_node_lines_free (&lines);
891 g_free (font_family);
893 gl_debug (DEBUG_LABEL, "END");
896 /*****************************************************************************/
897 /* Draw shadow method. */
898 /*****************************************************************************/
900 draw_shadow (glLabelObject *object,
902 gboolean screen_flag,
903 glMergeRecord *record)
906 cairo_matrix_t matrix;
907 gdouble object_w, object_h;
908 gdouble raw_w, raw_h;
913 PangoWeight font_weight;
914 gboolean font_italic_flag;
915 gboolean auto_shrink;
917 glColorNode *color_node;
918 gdouble text_line_spacing;
919 glColorNode *shadow_color_node;
920 gdouble shadow_opacity;
922 PangoAlignment alignment;
925 PangoFontDescription *desc;
926 gdouble scale_x, scale_y;
927 cairo_font_options_t *font_options;
928 PangoContext *context;
931 gl_debug (DEBUG_LABEL, "START");
933 gl_label_object_get_position (object, &x0, &y0);
934 gl_label_object_get_matrix (object, &matrix);
936 gl_label_object_get_size (object, &object_w, &object_h);
937 gl_label_object_get_raw_size (object, &raw_w, &raw_h);
938 lines = gl_label_text_get_lines (GL_LABEL_TEXT (object));
939 font_family = gl_label_object_get_font_family (object);
940 font_size = gl_label_object_get_font_size (object) * FONT_SCALE;
941 font_weight = gl_label_object_get_font_weight (object);
942 font_italic_flag = gl_label_object_get_font_italic_flag (object);
944 color_node = gl_label_object_get_text_color (object);
945 color = gl_color_node_expand (color_node, record);
946 gl_color_node_free (&color_node);
948 alignment = gl_label_object_get_text_alignment (object);
950 gl_label_object_get_text_line_spacing (object);
951 auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
953 shadow_color_node = gl_label_object_get_shadow_color (object);
954 if (shadow_color_node->field_flag)
956 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
958 shadow_opacity = gl_label_object_get_shadow_opacity (object);
959 shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
960 gl_color_node_free (&shadow_color_node);
962 text = gl_text_node_lines_expand (lines, record);
964 style = font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
967 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
969 font_size = auto_shrink_font_size (cr,
980 * Workaround for pango Bug#341481.
981 * Render font at device scale and scale font size accordingly.
985 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
986 scale_x = fabs (scale_x);
987 scale_y = fabs (scale_y);
989 cairo_scale (cr, scale_x, scale_y);
991 layout = pango_cairo_create_layout (cr);
993 font_options = cairo_font_options_create ();
994 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
995 context = pango_layout_get_context (layout);
996 pango_cairo_context_set_font_options (context, font_options);
997 cairo_font_options_destroy (font_options);
999 desc = pango_font_description_new ();
1000 pango_font_description_set_family (desc, font_family);
1001 pango_font_description_set_weight (desc, font_weight);
1002 pango_font_description_set_style (desc, style);
1003 pango_font_description_set_size (desc, font_size * PANGO_SCALE / scale_x);
1004 pango_layout_set_font_description (layout, desc);
1005 pango_font_description_free (desc);
1007 pango_layout_set_text (layout, text, -1);
1008 pango_layout_set_spacing (layout, font_size * (text_line_spacing-1) * PANGO_SCALE / scale_x);
1011 pango_layout_set_width (layout, -1);
1015 pango_layout_set_width (layout, object_w * PANGO_SCALE / scale_x);
1017 pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
1018 pango_layout_set_alignment (layout, alignment);
1020 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (shadow_color));
1021 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, 0);
1022 pango_cairo_show_layout (cr, layout);
1027 g_object_unref (layout);
1029 gl_text_node_lines_free (&lines);
1030 g_free (font_family);
1032 gl_debug (DEBUG_LABEL, "END");
1035 /*****************************************************************************/
1036 /* Automatically shrink text size to fit within horizontal width. */
1037 /*****************************************************************************/
1039 auto_shrink_font_size (cairo_t *cr,
1047 PangoLayout *layout;
1048 PangoFontDescription *desc;
1050 gdouble layout_width;
1053 layout = pango_cairo_create_layout (cr);
1055 desc = pango_font_description_new ();
1056 pango_font_description_set_family (desc, family);
1057 pango_font_description_set_weight (desc, weight);
1058 pango_font_description_set_style (desc, style);
1059 pango_font_description_set_size (desc, size * PANGO_SCALE);
1061 pango_layout_set_font_description (layout, desc);
1062 pango_font_description_free (desc);
1064 pango_layout_set_text (layout, text, -1);
1065 pango_layout_set_width (layout, -1);
1066 pango_layout_get_size (layout, &iw, &ih);
1067 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
1069 g_object_unref (layout);
1071 g_print ("Object w = %g, layout w = %g\n", width, layout_width);
1073 if ( layout_width > width )
1076 new_size = size * (width-2*GL_LABEL_TEXT_MARGIN)/layout_width;
1078 /* Round down to nearest 1/2 point */
1079 new_size = (int)(new_size*2.0) / 2.0;
1081 /* don't get ridiculously small. */