1/* 2 * GTK plotting routines source file 3 * 4 * Copyright (c) 1999 Mark Taylor 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library 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 GNU 14 * 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 library; if not, write to the 18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 * Boston, MA 02111-1307, USA. 20 */ 21 22/* $Id$ */ 23 24#ifdef HAVE_CONFIG_H 25# include <config.h> 26#endif 27 28#include "gpkplotting.h" 29 30#ifdef STDC_HEADERS 31# include <string.h> 32#else 33# ifndef HAVE_STRCHR 34# define strchr index 35# define strrchr rindex 36# endif 37char *strchr(), *strrchr(); 38# ifndef HAVE_MEMCPY 39# define memcpy(d, s, n) bcopy ((s), (d), (n)) 40# define memmove(d, s, n) bcopy ((s), (d), (n)) 41# endif 42#endif 43 44#ifdef WITH_DMALLOC 45#include <dmalloc.h> 46#endif 47 48static gint num_plotwindows = 0; 49static gint max_plotwindows = 10; 50static GdkPixmap *pixmaps[10]; 51static GtkWidget *pixmapboxes[10]; 52 53 54 55 56/* compute a gdkcolor */ 57void 58setcolor(GtkWidget * widget, GdkColor * color, gint red, gint green, gint blue) 59{ 60 61 /* colors in GdkColor are taken from 0 to 65535, not 0 to 255. */ 62 color->red = red * (65535 / 255); 63 color->green = green * (65535 / 255); 64 color->blue = blue * (65535 / 255); 65 color->pixel = (gulong) (color->red * 65536 + color->green * 256 + color->blue); 66 /* find closest in colormap, if needed */ 67 gdk_color_alloc(gtk_widget_get_colormap(widget), color); 68} 69 70 71void 72gpk_redraw(GdkPixmap * pixmap, GtkWidget * pixmapbox) 73{ 74 /* redraw the entire pixmap */ 75 gdk_draw_pixmap(pixmapbox->window, 76 pixmapbox->style->fg_gc[GTK_WIDGET_STATE(pixmapbox)], 77 pixmap, 0, 0, 0, 0, pixmapbox->allocation.width, pixmapbox->allocation.height); 78} 79 80 81static GdkPixmap ** 82findpixmap(GtkWidget * widget) 83{ 84 int i; 85 for (i = 0; i < num_plotwindows && widget != pixmapboxes[i]; i++); 86 if (i >= num_plotwindows) { 87 g_print("findpixmap(): bad argument widget \n"); 88 return NULL; 89 } 90 return &pixmaps[i]; 91} 92 93void 94gpk_graph_draw(GtkWidget * widget, /* plot on this widged */ 95 int n, /* number of data points */ 96 gdouble * xcord, gdouble * ycord, /* data */ 97 gdouble xmn, gdouble ymn, /* coordinates of corners */ 98 gdouble xmx, gdouble ymx, int clear, /* clear old plot first */ 99 char *title, /* add a title (only if clear=1) */ 100 GdkColor * color) 101{ 102 GdkPixmap **ppixmap; 103 GdkPoint *points; 104 int i; 105 gint16 width, height; 106 GdkFont *fixed_font; 107 GdkGC *gc; 108 109 gc = gdk_gc_new(widget->window); 110 gdk_gc_set_foreground(gc, color); 111 112 113 114 if ((ppixmap = findpixmap(widget))) { 115 width = widget->allocation.width; 116 height = widget->allocation.height; 117 118 119 if (clear) { 120 /* white background */ 121 gdk_draw_rectangle(*ppixmap, widget->style->white_gc, TRUE, 0, 0, width, height); 122 /* title */ 123#ifdef _WIN32 124 fixed_font = gdk_font_load("-misc-fixed-large-r-*-*-*-100-*-*-*-*-*-*"); 125#else 126 fixed_font = gdk_font_load("-misc-fixed-medium-r-*-*-*-100-*-*-*-*-iso8859-1"); 127#endif 128 129 gdk_draw_text(*ppixmap, fixed_font, 130 widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 131 0, 10, title, strlen(title)); 132 } 133 134 135 points = g_malloc(n * sizeof(GdkPoint)); 136 for (i = 0; i < n; i++) { 137 points[i].x = .5 + ((xcord[i] - xmn) * (width - 1) / (xmx - xmn)); 138 points[i].y = .5 + ((ycord[i] - ymx) * (height - 1) / (ymn - ymx)); 139 } 140 gdk_draw_lines(*ppixmap, gc, points, n); 141 g_free(points); 142 gpk_redraw(*ppixmap, widget); 143 } 144 gdk_gc_destroy(gc); 145} 146 147 148 149void 150gpk_rectangle_draw(GtkWidget * widget, /* plot on this widged */ 151 gdouble * xcord, gdouble * ycord, /* corners */ 152 gdouble xmn, gdouble ymn, /* coordinates of corners */ 153 gdouble xmx, gdouble ymx, GdkColor * color) 154{ 155 GdkPixmap **ppixmap; 156 GdkPoint points[2]; 157 int i; 158 gint16 width, height; 159 GdkGC *gc; 160 161 162 gc = gdk_gc_new(widget->window); 163 gdk_gc_set_foreground(gc, color); 164 165 166 if ((ppixmap = findpixmap(widget))) { 167 width = widget->allocation.width; 168 height = widget->allocation.height; 169 170 171 for (i = 0; i < 2; i++) { 172 points[i].x = .5 + ((xcord[i] - xmn) * (width - 1) / (xmx - xmn)); 173 points[i].y = .5 + ((ycord[i] - ymx) * (height - 1) / (ymn - ymx)); 174 } 175 width = points[1].x - points[0].x + 1; 176 height = points[1].y - points[0].y + 1; 177 gdk_draw_rectangle(*ppixmap, gc, TRUE, points[0].x, points[0].y, width, height); 178 gpk_redraw(*ppixmap, widget); 179 } 180 gdk_gc_destroy(gc); 181} 182 183 184 185void 186gpk_bargraph_draw(GtkWidget * widget, /* plot on this widged */ 187 int n, /* number of data points */ 188 gdouble * xcord, gdouble * ycord, /* data */ 189 gdouble xmn, gdouble ymn, /* coordinates of corners */ 190 gdouble xmx, gdouble ymx, int clear, /* clear old plot first */ 191 char *title, /* add a title (only if clear=1) */ 192 int barwidth, /* bar width. 0=compute based on window size */ 193 GdkColor * color) 194{ 195 GdkPixmap **ppixmap; 196 GdkPoint points[2]; 197 int i; 198 gint16 width, height, x, y, barheight; 199 GdkFont *fixed_font; 200 GdkGC *gc; 201 int titleSplit; 202 203 204 gc = gdk_gc_new(widget->window); 205 gdk_gc_set_foreground(gc, color); 206 207 208 if ((ppixmap = findpixmap(widget))) { 209 width = widget->allocation.width; 210 height = widget->allocation.height; 211 212 213 if (clear) { 214 /* white background */ 215 gdk_draw_rectangle(*ppixmap, widget->style->white_gc, TRUE, 0, 0, width, height); 216 /* title */ 217#ifdef _WIN32 218 fixed_font = gdk_font_load("-misc-fixed-large-r-*-*-*-100-*-*-*-*-*-*"); 219#else 220 fixed_font = gdk_font_load("-misc-fixed-medium-r-*-*-*-100-*-*-*-*-iso8859-1"); 221#endif 222 223 titleSplit = strcspn(title, "\n"); 224 225 if (titleSplit && (titleSplit != strlen(title))) { 226 gdk_draw_text(*ppixmap, fixed_font, 227 widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 228 0, 10, title, titleSplit); 229 230 gdk_draw_text(*ppixmap, fixed_font, 231 widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 232 0, 22, title + titleSplit + 1, (strlen(title) - titleSplit) - 1); 233 234 235 } 236 else { 237 gdk_draw_text(*ppixmap, fixed_font, 238 widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 239 0, 10, title, strlen(title)); 240 } 241 } 242 243 244 for (i = 0; i < n; i++) { 245 points[1].x = .5 + ((xcord[i] - xmn) * (width - 1) / (xmx - xmn)); 246 points[1].y = .5 + ((ycord[i] - ymx) * (height - 1) / (ymn - ymx)); 247 points[0].x = points[1].x; 248 points[0].y = height - 1; 249 250 x = .5 + ((xcord[i] - xmn) * (width - 1) / (xmx - xmn)); 251 y = .5 + ((ycord[i] - ymx) * (height - 1) / (ymn - ymx)); 252 if (!barwidth) 253 barwidth = (width / (n + 1)) - 1; 254 barwidth = barwidth > 5 ? 5 : barwidth; 255 barwidth = barwidth < 1 ? 1 : barwidth; 256 barheight = height - 1 - y; 257 /* gdk_draw_lines(*ppixmap,gc,points,2); */ 258 gdk_draw_rectangle(*ppixmap, gc, TRUE, x, y, barwidth, barheight); 259 260 } 261 gpk_redraw(*ppixmap, widget); 262 } 263 gdk_gc_destroy(gc); 264} 265 266 267 268 269 270/* Create a new backing pixmap of the appropriate size */ 271static gint 272configure_event(GtkWidget * widget, GdkEventConfigure * event, gpointer data) 273{ 274 GdkPixmap **ppixmap; 275 if ((ppixmap = findpixmap(widget))) { 276 if (*ppixmap) 277 gdk_pixmap_unref(*ppixmap); 278 *ppixmap = gdk_pixmap_new(widget->window, 279 widget->allocation.width, widget->allocation.height, -1); 280 gdk_draw_rectangle(*ppixmap, 281 widget->style->white_gc, 282 TRUE, 0, 0, widget->allocation.width, widget->allocation.height); 283 } 284 return TRUE; 285} 286 287 288 289/* Redraw the screen from the backing pixmap */ 290static gint 291expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer data) 292{ 293 GdkPixmap **ppixmap; 294 if ((ppixmap = findpixmap(widget))) { 295 gdk_draw_pixmap(widget->window, 296 widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 297 *ppixmap, 298 event->area.x, event->area.y, 299 event->area.x, event->area.y, event->area.width, event->area.height); 300 } 301 302 return FALSE; 303} 304 305 306 307 308 309GtkWidget * 310gpk_plot_new(int width, int height) 311{ 312 GtkWidget *pixmapbox; 313 314 pixmapbox = gtk_drawing_area_new(); 315 gtk_drawing_area_size(GTK_DRAWING_AREA(pixmapbox), width, height); 316 gtk_signal_connect(GTK_OBJECT(pixmapbox), "expose_event", (GtkSignalFunc) expose_event, NULL); 317 gtk_signal_connect(GTK_OBJECT(pixmapbox), "configure_event", 318 (GtkSignalFunc) configure_event, NULL); 319 gtk_widget_set_events(pixmapbox, GDK_EXPOSURE_MASK); 320 321 if (num_plotwindows < max_plotwindows) { 322 pixmapboxes[num_plotwindows] = pixmapbox; 323 pixmaps[num_plotwindows] = NULL; 324 num_plotwindows++; 325 } 326 else { 327 g_print("gtk_plotarea_new(): exceeded maximum of 10 plotarea windows\n"); 328 } 329 330 return pixmapbox; 331} 332