source: projects/puncher/frontend.gtk.c @ 9

Last change on this file since 9 was 9, checked in by sven, 16 years ago
  • Recreated Makefiles in visualisator/ and puncher/
  • All /visualisator/ sources now compile with -Wall compiler flag
  • The basic /puncher/ sources compile with -Wall, too.
  • Added Readme for schriften/

Current development is now focussed at /puncher/frontend.gtk.c.

-- Sven @ workstation

File size: 13.7 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) Copyright 2008 Sven Köppel
9 *
10 *
11 *
12 **/
13
14
15#include <gtk/gtk.h>
16#include <math.h>
17#include <stdlib.h>
18#include "backend.h"
19#include "../visualisator/gtkpapertape.h"
20
21#define _(a) a
22
23/* while punching in the gtk main loop, update the gui! */
24#define UPDATE_GTK_GUI  { while (gtk_events_pending ()) gtk_main_iteration (); }
25
26/* The master structure... */
27struct puncher_frontend {
28        /* The state of our punching process */
29        enum PUNCHER_FRONTEND_PROGRESS_STATE {
30                PROGRESS_RUNNING,
31                PROGRESS_PAUSED,
32                PROGRESS_STOPPED
33        } state;
34       
35        /* The holy backend: */
36        PuncherBackend *backend;
37       
38        /* Various GtkWidgets: */
39        GtkWidget *progress_bar;                // The GtkProgressBar
40       
41        // Label Grid:
42        GtkWidget *progress_holes_total;        // counts ALL available bytes
43        GtkWidget *progress_holes_punched;      // counts the already punched bytes
44        GtkWidget *progress_holes_todo;         // counts the bytes which must be punched
45       
46        GtkWidget *progress_total_time;         // displays the calculated total punch time
47        GtkWidget *progress_estimated_time;     // displays the estimated time until finish
48        GtkWidget *progress_elapsed_time;       // displays the elapsed time since beginning
49       
50        GtkWidget *progress_time_per_hole;      // displays the time needed for one hole
51        GtkWidget *progress_frequency;          // displays the amount of holes per second
52
53        // Master buttons
54        GtkWidget *button_start;                // The button to start punching
55        GtkWidget *button_pause;                // The button to pause punching
56        GtkWidget *button_stop;                 // The button to stop punching
57
58        // The papertape context
59        GtkPaperTape *papertape;
60
61        // This is supposed to be a link to the data
62        // saved somewhere in GtkPaperTape/LOCHSTREIFEN*.
63        // Don't even think about to free() it. The memory
64        // leak doesn't hurt ;-)
65        int length;
66        byte_t *data;
67
68        int punched;  // the already punched holes
69        GTimer *timer; // the timer which measures
70} d;
71
72gboolean progress_update_time();
73gboolean puncher_frontend_punch_loop();
74
75void puncher_frontend_prepare(GtkWidget *window) {
76        /**
77         * This function will prepare the big struct puncher_frontend which is
78         * globally known as "d"
79         *
80         **/
81
82        d.state = PROGRESS_STOPPED;
83        d.length = 0;
84        d.data = 0;
85        d.punched = 0;
86       
87        d.papertape = GTK_PAPER_TAPE(gtk_paper_tape_new(window));
88       
89        d.progress_bar = gtk_progress_bar_new();
90       
91        #define PUNCHER_FRONTEND_FAST_LABEL(a) { d.a = gtk_label_new("x"); \
92                gtk_label_set_selectable(GTK_LABEL(d.a), TRUE); }
93        PUNCHER_FRONTEND_FAST_LABEL(progress_holes_total);
94        PUNCHER_FRONTEND_FAST_LABEL(progress_holes_punched);
95        PUNCHER_FRONTEND_FAST_LABEL(progress_holes_todo);
96        PUNCHER_FRONTEND_FAST_LABEL(progress_total_time);
97        PUNCHER_FRONTEND_FAST_LABEL(progress_estimated_time);
98        PUNCHER_FRONTEND_FAST_LABEL(progress_elapsed_time);
99        PUNCHER_FRONTEND_FAST_LABEL(progress_time_per_hole);
100        PUNCHER_FRONTEND_FAST_LABEL(progress_frequency);
101
102        d.button_start = gtk_button_new_with_mnemonic(_("Punch!")); 
103        gtk_button_set_image(GTK_BUTTON(d.button_start),
104                gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
105
106        d.button_pause = gtk_button_new_with_mnemonic(_("Pause")); 
107        gtk_button_set_image(GTK_BUTTON(d.button_pause),
108                gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_BUTTON));
109
110        d.button_stop = gtk_button_new_with_mnemonic(_("Stop")); 
111        gtk_button_set_image(GTK_BUTTON(d.button_stop),
112                gtk_image_new_from_stock(GTK_STOCK_MEDIA_STOP, GTK_ICON_SIZE_BUTTON));
113
114        d.timer = g_timer_new();
115}
116
117void puncher_frontend_progress_set() {
118        /**
119         * set information about holes
120         *
121         **/
122        gtk_label_set_markup(GTK_LABEL(d.progress_holes_total),
123                g_markup_printf_escaped("Loecher: <b>%3d</b>", d.length)
124        );
125        gtk_label_set_markup(GTK_LABEL(d.progress_holes_punched),
126                g_markup_printf_escaped("Gestanzt: <b>%3d</b>", d.punched)
127        );
128        gtk_label_set_markup(GTK_LABEL(d.progress_holes_todo),
129                g_markup_printf_escaped("Zu Stanzen: <b>%4d</b>", d.length - d.punched)
130        );
131}
132
133gboolean puncher_frontend_puncher_start(GtkWidget *start_widget, gpointer nada) {
134        /**
135         * The callback for the "start punching" button. This will prepare
136         * the gui, prepare observing and progress functions and of course
137         * this will start the low level punching driver.
138         **/
139       
140        // set the values
141        d.state = PROGRESS_RUNNING;
142       
143        // prepare the gui
144        gtk_widget_set_sensitive(d.button_start, FALSE);
145        gtk_widget_set_sensitive(d.button_pause, TRUE);
146        gtk_widget_set_sensitive(d.button_stop, TRUE);
147        gtk_widget_set_sensitive(d.progress_bar, TRUE);
148       
149        // start the progress indicators:
150        //g_timer_start(d.timer);
151        //g_timeout_add(1000, progress_update_time, NULL);
152        // kein Sinn - regelmaessig nach jedem punch machen!
153       
154        // start the punching loop
155        puncher_frontend_punch_loop();
156}
157
158gboolean puncher_frontend_punch_loop() {
159        /**
160         * The Punch main loop, as the gui drives it.
161         * Returns success or not (FALSE).
162         **/
163       
164        int x;
165       
166        for(x = 0; x < d.length; x++) {
167                puncher_frontend_progress_set();
168                puncher_frontend_progress_update_time();
169                gtk_paper_tape_set_highlight(d.papertape, x, TRUE); // TRUE: Abhängig von Checkbox!
170                UPDATE_GTK_GUI;
171                puncher_backend_write_byte(d.backend, d.data[x]);
172                d.punched++;
173        }
174       
175        gtk_paper_tape_remove_highlight(d.papertape);
176        return TRUE;
177}
178
179gboolean puncher_frontend_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 puncher_frontend_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 puncher_frontend_quit_application(GtkWidget *window, gpointer *nada) {
257        puncher_backend_destroy(d.backend);
258        exit(0);
259        // on window close: manage punching interaction!!
260}
261
262int main(int argc, char *argv[]) {
263        GtkWidget *window, *widget, *main_box, *tape_box, *punch_box, *statusbar;
264        gtk_init(&argc, &argv);
265       
266        // main window generation
267        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
268        gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);
269        gtk_window_set_title(GTK_WINDOW(window), _("Papertape Puncher"));
270        g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(puncher_frontend_quit_application), NULL);
271       
272        // above-main-box generation (contains menubar + mainbox)
273        puncher_frontend_prepare(window);
274        widget = gtk_vbox_new(FALSE, 0);
275        gtk_container_add(GTK_CONTAINER(window), widget);
276       
277        // menus generation start
278        {
279                GtkWidget *menu, *menubar, *menuitem;
280                // menus
281                menubar = gtk_menu_bar_new();
282                gtk_box_pack_start(GTK_BOX(widget), menubar, FALSE, TRUE, 0);
283                gtk_widget_show(menubar);
284       
285                // FIRST menu: File {{{
286                menu = gtk_menu_new();
287                // Oeffnen
288                g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_OPEN)),
289                        "activate", G_CALLBACK(puncher_frontend_open_file_dialog), d.papertape);
290                fast_menu_seperator(menu);
291                gtk_paper_tape_menu_export(d.papertape, menu);
292                fast_menu_seperator(menu);
293                g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_QUIT)),
294                        "activate", G_CALLBACK(gtk_main_quit), NULL);
295       
296                menuitem = gtk_menu_item_new_with_mnemonic("_Datei");
297                gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
298                gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
299                gtk_widget_show (menuitem);
300       
301                // Zweites Menue: Ansicht
302                menu = gtk_menu_new();
303                gtk_paper_tape_menu_view(d.papertape, menu);
304       
305                menuitem = gtk_menu_item_new_with_mnemonic("_Ansicht");
306                gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
307                gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
308                gtk_widget_show (menuitem);
309       
310                // Drittes Menue: Farben
311                menu = gtk_menu_new();
312                gtk_paper_tape_menu_colors(d.papertape, menu);
313       
314                menuitem = gtk_menu_item_new_with_mnemonic("_Farben");
315                gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
316                gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
317                gtk_widget_show (menuitem);
318        }
319        // menus end
320       
321        // main box generation
322        main_box = gtk_vbox_new(FALSE, 0);
323        gtk_container_set_border_width(GTK_CONTAINER(main_box), 10);
324        gtk_container_add(GTK_CONTAINER(widget), main_box);
325       
326        // tape box generation
327        widget = gtk_frame_new("udo-14.06.2008-generated-file.bin");
328        gtk_box_pack_start(GTK_BOX(main_box), widget, TRUE, TRUE, 0);
329        tape_box = GTK_WIDGET(gtk_paper_tape_get_whole_box(d.papertape));
330        gtk_container_set_border_width(GTK_CONTAINER(tape_box), 10);
331        gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(d.papertape->statusbar), FALSE);
332        gtk_container_add(GTK_CONTAINER(widget), tape_box);
333
334        // punch box generation
335        widget = gtk_frame_new(_("Punching controls"));
336        gtk_box_pack_start(GTK_BOX(main_box), widget, FALSE, TRUE, 0);
337        punch_box = gtk_vbox_new(FALSE, 0);
338        gtk_container_set_border_width(GTK_CONTAINER(punch_box), 10);
339        gtk_container_add(GTK_CONTAINER(widget), punch_box);
340       
341        // fill punch box:
342        {
343                GtkWidget *label;
344                GtkWidget *holes_box, *progress_box, *button_box;
345               
346                holes_box = gtk_hbox_new(FALSE, 0);
347                gtk_container_add(GTK_CONTAINER(punch_box), holes_box);
348               
349                gtk_container_add(GTK_CONTAINER(holes_box), d.progress_holes_total);
350                gtk_container_add(GTK_CONTAINER(holes_box), d.progress_holes_punched);
351                gtk_container_add(GTK_CONTAINER(holes_box), d.progress_holes_todo);
352
353                progress_box = gtk_hbox_new(FALSE, 0);
354                gtk_container_add(GTK_CONTAINER(punch_box), progress_box);
355               
356                /*label = gtk_label_new("Fortschritt: ");
357                gtk_container_add(GTK_CONTAINER(progress_box), label);*/
358               
359                gtk_box_pack_start(GTK_BOX(progress_box), d.progress_bar, TRUE, TRUE, 0);
360               
361                label = gtk_label_new("Zeit: ");
362                gtk_container_add(GTK_CONTAINER(progress_box), label);
363                gtk_container_add(GTK_CONTAINER(progress_box), d.progress_estimated_time);
364                gtk_container_add(GTK_CONTAINER(progress_box), d.progress_elapsed_time);
365               
366                // Button boxes
367                button_box = gtk_hbutton_box_new();
368                gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_START);
369                gtk_container_add(GTK_CONTAINER(punch_box), button_box);
370               
371                gtk_container_add(GTK_CONTAINER(button_box), d.button_start);
372                g_signal_connect(G_OBJECT(d.button_start), "clicked", G_CALLBACK(puncher_frontend_puncher_start), NULL);
373                gtk_container_add(GTK_CONTAINER(button_box), d.button_pause);
374                gtk_container_add(GTK_CONTAINER(button_box), d.button_stop);
375        }
376
377        // parse command options
378        {
379                char *filename = NULL;
380                gboolean read_from_stdin = FALSE;
381                GError *error = NULL;
382                GOptionContext *context;
383                byte_t show_mystart = 0; // eigene Startprozedur anzeigen?
384                GOptionEntry option_entries[] = {
385                        { "filename", 'f', 0, G_OPTION_ARG_FILENAME, &filename, _("file to open"), NULL },
386                        { "stdin", 's', 0, G_OPTION_ARG_NONE, &read_from_stdin, _("read from standard input"), NULL },
387                        { NULL }
388                };
389
390                context = g_option_context_new(_(" - GtkPaperTape visualisation"));
391                g_option_context_add_main_entries(context, option_entries, NULL);
392                g_option_context_add_group(context, gtk_get_option_group(TRUE));
393                g_option_context_parse(context, &argc, &argv, &error);
394
395                if(read_from_stdin) {
396                        printf(_("%s: Reading data from standard input, will open window after EOF.\n"), argv[0]);
397                        byte_t *data;
398                        int length = file_get_contents(stdin, &data);
399                        gtk_paper_tape_set_data(d.papertape, length, data);
400                } else if(filename != NULL) {
401                        // eine Datei einlesen
402                        printf(_("Reading from file '%s'\n"), filename);
403                        if(!gtk_paper_tape_read_from_file(d.papertape, argv[1])) {
404                                printf(_("Failed to read from file!\n"));
405                                return 1;
406                        }
407                }
408        }
409        // end of parsing command options
410       
411        // showing the main window
412        gtk_widget_show_all(window);
413       
414        // Initialisation of the backend
415        d.backend = puncher_backend_new(1);
416       
417        if(!d.backend) {
418                perror("backend init");
419                GtkWidget *error;
420                error = gtk_message_dialog_new (GTK_WINDOW(window),
421                        GTK_DIALOG_DESTROY_WITH_PARENT,
422                        GTK_MESSAGE_ERROR,
423                        GTK_BUTTONS_OK,
424                        "Error while initializing backend! Quitting!",
425                        "dumy");
426                gtk_dialog_run (GTK_DIALOG (error));
427                gtk_widget_destroy (error);
428                return 1;
429        }
430
431        gtk_main();
432        return 0;
433}
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