evolution-3.6.4/libgnomecanvas/gnome-canvas-text.c

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 }