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 set_text_path (glLabelText *this,
150 gboolean screen_flag,
151 glMergeRecord *record);
153 static void draw_object (glLabelObject *object,
155 gboolean screen_flag,
156 glMergeRecord *record);
158 static void draw_shadow (glLabelObject *object,
160 gboolean screen_flag,
161 glMergeRecord *record);
163 static void draw_text_real (glLabelObject *object,
165 gboolean screen_flag,
166 glMergeRecord *record,
169 static gdouble auto_shrink_font_size (cairo_t *cr,
174 gdouble line_spacing,
179 static gboolean object_at (glLabelObject *object,
184 static void draw_handles (glLabelObject *object,
188 /*****************************************************************************/
189 /* Object infrastructure. */
190 /*****************************************************************************/
191 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT)
194 /*****************************************************************************/
195 /* Class Init Function. */
196 /*****************************************************************************/
198 gl_label_text_class_init (glLabelTextClass *class)
200 GObjectClass *object_class = G_OBJECT_CLASS (class);
201 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
203 gl_label_text_parent_class = g_type_class_peek_parent (class);
205 label_object_class->copy = copy;
207 label_object_class->get_size = get_size;
209 label_object_class->set_font_family = set_font_family;
210 label_object_class->set_font_size = set_font_size;
211 label_object_class->set_font_weight = set_font_weight;
212 label_object_class->set_font_italic_flag = set_font_italic_flag;
213 label_object_class->set_text_alignment = set_text_alignment;
214 label_object_class->set_text_valignment = set_text_valignment;
215 label_object_class->set_text_line_spacing = set_text_line_spacing;
216 label_object_class->set_text_color = set_text_color;
217 label_object_class->get_font_family = get_font_family;
218 label_object_class->get_font_size = get_font_size;
219 label_object_class->get_font_weight = get_font_weight;
220 label_object_class->get_font_italic_flag = get_font_italic_flag;
221 label_object_class->get_text_alignment = get_text_alignment;
222 label_object_class->get_text_valignment = get_text_valignment;
223 label_object_class->get_text_line_spacing = get_text_line_spacing;
224 label_object_class->get_text_color = get_text_color;
225 label_object_class->draw_object = draw_object;
226 label_object_class->draw_shadow = draw_shadow;
227 label_object_class->object_at = object_at;
228 label_object_class->draw_handles = draw_handles;
230 object_class->finalize = gl_label_text_finalize;
234 /*****************************************************************************/
235 /* Object Instance Init Function. */
236 /*****************************************************************************/
238 gl_label_text_init (glLabelText *ltext)
240 ltext->priv = g_new0 (glLabelTextPrivate, 1);
242 ltext->priv->tag_table = gtk_text_tag_table_new ();
243 ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
245 ltext->priv->size_changed = TRUE;
247 ltext->priv->checkpoint_flag = TRUE;
249 g_signal_connect (G_OBJECT(ltext->priv->buffer), "begin-user-action",
250 G_CALLBACK(buffer_begin_user_action_cb), ltext);
251 g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
252 G_CALLBACK(buffer_changed_cb), ltext);
256 /*****************************************************************************/
257 /* Finalize Method. */
258 /*****************************************************************************/
260 gl_label_text_finalize (GObject *object)
262 glLabelText *ltext = GL_LABEL_TEXT (object);
264 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
266 g_object_unref (ltext->priv->tag_table);
267 g_object_unref (ltext->priv->buffer);
268 g_free (ltext->priv->font_family);
269 gl_color_node_free (&(ltext->priv->color_node));
270 g_free (ltext->priv);
272 G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
276 /*****************************************************************************/
277 /** New Object Generator. */
278 /*****************************************************************************/
280 gl_label_text_new (glLabel *label,
284 glColorNode *color_node;
286 ltext = g_object_new (gl_label_text_get_type(), NULL);
292 gl_label_checkpoint (label, _("Create text object"));
295 color_node = gl_color_node_new_default ();
297 color_node->color = gl_label_get_default_text_color (label);
299 ltext->priv->font_family = gl_label_get_default_font_family (label);
300 ltext->priv->font_size = gl_label_get_default_font_size (label);
301 ltext->priv->font_weight = gl_label_get_default_font_weight (label);
302 ltext->priv->font_italic_flag = gl_label_get_default_font_italic_flag (label);
303 ltext->priv->align = gl_label_get_default_text_alignment (label);
304 ltext->priv->valign = gl_label_get_default_text_valignment (label);
305 ltext->priv->color_node = color_node;
306 ltext->priv->line_spacing = gl_label_get_default_text_line_spacing (label);
308 gl_label_add_object (label, GL_LABEL_OBJECT (ltext));
309 gl_label_object_set_parent (GL_LABEL_OBJECT (ltext), label);
312 return G_OBJECT (ltext);
316 /*****************************************************************************/
317 /* Copy object contents. */
318 /*****************************************************************************/
320 copy (glLabelObject *dst_object,
321 glLabelObject *src_object)
323 glLabelText *ltext = (glLabelText *)src_object;
324 glLabelText *new_ltext = (glLabelText *)dst_object;
326 glColorNode *text_color_node;
328 gl_debug (DEBUG_LABEL, "START");
330 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
331 g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
333 lines = gl_label_text_get_lines (ltext);
334 text_color_node = get_text_color (src_object);
335 gl_label_text_set_lines (new_ltext, lines, FALSE);
337 new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
338 new_ltext->priv->font_size = ltext->priv->font_size;
339 new_ltext->priv->font_weight = ltext->priv->font_weight;
340 new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
341 set_text_color (dst_object, text_color_node, FALSE);
342 new_ltext->priv->align = ltext->priv->align;
343 new_ltext->priv->valign = ltext->priv->valign;
344 new_ltext->priv->line_spacing = ltext->priv->line_spacing;
345 new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
347 new_ltext->priv->size_changed = ltext->priv->size_changed;
348 new_ltext->priv->w = ltext->priv->w;
349 new_ltext->priv->h = ltext->priv->h;
351 gl_color_node_free (&text_color_node);
352 gl_text_node_lines_free (&lines);
354 gl_debug (DEBUG_LABEL, "END");
358 /*****************************************************************************/
359 /* Set object params. */
360 /*****************************************************************************/
362 gl_label_text_set_lines (glLabelText *ltext,
368 gl_debug (DEBUG_LABEL, "START");
370 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
372 ltext->priv->checkpoint_flag = checkpoint;
374 text = gl_text_node_lines_expand (lines, NULL);
375 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
378 ltext->priv->size_changed = TRUE;
380 ltext->priv->checkpoint_flag = TRUE;
382 gl_debug (DEBUG_LABEL, "END");
387 gl_label_text_set_text (glLabelText *ltext,
391 gl_debug (DEBUG_LABEL, "START");
393 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
395 ltext->priv->checkpoint_flag = checkpoint;
397 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
399 ltext->priv->size_changed = TRUE;
401 ltext->priv->checkpoint_flag = TRUE;
403 gl_debug (DEBUG_LABEL, "END");
407 /*****************************************************************************/
408 /* Get object params. */
409 /*****************************************************************************/
411 gl_label_text_get_buffer (glLabelText *ltext)
413 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
415 return ltext->priv->buffer;
420 gl_label_text_get_lines (glLabelText *ltext)
422 GtkTextIter start, end;
426 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
428 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
429 text = gtk_text_buffer_get_text (ltext->priv->buffer,
430 &start, &end, FALSE);
431 lines = gl_text_node_lines_new_from_text (text);
439 gl_label_text_get_text (glLabelText *ltext)
441 GtkTextIter start, end;
444 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
446 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
447 text = gtk_text_buffer_get_text (ltext->priv->buffer,
448 &start, &end, FALSE);
454 /*****************************************************************************/
455 /* Text buffer "changed" callback. */
456 /*****************************************************************************/
458 buffer_begin_user_action_cb (GtkTextBuffer *textbuffer,
463 if ( ltext->priv->checkpoint_flag )
465 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
466 gl_label_checkpoint (label, _("Typing"));
471 /*****************************************************************************/
472 /* Text buffer "changed" callback. */
473 /*****************************************************************************/
475 buffer_changed_cb (GtkTextBuffer *textbuffer,
478 ltext->priv->size_changed = TRUE;
480 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
484 /*****************************************************************************/
485 /* Get object size method. */
486 /*****************************************************************************/
488 get_size (glLabelObject *object,
492 glLabelText *ltext = (glLabelText *)object;
493 PangoFontMap *fontmap;
494 PangoContext *context;
495 cairo_font_options_t *options;
498 PangoFontDescription *desc;
500 gdouble line_spacing;
501 GtkTextIter start, end;
503 gdouble w_parent, h_parent;
506 gl_debug (DEBUG_LABEL, "START");
508 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
510 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
512 if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
518 if (!ltext->priv->size_changed)
525 font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
526 line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
528 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
529 text = gtk_text_buffer_get_text (ltext->priv->buffer,
530 &start, &end, FALSE);
533 fontmap = pango_cairo_font_map_new ();
534 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
535 options = cairo_font_options_create ();
536 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
537 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
538 pango_cairo_context_set_font_options (context, options);
539 cairo_font_options_destroy (options);
541 layout = pango_layout_new (context);
543 style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
545 desc = pango_font_description_new ();
546 pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
547 pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
548 pango_font_description_set_style (desc, style);
549 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
550 pango_layout_set_font_description (layout, desc);
551 pango_font_description_free (desc);
553 pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
554 pango_layout_set_text (layout, text, -1);
555 pango_layout_get_size (layout, &iw, &ih);
556 *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
557 *h = ltext->priv->h = ih / PANGO_SCALE;
558 ltext->priv->size_changed = FALSE;
560 g_object_unref (layout);
561 g_object_unref (context);
562 g_object_unref (fontmap);
565 gl_debug (DEBUG_LABEL, "END");
569 /*****************************************************************************/
570 /* Set font family method. */
571 /*****************************************************************************/
573 set_font_family (glLabelObject *object,
574 const gchar *font_family,
577 glLabelText *ltext = (glLabelText *)object;
578 gchar *good_font_family;
581 gl_debug (DEBUG_LABEL, "START");
583 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
584 g_return_if_fail (font_family);
586 good_font_family = gl_font_util_validate_family (font_family);
588 if (ltext->priv->font_family) {
589 if (strcmp (ltext->priv->font_family, good_font_family) == 0) {
590 g_free (good_font_family);
591 gl_debug (DEBUG_LABEL, "END (no change)");
594 g_free (ltext->priv->font_family);
599 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
600 gl_label_checkpoint (label, _("Font family"));
603 ltext->priv->font_family = g_strdup (good_font_family);
604 g_free (good_font_family);
606 gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
608 ltext->priv->size_changed = TRUE;
610 gl_font_history_model_add_family (gl_font_history, ltext->priv->font_family);
612 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
614 gl_debug (DEBUG_LABEL, "END");
618 /*****************************************************************************/
619 /* Set font size method. */
620 /*****************************************************************************/
622 set_font_size (glLabelObject *object,
626 glLabelText *ltext = (glLabelText *)object;
629 gl_debug (DEBUG_LABEL, "START");
631 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
633 if (ltext->priv->font_size != font_size)
637 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
638 gl_label_checkpoint (label, _("Font size"));
641 ltext->priv->size_changed = TRUE;
643 ltext->priv->font_size = font_size;
644 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
647 gl_debug (DEBUG_LABEL, "END");
651 /*****************************************************************************/
652 /* Set font weight method. */
653 /*****************************************************************************/
655 set_font_weight (glLabelObject *object,
656 PangoWeight font_weight,
659 glLabelText *ltext = (glLabelText *)object;
662 gl_debug (DEBUG_LABEL, "START");
664 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
666 if (ltext->priv->font_weight != font_weight)
670 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
671 gl_label_checkpoint (label, _("Font weight"));
674 ltext->priv->size_changed = TRUE;
676 ltext->priv->font_weight = font_weight;
677 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
680 gl_debug (DEBUG_LABEL, "END");
684 /*****************************************************************************/
685 /* Set font italic flag method. */
686 /*****************************************************************************/
688 set_font_italic_flag (glLabelObject *object,
689 gboolean font_italic_flag,
692 glLabelText *ltext = (glLabelText *)object;
695 gl_debug (DEBUG_LABEL, "START");
697 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
699 if (ltext->priv->font_italic_flag != font_italic_flag)
703 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
704 gl_label_checkpoint (label, _("Italic"));
707 ltext->priv->size_changed = TRUE;
709 ltext->priv->font_italic_flag = font_italic_flag;
710 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
713 gl_debug (DEBUG_LABEL, "END");
717 /*****************************************************************************/
718 /* Set text alignment method. */
719 /*****************************************************************************/
721 set_text_alignment (glLabelObject *object,
722 PangoAlignment text_alignment,
725 glLabelText *ltext = (glLabelText *)object;
728 gl_debug (DEBUG_LABEL, "START");
730 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
732 if (ltext->priv->align != text_alignment)
736 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
737 gl_label_checkpoint (label, _("Align text"));
740 ltext->priv->size_changed = TRUE;
742 ltext->priv->align = text_alignment;
743 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
746 gl_debug (DEBUG_LABEL, "END");
750 /*****************************************************************************/
751 /* Set vertical text alignment method. */
752 /*****************************************************************************/
754 set_text_valignment (glLabelObject *object,
755 glValignment text_valignment,
758 glLabelText *ltext = (glLabelText *)object;
761 gl_debug (DEBUG_LABEL, "START");
763 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
765 if (ltext->priv->valign != text_valignment)
769 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
770 gl_label_checkpoint (label, _("Vertically align text"));
773 ltext->priv->size_changed = TRUE;
775 ltext->priv->valign = text_valignment;
776 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
779 gl_debug (DEBUG_LABEL, "END");
783 /*****************************************************************************/
784 /* Set text line spacing method. */
785 /*****************************************************************************/
787 set_text_line_spacing (glLabelObject *object,
788 gdouble line_spacing,
791 glLabelText *ltext = (glLabelText *)object;
794 gl_debug (DEBUG_LABEL, "START");
796 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
798 if (ltext->priv->line_spacing != line_spacing)
802 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
803 gl_label_checkpoint (label, _("Line spacing"));
806 ltext->priv->size_changed = TRUE;
808 ltext->priv->line_spacing = line_spacing;
809 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
812 gl_debug (DEBUG_LABEL, "END");
816 /*****************************************************************************/
817 /* Set text color method. */
818 /*****************************************************************************/
820 set_text_color (glLabelObject *object,
821 glColorNode *text_color_node,
824 glLabelText *ltext = (glLabelText *)object;
827 gl_debug (DEBUG_LABEL, "START");
829 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
831 if (!gl_color_node_equal (ltext->priv->color_node, text_color_node))
835 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
836 gl_label_checkpoint (label, _("Text color"));
839 gl_color_node_free (&(ltext->priv->color_node));
840 ltext->priv->color_node = gl_color_node_dup (text_color_node);
842 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
845 gl_debug (DEBUG_LABEL, "END");
849 /*****************************************************************************/
850 /* Get font family method. */
851 /*****************************************************************************/
853 get_font_family (glLabelObject *object)
855 glLabelText *ltext = (glLabelText *)object;
857 gl_debug (DEBUG_LABEL, "");
859 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
861 return g_strdup (ltext->priv->font_family);
865 /*****************************************************************************/
866 /* Get font size method. */
867 /*****************************************************************************/
869 get_font_size (glLabelObject *object)
871 glLabelText *ltext = (glLabelText *)object;
873 gl_debug (DEBUG_LABEL, "");
875 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
877 return ltext->priv->font_size;
881 /*****************************************************************************/
882 /* Get font weight method. */
883 /*****************************************************************************/
885 get_font_weight (glLabelObject *object)
887 glLabelText *ltext = (glLabelText *)object;
889 gl_debug (DEBUG_LABEL, "");
891 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
893 return ltext->priv->font_weight;
897 /*****************************************************************************/
898 /* Get font italic flag method. */
899 /*****************************************************************************/
901 get_font_italic_flag (glLabelObject *object)
903 glLabelText *ltext = (glLabelText *)object;
905 gl_debug (DEBUG_LABEL, "");
907 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
909 return ltext->priv->font_italic_flag;
913 /*****************************************************************************/
914 /* Get text alignment method. */
915 /*****************************************************************************/
916 static PangoAlignment
917 get_text_alignment (glLabelObject *object)
919 glLabelText *ltext = (glLabelText *)object;
921 gl_debug (DEBUG_LABEL, "");
923 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
925 return ltext->priv->align;
929 /*****************************************************************************/
930 /* Get vertical text alignment method. */
931 /*****************************************************************************/
933 get_text_valignment (glLabelObject *object)
935 glLabelText *ltext = (glLabelText *)object;
937 gl_debug (DEBUG_LABEL, "");
939 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
941 return ltext->priv->valign;
945 /*****************************************************************************/
946 /* Get text line spacing method. */
947 /*****************************************************************************/
949 get_text_line_spacing (glLabelObject *object)
951 glLabelText *ltext = (glLabelText *)object;
953 gl_debug (DEBUG_LABEL, "");
955 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
957 return ltext->priv->line_spacing;
961 /*****************************************************************************/
962 /* Get text color method. */
963 /*****************************************************************************/
965 get_text_color (glLabelObject *object)
967 glLabelText *ltext = (glLabelText *)object;
969 gl_debug (DEBUG_LABEL, "");
971 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
973 return gl_color_node_dup (ltext->priv->color_node);
977 /*****************************************************************************/
978 /* Set auto shrink flag. */
979 /*****************************************************************************/
981 gl_label_text_set_auto_shrink (glLabelText *ltext,
982 gboolean auto_shrink,
987 gl_debug (DEBUG_LABEL, "BEGIN");
989 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
991 if (ltext->priv->auto_shrink != auto_shrink)
995 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
996 gl_label_checkpoint (label, _("Auto shrink"));
999 ltext->priv->auto_shrink = auto_shrink;
1000 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
1003 gl_debug (DEBUG_LABEL, "END");
1007 /*****************************************************************************/
1008 /* Query auto shrink flag. */
1009 /*****************************************************************************/
1011 gl_label_text_get_auto_shrink (glLabelText *ltext)
1013 gl_debug (DEBUG_LABEL, "");
1015 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
1017 return ltext->priv->auto_shrink;
1021 /*****************************************************************************/
1022 /* Automatically shrink text size to fit within bounding box. */
1023 /*****************************************************************************/
1025 auto_shrink_font_size (cairo_t *cr,
1030 gdouble line_spacing,
1035 PangoLayout *layout;
1036 PangoFontDescription *desc;
1038 gdouble layout_width, layout_height;
1039 gdouble new_wsize, new_hsize;
1041 layout = pango_cairo_create_layout (cr);
1043 desc = pango_font_description_new ();
1044 pango_font_description_set_family (desc, family);
1045 pango_font_description_set_weight (desc, weight);
1046 pango_font_description_set_style (desc, style);
1047 pango_font_description_set_size (desc, size * PANGO_SCALE);
1049 pango_layout_set_font_description (layout, desc);
1050 pango_font_description_free (desc);
1052 pango_layout_set_spacing (layout, size * (line_spacing-1) * PANGO_SCALE);
1053 pango_layout_set_width (layout, -1);
1054 pango_layout_set_text (layout, text, -1);
1055 pango_layout_get_size (layout, &iw, &ih);
1056 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
1057 layout_height = (gdouble)ih / (gdouble)PANGO_SCALE;
1059 g_object_unref (layout);
1061 g_print ("Object w = %g, layout w = %g\n", width, layout_width);
1062 g_print ("Object h = %g, layout h = %g\n", height, layout_height);
1064 new_wsize = new_hsize = size;
1065 if ( layout_width > width )
1068 new_wsize = size * (width-2*GL_LABEL_TEXT_MARGIN) / layout_width;
1070 /* Round down to nearest 1/2 point */
1071 new_wsize = (int)(new_wsize*2.0) / 2.0;
1073 /* don't get ridiculously small. */
1074 if (new_wsize < 1.0)
1080 if ( layout_height > height )
1083 new_hsize = size * height / layout_height;
1085 /* Round down to nearest 1/2 point */
1086 new_hsize = (int)(new_hsize*2.0) / 2.0;
1088 /* don't get ridiculously small. */
1089 if (new_hsize < 1.0)
1095 return (new_wsize < new_hsize ? new_wsize : new_hsize);
1099 /*****************************************************************************/
1100 /* Update pango layout. */
1101 /*****************************************************************************/
1103 set_text_path (glLabelText *this,
1105 gboolean screen_flag,
1106 glMergeRecord *record)
1109 gdouble object_w, object_h;
1110 gdouble raw_w, raw_h;
1114 gboolean auto_shrink;
1115 PangoLayout *layout;
1117 PangoFontDescription *desc;
1118 cairo_font_options_t *font_options;
1119 PangoContext *context;
1122 gl_debug (DEBUG_LABEL, "START");
1126 gl_label_object_get_size (GL_LABEL_OBJECT (this), &object_w, &object_h);
1127 gl_label_object_get_raw_size (GL_LABEL_OBJECT (this), &raw_w, &raw_h);
1129 lines = gl_label_text_get_lines (this);
1130 text = gl_text_node_lines_expand (lines, record);
1132 style = this->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
1134 font_size = this->priv->font_size * FONT_SCALE;
1135 auto_shrink = gl_label_text_get_auto_shrink (this);
1136 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
1138 font_size = auto_shrink_font_size (cr,
1139 this->priv->font_family,
1141 this->priv->font_weight,
1143 this->priv->line_spacing,
1150 layout = pango_cairo_create_layout (cr);
1152 font_options = cairo_font_options_create ();
1153 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
1154 cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
1155 context = pango_layout_get_context (layout);
1156 pango_cairo_context_set_font_options (context, font_options);
1157 cairo_font_options_destroy (font_options);
1159 desc = pango_font_description_new ();
1160 pango_font_description_set_family (desc, this->priv->font_family);
1161 pango_font_description_set_weight (desc, this->priv->font_weight);
1162 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
1163 pango_font_description_set_style (desc, style);
1164 pango_layout_set_font_description (layout, desc);
1165 pango_font_description_free (desc);
1167 pango_layout_set_text (layout, text, -1);
1168 pango_layout_set_spacing (layout, font_size * (this->priv->line_spacing-1) * PANGO_SCALE);
1171 pango_layout_set_width (layout, -1);
1175 pango_layout_set_width (layout, object_w * PANGO_SCALE);
1177 pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
1178 pango_layout_set_alignment (layout, this->priv->align);
1179 pango_layout_get_pixel_size (layout, &iw, &ih);
1181 switch (this->priv->valign)
1183 case GL_VALIGN_VCENTER:
1184 y = (object_h - ih) / 2;
1186 case GL_VALIGN_BOTTOM:
1194 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN, y);
1195 pango_cairo_layout_path (cr, layout);
1197 g_object_unref (layout);
1198 gl_text_node_lines_free (&lines);
1202 gl_debug (DEBUG_LABEL, "END");
1206 /*****************************************************************************/
1207 /* Draw object method. */
1208 /*****************************************************************************/
1210 draw_object (glLabelObject *object,
1212 gboolean screen_flag,
1213 glMergeRecord *record)
1215 glColorNode *color_node;
1218 gl_debug (DEBUG_LABEL, "START");
1220 color_node = gl_label_object_get_text_color (object);
1221 color = gl_color_node_expand (color_node, record);
1222 if (color_node->field_flag && screen_flag)
1224 color = GL_COLOR_MERGE_DEFAULT;
1226 gl_color_node_free (&color_node);
1228 draw_text_real (object, cr, screen_flag, record, color);
1230 gl_debug (DEBUG_LABEL, "END");
1234 /*****************************************************************************/
1235 /* Draw shadow method. */
1236 /*****************************************************************************/
1238 draw_shadow (glLabelObject *object,
1240 gboolean screen_flag,
1241 glMergeRecord *record)
1243 glColorNode *color_node;
1245 glColorNode *shadow_color_node;
1246 gdouble shadow_opacity;
1249 gl_debug (DEBUG_LABEL, "START");
1251 color_node = gl_label_object_get_text_color (object);
1252 color = gl_color_node_expand (color_node, record);
1253 if (color_node->field_flag && screen_flag)
1255 color = GL_COLOR_MERGE_DEFAULT;
1257 gl_color_node_free (&color_node);
1259 shadow_color_node = gl_label_object_get_shadow_color (object);
1260 if (shadow_color_node->field_flag)
1262 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
1264 shadow_opacity = gl_label_object_get_shadow_opacity (object);
1265 shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
1266 gl_color_node_free (&shadow_color_node);
1268 draw_text_real (object, cr, screen_flag, record, shadow_color);
1270 gl_debug (DEBUG_LABEL, "END");
1274 /*****************************************************************************/
1276 /*****************************************************************************/
1278 draw_text_real (glLabelObject *object,
1280 gboolean screen_flag,
1281 glMergeRecord *record,
1284 gl_debug (DEBUG_LABEL, "START");
1286 set_text_path (GL_LABEL_TEXT (object), cr, screen_flag, record);
1288 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
1291 gl_debug (DEBUG_LABEL, "END");
1295 /*****************************************************************************/
1296 /* Is object at coordinates? */
1297 /*****************************************************************************/
1299 object_at (glLabelObject *object,
1305 gdouble scale_x, scale_y;
1307 gl_label_object_get_size (object, &w, &h);
1309 if ( (x >= 0) && (x <= w) && (y >= 0) && (y <= h) )
1311 cairo_new_path (cr);
1312 set_text_path (GL_LABEL_TEXT (object), cr, TRUE, NULL);
1313 if (cairo_in_fill (cr, x, y))
1321 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1323 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1325 if (cairo_in_stroke (cr, x, y))
1331 if (gl_label_object_is_selected (object))
1333 cairo_new_path (cr);
1334 cairo_rectangle (cr, 0, 0, w, h);
1338 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1340 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1342 if (cairo_in_stroke (cr, x, y))
1354 /*****************************************************************************/
1355 /* Draw text style handles. */
1356 /*****************************************************************************/
1358 draw_handles (glLabelObject *object,
1362 gdouble scale_x, scale_y;
1363 gdouble dashes[2] = { 2, 2 };
1365 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1369 cairo_rectangle (cr, 0, 0, w, h);
1373 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1374 cairo_scale (cr, scale_x, scale_y);
1376 cairo_set_dash (cr, dashes, 2, 0);
1377 cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS);
1378 cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
1383 gl_label_object_draw_handles_box (object, cr);
1390 * Local Variables: -- emacs
1392 * c-basic-offset: 8 -- emacs
1393 * tab-width: 8 -- emacs
1394 * indent-tabs-mode: nil -- emacs