/* SciGraphica - Scientific graphics and data manipulation
* Copyright (C) 2001 Adrian E. Feiguin <feiguin@ifir.edu.ar>
*
* 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 <stdio.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <gtkextra/gtkextra.h>
#include <gdk/gdkkeysyms.h>
#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(scalex<scaley) sg_plot_rescale(plot, scalex*plot->scale);
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_size<s_width)
{
start=-((s_width-p_size)/2)/p_size*fac;
end=((s_width-p_size)/2+p_size)/p_size*fac;
allocation.x = (gint16)( (s_width - p_size)/2 );
gtk_widget_size_allocate(plot->canvas_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_size<s_height)
{
start=-((s_height-p_size)/2)/p_size*fac;
end=((s_height-p_size)/2+p_size)/p_size*fac;
allocation.y = (gint16)( (s_height - p_size)/2 );
gtk_widget_size_allocate(plot->canvas_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;
}
}
syntax highlighted by Code2HTML, v. 0.9.1