~ubuntu-branches/ubuntu/intrepid/plplot/intrepid

« back to all changes in this revision

Viewing changes to drivers/gcw.c

  • Committer: Bazaar Package Importer
  • Author(s): Rafael Laboissiere
  • Date: 2006-11-04 10:19:34 UTC
  • mfrom: (2.1.8 edgy)
  • Revision ID: james.westby@ubuntu.com-20061104101934-mlirvdg4gpwi6i5q
Tags: 5.6.1-10
* Orphaning the package
* debian/control: Changed the maintainer to the Debian QA Group

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gcw-driver - PLplot Gnome Canvas Widget device driver.
 
2
 
 
3
  Copyright (C) 2004, 2005  Thomas J. Duck
 
4
  Copyright (C) 2004  Rafael Laboissiere
 
5
  All rights reserved.
 
6
 
 
7
 
 
8
NOTICE
 
9
 
 
10
  This library is free software; you can redistribute it and/or
 
11
  modify it under the terms of the GNU Lesser General Public
 
12
  License as published by the Free Software Foundation; either
 
13
  version 2.1 of the License, or (at your option) any later version.
 
14
 
 
15
  This library is distributed in the hope that it will be useful,
 
16
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
  Lesser General Public License for more details.
 
19
 
 
20
  You should have received a copy of the GNU Lesser General Public
 
21
  License along with this library; if not, write to the Free Software
 
22
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 
23
  USA 
 
24
 
 
25
 
 
26
DESCRIPTION
 
27
 
 
28
  This is the Gnome Canvas Widget driver, written by Thomas J. Duck 
 
29
  following the heritage of the PLplot Gnome driver by Rafael Laboissiere.  
 
30
  Like all PLplot drivers, this operates in standalone mode by default.  
 
31
  However, this driver can also be used to write to a user-supplied 
 
32
  GnomeCanvas.
 
33
 
 
34
  Please see the PLplot documentation for more information.
 
35
 
 
36
 
 
37
DEVELOPMENT NOTES
 
38
 
 
39
  Truetype text is supplied using the PLPLOT_CANVAS_HACKTEXT item,
 
40
  which was cloned from gnome-print.  This text item was chosen because 
 
41
  it rotates and scales under a zoom correctly and easily.
 
42
 
 
43
  It would be better to use GNOME_CANVAS_TEXT, but currently 
 
44
  (4 March 2005) it doesn't rotate or scale under a zoom on the 
 
45
  GnomeCanvas.  GNOME_CANVAS_TEXT uses Pango, and rotations were only
 
46
  recently implemented in the Pango API (i.e., Fall 2004).  If the
 
47
  Pango API is used directly, the bounding box doesn't rotate with the 
 
48
  text on GnomeCanvas, which results in clipping.  It is likely that
 
49
  GnomeCanvas is not querying the bounding box from Pango correctly,
 
50
  and is not directing Pango to scale.  So, GnomeCanvas needs to be 
 
51
  updated to deal with Pango properly.
 
52
 
 
53
  Another problem is that drawing polylines on the Gnome Canvas sometimes
 
54
  results in an 'attempt to put segment in horiz list twice' error.
 
55
  The workaround here is to plot single line segments only, but this
 
56
  results in a performance hit.  This problem will need to be corrected
 
57
  in the GnomeCanvas.
 
58
 
 
59
 
 
60
KNOWN BUGS
 
61
 
 
62
  PLplot test suite problems:
 
63
 
 
64
    1) Example x10c does not clip the text (there is no text clipping).
 
65
 
 
66
    2) Example x17c, the strip chart demo, doesn't do a strip chart 
 
67
       (try the xwin driver to see how it should work).  Strip charts 
 
68
       are fundamentally incompatible with the tabbed window design of
 
69
       the GCW driver.  Use the PlplotCanvas to create animations 
 
70
       instead.
 
71
*/
 
72
 
 
73
#include <sys/stat.h>
 
74
 
 
75
#include "gcw.h"
 
76
#include "plplotcanvas-hacktext.h"
 
77
 
 
78
#ifdef HAVE_FREETYPE
 
79
 
 
80
#include "plfreetype.h"
 
81
#include "plfci-truetype.h"
 
82
 
 
83
/* Font lookup table that is constructed in plD_FreeType_init*/
 
84
extern FCI_to_FontName_Table FontLookup[N_TrueTypeLookup];
 
85
 
 
86
extern void plD_FreeType_init(PLStream *pls);
 
87
extern void plD_FreeType_Destroy(PLStream *pls);
 
88
 
 
89
#endif /* HAVE_FREETYPE */
 
90
 
 
91
 
 
92
/* Device info */
 
93
char* plD_DEVICE_INFO_gcw = "gcw:Gnome Canvas Widget:1:gcw:10:gcw";
 
94
 
 
95
/* Global driver options */
 
96
 
 
97
#ifdef HAVE_FREETYPE
 
98
static PLINT text = 1;
 
99
#else
 
100
static PLINT text = 0;
 
101
#endif
 
102
 
 
103
static PLINT hrshsym = 0;
 
104
static PLINT replot = 1;
 
105
 
 
106
static DrvOpt gcw_options[] = 
 
107
  {
 
108
    {"text", DRV_INT, &text, "Use truetype fonts (text=0|1)"},
 
109
    {"hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)"},
 
110
    {"replot", DRV_INT, &replot, "Allow replotting to other devices (replot=0|1)"},
 
111
    {NULL, DRV_INT, NULL, NULL}
 
112
  };
 
113
 
 
114
 
 
115
/*********************
 
116
 * Utility functions *
 
117
 *********************/
 
118
 
 
119
guint32 plcolor_to_rgba(PLColor color, guchar alpha)
 
120
{
 
121
  return
 
122
    ((int)(color.r) << 24)
 
123
    + ((int)(color.g) << 16)
 
124
    + ((int)(color.b) << 8)
 
125
    + alpha;
 
126
}
 
127
 
 
128
 
 
129
/*--------------------------------------------------------------------------*\
 
130
 * plD_dispatch_init_gcw()
 
131
 *
 
132
 * Initializes the dispatch table.
 
133
\*--------------------------------------------------------------------------*/
 
134
 
 
135
void plD_open_gcw(PLStream *pls);
 
136
void plD_init_gcw(PLStream *);
 
137
void plD_line_gcw(PLStream *, short, short, short, short);
 
138
void plD_polyline_gcw(PLStream *, short *, short *, PLINT);
 
139
void plD_eop_gcw(PLStream *);
 
140
void plD_bop_gcw(PLStream *);
 
141
void plD_tidy_gcw(PLStream *);
 
142
void plD_state_gcw(PLStream *, PLINT);
 
143
void plD_esc_gcw(PLStream *, PLINT, void *);
 
144
 
 
145
void plD_dispatch_init_gcw( PLDispatchTable *pdt )
 
146
{
 
147
 
 
148
#ifdef DEBUG_GCW_1
 
149
  gcw_debug("<plD_dispatch_init_gcw>\n");
 
150
#endif
 
151
 
 
152
#ifndef ENABLE_DYNDRIVERS
 
153
  pdt->pl_MenuStr  = "Gnome Canvas Widget";
 
154
  pdt->pl_DevName  = "gcw";
 
155
#endif
 
156
  pdt->pl_type     = plDevType_Interactive;
 
157
  pdt->pl_seq      = 1;
 
158
  pdt->pl_init     = (plD_init_fp)     plD_init_gcw;
 
159
  pdt->pl_line     = (plD_line_fp)     plD_line_gcw;
 
160
  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_gcw;
 
161
  pdt->pl_eop      = (plD_eop_fp)      plD_eop_gcw;
 
162
  pdt->pl_bop      = (plD_bop_fp)      plD_bop_gcw;
 
163
  pdt->pl_tidy     = (plD_tidy_fp)     plD_tidy_gcw;
 
164
  pdt->pl_state    = (plD_state_fp)    plD_state_gcw;
 
165
  pdt->pl_esc      = (plD_esc_fp)      plD_esc_gcw;
 
166
 
 
167
#ifdef DEBUG_GCW_1
 
168
  gcw_debug("</plD_dispatch_init_gcw>\n");
 
169
#endif
 
170
}
 
171
 
 
172
 
 
173
/*--------------------------------------------------------------------------*\
 
174
 * plD_init_gcw()
 
175
 *
 
176
 * Initializes the device.
 
177
 *
 
178
 * This routine is invoked by a call to plinit.
 
179
 *
 
180
\*--------------------------------------------------------------------------*/
 
181
 
 
182
void plD_init_gcw(PLStream *pls)
 
183
{
 
184
  GcwPLdev* dev;
 
185
 
 
186
  PLINT width, height, tmp;
 
187
 
 
188
  PLColor bgcolor = pls->cmap0[0];
 
189
 
 
190
#ifdef DEBUG_GCW_1
 
191
  gcw_debug("<plD_init_gcw>\n");
 
192
#endif
 
193
 
 
194
  /* Parse the driver options */
 
195
  plParseDrvOpts(gcw_options);
 
196
 
 
197
  /* Set up the stream */
 
198
  pls->termin = 1;      /* Is an interactive terminal */
 
199
  pls->dev_flush = 1;   /* Handle our own flushes */
 
200
  pls->plbuf_write = replot; /* Use plot buffer to replot to another device */
 
201
  pls->width = 1;
 
202
  pls->dev_clear = 0;   /* Handle plclear() */
 
203
  pls->dev_fill0 = 1;   /* Handle solid fills */
 
204
 
 
205
  /* Create the device */
 
206
  if((dev = g_malloc(sizeof(GcwPLdev))) == NULL) 
 
207
    plexit("GCW driver <plD_init_gcw>: Cannot create device");
 
208
  pls->dev = dev;
 
209
 
 
210
  /* Set text handling */
 
211
#ifdef HAVE_FREETYPE
 
212
  if(text) {
 
213
    pls->dev_text = TRUE;
 
214
    pls->dev_unicode = TRUE;
 
215
    if(hrshsym) pls->dev_hrshsym = 1;
 
216
 
 
217
    /* Initialize freetype */
 
218
    plD_FreeType_init(pls);
 
219
  }
 
220
  else {
 
221
    pls->dev_text = FALSE;
 
222
    pls->dev_unicode = FALSE;
 
223
  }
 
224
#else
 
225
  pls->dev_text = FALSE;
 
226
  pls->dev_unicode = FALSE;
 
227
#endif
 
228
 
 
229
  /* Set up pixmap support */
 
230
  dev->use_pixmap = (gboolean)(!pls->nopixmap);
 
231
  dev->pixmap_has_data = FALSE;
 
232
 
 
233
  /* Initialize the device colors */
 
234
  dev->color = plcolor_to_rgba(pls->cmap0[pls->icol0],0xFF);
 
235
  dev->bgcolor.red=(guint16)(bgcolor.r/255.*65535); 
 
236
  dev->bgcolor.green=(guint16)(bgcolor.b/255.*65535); 
 
237
  dev->bgcolor.blue=(guint16)(bgcolor.g/255.*65535);
 
238
 
 
239
  /* Set the device canvas and window pointers */
 
240
  dev->canvas = NULL;
 
241
  dev->background = NULL;
 
242
  dev->gc = NULL;
 
243
  dev->colormap = NULL;
 
244
  dev->window = NULL;
 
245
  dev->notebook = NULL;
 
246
  dev->statusbar = NULL;
 
247
  dev->filew = NULL;
 
248
    
 
249
  /* Initialize the Canvas groups.  All of the plplot plotting
 
250
   * commands are drawn to the hidden group.  When the page is finalized,
 
251
   * the group is made visible, and the old group destroyed. The persistent
 
252
   * group is never erased, and always plotted at the very front.
 
253
   */
 
254
  dev->group_visible=NULL;
 
255
  dev->group_hidden=NULL;
 
256
  dev->group_persistent=NULL;
 
257
 
 
258
  /* Assume that pladv should completeley refresh the page */
 
259
  dev->use_persistence = FALSE;
 
260
 
 
261
  /* Set the initialization state monitors to FALSE */
 
262
  dev->plstate_width = FALSE;
 
263
  dev->plstate_color0 = FALSE;
 
264
  dev->plstate_color1 = FALSE;
 
265
 
 
266
  /* Initialize gtk */
 
267
  gtk_init(0,NULL);
 
268
 
 
269
  /* Set up the physical device in the next series of commands.  It is very 
 
270
   * important to do this properly, because many PLplot routines depend on
 
271
   * physical coordinates (e.g., dashed lines, hatched areas, the
 
272
   * replot mechanism, hidden line removal, etc.
 
273
   *
 
274
   * Note that coordinates in the driver are measured in device units,
 
275
   * which correspond to the pixel size on a typical screen.  The coordinates
 
276
   * reported and received from the PLplot core, however, are in virtual
 
277
   * coordinates, which is just a scaled version of the device coordinates.
 
278
   * This strategy is used so that the calculations in the PLplot
 
279
   * core are performed at reasonably high resolution.
 
280
   *
 
281
   */
 
282
  if (pls->xlength > 0 && pls->ylength > 0) {
 
283
    /* xlength and length are the dimensions specified using -geometry
 
284
     * on the command line, in device coordinates.
 
285
     */
 
286
    width = pls->xlength;
 
287
    height = pls->ylength;
 
288
  }
 
289
  else {    
 
290
    width = (PLINT)(CANVAS_WIDTH*DEVICE_PIXELS_PER_IN);
 
291
    height = (PLINT)(CANVAS_HEIGHT*DEVICE_PIXELS_PER_IN);
 
292
  }
 
293
 
 
294
  /* If portrait mode, apply a rotation and set freeaspect */
 
295
  if(pls->portrait) {
 
296
    plsdiori((PLFLT)(4 - ORIENTATION));
 
297
    pls->freeaspect = 1;
 
298
  }
 
299
 
 
300
  /* Setup the page size for this device.  Very important for any driver! */
 
301
  gcw_set_device_size(width,height);
 
302
 
 
303
  /* Install a canvas... unless plsc->hack is set, which is a driver-specific
 
304
   * hack that indicates a PLESC_DEVINIT escape call will provide us with a 
 
305
   * canvas to use.  This hack is used by the PlplotCanvas.
 
306
   */
 
307
  if(!pls->hack) {
 
308
    dev->allow_resize = FALSE; /* The size is set an should not be changed */
 
309
    gcw_install_canvas(NULL);
 
310
  }
 
311
  else dev->allow_resize = TRUE; /* Resizing allowed for canvasses
 
312
                                  * provided via PLESC_DEVINIT */
 
313
 
 
314
 
 
315
#ifdef DEBUG_GCW_1
 
316
  gcw_debug("</plD_init_gcw>\n");
 
317
#endif
 
318
}
 
319
 
 
320
 
 
321
/*--------------------------------------------------------------------------*\
 
322
 * plD_polyline_gcw()
 
323
 *
 
324
 * Draw a polyline in the current color.
 
325
\*--------------------------------------------------------------------------*/
 
326
 
 
327
void plD_polyline_gcw(PLStream *pls, short *x, short *y, PLINT npts)
 
328
{
 
329
  GcwPLdev* dev = pls->dev;
 
330
  GnomeCanvasPoints* points;
 
331
  GnomeCanvasPoints pts;
 
332
  GnomeCanvasGroup* group;
 
333
  GnomeCanvasItem* item;
 
334
  GnomeCanvas* canvas;
 
335
 
 
336
  GdkPoint* gdkpoints;
 
337
 
 
338
  PLINT i;
 
339
 
 
340
  gdouble width;
 
341
  guint32 color;
 
342
 
 
343
#ifdef DEBUG_GCW_2
 
344
  gcw_debug("<plD_polyline_gcw />\n");
 
345
#endif
 
346
 
 
347
  if(!GNOME_IS_CANVAS(dev->canvas))
 
348
    plexit("GCW driver <plD_polyline_gcw>: Canvas not found");
 
349
  canvas = dev->canvas;
 
350
 
 
351
  if(dev->use_persistence) group = dev->group_persistent;
 
352
  else group = dev->group_hidden;
 
353
 
 
354
  if(dev->use_pixmap && !dev->use_persistence) { /* Write to bg pixmap */
 
355
 
 
356
    if((gdkpoints = (GdkPoint*)malloc(npts*sizeof(GdkPoint)))==NULL)
 
357
      plabort("GCW driver <plD_polyline_gcw>: Could not create gdkpoints");
 
358
 
 
359
    if(!pls->portrait) {
 
360
      for(i=0;i<npts;i++) {
 
361
        gdkpoints[i].x = (gint)(x[i]/VSCALE);
 
362
        gdkpoints[i].y = (gint)(dev->height-y[i]/VSCALE);
 
363
      }
 
364
    }
 
365
    else { /* Swap x and y for portrait mode */
 
366
      for(i=0;i<npts;i++) {
 
367
        gdkpoints[i].x = (gint)(dev->height-y[i]/VSCALE);
 
368
        gdkpoints[i].y = (gint)(dev->width-x[i]/VSCALE);
 
369
      }
 
370
    }
 
371
 
 
372
    gdk_draw_lines(dev->background,dev->gc,gdkpoints,npts);
 
373
 
 
374
    dev->pixmap_has_data = TRUE;
 
375
 
 
376
    free(gdkpoints);
 
377
  }
 
378
  else { /* Draw Canvas lines */
 
379
 
 
380
    /* Put the data in a points structure */
 
381
    if( (points = gnome_canvas_points_new(npts)) == NULL )
 
382
      plabort("GCW driver <plD_polyline_gcw>: Cannot create points");
 
383
    if(!pls->portrait) {
 
384
      for ( i = 0; i < npts; i++ ) {
 
385
        points->coords[2*i] = (gdouble)(x[i]/VSCALE);
 
386
        points->coords[2*i + 1] = (gdouble)(-y[i]/VSCALE);
 
387
      }
 
388
    }
 
389
    else { /* Swap x and y for portrait mode */
 
390
      for ( i = 0; i < npts; i++ ) {
 
391
        points->coords[2*i] = (gdouble)(dev->height-y[i]/VSCALE);
 
392
        points->coords[2*i + 1] = (gdouble)(-x[i]/VSCALE);
 
393
      }
 
394
    }
 
395
    
 
396
    /* Get the pen width and color */
 
397
    width = pls->width;
 
398
    color = dev->color;
 
399
 
 
400
 
 
401
    /* Workaround for the 'attempt to put segment in horiz list twice'
 
402
     * from libgnomecanvas:
 
403
     *
 
404
     *   Plot a series of line segments rather than a single polyline.
 
405
     *
 
406
     * This slows rendering down a considerable amount.  However, it is 
 
407
     * unclear what else can be done.  Libgnomecanvas should be able to 
 
408
     * deal with all valid data; bizarre plotting errors happen along with
 
409
     * this error.
 
410
     *
 
411
     * Note that instead of allocating a series of points structures, 
 
412
     * we just refer to the original one from a separate struct 
 
413
     * (GnomeCanvas does not hold a reference to the points structure).
 
414
     */
 
415
 
 
416
    pts.num_points = 2;
 
417
    pts.ref_count = 1;
 
418
    pts.coords = points->coords;
 
419
      
 
420
    for(i=0;i<npts-1;i++) {
 
421
      pts.coords=&(points->coords[2*i]);
 
422
 
 
423
      if(!GNOME_IS_CANVAS_ITEM(
 
424
            item=gnome_canvas_item_new(group,
 
425
                                       GNOME_TYPE_CANVAS_LINE,
 
426
                                       "cap_style", GDK_CAP_ROUND,
 
427
                                       "join-style", GDK_JOIN_ROUND,
 
428
                                       "points", &pts,
 
429
                                       "fill-color-rgba", color,
 
430
                                       "width-units", width,
 
431
                                       NULL)
 
432
      )) {
 
433
        plwarn("GCW driver <plD_polyline_gcw>: Canvas item not created.");
 
434
      }
 
435
    }
 
436
 
 
437
    /* Free the points structure */
 
438
    gnome_canvas_points_free(points);
 
439
  }
 
440
}
 
441
 
 
442
 
 
443
/*--------------------------------------------------------------------------*\
 
444
 * plD_line_gcw()
 
445
 *
 
446
 * Draw a line in the current color from (x1,y1) to (x2,y2).
 
447
\*--------------------------------------------------------------------------*/
 
448
 
 
449
void plD_line_gcw(PLStream *pls, short x1, short y1, short x2, short y2)
 
450
{
 
451
  short x[2];
 
452
  short y[2];
 
453
 
 
454
#ifdef DEBUG_GCW_2
 
455
  gcw_debug("<plD_line_gcw />\n");
 
456
#endif
 
457
 
 
458
  x[0] = x1;
 
459
  x[1] = x2;
 
460
  y[0] = y1;
 
461
  y[1] = y2;
 
462
 
 
463
  plD_polyline_gcw(pls, x, y, (PLINT) 2);
 
464
}
 
465
 
 
466
 
 
467
/*--------------------------------------------------------------------------*\
 
468
 * plD_eop_gcw()
 
469
 *
 
470
 * End of page.
 
471
\*--------------------------------------------------------------------------*/
 
472
 
 
473
void plD_eop_gcw(PLStream *pls)
 
474
{
 
475
  GcwPLdev* dev = pls->dev;
 
476
  GnomeCanvas* canvas;
 
477
 
 
478
  GdkPixbuf* pixbuf;
 
479
  GnomeCanvasItem* item;
 
480
  GnomeCanvasGroup* group;
 
481
 
 
482
  gdouble dx, dy;
 
483
 
 
484
  FILE *f;
 
485
  gint count=1,n;
 
486
  U_CHAR tmp;
 
487
 
 
488
  gint *icol,*ncol;
 
489
  PLColor *cmap;
 
490
 
 
491
  guint i;
 
492
 
 
493
  PLINT width,height;
 
494
 
 
495
  if(!GNOME_IS_CANVAS(dev->canvas))
 
496
    plexit("GCW driver <plD_eop_gcw>: Canvas not found");
 
497
  canvas = dev->canvas;
 
498
 
 
499
  /* Ignore if there is no hidden group.  This means BOP has not been
 
500
   * called yet.
 
501
   */
 
502
  if(!GNOME_IS_CANVAS_GROUP(dev->group_hidden)) return;
 
503
 
 
504
#ifdef DEBUG_GCW_1
 
505
  gcw_debug("<plD_eop_gcw>\n");
 
506
#endif
 
507
 
 
508
  if(dev->use_persistence) group = dev->group_persistent;
 
509
  else group = dev->group_hidden;
 
510
 
 
511
  /* Retrieve the device width and height of the canvas */
 
512
  width = *(PLINT*)g_object_get_data(G_OBJECT(canvas),"canvas-width");
 
513
  height = *(PLINT*)g_object_get_data(G_OBJECT(canvas),"canvas-height");
 
514
 
 
515
  if(dev->pixmap_has_data) {
 
516
 
 
517
    /* Render the pixmap to a pixbuf on the canvas. */
 
518
    if(!GDK_IS_PIXBUF(pixbuf=gdk_pixbuf_get_from_drawable(NULL,
 
519
                              dev->background,
 
520
                              dev->colormap,
 
521
                              0,0,
 
522
                              0,0,
 
523
                              width,height))) {
 
524
      plwarn("GCW driver <plD_eop_gcw>: Can't draw pixmap into pixbuf.");
 
525
    }
 
526
    else { /* Pixbuf creation succeeded */
 
527
 
 
528
      if(!GNOME_IS_CANVAS_ITEM(
 
529
            item = gnome_canvas_item_new(dev->group_hidden,
 
530
                                         GNOME_TYPE_CANVAS_PIXBUF,
 
531
                                         "pixbuf",pixbuf,
 
532
                                         "x", 1.,
 
533
                                         "y", (gdouble)(-height+1.),
 
534
                                         "width", (gdouble)(width),
 
535
                                         "height", (gdouble)(height),
 
536
                                         NULL)
 
537
      )) {
 
538
        plwarn("GCW driver <plD_eop_gcw>: Canvas item not created.");
 
539
      }
 
540
 
 
541
      /* Free the pixbuf */
 
542
      g_object_unref(pixbuf);
 
543
    }
 
544
  }
 
545
  else {
 
546
 
 
547
    /* Use a rectangle for the background instead (faster) */
 
548
    if(!GNOME_IS_CANVAS_ITEM(
 
549
          item = gnome_canvas_item_new(
 
550
                       dev->group_hidden,
 
551
                       GNOME_TYPE_CANVAS_RECT,
 
552
                       "x1", 0.,
 
553
                       "y1", (gdouble)(-height),
 
554
                       "x2", (gdouble)(width),
 
555
                       "y2", 0.,
 
556
                       "fill-color-rgba", plcolor_to_rgba(pls->cmap0[0],0xFF),
 
557
                       "width-units", 0.,
 
558
                       NULL)
 
559
    )) {
 
560
      plabort("GCW driver <pld_eop_gcw>: Canvas item not created");
 
561
    }
 
562
  }
 
563
 
 
564
  /* Move the persistent group to the front */
 
565
  gnome_canvas_item_raise_to_top(GNOME_CANVAS_ITEM(dev->group_persistent));
 
566
 
 
567
  /* Move the background to the back */
 
568
  if(GNOME_IS_CANVAS_ITEM(item)) gnome_canvas_item_lower_to_bottom(item);
 
569
    
 
570
  /* Make the hidden group visible */
 
571
  gnome_canvas_item_show(GNOME_CANVAS_ITEM(dev->group_hidden));
 
572
 
 
573
  /* Destroy the old visible group */
 
574
  if(GNOME_IS_CANVAS_GROUP(dev->group_visible)) {
 
575
    gtk_object_destroy((GtkObject*)(dev->group_visible));
 
576
    dev->group_visible = NULL;
 
577
  }
 
578
 
 
579
  /* Clear the background pixmap */
 
580
  if(!dev->use_persistence && dev->pixmap_has_data) gcw_clear_background();
 
581
 
 
582
  /* Name the hidden group as visible */
 
583
  dev->group_visible = dev->group_hidden;
 
584
  dev->group_hidden=NULL;
 
585
  
 
586
  /* Update the canvas */
 
587
  canvas->need_update = 1;
 
588
  gnome_canvas_update_now(canvas);
 
589
 
 
590
  /*
 
591
   * Copy the plot buffer for future reference, otherwise it is 
 
592
   * thrown out.  We will also need to store the colormaps.
 
593
   */
 
594
  if(pls->plbuf_write) {
 
595
    
 
596
    pls->plbuf_write = FALSE;
 
597
    pls->plbuf_read = TRUE;
 
598
    
 
599
    /* Remove the old tempfile, if it exists */
 
600
    if( (f=g_object_get_data(G_OBJECT(canvas),"plotbuf")) != NULL ) {
 
601
      fclose(f);
 
602
      g_object_set_data(G_OBJECT(canvas),"plotbuf",NULL);
 
603
    }
 
604
 
 
605
    /* Copy the plot buffer to a tempfile */
 
606
    if((f=tmpfile())==NULL) {
 
607
      plwarn("GCW driver <plD_eop_gcw>: Could not create tempfile.");
 
608
    }
 
609
    else {
 
610
      rewind(pls->plbufFile);
 
611
      while(count = fread(&tmp, sizeof(U_CHAR), 1, pls->plbufFile)) {
 
612
        if(fwrite(&tmp, sizeof(U_CHAR), 1, f)!=count) {
 
613
          plwarn("GCW driver <plD_eop_gcw>: Could not write to tempfile.");
 
614
          fclose(f);
 
615
          f=NULL;
 
616
        }
 
617
      }
 
618
      
 
619
      /* Attach the tempfile to the canvas */
 
620
      g_object_set_data(G_OBJECT(canvas),"plotbuf",(gpointer)f);
 
621
      
 
622
      pls->plbuf_write = TRUE;
 
623
      pls->plbuf_read = FALSE;      
 
624
      
 
625
      /* cmap 0 */
 
626
      if((icol=(gint*)malloc(sizeof(gint)))==NULL)
 
627
        plwarn("GCW driver <plD_eop_gcw>: Insufficient memory.");
 
628
      else *icol = pls->icol0;
 
629
      g_object_set_data(G_OBJECT(canvas),"icol0",(gpointer)icol);
 
630
      if((ncol=(gint*)malloc(sizeof(gint)))==NULL)
 
631
        plwarn("GCW driver <plD_eop_gcw>: Insufficient memory.");
 
632
      else *ncol = pls->ncol0;
 
633
      g_object_set_data(G_OBJECT(canvas),"ncol0",(gpointer)ncol);
 
634
      if((cmap=(PLColor *) calloc(1, pls->ncol0 * sizeof(PLColor)))==NULL) {
 
635
        plwarn("GCW driver <plD_eop_gcw>: Insufficient memory.");
 
636
      }
 
637
      else {
 
638
        for (i = 0; i < pls->ncol0; i++)
 
639
          pl_cpcolor(&cmap[i], &pls->cmap0[i]);
 
640
      }
 
641
      g_object_set_data(G_OBJECT(canvas),"cmap0",(gpointer)cmap);
 
642
      
 
643
      /* cmap 1 */
 
644
      if((icol=(gint*)malloc(sizeof(gint)))==NULL)
 
645
        plwarn("GCW driver <plD_eop_gcw>: Insufficient memory.");
 
646
 
 
647
      else *icol = pls->icol1;
 
648
      g_object_set_data(G_OBJECT(canvas),"icol1",(gpointer)icol);
 
649
      if((ncol=(gint*)malloc(sizeof(gint)))==NULL)
 
650
        plwarn("GCW driver <plD_eop_gcw>: Insufficient memory.");
 
651
      else *ncol = pls->ncol1;
 
652
      g_object_set_data(G_OBJECT(canvas),"ncol1",(gpointer)ncol);
 
653
      if((cmap=(PLColor *) calloc(1, pls->ncol1 * sizeof(PLColor)))==NULL) {
 
654
        plwarn("GCW driver <plD_eop_gcw>: Insufficient memory.");
 
655
      }
 
656
      else {
 
657
        for (i = 0; i < pls->ncol1; i++)
 
658
          pl_cpcolor(&cmap[i], &pls->cmap1[i]);
 
659
      }
 
660
      g_object_set_data(G_OBJECT(canvas),"cmap1",(gpointer)cmap);
 
661
    }
 
662
  }
 
663
  
 
664
  /* If the driver is creating its own canvasses, set dev->canvas to be
 
665
   * NULL now in order to force creation of a new canvas when the next
 
666
   * drawing call is made.  The new canvas will be placed in a new
 
667
   * notebook page.
 
668
   */
 
669
  if(dev->window!=NULL) {
 
670
    dev->canvas = NULL;
 
671
    dev->group_visible = NULL;
 
672
    dev->group_hidden = NULL;
 
673
    dev->group_persistent = NULL;
 
674
  }
 
675
 
 
676
#ifdef DEBUG_GCW_1
 
677
  gcw_debug("</plD_eop_gcw>\n");
 
678
#endif
 
679
}
 
680
 
 
681
 
 
682
/*--------------------------------------------------------------------------*\
 
683
 * plD_bop_gcw()
 
684
 *
 
685
 * Set up for the next page.
 
686
 *
 
687
\*--------------------------------------------------------------------------*/
 
688
 
 
689
void plD_bop_gcw(PLStream *pls)
 
690
{
 
691
  GcwPLdev* dev = pls->dev;
 
692
  GnomeCanvas* canvas;
 
693
 
 
694
  if(!GNOME_IS_CANVAS(dev->canvas)) {
 
695
    if(pls->hack) return; /* Wait for a canvas via DEVINIT */
 
696
    else gcw_install_canvas(NULL);
 
697
  }
 
698
  canvas = dev->canvas;
 
699
 
 
700
#ifdef DEBUG_GCW_1
 
701
  gcw_debug("<plD_bop_gcw>\n");
 
702
#endif
 
703
 
 
704
  /* Replay escape calls that come in before PLESC_DEVINIT.  Some of them
 
705
   * required a Canvas that didn't exist yet.
 
706
   */
 
707
  if(dev->plstate_width)  plD_state_gcw(pls, PLSTATE_WIDTH);
 
708
  if(dev->plstate_color0) plD_state_gcw(pls, PLSTATE_COLOR0);
 
709
  if(dev->plstate_color1) plD_state_gcw(pls, PLSTATE_COLOR1);
 
710
  dev->plstate_width = FALSE;
 
711
  dev->plstate_color0 = FALSE;
 
712
  dev->plstate_color1 = FALSE;
 
713
  
 
714
  /* Creat a new hidden group; all new drawing will be to this group */
 
715
  if(!GNOME_IS_CANVAS_ITEM(
 
716
    dev->group_hidden = GNOME_CANVAS_GROUP(gnome_canvas_item_new(
 
717
                                             gnome_canvas_root(canvas),
 
718
                                             gnome_canvas_clipgroup_get_type(),
 
719
                                             "x",0.,
 
720
                                             "y",0.,
 
721
                                             NULL))
 
722
    )) {
 
723
    plexit("GCW driver <plD_bop_gcw>: Canvas group cannot be created");
 
724
  }
 
725
  
 
726
  /* Set the clip to NULL */
 
727
  g_object_set(G_OBJECT(dev->group_hidden),"path",NULL,NULL);
 
728
  
 
729
  /* Hide this group until drawing is done */
 
730
  gnome_canvas_item_hide(GNOME_CANVAS_ITEM(dev->group_hidden));
 
731
 
 
732
#ifdef DEBUG_GCW_1
 
733
  gcw_debug("</plD_bop_gcw>\n");
 
734
#endif
 
735
}
 
736
 
 
737
 
 
738
/*--------------------------------------------------------------------------*\
 
739
 * plD_tidy_gcw()
 
740
 *
 
741
 * Close graphics file
 
742
\*--------------------------------------------------------------------------*/
 
743
 
 
744
void plD_tidy_gcw(PLStream *pls)
 
745
{
 
746
  GcwPLdev* dev = pls->dev;
 
747
 
 
748
#ifdef DEBUG_GCW_1
 
749
  gcw_debug("<plD_tidy_gcw>\n");
 
750
#endif
 
751
 
 
752
#ifdef HAVE_FREETYPE
 
753
  if (pls->dev_text) {
 
754
    FT_Data *FT=(FT_Data *)pls->FT;
 
755
    plscmap0n(FT->ncol0_org);
 
756
    plD_FreeType_Destroy(pls);
 
757
  }
 
758
#endif
 
759
 
 
760
  if(dev->window!=NULL) {
 
761
    gtk_main ();
 
762
  }
 
763
 
 
764
#ifdef DEBUG_GCW_1
 
765
  gcw_debug("</plD_tidy_gcw>\n");
 
766
#endif
 
767
}
 
768
 
 
769
 
 
770
/*--------------------------------------------------------------------------*\
 
771
 * plD_state_gcw()
 
772
 *
 
773
 * Handle change in PLStream state (color, pen width, fill attribute, etc).
 
774
 *
 
775
 * Note that PLplot sometimes tries to change states before the device is
 
776
 * fully initialized (i.e., via PLESC_DEVINIT).  We must keep track of
 
777
 * such attempts, and invoke the state change during the next call to
 
778
 * plD_bop_gcw.
 
779
 *
 
780
\*--------------------------------------------------------------------------*/
 
781
 
 
782
void plD_state_gcw(PLStream *pls, PLINT op)
 
783
{
 
784
  GcwPLdev* dev = pls->dev;
 
785
  char opname[20],msg[100];
 
786
 
 
787
#ifdef DEBUG_GCW_1
 
788
  if(op==PLSTATE_WIDTH) strcpy(opname,"PLSTATE_WIDTH");
 
789
  else if(op==PLSTATE_COLOR0) strcpy(opname,"PLSTATE_COLOR0");
 
790
  else if(op==PLSTATE_COLOR1) strcpy(opname,"PLSTATE_COLOR1");
 
791
  else if(op==PLSTATE_FILL) strcpy(opname,"PLSTATE_FILL");
 
792
  else if(op==PLSTATE_CMAP0) strcpy(opname,"PLSTATE_CMAP0");
 
793
  else if(op==PLSTATE_CMAP1) strcpy(opname,"PLSTATE_CMAP1");
 
794
  else strcpy(opname,"unknown");
 
795
  sprintf(msg,"<plD_state_gcw />: %s\n",opname);
 
796
  gcw_debug(msg);
 
797
#endif
 
798
 
 
799
  switch (op) {
 
800
 
 
801
    case PLSTATE_WIDTH:
 
802
      if(GNOME_IS_CANVAS(dev->canvas)) {
 
803
        if(dev->use_pixmap) {
 
804
          gdk_gc_set_line_attributes(dev->gc, pls->width,
 
805
                                     GDK_LINE_SOLID,
 
806
                                     GDK_CAP_BUTT,
 
807
                                     GDK_JOIN_MITER);
 
808
        }
 
809
      }
 
810
      else dev->plstate_width = TRUE;
 
811
      break;
 
812
 
 
813
    case PLSTATE_COLOR0:
 
814
      if(GNOME_IS_CANVAS(dev->canvas)) {
 
815
        dev->color = plcolor_to_rgba(pls->cmap0[pls->icol0],0xFF);
 
816
        if(dev->use_pixmap) gcw_set_gdk_color();
 
817
      }
 
818
      else dev->plstate_color0 = TRUE;
 
819
      break;
 
820
 
 
821
    case PLSTATE_COLOR1:
 
822
      if(GNOME_IS_CANVAS(dev->canvas)) {
 
823
        dev->color = plcolor_to_rgba(pls->cmap1[pls->icol1],0xFF);
 
824
        if(dev->use_pixmap) gcw_set_gdk_color();
 
825
      }
 
826
      else dev->plstate_color1 = TRUE;
 
827
      break;
 
828
 
 
829
    case PLSTATE_FILL:
 
830
      break;
 
831
 
 
832
    case PLSTATE_CMAP0:
 
833
      break;
 
834
 
 
835
    case PLSTATE_CMAP1:
 
836
      break;
 
837
 
 
838
    default: 
 
839
      break;
 
840
  }
 
841
}
 
842
 
 
843
 
 
844
/*--------------------------------------------------------------------------*\
 
845
 * fill_polygon()
 
846
 *
 
847
 * Fills the polygon defined by the given points.  Used for shade
 
848
 * plotting.  Only solid fills are allowed.
 
849
\*--------------------------------------------------------------------------*/
 
850
 
 
851
static void fill_polygon (PLStream* pls)
 
852
{
 
853
  GnomeCanvasPoints* points;
 
854
  GnomeCanvasGroup* group;
 
855
  GnomeCanvasItem* item;
 
856
  GcwPLdev* dev = pls->dev;
 
857
  GnomeCanvas* canvas;
 
858
  
 
859
  PLINT i;
 
860
 
 
861
  GdkPoint* gdkpoints;
 
862
 
 
863
  PLINT tmp;
 
864
 
 
865
#ifdef DEBUG_GCW_2
 
866
  gcw_debug("<fill_polygon />\n");
 
867
#endif
 
868
 
 
869
  if(!GNOME_IS_CANVAS(dev->canvas))
 
870
    plexit("GCW driver <fill_polygon>: Canvas not found");
 
871
  canvas = dev->canvas;
 
872
 
 
873
  if(dev->use_persistence) group = dev->group_persistent;
 
874
  else group = dev->group_hidden;
 
875
 
 
876
  if(dev->use_pixmap && !dev->use_persistence) { /* Write to a pixmap */
 
877
 
 
878
    if((gdkpoints = (GdkPoint*)malloc(pls->dev_npts*sizeof(GdkPoint)))==NULL)
 
879
      plabort("GCW driver <fill_polygon>: Could not create gdkpoints");
 
880
 
 
881
    if(!pls->portrait) {
 
882
      for(i=0;i<pls->dev_npts;i++) {
 
883
        gdkpoints[i].x = (gint)(pls->dev_x[i]/VSCALE);
 
884
        gdkpoints[i].y = (gint)(dev->height-pls->dev_y[i]/VSCALE);
 
885
      }
 
886
    }
 
887
    else { /* Swap x and y for portrait mode */
 
888
      for(i=0;i<pls->dev_npts;i++) {
 
889
        gdkpoints[i].x = (gint)(dev->height-pls->dev_y[i]/VSCALE);
 
890
        gdkpoints[i].y = (gint)(dev->width-pls->dev_x[i]/VSCALE);
 
891
      }
 
892
    }
 
893
 
 
894
    gdk_draw_polygon(dev->background,dev->gc,TRUE,gdkpoints,pls->dev_npts);
 
895
    
 
896
    dev->pixmap_has_data = TRUE;
 
897
 
 
898
    free(gdkpoints);
 
899
  }
 
900
  else { /* Use Gnome Canvas polygons */
 
901
 
 
902
    if( (points = gnome_canvas_points_new (pls->dev_npts)) == NULL )
 
903
      plabort("GCW driver <fill_polygon>: Could not create points");
 
904
 
 
905
    if(!pls->portrait) {
 
906
      for (i=0; i<pls->dev_npts; i++) {
 
907
        points->coords[2*i] = (gdouble)(pls->dev_x[i]/VSCALE);
 
908
        points->coords[2*i + 1] = (gdouble)(-pls->dev_y[i]/VSCALE);
 
909
      }
 
910
    }
 
911
    else { /* Swap x and y for portrait mode */
 
912
      for (i=0; i<pls->dev_npts; i++) {
 
913
        points->coords[2*i] = (gdouble)(dev->height-pls->dev_y[i]/VSCALE);
 
914
        points->coords[2*i + 1] = (gdouble)(-pls->dev_x[i]/VSCALE);
 
915
      } 
 
916
    }
 
917
 
 
918
    if(!GNOME_IS_CANVAS_ITEM(
 
919
      item = gnome_canvas_item_new (group,
 
920
                                    GNOME_TYPE_CANVAS_POLYGON,
 
921
                                    "points", points,
 
922
                                    "fill-color-rgba",dev->color,
 
923
                                    /* "outline-color-rgba",dev->color, */
 
924
                                    NULL)
 
925
      )) {
 
926
      plwarn("GCW driver <fill_polygon>: Canvas item not created.");
 
927
    }
 
928
  
 
929
    gnome_canvas_points_free(points);
 
930
 
 
931
 
 
932
    /* Draw a thin outline for each polygon; note that doing this
 
933
     * using the "outline-color-rgba" property above can result in 
 
934
     * Canvas errors.
 
935
     */
 
936
    tmp = pls->width;
 
937
    pls->width=1;
 
938
    plD_polyline_gcw(pls,pls->dev_x,pls->dev_y,pls->dev_npts);
 
939
    pls->width = tmp;
 
940
  }
 
941
}
 
942
 
 
943
 
 
944
/*--------------------------------------------------------------------------*\
 
945
 * proc_str()
 
946
 *
 
947
 * Handles call to draw text on the canvas when the HAS_TEXT escape funtion
 
948
 * case is invoked.
 
949
 *
 
950
 * This routine is unicode enabled, and requires freetype.
 
951
\*--------------------------------------------------------------------------*/
 
952
 
 
953
void proc_str(PLStream *pls, EscText *args)
 
954
{
 
955
  PLFLT *t = args->xform; /* Transform matrix for string */
 
956
 
 
957
  GnomeCanvasGroup* group;
 
958
  GcwPLdev* dev = pls->dev;
 
959
  GnomeCanvas* canvas;
 
960
 
 
961
  PLUNICODE fci; /* The unicode font characterization integer */
 
962
  guchar *fontname = NULL;
 
963
  gint font_size;
 
964
  GnomeFont *font;
 
965
  GnomeFontFace *face;
 
966
  GnomeGlyphList *glyphlist;
 
967
  guint Nglyphs;
 
968
 
 
969
  gdouble affine_baseline[6] = {0.,0.,0.,0.,0.,0.}; /* Affine transforms */
 
970
  gdouble affine_translate[6] = {0.,0.,0.,0.,0.,0.};
 
971
  gdouble affine_rotate[6] = {0.,0.,0.,0.,0.,0.};
 
972
  gdouble affine_plplot[6] = {0.,0.,0.,0.,0.,0.};
 
973
 
 
974
  GnomeCanvasItem* item[200]; /* List of string segments */
 
975
  gdouble width[200],height[200]; /* Height and width of string segment */
 
976
  gdouble up_list[200]; /* Indicates sub/sup position of string segment */
 
977
  gdouble up=0,scale=1; /* Used to create superscripts and subscripts */
 
978
 
 
979
  ArtDRect bbox; /* Bounding box for each segment to get width & height */
 
980
 
 
981
  const PLUNICODE *text; /* The text and pointers to it */
 
982
  guint i=0,Ntext; /* The text index and maximum length */
 
983
 
 
984
  char esc; /* The escape character */
 
985
 
 
986
  guint N=0; /* The number of text segments */
 
987
  gdouble total_width=0,sum_width=0;
 
988
 
 
989
  guint symbol;
 
990
 
 
991
 
 
992
#ifdef DEBUG_GCW_2
 
993
  gcw_debug("<proc_str>\n");
 
994
#endif
 
995
 
 
996
  if(!GNOME_IS_CANVAS(dev->canvas))
 
997
    plexit("GCW driver <proc_str>: Canvas not found");
 
998
  canvas = dev->canvas;
 
999
 
 
1000
  if(dev->use_persistence) group = dev->group_persistent;
 
1001
  else group = dev->group_hidden;
 
1002
 
 
1003
  /* Retrieve the escape character */
 
1004
  plgesc(&esc);
 
1005
 
 
1006
  /* Put the transform matrix values in the order expected by libart.
 
1007
   * Note that the plplot transform matrix only has a rotation and shear;
 
1008
   * plplot's rotation direction and shear are opposite from that expected 
 
1009
   * by libart, hence the negative signs below.
 
1010
   */
 
1011
  affine_plplot[0] = t[0];  /* cos(theta) */
 
1012
  affine_plplot[1] = -t[2]; /* sin(theta) */
 
1013
  affine_plplot[2] = -t[1]; /* a cos(theta) - sin(theta) */
 
1014
  affine_plplot[3] = t[3];  /* a sin(theta) + cos(theta) */
 
1015
 
 
1016
  /* Font size: size is in pixels but chrht is in mm.  Why the extra factor? */
 
1017
  font_size = (gint)(pls->chrht*DEVICE_PIXELS_PER_MM*1.5);
 
1018
 
 
1019
  /* Determine the default font */
 
1020
  plgfci(&fci);
 
1021
  fontname = plP_FCI2FontName(fci, FontLookup, N_TrueTypeLookup);
 
1022
  if (fontname == NULL) {
 
1023
    plabort("GCW driver <proc_str>: FCI inconsistent with TrueTypeLookup");
 
1024
  }
 
1025
 
 
1026
  /* Retrieve the font face */
 
1027
  face = gnome_font_face_find_from_filename(fontname,0);
 
1028
 
 
1029
  /* Get the unicode string */
 
1030
  text = args->unicode_array;
 
1031
  Ntext = (guint)(args->unicode_array_len);
 
1032
 
 
1033
  /* Process the string: Break it into segments of constant font and size,
 
1034
   * making sure we process control characters as we come to them.  Save
 
1035
   * the extra information that will allow us to place the text on the
 
1036
   * canvas.
 
1037
   */
 
1038
  while(i<Ntext) {
 
1039
 
 
1040
    /* Process the next character */
 
1041
 
 
1042
    if(text[i] & PL_FCI_MARK) { /* Is it a font characterization index? */
 
1043
 
 
1044
      /* Determine the font name */
 
1045
      fontname = plP_FCI2FontName(text[i], FontLookup, N_TrueTypeLookup);
 
1046
      if (fontname == NULL) {
 
1047
        plabort("GCW driver <proc_str>: FCI inconsistent with "
 
1048
                "TrueTypeLookup");
 
1049
      }
 
1050
 
 
1051
      /* Retrieve the font face */
 
1052
      gnome_font_unref(face); /* We already have a face */
 
1053
      face = gnome_font_face_find_from_filename(fontname,0);
 
1054
 
 
1055
      i++; /* Move ahead to the next character */
 
1056
 
 
1057
    }
 
1058
    else {
 
1059
 
 
1060
      if(text[i] == esc) { /* Check for escape sequences */
 
1061
 
 
1062
        /* Process escape sequence */
 
1063
 
 
1064
        i++; /* Move on to next character */
 
1065
        if(i>=Ntext) {
 
1066
          plwarn("GCW driver <proc_str>: Invalid escape sequence "
 
1067
                 "provided in text.");
 
1068
          return;
 
1069
        }
 
1070
 
 
1071
        switch(text[i]) {
 
1072
 
 
1073
        case '#': /* <esc><esc>; this should translate to a hash */
 
1074
          break;  /* Watch out for it later */
 
1075
 
 
1076
        /* Move to lower sub/sup position */
 
1077
        case 'd':
 
1078
        case 'D':
 
1079
          if(up>0.) scale *= 1.25;  /* Subscript scaling parameter */
 
1080
          else scale *= 0.8;  /* Subscript scaling parameter */
 
1081
          up -= font_size / 2.;
 
1082
          break;
 
1083
 
 
1084
        /* Move to higher sub/sup position */
 
1085
        case 'u':
 
1086
        case 'U':
 
1087
          if(up<0.) scale *= 1.25;  /* Subscript scaling parameter */
 
1088
          else scale *= 0.8;  /* Subscript scaling parameter */
 
1089
          up += font_size / 2.;
 
1090
          break;
 
1091
 
 
1092
        /* Ignore the next sequences */
 
1093
 
 
1094
        /* Overline */
 
1095
        case '+':
 
1096
 
 
1097
        /* Underline */
 
1098
        case '-':
 
1099
 
 
1100
        /* Backspace */
 
1101
        case 'b':
 
1102
        case 'B':
 
1103
          plwarn("GCW driver <proc_str>: '+', '-', and 'b' text "
 
1104
                 "escape sequences not processed.");
 
1105
          break;
 
1106
 
 
1107
        } /* switch(text[i]) */
 
1108
 
 
1109
        if(text[i]!='#') i++; /* Move ahead to the next character */
 
1110
 
 
1111
      } /* if(text[i] == esc) */
 
1112
    } /* if(text[i] & PL_FCI_MARK) */
 
1113
 
 
1114
 
 
1115
    if(i==Ntext) continue; /* End of string */
 
1116
 
 
1117
    /* Save the sub/sup position */
 
1118
    up_list[N] = up;
 
1119
 
 
1120
    /* Get the font */
 
1121
    font = gnome_font_face_get_font_default(face,font_size*scale);
 
1122
    /* printf("\n\nfont name = %s\n\n",gnome_font_get_name(font)); */
 
1123
 
 
1124
    /* Create the glyphlist for this text segment */
 
1125
    glyphlist = gnome_glyphlist_new ();
 
1126
    gnome_glyphlist_font(glyphlist, font);
 
1127
    gnome_glyphlist_color(glyphlist,dev->color);
 
1128
    gnome_glyphlist_advance(glyphlist, TRUE);
 
1129
    gnome_glyphlist_kerning(glyphlist, 0.);
 
1130
    gnome_glyphlist_letterspace(glyphlist, 0.);
 
1131
 
 
1132
    /* Free the font */
 
1133
    gnome_font_unref(font);
 
1134
 
 
1135
    /* Move along to the next escape or FCI character, stuffing 
 
1136
     * everything else into the glyphlist.
 
1137
     */
 
1138
    Nglyphs=0;
 
1139
    while(i<Ntext && !(text[i] & PL_FCI_MARK)) {
 
1140
 
 
1141
      /* Differentiate between ## and escape sequences */
 
1142
      if(text[i]==esc) {
 
1143
        if( !(i>0 && text[i-1]==esc) ) break;
 
1144
      }
 
1145
 
 
1146
      gnome_glyphlist_glyph(glyphlist, 
 
1147
                            gnome_font_lookup_default(font,text[i]));
 
1148
      i++; Nglyphs++;
 
1149
    }
 
1150
 
 
1151
    if(Nglyphs) {
 
1152
 
 
1153
      /* Determine the bounding box of the text */
 
1154
      gnome_glyphlist_bbox(glyphlist,NULL,0,&bbox);
 
1155
      width[N] = bbox.x1-bbox.x0;
 
1156
      height[N] = bbox.y1-bbox.y0;
 
1157
 
 
1158
      /* Keep track of the total string width so that we can justify it */
 
1159
      total_width += width[N];
 
1160
      if(N!=0) total_width += 2; /* Add a little extra space */
 
1161
 
 
1162
      /* Create the canvas text item */
 
1163
      if(!GNOME_IS_CANVAS_ITEM(
 
1164
        item[N] = gnome_canvas_item_new (group,
 
1165
                                       PLPLOT_TYPE_CANVAS_HACKTEXT,
 
1166
                                       "glyphlist",glyphlist,
 
1167
                                       "fill-color-rgba",dev->color,
 
1168
                                       "x",0.,
 
1169
                                       "y",0.,
 
1170
                                       NULL)
 
1171
        )) {
 
1172
        plabort("GCW driver <proc_str>: Canvas item not created");
 
1173
      }
 
1174
 
 
1175
      /* Free the glyphlist */
 
1176
      gnome_glyphlist_unref(glyphlist);
 
1177
      
 
1178
      /* Advance to next string segment */
 
1179
      N++;
 
1180
    } /* if(Nglyphs) */
 
1181
 
 
1182
 
 
1183
    /* Don't overflow buffer */
 
1184
    if(N==200 && i<Ntext)
 
1185
      plabort("GCW driver <proc_str>: too many text segments");
 
1186
 
 
1187
  } /* while(i<Ntext) */
 
1188
 
 
1189
  /* We have all of the string segments.  Place each on the canvas 
 
1190
   * appropriately.
 
1191
   */
 
1192
  for(i=0;i<N;i++) {
 
1193
 
 
1194
    /* Calculate and apply the affine transforms */
 
1195
    art_affine_rotate(affine_rotate,90.*(pls->diorot-pls->portrait));
 
1196
    if(!pls->portrait) {
 
1197
      art_affine_translate(affine_baseline,
 
1198
                           -total_width*args->just + sum_width,
 
1199
                           height[0]/2.5-up_list[i]);
 
1200
      art_affine_translate(affine_translate,
 
1201
                           args->x/VSCALE,-args->y/VSCALE);
 
1202
    }
 
1203
    else { /* Swap x and y for portrait mode */
 
1204
      art_affine_translate(affine_baseline,
 
1205
                           -total_width*args->just + sum_width,
 
1206
                           height[0]/2.5-up_list[i]);
 
1207
      art_affine_translate(affine_translate,
 
1208
                           dev->height-args->y/VSCALE,-args->x/VSCALE);
 
1209
    }
 
1210
    gnome_canvas_item_affine_relative(item[i],affine_translate);
 
1211
    gnome_canvas_item_affine_relative(item[i],affine_rotate);
 
1212
    gnome_canvas_item_affine_relative(item[i],affine_plplot);
 
1213
    gnome_canvas_item_affine_relative(item[i],affine_baseline);
 
1214
 
 
1215
    /* Keep track of the position in the string */
 
1216
    sum_width += width[i];
 
1217
    if(i!=N-1) sum_width += 2; /* Add a little extra space */
 
1218
  }
 
1219
 
 
1220
#ifdef DEBUG_GCW_2
 
1221
  gcw_debug("</proc_str>\n");
 
1222
#endif
 
1223
}
 
1224
 
 
1225
 
 
1226
/*--------------------------------------------------------------------------*\
 
1227
 * plD_esc_gcw()
 
1228
 *
 
1229
 * Escape functions.
 
1230
 *
 
1231
\*--------------------------------------------------------------------------*/
 
1232
 
 
1233
void plD_esc_gcw(PLStream *pls, PLINT op, void *ptr)
 
1234
{
 
1235
  GcwPLdev* dev = pls->dev;
 
1236
 
 
1237
#ifdef DEBUG_GCW_1
 
1238
  char opname[20], msg[100];
 
1239
  if(op==PLESC_DEVINIT) strcpy(opname,"PLESC_DEVINIT");
 
1240
  else if(op==PLESC_CLEAR) strcpy(opname,"PLESC_CLEAR");
 
1241
  else if(op==PLESC_FILL) strcpy(opname,"PLESC_FILL");
 
1242
  else if(op==PLESC_HAS_TEXT) strcpy(opname,"PLESC_HAS_TEXT");
 
1243
  else if(op==PLESC_GRAPH) strcpy(opname,"PLESC_GRAPH");
 
1244
  else strcpy(opname,"unknown");
 
1245
  sprintf(msg,"<plD_esc_gcw />: %s\n",opname);
 
1246
  gcw_debug(msg);
 
1247
#endif
 
1248
 
 
1249
  switch(op) {
 
1250
 
 
1251
  case PLESC_DEVINIT:
 
1252
    gcw_init_canvas(GNOME_CANVAS(ptr));
 
1253
    pls->hack=0;
 
1254
    break;
 
1255
 
 
1256
  case PLESC_CLEAR:
 
1257
    break;
 
1258
 
 
1259
  case PLESC_FILL:
 
1260
    fill_polygon(pls);
 
1261
    break;
 
1262
 
 
1263
  case PLESC_HAS_TEXT:
 
1264
    proc_str(pls, ptr); /* Draw the text */
 
1265
    break;
 
1266
 
 
1267
  case PLESC_GRAPH:
 
1268
    break;
 
1269
 
 
1270
  default:
 
1271
    break;
 
1272
  }
 
1273
}