]> git.sur5r.net Git - glabels/blob - src/label-text.c
Removed unused variables
[glabels] / src / label-text.c
1 /*
2  *  label-text.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #include <config.h>
22
23 #include "label-text.h"
24
25 #include <glib.h>
26 #include <pango/pango.h>
27 #include <math.h>
28 #include <string.h>
29
30 #include "font-util.h"
31 #include "font-history.h"
32
33 #include "debug.h"
34
35
36 /*========================================================*/
37 /* Private macros and constants.                          */
38 /*========================================================*/
39
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
48
49 #define FONT_SCALE (72.0/96.0)
50
51
52 /*========================================================*/
53 /* Private types.                                         */
54 /*========================================================*/
55
56 struct _glLabelTextPrivate {
57         GtkTextTagTable *tag_table;
58         GtkTextBuffer   *buffer;
59
60         gchar           *font_family;
61         gdouble          font_size;
62         PangoWeight      font_weight;
63         gboolean         font_italic_flag;
64         PangoAlignment   align;
65         glColorNode     *color_node;
66         gdouble          line_spacing;
67         gboolean         auto_shrink;
68
69         gboolean         size_changed;
70         gdouble          w;
71         gdouble          h;
72 };
73
74
75 /*========================================================*/
76 /* Private globals.                                       */
77 /*========================================================*/
78
79
80 /*========================================================*/
81 /* Private function prototypes.                           */
82 /*========================================================*/
83
84 static void gl_label_text_finalize      (GObject          *object);
85
86 static void copy                        (glLabelObject    *dst_object,
87                                          glLabelObject    *src_object);
88
89 static void buffer_changed_cb           (GtkTextBuffer    *textbuffer,
90                                          glLabelText      *ltext);
91
92 static void get_size                    (glLabelObject    *object,
93                                          gdouble          *w,
94                                          gdouble          *h);
95
96 static void set_font_family             (glLabelObject    *object,
97                                          const gchar      *font_family);
98
99 static void set_font_size               (glLabelObject    *object,
100                                          gdouble           font_size);
101
102 static void set_font_weight             (glLabelObject    *object,
103                                          PangoWeight       font_weight);
104
105 static void set_font_italic_flag        (glLabelObject    *object,
106                                          gboolean          font_italic_flag);
107
108 static void set_text_alignment          (glLabelObject    *object,
109                                          PangoAlignment    text_alignment);
110
111 static void set_text_line_spacing       (glLabelObject    *object,
112                                          gdouble           text_line_spacing);
113
114 static void set_text_color              (glLabelObject    *object,
115                                          glColorNode      *text_color_node);
116
117 static gchar          *get_font_family             (glLabelObject    *object);
118
119 static gdouble         get_font_size               (glLabelObject    *object);
120
121 static PangoWeight     get_font_weight             (glLabelObject    *object);
122
123 static gboolean        get_font_italic_flag        (glLabelObject    *object);
124
125 static PangoAlignment  get_text_alignment          (glLabelObject    *object);
126
127 static gdouble         get_text_line_spacing       (glLabelObject    *object);
128
129 static glColorNode*    get_text_color              (glLabelObject    *object);
130
131 static void            draw_object                 (glLabelObject    *object,
132                                                     cairo_t          *cr,
133                                                     gboolean          screen_flag,
134                                                     glMergeRecord    *record);
135
136 static void            draw_shadow                 (glLabelObject    *object,
137                                                     cairo_t          *cr,
138                                                     gboolean          screen_flag,
139                                                     glMergeRecord    *record);
140
141 static void            draw_text_real              (glLabelObject    *object,
142                                                     cairo_t          *cr,
143                                                     gboolean          screen_flag,
144                                                     glMergeRecord    *record,
145                                                     guint             color);
146
147 static gdouble         auto_shrink_font_size       (cairo_t          *cr,
148                                                     gchar            *family,
149                                                     gdouble           size,
150                                                     PangoWeight       weight,
151                                                     PangoStyle        style,
152                                                     gchar            *text,
153                                                     gdouble           width);
154
155
156 /*****************************************************************************/
157 /* Object infrastructure.                                                    */
158 /*****************************************************************************/
159 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT);
160
161
162 /*****************************************************************************/
163 /* Class Init Function.                                                      */
164 /*****************************************************************************/
165 static void
166 gl_label_text_class_init (glLabelTextClass *class)
167 {
168         GObjectClass       *object_class       = G_OBJECT_CLASS (class);
169         glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
170
171         gl_label_text_parent_class = g_type_class_peek_parent (class);
172
173         label_object_class->copy                  = copy;
174
175         label_object_class->get_size              = get_size;
176
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;
193
194         object_class->finalize = gl_label_text_finalize;
195 }
196
197
198 /*****************************************************************************/
199 /* Object Instance Init Function.                                            */
200 /*****************************************************************************/
201 static void
202 gl_label_text_init (glLabelText *ltext)
203 {
204         ltext->priv = g_new0 (glLabelTextPrivate, 1);
205
206         ltext->priv->tag_table         = gtk_text_tag_table_new ();
207         ltext->priv->buffer            = gtk_text_buffer_new (ltext->priv->tag_table);
208
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;
218
219         ltext->priv->size_changed      = TRUE;
220
221         g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
222                           G_CALLBACK(buffer_changed_cb), ltext);
223 }
224
225
226 /*****************************************************************************/
227 /* Finalize Method.                                                          */
228 /*****************************************************************************/
229 static void
230 gl_label_text_finalize (GObject *object)
231 {
232         glLabelText *ltext = GL_LABEL_TEXT (object);
233
234         g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
235
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);
241
242         G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
243 }
244
245
246 /*****************************************************************************/
247 /** New Object Generator.                                                    */
248 /*****************************************************************************/
249 GObject *
250 gl_label_text_new (glLabel *label)
251 {
252         glLabelText *ltext;
253
254         ltext = g_object_new (gl_label_text_get_type(), NULL);
255
256         gl_label_object_set_parent (GL_LABEL_OBJECT(ltext), label);
257
258         return G_OBJECT (ltext);
259 }
260
261
262 /*****************************************************************************/
263 /* Copy object contents.                                                     */
264 /*****************************************************************************/
265 static void
266 copy (glLabelObject *dst_object,
267       glLabelObject *src_object)
268 {
269         glLabelText      *ltext     = (glLabelText *)src_object;
270         glLabelText      *new_ltext = (glLabelText *)dst_object;
271         GList            *lines;
272         glColorNode      *text_color_node;
273
274         gl_debug (DEBUG_LABEL, "START");
275
276         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
277         g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
278
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);
282
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;
291
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;
295
296         gl_color_node_free (&text_color_node);
297         gl_text_node_lines_free (&lines);
298
299         gl_debug (DEBUG_LABEL, "END");
300 }
301
302
303 /*****************************************************************************/
304 /* Set object params.                                                        */
305 /*****************************************************************************/
306 void
307 gl_label_text_set_lines (glLabelText *ltext,
308                          GList       *lines)
309 {
310         gchar *text;
311
312         gl_debug (DEBUG_LABEL, "START");
313
314         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
315
316         text = gl_text_node_lines_expand (lines, NULL);
317         gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
318         g_free (text);
319
320         ltext->priv->size_changed = TRUE;
321
322         gl_debug (DEBUG_LABEL, "END");
323 }
324
325 /*****************************************************************************/
326 /* Get object params.                                                        */
327 /*****************************************************************************/
328 GtkTextBuffer *
329 gl_label_text_get_buffer (glLabelText *ltext)
330 {
331         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
332
333         return ltext->priv->buffer;
334 }
335
336
337 GList *
338 gl_label_text_get_lines (glLabelText *ltext)
339 {
340         GtkTextIter  start, end;
341         gchar       *text;
342         GList       *lines;
343
344         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
345
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);
350         g_free (text);
351
352         return lines;
353 }
354
355
356 /*****************************************************************************/
357 /* Text buffer "changed" callback.                                           */
358 /*****************************************************************************/
359 static void
360 buffer_changed_cb (GtkTextBuffer *textbuffer,
361                    glLabelText   *ltext)
362 {
363         ltext->priv->size_changed = TRUE;
364
365         gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
366 }
367
368
369 /*****************************************************************************/
370 /* Get object size method.                                                   */
371 /*****************************************************************************/
372 static void
373 get_size (glLabelObject *object,
374           gdouble       *w,
375           gdouble       *h)
376 {
377         glLabelText          *ltext = (glLabelText *)object;
378         PangoFontMap         *fontmap;
379         PangoContext         *context;
380         cairo_font_options_t *options;
381         PangoStyle            style;
382         PangoLayout          *layout;
383         PangoFontDescription *desc;
384         gdouble               font_size;
385         gdouble               line_spacing;
386         GtkTextIter           start, end;
387         gchar                *text;
388         gdouble               w_parent, h_parent;
389         gint                  iw, ih;
390
391         gl_debug (DEBUG_LABEL, "START");
392
393         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
394
395         gl_label_object_get_raw_size (object, &w_parent, &h_parent);
396
397         if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
398                 *w = w_parent;
399                 *h = h_parent;
400                 return;
401         }
402
403         if (!ltext->priv->size_changed)
404         {
405                 *w = ltext->priv->w;
406                 *h = ltext->priv->h;
407                 return;
408         }
409
410         font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
411         line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
412
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);
416
417         
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);
424
425         layout = pango_layout_new (context);
426
427         style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
428
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);
436
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;
443
444         g_object_unref (layout);
445         g_object_unref (context);
446         g_object_unref (fontmap);
447         g_free (text);
448
449         gl_debug (DEBUG_LABEL, "END");
450 }
451
452
453 /*****************************************************************************/
454 /* Set font family method.                                                   */
455 /*****************************************************************************/
456 static void
457 set_font_family (glLabelObject *object,
458                  const gchar   *font_family)
459 {
460         glLabelText    *ltext = (glLabelText *)object;
461         gchar          *good_font_family;
462
463         gl_debug (DEBUG_LABEL, "START");
464
465         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
466         g_return_if_fail (font_family);
467
468         good_font_family = gl_font_util_validate_family (font_family);
469
470         if (ltext->priv->font_family) {
471                 if (strcmp (ltext->priv->font_family, good_font_family) == 0) {
472                         g_free (good_font_family);
473                         gl_debug (DEBUG_LABEL, "END (no change)");
474                         return;
475                 }
476                 g_free (ltext->priv->font_family);
477         }
478         ltext->priv->font_family = g_strdup (good_font_family);
479         g_free (good_font_family);
480
481         gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
482
483         ltext->priv->size_changed = TRUE;
484
485         gl_font_history_model_add_family (gl_font_history, ltext->priv->font_family);
486
487         gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
488
489         gl_debug (DEBUG_LABEL, "END");
490 }
491
492
493 /*****************************************************************************/
494 /* Set font size method.                                                     */
495 /*****************************************************************************/
496 static void
497 set_font_size (glLabelObject *object,
498                gdouble        font_size)
499 {
500         glLabelText    *ltext = (glLabelText *)object;
501
502         gl_debug (DEBUG_LABEL, "START");
503
504         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
505
506         if (ltext->priv->font_size != font_size) {
507
508                 ltext->priv->size_changed = TRUE;
509
510                 ltext->priv->font_size = font_size;
511                 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
512
513         }
514
515         gl_debug (DEBUG_LABEL, "END");
516 }
517
518
519 /*****************************************************************************/
520 /* Set font weight method.                                                   */
521 /*****************************************************************************/
522 static void
523 set_font_weight (glLabelObject   *object,
524                  PangoWeight      font_weight)
525 {
526         glLabelText    *ltext = (glLabelText *)object;
527
528         gl_debug (DEBUG_LABEL, "START");
529
530         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
531
532         if (ltext->priv->font_weight != font_weight) {
533
534                 ltext->priv->size_changed = TRUE;
535
536                 ltext->priv->font_weight = font_weight;
537                 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
538
539         }
540
541         gl_debug (DEBUG_LABEL, "END");
542 }
543
544
545 /*****************************************************************************/
546 /* Set font italic flag method.                                              */
547 /*****************************************************************************/
548 static void
549 set_font_italic_flag (glLabelObject *object,
550                       gboolean       font_italic_flag)
551 {
552         glLabelText    *ltext = (glLabelText *)object;
553
554         gl_debug (DEBUG_LABEL, "START");
555
556         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
557
558         if (ltext->priv->font_italic_flag != font_italic_flag) {
559
560                 ltext->priv->size_changed = TRUE;
561
562                 ltext->priv->font_italic_flag = font_italic_flag;
563                 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
564
565         }
566
567         gl_debug (DEBUG_LABEL, "END");
568 }
569
570
571 /*****************************************************************************/
572 /* Set text alignment method.                                                */
573 /*****************************************************************************/
574 static void
575 set_text_alignment (glLabelObject    *object,
576                     PangoAlignment    text_alignment)
577 {
578         glLabelText    *ltext = (glLabelText *)object;
579
580         gl_debug (DEBUG_LABEL, "START");
581
582         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
583
584         if (ltext->priv->align != text_alignment) {
585
586                 ltext->priv->size_changed = TRUE;
587
588                 ltext->priv->align = text_alignment;
589                 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
590
591         }
592
593         gl_debug (DEBUG_LABEL, "END");
594 }
595
596
597 /*****************************************************************************/
598 /* Set text line spacing method.                                             */
599 /*****************************************************************************/
600 static void
601 set_text_line_spacing (glLabelObject *object,
602                        gdouble        line_spacing)
603 {
604         glLabelText    *ltext = (glLabelText *)object;
605
606         gl_debug (DEBUG_LABEL, "START");
607
608         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
609
610         if (ltext->priv->line_spacing != line_spacing) {
611
612                 ltext->priv->size_changed = TRUE;
613
614                 ltext->priv->line_spacing = line_spacing;
615                 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
616
617         }
618
619         gl_debug (DEBUG_LABEL, "END");
620 }
621
622
623 /*****************************************************************************/
624 /* Set text color method.                                                    */
625 /*****************************************************************************/
626 static void
627 set_text_color (glLabelObject *object,
628                 glColorNode   *text_color_node)
629 {
630         glLabelText    *ltext = (glLabelText *)object;
631
632         gl_debug (DEBUG_LABEL, "START");
633
634         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
635
636         if (!gl_color_node_equal (ltext->priv->color_node, text_color_node)) {
637
638                 gl_color_node_free (&(ltext->priv->color_node));
639                 ltext->priv->color_node = gl_color_node_dup (text_color_node);
640                 
641                 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
642
643         }
644
645         gl_debug (DEBUG_LABEL, "END");
646 }
647
648
649 /*****************************************************************************/
650 /* Get font family method.                                                   */
651 /*****************************************************************************/
652 static gchar *
653 get_font_family (glLabelObject *object)
654 {
655         glLabelText    *ltext = (glLabelText *)object;
656
657         gl_debug (DEBUG_LABEL, "");
658
659         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
660
661         return g_strdup (ltext->priv->font_family);
662 }
663
664
665 /*****************************************************************************/
666 /* Get font size method.                                                     */
667 /*****************************************************************************/
668 static gdouble
669 get_font_size (glLabelObject *object)
670 {
671         glLabelText    *ltext = (glLabelText *)object;
672
673         gl_debug (DEBUG_LABEL, "");
674
675         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
676
677         return ltext->priv->font_size;
678 }
679
680
681 /*****************************************************************************/
682 /* Get font weight method.                                                   */
683 /*****************************************************************************/
684 static PangoWeight
685 get_font_weight (glLabelObject   *object)
686 {
687         glLabelText    *ltext = (glLabelText *)object;
688
689         gl_debug (DEBUG_LABEL, "");
690
691         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
692
693         return ltext->priv->font_weight;
694 }
695
696
697 /*****************************************************************************/
698 /* Get font italic flag method.                                              */
699 /*****************************************************************************/
700 static gboolean
701 get_font_italic_flag (glLabelObject *object)
702 {
703         glLabelText    *ltext = (glLabelText *)object;
704
705         gl_debug (DEBUG_LABEL, "");
706
707         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
708
709         return ltext->priv->font_italic_flag;
710 }
711
712
713 /*****************************************************************************/
714 /* Get text alignment method.                                                */
715 /*****************************************************************************/
716 static PangoAlignment
717 get_text_alignment (glLabelObject    *object)
718 {
719         glLabelText    *ltext = (glLabelText *)object;
720
721         gl_debug (DEBUG_LABEL, "");
722
723         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
724
725         return ltext->priv->align;
726 }
727
728
729 /*****************************************************************************/
730 /* Get text line spacing method.                                             */
731 /*****************************************************************************/
732 static gdouble
733 get_text_line_spacing (glLabelObject *object)
734 {
735         glLabelText    *ltext = (glLabelText *)object;
736
737         gl_debug (DEBUG_LABEL, "");
738
739         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
740
741         return ltext->priv->line_spacing;
742 }
743
744
745 /*****************************************************************************/
746 /* Get text color method.                                                    */
747 /*****************************************************************************/
748 static glColorNode*
749 get_text_color (glLabelObject *object)
750 {
751         glLabelText    *ltext = (glLabelText *)object;
752
753         gl_debug (DEBUG_LABEL, "");
754
755         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
756
757         return gl_color_node_dup (ltext->priv->color_node);
758 }
759
760
761 /*****************************************************************************/
762 /* Set auto shrink flag.                                                     */
763 /*****************************************************************************/
764 void
765 gl_label_text_set_auto_shrink (glLabelText      *ltext,
766                                gboolean          auto_shrink)
767 {
768         gl_debug (DEBUG_LABEL, "BEGIN");
769
770         g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
771
772         if (ltext->priv->auto_shrink != auto_shrink) {
773
774                 ltext->priv->auto_shrink = auto_shrink;
775                 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
776
777         }
778
779         gl_debug (DEBUG_LABEL, "END");
780 }
781
782
783 /*****************************************************************************/
784 /* Query auto shrink flag.                                                   */
785 /*****************************************************************************/
786 gboolean
787 gl_label_text_get_auto_shrink (glLabelText      *ltext)
788 {
789         gl_debug (DEBUG_LABEL, "");
790
791         g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
792
793         return ltext->priv->auto_shrink;
794 }
795
796
797 /*****************************************************************************/
798 /* Draw object method.                                                       */
799 /*****************************************************************************/
800 static void
801 draw_object (glLabelObject *object,
802              cairo_t       *cr,
803              gboolean       screen_flag,
804              glMergeRecord *record)
805 {
806         glColorNode     *color_node;
807         guint            color;
808
809         gl_debug (DEBUG_LABEL, "START");
810
811         color_node = gl_label_object_get_text_color (object);
812         color = gl_color_node_expand (color_node, record);
813         if (color_node->field_flag && screen_flag)
814         {
815                 color = GL_COLOR_MERGE_DEFAULT;
816         }
817         gl_color_node_free (&color_node);
818         
819         draw_text_real (object, cr, screen_flag, record, color);
820
821         gl_debug (DEBUG_LABEL, "END");
822 }
823
824
825 /*****************************************************************************/
826 /* Draw shadow method.                                                       */
827 /*****************************************************************************/
828 static void
829 draw_shadow (glLabelObject *object,
830              cairo_t       *cr,
831              gboolean       screen_flag,
832              glMergeRecord *record)
833 {
834         glColorNode     *color_node;
835         guint            color;
836         glColorNode     *shadow_color_node;
837         gdouble          shadow_opacity;
838         guint            shadow_color;
839
840         gl_debug (DEBUG_LABEL, "START");
841
842         color_node = gl_label_object_get_text_color (object);
843         color = gl_color_node_expand (color_node, record);
844         if (color_node->field_flag && screen_flag)
845         {
846                 color = GL_COLOR_MERGE_DEFAULT;
847         }
848         gl_color_node_free (&color_node);
849         
850         shadow_color_node = gl_label_object_get_shadow_color (object);
851         if (shadow_color_node->field_flag)
852         {
853                 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
854         }
855         shadow_opacity = gl_label_object_get_shadow_opacity (object);
856         shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
857         gl_color_node_free (&shadow_color_node);
858
859         draw_text_real (object, cr, screen_flag, record, shadow_color);
860
861         gl_debug (DEBUG_LABEL, "END");
862 }
863
864
865 /*****************************************************************************/
866 /* Draw text.                                                                */
867 /*****************************************************************************/
868 static void
869 draw_text_real (glLabelObject *object,
870                 cairo_t       *cr,
871                 gboolean       screen_flag,
872                 glMergeRecord *record,
873                 guint          color)
874 {
875         gdouble          object_w, object_h;
876         gdouble          raw_w, raw_h;
877         gchar           *text;
878         GList           *lines;
879         gchar           *font_family;
880         gdouble          font_size;
881         PangoWeight      font_weight;
882         gboolean         font_italic_flag;
883         gboolean         auto_shrink;
884         gdouble          text_line_spacing;
885         PangoAlignment   alignment;
886         PangoStyle       style;
887         PangoLayout     *layout;
888         PangoFontDescription *desc;
889         gdouble          scale_x, scale_y;
890         cairo_font_options_t *font_options;
891         PangoContext         *context;
892
893
894         gl_debug (DEBUG_LABEL, "START");
895
896         gl_label_object_get_size (object, &object_w, &object_h);
897         gl_label_object_get_raw_size (object, &raw_w, &raw_h);
898         lines = gl_label_text_get_lines (GL_LABEL_TEXT (object));
899         font_family = gl_label_object_get_font_family (object);
900         font_size = gl_label_object_get_font_size (object) * FONT_SCALE;
901         font_weight = gl_label_object_get_font_weight (object);
902         font_italic_flag = gl_label_object_get_font_italic_flag (object);
903
904         alignment = gl_label_object_get_text_alignment (object);
905         text_line_spacing =
906                 gl_label_object_get_text_line_spacing (object);
907         auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
908
909         text = gl_text_node_lines_expand (lines, record);
910
911         style = font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
912
913
914         if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
915         {
916                 font_size = auto_shrink_font_size (cr,
917                                                    font_family,
918                                                    font_size,
919                                                    font_weight,
920                                                    style,
921                                                    text,
922                                                    object_w);
923         }
924
925
926         /*
927          * Workaround for pango Bug#341481.
928          * Render font at device scale and scale font size accordingly.
929          */
930         scale_x = 1.0;
931         scale_y = 1.0;
932         cairo_device_to_user_distance (cr, &scale_x, &scale_y);
933         scale_x = fabs (scale_x);
934         scale_y = fabs (scale_y);
935         cairo_save (cr);
936         cairo_scale (cr, scale_x, scale_y);
937
938         layout = pango_cairo_create_layout (cr);
939
940         font_options = cairo_font_options_create ();
941         cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
942         context = pango_layout_get_context (layout);
943         pango_cairo_context_set_font_options (context, font_options);
944         cairo_font_options_destroy (font_options);
945
946         desc = pango_font_description_new ();
947         pango_font_description_set_family (desc, font_family);
948         pango_font_description_set_weight (desc, font_weight);
949         pango_font_description_set_style  (desc, style);
950         pango_font_description_set_size   (desc, font_size * PANGO_SCALE / scale_x);
951         pango_layout_set_font_description (layout, desc);
952         pango_font_description_free       (desc);
953
954         pango_layout_set_text (layout, text, -1);
955         pango_layout_set_spacing (layout, font_size * (text_line_spacing-1) * PANGO_SCALE / scale_x);
956         if (raw_w == 0.0)
957         {
958                 pango_layout_set_width (layout, -1);
959         }
960         else
961         {
962                 pango_layout_set_width (layout, object_w * PANGO_SCALE / scale_x);
963         }
964         pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
965         pango_layout_set_alignment (layout, alignment);
966
967
968         cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
969         cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, 0);
970         pango_cairo_show_layout (cr, layout);
971
972         cairo_restore (cr);
973
974         g_object_unref (layout);
975
976
977         gl_text_node_lines_free (&lines);
978         g_free (font_family);
979
980         gl_debug (DEBUG_LABEL, "END");
981 }
982
983
984 /*****************************************************************************/
985 /* Automatically shrink text size to fit within horizontal width.            */
986 /*****************************************************************************/
987 static gdouble
988 auto_shrink_font_size (cairo_t     *cr,
989                        gchar       *family,
990                        gdouble      size,
991                        PangoWeight  weight,
992                        PangoStyle   style,
993                        gchar       *text,
994                        gdouble      width)
995 {
996         PangoLayout          *layout;
997         PangoFontDescription *desc;
998         gint                  iw, ih;
999         gdouble               layout_width;
1000         gdouble               new_size;
1001
1002         layout = pango_cairo_create_layout (cr);
1003
1004         desc = pango_font_description_new ();
1005         pango_font_description_set_family (desc, family);
1006         pango_font_description_set_weight (desc, weight);
1007         pango_font_description_set_style  (desc, style);
1008         pango_font_description_set_size   (desc, size * PANGO_SCALE);
1009         
1010         pango_layout_set_font_description (layout, desc);
1011         pango_font_description_free       (desc);
1012
1013         pango_layout_set_text (layout, text, -1);
1014         pango_layout_set_width (layout, -1);
1015         pango_layout_get_size (layout, &iw, &ih);
1016         layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
1017
1018         g_object_unref (layout);
1019
1020         g_print ("Object w = %g, layout w = %g\n", width, layout_width);
1021
1022         if ( layout_width > width )
1023         {
1024                 /* Scale down. */
1025                 new_size = size * (width-2*GL_LABEL_TEXT_MARGIN)/layout_width;
1026
1027                 /* Round down to nearest 1/2 point */
1028                 new_size = (int)(new_size*2.0) / 2.0;
1029
1030                 /* don't get ridiculously small. */
1031                 if (new_size < 1.0)
1032                 {
1033                         new_size = 1.0;
1034                 }
1035         }
1036         else
1037         {
1038                 new_size = size;
1039         }
1040
1041         return new_size;
1042 }
1043
1044
1045
1046 /*
1047  * Local Variables:       -- emacs
1048  * mode: C                -- emacs
1049  * c-basic-offset: 8      -- emacs
1050  * tab-width: 8           -- emacs
1051  * indent-tabs-mode: nil  -- emacs
1052  * End:                   -- emacs
1053  */