/* g3data : A program for grabbing data from scanned graphs Copyright (C) 2000 Jonas Frantz This file is part of g3data. g3data 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. g3data 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 Authors email : jonas.frantz@welho.com */ #include /* Include gtk library */ #include /* Include stdio library */ #include #include #include /* Include stdlib library */ #include /* Include string library */ #include /* Include math library */ #include #include #include "main.h" /* Include predined variables */ #include "strings.h" /* Include strings */ #ifdef NOSPACING #define SECT_SEP 0 #define GROUP_SEP 0 #define ELEM_SEP 0 #define FRAME_INDENT 0 #define WINDOW_BORDER 0 #else #define SECT_SEP 12 #define GROUP_SEP 12 #define ELEM_SEP 6 #define FRAME_INDENT 18 #define WINDOW_BORDER 12 #endif /* Declaration of gtk variables */ GtkWidget *window; /* Window */ GtkWidget *drawing_area[MAXNUMTABS], *zoom_area[MAXNUMTABS]; /* Drawing areas */ GtkWidget *xyentry[MAXNUMTABS][4]; GtkWidget *exportbutton[MAXNUMTABS], *remlastbutton[MAXNUMTABS]; /* Various buttons */ GtkWidget *setxybutton[MAXNUMTABS][4]; GtkWidget *remallbutton[MAXNUMTABS]; /* Even more various buttons */ GtkWidget *xc_entry[MAXNUMTABS],*yc_entry[MAXNUMTABS]; GtkWidget *file_entry[MAXNUMTABS], *nump_entry[MAXNUMTABS]; GtkWidget *xerr_entry[MAXNUMTABS],*yerr_entry[MAXNUMTABS]; /* Coordinate and filename entries */ GtkWidget *logbox[MAXNUMTABS] = {NULL}, *zoomareabox[MAXNUMTABS] = {NULL}, *oppropbox[MAXNUMTABS] = {NULL}; GtkWidget *pm_label, *pm_label2, *file_label; GtkWidget *ViewPort; GdkColor *colors; /* Pointer to colors */ GdkPixbuf *gpbimage[MAXNUMTABS]; GtkWidget *mainnotebook; GtkActionGroup *tab_action_group; GtkTooltips *tooltip; /* Declaration of global variables */ gint axiscoords[MAXNUMTABS][4][2]; /* X,Y coordinates of axispoints */ gint **points[MAXNUMTABS]; /* Indexes of graphpoints and their coordinates */ gint *lastpoints[MAXNUMTABS]; /* Indexes of last points put out */ gint numpoints[MAXNUMTABS]; gint numlastpoints[MAXNUMTABS]; /* Number of points on graph and last put out */ gint remthis = 0, ordering[MAXNUMTABS]; /* Various control variables */ gint XSize[MAXNUMTABS], YSize[MAXNUMTABS]; gint file_name_length[MAXNUMTABS]; gint MaxPoints[MAXNUMTABS] = {MAXPOINTS}; gint Action[MAXNUMTABS]; gint ViewedTabNum = -1; /* The currently viewed tab */ gint NoteBookNumPages = 0; gdouble realcoords[MAXNUMTABS][4]; /* X,Y coords on graph */ gboolean UseErrors[MAXNUMTABS], WinFullScreen; gboolean setxypressed[MAXNUMTABS][4]; gboolean bpressed[MAXNUMTABS][4]; /* What axispoints have been set out ? */ gboolean valueset[MAXNUMTABS][4]; gboolean logxy[MAXNUMTABS][2] = {{FALSE,FALSE}}; gboolean MovePointMode = FALSE; gboolean HideLog = FALSE, HideZoomArea = FALSE, HideOpProp = FALSE; gchar *file_name[MAXNUMTABS]; /* Pointer to filename */ gchar FileNames[MAXNUMTABS][256]; FILE *FP; /* File pointer */ GtkWidget *drawing_area_alignment; /* Declaration of extern functions */ extern void SetNumPointsEntry(GtkWidget *np_entry, gint np); extern gint min(gint x, gint y); extern void DrawMarker(GtkWidget *da, gint x, gint y, gint type, GdkColor *color); extern struct PointValue CalcPointValue(gint Xpos, gint Ypos, gint TabNum); extern void print_results(GtkWidget *widget, gpointer func_data); extern gboolean setcolors(GdkColor **color); /* Explicit declaration of functions */ void remove_last(GtkWidget *widget, gpointer data); void SetOrdering(GtkWidget *widget, gpointer func_data); void SetAction(GtkWidget *widget, gpointer func_data); void UseErrCB(GtkWidget *widget, gpointer func_data); void read_file_entry(GtkWidget *entry, gpointer func_data); // GCallback full_screen_action_callback(GtkWidget *widget, gpointer func_dat); /****************************************************************/ /* This function closes the window when the application is */ /* killed. */ /****************************************************************/ gint close_application(GtkWidget *widget, GdkEvent *event, gpointer data) { gtk_main_quit(); /* Quit gtk */ return FALSE; } /****************************************************************/ /* This function sets the sensitivity of the buttons depending */ /* the control variables. */ /****************************************************************/ void SetButtonSensitivity(int TabNum) { char ttbuf[256]; if (Action[TabNum] == PRINT2FILE) { snprintf(ttbuf, sizeof(ttbuf), printfilett, gtk_entry_get_text(GTK_ENTRY (file_entry[TabNum]))); gtk_tooltips_set_tip (tooltip,exportbutton[TabNum],ttbuf,ttbuf); gtk_widget_set_sensitive(file_entry[TabNum], TRUE); if (valueset[TabNum][0] && valueset[TabNum][1] && valueset[TabNum][2] && valueset[TabNum][3] && bpressed[TabNum][0] && bpressed[TabNum][1] && bpressed[TabNum][2] && bpressed[TabNum][3] && numpoints[TabNum] > 0 && file_name_length[TabNum] > 0) gtk_widget_set_sensitive(exportbutton[TabNum], TRUE); else gtk_widget_set_sensitive(exportbutton[TabNum], FALSE); } else { gtk_tooltips_set_tip (tooltip,exportbutton[TabNum],printrestt,printrestt); gtk_widget_set_sensitive(file_entry[TabNum], FALSE); if (valueset[TabNum][0] && valueset[TabNum][1] && valueset[TabNum][2] && valueset[TabNum][3] && bpressed[TabNum][0] && bpressed[TabNum][1] && bpressed[TabNum][2] && bpressed[TabNum][3] && numpoints[TabNum] > 0) gtk_widget_set_sensitive(exportbutton[TabNum], TRUE); else gtk_widget_set_sensitive(exportbutton[TabNum], FALSE); } if (numlastpoints[TabNum]==0) { gtk_widget_set_sensitive(remlastbutton[TabNum],FALSE); gtk_widget_set_sensitive(remallbutton[TabNum],FALSE); } else { gtk_widget_set_sensitive(remlastbutton[TabNum],TRUE); gtk_widget_set_sensitive(remallbutton[TabNum],TRUE); } } /****************************************************************/ /* When a button is pressed inside the drawing area this */ /* function is called, it handles axispoints and graphpoints */ /* and paints a square in that position. */ /****************************************************************/ gint button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { GdkModifierType state; gint x, y, i, j, TabNum; TabNum = GPOINTER_TO_INT(data); gdk_window_get_pointer (event->window, &x, &y, &state); /* Get pointer state */ if (event->button == 1) { /* If button 1 (leftmost) is pressed */ if (MovePointMode) { for (i=0;i MaxPoints[TabNum]-1) { i = MaxPoints[TabNum]; MaxPoints[TabNum] += MAXPOINTS; lastpoints[TabNum] = realloc(lastpoints[TabNum],sizeof(gint) * (MaxPoints[TabNum]+4)); if (lastpoints[TabNum]==NULL) { printf("Error reallocating memory for lastpoints. Exiting.\n"); exit(-1); } points[TabNum] = realloc(points[TabNum],sizeof(gint *) * MaxPoints[TabNum]); if (points[TabNum]==NULL) { printf("Error reallocating memory for points. Exiting.\n"); exit(-1); } for (;ibutton == 2) { /* Is the middle button pressed ? */ for (i=0;i<2;i++) if (!bpressed[TabNum][i]) { axiscoords[TabNum][i][0]=x; axiscoords[TabNum][i][1]=y; for (j=0;j<4;j++) if (i!=j) gtk_widget_set_sensitive(setxybutton[TabNum][j],TRUE); gtk_widget_set_sensitive(xyentry[TabNum][i],TRUE); gtk_editable_set_editable((GtkEditable *) xyentry[TabNum][i],TRUE); gtk_widget_grab_focus(xyentry[TabNum][i]); setxypressed[TabNum][i]=FALSE; bpressed[TabNum][i]=TRUE; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(setxybutton[TabNum][i]),FALSE); lastpoints[TabNum][numlastpoints[TabNum]]=-(i+1); numlastpoints[TabNum]++; DrawMarker(drawing_area[TabNum], x, y, 0, colors); break; } } else if (event->button == 3) { /* Is the right button pressed ? */ for (i=2;i<4;i++) if (!bpressed[TabNum][i]) { axiscoords[TabNum][i][0]=x; axiscoords[TabNum][i][1]=y; for (j=0;j<4;j++) if (i!=j) gtk_widget_set_sensitive(setxybutton[TabNum][j],TRUE); gtk_widget_set_sensitive(xyentry[TabNum][i],TRUE); gtk_editable_set_editable((GtkEditable *) xyentry[TabNum][i],TRUE); gtk_widget_grab_focus(xyentry[TabNum][i]); setxypressed[TabNum][i]=FALSE; bpressed[TabNum][i]=TRUE; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(setxybutton[TabNum][i]),FALSE); lastpoints[TabNum][numlastpoints[TabNum]]=-(i+1); numlastpoints[TabNum]++; DrawMarker(drawing_area[TabNum], x, y, 1, colors); break; } } SetButtonSensitivity(TabNum); return TRUE; } /****************************************************************/ /* This function is called when a button is released on the */ /* drawing area, currently this function does not perform any */ /* task. */ /****************************************************************/ gint button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { if (event->button == 1) { } else if (event->button == 2) { } else if (event->button == 3) { } return TRUE; } /****************************************************************/ /* This function is called when movement is detected in the */ /* drawing area, it captures the coordinates and zoom in om the */ /* position and plots it on the zoom area. */ /****************************************************************/ gint motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) { gint x, y, TabNum; gchar buf[32]; GdkModifierType state; static gboolean FirstTime = TRUE; static GdkGC *mngc; /* Graphic context */ static GdkPixbuf *gpbzoomimage; struct PointValue CalcVal; TabNum = GPOINTER_TO_INT(data); gdk_window_get_pointer (event->window, &x, &y, &state); /* Grab mousepointers coordinates */ /* on drawing area. */ mngc = gdk_gc_new (zoom_area[TabNum]->window); /* Create graphics context */ if (FirstTime) { gpbzoomimage = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, ZOOMPIXSIZE, ZOOMPIXSIZE); FirstTime = FALSE; } if (x>=0 && y>=0 && xwindow,zoom_area[TabNum]->style->white_gc,gpbzoomimage, 0,0,0,0,ZOOMPIXSIZE,ZOOMPIXSIZE,GDK_RGB_DITHER_NONE,0,0); DrawMarker(zoom_area[TabNum], ZOOMPIXSIZE/2, ZOOMPIXSIZE/2, 2, colors); /* Then draw the square in the middle of the zoom area */ if (valueset[TabNum][0] && valueset[TabNum][1] && valueset[TabNum][2] && valueset[TabNum][3]) { CalcVal = CalcPointValue(x,y,TabNum); sprintf(buf,"%.12g",CalcVal.Xv); gtk_entry_set_text(GTK_ENTRY(xc_entry[TabNum]),buf); /* Put out coordinates in entries */ sprintf(buf,"%.12g",CalcVal.Yv); gtk_entry_set_text(GTK_ENTRY(yc_entry[TabNum]),buf); sprintf(buf,"%.12g",CalcVal.Xerr); gtk_entry_set_text(GTK_ENTRY(xerr_entry[TabNum]),buf); /* Put out coordinates in entries */ sprintf(buf,"%.12g",CalcVal.Yerr); gtk_entry_set_text(GTK_ENTRY(yerr_entry[TabNum]),buf); } else { gtk_entry_set_text(GTK_ENTRY(xc_entry[TabNum]),""); /* Else clear entries */ gtk_entry_set_text(GTK_ENTRY(yc_entry[TabNum]),""); gtk_entry_set_text(GTK_ENTRY(xerr_entry[TabNum]),""); gtk_entry_set_text(GTK_ENTRY(yerr_entry[TabNum]),""); } } else { gtk_entry_set_text(GTK_ENTRY(xc_entry[TabNum]),""); /* Else clear entries */ gtk_entry_set_text(GTK_ENTRY(yc_entry[TabNum]),""); gtk_entry_set_text(GTK_ENTRY(xerr_entry[TabNum]),""); gtk_entry_set_text(GTK_ENTRY(yerr_entry[TabNum]),""); } g_object_unref(mngc); /* Kill graphics context */ return TRUE; } /****************************************************************/ /* This function is called when the drawing area is exposed, it */ /* simply redraws the pixmap on it. */ /****************************************************************/ static gint expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { gint i, TabNum; TabNum = GPOINTER_TO_INT(data); gdk_draw_pixbuf(widget->window,widget->style->white_gc,gpbimage[TabNum], event->area.x, event->area.y, event->area.x, event->area.y, min(event->area.width,XSize[TabNum]), min(event->area.height,YSize[TabNum]), GDK_RGB_DITHER_NONE,0,0); for (i=0;i<4;i++) if (bpressed[TabNum][i]) DrawMarker(drawing_area[TabNum], axiscoords[TabNum][i][0], axiscoords[TabNum][i][1], i/2, colors); for (i=0;iactive) { /* Is the button pressed on ? */ setxypressed[ViewedTabNum][index]=TRUE; /* The button is pressed down */ for (i=0;i<4;i++) { if (index != i) gtk_widget_set_sensitive(setxybutton[ViewedTabNum][i],FALSE); } if (bpressed[index]) { /* If the x axis point is already set */ remthis=-(index+1); /* remove the square */ remove_last(widget,NULL); } bpressed[ViewedTabNum][index]=FALSE; /* Set x axis point 1 to unset */ } else { /* If button is trying to get unpressed */ if (setxypressed[ViewedTabNum][index]) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),TRUE); /* Set button down */ } } /****************************************************************/ /* Set type of ordering at output of data. */ /****************************************************************/ void SetOrdering(GtkWidget *widget, gpointer func_data) { ordering[ViewedTabNum] = GPOINTER_TO_INT (func_data); /* Set ordering control variable */ } /****************************************************************/ /****************************************************************/ void SetAction(GtkWidget *widget, gpointer func_data) { Action[ViewedTabNum] = GPOINTER_TO_INT (func_data); SetButtonSensitivity(ViewedTabNum); } /****************************************************************/ /* Set whether to use error evaluation and printing or not. */ /****************************************************************/ void UseErrCB(GtkWidget *widget, gpointer func_data) { UseErrors[ViewedTabNum] = (GTK_TOGGLE_BUTTON (widget)->active); } /****************************************************************/ /* When the value of the entry of any axis point is changed, */ /* this function gets called. */ /****************************************************************/ void read_xy_entry(GtkWidget *entry, gpointer func_data) { gchar *xy_text; gint index; index = GPOINTER_TO_INT (func_data); xy_text = (gchar *) gtk_entry_get_text(GTK_ENTRY (entry)); sscanf(xy_text,"%lf",&realcoords[ViewedTabNum][index]); /* Convert string to double value and */ /* store in realcoords[0]. */ if (logxy[ViewedTabNum][index/2] && realcoords[ViewedTabNum][index] > 0) valueset[ViewedTabNum][index]=TRUE; else if (logxy[ViewedTabNum][index/2]) valueset[ViewedTabNum][index]=FALSE; else valueset[ViewedTabNum][index]= TRUE; SetButtonSensitivity(ViewedTabNum); } /****************************************************************/ /* If all the axispoints has been put out, values for these */ /* have been assigned and at least one point has been set on */ /* the graph activate the write to file button. */ /****************************************************************/ void read_file_entry(GtkWidget *entry, gpointer func_data) { gint TabNum; TabNum = GPOINTER_TO_INT (func_data); file_name[TabNum] = (gchar *) gtk_entry_get_text (GTK_ENTRY (entry)); file_name_length[TabNum] = strlen(file_name[TabNum]); /* Get length of string */ if (bpressed[TabNum][0] && bpressed[TabNum][1] && bpressed[TabNum][2] && bpressed[TabNum][3] && valueset[TabNum][0] && valueset[TabNum][1] && valueset[TabNum][2] && valueset[TabNum][3] && numpoints[TabNum] > 0 && file_name_length[TabNum] > 0) { gtk_widget_set_sensitive(exportbutton[TabNum],TRUE); } else gtk_widget_set_sensitive(exportbutton[TabNum],FALSE); } /****************************************************************/ /* If the "X/Y axis is logarithmic" check button is toggled */ /* this function gets called. It sets the logx variable to its */ /* correct value corresponding to the buttons state. */ /****************************************************************/ void islogxy(GtkWidget *widget, gpointer func_data) { gint index; index = GPOINTER_TO_INT (func_data); logxy[ViewedTabNum][index] = (GTK_TOGGLE_BUTTON (widget)->active); /* If checkbutton is pressed down */ /* logxy = TRUE else FALSE. */ if (logxy[ViewedTabNum][index]) { if (realcoords[ViewedTabNum][index*2] <= 0) { /* If a negative value has been insert */ valueset[ViewedTabNum][index*2]=FALSE; gtk_entry_set_text(GTK_ENTRY(xyentry[ViewedTabNum][index*2]),""); /* Zero it */ } if (realcoords[ViewedTabNum][index*2+1] <= 0) { /* If a negative value has been insert */ valueset[ViewedTabNum][index*2+1]=FALSE; gtk_entry_set_text(GTK_ENTRY(xyentry[ViewedTabNum][index*2+1]),""); /* Zero it */ } } } /****************************************************************/ /* This function removes the last inserted point or the point */ /* indexed by remthis (<0). */ /****************************************************************/ void remove_last(GtkWidget *widget, gpointer data) { gint i, j, TabNum; TabNum = GPOINTER_TO_INT(data); /* First redraw the drawing_area with the original image, to clean it. */ gdk_draw_pixbuf(drawing_area[TabNum]->window,widget->style->white_gc,gpbimage[TabNum], 0, 0, 0, 0, XSize[TabNum], YSize[TabNum],GDK_RGB_DITHER_NONE,0,0); if (numlastpoints[TabNum]>0) { /* If points been put out, remove last one */ if (remthis==0) { /* If remthis is 0, ignore it. */ numlastpoints[TabNum]--; for (i=0;i<4;i++) if (lastpoints[TabNum][numlastpoints[TabNum]]==-(i+1)) { /* If point to be removed is axispoint 1-4 */ bpressed[TabNum][i]=FALSE; /* Mark it unpressed. */ gtk_widget_set_sensitive(xyentry[TabNum][i],FALSE); /* Inactivate entry for point. */ break; } if (i==4) numpoints[TabNum]--; /* If its none of the X/Y markers then */ SetNumPointsEntry(nump_entry[TabNum], numpoints[TabNum]); /* its an ordinary marker, remove it. */ } if (numlastpoints[TabNum]>0) { /* If more than 0 points left, start to redraw */ for (i=0;i=0) DrawMarker(drawing_area[TabNum], points[TabNum][lastpoints[TabNum][i]][0], points[TabNum][lastpoints[TabNum][i]][1], 2, colors); } } } SetButtonSensitivity(TabNum); remthis = 0; /* Reset remthis variable */ } /****************************************************************/ /* This function sets the proper variables and then calls */ /* remove_last, to remove all points except the axis points. */ /****************************************************************/ void remove_all(GtkWidget *widget, gpointer data) { gint i, j, index, TabNum; TabNum = GPOINTER_TO_INT(data); if (numlastpoints[TabNum]>0 && numpoints[TabNum]>0) { index = 0; for (i=0;i0 && numpoints[TabNum]==0) { numlastpoints[TabNum] = 0; /* Nullify amount of points */ for (i=0;i<4;i++) { valueset[TabNum][i] = FALSE; bpressed[TabNum][i] = FALSE; gtk_entry_set_text((GtkEntry *) xyentry[TabNum][i], ""); } remove_last(widget,data); /* Call remove_last() */ } SetButtonSensitivity(TabNum); } /****************************************************************/ /* This function handles all of the keypresses done within the */ /* main window and handles the appropriate measures. */ /****************************************************************/ gint key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer pointer) { GtkAdjustment *adjustment; gdouble adj_val; GdkCursor *cursor; if (event->keyval==GDK_Left) { adjustment = gtk_viewport_get_hadjustment((GtkViewport *) ViewPort); adj_val = gtk_adjustment_get_value(adjustment); adj_val -= adjustment->page_size/10.0; if (adj_val < adjustment->lower) adj_val = adjustment->lower; gtk_adjustment_set_value(adjustment, adj_val); gtk_viewport_set_hadjustment((GtkViewport *) ViewPort, adjustment); } else if (event->keyval==GDK_Right) { adjustment = gtk_viewport_get_hadjustment((GtkViewport *) ViewPort); adj_val = gtk_adjustment_get_value(adjustment); adj_val += adjustment->page_size/10.0; if (adj_val > (adjustment->upper-adjustment->page_size)) adj_val = (adjustment->upper-adjustment->page_size); gtk_adjustment_set_value(adjustment, adj_val); gtk_viewport_set_hadjustment((GtkViewport *) ViewPort, adjustment); } else if (event->keyval==GDK_Up) { adjustment = gtk_viewport_get_vadjustment((GtkViewport *) ViewPort); adj_val = gtk_adjustment_get_value(adjustment); adj_val -= adjustment->page_size/10.0; if (adj_val < adjustment->lower) adj_val = adjustment->lower; gtk_adjustment_set_value(adjustment, adj_val); gtk_viewport_set_vadjustment((GtkViewport *) ViewPort, adjustment); } else if (event->keyval==GDK_Down) { adjustment = gtk_viewport_get_vadjustment((GtkViewport *) ViewPort); adj_val = gtk_adjustment_get_value(adjustment); adj_val += adjustment->page_size/10.0; if (adj_val > (adjustment->upper-adjustment->page_size)) adj_val = (adjustment->upper-adjustment->page_size); gtk_adjustment_set_value(adjustment, adj_val); gtk_viewport_set_vadjustment((GtkViewport *) ViewPort, adjustment); } else if (event->keyval==GDK_Control_L) { if (ViewedTabNum != -1) { cursor = gdk_cursor_new (GDK_CIRCLE); gdk_window_set_cursor (drawing_area[ViewedTabNum]->window, cursor); MovePointMode = TRUE; } } return 0; } /****************************************************************/ /****************************************************************/ gint key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer pointer) { GdkCursor *cursor; if (event->keyval==GDK_Control_L) { if (ViewedTabNum != -1) { cursor = gdk_cursor_new (GDK_CROSSHAIR); gdk_window_set_cursor (drawing_area[ViewedTabNum]->window, cursor); MovePointMode = FALSE; } } return 0; } /****************************************************************/ /* This function loads the image, and inserts it into the tab */ /* and sets up all of the different signals associated with it. */ /****************************************************************/ gint InsertImage(char *filename, gdouble Scale, gdouble maxX, gdouble maxY, gint TabNum) { gint newX, newY; gdouble mScale; GdkPixbuf *loadgpbimage; GdkCursor *cursor; GtkWidget *dialog; gchar buf[256]; /* Text buffer for window title */ loadgpbimage = gdk_pixbuf_new_from_file(filename,NULL); /* Load image */ if (loadgpbimage==NULL) { /* If unable to load image */ dialog = gtk_message_dialog_new (GTK_WINDOW(window), /* Notify user of the error */ GTK_DIALOG_DESTROY_WITH_PARENT, /* with a dialog */ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Error loading file '%s'", filename); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return -1; /* exit */ } XSize[TabNum] = gdk_pixbuf_get_width(loadgpbimage); /* Get image width */ YSize[TabNum] = gdk_pixbuf_get_height(loadgpbimage); /* Get image height */ sprintf(buf, Window_Title, filename); /* Print window title in buffer */ gtk_window_set_title (GTK_WINDOW (window), buf); /* Set window title */ mScale = -1; if (maxX != -1 && maxY != -1) { if (XSize[TabNum] > maxX) { mScale = (double) maxX/XSize[TabNum]; } if (YSize[TabNum] > maxY && (double) maxY/YSize[TabNum] < mScale) mScale = (double) maxY/YSize[TabNum]; } if (Scale == -1 && mScale != -1) Scale = mScale; if (Scale != -1) { newX = XSize[TabNum]*Scale; newY = YSize[TabNum]*Scale; gpbimage[TabNum] = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, newX, newY); gdk_pixbuf_composite(loadgpbimage, gpbimage[TabNum], 0, 0, newX, newY, 0, 0, Scale, Scale, GDK_INTERP_BILINEAR, 255); g_object_unref(loadgpbimage); } else gpbimage[TabNum] = loadgpbimage; XSize[TabNum] = gdk_pixbuf_get_width(gpbimage[TabNum]); /* Get image width */ YSize[TabNum] = gdk_pixbuf_get_height(gpbimage[TabNum]); /* Get image height */ drawing_area[TabNum] = gtk_drawing_area_new (); /* Create new drawing area */ gtk_widget_set_size_request (drawing_area[TabNum], XSize[TabNum], YSize[TabNum]); g_signal_connect (G_OBJECT (drawing_area[TabNum]), "expose_event", /* Connect drawing area to */ G_CALLBACK (expose_event), GINT_TO_POINTER (TabNum)); /* expose_event. */ g_signal_connect (G_OBJECT (drawing_area[TabNum]), "configure_event", /* Connect drawing area to */ G_CALLBACK (configure_event), GINT_TO_POINTER (TabNum)); /* configure_event. */ g_signal_connect (G_OBJECT (drawing_area[TabNum]), "button_press_event", /* Connect drawing area to */ G_CALLBACK (button_press_event), GINT_TO_POINTER (TabNum)); /* button_press_event. */ g_signal_connect (G_OBJECT (drawing_area[TabNum]), "button_release_event", /* Connect drawing area to */ G_CALLBACK (button_release_event), GINT_TO_POINTER (TabNum)); /* button_release_event */ g_signal_connect (G_OBJECT (drawing_area[TabNum]), "motion_notify_event", /* Connect drawing area to */ G_CALLBACK (motion_notify_event), GINT_TO_POINTER (TabNum)); /* motion_notify_event. */ gtk_widget_set_events (drawing_area[TabNum], GDK_EXPOSURE_MASK | /* Set the events active */ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); gtk_container_add((GtkContainer *) drawing_area_alignment, drawing_area[TabNum]); gtk_widget_show(drawing_area[TabNum]); cursor = gdk_cursor_new (GDK_CROSSHAIR); gdk_window_set_cursor (drawing_area[TabNum]->window, cursor); return 0; } /****************************************************************/ /* This callback is called when the file - exit menuoptioned is */ /* selected. */ /****************************************************************/ GCallback menu_file_exit(void) { close_application(NULL,NULL,NULL); return NULL; } /****************************************************************/ /* This callback sets up the thumbnail in the Fileopen dialog. */ /****************************************************************/ static void update_preview_cb (GtkFileChooser *file_chooser, gpointer data) { GtkWidget *preview; char *filename; GdkPixbuf *pixbuf; gboolean have_preview; preview = GTK_WIDGET (data); filename = gtk_file_chooser_get_preview_filename (file_chooser); pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL); have_preview = (pixbuf != NULL); g_free (filename); gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf); if (pixbuf) gdk_pixbuf_unref (pixbuf); gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview); } /****************************************************************/ /* This function sets up a new tab, sets up all of the widgets */ /* needed. */ /****************************************************************/ gint SetupNewTab(char *filename, gdouble Scale, gdouble maxX, gdouble maxY, gboolean UsePreSetCoords) { GtkWidget *table; /* GTK table/box variables for packing */ GtkWidget *tophbox, *bottomhbox; GtkWidget *trvbox, *tlvbox, *brvbox, *blvbox, *subvbox; GtkWidget *xy_label[4]; /* Labels for texts in window */ GtkWidget *logcheckb[2]; /* Logarithmic checkbuttons */ GtkWidget *nump_label, *ScrollWindow; /* Various widgets */ GtkWidget *APlabel, *PIlabel, *ZAlabel, *Llabel, *tab_label; GtkWidget *alignment, *fixed; GtkWidget *x_label, *y_label, *tmplabel; GtkWidget *ordercheckb[3], *UseErrCheckB, *actioncheckb[2]; GtkWidget *Olabel, *Elabel, *Alabel; GSList *group; GtkWidget *dialog; gchar buf[256], buf2[256]; gint i, TabNum; gboolean FileInCwd; static gint NumberOfTabs=0; if (NumberOfTabs == MAXNUMTABS-1) { dialog = gtk_message_dialog_new (GTK_WINDOW(window), /* Notify user of the error */ GTK_DIALOG_DESTROY_WITH_PARENT, /* with a dialog */ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot open more tabs, maximum number reached (%d)", MAXNUMTABS); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return -1; } NumberOfTabs++; strncpy(buf2,filename,256); if (strcmp(dirname(buf2),getcwd(buf,256)) == 0) { tab_label = gtk_label_new(basename(filename)); FileInCwd = TRUE; } else { tab_label = gtk_label_new(filename); FileInCwd = FALSE; } table = gtk_table_new(1, 2 ,FALSE); /* Create table */ gtk_container_set_border_width (GTK_CONTAINER (table), WINDOW_BORDER); gtk_table_set_row_spacings(GTK_TABLE(table), SECT_SEP); /* Set spacings */ gtk_table_set_col_spacings(GTK_TABLE(table), 0); TabNum = gtk_notebook_append_page((GtkNotebook *) mainnotebook, table, tab_label); if (TabNum == -1) { return -1; } /* Init datastructures */ bpressed[TabNum][0] = FALSE; bpressed[TabNum][1] = FALSE; bpressed[TabNum][2] = FALSE; bpressed[TabNum][3] = FALSE; valueset[TabNum][0] = FALSE; valueset[TabNum][1] = FALSE; valueset[TabNum][2] = FALSE; valueset[TabNum][3] = FALSE; numpoints[TabNum] = 0; numlastpoints[TabNum] = 0; ordering[TabNum] = 0; lastpoints[TabNum] = (gint *) malloc(sizeof(gint) * (MaxPoints[TabNum]+4)); if (lastpoints[TabNum]==NULL) { printf("Error allocating memory for lastpoints. Exiting.\n"); return -1; } points[TabNum] = (void *) malloc(sizeof(gint *) * MaxPoints[TabNum]); if (points[TabNum]==NULL) { printf("Error allocating memory for points. Exiting.\n"); return -1; } for (i=0;idata); if ((c = strstr((gchar *) data->data, URI_IDENTIFIER)) == NULL) { dialog = gtk_message_dialog_new (GTK_WINDOW(window), /* Notify user of the error */ GTK_DIALOG_DESTROY_WITH_PARENT, /* with a dialog */ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot extract filename from uri '%s'", filename); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); break; } strncpy(filename,&(c[strlen(URI_IDENTIFIER)]),256); for (i=0;i%s<\n",filename); SetupNewTab(filename, 1.0, -1, -1, FALSE); break; } case JPEG_DATA: case PNG_DATA: { printf("Received drag-and-drop jpeg_data or png_data\n"); GError *error = NULL; GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type(gdk_atom_name(data->type), &error); if (loader) { error = NULL; if (gdk_pixbuf_loader_write( loader, data->data, data->length, &error)) { GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader); if ( pbuf ) { int width = gdk_pixbuf_get_width(pbuf); int height = gdk_pixbuf_get_height(pbuf); printf("Received image of size %d x %d\n", width, height); // Print debugging information /* snprintf(tmp, sizeof(tmp), "%d", width); newImage->setAttribute("width", tmp); snprintf(tmp, sizeof(tmp), "%d", height); newImage->setAttribute("height", tmp); */ } } } break; } case APP_X_COLOR: { printf("Received drag-and-drop app-x-color\n"); break; } } gtk_drag_finish (drag_context, TRUE, FALSE, event_time); } /****************************************************************/ /* This callback handles the file - open dialog. */ /****************************************************************/ GCallback menu_file_open(void) { GtkWidget *dialog, *scalespinbutton, *hboxextra, *scalelabel; GtkImage *preview; GtkAdjustment *scaleadj; GtkFileFilter *filefilter; dialog = gtk_file_chooser_dialog_new ("Open File", GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); // Set filtering of files to open to filetypes gdk_pixbuf can handle filefilter = gtk_file_filter_new(); gtk_file_filter_add_pixbuf_formats(filefilter); gtk_file_chooser_set_filter((GtkFileChooser *) dialog, (GtkFileFilter *) filefilter); hboxextra = gtk_hbox_new(FALSE, ELEM_SEP); scalelabel = gtk_label_new(scale_string); scaleadj = (GtkAdjustment *) gtk_adjustment_new(1, 0.1, 100, 0.1, 0.1, 1); scalespinbutton = gtk_spin_button_new(scaleadj, 0.1, 1); gtk_box_pack_start (GTK_BOX (hboxextra), scalelabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hboxextra), scalespinbutton, FALSE, FALSE, 0); gtk_file_chooser_set_extra_widget((GtkFileChooser *) dialog, hboxextra); gtk_widget_show(hboxextra); gtk_widget_show(scalelabel); gtk_widget_show(scalespinbutton); preview = (GtkImage *) gtk_image_new (); gtk_file_chooser_set_preview_widget ((GtkFileChooser *) dialog, (GtkWidget *) preview); g_signal_connect (dialog, "update-preview", G_CALLBACK (update_preview_cb), preview); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { char *filename; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); SetupNewTab(filename, gtk_spin_button_get_value((GtkSpinButton *) scalespinbutton), -1, -1, FALSE); g_free (filename); } gtk_widget_destroy (dialog); return NULL; } /****************************************************************/ /* This function destroys a dialog. */ /****************************************************************/ void dialog_destroy( GtkWidget *widget, gpointer data) { gtk_grab_remove(GTK_WIDGET(widget)); } /****************************************************************/ /* This function closes a dialog. */ /****************************************************************/ void dialog_close( GtkWidget *widget, gpointer data) { gtk_widget_destroy(GTK_WIDGET(data)); } /****************************************************************/ /* This Callback generates the help - about dialog. */ /****************************************************************/ GCallback menu_help_about(void) { gchar *authors[] = AUTHORS; gtk_show_about_dialog((GtkWindow *) window, "authors", authors, "comments", COMMENTS, "copyright", COPYRIGHT, "license", LICENSE, "name", PROGNAME, "version", VERSION, "website", HOMEPAGEURL, "website-label", HOMEPAGELABEL, NULL); return NULL; } /****************************************************************/ /* This function is called when a tab is closed. It removes the */ /* page from the notebook, all widgets within the page are */ /* destroyed. */ /****************************************************************/ GCallback menu_tab_close(void) { gtk_notebook_remove_page((GtkNotebook *) mainnotebook, ViewedTabNum); /* This appearently takes care of everything */ logxy[ViewedTabNum][0] = FALSE; logxy[ViewedTabNum][1] = FALSE; zoomareabox[ViewedTabNum] = NULL; logbox[ViewedTabNum] = NULL; oppropbox[ViewedTabNum] = NULL; NoteBookNumPages--; if (NoteBookNumPages == 0) gtk_action_group_set_sensitive(tab_action_group, FALSE); return NULL; } /****************************************************************/ /* This callback handles the fullscreen toggling. */ /****************************************************************/ GCallback full_screen_action_callback(GtkWidget *widget, gpointer func_data) { if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget))) { gtk_window_fullscreen(GTK_WINDOW (window)); WinFullScreen = TRUE; } else { gtk_window_unfullscreen(GTK_WINDOW (window)); WinFullScreen = FALSE; } return NULL; } /****************************************************************/ /* This callback handles the hide zoom area toggling. */ /****************************************************************/ GCallback hide_zoom_area_callback(GtkWidget *widget, gpointer func_data) { int i; if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget))) { for (i=0;i 1) if (strcmp(argv[1],"-h")==0 || /* If no parameters given, -h or --help */ strcmp(argv[1],"--help")==0) { printf("%s",HelpText); /* Print help */ exit(0); /* and exit */ } maxX = -1; maxY = -1; Scale = -1; UseError = FALSE; UsePreSetCoords = FALSE; Uselogxy[0] = FALSE; Uselogxy[1] = FALSE; for (i=1;i= argc) break; } else if (strcmp(argv[i],"-errors")==0) { UseError = TRUE; } else if (strcmp(argv[i],"-lnx")==0) { Uselogxy[0] = TRUE; } else if (strcmp(argv[i],"-lny")==0) { Uselogxy[1] = TRUE; } else if (strcmp(argv[i],"-max")==0) { if (argc-i < 3) { printf("Too few parameters for -max\n"); exit(0); } if (sscanf(argv[i+1],"%d", &maxX)!=1) { printf("-max first parameter in invalid form !\n"); exit(0); } if (sscanf(argv[i+2],"%d", &maxY)!=1) { printf("-max second parameter in invalid form !\n"); exit(0); } i+=2; if (i >= argc) break; } else if (strcmp(argv[i],"-coords")==0) { UsePreSetCoords = TRUE; if (argc-i < 5) { printf("Too few parameters for -coords\n"); exit(0); } if (sscanf(argv[i+1],"%lf", &TempCoords[0])!=1) { printf("-max first parameter in invalid form !\n"); exit(0); } if (sscanf(argv[i+2],"%lf", &TempCoords[1])!=1) { printf("-max second parameter in invalid form !\n"); exit(0); } if (sscanf(argv[i+3],"%lf", &TempCoords[2])!=1) { printf("-max third parameter in invalid form !\n"); exit(0); } if (sscanf(argv[i+4],"%lf", &TempCoords[3])!=1) { printf("-max fourth parameter in invalid form !\n"); exit(0); } i+=4; if (i >= argc) break; /* } else if (strcmp(argv[i],"-hidelog")==0) { HideLog = TRUE; } else if (strcmp(argv[i],"-hideza")==0) { HideZoomArea = TRUE; } else if (strcmp(argv[i],"-hideop")==0) { HideOpProp = TRUE; */ } else { printf("Unknown parameter : %s\n", argv[i]); exit(0); } continue; } else { FileIndex[NumFiles] = i; NumFiles++; } } window = gtk_window_new(GTK_WINDOW_TOPLEVEL); /* Create window */ gtk_window_set_default_size((GtkWindow *) window, 640, 480); gtk_window_set_title(GTK_WINDOW (window), Window_Title_NoneOpen); /* Set window title */ gtk_window_set_policy(GTK_WINDOW (window), FALSE, FALSE, TRUE); gtk_window_set_resizable(GTK_WINDOW (window), TRUE); gtk_container_set_border_width(GTK_CONTAINER (window), 0); /* Set borders in window */ mainvbox = gtk_vbox_new(FALSE, 0); gtk_container_add( GTK_CONTAINER(window), mainvbox); g_signal_connect(G_OBJECT (window), "delete_event", /* Init delete event of window */ G_CALLBACK (close_application), NULL); gtk_drag_dest_set(window, GTK_DEST_DEFAULT_ALL, ui_drop_target_entries, NUM_IMAGE_DATA, (GDK_ACTION_COPY | GDK_ACTION_MOVE)); g_signal_connect(G_OBJECT (window), "drag-data-received", /* Drag and drop catch */ G_CALLBACK (drag_data_received), NULL); /* Create menues */ action_group = gtk_action_group_new("MenuActions"); gtk_action_group_add_actions(action_group, entries, G_N_ELEMENTS (entries), window); gtk_action_group_add_toggle_actions(action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), window); tab_action_group = gtk_action_group_new("TabActions"); gtk_action_group_add_actions(tab_action_group, closeaction, G_N_ELEMENTS (closeaction), window); gtk_action_group_set_sensitive(tab_action_group, FALSE); ui_manager = gtk_ui_manager_new(); gtk_ui_manager_insert_action_group(ui_manager, action_group, 0); gtk_ui_manager_insert_action_group(ui_manager, tab_action_group, 0); accel_group = gtk_ui_manager_get_accel_group(ui_manager); gtk_window_add_accel_group(GTK_WINDOW (window), accel_group); error = NULL; if (!gtk_ui_manager_add_ui_from_string(ui_manager, ui_description, -1, &error)) { g_message("building menus failed: %s", error->message); g_error_free(error); exit(EXIT_FAILURE); } menubar = gtk_ui_manager_get_widget(ui_manager, "/MainMenu"); gtk_box_pack_start(GTK_BOX (mainvbox), menubar, FALSE, FALSE, 0); mainnotebook = gtk_notebook_new(); gtk_box_pack_start(GTK_BOX (mainvbox), mainnotebook, TRUE, TRUE, 0); g_signal_connect(G_OBJECT (mainnotebook), "switch-page", /* Init switch-page event of notebook */ G_CALLBACK (NoteBookTabChange), NULL); if (NumFiles > 0) { for (i=0;i