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,
177 static gboolean object_at (glLabelObject *object,
182 static void draw_handles (glLabelObject *object,
186 /*****************************************************************************/
187 /* Object infrastructure. */
188 /*****************************************************************************/
189 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT)
192 /*****************************************************************************/
193 /* Class Init Function. */
194 /*****************************************************************************/
196 gl_label_text_class_init (glLabelTextClass *class)
198 GObjectClass *object_class = G_OBJECT_CLASS (class);
199 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
201 gl_label_text_parent_class = g_type_class_peek_parent (class);
203 label_object_class->copy = copy;
205 label_object_class->get_size = get_size;
207 label_object_class->set_font_family = set_font_family;
208 label_object_class->set_font_size = set_font_size;
209 label_object_class->set_font_weight = set_font_weight;
210 label_object_class->set_font_italic_flag = set_font_italic_flag;
211 label_object_class->set_text_alignment = set_text_alignment;
212 label_object_class->set_text_valignment = set_text_valignment;
213 label_object_class->set_text_line_spacing = set_text_line_spacing;
214 label_object_class->set_text_color = set_text_color;
215 label_object_class->get_font_family = get_font_family;
216 label_object_class->get_font_size = get_font_size;
217 label_object_class->get_font_weight = get_font_weight;
218 label_object_class->get_font_italic_flag = get_font_italic_flag;
219 label_object_class->get_text_alignment = get_text_alignment;
220 label_object_class->get_text_valignment = get_text_valignment;
221 label_object_class->get_text_line_spacing = get_text_line_spacing;
222 label_object_class->get_text_color = get_text_color;
223 label_object_class->draw_object = draw_object;
224 label_object_class->draw_shadow = draw_shadow;
225 label_object_class->object_at = object_at;
226 label_object_class->draw_handles = draw_handles;
228 object_class->finalize = gl_label_text_finalize;
232 /*****************************************************************************/
233 /* Object Instance Init Function. */
234 /*****************************************************************************/
236 gl_label_text_init (glLabelText *ltext)
238 ltext->priv = g_new0 (glLabelTextPrivate, 1);
240 ltext->priv->tag_table = gtk_text_tag_table_new ();
241 ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
243 ltext->priv->size_changed = TRUE;
245 ltext->priv->checkpoint_flag = TRUE;
247 g_signal_connect (G_OBJECT(ltext->priv->buffer), "begin-user-action",
248 G_CALLBACK(buffer_begin_user_action_cb), ltext);
249 g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
250 G_CALLBACK(buffer_changed_cb), ltext);
254 /*****************************************************************************/
255 /* Finalize Method. */
256 /*****************************************************************************/
258 gl_label_text_finalize (GObject *object)
260 glLabelText *ltext = GL_LABEL_TEXT (object);
262 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
264 g_object_unref (ltext->priv->tag_table);
265 g_object_unref (ltext->priv->buffer);
266 g_free (ltext->priv->font_family);
267 gl_color_node_free (&(ltext->priv->color_node));
268 g_free (ltext->priv);
270 G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
274 /*****************************************************************************/
275 /** New Object Generator. */
276 /*****************************************************************************/
278 gl_label_text_new (glLabel *label,
282 glColorNode *color_node;
284 ltext = g_object_new (gl_label_text_get_type(), NULL);
290 gl_label_checkpoint (label, _("Create text object"));
293 color_node = gl_color_node_new_default ();
295 color_node->color = gl_label_get_default_text_color (label);
297 ltext->priv->font_family = gl_label_get_default_font_family (label);
298 ltext->priv->font_size = gl_label_get_default_font_size (label);
299 ltext->priv->font_weight = gl_label_get_default_font_weight (label);
300 ltext->priv->font_italic_flag = gl_label_get_default_font_italic_flag (label);
301 ltext->priv->align = gl_label_get_default_text_alignment (label);
302 ltext->priv->valign = gl_label_get_default_text_valignment (label);
303 ltext->priv->color_node = color_node;
304 ltext->priv->line_spacing = gl_label_get_default_text_line_spacing (label);
306 gl_label_add_object (label, GL_LABEL_OBJECT (ltext));
307 gl_label_object_set_parent (GL_LABEL_OBJECT (ltext), label);
310 return G_OBJECT (ltext);
314 /*****************************************************************************/
315 /* Copy object contents. */
316 /*****************************************************************************/
318 copy (glLabelObject *dst_object,
319 glLabelObject *src_object)
321 glLabelText *ltext = (glLabelText *)src_object;
322 glLabelText *new_ltext = (glLabelText *)dst_object;
324 glColorNode *text_color_node;
326 gl_debug (DEBUG_LABEL, "START");
328 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
329 g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
331 lines = gl_label_text_get_lines (ltext);
332 text_color_node = get_text_color (src_object);
333 gl_label_text_set_lines (new_ltext, lines, FALSE);
335 new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
336 new_ltext->priv->font_size = ltext->priv->font_size;
337 new_ltext->priv->font_weight = ltext->priv->font_weight;
338 new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
339 set_text_color (dst_object, text_color_node, FALSE);
340 new_ltext->priv->align = ltext->priv->align;
341 new_ltext->priv->valign = ltext->priv->valign;
342 new_ltext->priv->line_spacing = ltext->priv->line_spacing;
343 new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
345 new_ltext->priv->size_changed = ltext->priv->size_changed;
346 new_ltext->priv->w = ltext->priv->w;
347 new_ltext->priv->h = ltext->priv->h;
349 gl_color_node_free (&text_color_node);
350 gl_text_node_lines_free (&lines);
352 gl_debug (DEBUG_LABEL, "END");
356 /*****************************************************************************/
357 /* Set object params. */
358 /*****************************************************************************/
360 gl_label_text_set_lines (glLabelText *ltext,
366 gl_debug (DEBUG_LABEL, "START");
368 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
370 ltext->priv->checkpoint_flag = checkpoint;
372 text = gl_text_node_lines_expand (lines, NULL);
373 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
376 ltext->priv->size_changed = TRUE;
378 ltext->priv->checkpoint_flag = TRUE;
380 gl_debug (DEBUG_LABEL, "END");
385 gl_label_text_set_text (glLabelText *ltext,
389 gl_debug (DEBUG_LABEL, "START");
391 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
393 ltext->priv->checkpoint_flag = checkpoint;
395 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
397 ltext->priv->size_changed = TRUE;
399 ltext->priv->checkpoint_flag = TRUE;
401 gl_debug (DEBUG_LABEL, "END");
405 /*****************************************************************************/
406 /* Get object params. */
407 /*****************************************************************************/
409 gl_label_text_get_buffer (glLabelText *ltext)
411 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
413 return ltext->priv->buffer;
418 gl_label_text_get_lines (glLabelText *ltext)
420 GtkTextIter start, end;
424 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
426 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
427 text = gtk_text_buffer_get_text (ltext->priv->buffer,
428 &start, &end, FALSE);
429 lines = gl_text_node_lines_new_from_text (text);
437 gl_label_text_get_text (glLabelText *ltext)
439 GtkTextIter start, end;
442 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
444 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
445 text = gtk_text_buffer_get_text (ltext->priv->buffer,
446 &start, &end, FALSE);
452 /*****************************************************************************/
453 /* Text buffer "changed" callback. */
454 /*****************************************************************************/
456 buffer_begin_user_action_cb (GtkTextBuffer *textbuffer,
461 if ( ltext->priv->checkpoint_flag )
463 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
464 gl_label_checkpoint (label, _("Typing"));
469 /*****************************************************************************/
470 /* Text buffer "changed" callback. */
471 /*****************************************************************************/
473 buffer_changed_cb (GtkTextBuffer *textbuffer,
476 ltext->priv->size_changed = TRUE;
478 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
482 /*****************************************************************************/
483 /* Get object size method. */
484 /*****************************************************************************/
486 get_size (glLabelObject *object,
490 glLabelText *ltext = (glLabelText *)object;
491 PangoFontMap *fontmap;
492 PangoContext *context;
493 cairo_font_options_t *options;
496 PangoFontDescription *desc;
498 gdouble line_spacing;
499 GtkTextIter start, end;
501 gdouble w_parent, h_parent;
504 gl_debug (DEBUG_LABEL, "START");
506 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
508 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
510 if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
516 if (!ltext->priv->size_changed)
523 font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
524 line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
526 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
527 text = gtk_text_buffer_get_text (ltext->priv->buffer,
528 &start, &end, FALSE);
531 fontmap = pango_cairo_font_map_new ();
532 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
533 options = cairo_font_options_create ();
534 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
535 pango_cairo_context_set_font_options (context, options);
536 cairo_font_options_destroy (options);
538 layout = pango_layout_new (context);
540 style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
542 desc = pango_font_description_new ();
543 pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
544 pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
545 pango_font_description_set_style (desc, style);
546 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
547 pango_layout_set_font_description (layout, desc);
548 pango_font_description_free (desc);
550 pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
551 pango_layout_set_text (layout, text, -1);
552 pango_layout_get_size (layout, &iw, &ih);
553 *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
554 *h = ltext->priv->h = ih / PANGO_SCALE;
555 ltext->priv->size_changed = FALSE;
557 g_object_unref (layout);
558 g_object_unref (context);
559 g_object_unref (fontmap);
562 gl_debug (DEBUG_LABEL, "END");
566 /*****************************************************************************/
567 /* Set font family method. */
568 /*****************************************************************************/
570 set_font_family (glLabelObject *object,
571 const gchar *font_family,
574 glLabelText *ltext = (glLabelText *)object;
575 gchar *good_font_family;
578 gl_debug (DEBUG_LABEL, "START");
580 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
581 g_return_if_fail (font_family);
583 good_font_family = gl_font_util_validate_family (font_family);
585 if (ltext->priv->font_family) {
586 if (strcmp (ltext->priv->font_family, good_font_family) == 0) {
587 g_free (good_font_family);
588 gl_debug (DEBUG_LABEL, "END (no change)");
591 g_free (ltext->priv->font_family);
596 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
597 gl_label_checkpoint (label, _("Font family"));
600 ltext->priv->font_family = g_strdup (good_font_family);
601 g_free (good_font_family);
603 gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
605 ltext->priv->size_changed = TRUE;
607 gl_font_history_model_add_family (gl_font_history, ltext->priv->font_family);
609 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
611 gl_debug (DEBUG_LABEL, "END");
615 /*****************************************************************************/
616 /* Set font size method. */
617 /*****************************************************************************/
619 set_font_size (glLabelObject *object,
623 glLabelText *ltext = (glLabelText *)object;
626 gl_debug (DEBUG_LABEL, "START");
628 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
630 if (ltext->priv->font_size != font_size)
634 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
635 gl_label_checkpoint (label, _("Font size"));
638 ltext->priv->size_changed = TRUE;
640 ltext->priv->font_size = font_size;
641 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
644 gl_debug (DEBUG_LABEL, "END");
648 /*****************************************************************************/
649 /* Set font weight method. */
650 /*****************************************************************************/
652 set_font_weight (glLabelObject *object,
653 PangoWeight font_weight,
656 glLabelText *ltext = (glLabelText *)object;
659 gl_debug (DEBUG_LABEL, "START");
661 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
663 if (ltext->priv->font_weight != font_weight)
667 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
668 gl_label_checkpoint (label, _("Font weight"));
671 ltext->priv->size_changed = TRUE;
673 ltext->priv->font_weight = font_weight;
674 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
677 gl_debug (DEBUG_LABEL, "END");
681 /*****************************************************************************/
682 /* Set font italic flag method. */
683 /*****************************************************************************/
685 set_font_italic_flag (glLabelObject *object,
686 gboolean font_italic_flag,
689 glLabelText *ltext = (glLabelText *)object;
692 gl_debug (DEBUG_LABEL, "START");
694 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
696 if (ltext->priv->font_italic_flag != font_italic_flag)
700 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
701 gl_label_checkpoint (label, _("Italic"));
704 ltext->priv->size_changed = TRUE;
706 ltext->priv->font_italic_flag = font_italic_flag;
707 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
710 gl_debug (DEBUG_LABEL, "END");
714 /*****************************************************************************/
715 /* Set text alignment method. */
716 /*****************************************************************************/
718 set_text_alignment (glLabelObject *object,
719 PangoAlignment text_alignment,
722 glLabelText *ltext = (glLabelText *)object;
725 gl_debug (DEBUG_LABEL, "START");
727 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
729 if (ltext->priv->align != text_alignment)
733 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
734 gl_label_checkpoint (label, _("Align text"));
737 ltext->priv->size_changed = TRUE;
739 ltext->priv->align = text_alignment;
740 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
743 gl_debug (DEBUG_LABEL, "END");
747 /*****************************************************************************/
748 /* Set vertical text alignment method. */
749 /*****************************************************************************/
751 set_text_valignment (glLabelObject *object,
752 glValignment text_valignment,
755 glLabelText *ltext = (glLabelText *)object;
758 gl_debug (DEBUG_LABEL, "START");
760 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
762 if (ltext->priv->valign != text_valignment)
766 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
767 gl_label_checkpoint (label, _("Vertically align text"));
770 ltext->priv->size_changed = TRUE;
772 ltext->priv->valign = text_valignment;
773 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
776 gl_debug (DEBUG_LABEL, "END");
780 /*****************************************************************************/
781 /* Set text line spacing method. */
782 /*****************************************************************************/
784 set_text_line_spacing (glLabelObject *object,
785 gdouble line_spacing,
788 glLabelText *ltext = (glLabelText *)object;
791 gl_debug (DEBUG_LABEL, "START");
793 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
795 if (ltext->priv->line_spacing != line_spacing)
799 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
800 gl_label_checkpoint (label, _("Line spacing"));
803 ltext->priv->size_changed = TRUE;
805 ltext->priv->line_spacing = line_spacing;
806 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
809 gl_debug (DEBUG_LABEL, "END");
813 /*****************************************************************************/
814 /* Set text color method. */
815 /*****************************************************************************/
817 set_text_color (glLabelObject *object,
818 glColorNode *text_color_node,
821 glLabelText *ltext = (glLabelText *)object;
824 gl_debug (DEBUG_LABEL, "START");
826 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
828 if (!gl_color_node_equal (ltext->priv->color_node, text_color_node))
832 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
833 gl_label_checkpoint (label, _("Text color"));
836 gl_color_node_free (&(ltext->priv->color_node));
837 ltext->priv->color_node = gl_color_node_dup (text_color_node);
839 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
842 gl_debug (DEBUG_LABEL, "END");
846 /*****************************************************************************/
847 /* Get font family method. */
848 /*****************************************************************************/
850 get_font_family (glLabelObject *object)
852 glLabelText *ltext = (glLabelText *)object;
854 gl_debug (DEBUG_LABEL, "");
856 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
858 return g_strdup (ltext->priv->font_family);
862 /*****************************************************************************/
863 /* Get font size method. */
864 /*****************************************************************************/
866 get_font_size (glLabelObject *object)
868 glLabelText *ltext = (glLabelText *)object;
870 gl_debug (DEBUG_LABEL, "");
872 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
874 return ltext->priv->font_size;
878 /*****************************************************************************/
879 /* Get font weight method. */
880 /*****************************************************************************/
882 get_font_weight (glLabelObject *object)
884 glLabelText *ltext = (glLabelText *)object;
886 gl_debug (DEBUG_LABEL, "");
888 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
890 return ltext->priv->font_weight;
894 /*****************************************************************************/
895 /* Get font italic flag method. */
896 /*****************************************************************************/
898 get_font_italic_flag (glLabelObject *object)
900 glLabelText *ltext = (glLabelText *)object;
902 gl_debug (DEBUG_LABEL, "");
904 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
906 return ltext->priv->font_italic_flag;
910 /*****************************************************************************/
911 /* Get text alignment method. */
912 /*****************************************************************************/
913 static PangoAlignment
914 get_text_alignment (glLabelObject *object)
916 glLabelText *ltext = (glLabelText *)object;
918 gl_debug (DEBUG_LABEL, "");
920 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
922 return ltext->priv->align;
926 /*****************************************************************************/
927 /* Get vertical text alignment method. */
928 /*****************************************************************************/
930 get_text_valignment (glLabelObject *object)
932 glLabelText *ltext = (glLabelText *)object;
934 gl_debug (DEBUG_LABEL, "");
936 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
938 return ltext->priv->valign;
942 /*****************************************************************************/
943 /* Get text line spacing method. */
944 /*****************************************************************************/
946 get_text_line_spacing (glLabelObject *object)
948 glLabelText *ltext = (glLabelText *)object;
950 gl_debug (DEBUG_LABEL, "");
952 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
954 return ltext->priv->line_spacing;
958 /*****************************************************************************/
959 /* Get text color method. */
960 /*****************************************************************************/
962 get_text_color (glLabelObject *object)
964 glLabelText *ltext = (glLabelText *)object;
966 gl_debug (DEBUG_LABEL, "");
968 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
970 return gl_color_node_dup (ltext->priv->color_node);
974 /*****************************************************************************/
975 /* Set auto shrink flag. */
976 /*****************************************************************************/
978 gl_label_text_set_auto_shrink (glLabelText *ltext,
979 gboolean auto_shrink,
984 gl_debug (DEBUG_LABEL, "BEGIN");
986 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
988 if (ltext->priv->auto_shrink != auto_shrink)
992 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
993 gl_label_checkpoint (label, _("Auto shrink"));
996 ltext->priv->auto_shrink = auto_shrink;
997 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
1000 gl_debug (DEBUG_LABEL, "END");
1004 /*****************************************************************************/
1005 /* Query auto shrink flag. */
1006 /*****************************************************************************/
1008 gl_label_text_get_auto_shrink (glLabelText *ltext)
1010 gl_debug (DEBUG_LABEL, "");
1012 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
1014 return ltext->priv->auto_shrink;
1018 /*****************************************************************************/
1019 /* Automatically shrink text size to fit within horizontal width. */
1020 /*****************************************************************************/
1022 auto_shrink_font_size (cairo_t *cr,
1030 PangoLayout *layout;
1031 PangoFontDescription *desc;
1033 gdouble layout_width;
1036 layout = pango_cairo_create_layout (cr);
1038 desc = pango_font_description_new ();
1039 pango_font_description_set_family (desc, family);
1040 pango_font_description_set_weight (desc, weight);
1041 pango_font_description_set_style (desc, style);
1042 pango_font_description_set_size (desc, size * PANGO_SCALE);
1044 pango_layout_set_font_description (layout, desc);
1045 pango_font_description_free (desc);
1047 pango_layout_set_text (layout, text, -1);
1048 pango_layout_set_width (layout, -1);
1049 pango_layout_get_size (layout, &iw, &ih);
1050 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
1052 g_object_unref (layout);
1054 g_print ("Object w = %g, layout w = %g\n", width, layout_width);
1056 if ( layout_width > width )
1059 new_size = size * (width-2*GL_LABEL_TEXT_MARGIN)/layout_width;
1061 /* Round down to nearest 1/2 point */
1062 new_size = (int)(new_size*2.0) / 2.0;
1064 /* don't get ridiculously small. */
1079 /*****************************************************************************/
1080 /* Update pango layout. */
1081 /*****************************************************************************/
1083 set_text_path (glLabelText *this,
1085 gboolean screen_flag,
1086 glMergeRecord *record)
1089 gdouble object_w, object_h;
1090 gdouble raw_w, raw_h;
1094 gboolean auto_shrink;
1095 PangoLayout *layout;
1097 PangoFontDescription *desc;
1098 cairo_font_options_t *font_options;
1099 PangoContext *context;
1102 gl_debug (DEBUG_LABEL, "START");
1106 gl_label_object_get_size (GL_LABEL_OBJECT (this), &object_w, &object_h);
1107 gl_label_object_get_raw_size (GL_LABEL_OBJECT (this), &raw_w, &raw_h);
1109 lines = gl_label_text_get_lines (this);
1110 text = gl_text_node_lines_expand (lines, record);
1112 style = this->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
1114 font_size = this->priv->font_size;
1115 auto_shrink = gl_label_text_get_auto_shrink (this);
1116 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
1118 font_size = auto_shrink_font_size (cr,
1119 this->priv->font_family,
1120 this->priv->font_size * FONT_SCALE,
1121 this->priv->font_weight,
1128 layout = pango_cairo_create_layout (cr);
1130 font_options = cairo_font_options_create ();
1131 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
1132 context = pango_layout_get_context (layout);
1133 pango_cairo_context_set_font_options (context, font_options);
1134 cairo_font_options_destroy (font_options);
1136 desc = pango_font_description_new ();
1137 pango_font_description_set_family (desc, this->priv->font_family);
1138 pango_font_description_set_weight (desc, this->priv->font_weight);
1139 pango_font_description_set_size (desc, font_size * FONT_SCALE * PANGO_SCALE);
1140 pango_font_description_set_style (desc, style);
1141 pango_layout_set_font_description (layout, desc);
1142 pango_font_description_free (desc);
1144 pango_layout_set_text (layout, text, -1);
1145 pango_layout_set_spacing (layout, font_size * (this->priv->line_spacing-1) * PANGO_SCALE);
1148 pango_layout_set_width (layout, -1);
1152 pango_layout_set_width (layout, object_w * PANGO_SCALE);
1154 pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
1155 pango_layout_set_alignment (layout, this->priv->align);
1156 pango_layout_get_pixel_size (layout, &iw, &ih);
1158 switch (this->priv->valign)
1160 case GL_VALIGN_VCENTER:
1161 y = (object_h - ih) / 2;
1163 case GL_VALIGN_BOTTOM:
1171 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN, y);
1172 pango_cairo_layout_path (cr, layout);
1174 g_object_unref (layout);
1175 gl_text_node_lines_free (&lines);
1179 gl_debug (DEBUG_LABEL, "END");
1183 /*****************************************************************************/
1184 /* Draw object method. */
1185 /*****************************************************************************/
1187 draw_object (glLabelObject *object,
1189 gboolean screen_flag,
1190 glMergeRecord *record)
1192 glColorNode *color_node;
1195 gl_debug (DEBUG_LABEL, "START");
1197 color_node = gl_label_object_get_text_color (object);
1198 color = gl_color_node_expand (color_node, record);
1199 if (color_node->field_flag && screen_flag)
1201 color = GL_COLOR_MERGE_DEFAULT;
1203 gl_color_node_free (&color_node);
1205 draw_text_real (object, cr, screen_flag, record, color);
1207 gl_debug (DEBUG_LABEL, "END");
1211 /*****************************************************************************/
1212 /* Draw shadow method. */
1213 /*****************************************************************************/
1215 draw_shadow (glLabelObject *object,
1217 gboolean screen_flag,
1218 glMergeRecord *record)
1220 glColorNode *color_node;
1222 glColorNode *shadow_color_node;
1223 gdouble shadow_opacity;
1226 gl_debug (DEBUG_LABEL, "START");
1228 color_node = gl_label_object_get_text_color (object);
1229 color = gl_color_node_expand (color_node, record);
1230 if (color_node->field_flag && screen_flag)
1232 color = GL_COLOR_MERGE_DEFAULT;
1234 gl_color_node_free (&color_node);
1236 shadow_color_node = gl_label_object_get_shadow_color (object);
1237 if (shadow_color_node->field_flag)
1239 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
1241 shadow_opacity = gl_label_object_get_shadow_opacity (object);
1242 shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
1243 gl_color_node_free (&shadow_color_node);
1245 draw_text_real (object, cr, screen_flag, record, shadow_color);
1247 gl_debug (DEBUG_LABEL, "END");
1251 /*****************************************************************************/
1253 /*****************************************************************************/
1255 draw_text_real (glLabelObject *object,
1257 gboolean screen_flag,
1258 glMergeRecord *record,
1261 gl_debug (DEBUG_LABEL, "START");
1263 set_text_path (GL_LABEL_TEXT (object), cr, screen_flag, record);
1265 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
1268 gl_debug (DEBUG_LABEL, "END");
1272 /*****************************************************************************/
1273 /* Is object at coordinates? */
1274 /*****************************************************************************/
1276 object_at (glLabelObject *object,
1282 gdouble scale_x, scale_y;
1284 gl_label_object_get_size (object, &w, &h);
1286 if ( (x >= 0) && (x <= w) && (y >= 0) && (y <= h) )
1288 cairo_new_path (cr);
1289 set_text_path (GL_LABEL_TEXT (object), cr, TRUE, NULL);
1290 if (cairo_in_fill (cr, x, y))
1298 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1300 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1302 if (cairo_in_stroke (cr, x, y))
1308 if (gl_label_object_is_selected (object))
1310 cairo_new_path (cr);
1311 cairo_rectangle (cr, 0, 0, w, h);
1315 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1317 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1319 if (cairo_in_stroke (cr, x, y))
1331 /*****************************************************************************/
1332 /* Draw text style handles. */
1333 /*****************************************************************************/
1335 draw_handles (glLabelObject *object,
1339 gdouble scale_x, scale_y;
1340 gdouble dashes[2] = { 2, 2 };
1342 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1346 cairo_rectangle (cr, 0, 0, w, h);
1350 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1351 cairo_scale (cr, scale_x, scale_y);
1353 cairo_set_dash (cr, dashes, 2, 0);
1354 cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS);
1355 cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
1360 gl_label_object_draw_handles_box (object, cr);
1367 * Local Variables: -- emacs
1369 * c-basic-offset: 8 -- emacs
1370 * tab-width: 8 -- emacs
1371 * indent-tabs-mode: nil -- emacs