[AdgTable] Prefixed internal symbols
[adg.git] / nodist / AdgText / foo-canvas-text.c
blob073ed56d32116debe6e2be50dd753ef77db6dbd9
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.
7 * This file is part of the Gnome Library.
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.
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.
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.
25 @NOTATION@
27 /* Text item type for FooCanvas widget
29 * FooCanvas 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.
34 * Author: Federico Mena <federico@nuclecu.unam.mx>
35 * Port to Pango co-done by Gergõ Érdi <cactus@cactus.rulez.org>
38 #include <config.h>
39 #include <math.h>
40 #include <string.h>
41 #include "foo-canvas-text.h"
43 #include "foo-canvas-util.h"
44 #include "foo-canvas-i18n.h"
48 /* Object argument IDs */
49 enum {
50 PROP_0,
52 /* Text contents */
53 PROP_TEXT,
54 PROP_MARKUP,
56 /* Position */
57 PROP_X,
58 PROP_Y,
60 /* Font */
61 PROP_FONT,
62 PROP_FONT_DESC,
63 PROP_FAMILY, PROP_FAMILY_SET,
65 /* Style */
66 PROP_ATTRIBUTES,
67 PROP_STYLE, PROP_STYLE_SET,
68 PROP_VARIANT, PROP_VARIANT_SET,
69 PROP_WEIGHT, PROP_WEIGHT_SET,
70 PROP_STRETCH, PROP_STRETCH_SET,
71 PROP_SIZE, PROP_SIZE_SET,
72 PROP_SIZE_POINTS,
73 PROP_STRIKETHROUGH, PROP_STRIKETHROUGH_SET,
74 PROP_UNDERLINE, PROP_UNDERLINE_SET,
75 PROP_RISE, PROP_RISE_SET,
76 PROP_SCALE, PROP_SCALE_SET,
78 /* Clipping */
79 PROP_ANCHOR,
80 PROP_JUSTIFICATION,
81 PROP_CLIP_WIDTH,
82 PROP_CLIP_HEIGHT,
83 PROP_CLIP,
84 PROP_WRAP_WIDTH,
85 PROP_X_OFFSET,
86 PROP_Y_OFFSET,
88 /* Coloring */
89 PROP_FILL_COLOR,
90 PROP_FILL_COLOR_GDK,
91 PROP_FILL_COLOR_RGBA,
92 PROP_FILL_STIPPLE,
94 /* Rendered size accessors */
95 PROP_TEXT_WIDTH,
96 PROP_TEXT_HEIGHT
99 struct _FooCanvasTextPrivate {
100 gint placeholder;
103 static void foo_canvas_text_class_init (FooCanvasTextClass *klass);
104 static void foo_canvas_text_init (FooCanvasText *text);
105 static void foo_canvas_text_destroy (GtkObject *object);
106 static void foo_canvas_text_set_property (GObject *object,
107 guint param_id,
108 const GValue *value,
109 GParamSpec *pspec);
110 static void foo_canvas_text_get_property (GObject *object,
111 guint param_id,
112 GValue *value,
113 GParamSpec *pspec);
115 static void foo_canvas_text_update (FooCanvasItem *item,
116 double i2w_dx,
117 double i2w_dy,
118 int flags);
119 static void foo_canvas_text_realize (FooCanvasItem *item);
120 static void foo_canvas_text_unrealize (FooCanvasItem *item);
121 static void foo_canvas_text_draw (FooCanvasItem *item,
122 GdkDrawable *drawable,
123 GdkEventExpose *expose);
124 static double foo_canvas_text_point (FooCanvasItem *item,
125 double x,
126 double y,
127 int cx,
128 int cy,
129 FooCanvasItem **actual_item);
130 static void foo_canvas_text_translate (FooCanvasItem *item,
131 double dx,
132 double dy);
133 static void foo_canvas_text_bounds (FooCanvasItem *item,
134 double *x1,
135 double *y1,
136 double *x2,
137 double *y2);
139 static void foo_canvas_text_set_markup (FooCanvasText *textitem,
140 const gchar *markup);
142 static void foo_canvas_text_set_font_desc (FooCanvasText *textitem,
143 PangoFontDescription *font_desc);
145 static void foo_canvas_text_apply_font_desc (FooCanvasText *textitem);
146 static void foo_canvas_text_apply_attributes (FooCanvasText *textitem);
148 static void add_attr (PangoAttrList *attr_list,
149 PangoAttribute *attr);
151 static FooCanvasItemClass *parent_class;
153 G_DEFINE_TYPE (FooCanvasText, foo_canvas_text, FOO_TYPE_CANVAS_ITEM)
155 /* Class initialization function for the text item */
156 static void
157 foo_canvas_text_class_init (FooCanvasTextClass *klass)
159 GObjectClass *gobject_class;
160 GtkObjectClass *object_class;
161 FooCanvasItemClass *item_class;
163 gobject_class = (GObjectClass *) klass;
164 object_class = (GtkObjectClass *) klass;
165 item_class = (FooCanvasItemClass *) klass;
167 parent_class = g_type_class_peek_parent (klass);
169 gobject_class->set_property = foo_canvas_text_set_property;
170 gobject_class->get_property = foo_canvas_text_get_property;
172 /* Text */
173 g_object_class_install_property
174 (gobject_class,
175 PROP_TEXT,
176 g_param_spec_string ("text",
177 _("Text"),
178 _("Text to render"),
179 NULL,
180 G_PARAM_READWRITE));
182 g_object_class_install_property
183 (gobject_class,
184 PROP_MARKUP,
185 g_param_spec_string ("markup",
186 _("Markup"),
187 _("Marked up text to render"),
188 NULL,
189 (G_PARAM_WRITABLE)));
191 /* Position */
192 g_object_class_install_property
193 (gobject_class,
194 PROP_X,
195 g_param_spec_double ("x", NULL, NULL,
196 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
197 G_PARAM_READWRITE));
199 g_object_class_install_property
200 (gobject_class,
201 PROP_Y,
202 g_param_spec_double ("y", NULL, NULL,
203 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
204 G_PARAM_READWRITE));
207 /* Font */
208 g_object_class_install_property
209 (gobject_class,
210 PROP_FONT,
211 g_param_spec_string ("font",
212 _("Font"),
213 _("Font description as a string"),
214 NULL,
215 G_PARAM_READWRITE));
217 g_object_class_install_property
218 (gobject_class,
219 PROP_FONT_DESC,
220 g_param_spec_boxed ("font-desc",
221 _("Font description"),
222 _("Font description as a PangoFontDescription struct"),
223 PANGO_TYPE_FONT_DESCRIPTION,
224 G_PARAM_READWRITE));
226 g_object_class_install_property
227 (gobject_class,
228 PROP_FAMILY,
229 g_param_spec_string ("family",
230 _("Font family"),
231 _("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
232 NULL,
233 G_PARAM_READWRITE));
235 /* Style */
236 g_object_class_install_property
237 (gobject_class,
238 PROP_ATTRIBUTES,
239 g_param_spec_boxed ("attributes", NULL, NULL,
240 PANGO_TYPE_ATTR_LIST,
241 G_PARAM_READWRITE));
243 g_object_class_install_property
244 (gobject_class,
245 PROP_STYLE,
246 g_param_spec_enum ("style",
247 _("Font style"),
248 _("Font style"),
249 PANGO_TYPE_STYLE,
250 PANGO_STYLE_NORMAL,
251 G_PARAM_READABLE | G_PARAM_WRITABLE));
253 g_object_class_install_property
254 (gobject_class,
255 PROP_VARIANT,
256 g_param_spec_enum ("variant",
257 _("Font variant"),
258 _("Font variant"),
259 PANGO_TYPE_VARIANT,
260 PANGO_VARIANT_NORMAL,
261 G_PARAM_READABLE | G_PARAM_WRITABLE));
263 g_object_class_install_property
264 (gobject_class,
265 PROP_WEIGHT,
266 g_param_spec_int ("weight",
267 _("Font weight"),
268 _("Font weight"),
270 G_MAXINT,
271 PANGO_WEIGHT_NORMAL,
272 G_PARAM_READABLE | G_PARAM_WRITABLE));
275 g_object_class_install_property
276 (gobject_class,
277 PROP_STRETCH,
278 g_param_spec_enum ("stretch",
279 _("Font stretch"),
280 _("Font stretch"),
281 PANGO_TYPE_STRETCH,
282 PANGO_STRETCH_NORMAL,
283 G_PARAM_READABLE | G_PARAM_WRITABLE));
285 g_object_class_install_property
286 (gobject_class,
287 PROP_SIZE,
288 g_param_spec_int ("size",
289 _("Font size"),
290 _("Font size"),
292 G_MAXINT,
294 G_PARAM_READABLE | G_PARAM_WRITABLE));
296 g_object_class_install_property
297 (gobject_class,
298 PROP_SIZE_POINTS,
299 g_param_spec_double ("size-points",
300 _("Font points"),
301 _("Font size in points"),
302 0.0,
303 G_MAXDOUBLE,
304 0.0,
305 G_PARAM_READABLE | G_PARAM_WRITABLE));
307 g_object_class_install_property
308 (gobject_class,
309 PROP_RISE,
310 g_param_spec_int ("rise",
311 _("Rise"),
312 _("Offset of text above the baseline (below the baseline if rise is negative)"),
313 -G_MAXINT,
314 G_MAXINT,
316 G_PARAM_READABLE | G_PARAM_WRITABLE));
318 g_object_class_install_property
319 (gobject_class,
320 PROP_STRIKETHROUGH,
321 g_param_spec_boolean ("strikethrough",
322 _("Strikethrough"),
323 _("Whether to strike through the text"),
324 FALSE,
325 G_PARAM_READABLE | G_PARAM_WRITABLE));
327 g_object_class_install_property
328 (gobject_class,
329 PROP_UNDERLINE,
330 g_param_spec_enum ("underline",
331 _("Underline"),
332 _("Style of underline for this text"),
333 PANGO_TYPE_UNDERLINE,
334 PANGO_UNDERLINE_NONE,
335 G_PARAM_READABLE | G_PARAM_WRITABLE));
337 g_object_class_install_property
338 (gobject_class,
339 PROP_SCALE,
340 g_param_spec_double ("scale",
341 _("Scale"),
342 _("Size of font, relative to default size"),
343 0.0,
344 G_MAXDOUBLE,
345 1.0,
346 G_PARAM_READABLE | G_PARAM_WRITABLE));
348 g_object_class_install_property
349 (gobject_class,
350 PROP_ANCHOR,
351 g_param_spec_enum ("anchor", NULL, NULL,
352 GTK_TYPE_ANCHOR_TYPE,
353 GTK_ANCHOR_CENTER,
354 G_PARAM_READWRITE));
355 g_object_class_install_property
356 (gobject_class,
357 PROP_JUSTIFICATION,
358 g_param_spec_enum ("justification", NULL, NULL,
359 GTK_TYPE_JUSTIFICATION,
360 GTK_JUSTIFY_LEFT,
361 G_PARAM_READWRITE));
362 g_object_class_install_property
363 (gobject_class,
364 PROP_CLIP_WIDTH,
365 g_param_spec_double ("clip-width", NULL, NULL,
366 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
367 G_PARAM_READWRITE));
368 g_object_class_install_property
369 (gobject_class,
370 PROP_CLIP_HEIGHT,
371 g_param_spec_double ("clip-height", NULL, NULL,
372 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
373 G_PARAM_READWRITE));
374 g_object_class_install_property
375 (gobject_class,
376 PROP_CLIP,
377 g_param_spec_boolean ("clip", NULL, NULL,
378 FALSE,
379 G_PARAM_READWRITE));
380 g_object_class_install_property
381 (gobject_class,
382 PROP_WRAP_WIDTH,
383 g_param_spec_double ("wrap-width", NULL, NULL,
384 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
385 G_PARAM_READWRITE));
386 g_object_class_install_property
387 (gobject_class,
388 PROP_X_OFFSET,
389 g_param_spec_double ("x-offset", NULL, NULL,
390 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
391 G_PARAM_READWRITE));
392 g_object_class_install_property
393 (gobject_class,
394 PROP_Y_OFFSET,
395 g_param_spec_double ("y-offset", NULL, NULL,
396 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
397 G_PARAM_READWRITE));
398 g_object_class_install_property
399 (gobject_class,
400 PROP_FILL_COLOR,
401 g_param_spec_string ("fill-color",
402 _("Color"),
403 _("Text color, as string"),
404 NULL,
405 G_PARAM_READWRITE));
406 g_object_class_install_property
407 (gobject_class,
408 PROP_FILL_COLOR_GDK,
409 g_param_spec_boxed ("fill-color-gdk",
410 _("Color"),
411 _("Text color, as a GdkColor"),
412 GDK_TYPE_COLOR,
413 G_PARAM_READWRITE));
414 g_object_class_install_property
415 (gobject_class,
416 PROP_FILL_COLOR_RGBA,
417 g_param_spec_uint ("fill-color-rgba",
418 _("Color"),
419 _("Text color, as an R/G/B/A combined integer"),
420 0, G_MAXUINT, 0,
421 G_PARAM_READWRITE));
422 g_object_class_install_property
423 (gobject_class,
424 PROP_FILL_STIPPLE,
425 g_param_spec_object ("fill-stipple", NULL, NULL,
426 GDK_TYPE_DRAWABLE,
427 G_PARAM_READWRITE));
428 g_object_class_install_property
429 (gobject_class,
430 PROP_TEXT_WIDTH,
431 g_param_spec_double ("text-width",
432 _("Text width"),
433 _("Width of the rendered text"),
434 0.0, G_MAXDOUBLE, 0.0,
435 G_PARAM_READWRITE));
436 g_object_class_install_property
437 (gobject_class,
438 PROP_TEXT_HEIGHT,
439 g_param_spec_double ("text-height",
440 _("Text height"),
441 _("Height of the rendered text"),
442 0.0, G_MAXDOUBLE, 0.0,
443 G_PARAM_READWRITE));
445 /* Style props are set (explicitly applied) or not */
446 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE))
448 ADD_SET_PROP ("family-set", PROP_FAMILY_SET,
449 _("Font family set"),
450 _("Whether this tag affects the font family"));
452 ADD_SET_PROP ("style-set", PROP_STYLE_SET,
453 _("Font style set"),
454 _("Whether this tag affects the font style"));
456 ADD_SET_PROP ("variant-set", PROP_VARIANT_SET,
457 _("Font variant set"),
458 _("Whether this tag affects the font variant"));
460 ADD_SET_PROP ("weight-set", PROP_WEIGHT_SET,
461 _("Font weight set"),
462 _("Whether this tag affects the font weight"));
464 ADD_SET_PROP ("stretch-set", PROP_STRETCH_SET,
465 _("Font stretch set"),
466 _("Whether this tag affects the font stretch"));
468 ADD_SET_PROP ("size-set", PROP_SIZE_SET,
469 _("Font size set"),
470 _("Whether this tag affects the font size"));
472 ADD_SET_PROP ("rise-set", PROP_RISE_SET,
473 _("Rise set"),
474 _("Whether this tag affects the rise"));
476 ADD_SET_PROP ("strikethrough-set", PROP_STRIKETHROUGH_SET,
477 _("Strikethrough set"),
478 _("Whether this tag affects strikethrough"));
480 ADD_SET_PROP ("underline-set", PROP_UNDERLINE_SET,
481 _("Underline set"),
482 _("Whether this tag affects underlining"));
484 ADD_SET_PROP ("scale-set", PROP_SCALE_SET,
485 _("Scale set"),
486 _("Whether this tag affects font scaling"));
487 #undef ADD_SET_PROP
489 object_class->destroy = foo_canvas_text_destroy;
491 item_class->update = foo_canvas_text_update;
492 item_class->realize = foo_canvas_text_realize;
493 item_class->unrealize = foo_canvas_text_unrealize;
494 item_class->draw = foo_canvas_text_draw;
495 item_class->point = foo_canvas_text_point;
496 item_class->translate = foo_canvas_text_translate;
497 item_class->bounds = foo_canvas_text_bounds;
500 /* Object initialization function for the text item */
501 static void
502 foo_canvas_text_init (FooCanvasText *text)
504 text->x = 0.0;
505 text->y = 0.0;
506 text->anchor = GTK_ANCHOR_CENTER;
507 text->justification = GTK_JUSTIFY_LEFT;
508 text->clip_width = 0.0;
509 text->clip_height = 0.0;
510 text->xofs = 0.0;
511 text->yofs = 0.0;
512 text->layout = NULL;
514 text->font_desc = NULL;
516 text->underline = PANGO_UNDERLINE_NONE;
517 text->strikethrough = FALSE;
518 text->rise = 0;
520 text->underline_set = FALSE;
521 text->strike_set = FALSE;
522 text->rise_set = FALSE;
524 text->priv = g_new (FooCanvasTextPrivate, 1);
527 /* Destroy handler for the text item */
528 static void
529 foo_canvas_text_destroy (GtkObject *object)
531 FooCanvasText *text;
533 g_return_if_fail (FOO_IS_CANVAS_TEXT (object));
535 text = FOO_CANVAS_TEXT (object);
537 /* remember, destroy can be run multiple times! */
539 g_free (text->text);
540 text->text = NULL;
542 if (text->layout)
543 g_object_unref (G_OBJECT (text->layout));
544 text->layout = NULL;
546 if (text->font_desc) {
547 pango_font_description_free (text->font_desc);
548 text->font_desc = NULL;
551 if (text->attr_list)
552 pango_attr_list_unref (text->attr_list);
553 text->attr_list = NULL;
555 if (text->stipple)
556 g_object_unref (text->stipple);
557 text->stipple = NULL;
559 g_free (text->priv);
560 text->priv = NULL;
562 if (GTK_OBJECT_CLASS (parent_class)->destroy)
563 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
566 static void
567 get_bounds (FooCanvasText *text, double *px1, double *py1, double *px2, double *py2)
569 FooCanvasItem *item;
570 double wx, wy;
572 item = FOO_CANVAS_ITEM (text);
574 /* Get canvas pixel coordinates for text position */
577 wx = text->x;
578 wy = text->y;
579 foo_canvas_item_i2w (item, &wx, &wy);
580 foo_canvas_w2c (item->canvas, wx + text->xofs, wy + text->yofs, &text->cx, &text->cy);
582 /* Get canvas pixel coordinates for clip rectangle position */
584 foo_canvas_w2c (item->canvas, wx, wy, &text->clip_cx, &text->clip_cy);
585 text->clip_cwidth = text->clip_width * item->canvas->pixels_per_unit;
586 text->clip_cheight = text->clip_height * item->canvas->pixels_per_unit;
588 /* Anchor text */
590 switch (text->anchor) {
591 case GTK_ANCHOR_NW:
592 case GTK_ANCHOR_W:
593 case GTK_ANCHOR_SW:
594 break;
596 case GTK_ANCHOR_N:
597 case GTK_ANCHOR_CENTER:
598 case GTK_ANCHOR_S:
599 text->cx -= text->max_width / 2;
600 text->clip_cx -= text->clip_cwidth / 2;
601 break;
603 case GTK_ANCHOR_NE:
604 case GTK_ANCHOR_E:
605 case GTK_ANCHOR_SE:
606 text->cx -= text->max_width;
607 text->clip_cx -= text->clip_cwidth;
608 break;
610 default:
611 break;
614 switch (text->anchor) {
615 case GTK_ANCHOR_NW:
616 case GTK_ANCHOR_N:
617 case GTK_ANCHOR_NE:
618 break;
620 case GTK_ANCHOR_W:
621 case GTK_ANCHOR_CENTER:
622 case GTK_ANCHOR_E:
623 text->cy -= text->height / 2;
624 text->clip_cy -= text->clip_cheight / 2;
625 break;
627 case GTK_ANCHOR_SW:
628 case GTK_ANCHOR_S:
629 case GTK_ANCHOR_SE:
630 text->cy -= text->height;
631 text->clip_cy -= text->clip_cheight;
632 break;
634 default:
635 break;
638 /* Bounds */
640 if (text->clip) {
641 *px1 = text->clip_cx;
642 *py1 = text->clip_cy;
643 *px2 = text->clip_cx + text->clip_cwidth;
644 *py2 = text->clip_cy + text->clip_cheight;
645 } else {
646 *px1 = text->cx;
647 *py1 = text->cy;
648 *px2 = text->cx + text->max_width;
649 *py2 = text->cy + text->height;
653 /* Convenience function to set the text's GC's foreground color */
654 static void
655 set_text_gc_foreground (FooCanvasText *text)
657 GdkColor c;
659 if (!text->gc)
660 return;
662 c.pixel = text->pixel;
663 gdk_gc_set_foreground (text->gc, &c);
666 /* Sets the stipple pattern for the text */
667 static void
668 set_stipple (FooCanvasText *text, GdkBitmap *stipple, int reconfigure)
670 if (text->stipple && !reconfigure)
671 g_object_unref (text->stipple);
673 text->stipple = stipple;
674 if (stipple && !reconfigure)
675 g_object_ref (stipple);
677 if (text->gc) {
678 if (stipple) {
679 gdk_gc_set_stipple (text->gc, stipple);
680 gdk_gc_set_fill (text->gc, GDK_STIPPLED);
681 } else
682 gdk_gc_set_fill (text->gc, GDK_SOLID);
686 static PangoFontMask
687 get_property_font_set_mask (guint prop_id)
689 switch (prop_id)
691 case PROP_FAMILY_SET:
692 return PANGO_FONT_MASK_FAMILY;
693 case PROP_STYLE_SET:
694 return PANGO_FONT_MASK_STYLE;
695 case PROP_VARIANT_SET:
696 return PANGO_FONT_MASK_VARIANT;
697 case PROP_WEIGHT_SET:
698 return PANGO_FONT_MASK_WEIGHT;
699 case PROP_STRETCH_SET:
700 return PANGO_FONT_MASK_STRETCH;
701 case PROP_SIZE_SET:
702 return PANGO_FONT_MASK_SIZE;
705 return 0;
708 static void
709 ensure_font (FooCanvasText *text)
711 if (!text->font_desc)
712 text->font_desc = pango_font_description_new ();
715 /* Set_arg handler for the text item */
716 static void
717 foo_canvas_text_set_property (GObject *object,
718 guint param_id,
719 const GValue *value,
720 GParamSpec *pspec)
722 FooCanvasItem *item;
723 FooCanvasText *text;
724 GdkColor color = { 0, 0, 0, 0, };
725 GdkColor *pcolor;
726 gboolean color_changed;
727 int have_pixel;
728 PangoAlignment align;
730 g_return_if_fail (object != NULL);
731 g_return_if_fail (FOO_IS_CANVAS_TEXT (object));
733 item = FOO_CANVAS_ITEM (object);
734 text = FOO_CANVAS_TEXT (object);
736 color_changed = FALSE;
737 have_pixel = FALSE;
740 if (!text->layout) {
741 text->layout = gtk_widget_create_pango_layout (GTK_WIDGET (item->canvas), NULL);
744 switch (param_id) {
745 case PROP_TEXT:
746 if (text->text)
747 g_free (text->text);
749 text->text = g_value_dup_string (value);
750 pango_layout_set_text (text->layout, text->text, -1);
752 break;
754 case PROP_MARKUP:
755 foo_canvas_text_set_markup (text,
756 g_value_get_string (value));
757 break;
759 case PROP_X:
760 text->x = g_value_get_double (value);
761 break;
763 case PROP_Y:
764 text->y = g_value_get_double (value);
765 break;
767 case PROP_FONT: {
768 const char *font_name;
769 PangoFontDescription *font_desc;
771 font_name = g_value_get_string (value);
772 if (font_name)
773 font_desc = pango_font_description_from_string (font_name);
774 else
775 font_desc = NULL;
777 foo_canvas_text_set_font_desc (text, font_desc);
778 if (font_desc)
779 pango_font_description_free (font_desc);
781 break;
784 case PROP_FONT_DESC:
785 foo_canvas_text_set_font_desc (text, g_value_peek_pointer (value));
786 break;
788 case PROP_FAMILY:
789 case PROP_STYLE:
790 case PROP_VARIANT:
791 case PROP_WEIGHT:
792 case PROP_STRETCH:
793 case PROP_SIZE:
794 case PROP_SIZE_POINTS:
795 ensure_font (text);
797 switch (param_id) {
798 case PROP_FAMILY:
799 pango_font_description_set_family (text->font_desc,
800 g_value_get_string (value));
801 break;
802 case PROP_STYLE:
803 pango_font_description_set_style (text->font_desc,
804 g_value_get_enum (value));
805 break;
806 case PROP_VARIANT:
807 pango_font_description_set_variant (text->font_desc,
808 g_value_get_enum (value));
809 break;
810 case PROP_WEIGHT:
811 pango_font_description_set_weight (text->font_desc,
812 g_value_get_int (value));
813 break;
814 case PROP_STRETCH:
815 pango_font_description_set_stretch (text->font_desc,
816 g_value_get_enum (value));
817 break;
818 case PROP_SIZE:
819 /* FIXME: This is bogus! It should be pixels, not points/PANGO_SCALE! */
820 pango_font_description_set_size (text->font_desc,
821 g_value_get_int (value));
822 break;
823 case PROP_SIZE_POINTS:
824 pango_font_description_set_size (text->font_desc,
825 g_value_get_double (value) * PANGO_SCALE);
826 break;
829 foo_canvas_text_apply_font_desc (text);
830 break;
832 case PROP_FAMILY_SET:
833 case PROP_STYLE_SET:
834 case PROP_VARIANT_SET:
835 case PROP_WEIGHT_SET:
836 case PROP_STRETCH_SET:
837 case PROP_SIZE_SET:
838 if (!g_value_get_boolean (value) && text->font_desc)
839 pango_font_description_unset_fields (text->font_desc,
840 get_property_font_set_mask (param_id));
841 break;
843 case PROP_SCALE:
844 text->scale = g_value_get_double (value);
845 text->scale_set = TRUE;
847 foo_canvas_text_apply_font_desc (text);
848 break;
850 case PROP_SCALE_SET:
851 text->scale_set = g_value_get_boolean (value);
853 foo_canvas_text_apply_font_desc (text);
854 break;
856 case PROP_UNDERLINE:
857 text->underline = g_value_get_enum (value);
858 text->underline_set = TRUE;
860 foo_canvas_text_apply_attributes (text);
861 break;
863 case PROP_UNDERLINE_SET:
864 text->underline_set = g_value_get_boolean (value);
866 foo_canvas_text_apply_attributes (text);
867 break;
869 case PROP_STRIKETHROUGH:
870 text->strikethrough = g_value_get_boolean (value);
871 text->strike_set = TRUE;
873 foo_canvas_text_apply_attributes (text);
874 break;
876 case PROP_STRIKETHROUGH_SET:
877 text->strike_set = g_value_get_boolean (value);
879 foo_canvas_text_apply_attributes (text);
880 break;
882 case PROP_RISE:
883 text->rise = g_value_get_int (value);
884 text->rise_set = TRUE;
886 foo_canvas_text_apply_attributes (text);
887 break;
889 case PROP_RISE_SET:
890 text->rise_set = TRUE;
892 foo_canvas_text_apply_attributes (text);
893 break;
895 case PROP_ATTRIBUTES:
896 if (text->attr_list)
897 pango_attr_list_unref (text->attr_list);
899 text->attr_list = g_value_peek_pointer (value);
900 if (text->attr_list)
901 pango_attr_list_ref (text->attr_list);
903 foo_canvas_text_apply_attributes (text);
904 break;
906 case PROP_ANCHOR:
907 text->anchor = g_value_get_enum (value);
908 break;
910 case PROP_JUSTIFICATION:
911 text->justification = g_value_get_enum (value);
913 switch (text->justification) {
914 case GTK_JUSTIFY_LEFT:
915 align = PANGO_ALIGN_LEFT;
916 break;
917 case GTK_JUSTIFY_CENTER:
918 align = PANGO_ALIGN_CENTER;
919 break;
920 case GTK_JUSTIFY_RIGHT:
921 align = PANGO_ALIGN_RIGHT;
922 break;
923 default:
924 /* GTK_JUSTIFY_FILL isn't supported yet. */
925 align = PANGO_ALIGN_LEFT;
926 break;
928 pango_layout_set_alignment (text->layout, align);
929 break;
931 case PROP_CLIP_WIDTH:
932 text->clip_width = fabs (g_value_get_double (value));
933 break;
935 case PROP_CLIP_HEIGHT:
936 text->clip_height = fabs (g_value_get_double (value));
937 break;
939 case PROP_CLIP:
940 text->clip = g_value_get_boolean (value);
941 break;
943 case PROP_WRAP_WIDTH: {
944 double w = fabs (g_value_get_double (value));
945 pango_layout_set_width (text->layout,
946 w * text->item.canvas->pixels_per_unit * PANGO_SCALE);
948 break;
951 case PROP_X_OFFSET:
952 text->xofs = g_value_get_double (value);
953 break;
955 case PROP_Y_OFFSET:
956 text->yofs = g_value_get_double (value);
957 break;
959 case PROP_FILL_COLOR: {
960 const char *color_name;
962 color_name = g_value_get_string (value);
963 if (color_name) {
964 gdk_color_parse (color_name, &color);
966 text->rgba = ((color.red & 0xff00) << 16 |
967 (color.green & 0xff00) << 8 |
968 (color.blue & 0xff00) |
969 0xff);
970 color_changed = TRUE;
972 break;
975 case PROP_FILL_COLOR_GDK:
976 pcolor = g_value_get_boxed (value);
977 if (pcolor) {
978 GdkColormap *colormap;
980 color = *pcolor;
981 colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
982 gdk_rgb_find_color (colormap, &color);
983 have_pixel = TRUE;
986 text->rgba = ((color.red & 0xff00) << 16 |
987 (color.green & 0xff00) << 8|
988 (color.blue & 0xff00) |
989 0xff);
990 color_changed = TRUE;
991 break;
993 case PROP_FILL_COLOR_RGBA:
994 text->rgba = g_value_get_uint (value);
995 color_changed = TRUE;
996 break;
998 case PROP_FILL_STIPPLE:
999 set_stipple (text, (GdkBitmap *)g_value_get_object (value), FALSE);
1000 break;
1002 default:
1003 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1004 break;
1007 if (color_changed) {
1008 if (have_pixel)
1009 text->pixel = color.pixel;
1010 else
1011 text->pixel = foo_canvas_get_color_pixel (item->canvas, text->rgba);
1013 set_text_gc_foreground (text);
1016 /* Calculate text dimensions */
1018 if (text->layout)
1019 pango_layout_get_pixel_size (text->layout,
1020 &text->max_width,
1021 &text->height);
1022 else {
1023 text->max_width = 0;
1024 text->height = 0;
1027 foo_canvas_item_request_update (item);
1030 /* Get_arg handler for the text item */
1031 static void
1032 foo_canvas_text_get_property (GObject *object,
1033 guint param_id,
1034 GValue *value,
1035 GParamSpec *pspec)
1037 FooCanvasText *text;
1039 g_return_if_fail (object != NULL);
1040 g_return_if_fail (FOO_IS_CANVAS_TEXT (object));
1042 text = FOO_CANVAS_TEXT (object);
1044 switch (param_id) {
1045 case PROP_TEXT:
1046 g_value_set_string (value, text->text);
1047 break;
1049 case PROP_X:
1050 g_value_set_double (value, text->x);
1051 break;
1053 case PROP_Y:
1054 g_value_set_double (value, text->y);
1055 break;
1057 case PROP_FONT:
1058 case PROP_FONT_DESC:
1059 case PROP_FAMILY:
1060 case PROP_STYLE:
1061 case PROP_VARIANT:
1062 case PROP_WEIGHT:
1063 case PROP_STRETCH:
1064 case PROP_SIZE:
1065 case PROP_SIZE_POINTS:
1066 ensure_font (text);
1068 switch (param_id) {
1069 case PROP_FONT:
1071 /* FIXME GValue imposes a totally gratuitous string copy
1072 * here, we could just hand off string ownership
1074 gchar *str;
1076 str = pango_font_description_to_string (text->font_desc);
1077 g_value_set_string (value, str);
1078 g_free (str);
1080 break;
1083 case PROP_FONT_DESC:
1084 g_value_set_boxed (value, text->font_desc);
1085 break;
1087 case PROP_FAMILY:
1088 g_value_set_string (value, pango_font_description_get_family (text->font_desc));
1089 break;
1091 case PROP_STYLE:
1092 g_value_set_enum (value, pango_font_description_get_style (text->font_desc));
1093 break;
1095 case PROP_VARIANT:
1096 g_value_set_enum (value, pango_font_description_get_variant (text->font_desc));
1097 break;
1099 case PROP_WEIGHT:
1100 g_value_set_int (value, pango_font_description_get_weight (text->font_desc));
1101 break;
1103 case PROP_STRETCH:
1104 g_value_set_enum (value, pango_font_description_get_stretch (text->font_desc));
1105 break;
1107 case PROP_SIZE:
1108 g_value_set_int (value, pango_font_description_get_size (text->font_desc));
1109 break;
1111 case PROP_SIZE_POINTS:
1112 g_value_set_double (value, ((double)pango_font_description_get_size (text->font_desc)) / (double)PANGO_SCALE);
1113 break;
1115 break;
1117 case PROP_FAMILY_SET:
1118 case PROP_STYLE_SET:
1119 case PROP_VARIANT_SET:
1120 case PROP_WEIGHT_SET:
1121 case PROP_STRETCH_SET:
1122 case PROP_SIZE_SET:
1124 PangoFontMask set_mask = text->font_desc ? pango_font_description_get_set_fields (text->font_desc) : 0;
1125 PangoFontMask test_mask = get_property_font_set_mask (param_id);
1126 g_value_set_boolean (value, (set_mask & test_mask) != 0);
1128 break;
1131 case PROP_SCALE:
1132 g_value_set_double (value, text->scale);
1133 break;
1134 case PROP_SCALE_SET:
1135 g_value_set_boolean (value, text->scale_set);
1136 break;
1138 case PROP_UNDERLINE:
1139 g_value_set_enum (value, text->underline);
1140 break;
1141 case PROP_UNDERLINE_SET:
1142 g_value_set_boolean (value, text->underline_set);
1143 break;
1145 case PROP_STRIKETHROUGH:
1146 g_value_set_boolean (value, text->strikethrough);
1147 break;
1148 case PROP_STRIKETHROUGH_SET:
1149 g_value_set_boolean (value, text->strike_set);
1150 break;
1152 case PROP_RISE:
1153 g_value_set_int (value, text->rise);
1154 break;
1155 case PROP_RISE_SET:
1156 g_value_set_boolean (value, text->rise_set);
1157 break;
1159 case PROP_ATTRIBUTES:
1160 g_value_set_boxed (value, text->attr_list);
1161 break;
1163 case PROP_ANCHOR:
1164 g_value_set_enum (value, text->anchor);
1165 break;
1167 case PROP_JUSTIFICATION:
1168 g_value_set_enum (value, text->justification);
1169 break;
1171 case PROP_CLIP_WIDTH:
1172 g_value_set_double (value, text->clip_width);
1173 break;
1175 case PROP_CLIP_HEIGHT:
1176 g_value_set_double (value, text->clip_height);
1177 break;
1179 case PROP_CLIP:
1180 g_value_set_boolean (value, text->clip);
1181 break;
1183 case PROP_WRAP_WIDTH:
1184 g_value_set_double (value,
1185 pango_layout_get_width (text->layout) / PANGO_SCALE);
1186 break;
1188 case PROP_X_OFFSET:
1189 g_value_set_double (value, text->xofs);
1190 break;
1192 case PROP_Y_OFFSET:
1193 g_value_set_double (value, text->yofs);
1194 break;
1196 case PROP_FILL_COLOR:
1197 g_value_take_string (value,
1198 g_strdup_printf ("#%02x%02x%02x",
1199 text->rgba >> 24,
1200 (text->rgba >> 16) & 0xff,
1201 (text->rgba >> 8) & 0xff));
1202 break;
1204 case PROP_FILL_COLOR_GDK: {
1205 FooCanvas *canvas = FOO_CANVAS_ITEM (text)->canvas;
1206 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
1207 GdkColor color;
1209 gdk_colormap_query_color (colormap, text->pixel, &color);
1210 g_value_set_boxed (value, &color);
1211 break;
1213 case PROP_FILL_COLOR_RGBA:
1214 g_value_set_uint (value, text->rgba);
1215 break;
1217 case PROP_FILL_STIPPLE:
1218 g_value_set_object (value, text->stipple);
1219 break;
1221 case PROP_TEXT_WIDTH:
1222 g_value_set_double (value, text->max_width / text->item.canvas->pixels_per_unit);
1223 break;
1225 case PROP_TEXT_HEIGHT:
1226 g_value_set_double (value, text->height / text->item.canvas->pixels_per_unit);
1227 break;
1229 default:
1230 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1231 break;
1235 /* */
1236 static void
1237 foo_canvas_text_apply_font_desc (FooCanvasText *text)
1239 PangoFontDescription *font_desc =
1240 pango_font_description_copy (
1241 GTK_WIDGET (FOO_CANVAS_ITEM (text)->canvas)->style->font_desc);
1243 if (text->font_desc)
1244 pango_font_description_merge (font_desc, text->font_desc, TRUE);
1246 pango_layout_set_font_description (text->layout, font_desc);
1247 pango_font_description_free (font_desc);
1250 static void
1251 add_attr (PangoAttrList *attr_list,
1252 PangoAttribute *attr)
1254 attr->start_index = 0;
1255 attr->end_index = G_MAXINT;
1257 pango_attr_list_insert (attr_list, attr);
1260 /* */
1261 static void
1262 foo_canvas_text_apply_attributes (FooCanvasText *text)
1264 PangoAttrList *attr_list;
1265 double zoom;
1267 if (text->attr_list)
1268 attr_list = pango_attr_list_copy (text->attr_list);
1269 else
1270 attr_list = pango_attr_list_new ();
1272 if (text->underline_set)
1273 add_attr (attr_list, pango_attr_underline_new (text->underline));
1274 if (text->strike_set)
1275 add_attr (attr_list, pango_attr_strikethrough_new (text->strikethrough));
1276 if (text->rise_set)
1277 add_attr (attr_list, pango_attr_rise_new (text->rise));
1279 zoom = text->item.canvas->pixels_per_unit;
1280 if (fabs (zoom - 1.) > 1e-4) {
1281 PangoAttribute *attr = pango_attr_scale_new (zoom);
1282 attr->start_index = 0;
1283 attr->end_index = -1;
1284 pango_attr_list_insert_before (attr_list, attr);
1287 pango_layout_set_attributes (text->layout, attr_list);
1288 pango_attr_list_unref (attr_list);
1291 static void
1292 foo_canvas_text_set_font_desc (FooCanvasText *text,
1293 PangoFontDescription *font_desc)
1295 if (text->font_desc)
1296 pango_font_description_free (text->font_desc);
1298 if (font_desc)
1299 text->font_desc = pango_font_description_copy (font_desc);
1300 else
1301 text->font_desc = NULL;
1303 foo_canvas_text_apply_font_desc (text);
1306 /* Setting the text from a Pango markup string */
1307 static void
1308 foo_canvas_text_set_markup (FooCanvasText *textitem,
1309 const gchar *markup)
1311 PangoAttrList *attr_list = NULL;
1312 gchar *text = NULL;
1313 GError *error = NULL;
1315 if (textitem->text)
1316 g_free (textitem->text);
1317 if (textitem->attr_list)
1318 pango_attr_list_unref (textitem->attr_list);
1320 if (markup && !pango_parse_markup (markup, -1,
1322 &attr_list, &text, NULL,
1323 &error))
1325 g_warning ("Failed to set cell text from markup due to error parsing markup: %s",
1326 error->message);
1327 g_error_free (error);
1328 return;
1331 textitem->text = text;
1332 textitem->attr_list = attr_list;
1334 pango_layout_set_text (textitem->layout, text, -1);
1336 foo_canvas_text_apply_attributes (textitem);
1339 /* Update handler for the text item */
1340 static void
1341 foo_canvas_text_update (FooCanvasItem *item, double i2w_dx, double i2w_dy, int flags)
1343 FooCanvasText *text;
1344 double x1, y1, x2, y2;
1346 text = FOO_CANVAS_TEXT (item);
1348 if (parent_class->update)
1349 (* parent_class->update) (item, i2w_dx, i2w_dy, flags);
1351 set_text_gc_foreground (text);
1352 set_stipple (text, text->stipple, TRUE);
1353 get_bounds (text, &x1, &y1, &x2, &y2);
1355 foo_canvas_update_bbox (item,
1356 floor (x1+.5), floor (y1+.5),
1357 floor (x2+.5), floor (y2+.5));
1360 /* Realize handler for the text item */
1361 static void
1362 foo_canvas_text_realize (FooCanvasItem *item)
1364 FooCanvasText *text;
1366 text = FOO_CANVAS_TEXT (item);
1368 if (parent_class->realize)
1369 (* parent_class->realize) (item);
1371 text->gc = gdk_gc_new (item->canvas->layout.bin_window);
1374 /* Unrealize handler for the text item */
1375 static void
1376 foo_canvas_text_unrealize (FooCanvasItem *item)
1378 FooCanvasText *text;
1380 text = FOO_CANVAS_TEXT (item);
1382 g_object_unref (text->gc);
1383 text->gc = NULL;
1385 if (parent_class->unrealize)
1386 (* parent_class->unrealize) (item);
1389 /* Draw handler for the text item */
1390 static void
1391 foo_canvas_text_draw (FooCanvasItem *item, GdkDrawable *drawable,
1392 GdkEventExpose *expose)
1394 FooCanvasText *text;
1395 GdkRectangle rect;
1397 text = FOO_CANVAS_TEXT (item);
1399 if (!text->text)
1400 return;
1402 if (text->clip) {
1403 rect.x = text->clip_cx;
1404 rect.y = text->clip_cy;
1405 rect.width = text->clip_cwidth;
1406 rect.height = text->clip_cheight;
1408 gdk_gc_set_clip_rectangle (text->gc, &rect);
1411 if (text->stipple)
1412 foo_canvas_set_stipple_origin (item->canvas, text->gc);
1415 gdk_draw_layout (drawable, text->gc, text->cx, text->cy, text->layout);
1417 if (text->clip)
1418 gdk_gc_set_clip_rectangle (text->gc, NULL);
1421 /* Point handler for the text item */
1422 static double
1423 foo_canvas_text_point (FooCanvasItem *item, double x, double y,
1424 int cx, int cy, FooCanvasItem **actual_item)
1426 FooCanvasText *text;
1427 PangoLayoutIter *iter;
1428 int x1, y1, x2, y2;
1429 int dx, dy;
1430 double dist, best;
1432 text = FOO_CANVAS_TEXT (item);
1434 *actual_item = item;
1436 /* The idea is to build bounding rectangles for each of the lines of
1437 * text (clipped by the clipping rectangle, if it is activated) and see
1438 * whether the point is inside any of these. If it is, we are done.
1439 * Otherwise, calculate the distance to the nearest rectangle.
1442 best = 1.0e36;
1444 iter = pango_layout_get_iter (text->layout);
1445 do {
1446 PangoRectangle log_rect;
1448 pango_layout_iter_get_line_extents (iter, NULL, &log_rect);
1450 if (text->clip) {
1451 x1 = PANGO_PIXELS (log_rect.x);
1452 y1 = PANGO_PIXELS (log_rect.y);
1453 x2 = PANGO_PIXELS (log_rect.x+log_rect.width);
1454 y2 = PANGO_PIXELS (log_rect.y+log_rect.height);
1457 if (x1 < text->clip_cx)
1458 x1 = text->clip_cx;
1460 if (y1 < text->clip_cy)
1461 y1 = text->clip_cy;
1463 if (x2 > (text->clip_cx + text->clip_width))
1464 x2 = text->clip_cx + text->clip_width;
1466 if (y2 > (text->clip_cy + text->clip_height))
1467 y2 = text->clip_cy + text->clip_height;
1469 if ((x1 >= x2) || (y1 >= y2))
1470 continue;
1471 } else {
1472 x1 = text->x;
1473 y1 = text->y;
1474 x2 = log_rect.width;
1475 y2 = log_rect.height;
1478 /* Calculate distance from point to rectangle */
1480 if (cx < x1)
1481 dx = x1 - cx;
1482 else if (cx >= x2)
1483 dx = cx - x2 + 1;
1484 else
1485 dx = 0;
1487 if (cy < y1)
1488 dy = y1 - cy;
1489 else if (cy >= y2)
1490 dy = cy - y2 + 1;
1491 else
1492 dy = 0;
1494 if ((dx == 0) && (dy == 0)) {
1495 pango_layout_iter_free(iter);
1496 return 0.0;
1499 dist = sqrt (dx * dx + dy * dy);
1500 if (dist < best)
1501 best = dist;
1503 } while (pango_layout_iter_next_line(iter));
1505 pango_layout_iter_free(iter);
1507 return best / item->canvas->pixels_per_unit;
1510 static void
1511 foo_canvas_text_translate (FooCanvasItem *item, double dx, double dy)
1513 FooCanvasText *text;
1515 text = FOO_CANVAS_TEXT (item);
1517 text->x += dx;
1518 text->y += dy;
1521 /* Bounds handler for the text item */
1522 static void
1523 foo_canvas_text_bounds (FooCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1525 FooCanvasText *text;
1526 double width, height;
1528 text = FOO_CANVAS_TEXT (item);
1530 *x1 = text->x;
1531 *y1 = text->y;
1533 if (text->clip) {
1534 width = text->clip_width;
1535 height = text->clip_height;
1536 } else {
1537 width = text->max_width / item->canvas->pixels_per_unit;
1538 height = text->height / item->canvas->pixels_per_unit;
1541 switch (text->anchor) {
1542 case GTK_ANCHOR_NW:
1543 case GTK_ANCHOR_W:
1544 case GTK_ANCHOR_SW:
1545 break;
1547 case GTK_ANCHOR_N:
1548 case GTK_ANCHOR_CENTER:
1549 case GTK_ANCHOR_S:
1550 *x1 -= width / 2.0;
1551 break;
1553 case GTK_ANCHOR_NE:
1554 case GTK_ANCHOR_E:
1555 case GTK_ANCHOR_SE:
1556 *x1 -= width;
1557 break;
1559 default:
1560 break;
1563 switch (text->anchor) {
1564 case GTK_ANCHOR_NW:
1565 case GTK_ANCHOR_N:
1566 case GTK_ANCHOR_NE:
1567 break;
1569 case GTK_ANCHOR_W:
1570 case GTK_ANCHOR_CENTER:
1571 case GTK_ANCHOR_E:
1572 *y1 -= height / 2.0;
1573 break;
1575 case GTK_ANCHOR_SW:
1576 case GTK_ANCHOR_S:
1577 case GTK_ANCHOR_SE:
1578 *y1 -= height;
1579 break;
1581 default:
1582 break;
1585 *x2 = *x1 + width;
1586 *y2 = *y1 + height;