Rev 6098 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Langage for Statistical Data Analysis* Copyright (C) 1998-1999 Lyndon Drake* and the R Development Core Team** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include <gnome.h>#include "Defn.h"#include "Graphics.h"#include "devGNOME.h"#include "terminal.h"#define CURSOR GDK_CROSSHAIR /* Default cursor */#define MM_PER_INCH 25.4 /* mm -> inch conversion */typedef struct {/* R Graphics Parameters *//* local device copy so that we can detect *//* when parameter changes */double cex; /* Character expansion */double srt; /* String rotation */gint bg; /* Background */int fontface; /* Typeface */int fontsize; /* Size in points *//* GNOME Driver Specific */int windowWidth; /* Window width (pixels) */int windowHeight; /* Window height (pixels) */int resize; /* Window resized */GtkWidget *window; /* Graphics Window */GtkWidget *canvas;GdkColor *gcol_bg;GdkCursor *gcursor;int usefixed;GdkFont *fixedfont;GdkFont *font;} gnomeDesc;static int numGNOMEDevices = 0;/* Device driver actions */static void GNOME_Activate(DevDesc *);static void GNOME_Circle(double, double, int, double, int, int, DevDesc*);static void GNOME_Clip(double, double, double, double, DevDesc*);static void GNOME_Close(DevDesc*);static void GNOME_Deactivate(DevDesc *);static void GNOME_Hold(DevDesc*);static void GNOME_Line(double, double, double, double, int, DevDesc*);static int GNOME_Locator(double*, double*, DevDesc*);static void GNOME_Mode(int);static void GNOME_NewPage(DevDesc*);static int GNOME_Open(DevDesc*, gnomeDesc*, char*, double, double);static void GNOME_Polygon(int, double*, double*, int, int, int, DevDesc*);static void GNOME_Polyline(int, double*, double*, int, DevDesc*);static void GNOME_Rect(double, double, double, double, int, int, int, DevDesc*);static void GNOME_Resize(DevDesc*);static double GNOME_StrWidth(char*, DevDesc*);static void GNOME_Text(double, double, int, char*, double, double, double,DevDesc*);static void GNOME_MetricInfo(int, double*, double*, double*, DevDesc*);/* Pixel Dimensions (Inches) */static double pixelWidth(void){double width, widthMM;width = gdk_screen_width();widthMM = gdk_screen_width_mm();return ((double)widthMM / (double)width) / MM_PER_INCH;}static double pixelHeight(void){double height, heightMM;height = gdk_screen_height();heightMM = gdk_screen_height_mm();return ((double)heightMM / (double)height) / MM_PER_INCH;}/* font stuff *//* set the r, g, b, and pixel values of gcol to color */static void SetColor(GdkColor *gcol, int color){int red, green, blue;red = R_RED(color);green = R_GREEN(color);blue = R_BLUE(color);gcol->red = red * 257;gcol->green = green * 257;gcol->blue = blue * 257;gcol->pixel = gdk_rgb_xpixel_from_rgb((red << 16)|(green << 8)|(blue));}/* line type */static void SetLineType(GdkBitmap *stipple, int newlty, int newlwd){/* static gchar dashlist[8];gint i, j;if(newlwd < 1)newlwd = 1;for(i = 0; (i < 8) && (newlty != 0); i++) {j = newlty & 15;if(j == 0)j = 1;j = j * newlwd;if(j > 255)j = 255;dashlist[i] = j;newlty = newlty >> 4;}*//* set dashes *//* gdk_gc_set_dashes(gc, 0, dashlist, i);*/}/* signal functions */static gint configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer data) {DevDesc *dd;gnomeDesc *gtkd;/* g_print("configure\n"); */dd = (DevDesc *) data;g_return_val_if_fail(dd != NULL, FALSE);gtkd = (gnomeDesc *) dd->deviceSpecific;g_return_val_if_fail(gtkd != NULL, FALSE);g_return_val_if_fail(gtkd->canvas != NULL, FALSE);g_return_val_if_fail(GNOME_IS_CANVAS(gtkd->canvas), FALSE);/* resize */if((gtkd->windowWidth != event->width) || (gtkd->windowHeight != event->height)) {gtkd->windowWidth = event->width;gtkd->windowHeight = event->height;gtkd->resize = 1;}return FALSE;}static gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {DevDesc *dd;dd = (DevDesc *) data;g_return_val_if_fail(dd != NULL, FALSE);KillDevice(dd);return TRUE;}static void tb_activate_cb(GtkWidget *widget, gpointer data) {DevDesc *dd;dd = (DevDesc *) data;g_return_if_fail(dd != NULL);selectDevice(deviceNumber(dd));}static void tb_close_cb(GtkWidget *widget, gpointer data) {DevDesc *dd;dd = (DevDesc *) data;g_return_if_fail(dd != NULL);KillDevice(dd);}static GnomeUIInfo graphics_toolbar[] ={{ GNOME_APP_UI_ITEM, "Activate", "Make this window the current device", tb_activate_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_JUMP_TO, 0, (GdkModifierType) 0, NULL },GNOMEUIINFO_SEPARATOR,{ GNOME_APP_UI_ITEM, "Save As", "Save as a PS file", NULL, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_SAVE_AS, 0, (GdkModifierType) 0, NULL },{ GNOME_APP_UI_ITEM, "Print", "Print graphics", NULL, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_PRINT, 0, (GdkModifierType) 0, NULL },GNOMEUIINFO_SEPARATOR,{ GNOME_APP_UI_ITEM, "Close", "Close this graphics device", tb_close_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_CLOSE, 0, (GdkModifierType) 0, NULL },GNOMEUIINFO_END};/* create window etc */static int GNOME_Open(DevDesc *dd, gnomeDesc *gtkd, char *dsp, double w, double h){GdkColor bg;GtkStyle *wstyle;gint iw, ih;/*gdk_rgb_set_install(TRUE); */gdk_rgb_set_verbose(TRUE);gdk_rgb_init();gtk_widget_push_visual(gdk_rgb_get_visual());gtk_widget_push_colormap(gdk_rgb_get_cmap());/* initialise pointers */gtkd->canvas = NULL;/* FIXME: SetBaseFont *//* create window etc */gtkd->windowWidth = iw = w / pixelWidth();gtkd->windowHeight = ih = h / pixelHeight();gtkd->window = gnome_app_new("R.gnome.graphics", "R Graphics");gtk_window_set_policy(GTK_WINDOW(gtkd->window), TRUE, TRUE, FALSE);gtk_widget_realize(gtkd->window);/* create toolbar */gnome_app_create_toolbar_with_data(GNOME_APP(gtkd->window), graphics_toolbar, (gpointer) dd);/* create canvas */gtkd->canvas = gnome_canvas_new_aa();/* set window background color */gtkd->bg = dd->dp.bg = R_RGB(255, 255, 255);gtkd->gcol_bg = gdk_color_copy(&bg);SetColor(gtkd->gcol_bg, gtkd->bg);wstyle = gtk_style_copy(gtk_widget_get_style(gtkd->canvas));wstyle->bg[GTK_STATE_NORMAL] = *(gtkd->gcol_bg);gtk_widget_set_style(gtkd->canvas, wstyle);/* canvas properties */gtk_widget_set_usize(gtkd->canvas, iw, ih);gnome_canvas_set_scroll_region(GNOME_CANVAS(gtkd->canvas), 0, 0, iw, ih);/* place and realize the canvas */gnome_app_set_contents(GNOME_APP(gtkd->window), gtkd->canvas);gtk_widget_realize(gtkd->canvas);/* same as XSynch() */gdk_flush();/* set the cursor */gtkd->gcursor = gdk_cursor_new(GDK_CROSSHAIR);gdk_window_set_cursor(gtkd->canvas->window, gtkd->gcursor);/* connect to delete signal handler, etc */gtk_signal_connect(GTK_OBJECT(gtkd->canvas), "configure_event",(GtkSignalFunc) configure_event, (gpointer) dd);gtk_signal_connect(GTK_OBJECT(gtkd->window), "delete_event",(GtkSignalFunc) delete_event, (gpointer) dd);/* show everything */gtk_widget_show_all(gtkd->window);/* let other widgets use the default settings */gtk_widget_pop_visual();gtk_widget_pop_colormap();/* we made it! */return 1;}static double GNOME_StrWidth(char *str, DevDesc *dd){return 6.0;}static void GNOME_MetricInfo(int c, double *ascent, double *descent, double *width, DevDesc *dd){#ifdef BUG61#else/* metric information not available => return 0,0,0 */*ascent = 0.0;*descent = 0.0;*width = 0.0;#endif}static void GNOME_Clip(double x0, double x1, double y0, double y1, DevDesc *dd){}static void GNOME_Resize(DevDesc *dd){gnomeDesc *gtkd = (gnomeDesc *) dd->deviceSpecific;if (gtkd->resize != 0) {dd->dp.left = dd->gp.left = 0.0;dd->dp.right = dd->gp.right = gtkd->windowWidth;dd->dp.bottom = dd->gp.bottom = gtkd->windowHeight;dd->dp.top = dd->gp.top = 0.0;gtkd->resize = 0;}}/* clear the drawing area */void GNOME_NewPage_iterator(gpointer data, gpointer user_data){GList *list;GnomeCanvasItem *child;list = (GList *) data;child = (GnomeCanvasItem *) list->data;gtk_object_destroy(GTK_OBJECT(child));}static void GNOME_NewPage(DevDesc *dd){gnomeDesc *gtkd = (gnomeDesc *) dd->deviceSpecific;/* reset background color */if(gtkd->bg != dd->dp.bg) {gtkd->bg = dd->dp.bg;SetColor(gtkd->gcol_bg, gtkd->bg);/* FIXME: change window style */}/* clear off items *//* list = GNOME_CANVAS_GROUP(gnome_canvas_root(GNOME_CANVAS(gtkd->canvas)))->item_list;if(list != NULL) {g_list_foreach(list, GNOME_NewPage_iterator, NULL);g_list_free(list);GNOME_CANVAS_GROUP(gnome_canvas_root(GNOME_CANVAS(gtkd->canvas)))->item_list = NULL;GNOME_CANVAS_GROUP(gnome_canvas_root(GNOME_CANVAS(gtkd->canvas)))->item_list_end = NULL;}*/}/* kill off the window etc */static void GNOME_Close(DevDesc *dd){gnomeDesc *gtkd = (gnomeDesc *) dd->deviceSpecific;gtk_widget_destroy(gtkd->window);numGNOMEDevices--;free(gtkd);}#define title_text_inactive "R graphics device %d"#define title_text_active "R graphics device %d - Active"static void GNOME_Activate(DevDesc *dd){gnomeDesc *gtkd;gint devnum, numdigits;gchar *title_text;gint text_len;text_len = strlen(title_text_active);gtkd = (gnomeDesc *) dd->deviceSpecific;g_return_if_fail(gtkd != NULL);devnum = deviceNumber(dd);devnum++;numdigits = floor(Log10(devnum)) + 1;title_text = g_malloc(text_len + numdigits + 1);g_return_if_fail(title_text != NULL);snprintf(title_text, text_len + numdigits + 1, title_text_active, devnum);*(title_text + text_len + numdigits) = '\0';gtk_window_set_title(GTK_WINDOW(gtkd->window), title_text);g_free(title_text);}static void GNOME_Deactivate(DevDesc *dd){gnomeDesc *gtkd;gint devnum, numdigits;gchar *title_text;gint text_len;text_len = strlen(title_text_inactive);gtkd = (gnomeDesc *) dd->deviceSpecific;g_return_if_fail(gtkd != NULL);devnum = deviceNumber(dd);devnum++;numdigits = floor(Log10(devnum)) + 1;title_text = g_malloc(text_len + numdigits + 1);g_return_if_fail(title_text != NULL);snprintf(title_text, text_len + numdigits + 1, title_text_inactive, devnum);*(title_text + text_len + numdigits) = '\0';gtk_window_set_title(GTK_WINDOW(gtkd->window), title_text);g_free(title_text);}/* drawing stuff */static void GNOME_Rect(double x0, double y0, double x1, double y1,int coords, int bg, int fg, DevDesc *dd){double tmp;gnomeDesc *gtkd = (gnomeDesc *) dd->deviceSpecific;GdkColor gcol_fill, gcol_outline;GnomeCanvasItem *item;GConvert(&x0, &y0, coords, DEVICE, dd);GConvert(&x1, &y1, coords, DEVICE, dd);if(x0 > x1) {tmp = x0;x0 = x1;x1 = tmp;}if(y0 > y1) {tmp = y0;y0 = y1;y1 = tmp;}item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(gtkd->canvas)),gnome_canvas_rect_get_type(),"x1", x0,"y1", y0,"x2", x1,"y2", y1,"width_pixels", (guint) dd->gp.lwd,NULL);if(bg != NA_INTEGER) {SetColor(&gcol_fill, bg);gnome_canvas_item_set(item,"fill_color_gdk", &gcol_fill,NULL);}if(fg != NA_INTEGER) {SetColor(&gcol_outline, fg);gnome_canvas_item_set(item,"outline_color_gdk", &gcol_outline,NULL);}}static void GNOME_Circle(double x, double y, int coords,double r, int col, int border, DevDesc *dd){GdkColor gcol_fill, gcol_outline;double x1, y1, x2, y2;gnomeDesc *gtkd = (gnomeDesc *) dd->deviceSpecific;GnomeCanvasItem *item;GConvert(&x, &y, coords, DEVICE, dd);x1 = x - r; y1 = y - r;x2 = x + r; y2 = y + r;item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(gtkd->canvas)),gnome_canvas_ellipse_get_type(),"x1", x1,"y1", y1,"x2", x2,"y2", y2,"width_pixels", (guint) dd->gp.lwd,NULL);if(col != NA_INTEGER) {SetColor(&gcol_fill, col);gnome_canvas_item_set(item,"fill_color_gdk", &gcol_fill,NULL);}if(border != NA_INTEGER) {SetColor(&gcol_outline, border);gnome_canvas_item_set(item,"outline_color_gdk", &gcol_outline,NULL);}}static void GNOME_Line(double x1, double y1, double x2, double y2,int coords, DevDesc *dd){GnomeCanvasPoints *points;gnomeDesc *gtkd = (gnomeDesc *) dd->deviceSpecific;GnomeCanvasItem *item;GdkColor gcol_fill;GConvert(&x1, &y1, coords, DEVICE, dd);GConvert(&x2, &y2, coords, DEVICE, dd);points = gnome_canvas_points_new(2);points->coords[0] = x1;points->coords[1] = y1;points->coords[2] = x2;points->coords[3] = y2;item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(gtkd->canvas)),gnome_canvas_line_get_type(),"points", points,"width_pixels", (guint) dd->gp.lwd,NULL);if(dd->gp.col != NA_INTEGER) {SetColor(&gcol_fill, dd->gp.col);if(dd->gp.lty != 0) {/* SetLineType(GNOME_CANVAS_LINE(item)->gc, dd->gp.lty, dd->gp.lwd); */gnome_canvas_item_set(item,"line_style", GDK_LINE_ON_OFF_DASH,NULL);}gnome_canvas_item_set(item,"fill_color_gdk", &gcol_fill,NULL);}gnome_canvas_points_free(points);}static void GNOME_Polyline(int n, double *x, double *y, int coords, DevDesc *dd){double devx, devy;int i;GnomeCanvasPoints *points;gnomeDesc *gtkd = (gnomeDesc *) dd->deviceSpecific;GnomeCanvasItem *item;GdkColor gcol_fill;GdkBitmap stipple;points = gnome_canvas_points_new(n);for(i = 0; i < n; i++) {devx = x[i]; devy = y[i];GConvert(&devx, &devy, coords, DEVICE, dd);points->coords[i * 2] = devx;points->coords[i * 2 + 1] = devy;}item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(gtkd->canvas)),gnome_canvas_line_get_type(),"points", points,"width_pixels", (guint) dd->gp.lwd,NULL);if(dd->gp.col != NA_INTEGER) {SetColor(&gcol_fill, dd->gp.col);if(dd->gp.lty != 0) {SetLineType(&stipple, dd->gp.lty, dd->gp.lwd);gnome_canvas_item_set(item,"fill_stipple", &stipple,NULL);}gnome_canvas_item_set(item,"fill_color_gdk", &gcol_fill,NULL);}gnome_canvas_points_free(points);}static void GNOME_Polygon(int n, double *x, double *y, int coords,int bg, int fg, DevDesc *dd){double devx, devy;int i;GnomeCanvasPoints *points;gnomeDesc *gtkd = (gnomeDesc *) dd->deviceSpecific;GnomeCanvasItem *item;GdkColor gcol_fill, gcol_outline;points = gnome_canvas_points_new(n);for(i = 0; i < n; i++) {devx = x[i]; devy = y[i];GConvert(&devx, &devy, coords, DEVICE, dd);points->coords[i * 2] = floor(devx);points->coords[i * 2 + 1] = floor(devy);}item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(gtkd->canvas)),gnome_canvas_polygon_get_type(),"points", points,"width_units", (double) 2,NULL);if(bg != NA_INTEGER) {SetColor(&gcol_fill, bg);gnome_canvas_item_set(item,"fill_color_gdk", &gcol_fill,NULL);}if(fg != NA_INTEGER) {SetColor(&gcol_outline, fg);gnome_canvas_item_set(item,"outline_color", "black",NULL);}gnome_canvas_points_free(points);}static void GNOME_Text(double x, double y, int coords,char *str, double xc, double yc, double rot, DevDesc *dd){GnomeCanvasItem *item;gnomeDesc *gtkd = (gnomeDesc *) dd->deviceSpecific;GdkColor gcol_fill;GConvert(&x, &y, coords, DEVICE, dd);SetColor(&gcol_fill, dd->gp.col);item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(gtkd->canvas)),gnome_canvas_text_get_type(),"text", str,"anchor", GTK_ANCHOR_NW,"x", x,"y", y,/*"font", "-adobe-times-medium-r-normal-*-*-120-*-*-p-*-iso8859-1",*/"font", "-*-times-medium-r-*-*-120-*-*-*-*-*-*-*","fill_color_gdk", &gcol_fill,NULL);}/* locator */static int GNOME_Locator(double *x, double *y, DevDesc *dd){return 0;}/* useless stuff */static void GNOME_Mode(gint mode){}static void GNOME_Hold(DevDesc *dd){}/* Device driver entry point */int GnomeDeviceDriver(DevDesc *dd, char *display, double width, double height, double pointsize){int ps;gnomeDesc *gtkd;if(!(gtkd = (gnomeDesc *) malloc(sizeof(gnomeDesc))))return 0;dd->deviceSpecific = (void *) gtkd;/* FIXME: font loading */ps = pointsize;if(ps < 6 || ps > 24) ps = 12;ps = 2 * (ps / 2);gtkd->fontface = -1;gtkd->fontsize = -1;dd->dp.font = 1;dd->dp.ps = ps;/* device driver start */if(!GNOME_Open(dd, gtkd, display, width, height)) {free(gtkd);return 0;}/* setup data structure */dd->dp.open = GNOME_Open;dd->dp.close = GNOME_Close;dd->dp.activate = GNOME_Activate;dd->dp.deactivate = GNOME_Deactivate;dd->dp.resize = GNOME_Resize;dd->dp.newPage = GNOME_NewPage;dd->dp.clip = GNOME_Clip;dd->dp.strWidth = GNOME_StrWidth;dd->dp.text = GNOME_Text;dd->dp.rect = GNOME_Rect;dd->dp.circle = GNOME_Circle;dd->dp.line = GNOME_Line;dd->dp.polyline = GNOME_Polyline;dd->dp.polygon = GNOME_Polygon;dd->dp.locator = GNOME_Locator;dd->dp.mode = GNOME_Mode;dd->dp.hold = GNOME_Hold;dd->dp.metricInfo = GNOME_MetricInfo;dd->dp.left = 0;dd->dp.right = gtkd->windowWidth;dd->dp.bottom = gtkd->windowHeight;dd->dp.top = 0;/* FIXME: nominal character sizes */dd->dp.cra[0] = 10;dd->dp.cra[1] = 10;/* FIXME: character addressing offsets */dd->dp.xCharOffset = 0.4900;dd->dp.yCharOffset = 0.3333;dd->dp.yLineBias = 0.1;/* inches per raster unit */dd->dp.ipr[0] = pixelWidth();dd->dp.ipr[1] = pixelHeight();/* device capabilities */dd->dp.canResizePlot = 1;dd->dp.canChangeFont = 0; /* FIXME: surely this is possible */dd->dp.canRotateText = 1;dd->dp.canResizeText = 1;dd->dp.canClip = 0;/* x11 device description stuff */gtkd->cex = 1.0;gtkd->srt = 0.0;gtkd->resize = 0;dd->displayListOn = 1;/* finish */return 1;}