source: projects/puncher/gtk-frontend.c @ 7

Last change on this file since 7 was 5, checked in by sven, 12 years ago

The new puncher subsystem which shall replace the existing Linux-only
userspace driver (where the whole user frontend and backend is hardcoded
in only one c file) at [the paper tape project reposity]/userspace-driver.

This puncher subsystem has not been finished yet, but the userspace-driver
directory will be quite legacy at some time when the new subsystem works
(at least on Linux).

File size: 12.8 KB
Line 
1/**
2 * The GTK frontend to the puncher backends.
3 *
4 * It uses GtkPaperTape to display the current open file and
5 * serves several controls to control the punch process.
6 *
7 * started at 14.06.2008
8 * (c) Sven
9 *
10 *
11 *
12 **/
13
14
15#include <gtk/gtk.h>
16#include <math.h>
17#include <stdlib.h>
18#include "../visualisator/gtkpapertape.h"
19
20#define _(a) a
21
22/* while punching in the gtk main loop, update the gui! */
23#define UPDATE_GTK_GUI  { while (gtk_events_pending ()) gtk_main_iteration (); }
24
25/* The master structure... */
26struct my_frontend {
27        /* The state of our punching process */
28        enum MY_PROGRESS_STATE {
29                PROGRESS_RUNNING,
30                PROGRESS_PAUSED,
31                PROGRESS_STOPPED
32        } state;
33       
34        /* Various GtkWidgets: */
35        GtkWidget *progress_bar;                // The GtkProgressBar
36       
37        // Label Grid:
38        GtkWidget *progress_holes_total;        // counts ALL available bytes
39        GtkWidget *progress_holes_punched;      // counts the already punched bytes
40        GtkWidget *progress_holes_todo;         // counts the bytes which must be punched
41       
42        GtkWidget *progress_total_time;         // displays the calculated total punch time
43        GtkWidget *progress_estimated_time;     // displays the estimated time until finish
44        GtkWidget *progress_elapsed_time;       // displays the elapsed time since beginning
45       
46        GtkWidget *progress_time_per_hole;      // displays the time needed for one hole
47        GtkWidget *progress_frequency;          // displays the amount of holes per second
48
49        // Master buttons
50        GtkWidget *button_start;                // The button to start punching
51        GtkWidget *button_pause;                // The button to pause punching
52        GtkWidget *button_stop;                 // The button to stop punching
53
54        // The papertape context
55        GtkPaperTape *papertape;
56
57        // This is supposed to be a link to the data
58        // saved somewhere in GtkPaperTape/LOCHSTREIFEN*.
59        // Don't even think about to free() it. The memory
60        // leak doesn't hurt ;-)
61        int length;
62        byte_t *data;
63
64        int punched;  // the already punched holes
65        GTimer *timer; // the timer which measures
66} d;
67
68gboolean progress_update_time();
69void punch_byte(unsigned char byte);
70
71void prepare_my_frontend(GtkWidget *window) {
72        /**
73         * This function will prepare the big struct my_frontend which is
74         * globally known as "d"
75         *
76         **/
77
78        d.state = PROGRESS_STOPPED;
79        d.length = 0;
80        d.data = 0;
81        d.punched = 0;
82       
83        d.papertape = GTK_PAPER_TAPE(gtk_paper_tape_new(window));
84       
85        d.progress_bar = gtk_progress_bar_new();
86       
87        #define MY_FRONTEND_FAST_LABEL(a) { d.a = gtk_label_new("x"); \
88                gtk_label_set_selectable(GTK_LABEL(d.a), TRUE); }
89        MY_FRONTEND_FAST_LABEL(progress_holes_total);
90        MY_FRONTEND_FAST_LABEL(progress_holes_punched);
91        MY_FRONTEND_FAST_LABEL(progress_holes_todo);
92        MY_FRONTEND_FAST_LABEL(progress_total_time);
93        MY_FRONTEND_FAST_LABEL(progress_estimated_time);
94        MY_FRONTEND_FAST_LABEL(progress_elapsed_time);
95        MY_FRONTEND_FAST_LABEL(progress_time_per_hole);
96        MY_FRONTEND_FAST_LABEL(progress_frequency);
97
98        d.button_start = gtk_button_new_with_mnemonic(_("Punch!")); 
99        gtk_button_set_image(GTK_BUTTON(d.button_start),
100                gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
101
102        d.button_pause = gtk_button_new_with_mnemonic(_("Pause")); 
103        gtk_button_set_image(GTK_BUTTON(d.button_pause),
104                gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_BUTTON));
105
106        d.button_stop = gtk_button_new_with_mnemonic(_("Stop")); 
107        gtk_button_set_image(GTK_BUTTON(d.button_stop),
108                gtk_image_new_from_stock(GTK_STOCK_MEDIA_STOP, GTK_ICON_SIZE_BUTTON));
109
110        d.timer = g_timer_new();
111}
112
113void progress_set() {
114        /**
115         * set information about holes
116         *
117         **/
118        gtk_label_set_markup(GTK_LABEL(d.progress_holes_total),
119                g_markup_printf_escaped("Loecher: <b>%3d</b>", d.length)
120        );
121        gtk_label_set_markup(GTK_LABEL(d.progress_holes_punched),
122                g_markup_printf_escaped("Gestanzt: <b>%3d</b>", d.punched)
123        );
124        gtk_label_set_markup(GTK_LABEL(d.progress_holes_todo),
125                g_markup_printf_escaped("Zu Stanzen: <b>%4d</b>", d.length - d.punched)
126        );
127}
128
129gboolean gui_puncher_start(GtkWidget *start_widget, gpointer nada) {
130        /**
131         * The callback for the "start punching" button. This will prepare
132         * the gui, prepare observing and progress functions and of course
133         * this will start the low level punching driver.
134         **/
135       
136        // set the values
137        d.state = PROGRESS_RUNNING;
138       
139        // prepare the gui
140        gtk_widget_set_sensitive(d.button_start, FALSE);
141        gtk_widget_set_sensitive(d.button_pause, TRUE);
142        gtk_widget_set_sensitive(d.button_stop, TRUE);
143        gtk_widget_set_sensitive(d.progress_bar, TRUE);
144       
145        // start the progress indicators:
146        //g_timer_start(d.timer);
147        //g_timeout_add(1000, progress_update_time, NULL);
148        // kein Sinn - regelmaessig nach jedem punch machen!
149       
150        // start the punching loop
151        gui_punch();
152}
153
154gboolean gui_punch() {
155        /**
156         * The Punch main loop, as the gui drives it.
157         * Returns success or not (FALSE).
158         **/
159       
160        int x;
161       
162        for(x = 0; x < d.length; x++) {
163                progress_set();
164                progress_update_time();
165                gtk_paper_tape_set_highlight(d.papertape, x, TRUE); // TRUE: Abhängig von Checkbox!
166                UPDATE_GTK_GUI;
167                punch_byte(d.data[x]);
168                d.punched++;
169        }
170       
171        gtk_paper_tape_remove_highlight(d.papertape);
172        return TRUE;
173}
174
175void punch_byte(unsigned char byte) {
176        usleep(20*1000);
177}
178
179gboolean progress_update_time() {
180        /**
181         * This does exactly what the low level function "calculate_time" does;
182         * using the power of glib (GTimer). Furthermore additional values are
183         * calculated.
184         *
185         * expects the GTimer to be started.
186         **/
187
188        int percentage = (int)rint(((float)d.punched / (float)d.length) * 100);
189        int sec_since_beginning = (int)rint(g_timer_elapsed(d.timer, NULL));
190        int sec_total;
191        int est = 0;
192       
193        gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(d.progress_bar),
194                (double)d.punched / (double)d.length);
195        gtk_progress_bar_set_text(GTK_PROGRESS_BAR(d.progress_bar),
196                g_strdup_printf("%d%%", percentage)
197        );
198       
199        // calc after first cycle
200        if(sec_since_beginning != 0) {
201                est = (int)rint((float)sec_since_beginning / ((float)d.punched / (float)d.length));
202               
203                gtk_label_set_markup(GTK_LABEL(d.progress_estimated_time),
204                        g_markup_printf_escaped("<b>%d</b> sec", est)
205                );
206        }
207       
208        gtk_label_set_markup(GTK_LABEL(d.progress_elapsed_time),
209                g_markup_printf_escaped("%d", sec_since_beginning)
210        );
211       
212        return !(est == sec_since_beginning && percentage == 100);
213        // true zurueckgeben, wenns weitergehen soll.
214}
215
216
217gboolean open_file_dialog(GtkWidget *menuitem, GtkPaperTape* papertape) {
218        /**
219         * displays an "open file" dialog which runs gtk_paper_tape_read_from_file() if success,
220         * is run by the menu item "open file"
221         **/
222
223        GtkWidget *chooser;
224        chooser = gtk_file_chooser_dialog_new(
225                _("Select (binary) file to display as a paper tape"),
226                GTK_WINDOW(papertape->parent_window),
227                GTK_FILE_CHOOSER_ACTION_OPEN,
228                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
229                GTK_STOCK_OPEN, GTK_RESPONSE_OK,
230                NULL);
231
232        if(gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) {
233                char *filename;
234                FILE *file;
235
236                filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (chooser));
237                if(filename == NULL) {
238                        g_printf(_("No file selected to open.\n"));
239                        gtk_widget_destroy(GTK_WIDGET(chooser));
240                        return FALSE;
241                } else {
242                        gtk_paper_tape_read_from_file(papertape, filename);
243                       
244                        d.length = papertape->lochstreifen->data_length;
245                        d.data = papertape->lochstreifen->data;
246                       
247                        g_free(filename);
248                        gtk_widget_destroy(GTK_WIDGET(chooser));
249                        return TRUE;
250                }
251        }
252        gtk_widget_destroy(chooser);
253        return FALSE;
254} // open_file_dialog
255
256void quit_application(GtkWidget *window, gpointer *nada) {
257        exit(0);
258        // on window close: manage punching interaction!!
259}
260
261int main(int argc, char *argv[]) {
262        GtkWidget *window, *widget, *main_box, *tape_box, *punch_box, *statusbar;
263        gtk_init(&argc, &argv);
264       
265        // main window generation
266        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
267        gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);
268        gtk_window_set_title(GTK_WINDOW(window), _("Papertape Puncher"));
269        g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(quit_application), NULL);
270       
271        // above-main-box generation (contains menubar + mainbox)
272        prepare_my_frontend(window);
273        widget = gtk_vbox_new(FALSE, 0);
274        gtk_container_add(GTK_CONTAINER(window), widget);
275       
276        // menus generation start
277        {
278                GtkWidget *menu, *menubar, *menuitem;
279                // menus
280                menubar = gtk_menu_bar_new();
281                gtk_box_pack_start(GTK_BOX(widget), menubar, FALSE, TRUE, 0);
282                gtk_widget_show(menubar);
283       
284                // FIRST menu: File {{{
285                menu = gtk_menu_new();
286                // Oeffnen
287                g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_OPEN)),
288                        "activate", G_CALLBACK(open_file_dialog), d.papertape);
289                fast_menu_seperator(menu);
290                gtk_paper_tape_menu_export(d.papertape, menu);
291                fast_menu_seperator(menu);
292                g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_QUIT)),
293                        "activate", G_CALLBACK(gtk_main_quit), NULL);
294       
295                menuitem = gtk_menu_item_new_with_mnemonic("_Datei");
296                gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
297                gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
298                gtk_widget_show (menuitem);
299       
300                // Zweites Menue: Ansicht
301                menu = gtk_menu_new();
302                gtk_paper_tape_menu_view(d.papertape, menu);
303       
304                menuitem = gtk_menu_item_new_with_mnemonic("_Ansicht");
305                gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
306                gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
307                gtk_widget_show (menuitem);
308       
309                // Drittes Menue: Farben
310                menu = gtk_menu_new();
311                gtk_paper_tape_menu_colors(d.papertape, menu);
312       
313                menuitem = gtk_menu_item_new_with_mnemonic("_Farben");
314                gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
315                gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
316                gtk_widget_show (menuitem);
317        }
318        // menus end
319       
320        // main box generation
321        main_box = gtk_vbox_new(FALSE, 0);
322        gtk_container_set_border_width(GTK_CONTAINER(main_box), 10);
323        gtk_container_add(GTK_CONTAINER(widget), main_box);
324       
325        // tape box generation
326        widget = gtk_frame_new("udo-14.06.2008-generated-file.bin");
327        gtk_box_pack_start(GTK_BOX(main_box), widget, TRUE, TRUE, 0);
328        tape_box = GTK_WIDGET(gtk_paper_tape_get_whole_box(d.papertape));
329        gtk_container_set_border_width(GTK_CONTAINER(tape_box), 10);
330        gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(d.papertape->statusbar), FALSE);
331        gtk_container_add(GTK_CONTAINER(widget), tape_box);
332
333        // punch box generation
334        widget = gtk_frame_new(_("Punching controls"));
335        gtk_box_pack_start(GTK_BOX(main_box), widget, FALSE, TRUE, 0);
336        punch_box = gtk_vbox_new(FALSE, 0);
337        gtk_container_set_border_width(GTK_CONTAINER(punch_box), 10);
338        gtk_container_add(GTK_CONTAINER(widget), punch_box);
339       
340        // fill punch box:
341        {
342                GtkWidget *label;
343                GtkWidget *holes_box, *progress_box, *button_box;
344               
345                holes_box = gtk_hbox_new(FALSE, 0);
346                gtk_container_add(GTK_CONTAINER(punch_box), holes_box);
347               
348                gtk_container_add(GTK_CONTAINER(holes_box), d.progress_holes_total);
349                gtk_container_add(GTK_CONTAINER(holes_box), d.progress_holes_punched);
350                gtk_container_add(GTK_CONTAINER(holes_box), d.progress_holes_todo);
351
352                progress_box = gtk_hbox_new(FALSE, 0);
353                gtk_container_add(GTK_CONTAINER(punch_box), progress_box);
354               
355                /*label = gtk_label_new("Fortschritt: ");
356                gtk_container_add(GTK_CONTAINER(progress_box), label);*/
357               
358                gtk_box_pack_start(GTK_BOX(progress_box), d.progress_bar, TRUE, TRUE, 0);
359               
360                label = gtk_label_new("Zeit: ");
361                gtk_container_add(GTK_CONTAINER(progress_box), label);
362                gtk_container_add(GTK_CONTAINER(progress_box), d.progress_estimated_time);
363                gtk_container_add(GTK_CONTAINER(progress_box), d.progress_elapsed_time);
364               
365                // Button boxes
366                button_box = gtk_hbutton_box_new();
367                gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_START);
368                gtk_container_add(GTK_CONTAINER(punch_box), button_box);
369               
370                gtk_container_add(GTK_CONTAINER(button_box), d.button_start);
371                g_signal_connect(G_OBJECT(d.button_start), "clicked", G_CALLBACK(gui_puncher_start), NULL);
372                gtk_container_add(GTK_CONTAINER(button_box), d.button_pause);
373                gtk_container_add(GTK_CONTAINER(button_box), d.button_stop);
374        }
375
376        // parse command options
377        {
378                char *filename = NULL;
379                gboolean read_from_stdin = FALSE;
380                GError *error = NULL;
381                GOptionContext *context;
382                byte_t show_mystart = 0; // eigene Startprozedur anzeigen?
383                GOptionEntry option_entries[] = {
384                        { "filename", 'f', 0, G_OPTION_ARG_FILENAME, &filename, _("file to open"), NULL },
385                        { "stdin", 's', 0, G_OPTION_ARG_NONE, &read_from_stdin, _("read from standard input"), NULL },
386                        { NULL }
387                };
388
389                context = g_option_context_new(_(" - GtkPaperTape visualisation"));
390                g_option_context_add_main_entries(context, option_entries, NULL);
391                g_option_context_add_group(context, gtk_get_option_group(TRUE));
392                g_option_context_parse(context, &argc, &argv, &error);
393
394                if(read_from_stdin) {
395                        printf(_("%s: Reading data from standard input, will open window after EOF.\n"), argv[0]);
396                        byte_t *data;
397                        int length = file_get_contents(stdin, &data);
398                        gtk_paper_tape_set_data(d.papertape, length, data);
399                } else if(filename != NULL) {
400                        // eine Datei einlesen
401                        printf(_("Reading from file '%s'\n"), filename);
402                        if(!gtk_paper_tape_read_from_file(d.papertape, argv[1])) {
403                                printf(_("Failed to read from file!\n"));
404                                return 1;
405                        }
406                }
407        }
408        // end of parsing command options
409
410        gtk_widget_show_all(window);
411        gtk_main();
412        return 0;
413}
Note: See TracBrowser for help on using the repository browser.
© 2008 - 2013 technikum29 • Sven Köppel • Some rights reserved
Powered by Trac
Expect where otherwise noted, content on this site is licensed under a Creative Commons 3.0 License