/* Gui for GTK+ 2.0 */ #include #include "gtk2_ui.h" using namespace std; void *tryit; void gtk2_ui::usage() const { use(); printf("GTK+2 UI version %s \n", VERSION); printf("Usage:\n mp3stat \n-h/-H/--help This help screen\n"); printf("-v/-V/--version Display Version\n"); } /* Redraws pixmaps on expose event */ gboolean gtk2_ui::expose_event (GtkWidget *graph, GdkEventExpose *event, GdkPixmap *pixmap) { if (!pixmap) return TRUE; gdk_draw_pixmap (graph->window, graph->style->white_gc, pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; } /* draws the currently selected file's graph takes the average for 1/500th of the file and uses the range of bitrates to select a color. Oggs are free-format bitrates, so colors are more accurate. mp3s are mostly a specific bitrate of 19 choices, it's colors will be less accurate. */ void gtk2_ui::draw_graph (Info * chosen1) { float divisor = (float) chosen1->mp3infoa.getTframes() / 500; float x = 0; int avg = 0, y = 0, zy = 0; GdkGC *gc = NULL; GdkPixmap *pixmap = NULL; vector tempBit; gc = gdk_gc_new (chosen1->graph->window); chosen1->zz = 0; pixmap = gdk_pixmap_new (chosen1->graph->window, 500, 35, -1); gdk_gc_set_fill (gc, GDK_SOLID); /* increment for all frames */ tempBit = chosen1->mp3infoa.getBitrates(); for (x = 0; x < chosen1->mp3infoa.getTframes(); x += divisor) { /* Take average incrementing by our divisor (1/500th) */ for (y = (int) x; (y < (x + divisor)) && (y < chosen1->mp3infoa.getTframes()); y++) { avg += chosen1->mp3infoa.place (tempBit[y]); zy++; } avg /= zy; zy = 0; gdk_gc_set_foreground (gc, &color_array[avg]); /* In case our for loop is (due to rounding) greater than 499, we dont want to overrun our pixmap length */ if (chosen1->zz < 500) { gdk_draw_rectangle (pixmap, gc, TRUE, chosen1->zz, 0, 1, 35); gdk_draw_pixmap (chosen1->graph->window, gc, pixmap, chosen1->zz, 0, chosen1->zz, 0, 1, 35); } avg = 0; chosen1->zz++; } chosen1->zz = 0; gtk_tooltips_enable(chosen1->graphtip); g_signal_connect (GTK_OBJECT (chosen1->graph), "expose_event", G_CALLBACK (fexpose_event), pixmap); gtk_widget_queue_draw (chosen1->graph); } /* Shock, draws the pixmaps used in the key for both sides. Redrawn due to tables being destroyed to not leak memory. */ void gtk2_ui::draw_keys (Info * chosen1) { GtkWidget *key = NULL; GdkPixmap *pixmap = NULL; GdkGC *gc2 = NULL; for (int x = 0; x < 19; x++) { key = gtk_drawing_area_new (); gtk_drawing_area_size (GTK_DRAWING_AREA (key), 10, 10); gtk_widget_show (key); gtk_table_attach (GTK_TABLE (chosen1->table2), key, 1, 2, x, x + 1, GTK_SHRINK, GTK_SHRINK, 0, 0); gc2 = gdk_gc_new (key->window); pixmap = gdk_pixmap_new (key->window, 10, 10, -1); gdk_gc_set_foreground (gc2, &color_array[x]); gdk_gc_set_fill (gc2, GDK_SOLID); gdk_draw_rectangle (pixmap, gc2, TRUE, 0, 0, 10, 10); gdk_draw_pixmap (key->window, gc2, pixmap, 0, 0, 0, 0, 10, 10); gtk_widget_queue_draw (key); g_signal_connect (GTK_OBJECT (key), "expose_event", G_CALLBACK (fexpose_event), pixmap); } } /* Depending on which file was selected, generate the labels for that side of the program. */ void gtk2_ui::text_output (Info * chosen1) { Info chosen,chosen2; char time[18]; string name; char sibit[40]; char amnt[10]; int x = 0, y = 0; GtkWidget *label = NULL; /* Don't leak memory on subsequent queries */ if (chosen1->table2) { if(chosen1->detailw) { gtk_widget_destroy (chosen1->detailw); chosen1->detailw = NULL; } gtk_widget_destroy (chosen1->table2); gtk_widget_destroy (chosen1->table3); } /* Recreate tables since we destroyed them */ chosen1->table2 = gtk_table_new (3, 21, FALSE); gtk_table_set_col_spacing (GTK_TABLE (chosen1->table2), 0, 20); gtk_table_set_col_spacing (GTK_TABLE (chosen1->table2), 1, 20); gtk_container_add (GTK_CONTAINER (chosen1->bbreak), chosen1->table2); gtk_container_border_width (GTK_CONTAINER (chosen1->table2), 5); chosen1->table3 = gtk_table_new (2, 4, FALSE); gtk_table_set_col_spacing (GTK_TABLE (chosen1->table3), 0, 20); gtk_container_add (GTK_CONTAINER (chosen1->fsum), chosen1->table3); gtk_container_border_width (GTK_CONTAINER (chosen1->table3), 5); /* Tables done, populate with text now */ name = "Name: " + chosen1->mp3infoa.getName(); label = gtk_label_new (name.c_str()); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL); gtk_misc_set_alignment (GTK_MISC (label), 0, 0); gtk_widget_set_usize (GTK_WIDGET (label), 500, -1); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (chosen1->table3), label, 0, 2, 1, 2, GTK_FILL, GTK_SHRINK, 0, 0); if ((int) chosen1->mp3infoa.getSec() % 60 <= 9) sprintf (time, "Time: %d:0%d", (int) chosen1->mp3infoa.getSec() / 60, (int) chosen1->mp3infoa.getSec() % 60); else sprintf (time, "Time: %d:%d", (int) chosen1->mp3infoa.getSec() / 60, (int) chosen1->mp3infoa.getSec() % 60); label = gtk_label_new (time); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL); gtk_misc_set_alignment (GTK_MISC (label), 0, 0); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (chosen1->table3), label, 0, 1, 2, 3, GTK_FILL, GTK_SHRINK, 0, 0); sprintf (sibit, "Size: %.2fKB ABR: %d", chosen1->mp3infoa.getSize(), (int) chosen1->mp3infoa.getAvgbit()); label = gtk_label_new (sibit); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL); gtk_misc_set_alignment (GTK_MISC (label), 1, 0); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (chosen1->table3), label, 1, 2, 2, 3, GTK_FILL, GTK_SHRINK, 0, 0); y = 3; /* generates the labels used in bitrate table */ /* We lose the pointers to these buttons but we destroy the whole table before re-calling this function */ for (x = 0; x < 19; x++) { label = gtk_label_new (kbit_array[x]); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (label), 0, 0); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (chosen1->table2), label, 0, 1, x, x + 1, GTK_FILL, GTK_SHRINK, 0, 0); y++; sprintf (amnt, "%d", chosen1->mp3infoa.getAmntbit(x)); label = gtk_label_new (amnt); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); gtk_misc_set_alignment (GTK_MISC (label), 0, 0); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (chosen1->table2), label, 2, 3, x, x + 1, GTK_FILL, GTK_SHRINK, 0, 0); y++; } gtk_widget_show (chosen1->table2); gtk_widget_show (chosen1->table3); } /* Only execute the redrawing functions if we have a file we can scan */ void gtk2_ui::is_mp3 (GtkWidget * ok_button, Info * chosen1) { statistic tempIn; tempIn = get_file_data( (char *) gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_selector_menu))); if (tempIn.getTframes() > 0) { clear_file_selector(); chosen1->mp3infoa = tempIn; chosen1->selected_oldfile = chosen1->mp3infoa.getName(); text_output (chosen1); draw_keys (chosen1); draw_graph (chosen1); } } /* Destroys file selector and nulls it out, since widget destroy doesn't */ inline void gtk2_ui::clear_file_selector () { if(file_selector_menu) gtk_widget_destroy(file_selector_menu); file_selector_menu = NULL; } /* Generates a window for the file selection box, setting it to the last directory where a file was analyzed and removing extra features. is_mp3() is attached to the ok button, then destroys widget gtk_widget_destroy() is attached to the cancel button. */ void gtk2_ui::create_file_select (GtkWidget * button1, Info * chosen1) { if(file_selector_menu) return; file_selector_menu = gtk_file_selection_new (" Select an ogg/mp3 file to scan"); gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_selector_menu), chosen1->selected_oldfile.c_str()); gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_selector_menu)); g_signal_connect (GTK_OBJECT (file_selector_menu), "destroy", G_CALLBACK (fclear_file_selector), NULL); g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_selector_menu)-> ok_button), "clicked", G_CALLBACK (fis_mp3), chosen1); g_signal_connect_swapped (GTK_OBJECT (GTK_FILE_SELECTION (file_selector_menu)-> cancel_button), "clicked", G_CALLBACK (fclear_file_selector), NULL); gtk_widget_show (file_selector_menu); } /* closes the application */ void gtk2_ui::close_application (GtkWidget * widget) { gtk_main_quit (); } /* Formats the UI main window */ int gtk2_ui::gtk_interface() { GtkWidget *window = NULL; /* Main window */ GtkWidget *button = NULL; /* buttons */ GtkWidget *table = NULL; /* table to organize file1 and file2 */ GtkWidget *graphbox = NULL; /* Holds pixmaps */ Info chosen; Info chosen2; gtk_init (NULL, NULL); cmap = gdk_colormap_get_system (); set_graph_colors (); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (GTK_OBJECT (window), "destroy", G_CALLBACK (fclose_application), NULL); gtk_window_set_title (GTK_WINDOW (window), "Mp3stat"); gtk_container_border_width (GTK_CONTAINER (window), 5); /* Main table for gui 2x7 */ table = gtk_table_new (2, 8, FALSE); gtk_container_add (GTK_CONTAINER (window), table); /* Attach ui to Main table */ button = gtk_button_new_with_label ("Scan file #1"); g_signal_connect (GTK_OBJECT (button), "clicked", G_CALLBACK (fcreate_file_select), &chosen); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach (GTK_TABLE (table), button, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0); gtk_widget_grab_default (button); gtk_widget_show (button); chosen.graph = gtk_drawing_area_new (); gtk_drawing_area_size (GTK_DRAWING_AREA (chosen.graph), 500, 35); graphbox = gtk_event_box_new (); chosen.graphtip = gtk_tooltips_new(); gtk_tooltips_set_tip (chosen.graphtip,graphbox, "Click for detailed graph of file 1", NULL); gtk_tooltips_disable(chosen.graphtip); #if GTK_MINOR_VERSION >= 4 gtk_event_box_set_visible_window (GTK_EVENT_BOX (graphbox), FALSE); gtk_event_box_set_above_child (GTK_EVENT_BOX (graphbox), TRUE); #endif gtk_container_add (GTK_CONTAINER (graphbox), chosen.graph); g_signal_connect (GTK_OBJECT (graphbox), "button_press_event", G_CALLBACK (fdetailed_info), &chosen); gtk_table_attach (GTK_TABLE (table), graphbox, 0, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0); gtk_widget_show (graphbox); chosen2.graph = gtk_drawing_area_new (); gtk_drawing_area_size (GTK_DRAWING_AREA (chosen2.graph), 500, 35); graphbox = gtk_event_box_new (); chosen2.graphtip = gtk_tooltips_new(); gtk_tooltips_set_tip (chosen2.graphtip, graphbox, "Click for detailed graph of file 2", NULL); gtk_tooltips_disable(chosen2.graphtip); #if GTK_MINOR_VERSION >= 4 gtk_event_box_set_visible_window (GTK_EVENT_BOX (graphbox), FALSE); gtk_event_box_set_above_child (GTK_EVENT_BOX (graphbox), TRUE); #endif gtk_container_add (GTK_CONTAINER (graphbox), chosen2.graph); g_signal_connect (GTK_OBJECT (graphbox), "button_press_event", G_CALLBACK (fdetailed_info), &chosen2); gtk_table_attach (GTK_TABLE (table), graphbox, 0, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 0, 0); gtk_widget_show (graphbox); button = gtk_button_new_with_label ("Scan file #2"); g_signal_connect (GTK_OBJECT (button), "clicked", G_CALLBACK (fcreate_file_select), &chosen2); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach (GTK_TABLE (table), button, 1, 2, 3, 4, GTK_SHRINK, GTK_SHRINK, 0, 0); gtk_widget_grab_default (button); gtk_widget_show (button); chosen.fsum = gtk_frame_new ("File 1 Summary"); gtk_table_attach (GTK_TABLE (table), chosen.fsum, 0, 2, 4, 5, GTK_FILL, GTK_SHRINK, 0, 0); chosen.bbreak = gtk_frame_new ("File 1 bitrate breakdown"); gtk_table_attach (GTK_TABLE (table), chosen.bbreak, 0, 1, 5, 6, GTK_SHRINK, GTK_SHRINK, 0, 0); chosen2.bbreak = gtk_frame_new ("File 2 bitrate breakdown"); gtk_table_attach (GTK_TABLE (table), chosen2.bbreak, 1, 2, 5, 6, GTK_SHRINK, GTK_SHRINK, 0, 0); chosen2.fsum = gtk_frame_new ("File 2 Summary"); gtk_table_attach (GTK_TABLE (table), chosen2.fsum, 0, 2, 6, 7, GTK_FILL, GTK_SHRINK, 0, 0); /* Realize widgets and start gtk main loop */ gtk_widget_show (chosen.fsum); gtk_widget_show (chosen.bbreak); gtk_widget_show (chosen2.fsum); gtk_widget_show (chosen2.bbreak); gtk_widget_show (chosen.graph); gtk_widget_show (chosen2.graph); gtk_widget_show (table); gtk_widget_show (window); gtk_main (); return 0; } /* calls for gtk output */ int gtk2_ui::start (vector args) { tryit = this; vector::iterator i; /* GTK2 ui has no other arguments but help and version */ if(args.begin() != args.end()){ for(i = args.begin();i!= args.end();i++){ if(!strcmp((*i),"-h") || !strcmp((*i),"-H") || !strcmp((*i),"--help")){ usage(); return(0); } if(!strcmp(*i,"-v") || !strcmp(*i, "-V") || !strcmp(*i, "--version")){ ver(); printf("GTK2 UI %s\n",VERSION); return(0); } usage(); return(0); } } else { gtk_interface (); return 0; } return 0; } extern "C" gui* createu() { return new gtk2_ui; } extern "C" void destroyu(gui* tempUI) { delete tempUI; }