/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include /* Backing pixmap for drawing area */ static GdkPixmap *pixmap = NULL; //buffer pixmap which will be drawn into the pixmap drawn on screen static GdkPixmap *buffer_pixmap = NULL; //point data to be added to an appropriate file upon leaving the relevant page [or exiting?] static GList *points_list = NULL; //static char *folder_name = "chopin_prelude_op45-a4"; static int current_page = 0; static int prev_page = 0; static int vert_page_progress = 0; static int hori_page_progress = 0; //percentage of height at which we change from uncovering vertically to horizontally static int change_height_percent=80; static GdkPixbuf *pp_pbuf_image = NULL; static GdkGC* pp_gc = NULL; static int pp_width = 0; static int pp_height = 0; static int page_width = 0; static int page_height = 0; //for tracking mouse movement static int last_x_pos = -1; static int last_y_pos = -1; static gboolean in_progress = FALSE; static gboolean load_show_page( GtkWidget *widget, char *folder_name, int page_number); static gboolean load_show_page_immediate( GtkWidget *widget, char *folder_name, int page_number); static gboolean read_point_data_from_file (GtkWidget *widget, GdkPixmap *drawing_pixmap, char *filename); static guint timeout_id = 0; static gboolean update_progress_page(gpointer data) { GtkWidget* widget = (GtkWidget*)data; g_print("updating page progress = %d\n", vert_page_progress); if (vert_page_progress < 100) { if (vert_page_progress < change_height_percent) { vert_page_progress+=10; int update_height = (int)(pp_height * (vert_page_progress / 100.0)); // gdk_draw_pixbuf (pixmap, pp_gc, pp_pbuf_image, // 0, 0, 0, 0, -1, update_height, GDK_RGB_DITHER_NONE, 0, 0); gdk_draw_drawable (pixmap, pp_gc, buffer_pixmap, 0, 0, 0, 0, -1, update_height); gtk_widget_queue_draw_area (widget, 0, 0, pp_width, update_height); return TRUE; } else { //update horizontally if (hori_page_progress < 100) { hori_page_progress+=10; int update_height = (int)(pp_height * (vert_page_progress / 100.0)); int update_width = (int)(pp_width * (hori_page_progress / 100.0)); // gdk_draw_pixbuf (pixmap, pp_gc, pp_pbuf_image, // 0, update_height, 0, update_height, update_width, pp_height - update_height, GDK_RGB_DITHER_NONE, 0, 0); gdk_draw_drawable (pixmap, pp_gc, buffer_pixmap, 0, update_height, 0, update_height, update_width, pp_height - update_height); gtk_widget_queue_draw_area (widget, 0, 0, update_width, pp_height); return TRUE; } else { //reset values // vert_page_progress = 0; // hori_page_progress = 0; in_progress = FALSE; return FALSE; } } } else { //reset values // vert_page_progress = 0; // hori_page_progress = 0; in_progress = FALSE; return FALSE; } } /* Create a new backing pixmap of the appropriate size */ static gboolean configure_event( GtkWidget *widget, GdkEventConfigure *event, gpointer folder_name ) { // char *filename = "chopin_prelude_op45-a4/chopin_prelude_op45-a4-page00.tif"; // char *filename = "page1.tif"; if (pixmap) g_object_unref (pixmap); pixmap = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1); buffer_pixmap = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1); gdk_draw_rectangle (pixmap, widget->style->black_gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height); pp_gc = gdk_gc_new (pixmap); //reset values vert_page_progress = 0; hori_page_progress = 0; in_progress = TRUE; load_show_page_immediate (widget, (char*)folder_name, 0); return TRUE; } /* Redraw the screen from the backing pixmap */ static gboolean expose_event( GtkWidget *widget, GdkEventExpose *event ) { gdk_draw_drawable (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; } #define min2(x,y) (xy)?x:y //connecting line static void draw_connecting_line (GtkWidget *widget, GdkPixmap *drawing_pixmap, gdouble last_x, gdouble last_y, gdouble x, gdouble y) { //we are going to draw a line between two points instead of just drawing the next point gdk_gc_set_line_attributes ( widget->style->black_gc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_ROUND); gdk_draw_line ( drawing_pixmap, widget->style->black_gc, last_x, last_y, x, y); int x_min = min2(x, last_x); int y_min = min2(y, last_y); int x_max = max2(x, last_x); int y_max = max2(y, last_y); gtk_widget_queue_draw_area ( widget, x_min - 2, y_min - 2, x_max - x_min + 5, y_max - y_min + 5); } /* Draw a rectangle on the screen */ static void draw_brush( GtkWidget *widget, GdkPixmap *drawing_pixmap, gdouble x, gdouble y) { GdkRectangle update_rect; update_rect.x = x - 2; update_rect.y = y - 2; update_rect.width = 4; update_rect.height = 4; gdk_draw_rectangle (drawing_pixmap, widget->style->black_gc, TRUE, update_rect.x, update_rect.y, update_rect.width, update_rect.height); gtk_widget_queue_draw_area (widget, update_rect.x, update_rect.y, update_rect.width, update_rect.height); } static gboolean file_exists (char *filename) { //if NULL is returned then the file probably does not exist; return false if (g_fopen(filename, "r") == NULL) return FALSE; return TRUE; } static gboolean load_show_page( GtkWidget *widget, char *folder_name, int page_number) { char filename[512]; sprintf(filename, "%s/%s-page%02d.tif", folder_name, folder_name, page_number); g_print("%s\n\n", filename); // filename = "chopin_prelude_op45-a4/chopin_prelude_op45-a4-page01.tif"; if (!file_exists(filename)) return FALSE; //get the percentage of page to load/display before swapping from vertical loading to horizontal loading char filename_pagebreak[512]; sprintf (filename_pagebreak, "%s.pagebreak", filename); if (file_exists(filename_pagebreak)) { FILE *file = fopen(filename_pagebreak, "r"); char line_buf[10]; //shouldn't be longer than 2 characters, really fgets(line_buf, 10, file); change_height_percent = atoi ( line_buf ); } else { change_height_percent = 80; //defaults to 80% if there is no pagebreak file } g_print("change_height_percent: %d\n", change_height_percent); // Get the origial image size. gdk_pixbuf_get_file_info(filename, &pp_width, &pp_height); page_width = widget->allocation.width; page_height = widget->allocation.height; gdk_drawable_get_size(pixmap, &page_width, &page_height); //getting the scaled sizes to load the image in at fullscreen int w = pp_width; int h = pp_height; double scale = 1; if (pp_width >= pp_height) { if (pp_width != page_width) { scale = (double)pp_width / (double)page_width; } } else if (pp_height > pp_width) { if (pp_height != page_height) { scale = (double)pp_height / (double)page_height; } } w = (int)((double)pp_width / scale); h = (int)((double)pp_height / scale)- 1; pp_width = w; pp_height = h; pp_pbuf_image = gdk_pixbuf_new_from_file_at_size(filename, pp_width, pp_height, 0); gdk_draw_pixbuf (buffer_pixmap, pp_gc, pp_pbuf_image, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); //drawing the point/scribble data onto the buffer pixmap char point_filename[512]; sprintf(point_filename, "%s/%s-page%02d.tif.pointdata", folder_name, folder_name, page_number); read_point_data_from_file(widget, buffer_pixmap, point_filename); //pp_gc = gdk_gc_new (pixmap); //reset values vert_page_progress = 0; hori_page_progress = 0; timeout_id = g_timeout_add (1000, update_progress_page, widget); return TRUE; } static gboolean load_show_page_immediate( GtkWidget *widget, char *folder_name, int page_number) { char filename[512]; sprintf(filename, "%s/%s-page%02d.tif", folder_name, folder_name, page_number); g_print("%s\n\n", filename); // filename = "chopin_prelude_op45-a4/chopin_prelude_op45-a4-page01.tif"; if (!file_exists(filename)) return FALSE; // Get the origial image size. gdk_pixbuf_get_file_info(filename, &pp_width, &pp_height); page_width = widget->allocation.width; page_height = widget->allocation.height; gdk_drawable_get_size(pixmap, &page_width, &page_height); //getting the scaled sizes to load the image in at fullscreen int w = pp_width; int h = pp_height; double scale = 1; if (pp_width >= pp_height) { if (pp_width != page_width) { scale = (double)pp_width / (double)page_width; } } else if (pp_height > pp_width) { if (pp_height != page_height) { scale = (double)pp_height / (double)page_height; } } w = (int)((double)pp_width / scale); h = (int)((double)pp_height / scale)- 1; pp_width = w; pp_height = h; pp_pbuf_image = gdk_pixbuf_new_from_file_at_size(filename, pp_width, pp_height, 0); //pp_gc = gdk_gc_new (pixmap); //reset values vert_page_progress = 0; hori_page_progress = 0; gdk_draw_pixbuf (buffer_pixmap, pp_gc, pp_pbuf_image, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); //drawing the point/scribble data onto the buffer pixmap char point_filename[512]; sprintf(point_filename, "%s/%s-page%02d.tif.pointdata", folder_name, folder_name, page_number); read_point_data_from_file(widget, buffer_pixmap, point_filename); //current gdk_draw_drawable (pixmap, pp_gc, buffer_pixmap, 0, 0, 0, 0, -1, -1); // gdk_draw_pixbuf (pixmap, pp_gc, pp_pbuf_image, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); gtk_widget_queue_draw_area (widget, 0, 0, pp_width, pp_height); // g_timeout_add (1000, update_progress_page, widget); in_progress = FALSE; return TRUE; } static gboolean write_point_data_to_file ( char *filename) { FILE *file; file = fopen(filename, "w+"); GList *curr = points_list; while (curr != NULL) { g_print("writing: %s\n", (char*)curr->data); fprintf(file, "%s\n", (char*)curr->data); curr = g_list_next(curr); } fclose(file); return TRUE; } static gboolean read_point_data_from_file (GtkWidget *widget, GdkPixmap *drawing_pixmap, char *filename) { FILE *file; file = fopen(filename, "r+"); if (file == NULL) { g_print ("no point file data\n"); return FALSE; } int old_x_val, old_y_val, x_val, y_val; gboolean start_line = TRUE; // while (feof(file) == 0) g_print("gonna scan us some file: %s\n", filename); //reset points list points_list = NULL; while (fscanf(file, "%d %d\n", &x_val, &y_val) != EOF) { //add this data to the list of point data, ... char *data = malloc(16); if (data == NULL) { fprintf(stderr, "error (failed to allocate memory in button_press_event"); exit(-1); } sprintf (data, "%d %d", x_val, y_val); points_list = g_list_append(points_list, data); g_print("%s\n", data); //break; // fscanf(file, "%d %d\n", &x_val, &y_val); if (x_val == -1) //then continue; { start_line = TRUE; continue; } else if (start_line) { draw_brush(widget, drawing_pixmap, x_val, y_val); old_x_val = x_val; old_y_val = y_val; } else { draw_connecting_line (widget, drawing_pixmap, old_x_val, old_y_val, x_val, y_val); old_x_val = x_val; old_y_val = y_val; } start_line = FALSE; } fclose(file); return TRUE; } static gboolean button_release_event( GtkWidget *widget, GdkEventButton *event) { g_print("mouse released\n"); last_x_pos = -1; last_y_pos = -1; //add this gap to the list of point data, ... points_list = g_list_append(points_list, "-1 -1"); return TRUE; } static gboolean button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer folder_name) { if (event->button == 1 && pixmap != NULL) { if (!in_progress) { draw_brush (widget, pixmap, event->x, event->y); last_x_pos = event->x; last_y_pos = event->y; //add this data to the list of point data, ... char *data = malloc(16); if (data == NULL) { fprintf(stderr, "error (failed to allocate memory in button_press_event"); exit(-1); } sprintf (data, "%d %d", (int)event->x, (int)event->y); points_list = g_list_append(points_list, data); //g_print("%x\n", folder_name); //in_progress = TRUE; //current_page += 1; //load_show_page (widget, (char*)folder_name, current_page); } else { g_print("in progress so can't draw\n"); } } return TRUE; } static gboolean key_press_event( GtkWidget *widget, GdkEventKey *event, gpointer data_list) { if (event->type == GDK_KEY_RELEASE) return TRUE; GtkWidget *drawing_area = (GtkWidget*)g_list_nth_data(data_list, 0); char *folder_name = (char*)g_list_nth_data(data_list, 1); g_print("called keypress event\n"); if (!in_progress) { g_print("NOT inprogress\n"); //write the point data for this page to a file char filename[512]; sprintf(filename, "%s/%s-page%02d.tif.pointdata", folder_name, folder_name, current_page); g_print("writing to file: %s", filename); write_point_data_to_file (filename); switch (event->keyval) { case GDK_Right: printf("right!\n"); prev_page = current_page; current_page += 1; break; case GDK_Left: printf("left!\n"); prev_page = current_page; current_page -= 1; break; default: return TRUE; } in_progress = TRUE; load_show_page (drawing_area, folder_name, current_page); } else //in progress, so speed up that progress: load page immediately { g_print("in progress\n"); switch (event->keyval) { case GDK_Right: g_source_remove(timeout_id); if (current_page != prev_page+1) { current_page = prev_page; } load_show_page_immediate(drawing_area, folder_name, current_page); // printf("right!\n"); // current_page += 1; break; case GDK_Left: g_source_remove(timeout_id); if (current_page != prev_page-1) { current_page = prev_page; } load_show_page_immediate(drawing_area, folder_name, current_page); // printf("left!\n"); // current_page -= 1; break; default: return TRUE; } // load_show_page_immediate(drawing_area, folder_name, current_page); } return TRUE; } static gboolean motion_notify_event( GtkWidget *widget, GdkEventMotion *event ) { int x, y; GdkModifierType state; if (event->is_hint) gdk_window_get_pointer (event->window, &x, &y, &state); else { x = event->x; y = event->y; state = event->state; } if (state & GDK_BUTTON1_MASK && pixmap != NULL) { if (!in_progress) { //if we haven't set x yet, don't do this if (last_x_pos == -1) return TRUE; draw_connecting_line (widget, pixmap, last_x_pos, last_y_pos, x, y); last_x_pos = x; last_y_pos = y; //add this data to the list of point data, ... char *data = malloc(16); if (data == NULL) { fprintf(stderr, "error (failed to allocate memory in button_press_event"); exit(-1); } sprintf (data, "%d %d", (int)event->x, (int)event->y); points_list = g_list_append(points_list, data); // draw_brush (widget, x, y); } } return TRUE; } void quit () { exit (0); } int main( int argc, char *argv[] ) { char *folder_name; if (argc == 1) { //default folder_name = "chopin_prelude_op45-a4"; } else { folder_name = argv[1]; } //************************************ /* FILE *writing; //int buffer = 256; int value = 6; char *filename; filename = "file.txt"; writing = fopen(filename, "w+"); fprintf(writing, "%d\n", value); value = 7; fprintf(writing, "%d\n", value); value = 8; fprintf(writing, "%d\n", value); fclose(writing); int blah = 0; writing = fopen(filename, "r+"); fscanf(writing, "%d\n", &blah); g_print("%d\n", blah); fscanf(writing, "%d\n", &blah); g_print("%d\n", blah); fscanf(writing, "%d\n", &blah); g_print("%d\n", blah); fclose(writing); */ //************************************ GtkWidget *window; GtkWidget *drawing_area; GtkWidget *vbox; GtkWidget *button; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_set_name (window, "Test Input"); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show (vbox); g_signal_connect (window, "destroy", G_CALLBACK (quit), NULL); /* Create the drawing area */ drawing_area = gtk_drawing_area_new (); gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200); gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); gtk_widget_show (drawing_area); /* Signals used to handle backing pixmap */ g_signal_connect (drawing_area, "expose-event", G_CALLBACK (expose_event), NULL); g_signal_connect (drawing_area,"configure-event", G_CALLBACK (configure_event), folder_name); /* Event signals */ g_signal_connect (drawing_area, "motion-notify-event", G_CALLBACK (motion_notify_event), NULL); g_signal_connect (drawing_area, "button-press-event", G_CALLBACK (button_press_event), folder_name); g_signal_connect (drawing_area, "button-release-event", G_CALLBACK (button_release_event), NULL); //needs to be passed both the drawing_area, and the folder_name, so create a glist and pass a pointer to that GList *key_press_data = NULL; key_press_data = g_list_append(key_press_data, drawing_area); key_press_data = g_list_append(key_press_data, folder_name); g_signal_connect (window, "key-press-event", G_CALLBACK (key_press_event), key_press_data); gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); /* .. And a quit button */ button = gtk_button_new_with_label ("Quit"); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window); gtk_widget_show (button); gtk_widget_show (window); gtk_main (); return 0; }