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
47 /*========================================================*/
49 /*========================================================*/
51 struct _glLabelTextPrivate {
53 GtkTextTagTable *tag_table;
54 GtkTextBuffer *buffer;
58 PangoWeight font_weight;
59 gboolean font_italic_flag;
61 glColorNode *color_node;
65 gboolean size_changed;
69 gboolean checkpoint_flag;
73 /*========================================================*/
74 /* Private globals. */
75 /*========================================================*/
78 /*========================================================*/
79 /* Private function prototypes. */
80 /*========================================================*/
82 static void gl_label_text_finalize (GObject *object);
84 static void copy (glLabelObject *dst_object,
85 glLabelObject *src_object);
87 static void buffer_begin_user_action_cb (GtkTextBuffer *textbuffer,
90 static void buffer_changed_cb (GtkTextBuffer *textbuffer,
93 static void get_size (glLabelObject *object,
97 static void set_font_family (glLabelObject *object,
98 const gchar *font_family,
101 static void set_font_size (glLabelObject *object,
103 gboolean checkpoint);
105 static void set_font_weight (glLabelObject *object,
106 PangoWeight font_weight,
107 gboolean checkpoint);
109 static void set_font_italic_flag (glLabelObject *object,
110 gboolean font_italic_flag,
111 gboolean checkpoint);
113 static void set_text_alignment (glLabelObject *object,
114 PangoAlignment text_alignment,
115 gboolean checkpoint);
117 static void set_text_line_spacing (glLabelObject *object,
118 gdouble text_line_spacing,
119 gboolean checkpoint);
121 static void set_text_color (glLabelObject *object,
122 glColorNode *text_color_node,
123 gboolean checkpoint);
125 static gchar *get_font_family (glLabelObject *object);
127 static gdouble get_font_size (glLabelObject *object);
129 static PangoWeight get_font_weight (glLabelObject *object);
131 static gboolean get_font_italic_flag (glLabelObject *object);
133 static PangoAlignment get_text_alignment (glLabelObject *object);
135 static gdouble get_text_line_spacing (glLabelObject *object);
137 static glColorNode* get_text_color (glLabelObject *object);
139 static void set_text_path (glLabelText *this,
141 gboolean screen_flag,
142 glMergeRecord *record);
144 static void draw_object (glLabelObject *object,
146 gboolean screen_flag,
147 glMergeRecord *record);
149 static void draw_shadow (glLabelObject *object,
151 gboolean screen_flag,
152 glMergeRecord *record);
154 static void draw_text_real (glLabelObject *object,
156 gboolean screen_flag,
157 glMergeRecord *record,
160 static gdouble auto_shrink_font_size (cairo_t *cr,
168 static gboolean object_at (glLabelObject *object,
173 static void draw_handles (glLabelObject *object,
177 /*****************************************************************************/
178 /* Object infrastructure. */
179 /*****************************************************************************/
180 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT);
183 /*****************************************************************************/
184 /* Class Init Function. */
185 /*****************************************************************************/
187 gl_label_text_class_init (glLabelTextClass *class)
189 GObjectClass *object_class = G_OBJECT_CLASS (class);
190 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
192 gl_label_text_parent_class = g_type_class_peek_parent (class);
194 label_object_class->copy = copy;
196 label_object_class->get_size = get_size;
198 label_object_class->set_font_family = set_font_family;
199 label_object_class->set_font_size = set_font_size;
200 label_object_class->set_font_weight = set_font_weight;
201 label_object_class->set_font_italic_flag = set_font_italic_flag;
202 label_object_class->set_text_alignment = set_text_alignment;
203 label_object_class->set_text_line_spacing = set_text_line_spacing;
204 label_object_class->set_text_color = set_text_color;
205 label_object_class->get_font_family = get_font_family;
206 label_object_class->get_font_size = get_font_size;
207 label_object_class->get_font_weight = get_font_weight;
208 label_object_class->get_font_italic_flag = get_font_italic_flag;
209 label_object_class->get_text_alignment = get_text_alignment;
210 label_object_class->get_text_line_spacing = get_text_line_spacing;
211 label_object_class->get_text_color = get_text_color;
212 label_object_class->draw_object = draw_object;
213 label_object_class->draw_shadow = draw_shadow;
214 label_object_class->object_at = object_at;
215 label_object_class->draw_handles = draw_handles;
217 object_class->finalize = gl_label_text_finalize;
221 /*****************************************************************************/
222 /* Object Instance Init Function. */
223 /*****************************************************************************/
225 gl_label_text_init (glLabelText *ltext)
227 ltext->priv = g_new0 (glLabelTextPrivate, 1);
229 ltext->priv->tag_table = gtk_text_tag_table_new ();
230 ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
232 ltext->priv->size_changed = TRUE;
234 ltext->priv->checkpoint_flag = TRUE;
236 g_signal_connect (G_OBJECT(ltext->priv->buffer), "begin-user-action",
237 G_CALLBACK(buffer_begin_user_action_cb), ltext);
238 g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
239 G_CALLBACK(buffer_changed_cb), ltext);
243 /*****************************************************************************/
244 /* Finalize Method. */
245 /*****************************************************************************/
247 gl_label_text_finalize (GObject *object)
249 glLabelText *ltext = GL_LABEL_TEXT (object);
251 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
253 g_object_unref (ltext->priv->tag_table);
254 g_object_unref (ltext->priv->buffer);
255 g_free (ltext->priv->font_family);
256 gl_color_node_free (&(ltext->priv->color_node));
257 g_free (ltext->priv);
259 G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
263 /*****************************************************************************/
264 /** New Object Generator. */
265 /*****************************************************************************/
267 gl_label_text_new (glLabel *label,
271 glColorNode *color_node;
273 ltext = g_object_new (gl_label_text_get_type(), NULL);
279 gl_label_checkpoint (label, _("Create text object"));
282 color_node = gl_color_node_new_default ();
284 color_node->color = gl_label_get_default_text_color (label);
286 ltext->priv->font_family = gl_label_get_default_font_family (label);
287 ltext->priv->font_size = gl_label_get_default_font_size (label);
288 ltext->priv->font_weight = gl_label_get_default_font_weight (label);
289 ltext->priv->font_italic_flag = gl_label_get_default_font_italic_flag (label);
290 ltext->priv->align = gl_label_get_default_text_alignment (label);
291 ltext->priv->color_node = color_node;
292 ltext->priv->line_spacing = gl_label_get_default_text_line_spacing (label);
294 gl_label_add_object (label, GL_LABEL_OBJECT (ltext));
295 gl_label_object_set_parent (GL_LABEL_OBJECT (ltext), label);
298 return G_OBJECT (ltext);
302 /*****************************************************************************/
303 /* Copy object contents. */
304 /*****************************************************************************/
306 copy (glLabelObject *dst_object,
307 glLabelObject *src_object)
309 glLabelText *ltext = (glLabelText *)src_object;
310 glLabelText *new_ltext = (glLabelText *)dst_object;
312 glColorNode *text_color_node;
314 gl_debug (DEBUG_LABEL, "START");
316 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
317 g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
319 lines = gl_label_text_get_lines (ltext);
320 text_color_node = get_text_color (src_object);
321 gl_label_text_set_lines (new_ltext, lines, FALSE);
323 new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
324 new_ltext->priv->font_size = ltext->priv->font_size;
325 new_ltext->priv->font_weight = ltext->priv->font_weight;
326 new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
327 set_text_color (dst_object, text_color_node, FALSE);
328 new_ltext->priv->align = ltext->priv->align;
329 new_ltext->priv->line_spacing = ltext->priv->line_spacing;
330 new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
332 new_ltext->priv->size_changed = ltext->priv->size_changed;
333 new_ltext->priv->w = ltext->priv->w;
334 new_ltext->priv->h = ltext->priv->h;
336 gl_color_node_free (&text_color_node);
337 gl_text_node_lines_free (&lines);
339 gl_debug (DEBUG_LABEL, "END");
343 /*****************************************************************************/
344 /* Set object params. */
345 /*****************************************************************************/
347 gl_label_text_set_lines (glLabelText *ltext,
353 gl_debug (DEBUG_LABEL, "START");
355 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
357 ltext->priv->checkpoint_flag = checkpoint;
359 text = gl_text_node_lines_expand (lines, NULL);
360 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
363 ltext->priv->size_changed = TRUE;
365 ltext->priv->checkpoint_flag = TRUE;
367 gl_debug (DEBUG_LABEL, "END");
372 gl_label_text_set_text (glLabelText *ltext,
376 gl_debug (DEBUG_LABEL, "START");
378 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
380 ltext->priv->checkpoint_flag = checkpoint;
382 gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
384 ltext->priv->size_changed = TRUE;
386 ltext->priv->checkpoint_flag = TRUE;
388 gl_debug (DEBUG_LABEL, "END");
392 /*****************************************************************************/
393 /* Get object params. */
394 /*****************************************************************************/
396 gl_label_text_get_buffer (glLabelText *ltext)
398 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
400 return ltext->priv->buffer;
405 gl_label_text_get_lines (glLabelText *ltext)
407 GtkTextIter start, end;
411 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
413 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
414 text = gtk_text_buffer_get_text (ltext->priv->buffer,
415 &start, &end, FALSE);
416 lines = gl_text_node_lines_new_from_text (text);
424 gl_label_text_get_text (glLabelText *ltext)
426 GtkTextIter start, end;
429 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
431 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
432 text = gtk_text_buffer_get_text (ltext->priv->buffer,
433 &start, &end, FALSE);
439 /*****************************************************************************/
440 /* Text buffer "changed" callback. */
441 /*****************************************************************************/
443 buffer_begin_user_action_cb (GtkTextBuffer *textbuffer,
448 if ( ltext->priv->checkpoint_flag )
450 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
451 gl_label_checkpoint (label, _("Typing"));
456 /*****************************************************************************/
457 /* Text buffer "changed" callback. */
458 /*****************************************************************************/
460 buffer_changed_cb (GtkTextBuffer *textbuffer,
463 ltext->priv->size_changed = TRUE;
465 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
469 /*****************************************************************************/
470 /* Get object size method. */
471 /*****************************************************************************/
473 get_size (glLabelObject *object,
477 glLabelText *ltext = (glLabelText *)object;
478 PangoFontMap *fontmap;
479 PangoContext *context;
480 cairo_font_options_t *options;
483 PangoFontDescription *desc;
485 gdouble line_spacing;
486 GtkTextIter start, end;
488 gdouble w_parent, h_parent;
491 gl_debug (DEBUG_LABEL, "START");
493 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
495 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
497 if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
503 if (!ltext->priv->size_changed)
510 font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
511 line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
513 gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
514 text = gtk_text_buffer_get_text (ltext->priv->buffer,
515 &start, &end, FALSE);
518 fontmap = pango_cairo_font_map_new ();
519 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
520 options = cairo_font_options_create ();
521 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
522 pango_cairo_context_set_font_options (context, options);
523 cairo_font_options_destroy (options);
525 layout = pango_layout_new (context);
527 style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
529 desc = pango_font_description_new ();
530 pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
531 pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
532 pango_font_description_set_style (desc, style);
533 pango_font_description_set_size (desc, font_size * PANGO_SCALE);
534 pango_layout_set_font_description (layout, desc);
535 pango_font_description_free (desc);
537 pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
538 pango_layout_set_text (layout, text, -1);
539 pango_layout_get_size (layout, &iw, &ih);
540 *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
541 *h = ltext->priv->h = ih / PANGO_SCALE;
542 ltext->priv->size_changed = FALSE;
544 g_object_unref (layout);
545 g_object_unref (context);
546 g_object_unref (fontmap);
549 gl_debug (DEBUG_LABEL, "END");
553 /*****************************************************************************/
554 /* Set font family method. */
555 /*****************************************************************************/
557 set_font_family (glLabelObject *object,
558 const gchar *font_family,
561 glLabelText *ltext = (glLabelText *)object;
562 gchar *good_font_family;
565 gl_debug (DEBUG_LABEL, "START");
567 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
568 g_return_if_fail (font_family);
570 good_font_family = gl_font_util_validate_family (font_family);
572 if (ltext->priv->font_family) {
573 if (strcmp (ltext->priv->font_family, good_font_family) == 0) {
574 g_free (good_font_family);
575 gl_debug (DEBUG_LABEL, "END (no change)");
578 g_free (ltext->priv->font_family);
583 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
584 gl_label_checkpoint (label, _("Font family"));
587 ltext->priv->font_family = g_strdup (good_font_family);
588 g_free (good_font_family);
590 gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
592 ltext->priv->size_changed = TRUE;
594 gl_font_history_model_add_family (gl_font_history, ltext->priv->font_family);
596 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
598 gl_debug (DEBUG_LABEL, "END");
602 /*****************************************************************************/
603 /* Set font size method. */
604 /*****************************************************************************/
606 set_font_size (glLabelObject *object,
610 glLabelText *ltext = (glLabelText *)object;
613 gl_debug (DEBUG_LABEL, "START");
615 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
617 if (ltext->priv->font_size != font_size)
621 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
622 gl_label_checkpoint (label, _("Font size"));
625 ltext->priv->size_changed = TRUE;
627 ltext->priv->font_size = font_size;
628 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
631 gl_debug (DEBUG_LABEL, "END");
635 /*****************************************************************************/
636 /* Set font weight method. */
637 /*****************************************************************************/
639 set_font_weight (glLabelObject *object,
640 PangoWeight font_weight,
643 glLabelText *ltext = (glLabelText *)object;
646 gl_debug (DEBUG_LABEL, "START");
648 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
650 if (ltext->priv->font_weight != font_weight)
654 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
655 gl_label_checkpoint (label, _("Font weight"));
658 ltext->priv->size_changed = TRUE;
660 ltext->priv->font_weight = font_weight;
661 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
664 gl_debug (DEBUG_LABEL, "END");
668 /*****************************************************************************/
669 /* Set font italic flag method. */
670 /*****************************************************************************/
672 set_font_italic_flag (glLabelObject *object,
673 gboolean font_italic_flag,
676 glLabelText *ltext = (glLabelText *)object;
679 gl_debug (DEBUG_LABEL, "START");
681 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
683 if (ltext->priv->font_italic_flag != font_italic_flag)
687 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
688 gl_label_checkpoint (label, _("Italic"));
691 ltext->priv->size_changed = TRUE;
693 ltext->priv->font_italic_flag = font_italic_flag;
694 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
697 gl_debug (DEBUG_LABEL, "END");
701 /*****************************************************************************/
702 /* Set text alignment method. */
703 /*****************************************************************************/
705 set_text_alignment (glLabelObject *object,
706 PangoAlignment text_alignment,
709 glLabelText *ltext = (glLabelText *)object;
712 gl_debug (DEBUG_LABEL, "START");
714 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
716 if (ltext->priv->align != text_alignment)
720 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
721 gl_label_checkpoint (label, _("Align text"));
724 ltext->priv->size_changed = TRUE;
726 ltext->priv->align = text_alignment;
727 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
730 gl_debug (DEBUG_LABEL, "END");
734 /*****************************************************************************/
735 /* Set text line spacing method. */
736 /*****************************************************************************/
738 set_text_line_spacing (glLabelObject *object,
739 gdouble line_spacing,
742 glLabelText *ltext = (glLabelText *)object;
745 gl_debug (DEBUG_LABEL, "START");
747 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
749 if (ltext->priv->line_spacing != line_spacing)
753 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
754 gl_label_checkpoint (label, _("Line spacing"));
757 ltext->priv->size_changed = TRUE;
759 ltext->priv->line_spacing = line_spacing;
760 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
763 gl_debug (DEBUG_LABEL, "END");
767 /*****************************************************************************/
768 /* Set text color method. */
769 /*****************************************************************************/
771 set_text_color (glLabelObject *object,
772 glColorNode *text_color_node,
775 glLabelText *ltext = (glLabelText *)object;
778 gl_debug (DEBUG_LABEL, "START");
780 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
782 if (!gl_color_node_equal (ltext->priv->color_node, text_color_node))
786 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
787 gl_label_checkpoint (label, _("Text color"));
790 gl_color_node_free (&(ltext->priv->color_node));
791 ltext->priv->color_node = gl_color_node_dup (text_color_node);
793 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
796 gl_debug (DEBUG_LABEL, "END");
800 /*****************************************************************************/
801 /* Get font family method. */
802 /*****************************************************************************/
804 get_font_family (glLabelObject *object)
806 glLabelText *ltext = (glLabelText *)object;
808 gl_debug (DEBUG_LABEL, "");
810 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
812 return g_strdup (ltext->priv->font_family);
816 /*****************************************************************************/
817 /* Get font size method. */
818 /*****************************************************************************/
820 get_font_size (glLabelObject *object)
822 glLabelText *ltext = (glLabelText *)object;
824 gl_debug (DEBUG_LABEL, "");
826 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
828 return ltext->priv->font_size;
832 /*****************************************************************************/
833 /* Get font weight method. */
834 /*****************************************************************************/
836 get_font_weight (glLabelObject *object)
838 glLabelText *ltext = (glLabelText *)object;
840 gl_debug (DEBUG_LABEL, "");
842 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
844 return ltext->priv->font_weight;
848 /*****************************************************************************/
849 /* Get font italic flag method. */
850 /*****************************************************************************/
852 get_font_italic_flag (glLabelObject *object)
854 glLabelText *ltext = (glLabelText *)object;
856 gl_debug (DEBUG_LABEL, "");
858 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
860 return ltext->priv->font_italic_flag;
864 /*****************************************************************************/
865 /* Get text alignment method. */
866 /*****************************************************************************/
867 static PangoAlignment
868 get_text_alignment (glLabelObject *object)
870 glLabelText *ltext = (glLabelText *)object;
872 gl_debug (DEBUG_LABEL, "");
874 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
876 return ltext->priv->align;
880 /*****************************************************************************/
881 /* Get text line spacing method. */
882 /*****************************************************************************/
884 get_text_line_spacing (glLabelObject *object)
886 glLabelText *ltext = (glLabelText *)object;
888 gl_debug (DEBUG_LABEL, "");
890 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
892 return ltext->priv->line_spacing;
896 /*****************************************************************************/
897 /* Get text color method. */
898 /*****************************************************************************/
900 get_text_color (glLabelObject *object)
902 glLabelText *ltext = (glLabelText *)object;
904 gl_debug (DEBUG_LABEL, "");
906 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
908 return gl_color_node_dup (ltext->priv->color_node);
912 /*****************************************************************************/
913 /* Set auto shrink flag. */
914 /*****************************************************************************/
916 gl_label_text_set_auto_shrink (glLabelText *ltext,
917 gboolean auto_shrink,
922 gl_debug (DEBUG_LABEL, "BEGIN");
924 g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
926 if (ltext->priv->auto_shrink != auto_shrink)
930 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
931 gl_label_checkpoint (label, _("Auto shrink"));
934 ltext->priv->auto_shrink = auto_shrink;
935 gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
938 gl_debug (DEBUG_LABEL, "END");
942 /*****************************************************************************/
943 /* Query auto shrink flag. */
944 /*****************************************************************************/
946 gl_label_text_get_auto_shrink (glLabelText *ltext)
948 gl_debug (DEBUG_LABEL, "");
950 g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
952 return ltext->priv->auto_shrink;
956 /*****************************************************************************/
957 /* Automatically shrink text size to fit within horizontal width. */
958 /*****************************************************************************/
960 auto_shrink_font_size (cairo_t *cr,
969 PangoFontDescription *desc;
971 gdouble layout_width;
974 layout = pango_cairo_create_layout (cr);
976 desc = pango_font_description_new ();
977 pango_font_description_set_family (desc, family);
978 pango_font_description_set_weight (desc, weight);
979 pango_font_description_set_style (desc, style);
980 pango_font_description_set_size (desc, size * PANGO_SCALE);
982 pango_layout_set_font_description (layout, desc);
983 pango_font_description_free (desc);
985 pango_layout_set_text (layout, text, -1);
986 pango_layout_set_width (layout, -1);
987 pango_layout_get_size (layout, &iw, &ih);
988 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
990 g_object_unref (layout);
992 g_print ("Object w = %g, layout w = %g\n", width, layout_width);
994 if ( layout_width > width )
997 new_size = size * (width-2*GL_LABEL_TEXT_MARGIN)/layout_width;
999 /* Round down to nearest 1/2 point */
1000 new_size = (int)(new_size*2.0) / 2.0;
1002 /* don't get ridiculously small. */
1017 /*****************************************************************************/
1018 /* Update pango layout. */
1019 /*****************************************************************************/
1021 set_text_path (glLabelText *this,
1023 gboolean screen_flag,
1024 glMergeRecord *record)
1026 gdouble object_w, object_h;
1027 gdouble raw_w, raw_h;
1031 gboolean auto_shrink;
1032 PangoLayout *layout;
1034 PangoFontDescription *desc;
1035 cairo_font_options_t *font_options;
1036 PangoContext *context;
1039 gl_debug (DEBUG_LABEL, "START");
1043 gl_label_object_get_size (GL_LABEL_OBJECT (this), &object_w, &object_h);
1044 gl_label_object_get_raw_size (GL_LABEL_OBJECT (this), &raw_w, &raw_h);
1046 lines = gl_label_text_get_lines (this);
1047 text = gl_text_node_lines_expand (lines, record);
1049 style = this->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
1051 font_size = this->priv->font_size;
1052 auto_shrink = gl_label_text_get_auto_shrink (this);
1053 if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
1055 font_size = auto_shrink_font_size (cr,
1056 this->priv->font_family,
1057 this->priv->font_size * FONT_SCALE,
1058 this->priv->font_weight,
1065 layout = pango_cairo_create_layout (cr);
1067 font_options = cairo_font_options_create ();
1068 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
1069 context = pango_layout_get_context (layout);
1070 pango_cairo_context_set_font_options (context, font_options);
1071 cairo_font_options_destroy (font_options);
1073 desc = pango_font_description_new ();
1074 pango_font_description_set_family (desc, this->priv->font_family);
1075 pango_font_description_set_weight (desc, this->priv->font_weight);
1076 pango_font_description_set_size (desc, font_size * FONT_SCALE * PANGO_SCALE);
1077 pango_font_description_set_style (desc, style);
1078 pango_layout_set_font_description (layout, desc);
1079 pango_font_description_free (desc);
1081 pango_layout_set_text (layout, text, -1);
1082 pango_layout_set_spacing (layout, font_size * (this->priv->line_spacing-1) * PANGO_SCALE);
1085 pango_layout_set_width (layout, -1);
1089 pango_layout_set_width (layout, object_w * PANGO_SCALE);
1091 pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
1092 pango_layout_set_alignment (layout, this->priv->align);
1095 cairo_move_to (cr, GL_LABEL_TEXT_MARGIN, 0);
1096 pango_cairo_layout_path (cr, layout);
1098 g_object_unref (layout);
1099 gl_text_node_lines_free (&lines);
1103 gl_debug (DEBUG_LABEL, "END");
1107 /*****************************************************************************/
1108 /* Draw object method. */
1109 /*****************************************************************************/
1111 draw_object (glLabelObject *object,
1113 gboolean screen_flag,
1114 glMergeRecord *record)
1116 glColorNode *color_node;
1119 gl_debug (DEBUG_LABEL, "START");
1121 color_node = gl_label_object_get_text_color (object);
1122 color = gl_color_node_expand (color_node, record);
1123 if (color_node->field_flag && screen_flag)
1125 color = GL_COLOR_MERGE_DEFAULT;
1127 gl_color_node_free (&color_node);
1129 draw_text_real (object, cr, screen_flag, record, color);
1131 gl_debug (DEBUG_LABEL, "END");
1135 /*****************************************************************************/
1136 /* Draw shadow method. */
1137 /*****************************************************************************/
1139 draw_shadow (glLabelObject *object,
1141 gboolean screen_flag,
1142 glMergeRecord *record)
1144 glColorNode *color_node;
1146 glColorNode *shadow_color_node;
1147 gdouble shadow_opacity;
1150 gl_debug (DEBUG_LABEL, "START");
1152 color_node = gl_label_object_get_text_color (object);
1153 color = gl_color_node_expand (color_node, record);
1154 if (color_node->field_flag && screen_flag)
1156 color = GL_COLOR_MERGE_DEFAULT;
1158 gl_color_node_free (&color_node);
1160 shadow_color_node = gl_label_object_get_shadow_color (object);
1161 if (shadow_color_node->field_flag)
1163 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
1165 shadow_opacity = gl_label_object_get_shadow_opacity (object);
1166 shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
1167 gl_color_node_free (&shadow_color_node);
1169 draw_text_real (object, cr, screen_flag, record, shadow_color);
1171 gl_debug (DEBUG_LABEL, "END");
1175 /*****************************************************************************/
1177 /*****************************************************************************/
1179 draw_text_real (glLabelObject *object,
1181 gboolean screen_flag,
1182 glMergeRecord *record,
1185 gl_debug (DEBUG_LABEL, "START");
1187 set_text_path (GL_LABEL_TEXT (object), cr, screen_flag, record);
1189 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
1192 gl_debug (DEBUG_LABEL, "END");
1196 /*****************************************************************************/
1197 /* Is object at coordinates? */
1198 /*****************************************************************************/
1200 object_at (glLabelObject *object,
1207 gl_label_object_get_size (object, &w, &h);
1209 if ( (x >= 0) && (x <= w) && (y >= 0) && (y <= h) )
1211 set_text_path (GL_LABEL_TEXT (object), cr, TRUE, NULL);
1212 if (cairo_in_fill (cr, x, y))
1218 if (gl_label_object_is_selected (object))
1220 cairo_rectangle (cr, 0, 0, w, h);
1221 if (cairo_in_stroke (cr, x, y))
1231 /*****************************************************************************/
1232 /* Draw text style handles. */
1233 /*****************************************************************************/
1235 draw_handles (glLabelObject *object,
1239 gdouble scale_x, scale_y;
1240 gdouble dashes[2] = { 2, 2 };
1242 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1246 cairo_rectangle (cr, 0, 0, w, h);
1250 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1251 cairo_scale (cr, scale_x, scale_y);
1253 cairo_set_dash (cr, dashes, 2, 0);
1254 cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS);
1255 cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
1260 gl_label_object_draw_handles_box (object, cr);
1267 * Local Variables: -- emacs
1269 * c-basic-offset: 8 -- emacs
1270 * tab-width: 8 -- emacs
1271 * indent-tabs-mode: nil -- emacs