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/gi18n.h>
27 #include <pango/pango.h>
31 #include "font-util.h"
32 #include "font-history.h"
37 /*========================================================*/
38 /* Private macros and constants. */
39 /*========================================================*/
41 #define FONT_SCALE (72.0/96.0)
43 #define HANDLE_OUTLINE_RGBA_ARGS 0.5, 0.5, 0.5, 0.75
44 #define HANDLE_OUTLINE_WIDTH_PIXELS 2.0
46 #define SELECTION_SLOP_PIXELS 4.0
49 /*========================================================*/
51 /*========================================================*/
53 struct _glLabelTextPrivate {
55 GtkTextTagTable *tag_table;
56 GtkTextBuffer *buffer;
60 PangoWeight font_weight;
61 gboolean font_italic_flag;
63 glColorNode *color_node;
67 gboolean size_changed;
71 gboolean checkpoint_flag;
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_begin_user_action_cb (GtkTextBuffer *textbuffer,
92 static void buffer_changed_cb (GtkTextBuffer *textbuffer,
95 static void get_size (glLabelObject *object,
99 static void set_font_family (glLabelObject *object,
100 const gchar *font_family,
101 gboolean checkpoint);
103 static void set_font_size (glLabelObject *object,
105 gboolean checkpoint);
107 static void set_font_weight (glLabelObject *object,
108 PangoWeight font_weight,
109 gboolean checkpoint);
111 static void set_font_italic_flag (glLabelObject *object,
112 gboolean font_italic_flag,
113 gboolean checkpoint);
115 static void set_text_alignment (glLabelObject *object,
116 PangoAlignment text_alignment,
117 gboolean checkpoint);
119 static void set_text_line_spacing (glLabelObject *object,
120 gdouble text_line_spacing,
121 gboolean checkpoint);
123 static void set_text_color (glLabelObject *object,
124 glColorNode *text_color_node,
125 gboolean checkpoint);
127 static gchar *get_font_family (glLabelObject *object);
129 static gdouble get_font_size (glLabelObject *object);
131 static PangoWeight get_font_weight (glLabelObject *object);
133 static gboolean get_font_italic_flag (glLabelObject *object);
135 static PangoAlignment get_text_alignment (glLabelObject *object);
137 static gdouble get_text_line_spacing (glLabelObject *object);
139 static glColorNode* get_text_color (glLabelObject *object);
141 static void set_text_path (glLabelText *this,
143 gboolean screen_flag,
144 glMergeRecord *record);
146 static void draw_object (glLabelObject *object,
148 gboolean screen_flag,
149 glMergeRecord *record);
151 static void draw_shadow (glLabelObject *object,
153 gboolean screen_flag,
154 glMergeRecord *record);
156 static void draw_text_real (glLabelObject *object,
158 gboolean screen_flag,
159 glMergeRecord *record,
162 static gdouble auto_shrink_font_size (cairo_t *cr,
170 static gboolean object_at (glLabelObject *object,
175 static void draw_handles (glLabelObject *object,
179 /*****************************************************************************/
180 /* Object infrastructure. */
181 /*****************************************************************************/
182 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT)
185 /*****************************************************************************/
186 /* Class Init Function. */
187 /*****************************************************************************/
189 gl_label_text_class_init (glLabelTextClass *class)
191 GObjectClass *object_class = G_OBJECT_CLASS (class);
192 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
194 gl_label_text_parent_class = g_type_class_peek_parent (class);
196 label_object_class->copy = copy;
198 label_object_class->get_size = get_size;
200 label_object_class->set_font_family = set_font_family;
201 label_object_class->set_font_size = set_font_size;
202 label_object_class->set_font_weight = set_font_weight;
203 label_object_class->set_font_italic_flag = set_font_italic_flag;
204 label_object_class->set_text_alignment = set_text_alignment;
205 label_object_class->set_text_line_spacing = set_text_line_spacing;
206 label_object_class->set_text_color = set_text_color;
207 label_object_class->get_font_family = get_font_family;
208 label_object_class->get_font_size = get_font_size;
209 label_object_class->get_font_weight = get_font_weight;
210 label_object_class->get_font_italic_flag = get_font_italic_flag;
211 label_object_class->get_text_alignment = get_text_alignment;
212 label_object_class->get_text_line_spacing = get_text_line_spacing;
213 label_object_class->get_text_color = get_text_color;
214 label_object_class->draw_object = draw_object;
215 label_object_class->draw_shadow = draw_shadow;
216 label_object_class->object_at = object_at;
217 label_object_class->draw_handles = draw_handles;
219 object_class->finalize = gl_label_text_finalize;
223 /*****************************************************************************/
224 /* Object Instance Init Function. */
225 /*****************************************************************************/
227 gl_label_text_init (glLabelText *ltext)
229 ltext->priv = g_new0 (glLabelTextPrivate, 1);
231 ltext->priv->tag_table = gtk_text_tag_table_new ();
232 ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
234 ltext->priv->size_changed = TRUE;
236 ltext->priv->checkpoint_flag = TRUE;
238 g_signal_connect (G_OBJECT(ltext->priv->buffer), "begin-user-action",
239 G_CALLBACK(buffer_begin_user_action_cb), ltext);
240 g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
241 G_CALLBACK(buffer_changed_cb), ltext);
245 /*****************************************************************************/
246 /* Finalize Method. */
247 /*****************************************************************************/
249 gl_label_text_finalize (GObject *object)
251 glLabelText *ltext = GL_LABEL_TEXT (object);
253 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
255 g_object_unref (ltext->priv->tag_table);
256 g_object_unref (ltext->priv->buffer);
257 g_free (ltext->priv->font_family);
258 gl_color_node_free (&(ltext->priv->color_node));
259 g_free (ltext->priv);
261 G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
265 /*****************************************************************************/
266 /** New Object Generator. */
267 /*****************************************************************************/
269 gl_label_text_new (glLabel *label,
273 glColorNode *color_node;
275 ltext = g_object_new (gl_label_text_get_type(), NULL);
281 gl_label_checkpoint (label, _("Create text object"));
284 color_node = gl_color_node_new_default ();
286 color_node->color = gl_label_get_default_text_color (label);
288 ltext->priv->font_family = gl_label_get_default_font_family (label);
289 ltext->priv->font_size = gl_label_get_default_font_size (label);
290 ltext->priv->font_weight = gl_label_get_default_font_weight (label);
291 ltext->priv->font_italic_flag = gl_label_get_default_font_italic_flag (label);
292 ltext->priv->align = gl_label_get_default_text_alignment (label);
293 ltext->priv->color_node = color_node;
294 ltext->priv->line_spacing = gl_label_get_default_text_line_spacing (label);
296 gl_label_add_object (label, GL_LABEL_OBJECT (ltext));
297 gl_label_object_set_parent (GL_LABEL_OBJECT (ltext), label);
300 return G_OBJECT (ltext);
304 /*****************************************************************************/
305 /* Copy object contents. */
306 /*****************************************************************************/
308 copy (glLabelObject *dst_object,
309 glLabelObject *src_object)
311 glLabelText *ltext = (glLabelText *)src_object;
312 glLabelText *new_ltext = (glLabelText *)dst_object;
314 glColorNode *text_color_node;
316 gl_debug (DEBUG_LABEL, "START");
318 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
319 g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
321 lines = gl_label_text_get_lines (ltext);
322 text_color_node = get_text_color (src_object);
323 gl_label_text_set_lines (new_ltext, lines, FALSE);
325 new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
326 new_ltext->priv->font_size = ltext->priv->font_size;
327 new_ltext->priv->font_weight = ltext->priv->font_weight;
328 new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
329 set_text_color (dst_object, text_color_node, FALSE);
330 new_ltext->priv->align = ltext->priv->align;
331 new_ltext->priv->line_spacing = ltext->priv->line_spacing;
332 new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
334 new_ltext->priv->size_changed = ltext->priv->size_changed;
335 new_ltext->priv->w = ltext->priv->w;
336 new_ltext->priv->h = ltext->priv->h;
338 gl_color_node_free (&text_color_node);
339 gl_text_node_lines_free (&lines);
341 gl_debug (DEBUG_LABEL, "END");
345 /*****************************************************************************/
346 /* Set object params. */
347 /*****************************************************************************/
349 gl_label_text_set_lines (glLabelText *ltext,
355 gl_debug (DEBUG_LABEL, "START");
357 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
359 ltext->priv->checkpoint_flag = checkpoint;
361 text = gl_text_node_lines_expand (lines, NULL);
362 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
365 ltext->priv->size_changed = TRUE;
367 ltext->priv->checkpoint_flag = TRUE;
369 gl_debug (DEBUG_LABEL, "END");
374 gl_label_text_set_text (glLabelText *ltext,
378 gl_debug (DEBUG_LABEL, "START");
380 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
382 ltext->priv->checkpoint_flag = checkpoint;
384 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
386 ltext->priv->size_changed = TRUE;
388 ltext->priv->checkpoint_flag = TRUE;
390 gl_debug (DEBUG_LABEL, "END");
394 /*****************************************************************************/
395 /* Get object params. */
396 /*****************************************************************************/
398 gl_label_text_get_buffer (glLabelText *ltext)
400 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
402 return ltext->priv->buffer;
407 gl_label_text_get_lines (glLabelText *ltext)
409 GtkTextIter start, end;
413 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
415 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
416 text = gtk_text_buffer_get_text (ltext->priv->buffer,
417 &start, &end, FALSE);
418 lines = gl_text_node_lines_new_from_text (text);
426 gl_label_text_get_text (glLabelText *ltext)
428 GtkTextIter start, end;
431 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
433 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
434 text = gtk_text_buffer_get_text (ltext->priv->buffer,
435 &start, &end, FALSE);
441 /*****************************************************************************/
442 /* Text buffer "changed" callback. */
443 /*****************************************************************************/
445 buffer_begin_user_action_cb (GtkTextBuffer *textbuffer,
450 if ( ltext->priv->checkpoint_flag )
452 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
453 gl_label_checkpoint (label, _("Typing"));
458 /*****************************************************************************/
459 /* Text buffer "changed" callback. */
460 /*****************************************************************************/
462 buffer_changed_cb (GtkTextBuffer *textbuffer,
465 ltext->priv->size_changed = TRUE;
467 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
471 /*****************************************************************************/
472 /* Get object size method. */
473 /*****************************************************************************/
475 get_size (glLabelObject *object,
479 glLabelText *ltext = (glLabelText *)object;
480 PangoFontMap *fontmap;
481 PangoContext *context;
482 cairo_font_options_t *options;
485 PangoFontDescription *desc;
487 gdouble line_spacing;
488 GtkTextIter start, end;
490 gdouble w_parent, h_parent;
493 gl_debug (DEBUG_LABEL, "START");
495 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
497 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
499 if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
505 if (!ltext->priv->size_changed)
512 font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
513 line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
515 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
516 text = gtk_text_buffer_get_text (ltext->priv->buffer,
517 &start, &end, FALSE);
520 fontmap = pango_cairo_font_map_new ();
521 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
522 options = cairo_font_options_create ();
523 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
524 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
525 pango_cairo_context_set_font_options (context, options);
526 cairo_font_options_destroy (options);
528 layout = pango_layout_new (context);
530 style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
532 desc = pango_font_description_new ();
533 pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
534 pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
535 pango_font_description_set_style (desc, style);
536 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
537 pango_layout_set_font_description (layout, desc);
538 pango_font_description_free (desc);
540 pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
541 pango_layout_set_text (layout, text, -1);
542 pango_layout_get_size (layout, &iw, &ih);
543 *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
544 *h = ltext->priv->h = ih / PANGO_SCALE;
545 ltext->priv->size_changed = FALSE;
547 g_object_unref (layout);
548 g_object_unref (context);
549 g_object_unref (fontmap);
552 gl_debug (DEBUG_LABEL, "END");
556 /*****************************************************************************/
557 /* Set font family method. */
558 /*****************************************************************************/
560 set_font_family (glLabelObject *object,
561 const gchar *font_family,
564 glLabelText *ltext = (glLabelText *)object;
565 gchar *good_font_family;
568 gl_debug (DEBUG_LABEL, "START");
570 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
571 g_return_if_fail (font_family);
573 good_font_family = gl_font_util_validate_family (font_family);
575 if (ltext->priv->font_family) {
576 if (strcmp (ltext->priv->font_family, good_font_family) == 0) {
577 g_free (good_font_family);
578 gl_debug (DEBUG_LABEL, "END (no change)");
581 g_free (ltext->priv->font_family);
586 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
587 gl_label_checkpoint (label, _("Font family"));
590 ltext->priv->font_family = g_strdup (good_font_family);
591 g_free (good_font_family);
593 gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
595 ltext->priv->size_changed = TRUE;
597 gl_font_history_model_add_family (gl_font_history, ltext->priv->font_family);
599 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
601 gl_debug (DEBUG_LABEL, "END");
605 /*****************************************************************************/
606 /* Set font size method. */
607 /*****************************************************************************/
609 set_font_size (glLabelObject *object,
613 glLabelText *ltext = (glLabelText *)object;
616 gl_debug (DEBUG_LABEL, "START");
618 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
620 if (ltext->priv->font_size != font_size)
624 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
625 gl_label_checkpoint (label, _("Font size"));
628 ltext->priv->size_changed = TRUE;
630 ltext->priv->font_size = font_size;
631 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
634 gl_debug (DEBUG_LABEL, "END");
638 /*****************************************************************************/
639 /* Set font weight method. */
640 /*****************************************************************************/
642 set_font_weight (glLabelObject *object,
643 PangoWeight font_weight,
646 glLabelText *ltext = (glLabelText *)object;
649 gl_debug (DEBUG_LABEL, "START");
651 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
653 if (ltext->priv->font_weight != font_weight)
657 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
658 gl_label_checkpoint (label, _("Font weight"));
661 ltext->priv->size_changed = TRUE;
663 ltext->priv->font_weight = font_weight;
664 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
667 gl_debug (DEBUG_LABEL, "END");
671 /*****************************************************************************/
672 /* Set font italic flag method. */
673 /*****************************************************************************/
675 set_font_italic_flag (glLabelObject *object,
676 gboolean font_italic_flag,
679 glLabelText *ltext = (glLabelText *)object;
682 gl_debug (DEBUG_LABEL, "START");
684 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
686 if (ltext->priv->font_italic_flag != font_italic_flag)
690 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
691 gl_label_checkpoint (label, _("Italic"));
694 ltext->priv->size_changed = TRUE;
696 ltext->priv->font_italic_flag = font_italic_flag;
697 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
700 gl_debug (DEBUG_LABEL, "END");
704 /*****************************************************************************/
705 /* Set text alignment method. */
706 /*****************************************************************************/
708 set_text_alignment (glLabelObject *object,
709 PangoAlignment text_alignment,
712 glLabelText *ltext = (glLabelText *)object;
715 gl_debug (DEBUG_LABEL, "START");
717 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
719 if (ltext->priv->align != text_alignment)
723 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
724 gl_label_checkpoint (label, _("Align text"));
727 ltext->priv->size_changed = TRUE;
729 ltext->priv->align = text_alignment;
730 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
733 gl_debug (DEBUG_LABEL, "END");
737 /*****************************************************************************/
738 /* Set text line spacing method. */
739 /*****************************************************************************/
741 set_text_line_spacing (glLabelObject *object,
742 gdouble line_spacing,
745 glLabelText *ltext = (glLabelText *)object;
748 gl_debug (DEBUG_LABEL, "START");
750 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
752 if (ltext->priv->line_spacing != line_spacing)
756 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
757 gl_label_checkpoint (label, _("Line spacing"));
760 ltext->priv->size_changed = TRUE;
762 ltext->priv->line_spacing = line_spacing;
763 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
766 gl_debug (DEBUG_LABEL, "END");
770 /*****************************************************************************/
771 /* Set text color method. */
772 /*****************************************************************************/
774 set_text_color (glLabelObject *object,
775 glColorNode *text_color_node,
778 glLabelText *ltext = (glLabelText *)object;
781 gl_debug (DEBUG_LABEL, "START");
783 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
785 if (!gl_color_node_equal (ltext->priv->color_node, text_color_node))
789 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
790 gl_label_checkpoint (label, _("Text color"));
793 gl_color_node_free (&(ltext->priv->color_node));
794 ltext->priv->color_node = gl_color_node_dup (text_color_node);
796 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
799 gl_debug (DEBUG_LABEL, "END");
803 /*****************************************************************************/
804 /* Get font family method. */
805 /*****************************************************************************/
807 get_font_family (glLabelObject *object)
809 glLabelText *ltext = (glLabelText *)object;
811 gl_debug (DEBUG_LABEL, "");
813 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
815 return g_strdup (ltext->priv->font_family);
819 /*****************************************************************************/
820 /* Get font size method. */
821 /*****************************************************************************/
823 get_font_size (glLabelObject *object)
825 glLabelText *ltext = (glLabelText *)object;
827 gl_debug (DEBUG_LABEL, "");
829 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
831 return ltext->priv->font_size;
835 /*****************************************************************************/
836 /* Get font weight method. */
837 /*****************************************************************************/
839 get_font_weight (glLabelObject *object)
841 glLabelText *ltext = (glLabelText *)object;
843 gl_debug (DEBUG_LABEL, "");
845 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
847 return ltext->priv->font_weight;
851 /*****************************************************************************/
852 /* Get font italic flag method. */
853 /*****************************************************************************/
855 get_font_italic_flag (glLabelObject *object)
857 glLabelText *ltext = (glLabelText *)object;
859 gl_debug (DEBUG_LABEL, "");
861 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
863 return ltext->priv->font_italic_flag;
867 /*****************************************************************************/
868 /* Get text alignment method. */
869 /*****************************************************************************/
870 static PangoAlignment
871 get_text_alignment (glLabelObject *object)
873 glLabelText *ltext = (glLabelText *)object;
875 gl_debug (DEBUG_LABEL, "");
877 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
879 return ltext->priv->align;
883 /*****************************************************************************/
884 /* Get text line spacing method. */
885 /*****************************************************************************/
887 get_text_line_spacing (glLabelObject *object)
889 glLabelText *ltext = (glLabelText *)object;
891 gl_debug (DEBUG_LABEL, "");
893 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
895 return ltext->priv->line_spacing;
899 /*****************************************************************************/
900 /* Get text color method. */
901 /*****************************************************************************/
903 get_text_color (glLabelObject *object)
905 glLabelText *ltext = (glLabelText *)object;
907 gl_debug (DEBUG_LABEL, "");
909 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
911 return gl_color_node_dup (ltext->priv->color_node);
915 /*****************************************************************************/
916 /* Set auto shrink flag. */
917 /*****************************************************************************/
919 gl_label_text_set_auto_shrink (glLabelText *ltext,
920 gboolean auto_shrink,
925 gl_debug (DEBUG_LABEL, "BEGIN");
927 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
929 if (ltext->priv->auto_shrink != auto_shrink)
933 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
934 gl_label_checkpoint (label, _("Auto shrink"));
937 ltext->priv->auto_shrink = auto_shrink;
938 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
941 gl_debug (DEBUG_LABEL, "END");
945 /*****************************************************************************/
946 /* Query auto shrink flag. */
947 /*****************************************************************************/
949 gl_label_text_get_auto_shrink (glLabelText *ltext)
951 gl_debug (DEBUG_LABEL, "");
953 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
955 return ltext->priv->auto_shrink;
959 /*****************************************************************************/
960 /* Automatically shrink text size to fit within horizontal width. */
961 /*****************************************************************************/
963 auto_shrink_font_size (cairo_t *cr,
972 PangoFontDescription *desc;
974 gdouble layout_width;
977 layout = pango_cairo_create_layout (cr);
979 desc = pango_font_description_new ();
980 pango_font_description_set_family (desc, family);
981 pango_font_description_set_weight (desc, weight);
982 pango_font_description_set_style (desc, style);
983 pango_font_description_set_size (desc, size * PANGO_SCALE);
985 pango_layout_set_font_description (layout, desc);
986 pango_font_description_free (desc);
988 pango_layout_set_text (layout, text, -1);
989 pango_layout_set_width (layout, -1);
990 pango_layout_get_size (layout, &iw, &ih);
991 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
993 g_object_unref (layout);
995 g_print ("Object w = %g, layout w = %g\n", width, layout_width);
997 if ( layout_width > width )
1000 new_size = size * (width-2*GL_LABEL_TEXT_MARGIN)/layout_width;
1002 /* Round down to nearest 1/2 point */
1003 new_size = (int)(new_size*2.0) / 2.0;
1005 /* don't get ridiculously small. */
1020 /*****************************************************************************/
1021 /* Update pango layout. */
1022 /*****************************************************************************/
1024 set_text_path (glLabelText *this,
1026 gboolean screen_flag,
1027 glMergeRecord *record)
1029 gdouble object_w, object_h;
1030 gdouble raw_w, raw_h;
1034 gboolean auto_shrink;
1035 PangoLayout *layout;
1037 PangoFontDescription *desc;
1038 cairo_font_options_t *font_options;
1039 PangoContext *context;
1042 gl_debug (DEBUG_LABEL, "START");
1046 gl_label_object_get_size (GL_LABEL_OBJECT (this), &object_w, &object_h);
1047 gl_label_object_get_raw_size (GL_LABEL_OBJECT (this), &raw_w, &raw_h);
1049 lines = gl_label_text_get_lines (this);
1050 text = gl_text_node_lines_expand (lines, record);
1052 style = this->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
1054 font_size = this->priv->font_size * FONT_SCALE;
1055 auto_shrink = gl_label_text_get_auto_shrink (this);
1056 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
1058 font_size = auto_shrink_font_size (cr,
1059 this->priv->font_family,
1061 this->priv->font_weight,
1068 layout = pango_cairo_create_layout (cr);
1070 font_options = cairo_font_options_create ();
1071 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
1072 cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
1073 context = pango_layout_get_context (layout);
1074 pango_cairo_context_set_font_options (context, font_options);
1075 cairo_font_options_destroy (font_options);
1077 desc = pango_font_description_new ();
1078 pango_font_description_set_family (desc, this->priv->font_family);
1079 pango_font_description_set_weight (desc, this->priv->font_weight);
1080 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
1081 pango_font_description_set_style (desc, style);
1082 pango_layout_set_font_description (layout, desc);
1083 pango_font_description_free (desc);
1085 pango_layout_set_text (layout, text, -1);
1086 pango_layout_set_spacing (layout, font_size * (this->priv->line_spacing-1) * PANGO_SCALE);
1089 pango_layout_set_width (layout, -1);
1093 pango_layout_set_width (layout, object_w * PANGO_SCALE);
1095 pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
1096 pango_layout_set_alignment (layout, this->priv->align);
1099 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN, 0);
1100 pango_cairo_layout_path (cr, layout);
1102 g_object_unref (layout);
1103 gl_text_node_lines_free (&lines);
1107 gl_debug (DEBUG_LABEL, "END");
1111 /*****************************************************************************/
1112 /* Draw object method. */
1113 /*****************************************************************************/
1115 draw_object (glLabelObject *object,
1117 gboolean screen_flag,
1118 glMergeRecord *record)
1120 glColorNode *color_node;
1123 gl_debug (DEBUG_LABEL, "START");
1125 color_node = gl_label_object_get_text_color (object);
1126 color = gl_color_node_expand (color_node, record);
1127 if (color_node->field_flag && screen_flag)
1129 color = GL_COLOR_MERGE_DEFAULT;
1131 gl_color_node_free (&color_node);
1133 draw_text_real (object, cr, screen_flag, record, color);
1135 gl_debug (DEBUG_LABEL, "END");
1139 /*****************************************************************************/
1140 /* Draw shadow method. */
1141 /*****************************************************************************/
1143 draw_shadow (glLabelObject *object,
1145 gboolean screen_flag,
1146 glMergeRecord *record)
1148 glColorNode *color_node;
1150 glColorNode *shadow_color_node;
1151 gdouble shadow_opacity;
1154 gl_debug (DEBUG_LABEL, "START");
1156 color_node = gl_label_object_get_text_color (object);
1157 color = gl_color_node_expand (color_node, record);
1158 if (color_node->field_flag && screen_flag)
1160 color = GL_COLOR_MERGE_DEFAULT;
1162 gl_color_node_free (&color_node);
1164 shadow_color_node = gl_label_object_get_shadow_color (object);
1165 if (shadow_color_node->field_flag)
1167 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
1169 shadow_opacity = gl_label_object_get_shadow_opacity (object);
1170 shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
1171 gl_color_node_free (&shadow_color_node);
1173 draw_text_real (object, cr, screen_flag, record, shadow_color);
1175 gl_debug (DEBUG_LABEL, "END");
1179 /*****************************************************************************/
1181 /*****************************************************************************/
1183 draw_text_real (glLabelObject *object,
1185 gboolean screen_flag,
1186 glMergeRecord *record,
1189 gl_debug (DEBUG_LABEL, "START");
1191 set_text_path (GL_LABEL_TEXT (object), cr, screen_flag, record);
1193 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
1196 gl_debug (DEBUG_LABEL, "END");
1200 /*****************************************************************************/
1201 /* Is object at coordinates? */
1202 /*****************************************************************************/
1204 object_at (glLabelObject *object,
1210 gdouble scale_x, scale_y;
1212 gl_label_object_get_size (object, &w, &h);
1214 if ( (x >= 0) && (x <= w) && (y >= 0) && (y <= h) )
1216 cairo_new_path (cr);
1217 set_text_path (GL_LABEL_TEXT (object), cr, TRUE, NULL);
1218 if (cairo_in_fill (cr, x, y))
1226 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1228 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1230 if (cairo_in_stroke (cr, x, y))
1236 if (gl_label_object_is_selected (object))
1238 cairo_new_path (cr);
1239 cairo_rectangle (cr, 0, 0, w, h);
1243 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1245 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1247 if (cairo_in_stroke (cr, x, y))
1259 /*****************************************************************************/
1260 /* Draw text style handles. */
1261 /*****************************************************************************/
1263 draw_handles (glLabelObject *object,
1267 gdouble scale_x, scale_y;
1268 gdouble dashes[2] = { 2, 2 };
1270 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1274 cairo_rectangle (cr, 0, 0, w, h);
1278 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1279 cairo_scale (cr, scale_x, scale_y);
1281 cairo_set_dash (cr, dashes, 2, 0);
1282 cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS);
1283 cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
1288 gl_label_object_draw_handles_box (object, cr);
1295 * Local Variables: -- emacs
1297 * c-basic-offset: 8 -- emacs
1298 * tab-width: 8 -- emacs
1299 * indent-tabs-mode: nil -- emacs