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;
64 glColorNode *color_node;
68 gboolean size_changed;
72 gboolean checkpoint_flag;
76 /*========================================================*/
77 /* Private globals. */
78 /*========================================================*/
81 /*========================================================*/
82 /* Private function prototypes. */
83 /*========================================================*/
85 static void gl_label_text_finalize (GObject *object);
87 static void copy (glLabelObject *dst_object,
88 glLabelObject *src_object);
90 static void buffer_begin_user_action_cb (GtkTextBuffer *textbuffer,
93 static void buffer_changed_cb (GtkTextBuffer *textbuffer,
96 static void get_size (glLabelObject *object,
100 static void set_font_family (glLabelObject *object,
101 const gchar *font_family,
102 gboolean checkpoint);
104 static void set_font_size (glLabelObject *object,
106 gboolean checkpoint);
108 static void set_font_weight (glLabelObject *object,
109 PangoWeight font_weight,
110 gboolean checkpoint);
112 static void set_font_italic_flag (glLabelObject *object,
113 gboolean font_italic_flag,
114 gboolean checkpoint);
116 static void set_text_alignment (glLabelObject *object,
117 PangoAlignment text_alignment,
118 gboolean checkpoint);
120 static void set_text_valignment (glLabelObject *object,
121 glValignment text_valignment,
122 gboolean checkpoint);
124 static void set_text_line_spacing (glLabelObject *object,
125 gdouble text_line_spacing,
126 gboolean checkpoint);
128 static void set_text_color (glLabelObject *object,
129 glColorNode *text_color_node,
130 gboolean checkpoint);
132 static gchar *get_font_family (glLabelObject *object);
134 static gdouble get_font_size (glLabelObject *object);
136 static PangoWeight get_font_weight (glLabelObject *object);
138 static gboolean get_font_italic_flag (glLabelObject *object);
140 static PangoAlignment get_text_alignment (glLabelObject *object);
142 static glValignment get_text_valignment (glLabelObject *object);
144 static gdouble get_text_line_spacing (glLabelObject *object);
146 static glColorNode* get_text_color (glLabelObject *object);
148 static void layout_text (glLabelText *this,
150 gboolean screen_flag,
151 glMergeRecord *record,
152 gboolean path_only_flag);
154 static void draw_object (glLabelObject *object,
156 gboolean screen_flag,
157 glMergeRecord *record);
159 static void draw_shadow (glLabelObject *object,
161 gboolean screen_flag,
162 glMergeRecord *record);
164 static void draw_text_real (glLabelObject *object,
166 gboolean screen_flag,
167 glMergeRecord *record,
170 static gdouble auto_shrink_font_size (cairo_t *cr,
175 gdouble line_spacing,
180 static gboolean object_at (glLabelObject *object,
185 static void draw_handles (glLabelObject *object,
189 /*****************************************************************************/
190 /* Object infrastructure. */
191 /*****************************************************************************/
192 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT)
195 /*****************************************************************************/
196 /* Class Init Function. */
197 /*****************************************************************************/
199 gl_label_text_class_init (glLabelTextClass *class)
201 GObjectClass *object_class = G_OBJECT_CLASS (class);
202 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
204 gl_label_text_parent_class = g_type_class_peek_parent (class);
206 label_object_class->copy = copy;
208 label_object_class->get_size = get_size;
210 label_object_class->set_font_family = set_font_family;
211 label_object_class->set_font_size = set_font_size;
212 label_object_class->set_font_weight = set_font_weight;
213 label_object_class->set_font_italic_flag = set_font_italic_flag;
214 label_object_class->set_text_alignment = set_text_alignment;
215 label_object_class->set_text_valignment = set_text_valignment;
216 label_object_class->set_text_line_spacing = set_text_line_spacing;
217 label_object_class->set_text_color = set_text_color;
218 label_object_class->get_font_family = get_font_family;
219 label_object_class->get_font_size = get_font_size;
220 label_object_class->get_font_weight = get_font_weight;
221 label_object_class->get_font_italic_flag = get_font_italic_flag;
222 label_object_class->get_text_alignment = get_text_alignment;
223 label_object_class->get_text_valignment = get_text_valignment;
224 label_object_class->get_text_line_spacing = get_text_line_spacing;
225 label_object_class->get_text_color = get_text_color;
226 label_object_class->draw_object = draw_object;
227 label_object_class->draw_shadow = draw_shadow;
228 label_object_class->object_at = object_at;
229 label_object_class->draw_handles = draw_handles;
231 object_class->finalize = gl_label_text_finalize;
235 /*****************************************************************************/
236 /* Object Instance Init Function. */
237 /*****************************************************************************/
239 gl_label_text_init (glLabelText *ltext)
241 ltext->priv = g_new0 (glLabelTextPrivate, 1);
243 ltext->priv->tag_table = gtk_text_tag_table_new ();
244 ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
246 ltext->priv->size_changed = TRUE;
248 ltext->priv->checkpoint_flag = TRUE;
250 g_signal_connect (G_OBJECT(ltext->priv->buffer), "begin-user-action",
251 G_CALLBACK(buffer_begin_user_action_cb), ltext);
252 g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
253 G_CALLBACK(buffer_changed_cb), ltext);
257 /*****************************************************************************/
258 /* Finalize Method. */
259 /*****************************************************************************/
261 gl_label_text_finalize (GObject *object)
263 glLabelText *ltext = GL_LABEL_TEXT (object);
265 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
267 g_object_unref (ltext->priv->tag_table);
268 g_object_unref (ltext->priv->buffer);
269 g_free (ltext->priv->font_family);
270 gl_color_node_free (&(ltext->priv->color_node));
271 g_free (ltext->priv);
273 G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
277 /*****************************************************************************/
278 /** New Object Generator. */
279 /*****************************************************************************/
281 gl_label_text_new (glLabel *label,
285 glColorNode *color_node;
287 ltext = g_object_new (gl_label_text_get_type(), NULL);
293 gl_label_checkpoint (label, _("Create text object"));
296 color_node = gl_color_node_new_default ();
298 color_node->color = gl_label_get_default_text_color (label);
300 ltext->priv->font_family = gl_label_get_default_font_family (label);
301 ltext->priv->font_size = gl_label_get_default_font_size (label);
302 ltext->priv->font_weight = gl_label_get_default_font_weight (label);
303 ltext->priv->font_italic_flag = gl_label_get_default_font_italic_flag (label);
304 ltext->priv->align = gl_label_get_default_text_alignment (label);
305 ltext->priv->valign = gl_label_get_default_text_valignment (label);
306 ltext->priv->color_node = color_node;
307 ltext->priv->line_spacing = gl_label_get_default_text_line_spacing (label);
309 gl_label_add_object (label, GL_LABEL_OBJECT (ltext));
310 gl_label_object_set_parent (GL_LABEL_OBJECT (ltext), label);
313 return G_OBJECT (ltext);
317 /*****************************************************************************/
318 /* Copy object contents. */
319 /*****************************************************************************/
321 copy (glLabelObject *dst_object,
322 glLabelObject *src_object)
324 glLabelText *ltext = (glLabelText *)src_object;
325 glLabelText *new_ltext = (glLabelText *)dst_object;
327 glColorNode *text_color_node;
329 gl_debug (DEBUG_LABEL, "START");
331 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
332 g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
334 lines = gl_label_text_get_lines (ltext);
335 text_color_node = get_text_color (src_object);
336 gl_label_text_set_lines (new_ltext, lines, FALSE);
338 new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
339 new_ltext->priv->font_size = ltext->priv->font_size;
340 new_ltext->priv->font_weight = ltext->priv->font_weight;
341 new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
342 set_text_color (dst_object, text_color_node, FALSE);
343 new_ltext->priv->align = ltext->priv->align;
344 new_ltext->priv->valign = ltext->priv->valign;
345 new_ltext->priv->line_spacing = ltext->priv->line_spacing;
346 new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
348 new_ltext->priv->size_changed = ltext->priv->size_changed;
349 new_ltext->priv->w = ltext->priv->w;
350 new_ltext->priv->h = ltext->priv->h;
352 gl_color_node_free (&text_color_node);
353 gl_text_node_lines_free (&lines);
355 gl_debug (DEBUG_LABEL, "END");
359 /*****************************************************************************/
360 /* Set object params. */
361 /*****************************************************************************/
363 gl_label_text_set_lines (glLabelText *ltext,
369 gl_debug (DEBUG_LABEL, "START");
371 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
373 ltext->priv->checkpoint_flag = checkpoint;
375 text = gl_text_node_lines_expand (lines, NULL);
376 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
379 ltext->priv->size_changed = TRUE;
381 ltext->priv->checkpoint_flag = TRUE;
383 gl_debug (DEBUG_LABEL, "END");
388 gl_label_text_set_text (glLabelText *ltext,
392 gl_debug (DEBUG_LABEL, "START");
394 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
396 ltext->priv->checkpoint_flag = checkpoint;
398 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
400 ltext->priv->size_changed = TRUE;
402 ltext->priv->checkpoint_flag = TRUE;
404 gl_debug (DEBUG_LABEL, "END");
408 /*****************************************************************************/
409 /* Get object params. */
410 /*****************************************************************************/
412 gl_label_text_get_buffer (glLabelText *ltext)
414 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
416 return ltext->priv->buffer;
421 gl_label_text_get_lines (glLabelText *ltext)
423 GtkTextIter start, end;
427 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
429 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
430 text = gtk_text_buffer_get_text (ltext->priv->buffer,
431 &start, &end, FALSE);
432 lines = gl_text_node_lines_new_from_text (text);
440 gl_label_text_get_text (glLabelText *ltext)
442 GtkTextIter start, end;
445 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
447 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
448 text = gtk_text_buffer_get_text (ltext->priv->buffer,
449 &start, &end, FALSE);
455 /*****************************************************************************/
456 /* Text buffer "changed" callback. */
457 /*****************************************************************************/
459 buffer_begin_user_action_cb (GtkTextBuffer *textbuffer,
464 if ( ltext->priv->checkpoint_flag )
466 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
467 gl_label_checkpoint (label, _("Typing"));
472 /*****************************************************************************/
473 /* Text buffer "changed" callback. */
474 /*****************************************************************************/
476 buffer_changed_cb (GtkTextBuffer *textbuffer,
479 ltext->priv->size_changed = TRUE;
481 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
485 /*****************************************************************************/
486 /* Get object size method. */
487 /*****************************************************************************/
489 get_size (glLabelObject *object,
493 glLabelText *ltext = (glLabelText *)object;
494 PangoFontMap *fontmap;
495 PangoContext *context;
496 cairo_font_options_t *options;
499 PangoFontDescription *desc;
501 gdouble line_spacing;
502 GtkTextIter start, end;
504 gdouble w_parent, h_parent;
507 gl_debug (DEBUG_LABEL, "START");
509 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
511 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
513 if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
519 if (!ltext->priv->size_changed)
526 font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
527 line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
529 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
530 text = gtk_text_buffer_get_text (ltext->priv->buffer,
531 &start, &end, FALSE);
534 fontmap = pango_cairo_font_map_new ();
535 context = pango_font_map_create_context (PANGO_FONT_MAP (fontmap));
536 options = cairo_font_options_create ();
537 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
538 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
539 pango_cairo_context_set_font_options (context, options);
540 cairo_font_options_destroy (options);
542 layout = pango_layout_new (context);
544 style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
546 desc = pango_font_description_new ();
547 pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
548 pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
549 pango_font_description_set_style (desc, style);
550 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
551 pango_layout_set_font_description (layout, desc);
552 pango_font_description_free (desc);
554 pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
555 pango_layout_set_text (layout, text, -1);
556 pango_layout_get_size (layout, &iw, &ih);
557 *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
558 *h = ltext->priv->h = ih / PANGO_SCALE;
559 ltext->priv->size_changed = FALSE;
561 g_object_unref (layout);
562 g_object_unref (context);
563 g_object_unref (fontmap);
566 gl_debug (DEBUG_LABEL, "END");
570 /*****************************************************************************/
571 /* Set font family method. */
572 /*****************************************************************************/
574 set_font_family (glLabelObject *object,
575 const gchar *font_family,
578 glLabelText *ltext = (glLabelText *)object;
579 gchar *good_font_family;
582 gl_debug (DEBUG_LABEL, "START");
584 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
585 g_return_if_fail (font_family);
587 good_font_family = gl_font_util_validate_family (font_family);
589 if (ltext->priv->font_family) {
590 if (strcmp (ltext->priv->font_family, good_font_family) == 0) {
591 g_free (good_font_family);
592 gl_debug (DEBUG_LABEL, "END (no change)");
595 g_free (ltext->priv->font_family);
600 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
601 gl_label_checkpoint (label, _("Font family"));
604 ltext->priv->font_family = g_strdup (good_font_family);
605 g_free (good_font_family);
607 gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
609 ltext->priv->size_changed = TRUE;
611 gl_font_history_model_add_family (gl_font_history, ltext->priv->font_family);
613 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
615 gl_debug (DEBUG_LABEL, "END");
619 /*****************************************************************************/
620 /* Set font size method. */
621 /*****************************************************************************/
623 set_font_size (glLabelObject *object,
627 glLabelText *ltext = (glLabelText *)object;
630 gl_debug (DEBUG_LABEL, "START");
632 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
634 if (ltext->priv->font_size != font_size)
638 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
639 gl_label_checkpoint (label, _("Font size"));
642 ltext->priv->size_changed = TRUE;
644 ltext->priv->font_size = font_size;
645 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
648 gl_debug (DEBUG_LABEL, "END");
652 /*****************************************************************************/
653 /* Set font weight method. */
654 /*****************************************************************************/
656 set_font_weight (glLabelObject *object,
657 PangoWeight font_weight,
660 glLabelText *ltext = (glLabelText *)object;
663 gl_debug (DEBUG_LABEL, "START");
665 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
667 if (ltext->priv->font_weight != font_weight)
671 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
672 gl_label_checkpoint (label, _("Font weight"));
675 ltext->priv->size_changed = TRUE;
677 ltext->priv->font_weight = font_weight;
678 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
681 gl_debug (DEBUG_LABEL, "END");
685 /*****************************************************************************/
686 /* Set font italic flag method. */
687 /*****************************************************************************/
689 set_font_italic_flag (glLabelObject *object,
690 gboolean font_italic_flag,
693 glLabelText *ltext = (glLabelText *)object;
696 gl_debug (DEBUG_LABEL, "START");
698 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
700 if (ltext->priv->font_italic_flag != font_italic_flag)
704 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
705 gl_label_checkpoint (label, _("Italic"));
708 ltext->priv->size_changed = TRUE;
710 ltext->priv->font_italic_flag = font_italic_flag;
711 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
714 gl_debug (DEBUG_LABEL, "END");
718 /*****************************************************************************/
719 /* Set text alignment method. */
720 /*****************************************************************************/
722 set_text_alignment (glLabelObject *object,
723 PangoAlignment text_alignment,
726 glLabelText *ltext = (glLabelText *)object;
729 gl_debug (DEBUG_LABEL, "START");
731 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
733 if (ltext->priv->align != text_alignment)
737 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
738 gl_label_checkpoint (label, _("Align text"));
741 ltext->priv->size_changed = TRUE;
743 ltext->priv->align = text_alignment;
744 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
747 gl_debug (DEBUG_LABEL, "END");
751 /*****************************************************************************/
752 /* Set vertical text alignment method. */
753 /*****************************************************************************/
755 set_text_valignment (glLabelObject *object,
756 glValignment text_valignment,
759 glLabelText *ltext = (glLabelText *)object;
762 gl_debug (DEBUG_LABEL, "START");
764 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
766 if (ltext->priv->valign != text_valignment)
770 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
771 gl_label_checkpoint (label, _("Vertically align text"));
774 ltext->priv->size_changed = TRUE;
776 ltext->priv->valign = text_valignment;
777 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
780 gl_debug (DEBUG_LABEL, "END");
784 /*****************************************************************************/
785 /* Set text line spacing method. */
786 /*****************************************************************************/
788 set_text_line_spacing (glLabelObject *object,
789 gdouble line_spacing,
792 glLabelText *ltext = (glLabelText *)object;
795 gl_debug (DEBUG_LABEL, "START");
797 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
799 if (ltext->priv->line_spacing != line_spacing)
803 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
804 gl_label_checkpoint (label, _("Line spacing"));
807 ltext->priv->size_changed = TRUE;
809 ltext->priv->line_spacing = line_spacing;
810 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
813 gl_debug (DEBUG_LABEL, "END");
817 /*****************************************************************************/
818 /* Set text color method. */
819 /*****************************************************************************/
821 set_text_color (glLabelObject *object,
822 glColorNode *text_color_node,
825 glLabelText *ltext = (glLabelText *)object;
828 gl_debug (DEBUG_LABEL, "START");
830 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
832 if (!gl_color_node_equal (ltext->priv->color_node, text_color_node))
836 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
837 gl_label_checkpoint (label, _("Text color"));
840 gl_color_node_free (&(ltext->priv->color_node));
841 ltext->priv->color_node = gl_color_node_dup (text_color_node);
843 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
846 gl_debug (DEBUG_LABEL, "END");
850 /*****************************************************************************/
851 /* Get font family method. */
852 /*****************************************************************************/
854 get_font_family (glLabelObject *object)
856 glLabelText *ltext = (glLabelText *)object;
858 gl_debug (DEBUG_LABEL, "");
860 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
862 return g_strdup (ltext->priv->font_family);
866 /*****************************************************************************/
867 /* Get font size method. */
868 /*****************************************************************************/
870 get_font_size (glLabelObject *object)
872 glLabelText *ltext = (glLabelText *)object;
874 gl_debug (DEBUG_LABEL, "");
876 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
878 return ltext->priv->font_size;
882 /*****************************************************************************/
883 /* Get font weight method. */
884 /*****************************************************************************/
886 get_font_weight (glLabelObject *object)
888 glLabelText *ltext = (glLabelText *)object;
890 gl_debug (DEBUG_LABEL, "");
892 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
894 return ltext->priv->font_weight;
898 /*****************************************************************************/
899 /* Get font italic flag method. */
900 /*****************************************************************************/
902 get_font_italic_flag (glLabelObject *object)
904 glLabelText *ltext = (glLabelText *)object;
906 gl_debug (DEBUG_LABEL, "");
908 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
910 return ltext->priv->font_italic_flag;
914 /*****************************************************************************/
915 /* Get text alignment method. */
916 /*****************************************************************************/
917 static PangoAlignment
918 get_text_alignment (glLabelObject *object)
920 glLabelText *ltext = (glLabelText *)object;
922 gl_debug (DEBUG_LABEL, "");
924 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
926 return ltext->priv->align;
930 /*****************************************************************************/
931 /* Get vertical text alignment method. */
932 /*****************************************************************************/
934 get_text_valignment (glLabelObject *object)
936 glLabelText *ltext = (glLabelText *)object;
938 gl_debug (DEBUG_LABEL, "");
940 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
942 return ltext->priv->valign;
946 /*****************************************************************************/
947 /* Get text line spacing method. */
948 /*****************************************************************************/
950 get_text_line_spacing (glLabelObject *object)
952 glLabelText *ltext = (glLabelText *)object;
954 gl_debug (DEBUG_LABEL, "");
956 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
958 return ltext->priv->line_spacing;
962 /*****************************************************************************/
963 /* Get text color method. */
964 /*****************************************************************************/
966 get_text_color (glLabelObject *object)
968 glLabelText *ltext = (glLabelText *)object;
970 gl_debug (DEBUG_LABEL, "");
972 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
974 return gl_color_node_dup (ltext->priv->color_node);
978 /*****************************************************************************/
979 /* Set auto shrink flag. */
980 /*****************************************************************************/
982 gl_label_text_set_auto_shrink (glLabelText *ltext,
983 gboolean auto_shrink,
988 gl_debug (DEBUG_LABEL, "BEGIN");
990 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
992 if (ltext->priv->auto_shrink != auto_shrink)
996 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
997 gl_label_checkpoint (label, _("Auto shrink"));
1000 ltext->priv->auto_shrink = auto_shrink;
1001 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
1004 gl_debug (DEBUG_LABEL, "END");
1008 /*****************************************************************************/
1009 /* Query auto shrink flag. */
1010 /*****************************************************************************/
1012 gl_label_text_get_auto_shrink (glLabelText *ltext)
1014 gl_debug (DEBUG_LABEL, "");
1016 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
1018 return ltext->priv->auto_shrink;
1022 /*****************************************************************************/
1023 /* Automatically shrink text size to fit within bounding box. */
1024 /*****************************************************************************/
1026 auto_shrink_font_size (cairo_t *cr,
1031 gdouble line_spacing,
1036 PangoLayout *layout;
1037 PangoFontDescription *desc;
1039 gdouble layout_width, layout_height;
1040 gdouble new_wsize, new_hsize;
1042 layout = pango_cairo_create_layout (cr);
1044 desc = pango_font_description_new ();
1045 pango_font_description_set_family (desc, family);
1046 pango_font_description_set_weight (desc, weight);
1047 pango_font_description_set_style (desc, style);
1048 pango_font_description_set_size (desc, size * PANGO_SCALE);
1050 pango_layout_set_font_description (layout, desc);
1051 pango_font_description_free (desc);
1053 pango_layout_set_spacing (layout, size * (line_spacing-1) * PANGO_SCALE);
1054 pango_layout_set_width (layout, -1);
1055 pango_layout_set_text (layout, text, -1);
1056 pango_layout_get_size (layout, &iw, &ih);
1057 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
1058 layout_height = (gdouble)ih / (gdouble)PANGO_SCALE;
1060 g_object_unref (layout);
1062 g_print ("Object w = %g, layout w = %g\n", width, layout_width);
1063 g_print ("Object h = %g, layout h = %g\n", height, layout_height);
1065 new_wsize = new_hsize = size;
1066 if ( layout_width > width )
1069 new_wsize = size * (width-2*GL_LABEL_TEXT_MARGIN) / layout_width;
1071 /* Round down to nearest 1/2 point */
1072 new_wsize = (int)(new_wsize*2.0) / 2.0;
1074 /* don't get ridiculously small. */
1075 if (new_wsize < 1.0)
1081 if ( layout_height > height )
1084 new_hsize = size * height / layout_height;
1086 /* Round down to nearest 1/2 point */
1087 new_hsize = (int)(new_hsize*2.0) / 2.0;
1089 /* don't get ridiculously small. */
1090 if (new_hsize < 1.0)
1096 return (new_wsize < new_hsize ? new_wsize : new_hsize);
1100 /*****************************************************************************/
1101 /* Update pango layout. */
1102 /*****************************************************************************/
1104 layout_text (glLabelText *this,
1106 gboolean screen_flag,
1107 glMergeRecord *record,
1108 gboolean path_only_flag)
1111 gdouble object_w, object_h;
1112 gdouble raw_w, raw_h;
1116 gboolean auto_shrink;
1117 PangoLayout *layout;
1119 PangoFontDescription *desc;
1120 gdouble scale_x, scale_y;
1121 cairo_font_options_t *font_options;
1122 PangoContext *context;
1125 gl_debug (DEBUG_LABEL, "START");
1128 * Workaround for pango Bug#700592, which is a regression of Bug#341481.
1129 * Render font at device scale and scale font size accordingly.
1133 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1134 scale_x = fabs (scale_x);
1135 scale_y = fabs (scale_y);
1137 cairo_scale (cr, scale_x, scale_y);
1139 gl_label_object_get_size (GL_LABEL_OBJECT (this), &object_w, &object_h);
1140 gl_label_object_get_raw_size (GL_LABEL_OBJECT (this), &raw_w, &raw_h);
1142 lines = gl_label_text_get_lines (this);
1143 text = gl_text_node_lines_expand (lines, record);
1145 style = this->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
1147 font_size = this->priv->font_size * FONT_SCALE;
1148 auto_shrink = gl_label_text_get_auto_shrink (this);
1149 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
1151 font_size = auto_shrink_font_size (cr,
1152 this->priv->font_family,
1154 this->priv->font_weight,
1156 this->priv->line_spacing,
1163 layout = pango_cairo_create_layout (cr);
1165 font_options = cairo_font_options_create ();
1166 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
1167 cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
1168 context = pango_layout_get_context (layout);
1169 pango_cairo_context_set_font_options (context, font_options);
1170 cairo_font_options_destroy (font_options);
1172 desc = pango_font_description_new ();
1173 pango_font_description_set_family (desc, this->priv->font_family);
1174 pango_font_description_set_weight (desc, this->priv->font_weight);
1175 pango_font_description_set_size (desc, font_size * PANGO_SCALE / scale_x);
1176 pango_font_description_set_style (desc, style);
1177 pango_layout_set_font_description (layout, desc);
1178 pango_font_description_free (desc);
1180 pango_layout_set_text (layout, text, -1);
1181 pango_layout_set_spacing (layout, font_size * (this->priv->line_spacing-1) * PANGO_SCALE / scale_x);
1184 pango_layout_set_width (layout, -1);
1188 pango_layout_set_width (layout, (object_w - 2*GL_LABEL_TEXT_MARGIN) * PANGO_SCALE / scale_x);
1190 pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
1191 pango_layout_set_alignment (layout, this->priv->align);
1192 pango_layout_get_pixel_size (layout, &iw, &ih);
1194 switch (this->priv->valign)
1196 case GL_VALIGN_VCENTER:
1197 y = (object_h/scale_x - ih) / 2;
1199 case GL_VALIGN_BOTTOM:
1200 y = object_h/scale_x - ih;
1207 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, y);
1208 if ( path_only_flag )
1210 pango_cairo_layout_path (cr, layout);
1214 pango_cairo_show_layout (cr, layout);
1217 g_object_unref (layout);
1218 gl_text_node_lines_free (&lines);
1222 gl_debug (DEBUG_LABEL, "END");
1226 /*****************************************************************************/
1227 /* Draw object method. */
1228 /*****************************************************************************/
1230 draw_object (glLabelObject *object,
1232 gboolean screen_flag,
1233 glMergeRecord *record)
1235 glColorNode *color_node;
1238 gl_debug (DEBUG_LABEL, "START");
1240 color_node = gl_label_object_get_text_color (object);
1241 color = gl_color_node_expand (color_node, record);
1242 if (color_node->field_flag && screen_flag)
1244 color = GL_COLOR_MERGE_DEFAULT;
1246 gl_color_node_free (&color_node);
1248 draw_text_real (object, cr, screen_flag, record, color);
1250 gl_debug (DEBUG_LABEL, "END");
1254 /*****************************************************************************/
1255 /* Draw shadow method. */
1256 /*****************************************************************************/
1258 draw_shadow (glLabelObject *object,
1260 gboolean screen_flag,
1261 glMergeRecord *record)
1263 glColorNode *color_node;
1265 glColorNode *shadow_color_node;
1266 gdouble shadow_opacity;
1269 gl_debug (DEBUG_LABEL, "START");
1271 color_node = gl_label_object_get_text_color (object);
1272 color = gl_color_node_expand (color_node, record);
1273 if (color_node->field_flag && screen_flag)
1275 color = GL_COLOR_MERGE_DEFAULT;
1277 gl_color_node_free (&color_node);
1279 shadow_color_node = gl_label_object_get_shadow_color (object);
1280 if (shadow_color_node->field_flag)
1282 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
1284 shadow_opacity = gl_label_object_get_shadow_opacity (object);
1285 shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
1286 gl_color_node_free (&shadow_color_node);
1288 draw_text_real (object, cr, screen_flag, record, shadow_color);
1290 gl_debug (DEBUG_LABEL, "END");
1294 /*****************************************************************************/
1296 /*****************************************************************************/
1298 draw_text_real (glLabelObject *object,
1300 gboolean screen_flag,
1301 glMergeRecord *record,
1304 gl_debug (DEBUG_LABEL, "START");
1306 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
1307 layout_text (GL_LABEL_TEXT (object), cr, screen_flag, record, FALSE);
1309 gl_debug (DEBUG_LABEL, "END");
1313 /*****************************************************************************/
1314 /* Is object at coordinates? */
1315 /*****************************************************************************/
1317 object_at (glLabelObject *object,
1323 gdouble scale_x, scale_y;
1325 gl_label_object_get_size (object, &w, &h);
1327 if ( (x >= 0) && (x <= w) && (y >= 0) && (y <= h) )
1329 cairo_new_path (cr);
1330 layout_text (GL_LABEL_TEXT (object), cr, TRUE, NULL, TRUE);
1331 if (cairo_in_fill (cr, x, y))
1339 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1341 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1343 if (cairo_in_stroke (cr, x, y))
1349 if (gl_label_object_is_selected (object))
1351 cairo_new_path (cr);
1352 cairo_rectangle (cr, 0, 0, w, h);
1356 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1358 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1360 if (cairo_in_stroke (cr, x, y))
1372 /*****************************************************************************/
1373 /* Draw text style handles. */
1374 /*****************************************************************************/
1376 draw_handles (glLabelObject *object,
1380 gdouble scale_x, scale_y;
1381 gdouble dashes[2] = { 2, 2 };
1383 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1387 cairo_rectangle (cr, 0, 0, w, h);
1391 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1392 cairo_scale (cr, scale_x, scale_y);
1394 cairo_set_dash (cr, dashes, 2, 0);
1395 cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS);
1396 cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
1401 gl_label_object_draw_handles_box (object, cr);
1408 * Local Variables: -- emacs
1410 * c-basic-offset: 8 -- emacs
1411 * tab-width: 8 -- emacs
1412 * indent-tabs-mode: nil -- emacs