/* SciGraphica - Scientific graphics and data manipulation * Copyright (C) 2001 Adrian E. Feiguin * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include "sg_plot.h" #include "sg.h" #include "sg_dialogs.h" #include "sg_layer.h" #include "gtkplotart.h" #include "../pixmaps/plot_icon2.xpm" #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x static const gdouble unit_pt[]={ 1.0, 2.83, 28.35, 72.0, (72.0/SG_DPI)}; static void sg_plot_class_init (SGplotClass *klass); static void sg_plot_init (SGplot *plot); static void sg_plot_init_gui (SGplot *plot); static void sg_plot_destroy (GtkObject *object); static void sg_plot_realize (GtkWidget *widget); static void sg_plot_map (GtkWidget *widget); static void reorder_buttons (SGplot *plot); static void button_toggled (GtkWidget *widget, gpointer data); static gint button_clicked (GtkWidget *widget, GdkEventButton *event, gpointer data); static gint edit_text (GtkWidget *widget, GdkEventButton *event, gpointer data); static GtkWidget *open_text_dialog (GtkPlotText *text); static gint apply_dialog_text (GtkWidget *widget, gpointer data); static gint click_on_item (GtkPlotCanvas *canvas, GdkEvent *event, GtkPlotCanvasChild *item, gpointer data); static void activate_layer (GtkPlotCanvas *canvas, gpointer data); static gboolean resize_item (GtkPlotCanvas *canvas, GtkPlotCanvasChild *item, gdouble width, gdouble height, gpointer data); static gboolean move_item (GtkPlotCanvas *canvas, GtkPlotCanvasChild *item, gdouble x, gdouble y, gpointer data); static gboolean key_press (GtkWidget *widget, GdkEventKey *key, gpointer data); static void update_ruler_expose_x (GtkWidget *scroll, gpointer data); static void update_ruler_expose_y (GtkWidget *scroll, gpointer data); static void sg_plot_motion (GtkWidget *widget, GdkEventMotion *event, gpointer data); static void canvas_changed (GtkPlotCanvas *canvas, gpointer data); #ifdef WITH_GNOME static GnomeAppClass *parent_class = NULL; #else static GtkWindowClass *parent_class = NULL; #endif GtkType sg_plot_get_type (void) { static GtkType sg_plot_type = 0; if (!sg_plot_type) { GtkTypeInfo sg_plot_info = { "SGplot", sizeof (SGplot), sizeof (SGplotClass), (GtkClassInitFunc) sg_plot_class_init, (GtkObjectInitFunc) sg_plot_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; #ifdef WITH_GNOME sg_plot_type = gtk_type_unique (gnome_app_get_type(), &sg_plot_info); #else sg_plot_type = gtk_type_unique (gtk_window_get_type(), &sg_plot_info); #endif } return sg_plot_type; } static void sg_plot_class_init (SGplotClass *klass) { GtkWidgetClass *widget_class; GtkObjectClass *object_class; widget_class = (GtkWidgetClass*) klass; object_class = (GtkObjectClass*) klass; #ifdef WITH_GNOME parent_class = (GnomeAppClass *)gtk_type_class (gnome_app_get_type ()); #else parent_class = (GtkWindowClass *)gtk_type_class (gtk_window_get_type ()); #endif widget_class->realize = sg_plot_realize; widget_class->map = sg_plot_map; object_class->destroy = sg_plot_destroy; } static void sg_plot_init (SGplot *plot) { plot->tool = SG_TOOL_ARROW; plot->orientation = GTK_PLOT_PORTRAIT; plot->page_size = GTK_PLOT_LETTER; plot->scale = .65; plot->page_width = GTK_PLOT_LETTER_W; plot->page_height = GTK_PLOT_LETTER_H; plot->page_units = SG_UNIT_IN; plot->hruler = NULL; plot->vruler = NULL; plot->real_canvas = gtk_plot_canvas_new(GTK_PLOT_LETTER_W, GTK_PLOT_LETTER_H, plot->scale); plot->layers = NULL; plot->nlayers = 0; plot->sw = NULL; plot->toolbox = NULL; plot->x = 20; plot->y = 20; plot->width = 600; plot->height = 600; sg_plot_rescale(plot, .65); plot->antialias = FALSE; sg_plot_init_gui(plot); } #ifdef WITH_GNOME void sg_plot_show_bands(GList *bandlist,gboolean show) { GnomeDockBand *dockband; GnomeDockBandChild *dockbandchild; GList *childlist; while (bandlist) { dockband=(GnomeDockBand*)bandlist->data; childlist=dockband->children; while (childlist) { dockbandchild=(GnomeDockBandChild*)childlist->data; if (show) gtk_widget_show(dockbandchild->widget); else gtk_widget_hide(dockbandchild->widget); childlist=childlist->next; } childlist=dockband->floating_child; while (childlist) { dockbandchild=(GnomeDockBandChild*)childlist->data; if (show) gtk_widget_show(dockbandchild->widget); else gtk_widget_hide(dockbandchild->widget); childlist=childlist->next; } bandlist=bandlist->next; } } void sg_plot_show_top_toolbar(SGplot *plot) { GnomeDock *dock; dock=gnome_app_get_dock (GNOME_APP(plot)); sg_plot_show_bands(dock->top_bands,sg_show_plot_menubar); sg_plot_show_bands(dock->bottom_bands,sg_show_plot_menubar); sg_plot_show_bands(dock->left_bands,sg_show_plot_menubar); sg_plot_show_bands(dock->right_bands,sg_show_plot_menubar); gtk_widget_queue_resize(GTK_WIDGET(plot)); } #else void sg_plot_show_top_toolbar(SGplot *plot) { GtkBox *box; GtkWidget *widget; box=GTK_BOX(GTK_BIN(plot)->child); widget=((GtkBoxChild*)box->children->data)->widget;; /* Assume the top toolbar is the first child */ if (sg_show_plot_menubar) gtk_widget_show(widget); else gtk_widget_hide(widget); } #endif /* WITH_GNOME */ static void sg_plot_init_gui(SGplot *plot) { GtkWidget *table, *hbox, *hbox2, *vbox, *top_hruler, *left_vruler; GtkWidget *frame,*sbar_vert, *sbar_horiz; GtkStyle *style; GtkWidget *toolbar; vbox = gtk_vbox_new(FALSE, 0); plot->canvas_box = gtk_vbox_new(TRUE, 0); gtk_box_set_spacing(GTK_BOX(vbox), 5); hbox = gtk_hbox_new(FALSE, 0); hbox2 = gtk_hbox_new(FALSE, 0); table = gtk_table_new(4, 3, FALSE); #ifdef WITH_GNOME gnome_app_construct(GNOME_APP(plot), PACKAGE, plot->name); gnome_app_set_contents(GNOME_APP(plot),vbox); #else gtk_container_add(GTK_CONTAINER(plot), vbox); #endif toolbar = sg_plot_build_toolbar(plot); gtk_window_set_title(GTK_WINDOW(plot), plot->name); gtk_window_set_policy(GTK_WINDOW(plot), TRUE, TRUE, FALSE); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); gtk_widget_show (hbox); plot->sw=gtk_viewport_new(NULL,NULL); sbar_vert=gtk_vscrollbar_new(gtk_viewport_get_vadjustment (GTK_VIEWPORT(plot->sw))); sbar_horiz=gtk_hscrollbar_new(gtk_viewport_get_hadjustment (GTK_VIEWPORT(plot->sw))); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(sbar_vert), 3, 4, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)(GTK_FILL|GTK_SHRINK|GTK_EXPAND),0,0); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(sbar_horiz), 2, 3, 2, 3, (GtkAttachOptions)(GTK_FILL|GTK_SHRINK|GTK_EXPAND), (GtkAttachOptions)0,0,0); plot->toolbox = sg_toolbox_new(); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(plot->toolbox), FALSE, FALSE, 0); gtk_widget_realize(GTK_WIDGET(plot->toolbox)); gtk_widget_show_all(plot->toolbox); if (!sg_show_plot_toolbar) gtk_widget_hide(plot->toolbox); gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(plot->sw),hbox2); gtk_box_pack_start(GTK_BOX(hbox2), GTK_WIDGET(plot->canvas_box), TRUE, FALSE, 0); gtk_box_pack_start(GTK_BOX(plot->canvas_box), GTK_WIDGET(plot->real_canvas), TRUE, FALSE, 0); gtk_widget_show(GTK_WIDGET(plot->real_canvas)); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(plot->sw), 2, 3, 1, 2, (GtkAttachOptions)(GTK_FILL|GTK_SHRINK|GTK_EXPAND), (GtkAttachOptions)(GTK_FILL|GTK_SHRINK|GTK_EXPAND), 0, 0); /*-------------------------------------------------------------*/ gtk_signal_connect(GTK_OBJECT(gtk_viewport_get_hadjustment (GTK_VIEWPORT(plot->sw))), "changed", (GtkSignalFunc)update_ruler_expose_x,(gpointer)plot); gtk_signal_connect(GTK_OBJECT(gtk_viewport_get_hadjustment (GTK_VIEWPORT(plot->sw))), "value_changed", (GtkSignalFunc)update_ruler_expose_x,(gpointer)plot); gtk_signal_connect(GTK_OBJECT(gtk_viewport_get_vadjustment (GTK_VIEWPORT(plot->sw))), "changed", (GtkSignalFunc)update_ruler_expose_y,(gpointer)plot); gtk_signal_connect(GTK_OBJECT(gtk_viewport_get_vadjustment (GTK_VIEWPORT(plot->sw))), "value_changed", (GtkSignalFunc)update_ruler_expose_y,(gpointer)plot); /*---------------------------------------------------------------*/ plot->hruler = top_hruler = gtk_hruler_new(); gtk_ruler_set_range(GTK_RULER(top_hruler), 0, plot->page_width, 0, plot->page_width); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(top_hruler), 2,3,0,1, (GtkAttachOptions)(GTK_SHRINK|GTK_FILL|GTK_EXPAND), (GtkAttachOptions)0,0,0); gtk_widget_show(top_hruler); plot->vruler = left_vruler = gtk_vruler_new(); gtk_ruler_set_range(GTK_RULER(left_vruler), 0, plot->page_height, 0, plot->page_height); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(left_vruler),1,2,1,2, (GtkAttachOptions)0, (GtkAttachOptions)(GTK_SHRINK|GTK_FILL|GTK_EXPAND),0,0); gtk_widget_show(left_vruler); style=gtk_style_copy(GTK_WIDGET(plot)->style); if (style && style->font){ gtk_widget_set_style(top_hruler,style); gtk_widget_set_style(left_vruler,style); } gtk_signal_connect(GTK_OBJECT(plot->hruler), "map", (GtkSignalFunc)update_ruler_expose_x,(gpointer)plot); gtk_signal_connect(GTK_OBJECT(plot->vruler), "map", (GtkSignalFunc)update_ruler_expose_y,(gpointer)plot); gtk_widget_show (left_vruler); gtk_signal_connect(GTK_OBJECT(plot->real_canvas),"motion_notify_event", GTK_SIGNAL_FUNC(sg_plot_motion), plot); /*-------------------------------------------------------------*/ frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); gtk_box_pack_end(GTK_BOX(vbox), frame, FALSE, FALSE, 0); gtk_widget_show(frame); plot->label = gtk_label_new(""); gtk_misc_set_alignment(GTK_MISC(plot->label), 0., .5); gtk_container_add(GTK_CONTAINER(frame), plot->label); gtk_widget_show(plot->label); /*-------------------------------------------------------------*/ gtk_plot_canvas_set_size(GTK_PLOT_CANVAS(plot->real_canvas), GTK_PLOT_CANVAS(plot->real_canvas)->width, GTK_PLOT_CANVAS(plot->real_canvas)->height); gtk_widget_ensure_style(plot->real_canvas); gtk_plot_canvas_paint(GTK_PLOT_CANVAS(plot->real_canvas)); gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(plot->real_canvas)); gtk_widget_show_all(table); gtk_widget_show(vbox); /* Signals */ gtk_signal_connect(GTK_OBJECT(plot->real_canvas), "changed", (GtkSignalFunc)canvas_changed, plot); gtk_signal_connect(GTK_OBJECT(plot->real_canvas), "select_item", (GtkSignalFunc)click_on_item, plot); gtk_signal_connect(GTK_OBJECT(plot->real_canvas), "button_press_event", (GtkSignalFunc)edit_text, plot); gtk_signal_connect(GTK_OBJECT(plot->real_canvas), "key_press_event", (GtkSignalFunc)key_press, plot); gtk_signal_connect(GTK_OBJECT(plot->real_canvas), "move_item", (GtkSignalFunc)move_item, plot); gtk_signal_connect(GTK_OBJECT(plot->real_canvas), "resize_item", (GtkSignalFunc)resize_item, plot); } static void sg_plot_realize(GtkWidget *widget) { SGplot *plot; GdkPixmap *plot_icon_pixmap; GdkBitmap *plot_icon_mask; plot = SG_PLOT(widget); if(plot->width > 0 && plot->height > 0){ gtk_widget_set_uposition(GTK_WIDGET(plot), plot->x, plot->y); gtk_widget_set_usize(GTK_WIDGET(plot), plot->width, plot->height); }else{ gtk_widget_set_usize(GTK_WIDGET(plot), 600, 600); } GTK_WIDGET_CLASS(parent_class)->realize(widget); plot_icon_pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, gdk_colormap_get_system(), &plot_icon_mask, NULL, plot_icon2_xpm); gdk_window_set_icon(GTK_WIDGET(plot)->window, NULL, plot_icon_pixmap, plot_icon_mask); } static void sg_plot_map(GtkWidget *widget) { SGplot *plot; GdkPixmap *plot_icon_pixmap; GdkBitmap *plot_icon_mask; plot = SG_PLOT(widget); GTK_WIDGET_CLASS(parent_class)->map(widget); sg_plot_show_top_toolbar(plot); sg_plot_toolbox_init(plot); } SGplot * sg_plot_new(gchar *name) { SGplot *plot; plot = SG_PLOT(gtk_widget_new(sg_plot_get_type(), NULL)); plot->name = g_strdup(name); gtk_window_set_title(GTK_WINDOW(plot), plot->name); return plot; } SGplot * sg_plot_new_with_layer(SGlayerType layer_type, gchar *name) { SGplot *plot; SGlayer *default_layer; plot = sg_plot_new(name); if(layer_type != SG_LAYER_POLAR) default_layer = sg_layer_new(layer_type, .65, .45); else default_layer = sg_layer_new(layer_type, .75, .45); sg_plot_add_layer(plot, default_layer, .175, .15); return plot; } void sg_plot_add_layer(SGplot *plot, SGlayer *layer, gdouble x, gdouble y) { gint nlayers; layer->parent = plot; nlayers = plot->nlayers; gtk_fixed_put(GTK_FIXED(plot->real_canvas), layer->button, nlayers * 24, 0); gtk_widget_show(layer->button); sg_layer_button_set_label(layer, nlayers + 1); gtk_plot_canvas_add_plot(GTK_PLOT_CANVAS(plot->real_canvas), GTK_PLOT(layer->real_plot), x, y); gtk_widget_show(GTK_WIDGET(layer->real_plot)); plot->layers = g_list_append(plot->layers, layer); sg_plot_set_active_layer(plot, layer); plot->nlayers++; gtk_signal_connect(GTK_OBJECT(layer->button), "toggled", GTK_SIGNAL_FUNC(button_toggled), layer); gtk_signal_connect(GTK_OBJECT(layer->button), "button_press_event", GTK_SIGNAL_FUNC(button_clicked), layer); sg_layer_control_refresh(plot->name); } void sg_plot_move_layer(SGplot *plot, SGlayer *layer, gdouble x, gdouble y) { gint nlayers; layer->parent = plot; gtk_plot_move(GTK_PLOT(layer->real_plot), x, y); gtk_plot_canvas_paint(GTK_PLOT_CANVAS(plot->real_canvas)); gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(plot->real_canvas)); } void sg_plot_resize_layer(SGplot *plot, SGlayer *layer, gdouble w, gdouble h) { gtk_plot_resize(GTK_PLOT(layer->real_plot), w, h); gtk_plot_canvas_paint(GTK_PLOT_CANVAS(plot->real_canvas)); gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(plot->real_canvas)); } void sg_plot_remove_layer(SGplot *plot, SGlayer *layer) { GList *layers = NULL; if(plot->nlayers == 0) return; gtk_container_remove(GTK_CONTAINER(plot->real_canvas), layer->real_plot); gtk_container_remove(GTK_CONTAINER(plot->real_canvas), layer->button); layers = plot->layers; while(layers) { if(layers->data == layer){ plot->layers = g_list_remove_link(plot->layers, layers); if(layer && GTK_IS_OBJECT(layer)) gtk_object_destroy(GTK_OBJECT(layer)); g_list_free_1(layers); plot->nlayers--; break; } layers = layers->next; } if(layer) g_free(layer); reorder_buttons(plot); if(plot->nlayers > 0) activate_layer(GTK_PLOT_CANVAS(plot->real_canvas), plot); else{ plot->layers = NULL; plot->active_layer = NULL; } sg_layer_control_refresh(plot->name); } static void reorder_buttons(SGplot *plot) { GList *layers = NULL; SGlayer *layer; gint nlayers = 0; layers = plot->layers; while(layers) { layer = (SGlayer *)layers->data; gtk_fixed_move(GTK_FIXED(plot->real_canvas), layer->button, nlayers * 24, 0); gtk_widget_show(layer->button); sg_layer_button_set_label(layer, nlayers + 1); nlayers++; layers = layers->next; } } static void button_toggled(GtkWidget *widget, gpointer data) { SGlayer *layer; layer = SG_LAYER(data); sg_plot_set_active_layer(SG_PLOT(layer->parent), layer); } static gint button_clicked(GtkWidget* widget, GdkEventButton *event, gpointer data) { SGlayer *layer; SGplot *plot; GList *llink; GdkModifierType mods; gchar path[1000]; gdk_window_get_pointer(widget->window, NULL, NULL, &mods); if(!(mods & GDK_BUTTON1_MASK)) return FALSE; if(event->type != GDK_2BUTTON_PRESS) return FALSE; layer = SG_LAYER(data); plot = SG_PLOT(layer->parent); llink = g_list_find(plot->layers, layer); sprintf(path, "%s:%d:dataset", plot->name, g_list_position(plot->layers, llink)+1); sg_layer_control(path); gtk_grab_remove(widget); return FALSE; } void sg_plot_set_active_layer(SGplot *plot, SGlayer *layer) { SGlayer *child = NULL; GList *list; plot->active_layer = layer; list = plot->layers; while(list){ child = (SGlayer *)list->data; GTK_BUTTON(child->button)->button_down = FALSE; GTK_TOGGLE_BUTTON(child->button)->active = FALSE; gtk_widget_set_state(child->button, GTK_STATE_NORMAL); gtk_widget_draw(child->button, NULL); list = list->next; } if(!layer) return; gtk_plot_canvas_set_active_plot(GTK_PLOT_CANVAS(plot->real_canvas), GTK_PLOT(layer->real_plot)); GTK_BUTTON(layer->button)->button_down = TRUE; GTK_TOGGLE_BUTTON(layer->button)->active = TRUE; gtk_widget_set_state(layer->button, GTK_STATE_ACTIVE); gtk_widget_draw(child->button, NULL); } gint sg_plot_rename(SGplot *plot, gchar *name) { if(strcmp(plot->name, name) == 0) return FALSE; if(plot->name){ g_free(plot->name); plot->name = NULL; } plot->name = g_strdup(name); gtk_window_set_title(GTK_WINDOW(plot),name); if(gui_iconlist){ if(plot->icon->label){ g_free(plot->icon->label); plot->icon->label = NULL; } plot->icon->label = g_strdup(name); if(plot->icon->entry_label){ g_free(plot->icon->entry_label); plot->icon->entry_label = NULL; } plot->icon->entry_label = g_strdup(name); gtk_entry_set_text(GTK_ENTRY(plot->icon->entry), name); } return TRUE; } SGplot * sg_plot_get_from_canvas(GtkWidget *canvas) { GList *w; SGplot *plot = NULL; GtkWidget *data; w = plots; while(w){ plot = (SGplot *)w->data; data = plot->real_canvas; if(data && data == canvas) break; w = w->next; } if(w) return (SGplot *)w->data; return NULL; } void sg_plot_rescale(SGplot *plot, gdouble scale) { if(scale < .15) return; plot->scale = scale; gtk_plot_canvas_set_magnification(GTK_PLOT_CANVAS(plot->real_canvas), plot->scale); if(plot->hruler) update_ruler_expose_x(NULL, plot); if(plot->vruler) update_ruler_expose_y(NULL, plot); } void sg_plot_fit_page(SGplot *plot) { gdouble width, height; gdouble w_width, w_height; GtkBin *bin; gdouble scale,scalex,scaley; w_width=(gdouble)plot->sw->allocation.width; w_height=(gdouble)plot->sw->allocation.height; width = (gdouble)GTK_PLOT_CANVAS(plot->real_canvas)->pixmap_width; height = (gdouble)GTK_PLOT_CANVAS(plot->real_canvas)->pixmap_height; scalex=w_width/width; scaley=w_height/height; if(scalexscale); else sg_plot_rescale(plot, scaley*plot->scale); } void sg_plot_fit_page_h(SGplot *plot) { gdouble width; gdouble w_width; GtkBin *bin; gdouble scalex; w_width=(gdouble)plot->sw->allocation.width; width = (gdouble)GTK_PLOT_CANVAS(plot->real_canvas)->pixmap_width; scalex=w_width/width; sg_plot_rescale(plot, scalex*plot->scale); } void sg_plot_fit_page_v(SGplot *plot) { gdouble height; gdouble w_height; GtkBin *bin; gdouble scaley; w_height=(gdouble)plot->sw->allocation.height; height = (gdouble)GTK_PLOT_CANVAS(plot->real_canvas)->pixmap_height; scaley=w_height/height; sg_plot_rescale(plot, scaley*plot->scale); } void sg_plot_set_size(SGplot *plot, gint page_size, gint width, gint height, gint orientation) { gint real_width, real_height; if(orientation == GTK_PLOT_PORTRAIT){ real_width = width; real_height = height; }else{ real_width = height; real_height = width; } plot->page_size = page_size; plot->page_width = real_width; plot->page_height = real_height; plot->orientation = orientation; GTK_PLOT_CANVAS(plot->real_canvas)->pixmap_width = real_width; GTK_PLOT_CANVAS(plot->real_canvas)->pixmap_height = real_height; gtk_plot_canvas_set_size(GTK_PLOT_CANVAS(plot->real_canvas), real_width, real_height); if(plot->hruler) update_ruler_expose_x(NULL, plot); if(plot->vruler) update_ruler_expose_y(NULL, plot); } void sg_plot_clear(SGplot *plot) { GList *list; list = plot->layers; while(list){ SGlayer *layer; layer = SG_LAYER(list->data); sg_plot_remove_layer(plot, layer); list = plot->layers; } plot->layers = NULL; } static void sg_plot_destroy(GtkObject *object) { SGplot *plot; plot = SG_PLOT(object); sg_plot_clear(plot); gtk_widget_destroy(plot->real_canvas); g_free(plot->name); if (GTK_OBJECT_CLASS (parent_class)->destroy) (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); } /* Events */ static gint dialog_quit (GtkWidget *widget) { sg_dialog_kill(widget); gtk_main_quit(); return FALSE; } static gint click_on_item(GtkPlotCanvas *canvas, GdkEvent *event, GtkPlotCanvasChild *item, gpointer data) { GtkPlotCanvasChild *child = NULL; SGplot *plot; GList *llink; gchar path[255]; gboolean double_click; gboolean return_value = TRUE; double_click = (event->type == GDK_2BUTTON_PRESS); plot = SG_PLOT(data); activate_layer(canvas, plot); llink = g_list_find(plot->layers, plot->active_layer); if(plot->tool == SG_TOOL_ZOOM || plot->tool == SG_TOOL_LINE || plot->tool == SG_TOOL_LINE_ARROW || plot->tool == SG_TOOL_RECTANGLE || plot->tool == SG_TOOL_ELLIPSE) return TRUE; switch(item->type){ case GTK_PLOT_CANVAS_PLOT: sprintf(path, "%s:%d", plot->name, g_list_position(plot->layers, llink)+1); if(double_click && plot->tool == SG_TOOL_ARROW){ sg_layer_control(path); return_value = FALSE; } break; case GTK_PLOT_CANVAS_TEXT: if(double_click && plot->tool == SG_TOOL_ARROW){ GtkPlotCanvasChild *child; GtkPlotText *real_text; GtkWidget *dialog; child = (GtkPlotCanvasChild *)item->data; real_text = (GtkPlotText *)child->data; dialog = open_text_dialog(real_text); gtk_signal_connect (GTK_OBJECT(SG_TEXT_DIALOG(dialog)->apply_button), "clicked", GTK_SIGNAL_FUNC (apply_dialog_text), plot); gtk_main(); gtk_plot_canvas_paint(GTK_PLOT_CANVAS(canvas)); gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(canvas)); return_value = FALSE; } break; case GTK_PLOT_CANVAS_TITLE: sprintf(path, "%s:%d:axis:title", plot->name, g_list_position(plot->layers, llink)+1); if(double_click && plot->tool == SG_TOOL_ARROW){ sg_layer_control(path); return_value = FALSE; } break; case GTK_PLOT_CANVAS_DATA: sprintf(path, "%s:%d:dataset:style", plot->name, g_list_position(plot->layers, llink)+1); if(double_click && plot->tool == SG_TOOL_ARROW){ sg_layer_control(path); return_value = FALSE; } if(plot->tool == SG_TOOL_POINTER){ if(GTK_IS_PLOT_POLAR(canvas->active_plot)) g_snprintf(path, 200, " (R, Angle) = (%f,%f)", GTK_PLOT_CANVAS(canvas)->active_x, GTK_PLOT_CANVAS(canvas)->active_y); else g_snprintf(path, 200, " (X,Y) = (%f,%f)", GTK_PLOT_CANVAS(canvas)->active_x, GTK_PLOT_CANVAS(canvas)->active_y); gtk_label_set_text(GTK_LABEL(plot->label), path); return_value = TRUE; } if(plot->tool == SG_TOOL_MARKERS){ GtkPlotData *active_data; GtkPlotMarker *marker = NULL; GList *markers; gint nmarkers = 0; active_data = plot->active_layer->active_data; if(active_data){ markers = active_data->markers; while(markers){ nmarkers++; markers = markers->next; } } if(nmarkers == 2) sg_layer_remove_markers(plot->active_layer); if(nmarkers <= 2){ active_data = GTK_PLOT_CANVAS(canvas)->active_data; if(GTK_IS_PLOT_POLAR(canvas->active_plot)) g_snprintf(path, 200, " (R, Angle) = (%f,%f)", GTK_PLOT_CANVAS(canvas)->active_x, GTK_PLOT_CANVAS(canvas)->active_y); else g_snprintf(path, 200, " (X,Y) = (%f,%f)", GTK_PLOT_CANVAS(canvas)->active_x, GTK_PLOT_CANVAS(canvas)->active_y); gtk_label_set_text(GTK_LABEL(plot->label), path); gtk_plot_data_add_marker(active_data, GTK_PLOT_CANVAS(canvas)->active_point); gtk_plot_canvas_paint(GTK_PLOT_CANVAS(canvas)); gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(canvas)); plot->active_layer->active_data = active_data; } return_value = FALSE; } break; case GTK_PLOT_CANVAS_AXIS: sprintf(path, "%s:%d:axis", plot->name, g_list_position(plot->layers, llink)+1); if(double_click && plot->tool == SG_TOOL_ARROW){ sg_layer_control(path); return_value = FALSE; } break; case GTK_PLOT_CANVAS_LEGENDS: sprintf(path, "%s:%d:legends", plot->name, g_list_position(plot->layers, llink)+1); if(double_click && plot->tool == SG_TOOL_ARROW){ sg_layer_control(path); return_value = FALSE; } break; case GTK_PLOT_CANVAS_LINE: child = (GtkPlotCanvasChild *)item->data; if(double_click && plot->tool == SG_TOOL_ARROW){ sg_line_dialog(canvas, (GtkPlotCanvasLine *)child->data); return_value = FALSE; } break; case GTK_PLOT_CANVAS_RECTANGLE: child = (GtkPlotCanvasChild *)item->data; if(double_click && plot->tool == SG_TOOL_ARROW){ sg_rectangle_dialog(canvas, (GtkPlotCanvasRectangle *)child->data); return_value = FALSE; } break; case GTK_PLOT_CANVAS_ELLIPSE: child = (GtkPlotCanvasChild *)item->data; if(double_click && plot->tool == SG_TOOL_ARROW){ sg_ellipse_dialog(canvas, (GtkPlotCanvasEllipse *)child->data); return_value = FALSE; } break; case GTK_PLOT_CANVAS_MARKER: return_value = TRUE; break; } return return_value; } static gint edit_text(GtkWidget *widget, GdkEventButton *event, gpointer data) { GtkPlotCanvasChild *child; GdkModifierType mods; GtkPlotText text; SGplot *plot; GtkWidget *dialog; GtkPlotText *real_text; gint x, y; plot = SG_PLOT(data); if(plot->tool != SG_TOOL_TEXT) return FALSE; gdk_window_get_pointer(widget->window, &x, &y, &mods); if(!(mods & GDK_BUTTON1_MASK)) return FALSE; activate_layer(GTK_PLOT_CANVAS(widget), plot); text.text = g_strdup("Enter text here"); gdk_color_black(gdk_colormap_get_system(), &text.fg); gdk_color_white(gdk_colormap_get_system(), &text.bg); text.angle = 0; text.height = 16; text.transparent = TRUE; text.border = (GtkPlotBorderStyle)0; text.border_width = 0; text.border_space = 2; text.shadow_width = 3; text.justification = GTK_JUSTIFY_LEFT; text.font = g_strdup("Helvetica"); gtk_plot_canvas_get_position(GTK_PLOT_CANVAS(widget), x, y, &text.x, &text.y); child = gtk_plot_canvas_put_text(GTK_PLOT_CANVAS(plot->real_canvas), text.x, text.y, text.font, text.height, text.angle, &text.fg, &text.bg, text.transparent, text.justification, text.text); real_text = (GtkPlotText *)child->data; real_text->border_space = 2; real_text->shadow_width = 3; dialog = open_text_dialog(real_text); gtk_signal_connect (GTK_OBJECT(SG_TEXT_DIALOG(dialog)->apply_button), "clicked", GTK_SIGNAL_FUNC (apply_dialog_text), plot); gtk_main(); if(!real_text->text || strlen(real_text->text) == 0){ gtk_plot_canvas_remove_child(GTK_PLOT_CANVAS(plot->real_canvas), child); } gtk_plot_canvas_paint(GTK_PLOT_CANVAS(plot->real_canvas)); gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(plot->real_canvas)); return TRUE; } static gint apply_dialog_text(GtkWidget *widget, gpointer data) { SGplot *plot = SG_PLOT(data); gtk_plot_canvas_paint(GTK_PLOT_CANVAS(plot->real_canvas)); gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(plot->real_canvas)); } static GtkWidget * open_text_dialog(GtkPlotText *text) { GtkWidget *dialog; dialog = sg_text_dialog_new(text); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); gtk_widget_show(dialog); sg_dialog_new(dialog); gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dialog_quit), NULL); gtk_signal_connect (GTK_OBJECT(SG_TEXT_DIALOG(dialog)->ok_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT(dialog)); gtk_signal_connect_object (GTK_OBJECT(SG_TEXT_DIALOG(dialog)->cancel_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT(dialog)); return dialog; } static void activate_layer(GtkPlotCanvas *canvas, gpointer data) { GList *list; SGlayer *layer; SGplot *plot; if(!canvas) return; plot = SG_PLOT(data); list = plot->layers; while(list) { layer = (SGlayer *)list->data; if(GTK_PLOT(layer->real_plot) == canvas->active_plot){ sg_plot_set_active_layer(plot, layer); break; } list = list->next; } } static gboolean resize_item(GtkPlotCanvas *canvas, GtkPlotCanvasChild *item, gdouble new_width, gdouble new_height, gpointer data) { return TRUE; } static gboolean move_item(GtkPlotCanvas *canvas, GtkPlotCanvasChild *item, gdouble x, gdouble y, gpointer data) { switch(item->type){ case GTK_PLOT_CANVAS_PLOT: return TRUE; break; case GTK_PLOT_CANVAS_LEGENDS: return TRUE; break; case GTK_PLOT_CANVAS_TITLE: return TRUE; break; case GTK_PLOT_CANVAS_TEXT: return TRUE; break; default: return TRUE; break; } gtk_plot_canvas_paint(canvas); gtk_plot_canvas_refresh(canvas); return FALSE; } static gboolean key_press(GtkWidget *widget, GdkEventKey *key, gpointer data) { GtkPlotCanvas *canvas = GTK_PLOT_CANVAS(active_plot->real_canvas); GtkPlotCanvasChild *child = NULL; GtkPlotAxis *axis = NULL; SGplot *plot = SG_PLOT(data); gint i = 0; gint the_axis = -1; switch(key->keyval){ case GDK_Escape: if(canvas->action != GTK_PLOT_CANVAS_ACTION_INACTIVE) gtk_plot_canvas_cancel_action(canvas); break; case GDK_Delete: case GDK_KP_Delete: if(canvas->state == GTK_STATE_SELECTED) switch(canvas->active_item.type){ case GTK_PLOT_CANVAS_PLOT: gtk_plot_canvas_cancel_action(canvas); if(canvas->num_plots > 1 && sg_accept_dialog("Remove layer?", 1) == YES_CLICKED) sg_plot_remove_layer(plot, plot->active_layer); return TRUE; case GTK_PLOT_CANVAS_LEGENDS: gtk_plot_canvas_cancel_action(canvas); gtk_plot_hide_legends(GTK_PLOT(canvas->active_plot)); gtk_plot_canvas_paint(canvas); gtk_plot_canvas_refresh(canvas); return TRUE; break; case GTK_PLOT_CANVAS_TITLE: for(i = 0; i < 4; i++){ axis = gtk_plot_get_axis(GTK_PLOT(canvas->active_plot), (GtkPlotAxisPos)i); if(axis == canvas->active_item.data){ the_axis = i; break; } } gtk_plot_canvas_cancel_action(canvas); if(the_axis != -1) gtk_plot_axis_hide_title(GTK_PLOT(canvas->active_plot), (GtkPlotAxisPos)the_axis); gtk_plot_canvas_paint(canvas); gtk_plot_canvas_refresh(canvas); return TRUE; case GTK_PLOT_CANVAS_AXIS: return TRUE; default: child = (GtkPlotCanvasChild *)canvas->active_item.data; gtk_plot_canvas_cancel_action(canvas); gtk_plot_canvas_remove_child(canvas, child); gtk_plot_canvas_paint(canvas); gtk_plot_canvas_refresh(canvas); return TRUE; } break; default: break; } return FALSE; } static void update_ruler_expose_x(GtkWidget *scroll, gpointer data) { GtkAdjustment *adj; SGplot *plot; gdouble start, end, fac, fac2,p_size; gint width,s_width,height; GtkAllocation allocation; if (!data) return; plot=(SGplot *)data; allocation = plot->real_canvas->allocation; /* width of vscrollbar*/ s_width=plot->sw->allocation.width; p_size = GTK_PLOT_CANVAS(plot->real_canvas)->width * GTK_PLOT_CANVAS(plot->real_canvas)->magnification; adj=gtk_viewport_get_hadjustment (GTK_VIEWPORT(plot->sw)); /* Conversion factor from pixels to real physical unit */ fac=plot->page_width/unit_pt[plot->page_units]; if (p_sizecanvas_box, &allocation); } else { start=adj->value/adj->upper*fac; end=(adj->value+adj->page_size)/adj->upper*fac; allocation.x = 0; gtk_widget_size_allocate(plot->canvas_box, &allocation); } gtk_ruler_set_range(GTK_RULER(plot->hruler), start, end, start, end); fac = (gdouble)GTK_PLOT_CANVAS(plot->real_canvas)->pixmap_width / (gdouble)plot->page_width * unit_pt[plot->page_units]; switch(plot->page_units){ case SG_UNIT_PT: case SG_UNIT_PIXEL: GTK_PLOT_CANVAS(plot->real_canvas)->grid_step = 20. * fac; break; case SG_UNIT_MM: GTK_PLOT_CANVAS(plot->real_canvas)->grid_step = 10. * fac; break; case SG_UNIT_CM: GTK_PLOT_CANVAS(plot->real_canvas)->grid_step = 1. * fac; break; case SG_UNIT_IN: GTK_PLOT_CANVAS(plot->real_canvas)->grid_step = .2 * fac; break; } } static void update_ruler_expose_y(GtkWidget *scroll, gpointer data) { GtkAdjustment *adj; SGplot *plot; gdouble start, end, fac, p_size; gint height,s_height; GtkAllocation allocation; if (!data) return; plot=(SGplot *)data; allocation = plot->real_canvas->allocation; /* height of hscrollbar*/ s_height=plot->sw->allocation.height; p_size = GTK_PLOT_CANVAS(plot->real_canvas)->height * GTK_PLOT_CANVAS(plot->real_canvas)->magnification; adj=gtk_viewport_get_vadjustment (GTK_VIEWPORT(plot->sw)); /* Conversion factor from pixels to real physical unit */ fac=plot->page_height/unit_pt[plot->page_units]; if (p_sizecanvas_box, &allocation); } else { start=adj->value/adj->upper*fac; end=(adj->value+adj->page_size)/adj->upper*fac; allocation.y = 0; gtk_widget_size_allocate(plot->canvas_box, &allocation); } gtk_ruler_set_range(GTK_RULER(plot->vruler), start, end, start, end); } static void sg_plot_motion(GtkWidget *widget, GdkEventMotion *event, gpointer data) { SGplot *plot; GtkPlotCanvas *canvas; plot = SG_PLOT(data); canvas = GTK_PLOT_CANVAS(widget); if(!plot->layers || !canvas->active_plot) return; if(!GTK_IS_PLOT3D(canvas->active_plot) && plot->tool == SG_TOOL_ARROW){ gint x, y; gdouble px, py; gchar text[200]; gtk_widget_get_pointer(widget, &x, &y); gtk_plot_get_point(GTK_PLOT(canvas->active_plot), x, y, &px, &py); if(GTK_IS_PLOT_POLAR(canvas->active_plot)) g_snprintf(text, 200, " (R,Angle) = (%f,%f)", px, py); else g_snprintf(text, 200, " (X,Y) = (%f,%f)", px, py); gtk_label_set(GTK_LABEL(plot->label), text); } gtk_widget_event(plot->hruler, (GdkEvent *)event); gtk_widget_event(plot->vruler, (GdkEvent *)event); } static void canvas_changed (GtkPlotCanvas *canvas, gpointer data) { sg_project_changed(TRUE); } void sg_plot_put_pixmap(SGplot *plot, GdkPixmap *pixmap) { GtkPlotCanvas *canvas; GtkPlotCanvasChild *child; gint width, height; canvas = GTK_PLOT_CANVAS(plot->real_canvas); gdk_window_get_size(pixmap, &width, &height); child = gtk_plot_canvas_put_pixmap(canvas, pixmap, 0., 0.); gtk_plot_canvas_refresh(canvas); } void sg_plot_antialias(SGplot *plot, gboolean do_art) { if(do_art && !plot->antialias){ plot->antialias = TRUE; #ifdef WITH_LIBART gtk_plot_canvas_set_pc(GTK_PLOT_CANVAS(plot->real_canvas), GTK_PLOT_PC(gtk_plot_art_new(NULL))); #endif /* WITH_LIBART */ } if(!do_art && plot->antialias){ plot->antialias = FALSE; gtk_plot_canvas_set_pc(GTK_PLOT_CANVAS(plot->real_canvas), GTK_PLOT_PC(gtk_plot_gdk_new(NULL))); } } void sg_plot_refresh_datasets(SGplot *plot) { GList *aux_layers; aux_layers = plot->layers; while(aux_layers){ SGlayer *layer; layer = (SGlayer *)aux_layers->data; sg_layer_refresh_datasets(layer); aux_layers = aux_layers->next; } }