]> git.sur5r.net Git - glabels/blob - glabels2/src/canvas-hacktext.c
Initial revision
[glabels] / glabels2 / src / canvas-hacktext.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  gnome-canvas-hacktext.c: Hacktext item type for GnomeCanvas widget
4  *                           This is mainly used for gnome-print preview context
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public License
8  *  as published by the Free Software Foundation; either version 2 of
9  *  the License, or (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public
17  *  License along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  *  Authors:
21  *    Federico Mena <federico@nuclecu.unam.mx>
22  *    Raph Levien <raph@acm.org>
23  *    Lauris Kaplinski <lauris@helixcode.com>
24  *
25  *  Copyright (C) 1998-1999 The Free Software Foundation
26  *  Copyright (C) 2000-2002 Ximian Inc.
27  *
28  */
29
30 /*
31  * TODO:
32  * - Clipping
33  */
34
35 #include <config.h>
36
37 #include <math.h>
38 #include <string.h>
39 #include <libgnomeprint/gnome-font.h>
40 #include <libgnomeprint/gnome-rfont.h>
41 #include <libgnomeprint/gnome-pgl.h>
42 #include "canvas-hacktext.h"
43
44 enum {
45         ARG_0,
46         ARG_TEXT,
47         ARG_GLYPHLIST,
48         ARG_FILL_COLOR,
49         ARG_FILL_COLOR_RGBA,
50         ARG_FONT,
51         ARG_X,
52         ARG_Y
53 };
54
55
56 static void gl_canvas_hacktext_class_init    (glCanvasHacktextClass *class);
57 static void gl_canvas_hacktext_init          (glCanvasHacktext      *hacktext);
58 static void gl_canvas_hacktext_destroy       (GtkObject             *object);
59 static void gl_canvas_hacktext_set_arg       (GObject               *object,
60                                               guint                  arg_id,
61                                               const GValue          *value,
62                                               GParamSpec            *pspec);
63 static void gl_canvas_hacktext_get_arg       (GObject               *object,
64                                               guint                  arg_id,
65                                               GValue                *value,
66                                               GParamSpec            *pspec);
67
68 static void   gl_canvas_hacktext_update      (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
69 static void   gl_canvas_hacktext_realize     (GnomeCanvasItem *item);
70 static void   gl_canvas_hacktext_unrealize   (GnomeCanvasItem *item);
71 static double gl_canvas_hacktext_point       (GnomeCanvasItem *item, double x, double y,
72                                                 int cx, int cy, GnomeCanvasItem **actual_item);
73 static void   gl_canvas_hacktext_bounds      (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
74 static void   gl_canvas_hacktext_render      (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
75 static void   gl_canvas_hacktext_req_repaint (glCanvasHacktext *hacktext, ArtIRect *bbox);
76
77
78 static GnomeCanvasItemClass *parent_class;
79
80 struct _glCanvasHacktextPriv {
81         GnomeFont * font;
82
83         GnomeGlyphList * glyphlist;
84         GnomePosGlyphList * pgl;
85         double affine[6]; /* the text to world transform (NB! mirrored Y) */
86 };
87
88 GType
89 gl_canvas_hacktext_get_type (void)
90 {
91         static GType hacktext_type = 0;
92
93         if (!hacktext_type) {
94                 static const GTypeInfo hacktext_info = {
95                         sizeof (glCanvasHacktextClass),
96                         NULL,
97                         NULL,
98                         (GClassInitFunc) gl_canvas_hacktext_class_init,
99                         NULL,
100                         NULL,
101                         sizeof (glCanvasHacktext),
102                         0,
103                         (GInstanceInitFunc) gl_canvas_hacktext_init,
104                         NULL
105                 };
106
107                 hacktext_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM,
108                                                         "glCanvasHacktext",
109                                                         &hacktext_info, 0);
110         }
111
112         return hacktext_type;
113 }
114
115 static void
116 gl_canvas_hacktext_class_init (glCanvasHacktextClass *class)
117 {
118         GObjectClass *gobject_class;
119         GtkObjectClass *object_class;
120         GnomeCanvasItemClass *item_class;
121
122         gobject_class = (GObjectClass *) class;
123         object_class = (GtkObjectClass *) class;
124         item_class = (GnomeCanvasItemClass *) class;
125
126         parent_class = g_type_class_peek_parent (class);
127
128         gobject_class->set_property = gl_canvas_hacktext_set_arg;
129         gobject_class->get_property = gl_canvas_hacktext_get_arg;
130
131         g_object_class_install_property
132                 (gobject_class,
133                  ARG_TEXT,
134                  g_param_spec_string ("text", NULL, NULL,
135                                       NULL,
136                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
137
138         g_object_class_install_property
139                 (gobject_class,
140                  ARG_GLYPHLIST,
141                  g_param_spec_pointer ("glyphlist", NULL, NULL,
142                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
143
144         g_object_class_install_property
145                 (gobject_class,
146                  ARG_FILL_COLOR,
147                  g_param_spec_string ("fill_color", NULL, NULL,
148                                       NULL,
149                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
150
151         g_object_class_install_property
152                 (gobject_class,
153                  ARG_FILL_COLOR_RGBA,
154                  g_param_spec_uint ("fill_color_rgba", NULL, NULL,
155                                     0, G_MAXUINT, 0,
156                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
157
158         g_object_class_install_property
159                 (gobject_class,
160                  ARG_FONT,
161                  g_param_spec_pointer ("font", NULL, NULL,
162                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
163
164         g_object_class_install_property
165                 (gobject_class,
166                  ARG_X,
167                  g_param_spec_double ("x", NULL, NULL,
168                                       -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
169                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
170
171         g_object_class_install_property
172                 (gobject_class,
173                  ARG_Y,
174                  g_param_spec_double ("y", NULL, NULL,
175                                       -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
176                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
177
178
179         object_class->destroy = gl_canvas_hacktext_destroy;
180
181         item_class->update = gl_canvas_hacktext_update;
182         item_class->realize = gl_canvas_hacktext_realize;
183         item_class->unrealize = gl_canvas_hacktext_unrealize;
184         item_class->point = gl_canvas_hacktext_point;
185         item_class->bounds = gl_canvas_hacktext_bounds;
186         item_class->render = gl_canvas_hacktext_render;
187 }
188
189 static void
190 gl_canvas_hacktext_init (glCanvasHacktext *hacktext)
191 {
192         hacktext->text = NULL;
193         hacktext->priv = g_new (glCanvasHacktextPriv, 1);
194         hacktext->priv->font = NULL;
195         hacktext->priv->glyphlist = NULL;
196         hacktext->priv->pgl = NULL;
197
198         art_affine_identity (hacktext->priv->affine);
199 }
200
201 static void
202 gl_canvas_hacktext_destroy (GtkObject *object)
203 {
204         glCanvasHacktext *hacktext;
205
206         g_return_if_fail (object != NULL);
207         g_return_if_fail (GL_IS_CANVAS_HACKTEXT (object));
208
209         hacktext = GL_CANVAS_HACKTEXT (object);
210
211         if (hacktext->text) {
212                 g_free (hacktext->text);
213                 hacktext->text = NULL;
214         }
215
216         if (hacktext->priv) {
217                 if (hacktext->priv->font) gnome_font_unref (hacktext->priv->font);
218                 if (hacktext->priv->glyphlist) gnome_glyphlist_unref (hacktext->priv->glyphlist);
219                 if (hacktext->priv->pgl) gnome_pgl_destroy (hacktext->priv->pgl);
220                 g_free (hacktext->priv);
221                 hacktext->priv = NULL;
222         }
223
224         if (GTK_OBJECT_CLASS (parent_class)->destroy)
225                 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
226 }
227
228 static void
229 art_drect_hacktext (ArtDRect *bbox, glCanvasHacktext *hacktext)
230 {
231         g_assert (bbox != NULL);
232         g_assert (hacktext != NULL);
233
234         g_return_if_fail (hacktext->priv);
235
236         if (GTK_OBJECT_FLAGS (hacktext) & GNOME_CANVAS_UPDATE_REQUESTED) {
237                 gnome_canvas_update_now (GNOME_CANVAS_ITEM (hacktext)->canvas);
238         }
239
240         if (!hacktext->priv->pgl) return;
241
242         gnome_pgl_bbox (hacktext->priv->pgl, bbox);
243 }
244
245 /* Computes the bounding box of the hacktext.  Assumes that the number of points in the hacktext is
246  * not zero.
247  */
248 static void
249 get_bounds (glCanvasHacktext *hacktext, double *bx1, double *by1, double *bx2, double *by2)
250 {
251         ArtDRect bbox;
252
253         /* Compute bounds of hacktext */
254         art_drect_hacktext (&bbox, hacktext);
255
256         /* Done */
257
258         *bx1 = bbox.x0;
259         *by1 = bbox.y0;
260         *bx2 = bbox.x1;
261         *by2 = bbox.y1;
262 }
263
264 #ifdef IFED_OUT_BY_CHEMA_TO_KILL_COMPILE_WARNING
265 /* Convenience function to set a GC's foreground color to the specified pixel value */
266 static void
267 set_gc_foreground (GdkGC *gc, gulong pixel)
268 {
269         GdkColor c;
270
271         if (!gc)
272                 return;
273
274         c.pixel = pixel;
275         gdk_gc_set_foreground (gc, &c);
276 }
277 #endif
278
279 static void
280 gl_canvas_hacktext_set_arg (GObject *object,
281                             guint arg_id,
282                             const GValue *value,
283                             GParamSpec *pspec)
284 {
285         GnomeCanvasItem *item;
286         glCanvasHacktext *bp;
287         char *text;
288         GnomeGlyphList * gl;
289         GdkColor color;
290         GnomeFont * font;
291
292         item = GNOME_CANVAS_ITEM (object);
293         bp = GL_CANVAS_HACKTEXT (object);
294
295         switch (arg_id) {
296         case ARG_TEXT:
297                 if (bp->text) {
298                         g_free (bp->text);
299                         bp->text = NULL;
300                 }
301
302                 if (bp->priv->glyphlist) {
303                         gnome_glyphlist_unref (bp->priv->glyphlist);
304                         bp->priv->glyphlist = NULL;
305                 }
306
307                 if (text) bp->text = g_value_dup_string (value);
308
309                 gnome_canvas_item_request_update (item);
310                 break;
311
312         case ARG_GLYPHLIST:
313                 gl = g_value_get_pointer (value);
314
315                 if (bp->text) {
316                         g_free (bp->text);
317                         bp->text = NULL;
318                 }
319
320                 if (bp->priv->glyphlist) {
321                         gnome_glyphlist_unref (bp->priv->glyphlist);
322                         bp->priv->glyphlist = NULL;
323                 }
324
325                 /* fixme: should be duplicate() */
326
327                 if (gl) gnome_glyphlist_ref (gl);
328
329                 bp->priv->glyphlist = gl;
330
331                 gnome_canvas_item_request_update (item);
332
333                 break;
334
335         case ARG_FILL_COLOR:
336                 if (gnome_canvas_get_color (item->canvas, g_value_get_string(value), &color)) {
337                         bp->fill_set = TRUE;
338                         bp->fill_pixel = color.pixel;
339                         bp->fill_rgba =
340                                 ((color.red & 0xff00) << 16) |
341                                 ((color.green & 0xff00) << 8) |
342                                 (color.blue & 0xff00) |
343                                 0xff;
344                 } else {
345                         bp->fill_set = FALSE;
346                         bp->fill_rgba = 0;
347                 }
348
349                 gnome_canvas_item_request_update (item);
350                 break;
351
352         case ARG_FILL_COLOR_RGBA:
353                 bp->fill_set = TRUE;
354                 bp->fill_rgba = g_value_get_uint (value);
355
356                 /* should probably request repaint on the fill_svp */
357                 gnome_canvas_item_request_update (item);
358
359                 break;
360
361         case ARG_FONT:
362                 font = g_value_get_pointer (value);
363                 if (font) gnome_font_ref (font);
364                 if (bp->priv->font) gnome_font_unref (bp->priv->font);
365                 bp->priv->font = font;
366                 bp->size = gnome_font_get_size (bp->priv->font);
367                 gnome_canvas_item_request_update (item);
368                 break;
369
370         case ARG_X:
371                 bp->x = g_value_get_double (value);
372                 gnome_canvas_item_request_update (item);
373                 break;
374
375         case ARG_Y:
376                 bp->y = g_value_get_double (value);
377                 gnome_canvas_item_request_update (item);
378                 break;
379
380         default:
381                 break;
382         }
383 }
384
385 static void
386 gl_canvas_hacktext_get_arg (GObject *object,
387                             guint arg_id,
388                             GValue *value,
389                             GParamSpec *pspec)
390 {
391         glCanvasHacktext *bp;
392
393         bp = GL_CANVAS_HACKTEXT (object);
394
395         switch (arg_id) {
396         case ARG_TEXT:
397                 if (bp->text) {
398                         g_value_set_string (value, g_strdup (bp->text));
399                 } else
400                         g_value_set_string (value,  NULL);
401                 break;
402         case ARG_FILL_COLOR_RGBA:
403                 g_value_set_uint (value, bp->fill_color);
404                 break;
405
406         case ARG_FONT:
407                 g_value_set_pointer (value, bp->priv->font);
408                 break;
409
410         case ARG_X:
411                 g_value_set_double (value, bp->x);
412                 break;
413
414         case ARG_Y:
415                 g_value_set_double (value, bp->y);
416                 break;
417
418         default:
419                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec);
420                 break;
421         }
422 }
423
424 static void
425 gl_canvas_hacktext_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
426 {
427         glCanvasHacktext *hacktext;
428         ArtIRect ibbox = {0, 0, 0, 0};
429
430         hacktext = (glCanvasHacktext *) item;
431
432         if (parent_class->update)
433                 (* parent_class->update) (item, affine, clip_path, flags);
434
435         if (hacktext->priv->pgl) gl_canvas_hacktext_req_repaint (hacktext, NULL);
436
437         gnome_canvas_item_reset_bounds (item);
438
439         hacktext->priv->affine[0] = affine[0];
440         hacktext->priv->affine[1] = affine[1];
441         hacktext->priv->affine[2] = -affine[2];
442         hacktext->priv->affine[3] = -affine[3];
443         hacktext->priv->affine[4] = affine[4] + hacktext->x * affine[0] + hacktext->y * affine[2];
444         hacktext->priv->affine[5] = affine[5] + hacktext->x * affine[1] + hacktext->y * affine[3];
445
446         if (hacktext->text) {
447                 if (hacktext->priv->glyphlist) {
448                         gnome_glyphlist_unref (hacktext->priv->glyphlist);
449                         hacktext->priv->glyphlist = NULL;
450                 }
451
452                 if (!hacktext->priv->font) return;
453
454                 hacktext->priv->glyphlist = gnome_glyphlist_from_text_dumb (hacktext->priv->font, hacktext->fill_rgba,
455                                                                             0.0, 0.0,
456                                                                             hacktext->text);
457         }
458
459         if (hacktext->priv->glyphlist) {
460                 GnomePosGlyphList * pgl;
461
462                 pgl = gnome_pgl_from_gl (hacktext->priv->glyphlist, hacktext->priv->affine, GNOME_PGL_RENDER_DEFAULT);
463
464                 if (hacktext->priv->pgl) gnome_pgl_destroy (hacktext->priv->pgl);
465
466                 hacktext->priv->pgl = pgl;
467         }
468                
469         gl_canvas_hacktext_req_repaint (hacktext, &ibbox);
470
471         hacktext->item.x1 = ibbox.x0;
472         hacktext->item.y1 = ibbox.y0;
473         hacktext->item.x2 = ibbox.x1;
474         hacktext->item.y2 = ibbox.y1;
475 }
476
477 static void
478 gl_canvas_hacktext_realize (GnomeCanvasItem *item)
479 {
480         glCanvasHacktext *hacktext;
481
482         hacktext = (glCanvasHacktext *) item;
483
484         if (parent_class->realize)
485                 (* parent_class->realize) (item);
486 }
487
488 static void
489 gl_canvas_hacktext_unrealize (GnomeCanvasItem *item)
490 {
491         glCanvasHacktext *hacktext;
492
493         hacktext = (glCanvasHacktext *) item;
494
495         if (parent_class->unrealize)
496                 (* parent_class->unrealize) (item);
497 }
498
499 static double
500 gl_canvas_hacktext_point (GnomeCanvasItem *item, double mx, double my,
501                             int cx, int cy, GnomeCanvasItem **actual_item)
502 {
503         glCanvasHacktext * hacktext;
504
505         hacktext = (glCanvasHacktext *) item;
506
507         if (!hacktext->priv->pgl) return 1e18;
508
509         *actual_item = item;
510
511         if (gnome_pgl_test_point (hacktext->priv->pgl, cx, cy)) return 0.0;
512
513         return 1e18;
514 }
515
516 static void
517 gl_canvas_hacktext_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
518 {
519         glCanvasHacktext *hacktext;
520
521         g_return_if_fail (item != NULL);
522         g_return_if_fail (GL_IS_CANVAS_HACKTEXT (item));
523
524         hacktext = GL_CANVAS_HACKTEXT (item);
525
526         if (hacktext->text == NULL) {
527                 *x1 = *y1 = *x2 = *y2 = 0.0;
528                 return;
529         }
530
531         get_bounds (hacktext, x1, y1, x2, y2);
532 }
533
534 static void
535 gl_canvas_hacktext_req_repaint (glCanvasHacktext *hacktext,
536                                    ArtIRect *bbox)
537 {
538         ArtDRect gbbox;
539
540         g_return_if_fail (hacktext->priv);
541
542         if (!hacktext->priv->pgl) return;
543
544         if (gnome_pgl_bbox (hacktext->priv->pgl, &gbbox)) {
545                 ArtIRect ibox;
546                 art_drect_to_irect (&ibox, &gbbox);
547                 gnome_canvas_request_redraw (hacktext->item.canvas, ibox.x0, ibox.y0, ibox.x1, ibox.y1);
548                 if (bbox) art_irect_union (bbox, bbox, &ibox);
549         }
550 }
551
552 static void
553 gl_canvas_hacktext_render (GnomeCanvasItem *item,
554                               GnomeCanvasBuf *buf)
555 {
556         glCanvasHacktext * hacktext;
557
558         hacktext = (glCanvasHacktext *) item;
559
560         g_return_if_fail (hacktext->priv);
561
562         if (!hacktext->priv->pgl) return;
563
564         gnome_canvas_buf_ensure_buf (buf);
565         buf->is_buf = TRUE;
566         buf->is_bg = FALSE;
567
568         gnome_rfont_render_pgl_rgb8 (hacktext->priv->pgl,
569                                      -buf->rect.x0, -buf->rect.y0,
570                                      buf->buf,
571                                      buf->rect.x1 - buf->rect.x0,
572                                      buf->rect.y1 - buf->rect.y0,
573                                      buf->buf_rowstride,
574                                      GNOME_RFONT_RENDER_DEFAULT);
575 }
576
577
578
579
580
581
582
583
584
585
586
587