1 /* gtkplotpc - gtkplot print context - a renderer for printing functions
2 * Copyright 1999-2001 Adrian E. Feiguin <feiguin@ifir.edu.ar>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 /**
21 * SECTION: gtkplotgdk
22 * @short_description: GDK drawing backend (mapped to Cairo)
23 *
24 * This Subclass of #GtkPlotPC has been rewritten to use Cairo
25 * drawing routines.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32 #include <ctype.h>
33 #include <time.h>
34 #include <gtk/gtk.h>
35 #include <gdk/gdk.h>
36
37 #include "gtkplotpc.h"
38 #include "gtkplotgdk.h"
39 #include "gtkplot.h"
40 #include "gtkpsfont.h"
41 #include "gtkplotcanvas.h"
42 #include <pango/pango.h>
43
44 static void gtk_plot_gdk_init (GtkPlotGdk *pc);
45 static void gtk_plot_gdk_class_init (GtkPlotGdkClass *klass);
46 static void gtk_plot_gdk_finalize (GObject *object);
47 static void gtk_plot_gdk_real_set_drawable (GtkPlotGdk *gdk,
48 GdkDrawable *drawable);
49 static gboolean gtk_plot_gdk_real_init (GtkPlotPC *pc);
50 static void gtk_plot_gdk_set_viewport (GtkPlotPC *pc,
51 gdouble w, gdouble h);
52 static void gtk_plot_gdk_leave (GtkPlotPC *pc);
53 static void gtk_plot_gdk_gsave (GtkPlotPC *pc);
54 static void gtk_plot_gdk_grestore (GtkPlotPC *pc);
55 static void gtk_plot_gdk_clip (GtkPlotPC *pc,
56 const GdkRectangle *area);
57 static void gtk_plot_gdk_clip_mask (GtkPlotPC *pc,
58 gdouble x,
59 gdouble y,
60 const GdkBitmap *mask);
61 static void gtk_plot_gdk_set_color (GtkPlotPC *pc,
62 const GdkColor *color);
63 static void gtk_plot_gdk_set_lineattr (GtkPlotPC *pc,
64 gfloat line_width,
65 GdkLineStyle line_style,
66 GdkCapStyle cap_style,
67 GdkJoinStyle join_style);
68 static void gtk_plot_gdk_set_dash (GtkPlotPC *pc,
69 gdouble offset_,
70 gdouble *values,
71 gint num_values);
72 static void gtk_plot_gdk_draw_point (GtkPlotPC *pc,
73 gdouble x, gdouble y);
74 static void gtk_plot_gdk_draw_line (GtkPlotPC *pc,
75 gdouble x1, gdouble y1,
76 gdouble x2, gdouble y2);
77 static void gtk_plot_gdk_draw_lines (GtkPlotPC *pc,
78 GtkPlotPoint *points,
79 gint numpoints);
80 static void gtk_plot_gdk_draw_rectangle (GtkPlotPC *pc,
81 gint filled,
82 gdouble x, gdouble y,
83 gdouble width,
84 gdouble height);
85 static void gtk_plot_gdk_draw_polygon (GtkPlotPC *pc,
86 gint filled,
87 GtkPlotPoint *points,
88 gint numpoints);
89 static void gtk_plot_gdk_draw_circle (GtkPlotPC *pc,
90 gint filled,
91 gdouble x, gdouble y,
92 gdouble size);
93 static void gtk_plot_gdk_draw_ellipse (GtkPlotPC *pc,
94 gint filled,
95 gdouble x, gdouble y,
96 gdouble width,
97 gdouble height);
98 static void gtk_plot_gdk_set_font (GtkPlotPC *pc,
99 GtkPSFont *psfont,
100 gint height);
101 static void gtk_plot_gdk_draw_string (GtkPlotPC *pc,
102 gint x, gint y,
103 gint angle,
104 const GdkColor *fg,
105 const GdkColor *bg,
106 gboolean transparent,
107 gint border,
108 gint border_space,
109 gint border_width,
110 gint shadow_width,
111 const gchar *font,
112 gint height,
113 GtkJustification just,
114 const gchar *text);
115 static void gtk_plot_gdk_draw_pixmap (GtkPlotPC *pc,
116 GdkPixmap *pixmap,
117 GdkBitmap *mask,
118 gint xsrc, gint ysrc,
119 gint xdest, gint ydest,
120 gint width, gint height,
121 gdouble scale_x,
122 gdouble scale_y);
123
124 static GdkPixmap * scale_pixmap (GdkWindow *window,
125 GdkPixmap *pixmap,
126 gdouble scale_x,
127 gdouble scale_y);
128 static GdkBitmap * scale_bitmap (GdkWindow *window,
129 GdkBitmap *bitmap,
130 gdouble scale_x,
131 gdouble scale_y);
132
133 extern gint roundint (gdouble x);
134
135 static GtkPlotPCClass *parent_class = NULL;
136
137 GType
gtk_plot_gdk_get_type(void)138 gtk_plot_gdk_get_type (void)
139 {
140 static GType pc_type = 0;
141
142 if (!pc_type)
143 {
144 pc_type = g_type_register_static_simple (
145 GTK_TYPE_PLOT_PC,
146 "GtkPlotGdk",
147 sizeof (GtkPlotGdkClass),
148 (GClassInitFunc) gtk_plot_gdk_class_init,
149 sizeof (GtkPlotGdk),
150 (GInstanceInitFunc) gtk_plot_gdk_init,
151 0);
152 }
153 return pc_type;
154 }
155
156 static void
gtk_plot_gdk_init(GtkPlotGdk * pc)157 gtk_plot_gdk_init (GtkPlotGdk *pc)
158 {
159 /*
160 GdkWindowAttr attributes;
161 gint attributes_mask;
162 GdkScreen *screen;
163
164 attributes.window_type = GDK_WINDOW_CHILD;
165 attributes.title = NULL;
166 attributes.wclass = GDK_INPUT_OUTPUT;
167 attributes.visual = gdk_visual_get_system ();
168 attributes.colormap = gdk_colormap_get_system ();
169 attributes.event_mask = 0;
170 attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
171 */
172 pc->gc = NULL;
173 pc->drawable = NULL;
174 pc->ref_count = 0;
175 pc->text_direction = GTK_TEXT_DIR_LTR;
176
177 /*
178 pc->window = gdk_window_new (NULL, &attributes, attributes_mask);
179
180 screen = gdk_screen_get_default ();
181 pc->context = gdk_pango_context_get ();
182 */
183 /*
184 pango_context_set_base_dir (pc->context,
185 pc->text_direction == GTK_TEXT_DIR_LTR ?
186 PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL);
187 */
188 /*
189 pango_context_set_language (pc->context, gtk_get_default_language ());
190
191 pc->layout = pango_layout_new(pc->context);
192 */
193 }
194
195
196 static void
gtk_plot_gdk_class_init(GtkPlotGdkClass * klass)197 gtk_plot_gdk_class_init (GtkPlotGdkClass *klass)
198 {
199 GtkObjectClass *object_class;
200 GObjectClass *gobject_class;
201 GtkPlotPCClass *pc_class;
202 GtkPlotGdkClass *gdk_class;
203
204 parent_class = g_type_class_ref (gtk_plot_pc_get_type ());
205
206 object_class = (GtkObjectClass *) klass;
207 gobject_class = (GObjectClass *) klass;
208
209 pc_class = (GtkPlotPCClass *) klass;
210 gdk_class = (GtkPlotGdkClass *) klass;
211
212 gobject_class->finalize = gtk_plot_gdk_finalize;
213
214 gdk_class->set_drawable = gtk_plot_gdk_real_set_drawable;
215
216 pc_class->init = gtk_plot_gdk_real_init;
217 pc_class->leave = gtk_plot_gdk_leave;
218 pc_class->set_viewport = gtk_plot_gdk_set_viewport;
219 pc_class->gsave = gtk_plot_gdk_gsave;
220 pc_class->grestore = gtk_plot_gdk_grestore;
221 pc_class->clip = gtk_plot_gdk_clip;
222 pc_class->clip_mask = gtk_plot_gdk_clip_mask;
223 pc_class->set_color = gtk_plot_gdk_set_color;
224 pc_class->set_dash = gtk_plot_gdk_set_dash;
225 pc_class->set_lineattr = gtk_plot_gdk_set_lineattr;
226 pc_class->draw_point = gtk_plot_gdk_draw_point;
227 pc_class->draw_line = gtk_plot_gdk_draw_line;
228 pc_class->draw_lines = gtk_plot_gdk_draw_lines;
229 pc_class->draw_rectangle = gtk_plot_gdk_draw_rectangle;
230 pc_class->draw_polygon = gtk_plot_gdk_draw_polygon;
231 pc_class->draw_circle = gtk_plot_gdk_draw_circle;
232 pc_class->draw_ellipse = gtk_plot_gdk_draw_ellipse;
233 pc_class->set_font = gtk_plot_gdk_set_font;
234 pc_class->draw_string = gtk_plot_gdk_draw_string;
235 pc_class->draw_pixmap = gtk_plot_gdk_draw_pixmap;
236 }
237
238
239 /**
240 * gtk_plot_gdk_new:
241 * @widget:
242 *
243 *
244 *
245 * Return value:
246 */
247 GtkObject *
gtk_plot_gdk_new(GtkWidget * widget)248 gtk_plot_gdk_new (GtkWidget *widget)
249 {
250 GtkObject *object;
251
252 object = g_object_new(gtk_plot_gdk_get_type(), NULL);
253
254 gtk_plot_gdk_construct(GTK_PLOT_GDK(object), widget);
255
256 return (object);
257 }
258
259 /**
260 * gtk_plot_gdk_construct:
261 * @pc:
262 * @widget:
263 *
264 *
265 */
266 void
gtk_plot_gdk_construct(GtkPlotGdk * pc,GtkWidget * widget)267 gtk_plot_gdk_construct(GtkPlotGdk *pc, GtkWidget *widget)
268 {
269 pc->window = gtk_widget_get_window(widget);
270 pc->context = gtk_widget_get_pango_context (widget);
271 g_object_ref(G_OBJECT(pc->context));
272 pc->layout = pango_layout_new(pc->context);
273 }
274
275
276 static void
gtk_plot_gdk_finalize(GObject * object)277 gtk_plot_gdk_finalize (GObject *object)
278 {
279 GtkPlotGdk *pc = GTK_PLOT_GDK(object);
280
281 GTK_PLOT_GDK(object)->window = NULL;
282
283 if(GTK_PLOT_GDK(object)->ref_count > 0 && GTK_PLOT_GDK(object)->gc){
284 gdk_gc_destroy(GTK_PLOT_GDK(object)->gc);
285 GTK_PLOT_GDK(object)->gc = NULL;
286 }
287
288 if(pc->layout)
289 g_object_unref(G_OBJECT(pc->layout));
290 pc->layout = NULL;
291
292 if(pc->context)
293 g_object_unref(G_OBJECT(pc->context));
294 pc->context = NULL;
295 }
296
297 static void
gtk_plot_gdk_real_set_drawable(GtkPlotGdk * pc,GdkDrawable * drawable)298 gtk_plot_gdk_real_set_drawable(GtkPlotGdk *pc, GdkDrawable *drawable)
299 {
300 pc->drawable = drawable;
301 }
302
303 static gboolean
gtk_plot_gdk_real_init(GtkPlotPC * pc)304 gtk_plot_gdk_real_init (GtkPlotPC *pc)
305 {
306 return TRUE;
307 }
308
309 static void
gtk_plot_gdk_leave(GtkPlotPC * pc)310 gtk_plot_gdk_leave (GtkPlotPC *pc)
311 {
312 }
313
314 /**
315 * gtk_plot_gdk_set_drawable:
316 * @gdk:
317 * @drawable:
318 *
319 *
320 */
321 void
gtk_plot_gdk_set_drawable(GtkPlotGdk * gdk,GdkDrawable * drawable)322 gtk_plot_gdk_set_drawable (GtkPlotGdk *gdk, GdkDrawable *drawable)
323 {
324 GTK_PLOT_GDK_CLASS(GTK_OBJECT_GET_CLASS(GTK_OBJECT(gdk)))->set_drawable(gdk, drawable);
325 }
326
327 static void
gtk_plot_gdk_set_viewport(GtkPlotPC * pc,gdouble w,gdouble h)328 gtk_plot_gdk_set_viewport (GtkPlotPC *pc, gdouble w, gdouble h)
329 {
330 }
331
332 static void
gtk_plot_gdk_gsave(GtkPlotPC * pc)333 gtk_plot_gdk_gsave (GtkPlotPC *pc)
334 {
335 if(GTK_PLOT_GDK(pc)->gc)
336 gdk_gc_ref(GTK_PLOT_GDK(pc)->gc);
337 else{
338 if(GTK_PLOT_GDK(pc)->drawable) GTK_PLOT_GDK(pc)->gc = gdk_gc_new(GTK_PLOT_GDK(pc)->drawable);
339 }
340
341 GTK_PLOT_GDK(pc)->ref_count++;
342 }
343
344 static void
gtk_plot_gdk_grestore(GtkPlotPC * pc)345 gtk_plot_gdk_grestore (GtkPlotPC *pc)
346 {
347 if(GTK_PLOT_GDK(pc)->gc) gdk_gc_unref(GTK_PLOT_GDK(pc)->gc);
348
349 GTK_PLOT_GDK(pc)->ref_count--;
350 if(GTK_PLOT_GDK(pc)->ref_count == 0) GTK_PLOT_GDK(pc)->gc = NULL;
351 }
352
353 static void
gtk_plot_gdk_clip(GtkPlotPC * pc,const GdkRectangle * area)354 gtk_plot_gdk_clip (GtkPlotPC *pc,
355 const GdkRectangle *area)
356 {
357 if(!GTK_PLOT_GDK(pc)->gc) return;
358
359 /* discard GdkRectangle* const:
360 * gdk_gc_set_clip_rectangle should have a const arg.
361 * I've checked the code and it doesn't change it or keep it. murrayc.
362 */
363
364 gdk_gc_set_clip_rectangle(GTK_PLOT_GDK(pc)->gc, (GdkRectangle*)area);
365 }
366
367 static void
gtk_plot_gdk_clip_mask(GtkPlotPC * pc,gdouble x,gdouble y,const GdkBitmap * mask)368 gtk_plot_gdk_clip_mask (GtkPlotPC *pc,
369 gdouble x,
370 gdouble y,
371 const GdkBitmap *mask)
372 {
373 if(!GTK_PLOT_GDK(pc)->gc) return;
374
375 if(x >= 0 && y >= 0)
376 gdk_gc_set_clip_origin(GTK_PLOT_GDK(pc)->gc, x, y);
377
378 gdk_gc_set_clip_mask(GTK_PLOT_GDK(pc)->gc, (GdkBitmap*)mask);
379 }
380
381 static void
gtk_plot_gdk_set_color(GtkPlotPC * pc,const GdkColor * color)382 gtk_plot_gdk_set_color (GtkPlotPC *pc,
383 const GdkColor *color)
384 {
385 GdkColor new_color;
386
387 if(!GTK_PLOT_GDK(pc)->gc) return;
388
389 new_color = *color;
390 gdk_color_alloc(gdk_colormap_get_system(), &new_color);
391 gdk_gc_set_foreground(GTK_PLOT_GDK(pc)->gc, &new_color);
392 }
393
394 static void
gtk_plot_gdk_set_dash(GtkPlotPC * pc,gdouble offset,gdouble * values,gint num_values)395 gtk_plot_gdk_set_dash (GtkPlotPC *pc,
396 gdouble offset,
397 gdouble *values,
398 gint num_values)
399 {
400 gint list[] = {0, 1, 2, 3, 4, 5, 6, 7};
401 gint8 dash[1000];
402 gint i;
403
404 if(!GTK_PLOT_GDK(pc)->gc) return;
405
406 if(num_values == 0){
407 return;
408 }
409
410 for(i = 0; i < num_values; i++){
411 gint value;
412 value = values[i];
413 dash[i] = list[value];
414 }
415
416 gdk_gc_set_dashes(GTK_PLOT_GDK(pc)->gc, 0, dash, num_values);
417 }
418
gtk_plot_gdk_set_lineattr(GtkPlotPC * pc,gfloat line_width,GdkLineStyle line_style,GdkCapStyle cap_style,GdkJoinStyle join_style)419 static void gtk_plot_gdk_set_lineattr (GtkPlotPC *pc,
420 gfloat line_width,
421 GdkLineStyle line_style,
422 GdkCapStyle cap_style,
423 GdkJoinStyle join_style)
424 {
425 if(!GTK_PLOT_GDK(pc)->gc) return;
426
427 gdk_gc_set_line_attributes(GTK_PLOT_GDK(pc)->gc,
428 roundint(line_width),
429 line_style,
430 cap_style,
431 join_style);
432 }
433
434 static void
gtk_plot_gdk_draw_point(GtkPlotPC * pc,gdouble x,gdouble y)435 gtk_plot_gdk_draw_point (GtkPlotPC *pc,
436 gdouble x, gdouble y)
437 {
438 if(!GTK_PLOT_GDK(pc)->gc) return;
439 if(!GTK_PLOT_GDK(pc)->drawable) return;
440
441 gdk_draw_point(GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
442 roundint(x), roundint(y));
443 }
444
445 static void
gtk_plot_gdk_draw_line(GtkPlotPC * pc,gdouble x1,gdouble y1,gdouble x2,gdouble y2)446 gtk_plot_gdk_draw_line (GtkPlotPC *pc,
447 gdouble x1, gdouble y1,
448 gdouble x2, gdouble y2)
449 {
450 if(!GTK_PLOT_GDK(pc)->gc) return;
451 if(!GTK_PLOT_GDK(pc)->drawable) return;
452
453 gdk_draw_line(GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
454 roundint(x1), roundint(y1), roundint(x2), roundint(y2));
455 }
456
457 static void
gtk_plot_gdk_draw_lines(GtkPlotPC * pc,GtkPlotPoint * points,gint numpoints)458 gtk_plot_gdk_draw_lines (GtkPlotPC *pc,
459 GtkPlotPoint *points,
460 gint numpoints)
461 {
462 GdkPoint *p = NULL;
463 gint i;
464
465 if(!GTK_PLOT_GDK(pc)->gc) return;
466 if(!GTK_PLOT_GDK(pc)->drawable) return;
467
468 p = (GdkPoint *)g_malloc(numpoints * sizeof(GdkPoint));
469 for(i = 0; i < numpoints; i++){
470 p[i].x = roundint(points[i].x);
471 p[i].y = roundint(points[i].y);
472 }
473
474 gdk_draw_lines(GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc, p, numpoints);
475
476 g_free(p);
477 }
478
479 static void
gtk_plot_gdk_draw_rectangle(GtkPlotPC * pc,gint filled,gdouble x,gdouble y,gdouble width,gdouble height)480 gtk_plot_gdk_draw_rectangle (GtkPlotPC *pc,
481 gint filled,
482 gdouble x, gdouble y,
483 gdouble width, gdouble height)
484 {
485 if(!GTK_PLOT_GDK(pc)->gc) return;
486 if(!GTK_PLOT_GDK(pc)->drawable) return;
487
488 gdk_draw_rectangle (GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
489 filled,
490 roundint(x), roundint(y),
491 roundint(width), roundint(height));
492
493 }
494
495 static void
gtk_plot_gdk_draw_polygon(GtkPlotPC * pc,gint filled,GtkPlotPoint * points,gint numpoints)496 gtk_plot_gdk_draw_polygon (GtkPlotPC *pc,
497 gint filled,
498 GtkPlotPoint *points,
499 gint numpoints)
500 {
501 GdkPoint *p = NULL;
502 gint i;
503
504 if(!GTK_PLOT_GDK(pc)->gc) return;
505 if(!GTK_PLOT_GDK(pc)->drawable) return;
506
507 p = (GdkPoint *)g_malloc(numpoints * sizeof(GdkPoint));
508 for(i = 0; i < numpoints; i++){
509 p[i].x = roundint(points[i].x);
510 p[i].y = roundint(points[i].y);
511 }
512
513 gdk_draw_polygon(GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
514 filled, p, numpoints);
515
516 g_free(p);
517 }
518
519 static void
gtk_plot_gdk_draw_circle(GtkPlotPC * pc,gint filled,gdouble x,gdouble y,gdouble size)520 gtk_plot_gdk_draw_circle (GtkPlotPC *pc,
521 gint filled,
522 gdouble x, gdouble y,
523 gdouble size)
524 {
525 if(!GTK_PLOT_GDK(pc)->gc) return;
526 if(!GTK_PLOT_GDK(pc)->drawable) return;
527
528 gdk_draw_arc (GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
529 filled,
530 roundint(x-size/2.0), roundint(y-size/2.0),
531 roundint(size), roundint(size), 0, 25000);
532
533 }
534
535 static void
gtk_plot_gdk_draw_ellipse(GtkPlotPC * pc,gint filled,gdouble x,gdouble y,gdouble width,gdouble height)536 gtk_plot_gdk_draw_ellipse (GtkPlotPC *pc,
537 gint filled,
538 gdouble x, gdouble y,
539 gdouble width, gdouble height)
540 {
541 if(!GTK_PLOT_GDK(pc)->gc) return;
542 if(!GTK_PLOT_GDK(pc)->drawable) return;
543
544 gdk_draw_arc (GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
545 filled,
546 roundint(x), roundint(y),
547 roundint(width), roundint(height), 0, 25000);
548 }
549
550 static void
gtk_plot_gdk_set_font(GtkPlotPC * pc,GtkPSFont * psfont,gint height)551 gtk_plot_gdk_set_font (GtkPlotPC *pc,
552 GtkPSFont *psfont,
553 gint height)
554 {
555
556 }
557
558 /* subfunction of gtk_plot_gdk_draw_string(). */
559 static gint
drawstring(GtkPlotPC * pc,GdkDrawable * drawable,GdkGC * gc,gint angle,gint dx,gint dy,GtkPSFont * psfont,gint height,const gchar * text)560 drawstring(GtkPlotPC *pc,
561 GdkDrawable *drawable,
562 GdkGC *gc,
563 gint angle,
564 gint dx, gint dy,
565 GtkPSFont *psfont, gint height,
566 const gchar *text)
567 {
568 PangoFontDescription *font;
569 PangoRectangle rect;
570 gint ret_value;
571
572 if(!text || strlen(text) == 0) return 0;
573 font = gtk_psfont_get_font_description(psfont, height);
574 pango_layout_set_font_description(GTK_PLOT_GDK(pc)->layout, font);
575
576 pango_layout_set_text(GTK_PLOT_GDK(pc)->layout, text, strlen(text));
577 pango_layout_get_extents(GTK_PLOT_GDK(pc)->layout, NULL, &rect);
578
579 if (psfont->i18n_latinfamily && psfont->vertical) {
580 /* vertical-writing CJK postscript fonts. */
581 return rect.height;
582 }
583 else
584 {
585 /* horizontal writing */
586 if(angle == 90)
587 gdk_draw_layout (drawable, gc, dx, dy-PANGO_PIXELS(rect.width), GTK_PLOT_GDK(pc)->layout);
588 else if(angle == 180)
589 gdk_draw_layout (drawable, gc, dx-PANGO_PIXELS(rect.width), dy, GTK_PLOT_GDK(pc)->layout);
590 else
591 gdk_draw_layout (drawable, gc, dx, dy, GTK_PLOT_GDK(pc)->layout);
592
593 /*
594 gdk_draw_layout (GTK_PLOT_GDK(pc)->drawable, gc, dx, dy, GTK_PLOT_GDK(pc)->layout);
595 */
596
597 }
598 if (font) pango_font_description_free(font);
599 ret_value = (angle == 0 || angle == 180) ? rect.width : rect.height;
600 return PANGO_PIXELS(rect.width);
601 }
602
603 static void
gtk_plot_gdk_draw_string(GtkPlotPC * pc,gint tx,gint ty,gint angle,const GdkColor * fg,const GdkColor * bg,gboolean transparent,gint border,gint border_space,gint border_width,gint shadow_width,const gchar * font_name,gint font_height,GtkJustification just,const gchar * text)604 gtk_plot_gdk_draw_string (GtkPlotPC *pc,
605 gint tx, gint ty,
606 gint angle,
607 const GdkColor *fg,
608 const GdkColor *bg,
609 gboolean transparent,
610 gint border,
611 gint border_space,
612 gint border_width,
613 gint shadow_width,
614 const gchar *font_name,
615 gint font_height,
616 GtkJustification just,
617 const gchar *text)
618 {
619 GdkGC *gc;
620 GList *family = NULL;
621 gint x0, y0;
622 gint old_width, old_height;
623 gboolean bold, italic;
624 gint fontsize;
625 gint ascent, descent;
626 gint numf;
627 gint width, height;
628 gint x, y;
629 gint i;
630 PangoFontDescription *font = NULL, *latin_font = NULL;
631 GtkPSFont *psfont, *base_psfont, *latin_psfont;
632 gchar subs[2], insert_char;
633 const gchar *aux = text;
634 const gchar *lastchar = text;
635 const gchar *wtext = text;
636 const gchar *xaux = text;
637 gchar *new_text; /* Support Tiny C compiler : Original : gchar new_text[strlen(text)+1];*/
638 gchar num[4];
639 PangoRectangle rect;
640 PangoFontMetrics *metrics = NULL;
641 PangoLayout *layout = NULL;
642 gint real_x, real_y, real_width, real_height;
643 GdkColor real_fg = *fg;
644 GdkColor real_bg = *bg;
645 PangoMatrix matrix = PANGO_MATRIX_INIT;
646 PangoContext *context = GTK_PLOT_GDK(pc)->context;
647 GdkDrawable *drawable = GTK_PLOT_GDK(pc)->drawable;
648 gint sign_x = 1, sign_y = 0;
649 gint old_tx = tx, old_ty = ty;
650
651 if(!GTK_PLOT_GDK(pc)->drawable) return;
652 if(!GTK_PLOT_GDK(pc)->gc) return;
653 if(!text || strlen(text) == 0) return;
654
655 gc = GTK_PLOT_GDK(pc)->gc;
656 layout = GTK_PLOT_GDK(pc)->layout;
657
658 if(!gc) return;
659
660 gtk_plot_text_get_size(text, angle, font_name, font_height, &width, &height, &ascent, &descent);
661
662 if(height == 0 || width == 0) return;
663
664 old_width = width;
665 old_height = height;
666 if(angle == 90 || angle == 270)
667 {
668 old_width = height;
669 old_height = width;
670 }
671 switch(angle){
672 case 90:
673 sign_x = 0;
674 sign_y = -1;
675 break;
676 case 180:
677 sign_x = -1;
678 sign_y = 0;
679 break;
680 case 270:
681 sign_x = 0;
682 sign_y = 1;
683 break;
684 case 0:
685 default:
686 sign_x = 1;
687 sign_y = 0;
688 break;
689 }
690
691 switch(just){
692 case GTK_JUSTIFY_LEFT:
693 switch(angle){
694 case 0:
695 ty -= ascent;
696 break;
697 case 90:
698 ty -= height;
699 tx -= ascent;
700 break;
701 case 180:
702 tx -= width;
703 ty -= descent;
704 break;
705 case 270:
706 tx -= descent;
707 break;
708 }
709 old_tx = tx;
710 old_ty = ty;
711 break;
712 case GTK_JUSTIFY_RIGHT:
713 switch(angle){
714 case 0:
715 tx -= width;
716 ty -= ascent;
717 old_tx -= width;
718 old_ty -= ascent;
719 break;
720 case 90:
721 tx -= ascent;
722 ty += height;
723 old_tx -= ascent;
724 break;
725 case 180:
726 tx += width;
727 ty -= descent;
728 old_ty -= descent;
729 break;
730 case 270:
731 tx -= descent;
732 old_tx -= descent;
733 old_ty -= height;
734 break;
735 }
736 break;
737 case GTK_JUSTIFY_CENTER:
738 default:
739 switch(angle){
740 case 0:
741 tx -= width / 2.;
742 ty -= ascent;
743 old_tx -= width / 2.;
744 old_ty -= ascent;
745 break;
746 case 90:
747 tx -= ascent;
748 ty += height / 2.;
749 old_tx -= ascent;
750 old_ty -= height / 2.;
751 break;
752 case 180:
753 tx += width / 2.;
754 ty -= descent;
755 old_tx -= width / 2.;
756 old_ty -= descent;
757 break;
758 case 270:
759 tx -= descent;
760 ty -= height / 2.;
761 old_tx -= descent;
762 old_ty -= height / 2.;
763 break;
764 }
765 }
766
767 real_x = tx;
768 real_y = ty;
769 real_width = width;
770 real_height = height;
771
772 pango_matrix_rotate (&matrix, angle);
773 pango_context_set_matrix (context, &matrix);
774 pango_layout_context_changed (layout);
775
776 if(!transparent){
777 gdk_gc_set_foreground(gc, &real_bg);
778 gdk_draw_rectangle(drawable, gc, TRUE, old_tx, old_ty, old_width, old_height);
779 }
780
781 /* TEST */
782 /*
783 gdk_draw_rectangle(text_pixmap, gc, FALSE, 0, 0, old_width-1, old_height-1);
784 */
785
786 gtk_psfont_get_families(&family, &numf);
787 base_psfont = psfont = gtk_psfont_get_by_name(font_name);
788 font = gtk_psfont_get_font_description(psfont, font_height);
789 italic = psfont->italic;
790 bold = psfont->bold;
791 fontsize = font_height;
792 x0 = x = 0;
793 y0 = y = 0;
794
795 if (psfont->i18n_latinfamily) {
796 latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily, italic,
797 bold);
798 if(latin_font) pango_font_description_free(latin_font);
799 latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
800 } else {
801 latin_psfont = NULL;
802 latin_font = NULL;
803 }
804
805 gdk_gc_set_foreground(gc, &real_fg);
806 aux = text;
807 while(aux && *aux != '\0' && *aux != '\n'){
808 if(*aux == '\\'){
809 aux = g_utf8_next_char(aux);
810 switch(*aux){
811 case '0': case '1': case '2': case '3':
812 case '4': case '5': case '6': case '7': case '9':
813 psfont = gtk_psfont_get_by_family((gchar *)g_list_nth_data(family, *aux-'0'), italic, bold);
814 pango_font_description_free(font);
815 font = gtk_psfont_get_font_description(psfont, fontsize);
816 aux = g_utf8_next_char(aux);
817 break;
818 case '8': case 'g':
819 psfont = gtk_psfont_get_by_family("Symbol", italic, bold);
820 pango_font_description_free(font);
821 font = gtk_psfont_get_font_description(psfont, fontsize);
822 aux = g_utf8_next_char(aux);
823 break;
824 case 'B':
825 bold = TRUE;
826 psfont = gtk_psfont_get_by_family(psfont->family, italic, bold);
827 pango_font_description_free(font);
828 font = gtk_psfont_get_font_description(psfont, fontsize);
829 if(latin_font){
830 latin_font = NULL;
831 }
832 if (psfont->i18n_latinfamily) {
833 latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily,
834 italic, bold);
835 if(latin_font) pango_font_description_free(latin_font);
836 latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
837 }
838 aux = g_utf8_next_char(aux);
839 break;
840 case 'x':
841 xaux = aux + 1;
842 for (i=0; i<3; i++){
843 if (xaux[i] >= '0' && xaux[i] <= '9')
844 num[i] = xaux[i];
845 else
846 break;
847 }
848 if (i < 3){
849 aux = g_utf8_next_char(aux);
850 break;
851 }
852 num[3] = '\0';
853 insert_char = (gchar)atoi(num);
854 subs[0] = insert_char;
855 subs[1] = '\0';
856 pango_layout_set_font_description(layout, font);
857 pango_layout_set_text(layout, subs, 1);
858 pango_layout_get_extents(layout, NULL, &rect);
859 x += sign_x*PANGO_PIXELS(rect.width);
860 y += sign_y*PANGO_PIXELS(rect.width);
861 aux += 4;
862 lastchar = aux - 1;
863 break;
864 case 'i':
865 italic = TRUE;
866 psfont = gtk_psfont_get_by_family(psfont->family, italic, bold);
867 pango_font_description_free(font);
868 font = gtk_psfont_get_font_description(psfont, fontsize);
869 if (psfont->i18n_latinfamily) {
870 latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily,
871 italic, bold);
872 if(latin_font) pango_font_description_free(latin_font);
873 latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
874 }
875 aux = g_utf8_next_char(aux);
876 break;
877 case 'S': case '^':
878 fontsize = (int)((gdouble)fontsize * 0.6 + 0.5);
879 pango_font_description_free(font);
880 font = gtk_psfont_get_font_description(psfont, fontsize);
881 if(metrics) pango_font_metrics_unref(metrics);
882 metrics = pango_context_get_metrics(pango_layout_get_context(layout), font, pango_context_get_language(pango_layout_get_context(layout)));
883 if (psfont->i18n_latinfamily) {
884 latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
885 }
886 if(angle == 180)
887 y = y0 + fontsize;
888 else if(angle == 270)
889 x = x0 + sign_y*fontsize;
890 aux = g_utf8_next_char(aux);
891 break;
892 case 's': case '_':
893 fontsize = (int)((gdouble)fontsize * 0.6 + 0.5);
894 pango_font_description_free(font);
895 font = gtk_psfont_get_font_description(psfont, fontsize);
896 if(metrics) pango_font_metrics_unref(metrics);
897 metrics = pango_context_get_metrics(pango_layout_get_context(layout), font, pango_context_get_language(pango_layout_get_context(layout)));
898 if(angle == 0)
899 y = y0 + fontsize;
900 else if(angle == 90)
901 x = x0 - sign_y*fontsize;
902 if (psfont->i18n_latinfamily) {
903 latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
904 }
905 aux = g_utf8_next_char(aux);
906 break;
907 case '+':
908 fontsize += 3;
909 y -= sign_x*3;
910 x += sign_y*3;
911 pango_font_description_free(font);
912 font = gtk_psfont_get_font_description(psfont, fontsize);
913 if (psfont->i18n_latinfamily) {
914 latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
915 }
916 aux = g_utf8_next_char(aux);
917 break;
918 case '-':
919 fontsize -= 3;
920 y += sign_x*3;
921 x -= sign_y*3;
922 pango_font_description_free(font);
923 font = gtk_psfont_get_font_description(psfont, fontsize);
924 if (psfont->i18n_latinfamily) {
925 latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
926 }
927 aux = g_utf8_next_char(aux);
928 break;
929 case 'N':
930 psfont = base_psfont;
931 fontsize = font_height;
932 pango_font_description_free(font);
933 font = gtk_psfont_get_font_description(psfont, fontsize);
934 if(angle == 0 || angle == 180)
935 y = y0;
936 else
937 x = x0;
938 italic = psfont->italic;
939 bold = psfont->bold;
940 aux = g_utf8_next_char(aux);
941 break;
942 case 'b':
943 if (lastchar) {
944 const gchar *aux2 = lastchar;
945 gint i = g_utf8_prev_char(lastchar) != --aux2 ? 2 : 1;
946 pango_layout_set_text(layout, lastchar, i);
947 pango_layout_get_extents(layout, NULL, &rect);
948 x -= sign_x*PANGO_PIXELS(rect.width);
949 y -= sign_y*PANGO_PIXELS(rect.width);
950
951 if (lastchar == wtext)
952 lastchar = NULL;
953 else
954 lastchar = g_utf8_prev_char(lastchar);
955 } else {
956 pango_layout_set_text(layout, "X", 1);
957 pango_layout_get_extents(layout, NULL, &rect);
958 x -= sign_x*PANGO_PIXELS(rect.width);
959 y -= sign_y*PANGO_PIXELS(rect.width);
960 }
961 aux = g_utf8_next_char(aux);
962 break;
963 default:
964 if(aux && *aux != '\0' && *aux !='\n'){
965 gint new_width = 0;
966 new_width = drawstring(pc, drawable, gc, angle, tx+x, ty+y,
967 psfont, fontsize, aux);
968 x += sign_x * new_width;
969 y += sign_y * new_width;
970 lastchar = aux;
971 aux = g_utf8_next_char(aux);
972 }
973 break;
974 }
975 } else {
976 gint new_len = 0;
977 gint new_width = 0;
978 lastchar = aux;
979 while(aux && *aux != '\0' && *aux !='\n' && *aux != '\\'){
980 xaux = aux;
981 new_len += g_utf8_next_char(aux) != ++xaux ? 2 : 1;
982 aux = g_utf8_next_char(aux);
983 }
984 xaux = lastchar;
985
986 new_text = (gchar *) g_new0(gchar , strlen(text)+1); /* Tiny C Compiler support */
987 for(i = 0; i < new_len; i++) new_text[i] = *xaux++;
988 new_text[new_len] = '\0';
989 new_width = drawstring(pc, drawable, gc, angle, tx+x, ty+y,
990 psfont, fontsize, new_text);
991 x += sign_x * new_width;
992 y += sign_y * new_width;
993 lastchar = aux;
994
995 g_free (new_text);
996 }
997 }
998
999 pango_matrix_rotate (&matrix, 0);
1000 pango_context_set_matrix (context, &matrix);
1001 pango_font_description_free(font);
1002 if(latin_font) pango_font_description_free(latin_font);
1003 if(metrics) pango_font_metrics_unref(metrics);
1004
1005 /* border */
1006
1007 gdk_gc_set_foreground(gc, &real_fg);
1008 gtk_plot_pc_set_dash(pc, 0, NULL, 0);
1009 gtk_plot_pc_set_lineattr(pc, border_width, 0, 0, 0);
1010 switch(border){
1011 case GTK_PLOT_BORDER_SHADOW:
1012 gtk_plot_pc_draw_rectangle(pc,
1013 TRUE,
1014 old_tx - border_space + shadow_width,
1015 old_ty + height + border_space,
1016 width + 2 * border_space, shadow_width);
1017 gtk_plot_pc_draw_rectangle(pc,
1018 TRUE,
1019 old_tx + width + border_space,
1020 old_ty - border_space + shadow_width,
1021 shadow_width, height + 2 * border_space);
1022 case GTK_PLOT_BORDER_LINE:
1023 gtk_plot_pc_draw_rectangle(pc,
1024 FALSE,
1025 old_tx - border_space, old_ty - border_space,
1026 width + 2*border_space, height + 2*border_space);
1027 case GTK_PLOT_BORDER_NONE:
1028 default:
1029 break;
1030 }
1031
1032 return;
1033 }
1034
gtk_plot_gdk_draw_pixmap(GtkPlotPC * pc,GdkPixmap * pixmap,GdkBitmap * mask,gint xsrc,gint ysrc,gint xdest,gint ydest,gint width,gint height,gdouble scale_x,gdouble scale_y)1035 static void gtk_plot_gdk_draw_pixmap (GtkPlotPC *pc,
1036 GdkPixmap *pixmap,
1037 GdkBitmap *mask,
1038 gint xsrc, gint ysrc,
1039 gint xdest, gint ydest,
1040 gint width,
1041 gint height,
1042 gdouble scale_x,
1043 gdouble scale_y)
1044 {
1045 GdkGC *gc;
1046 GdkPixmap *new_pixmap;
1047 GdkBitmap *new_mask = NULL;
1048
1049 if(!GTK_PLOT_GDK(pc)->drawable) return;
1050 if(!GTK_PLOT_GDK(pc)->gc) return;
1051
1052 gc = GTK_PLOT_GDK(pc)->gc;
1053
1054 if(!gc) return;
1055
1056 new_pixmap = scale_pixmap(GTK_PLOT_GDK(pc)->drawable, pixmap, scale_x, scale_y);
1057
1058 if(mask)
1059 new_mask = scale_bitmap(GTK_PLOT_GDK(pc)->drawable, mask, scale_x, scale_y);
1060
1061 /* TEST
1062 new_pixmap = pixmap; gdk_pixmap_ref(pixmap);
1063 if(mask) new_mask = mask; gdk_bitmap_ref(mask);
1064 */
1065
1066 gtk_plot_pc_clip_mask(pc, xdest, ydest, new_mask);
1067 gdk_draw_pixmap(GTK_PLOT_GDK(pc)->drawable, gc, new_pixmap,
1068 xsrc, ysrc, xdest, ydest, width*scale_x, height*scale_y);
1069 gtk_plot_pc_clip_mask(pc, xdest, ydest, NULL);
1070
1071 if(new_mask) gdk_bitmap_unref(new_mask);
1072 gdk_pixmap_unref(new_pixmap);
1073 }
1074
1075 static GdkPixmap *
scale_pixmap(GdkWindow * window,GdkPixmap * pixmap,gdouble scale_x,gdouble scale_y)1076 scale_pixmap (GdkWindow *window, GdkPixmap *pixmap, gdouble scale_x, gdouble scale_y)
1077 {
1078 GdkGC *gc = NULL;
1079 GdkPixmap *new_pixmap;
1080 gint width, height, new_width, new_height;
1081 GdkPixbuf *pixbuf = NULL;
1082 GdkPixbuf *aux_pixbuf = NULL;
1083
1084 if(!pixmap) return NULL;
1085 if(!window) return NULL;
1086
1087 gdk_window_get_size(pixmap, &width, &height);
1088
1089 gc = gdk_gc_new(window);
1090
1091 if(scale_x == 1.0 && scale_y == 1.0){
1092 new_pixmap = gdk_pixmap_new(window, width, height, -1);
1093 gdk_draw_pixmap(new_pixmap,
1094 gc,
1095 pixmap,
1096 0, 0,
1097 0, 0,
1098 width, height);
1099 return new_pixmap;
1100 }
1101
1102 new_width = roundint(width * scale_x);
1103 new_height = roundint(height * scale_y);
1104
1105 pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, gdk_drawable_get_colormap(window), 0, 0, 0, 0, width, height);
1106 aux_pixbuf = gdk_pixbuf_scale_simple(pixbuf, new_width, new_height, GDK_INTERP_BILINEAR);
1107 new_pixmap = gdk_pixmap_new(pixmap, new_width, new_height, -1);
1108 gdk_draw_pixbuf(new_pixmap, gc, aux_pixbuf, 0, 0, 0, 0, new_width, new_height, GDK_RGB_DITHER_MAX, 0, 0);
1109
1110 gdk_pixbuf_unref(pixbuf);
1111 gdk_pixbuf_unref(aux_pixbuf);
1112
1113 gdk_gc_unref(gc);
1114
1115 return new_pixmap;
1116 }
1117
1118 static GdkBitmap *
scale_bitmap(GdkWindow * window,GdkBitmap * bitmap,gdouble scale_x,gdouble scale_y)1119 scale_bitmap (GdkWindow *window, GdkBitmap *bitmap, gdouble scale_x, gdouble scale_y)
1120 {
1121 GdkGC *gc;
1122 GdkVisual *visual = NULL;
1123 GdkImage *image = NULL, *new_image = NULL;
1124 GdkBitmap *new_bitmap = NULL;
1125 gint x, y, width, height, new_width, new_height;
1126 GdkColor color;
1127
1128 if(!bitmap) return NULL;
1129 if(!window) return NULL;
1130
1131 gc = gdk_gc_new(bitmap);
1132
1133 gdk_window_get_size(bitmap, &width, &height);
1134
1135 if(scale_x == 1.0 && scale_y == 1.0){
1136 new_bitmap = gdk_pixmap_new(window, width, height, 1);
1137 color.pixel = 0;
1138 gdk_gc_set_foreground(gc, &color);
1139 gdk_draw_rectangle(new_bitmap, gc, TRUE, 0, 0, width, height);
1140 color.pixel = 1;
1141 gdk_gc_set_foreground(gc, &color);
1142
1143 gdk_draw_pixmap(new_bitmap,
1144 gc,
1145 bitmap,
1146 0, 0,
1147 0, 0,
1148 width, height);
1149 return new_bitmap;
1150 }
1151
1152 new_width = roundint(width * scale_x);
1153 new_height = roundint(height * scale_y);
1154
1155 /* make a client side image of the bitmap, and
1156 * scale the data into a another client side image */
1157 visual = gdk_window_get_visual (bitmap);
1158 if(!visual) return NULL;
1159 new_image = gdk_image_new(GDK_IMAGE_FASTEST,visual,new_width,new_height);
1160 if(!new_image) return NULL;
1161 new_bitmap = gdk_pixmap_new(window, new_width, new_height, 1);
1162
1163 image = gdk_drawable_get_image(bitmap,
1164 0, 0,
1165 width, height);
1166
1167 color.pixel = 0;
1168 gdk_gc_set_foreground(gc, &color);
1169 gdk_draw_rectangle(new_bitmap, gc, TRUE, 0, 0, width, height);
1170 color.pixel = 1;
1171 gdk_gc_set_foreground(gc, &color);
1172
1173 for(x = 0; x < new_width; x++){
1174 for(y = 0; y < new_height; y++){
1175 gint px, py;
1176 gulong pixel;
1177
1178 px = MIN(roundint(x / scale_x), width - 1);
1179 py = MIN(roundint(y / scale_y), height - 1);
1180
1181 pixel = gdk_image_get_pixel(image, px, py);
1182 gdk_image_put_pixel(new_image, x, y, pixel);
1183 }
1184 }
1185
1186 /* draw the image into a new pixmap */
1187 gdk_draw_image(new_bitmap,gc,new_image,0,0,0,0,new_width,new_height);
1188
1189 gdk_image_destroy(image);
1190 gdk_image_destroy(new_image);
1191
1192 return new_bitmap;
1193 }
1194
1195