No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * $Id$
4 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
5 * All rights reserved.
6 *
7 * This file is part of the Gnome Library.
8 *
9 * The Gnome Library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * The Gnome Library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with the Gnome Library; see the file COPYING.LIB. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
23 */
24 /*
25 @NOTATION@
26 */
27 /* Text item type for GnomeCanvas widget
28 *
29 * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas
30 * widget. Tk is copyrighted by the Regents of the University of California,
31 * Sun Microsystems, and other parties.
32 *
33 *
34 * Author: Federico Mena <federico@nuclecu.unam.mx>
35 * Port to Pango co-done by Gergő Érdi <cactus@cactus.rulez.org>
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <math.h>
43 #include <string.h>
44 #include "gnome-canvas-text.h"
45
46 #include "gnome-canvas-util.h"
47 #include "gnome-canvas-i18n.h"
48
49 /* Object argument IDs */
50 enum {
51 PROP_0,
52
53 /* Text contents */
54 PROP_TEXT,
55 PROP_MARKUP,
56
57 /* Position */
58 PROP_X,
59 PROP_Y,
60
61 /* Font */
62 PROP_FONT,
63 PROP_FONT_DESC,
64 PROP_FAMILY, PROP_FAMILY_SET,
65
66 /* Style */
67 PROP_ATTRIBUTES,
68 PROP_STYLE, PROP_STYLE_SET,
69 PROP_VARIANT, PROP_VARIANT_SET,
70 PROP_WEIGHT, PROP_WEIGHT_SET,
71 PROP_STRETCH, PROP_STRETCH_SET,
72 PROP_SIZE, PROP_SIZE_SET,
73 PROP_SIZE_POINTS,
74 PROP_STRIKETHROUGH, PROP_STRIKETHROUGH_SET,
75 PROP_UNDERLINE, PROP_UNDERLINE_SET,
76 PROP_RISE, PROP_RISE_SET,
77 PROP_SCALE, PROP_SCALE_SET,
78
79 /* Clipping */
80 PROP_JUSTIFICATION,
81 PROP_CLIP_WIDTH,
82 PROP_CLIP_HEIGHT,
83 PROP_CLIP,
84 PROP_X_OFFSET,
85 PROP_Y_OFFSET,
86
87 /* Coloring */
88 PROP_FILL_COLOR,
89 PROP_FILL_COLOR_GDK,
90 PROP_FILL_COLOR_RGBA,
91
92 /* Rendered size accessors */
93 PROP_TEXT_WIDTH,
94 PROP_TEXT_HEIGHT
95 };
96
97 static void gnome_canvas_text_dispose (GnomeCanvasItem *object);
98 static void gnome_canvas_text_set_property (GObject *object,
99 guint param_id,
100 const GValue *value,
101 GParamSpec *pspec);
102 static void gnome_canvas_text_get_property (GObject *object,
103 guint param_id,
104 GValue *value,
105 GParamSpec *pspec);
106
107 static void gnome_canvas_text_update (GnomeCanvasItem *item,
108 const cairo_matrix_t *matrix,
109 gint flags);
110 static void gnome_canvas_text_draw (GnomeCanvasItem *item, cairo_t *cr,
111 gint x, gint y, gint width, gint height);
112 static GnomeCanvasItem *gnome_canvas_text_point (GnomeCanvasItem *item,
113 gdouble x,
114 gdouble y,
115 gint cx,
116 gint cy);
117 static void gnome_canvas_text_bounds (GnomeCanvasItem *item,
118 gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2);
119
120 static void gnome_canvas_text_set_markup (GnomeCanvasText *textitem,
121 const gchar *markup);
122
123 static void gnome_canvas_text_set_font_desc (GnomeCanvasText *textitem,
124 PangoFontDescription *font_desc);
125
126 static void gnome_canvas_text_apply_font_desc (GnomeCanvasText *textitem);
127 static void gnome_canvas_text_apply_attributes (GnomeCanvasText *textitem);
128
129 static void add_attr (PangoAttrList *attr_list,
130 PangoAttribute *attr);
131
132 G_DEFINE_TYPE (
133 GnomeCanvasText,
134 gnome_canvas_text,
135 GNOME_TYPE_CANVAS_ITEM)
136
137 /* Class initialization function for the text item */
138 static void
139 gnome_canvas_text_class_init (GnomeCanvasTextClass *class)
140 {
141 GObjectClass *gobject_class;
142 GnomeCanvasItemClass *item_class;
143
144 gobject_class = (GObjectClass *) class;
145 item_class = (GnomeCanvasItemClass *) class;
146
147 gobject_class->set_property = gnome_canvas_text_set_property;
148 gobject_class->get_property = gnome_canvas_text_get_property;
149
150 /* Text */
151 g_object_class_install_property (
152 gobject_class,
153 PROP_TEXT,
154 g_param_spec_string (
155 "text",
156 "Text",
157 "Text to render",
158 NULL,
159 G_PARAM_READABLE |
160 G_PARAM_WRITABLE));
161
162 g_object_class_install_property (
163 gobject_class,
164 PROP_MARKUP,
165 g_param_spec_string (
166 "markup",
167 "Markup",
168 "Marked up text to render",
169 NULL,
170 G_PARAM_WRITABLE));
171
172 /* Position */
173 g_object_class_install_property (
174 gobject_class,
175 PROP_X,
176 g_param_spec_double (
177 "x",
178 NULL,
179 NULL,
180 -G_MAXDOUBLE,
181 G_MAXDOUBLE,
182 0.0,
183 G_PARAM_READABLE |
184 G_PARAM_WRITABLE));
185
186 g_object_class_install_property (
187 gobject_class,
188 PROP_Y,
189 g_param_spec_double (
190 "y",
191 NULL,
192 NULL,
193 -G_MAXDOUBLE,
194 G_MAXDOUBLE,
195 0.0,
196 G_PARAM_READABLE |
197 G_PARAM_WRITABLE));
198
199 /* Font */
200 g_object_class_install_property (
201 gobject_class,
202 PROP_FONT,
203 g_param_spec_string (
204 "font",
205 "Font",
206 "Font description as a string",
207 NULL,
208 G_PARAM_READABLE |
209 G_PARAM_WRITABLE));
210
211 g_object_class_install_property (
212 gobject_class,
213 PROP_FONT_DESC,
214 g_param_spec_boxed (
215 "font_desc",
216 "Font description",
217 "Font description as a PangoFontDescription struct",
218 PANGO_TYPE_FONT_DESCRIPTION,
219 G_PARAM_READABLE |
220 G_PARAM_WRITABLE));
221
222 g_object_class_install_property (
223 gobject_class,
224 PROP_FAMILY,
225 g_param_spec_string (
226 "family",
227 "Font family",
228 "Name of the font family, e.g. "
229 "Sans, Helvetica, Times, Monospace",
230 NULL,
231 G_PARAM_READABLE |
232 G_PARAM_WRITABLE));
233
234 /* Style */
235 g_object_class_install_property (
236 gobject_class,
237 PROP_ATTRIBUTES,
238 g_param_spec_boxed (
239 "attributes",
240 NULL,
241 NULL,
242 PANGO_TYPE_ATTR_LIST,
243 G_PARAM_READABLE |
244 G_PARAM_WRITABLE));
245
246 g_object_class_install_property (
247 gobject_class,
248 PROP_STYLE,
249 g_param_spec_enum (
250 "style",
251 "Font style",
252 "Font style",
253 PANGO_TYPE_STYLE,
254 PANGO_STYLE_NORMAL,
255 G_PARAM_READABLE |
256 G_PARAM_WRITABLE));
257
258 g_object_class_install_property (
259 gobject_class,
260 PROP_VARIANT,
261 g_param_spec_enum (
262 "variant",
263 "Font variant",
264 "Font variant",
265 PANGO_TYPE_VARIANT,
266 PANGO_VARIANT_NORMAL,
267 G_PARAM_READABLE |
268 G_PARAM_WRITABLE));
269
270 g_object_class_install_property (
271 gobject_class,
272 PROP_WEIGHT,
273 g_param_spec_int (
274 "weight",
275 "Font weight",
276 "Font weight",
277 0,
278 G_MAXINT,
279 PANGO_WEIGHT_NORMAL,
280 G_PARAM_READABLE |
281 G_PARAM_WRITABLE));
282
283 g_object_class_install_property (
284 gobject_class,
285 PROP_STRETCH,
286 g_param_spec_enum (
287 "stretch",
288 "Font stretch",
289 "Font stretch",
290 PANGO_TYPE_STRETCH,
291 PANGO_STRETCH_NORMAL,
292 G_PARAM_READABLE |
293 G_PARAM_WRITABLE));
294
295 g_object_class_install_property (
296 gobject_class,
297 PROP_SIZE,
298 g_param_spec_int (
299 "size",
300 "Font size",
301 "Font size (as a multiple of PANGO_SCALE, "
302 "eg. 12*PANGO_SCALE for a 12pt font size)",
303 0,
304 G_MAXINT,
305 0,
306 G_PARAM_READABLE |
307 G_PARAM_WRITABLE));
308
309 g_object_class_install_property (
310 gobject_class,
311 PROP_SIZE_POINTS,
312 g_param_spec_double (
313 "size_points",
314 "Font points",
315 "Font size in points (eg. 12 for a 12pt font size)",
316 0.0,
317 G_MAXDOUBLE,
318 0.0,
319 G_PARAM_READABLE |
320 G_PARAM_WRITABLE));
321
322 g_object_class_install_property (
323 gobject_class,
324 PROP_RISE,
325 g_param_spec_int (
326 "rise",
327 "Rise",
328 "Offset of text above the baseline "
329 "(below the baseline if rise is negative)",
330 -G_MAXINT,
331 G_MAXINT,
332 0,
333 G_PARAM_READABLE |
334 G_PARAM_WRITABLE));
335
336 g_object_class_install_property (
337 gobject_class,
338 PROP_STRIKETHROUGH,
339 g_param_spec_boolean (
340 "strikethrough",
341 "Strikethrough",
342 "Whether to strike through the text",
343 FALSE,
344 G_PARAM_READABLE |
345 G_PARAM_WRITABLE));
346
347 g_object_class_install_property (
348 gobject_class,
349 PROP_UNDERLINE,
350 g_param_spec_enum (
351 "underline",
352 "Underline",
353 "Style of underline for this text",
354 PANGO_TYPE_UNDERLINE,
355 PANGO_UNDERLINE_NONE,
356 G_PARAM_READABLE |
357 G_PARAM_WRITABLE));
358
359 g_object_class_install_property (
360 gobject_class,
361 PROP_SCALE,
362 g_param_spec_double (
363 "scale",
364 "Scale",
365 "Size of font, relative to default size",
366 0.0,
367 G_MAXDOUBLE,
368 1.0,
369 G_PARAM_READABLE |
370 G_PARAM_WRITABLE));
371
372 g_object_class_install_property (
373 gobject_class,
374 PROP_JUSTIFICATION,
375 g_param_spec_enum (
376 "justification",
377 NULL,
378 NULL,
379 GTK_TYPE_JUSTIFICATION,
380 GTK_JUSTIFY_LEFT,
381 G_PARAM_READABLE |
382 G_PARAM_WRITABLE));
383
384 g_object_class_install_property (
385 gobject_class,
386 PROP_CLIP_WIDTH,
387 g_param_spec_double (
388 "clip_width",
389 NULL,
390 NULL,
391 -G_MAXDOUBLE,
392 G_MAXDOUBLE,
393 0.0,
394 G_PARAM_READABLE |
395 G_PARAM_WRITABLE));
396
397 g_object_class_install_property (
398 gobject_class,
399 PROP_CLIP_HEIGHT,
400 g_param_spec_double (
401 "clip_height",
402 NULL,
403 NULL,
404 -G_MAXDOUBLE,
405 G_MAXDOUBLE,
406 0.0,
407 G_PARAM_READABLE |
408 G_PARAM_WRITABLE));
409
410 g_object_class_install_property (
411 gobject_class,
412 PROP_CLIP,
413 g_param_spec_boolean (
414 "clip",
415 NULL,
416 NULL,
417 FALSE,
418 G_PARAM_READABLE |
419 G_PARAM_WRITABLE));
420
421 g_object_class_install_property (
422 gobject_class,
423 PROP_X_OFFSET,
424 g_param_spec_double (
425 "x_offset",
426 NULL,
427 NULL,
428 -G_MAXDOUBLE,
429 G_MAXDOUBLE,
430 0.0,
431 G_PARAM_READABLE |
432 G_PARAM_WRITABLE));
433
434 g_object_class_install_property (
435 gobject_class,
436 PROP_Y_OFFSET,
437 g_param_spec_double (
438 "y_offset",
439 NULL,
440 NULL,
441 -G_MAXDOUBLE,
442 G_MAXDOUBLE,
443 0.0,
444 G_PARAM_READABLE |
445 G_PARAM_WRITABLE));
446
447 g_object_class_install_property (
448 gobject_class,
449 PROP_FILL_COLOR,
450 g_param_spec_string (
451 "fill_color",
452 "Color",
453 "Text color, as string",
454 NULL,
455 G_PARAM_WRITABLE));
456
457 g_object_class_install_property (
458 gobject_class,
459 PROP_FILL_COLOR_GDK,
460 g_param_spec_boxed (
461 "fill_color_gdk",
462 "Color",
463 "Text color, as a GdkColor",
464 GDK_TYPE_COLOR,
465 G_PARAM_WRITABLE));
466
467 g_object_class_install_property (
468 gobject_class,
469 PROP_FILL_COLOR_RGBA,
470 g_param_spec_uint (
471 "fill_color_rgba",
472 "Color",
473 "Text color, as an R/G/B/A combined integer",
474 0, G_MAXUINT, 0,
475 G_PARAM_READABLE |
476 G_PARAM_WRITABLE));
477
478 g_object_class_install_property (
479 gobject_class,
480 PROP_TEXT_WIDTH,
481 g_param_spec_double (
482 "text_width",
483 "Text width",
484 "Width of the rendered text",
485 0.0, G_MAXDOUBLE, 0.0,
486 G_PARAM_READABLE));
487
488 g_object_class_install_property (
489 gobject_class,
490 PROP_TEXT_HEIGHT,
491 g_param_spec_double (
492 "text_height",
493 "Text height",
494 "Height of the rendered text",
495 0.0, G_MAXDOUBLE, 0.0,
496 G_PARAM_READABLE));
497
498 /* Style props are set (explicitly applied) or not */
499 #define ADD_SET_PROP(propname, propval, nick, blurb) \
500 g_object_class_install_property ( \
501 gobject_class, propval, \
502 g_param_spec_boolean ( \
503 propname, nick, blurb, FALSE, \
504 G_PARAM_READABLE | G_PARAM_WRITABLE))
505
506 ADD_SET_PROP (
507 "family_set",
508 PROP_FAMILY_SET,
509 "Font family set",
510 "Whether this tag affects the font family");
511
512 ADD_SET_PROP (
513 "style_set",
514 PROP_STYLE_SET,
515 "Font style set",
516 "Whether this tag affects the font style");
517
518 ADD_SET_PROP (
519 "variant_set",
520 PROP_VARIANT_SET,
521 "Font variant set",
522 "Whether this tag affects the font variant");
523
524 ADD_SET_PROP (
525 "weight_set",
526 PROP_WEIGHT_SET,
527 "Font weight set",
528 "Whether this tag affects the font weight");
529
530 ADD_SET_PROP (
531 "stretch_set",
532 PROP_STRETCH_SET,
533 "Font stretch set",
534 "Whether this tag affects the font stretch");
535
536 ADD_SET_PROP (
537 "size_set",
538 PROP_SIZE_SET,
539 "Font size set",
540 "Whether this tag affects the font size");
541
542 ADD_SET_PROP (
543 "rise_set",
544 PROP_RISE_SET,
545 "Rise set",
546 "Whether this tag affects the rise");
547
548 ADD_SET_PROP (
549 "strikethrough_set",
550 PROP_STRIKETHROUGH_SET,
551 "Strikethrough set",
552 "Whether this tag affects strikethrough");
553
554 ADD_SET_PROP (
555 "underline_set",
556 PROP_UNDERLINE_SET,
557 "Underline set",
558 "Whether this tag affects underlining");
559
560 ADD_SET_PROP (
561 "scale_set",
562 PROP_SCALE_SET,
563 "Scale set",
564 "Whether this tag affects font scaling");
565 #undef ADD_SET_PROP
566
567 item_class->dispose = gnome_canvas_text_dispose;
568 item_class->update = gnome_canvas_text_update;
569 item_class->draw = gnome_canvas_text_draw;
570 item_class->point = gnome_canvas_text_point;
571 item_class->bounds = gnome_canvas_text_bounds;
572 }
573
574 /* Object initialization function for the text item */
575 static void
576 gnome_canvas_text_init (GnomeCanvasText *text)
577 {
578 text->x = 0.0;
579 text->y = 0.0;
580 text->justification = GTK_JUSTIFY_LEFT;
581 text->clip_width = 0.0;
582 text->clip_height = 0.0;
583 text->xofs = 0.0;
584 text->yofs = 0.0;
585 text->layout = NULL;
586
587 text->font_desc = NULL;
588
589 text->underline = PANGO_UNDERLINE_NONE;
590 text->strikethrough = FALSE;
591 text->rise = 0;
592
593 text->underline_set = FALSE;
594 text->strike_set = FALSE;
595 text->rise_set = FALSE;
596 }
597
598 /* Dispose handler for the text item */
599 static void
600 gnome_canvas_text_dispose (GnomeCanvasItem *object)
601 {
602 GnomeCanvasText *text;
603
604 g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
605
606 text = GNOME_CANVAS_TEXT (object);
607
608 g_free (text->text);
609 text->text = NULL;
610
611 if (text->layout != NULL) {
612 g_object_unref (text->layout);
613 text->layout = NULL;
614 }
615
616 if (text->font_desc != NULL) {
617 pango_font_description_free (text->font_desc);
618 text->font_desc = NULL;
619 }
620
621 if (text->attr_list != NULL) {
622 pango_attr_list_unref (text->attr_list);
623 text->attr_list = NULL;
624 }
625
626 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_text_parent_class)->
627 dispose (object);
628 }
629
630 static void
631 get_bounds (GnomeCanvasText *text,
632 gdouble *px1,
633 gdouble *py1,
634 gdouble *px2,
635 gdouble *py2)
636 {
637 GnomeCanvasItem *item;
638 gdouble wx, wy;
639
640 item = GNOME_CANVAS_ITEM (text);
641
642 /* Get canvas pixel coordinates for text position */
643
644 wx = text->x;
645 wy = text->y;
646 gnome_canvas_item_i2w (item, &wx, &wy);
647 gnome_canvas_w2c (
648 item->canvas, wx + text->xofs, wy + text->yofs,
649 &text->cx, &text->cy);
650
651 /* Get canvas pixel coordinates for clip rectangle position */
652
653 gnome_canvas_w2c (item->canvas, wx, wy, &text->clip_cx, &text->clip_cy);
654 text->clip_cwidth = text->clip_width;
655 text->clip_cheight = text->clip_height;
656
657 /* Bounds */
658
659 if (text->clip) {
660 *px1 = text->clip_cx;
661 *py1 = text->clip_cy;
662 *px2 = text->clip_cx + text->clip_cwidth;
663 *py2 = text->clip_cy + text->clip_cheight;
664 } else {
665 *px1 = text->cx;
666 *py1 = text->cy;
667 *px2 = text->cx + text->max_width;
668 *py2 = text->cy + text->height;
669 }
670 }
671
672 static PangoFontMask
673 get_property_font_set_mask (guint property_id)
674 {
675 switch (property_id) {
676 case PROP_FAMILY_SET:
677 return PANGO_FONT_MASK_FAMILY;
678 case PROP_STYLE_SET:
679 return PANGO_FONT_MASK_STYLE;
680 case PROP_VARIANT_SET:
681 return PANGO_FONT_MASK_VARIANT;
682 case PROP_WEIGHT_SET:
683 return PANGO_FONT_MASK_WEIGHT;
684 case PROP_STRETCH_SET:
685 return PANGO_FONT_MASK_STRETCH;
686 case PROP_SIZE_SET:
687 return PANGO_FONT_MASK_SIZE;
688 }
689
690 return 0;
691 }
692
693 static void
694 ensure_font (GnomeCanvasText *text)
695 {
696 if (!text->font_desc)
697 text->font_desc = pango_font_description_new ();
698 }
699
700 /* Set_arg handler for the text item */
701 static void
702 gnome_canvas_text_set_property (GObject *object,
703 guint param_id,
704 const GValue *value,
705 GParamSpec *pspec)
706 {
707 GnomeCanvasItem *item;
708 GnomeCanvasText *text;
709 GdkColor *pcolor;
710 PangoAlignment align;
711
712 g_return_if_fail (object != NULL);
713 g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
714
715 item = GNOME_CANVAS_ITEM (object);
716 text = GNOME_CANVAS_TEXT (object);
717
718 if (!text->layout)
719 text->layout = pango_layout_new (
720 gtk_widget_get_pango_context (
721 GTK_WIDGET (item->canvas)));
722
723 switch (param_id) {
724 case PROP_TEXT:
725 g_free (text->text);
726
727 text->text = g_value_dup_string (value);
728 pango_layout_set_text (text->layout, text->text, -1);
729
730 break;
731
732 case PROP_MARKUP:
733 gnome_canvas_text_set_markup (
734 text, g_value_get_string (value));
735 break;
736
737 case PROP_X:
738 text->x = g_value_get_double (value);
739 break;
740
741 case PROP_Y:
742 text->y = g_value_get_double (value);
743 break;
744
745 case PROP_FONT: {
746 const gchar *font_name;
747 PangoFontDescription *font_desc;
748
749 font_name = g_value_get_string (value);
750 if (font_name)
751 font_desc = pango_font_description_from_string (font_name);
752 else
753 font_desc = NULL;
754
755 gnome_canvas_text_set_font_desc (text, font_desc);
756 if (font_desc)
757 pango_font_description_free (font_desc);
758
759 break;
760 }
761
762 case PROP_FONT_DESC:
763 gnome_canvas_text_set_font_desc (text, g_value_peek_pointer (value));
764 break;
765
766 case PROP_FAMILY:
767 case PROP_STYLE:
768 case PROP_VARIANT:
769 case PROP_WEIGHT:
770 case PROP_STRETCH:
771 case PROP_SIZE:
772 case PROP_SIZE_POINTS:
773 ensure_font (text);
774
775 switch (param_id) {
776 case PROP_FAMILY:
777 pango_font_description_set_family (
778 text->font_desc,
779 g_value_get_string (value));
780 break;
781 case PROP_STYLE:
782 pango_font_description_set_style (
783 text->font_desc,
784 g_value_get_enum (value));
785 break;
786 case PROP_VARIANT:
787 pango_font_description_set_variant (
788 text->font_desc,
789 g_value_get_enum (value));
790 break;
791 case PROP_WEIGHT:
792 pango_font_description_set_weight (
793 text->font_desc,
794 g_value_get_int (value));
795 break;
796 case PROP_STRETCH:
797 pango_font_description_set_stretch (
798 text->font_desc,
799 g_value_get_enum (value));
800 break;
801 case PROP_SIZE:
802 /* FIXME: This is bogus! It should be pixels, not points/PANGO_SCALE! */
803 pango_font_description_set_size (
804 text->font_desc,
805 g_value_get_int (value));
806 break;
807 case PROP_SIZE_POINTS:
808 pango_font_description_set_size (
809 text->font_desc,
810 g_value_get_double (value) * PANGO_SCALE);
811 break;
812 }
813
814 gnome_canvas_text_apply_font_desc (text);
815 break;
816
817 case PROP_FAMILY_SET:
818 case PROP_STYLE_SET:
819 case PROP_VARIANT_SET:
820 case PROP_WEIGHT_SET:
821 case PROP_STRETCH_SET:
822 case PROP_SIZE_SET:
823 if (!g_value_get_boolean (value) && text->font_desc)
824 pango_font_description_unset_fields (
825 text->font_desc,
826 get_property_font_set_mask (param_id));
827 break;
828
829 case PROP_SCALE:
830 text->scale = g_value_get_double (value);
831 text->scale_set = TRUE;
832
833 gnome_canvas_text_apply_font_desc (text);
834 break;
835
836 case PROP_SCALE_SET:
837 text->scale_set = g_value_get_boolean (value);
838
839 gnome_canvas_text_apply_font_desc (text);
840 break;
841
842 case PROP_UNDERLINE:
843 text->underline = g_value_get_enum (value);
844 text->underline_set = TRUE;
845
846 gnome_canvas_text_apply_attributes (text);
847 break;
848
849 case PROP_UNDERLINE_SET:
850 text->underline_set = g_value_get_boolean (value);
851
852 gnome_canvas_text_apply_attributes (text);
853 break;
854
855 case PROP_STRIKETHROUGH:
856 text->strikethrough = g_value_get_boolean (value);
857 text->strike_set = TRUE;
858
859 gnome_canvas_text_apply_attributes (text);
860 break;
861
862 case PROP_STRIKETHROUGH_SET:
863 text->strike_set = g_value_get_boolean (value);
864
865 gnome_canvas_text_apply_attributes (text);
866 break;
867
868 case PROP_RISE:
869 text->rise = g_value_get_int (value);
870 text->rise_set = TRUE;
871
872 gnome_canvas_text_apply_attributes (text);
873 break;
874
875 case PROP_RISE_SET:
876 text->rise_set = TRUE;
877
878 gnome_canvas_text_apply_attributes (text);
879 break;
880
881 case PROP_ATTRIBUTES:
882 if (text->attr_list)
883 pango_attr_list_unref (text->attr_list);
884
885 text->attr_list = g_value_peek_pointer (value);
886 pango_attr_list_ref (text->attr_list);
887
888 gnome_canvas_text_apply_attributes (text);
889 break;
890
891 case PROP_JUSTIFICATION:
892 text->justification = g_value_get_enum (value);
893
894 switch (text->justification) {
895 case GTK_JUSTIFY_LEFT:
896 align = PANGO_ALIGN_LEFT;
897 break;
898 case GTK_JUSTIFY_CENTER:
899 align = PANGO_ALIGN_CENTER;
900 break;
901 case GTK_JUSTIFY_RIGHT:
902 align = PANGO_ALIGN_RIGHT;
903 break;
904 default:
905 /* GTK_JUSTIFY_FILL isn't supported yet. */
906 align = PANGO_ALIGN_LEFT;
907 break;
908 }
909 pango_layout_set_alignment (text->layout, align);
910 break;
911
912 case PROP_CLIP_WIDTH:
913 text->clip_width = fabs (g_value_get_double (value));
914 break;
915
916 case PROP_CLIP_HEIGHT:
917 text->clip_height = fabs (g_value_get_double (value));
918 break;
919
920 case PROP_CLIP:
921 text->clip = g_value_get_boolean (value);
922 break;
923
924 case PROP_X_OFFSET:
925 text->xofs = g_value_get_double (value);
926 break;
927
928 case PROP_Y_OFFSET:
929 text->yofs = g_value_get_double (value);
930 break;
931
932 case PROP_FILL_COLOR: {
933 const gchar *color_name;
934
935 color_name = g_value_get_string (value);
936 if (color_name) {
937 GdkColor color;
938 gdk_color_parse (color_name, &color);
939
940 text->rgba = ((color.red & 0xff00) << 16 |
941 (color.green & 0xff00) << 8 |
942 (color.blue & 0xff00) |
943 0xff);
944 }
945 break;
946 }
947
948 case PROP_FILL_COLOR_GDK:
949 pcolor = g_value_get_boxed (value);
950 if (pcolor) {
951 text->rgba = ((pcolor->red & 0xff00) << 16 |
952 (pcolor->green & 0xff00) << 8|
953 (pcolor->blue & 0xff00) |
954 0xff);
955 } else {
956 text->rgba = 0;
957 }
958 break;
959
960 case PROP_FILL_COLOR_RGBA:
961 text->rgba = g_value_get_uint (value);
962 break;
963
964 default:
965 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
966 break;
967 }
968
969 /* Calculate text dimensions */
970
971 if (text->layout)
972 pango_layout_get_pixel_size (
973 text->layout,
974 &text->max_width,
975 &text->height);
976 else {
977 text->max_width = 0;
978 text->height = 0;
979 }
980
981 gnome_canvas_item_request_update (item);
982 }
983
984 /* Get_arg handler for the text item */
985 static void
986 gnome_canvas_text_get_property (GObject *object,
987 guint param_id,
988 GValue *value,
989 GParamSpec *pspec)
990 {
991 GnomeCanvasText *text;
992
993 g_return_if_fail (object != NULL);
994 g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
995
996 text = GNOME_CANVAS_TEXT (object);
997
998 switch (param_id) {
999 case PROP_TEXT:
1000 g_value_set_string (value, text->text);
1001 break;
1002
1003 case PROP_X:
1004 g_value_set_double (value, text->x);
1005 break;
1006
1007 case PROP_Y:
1008 g_value_set_double (value, text->y);
1009 break;
1010
1011 case PROP_FONT:
1012 case PROP_FONT_DESC:
1013 case PROP_FAMILY:
1014 case PROP_STYLE:
1015 case PROP_VARIANT:
1016 case PROP_WEIGHT:
1017 case PROP_STRETCH:
1018 case PROP_SIZE:
1019 case PROP_SIZE_POINTS:
1020 ensure_font (text);
1021
1022 switch (param_id) {
1023 case PROP_FONT:
1024 {
1025 /* FIXME GValue imposes a totally gratuitous string
1026 * copy here, we could just hand off string
1027 * ownership. */
1028 gchar *str;
1029
1030 str = pango_font_description_to_string (text->font_desc);
1031 g_value_set_string (value, str);
1032 g_free (str);
1033
1034 break;
1035 }
1036
1037 case PROP_FONT_DESC:
1038 g_value_set_boxed (value, text->font_desc);
1039 break;
1040
1041 case PROP_FAMILY:
1042 g_value_set_string (
1043 value,
1044 pango_font_description_get_family (
1045 text->font_desc));
1046 break;
1047
1048 case PROP_STYLE:
1049 g_value_set_enum (
1050 value,
1051 pango_font_description_get_style (
1052 text->font_desc));
1053 break;
1054
1055 case PROP_VARIANT:
1056 g_value_set_enum (
1057 value,
1058 pango_font_description_get_variant (
1059 text->font_desc));
1060 break;
1061
1062 case PROP_WEIGHT:
1063 g_value_set_int (
1064 value,
1065 pango_font_description_get_weight (
1066 text->font_desc));
1067 break;
1068
1069 case PROP_STRETCH:
1070 g_value_set_enum (
1071 value,
1072 pango_font_description_get_stretch (
1073 text->font_desc));
1074 break;
1075
1076 case PROP_SIZE:
1077 g_value_set_int (
1078 value,
1079 pango_font_description_get_size (
1080 text->font_desc));
1081 break;
1082
1083 case PROP_SIZE_POINTS:
1084 g_value_set_double (
1085 value, ((gdouble)
1086 pango_font_description_get_size (
1087 text->font_desc)) / (gdouble) PANGO_SCALE);
1088 break;
1089 }
1090 break;
1091
1092 case PROP_FAMILY_SET:
1093 case PROP_STYLE_SET:
1094 case PROP_VARIANT_SET:
1095 case PROP_WEIGHT_SET:
1096 case PROP_STRETCH_SET:
1097 case PROP_SIZE_SET:
1098 {
1099 PangoFontMask set_mask = text->font_desc ?
1100 pango_font_description_get_set_fields (text->font_desc) : 0;
1101 PangoFontMask test_mask = get_property_font_set_mask (param_id);
1102 g_value_set_boolean (value, (set_mask & test_mask) != 0);
1103
1104 break;
1105 }
1106
1107 case PROP_SCALE:
1108 g_value_set_double (value, text->scale);
1109 break;
1110 case PROP_SCALE_SET:
1111 g_value_set_boolean (value, text->scale_set);
1112 break;
1113
1114 case PROP_UNDERLINE:
1115 g_value_set_enum (value, text->underline);
1116 break;
1117 case PROP_UNDERLINE_SET:
1118 g_value_set_boolean (value, text->underline_set);
1119 break;
1120
1121 case PROP_STRIKETHROUGH:
1122 g_value_set_boolean (value, text->strikethrough);
1123 break;
1124 case PROP_STRIKETHROUGH_SET:
1125 g_value_set_boolean (value, text->strike_set);
1126 break;
1127
1128 case PROP_RISE:
1129 g_value_set_int (value, text->rise);
1130 break;
1131 case PROP_RISE_SET:
1132 g_value_set_boolean (value, text->rise_set);
1133 break;
1134
1135 case PROP_ATTRIBUTES:
1136 g_value_set_boxed (value, text->attr_list);
1137 break;
1138
1139 case PROP_JUSTIFICATION:
1140 g_value_set_enum (value, text->justification);
1141 break;
1142
1143 case PROP_CLIP_WIDTH:
1144 g_value_set_double (value, text->clip_width);
1145 break;
1146
1147 case PROP_CLIP_HEIGHT:
1148 g_value_set_double (value, text->clip_height);
1149 break;
1150
1151 case PROP_CLIP:
1152 g_value_set_boolean (value, text->clip);
1153 break;
1154
1155 case PROP_X_OFFSET:
1156 g_value_set_double (value, text->xofs);
1157 break;
1158
1159 case PROP_Y_OFFSET:
1160 g_value_set_double (value, text->yofs);
1161 break;
1162
1163 case PROP_FILL_COLOR_RGBA:
1164 g_value_set_uint (value, text->rgba);
1165 break;
1166
1167 case PROP_TEXT_WIDTH:
1168 g_value_set_double (value, text->max_width);
1169 break;
1170
1171 case PROP_TEXT_HEIGHT:
1172 g_value_set_double (value, text->height);
1173 break;
1174
1175 default:
1176 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1177 break;
1178 }
1179 }
1180
1181 /* */
1182 static void
1183 gnome_canvas_text_apply_font_desc (GnomeCanvasText *text)
1184 {
1185 PangoFontDescription *font_desc;
1186 GtkWidget *widget;
1187 GtkStyle *style;
1188
1189 widget = GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas);
1190 style = gtk_widget_get_style (widget);
1191 font_desc = pango_font_description_copy (style->font_desc);
1192
1193 if (text->font_desc)
1194 pango_font_description_merge (font_desc, text->font_desc, TRUE);
1195
1196 pango_layout_set_font_description (text->layout, font_desc);
1197 pango_font_description_free (font_desc);
1198 }
1199
1200 static void
1201 add_attr (PangoAttrList *attr_list,
1202 PangoAttribute *attr)
1203 {
1204 attr->start_index = 0;
1205 attr->end_index = G_MAXINT;
1206
1207 pango_attr_list_insert (attr_list, attr);
1208 }
1209
1210 /* */
1211 static void
1212 gnome_canvas_text_apply_attributes (GnomeCanvasText *text)
1213 {
1214 PangoAttrList *attr_list;
1215
1216 if (text->attr_list)
1217 attr_list = pango_attr_list_copy (text->attr_list);
1218 else
1219 attr_list = pango_attr_list_new ();
1220
1221 if (text->underline_set)
1222 add_attr (attr_list, pango_attr_underline_new (text->underline));
1223 if (text->strike_set)
1224 add_attr (attr_list, pango_attr_strikethrough_new (text->strikethrough));
1225 if (text->rise_set)
1226 add_attr (attr_list, pango_attr_rise_new (text->rise));
1227
1228 pango_layout_set_attributes (text->layout, attr_list);
1229 pango_attr_list_unref (attr_list);
1230 }
1231
1232 static void
1233 gnome_canvas_text_set_font_desc (GnomeCanvasText *text,
1234 PangoFontDescription *font_desc)
1235 {
1236 if (text->font_desc)
1237 pango_font_description_free (text->font_desc);
1238
1239 if (font_desc)
1240 text->font_desc = pango_font_description_copy (font_desc);
1241 else
1242 text->font_desc = NULL;
1243
1244 gnome_canvas_text_apply_font_desc (text);
1245 }
1246
1247 /* Setting the text from a Pango markup string */
1248 static void
1249 gnome_canvas_text_set_markup (GnomeCanvasText *textitem,
1250 const gchar *markup)
1251 {
1252 PangoAttrList *attr_list = NULL;
1253 gchar *text = NULL;
1254 GError *error = NULL;
1255
1256 if (markup && !pango_parse_markup (markup, -1,
1257 0,
1258 &attr_list, &text, NULL,
1259 &error))
1260 {
1261 g_warning (
1262 "Failed to set cell text from markup due to "
1263 "error parsing markup: %s", error->message);
1264 g_error_free (error);
1265 return;
1266 }
1267
1268 g_free (textitem->text);
1269 if (textitem->attr_list)
1270 pango_attr_list_unref (textitem->attr_list);
1271
1272 textitem->text = text;
1273 textitem->attr_list = attr_list;
1274
1275 pango_layout_set_text (textitem->layout, text, -1);
1276
1277 gnome_canvas_text_apply_attributes (textitem);
1278 }
1279
1280 /* Update handler for the text item */
1281 static void
1282 gnome_canvas_text_update (GnomeCanvasItem *item,
1283 const cairo_matrix_t *matrix,
1284 gint flags)
1285 {
1286 GnomeCanvasText *text;
1287 gdouble x1, y1, x2, y2;
1288
1289 text = GNOME_CANVAS_TEXT (item);
1290
1291 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_text_parent_class)->
1292 update (item, matrix, flags);
1293
1294 get_bounds (text, &x1, &y1, &x2, &y2);
1295
1296 gnome_canvas_update_bbox (
1297 item,
1298 floor (x1), floor (y1),
1299 ceil (x2), ceil (y2));
1300 }
1301
1302 /* Draw handler for the text item */
1303 static void
1304 gnome_canvas_text_draw (GnomeCanvasItem *item,
1305 cairo_t *cr,
1306 gint x,
1307 gint y,
1308 gint width,
1309 gint height)
1310 {
1311 GnomeCanvasText *text = GNOME_CANVAS_TEXT (item);
1312
1313 if (!text->text)
1314 return;
1315
1316 cairo_save (cr);
1317
1318 if (text->clip) {
1319 cairo_rectangle (
1320 cr,
1321 text->clip_cx - x,
1322 text->clip_cy - y,
1323 text->clip_cwidth,
1324 text->clip_cheight);
1325 cairo_clip (cr);
1326 }
1327
1328 cairo_set_source_rgba (
1329 cr,
1330 ((text->rgba >> 24) & 0xff) / 255.0,
1331 ((text->rgba >> 16) & 0xff) / 255.0,
1332 ((text->rgba >> 8) & 0xff) / 255.0,
1333 ( text->rgba & 0xff) / 255.0);
1334
1335 cairo_move_to (cr, text->cx - x, text->cy - y);
1336 pango_cairo_show_layout (cr, text->layout);
1337
1338 cairo_restore (cr);
1339 }
1340
1341 /* Point handler for the text item */
1342 static GnomeCanvasItem *
1343 gnome_canvas_text_point (GnomeCanvasItem *item,
1344 gdouble x,
1345 gdouble y,
1346 gint cx,
1347 gint cy)
1348 {
1349 GnomeCanvasText *text;
1350 PangoLayoutIter *iter;
1351 gint x1, y1, x2, y2;
1352
1353 text = GNOME_CANVAS_TEXT (item);
1354
1355 /* The idea is to build bounding rectangles for each of the lines of
1356 * text (clipped by the clipping rectangle, if it is activated) and see
1357 * whether the point is inside any of these. If it is, we are done.
1358 * Otherwise, calculate the distance to the nearest rectangle.
1359 */
1360
1361 iter = pango_layout_get_iter (text->layout);
1362 do {
1363 PangoRectangle log_rect;
1364
1365 pango_layout_iter_get_line_extents (iter, NULL, &log_rect);
1366
1367 x1 = text->cx + PANGO_PIXELS (log_rect.x);
1368 y1 = text->cy + PANGO_PIXELS (log_rect.y);
1369 x2 = x1 + PANGO_PIXELS (log_rect.width);
1370 y2 = y1 + PANGO_PIXELS (log_rect.height);
1371
1372 if (text->clip) {
1373 if (x1 < text->clip_cx)
1374 x1 = text->clip_cx;
1375
1376 if (y1 < text->clip_cy)
1377 y1 = text->clip_cy;
1378
1379 if (x2 > (text->clip_cx + text->clip_width))
1380 x2 = text->clip_cx + text->clip_width;
1381
1382 if (y2 > (text->clip_cy + text->clip_height))
1383 y2 = text->clip_cy + text->clip_height;
1384
1385 if ((x1 >= x2) || (y1 >= y2))
1386 continue;
1387 }
1388
1389 /* Calculate distance from point to rectangle */
1390
1391 if (cx >= x1 && cx < x2 && cy >= y1 && cy < y2) {
1392 pango_layout_iter_free (iter);
1393 return item;
1394 }
1395
1396 } while (pango_layout_iter_next_line (iter));
1397
1398 pango_layout_iter_free (iter);
1399
1400 return NULL;
1401 }
1402
1403 /* Bounds handler for the text item */
1404 static void
1405 gnome_canvas_text_bounds (GnomeCanvasItem *item,
1406 gdouble *x1,
1407 gdouble *y1,
1408 gdouble *x2,
1409 gdouble *y2)
1410 {
1411 GnomeCanvasText *text;
1412 gdouble width, height;
1413
1414 text = GNOME_CANVAS_TEXT (item);
1415
1416 *x1 = text->x;
1417 *y1 = text->y;
1418
1419 if (text->clip) {
1420 width = text->clip_width;
1421 height = text->clip_height;
1422 } else {
1423 width = text->max_width;
1424 height = text->height;
1425 }
1426
1427 *x2 = *x1 + width;
1428 *y2 = *y1 + height;
1429 }