source: projects/visualisator/gtk-ohne-widget.c @ 3

Last change on this file since 3 was 3, checked in by sven, 16 years ago

Das Lochstreifenvisualisierungsprogramm wurde komplett umgeschrieben. Die
Datei gtkprogram.c wurde aufgeteilt in ein neues Objekt, GtkPaperTape,
welches alle Zeichenoperationen mit dem Lowlevel-Objekt LOCHSTREIFEN
abgleicht sowie zahlreiche GUI-Menues und aehnliches zur Verfuegung stellt.
Letztlich sieht die Verzeichnisstruktur jetzt so aus:

  • lochstreifen.c, lochstreifen.h: Das LOCHSTREIFEN Cairo-Zeichenobjekt
  • gtkpapertape.c, gtkpapertape.h: Das GtkPaperTape GTK-Widget
  • gtk.c: Ein GTK-Programm, welches das GtkPaperTape-Widget in einem Fenster anzeigt.
  • cli.c: Ein Kommandozeilenprogramm, welches ein Kommandozeileninterface (per Aufrufparameter) fuer das LOCHSTREIFEN-Objekt bietet
File size: 14.6 KB
Line 
1/**
2 * GTK-Programm, welches mit dem per Cairo gezeichneten Lochstreifen
3 * Dateien visualisieren kann.
4 *
5 * Dabei wird die Flexibilitaet des Cairo-Zeichners voll ausgeschoepft:
6 * Beliebige Dateien koennen zum Anzeigen geoeffnet werden, der Loch-
7 * streifen kann in saemtlichen Farben frei variiert werden, die
8 * anzuzeigenden Emptybytes koennen beliebig gesetzt werden.
9 * Die Darstellung kann jederzeit in jede Richtung gedreht und gespiegelt
10 * werden, ausserdem ist stufenloser Zoom sowie eine automatische
11 * Groessenanpassung moeglich, sodass der Lochstreifen sich immer genau an die
12 * Fenstergroesse anpasst und man sinnvoll einfach ueber die Daten "scrollen"
13 * kann.
14 *
15 * Die aktuelle Ansicht des Lochstreifens kann einfach als PNG-Bild oder
16 * SVG-Vektorgrafik in eine Datei exportiert werden. Die Aenderung der Datei
17 * à la "Hexeditor" ist nicht vorgesehen, dafuer werden aber beim Ueberfahren
18 * des Lochstreifens in der Statusleiste die Werte des Bytes, ueber dem man
19 * sich befindet, aufgeschluesselt.
20 *
21 * Das Programm ist bewusst unaufdringlich gehalten; die meisten Nachrichten
22 * werden ueber die Statuszeile ausgegeben. Die Bedienung erfolgt massgeblich
23 * ueber das Menue.
24 *
25 * Je nach Kommandozeilenparameter wird von STDIN gelesen oder eine Datei
26 * geoeffnet (mehr Informationen mit Aufruf --help).
27 * Wird gar kein Parameter angegeben, dann wird eine kleine Startanimation
28 * angezeigt, die von der Perfomance und Flexibilitaet des Zeichenprogramms
29 * zeugt ;-)
30 *
31 * -- Sven, November 2007
32 *
33 **/
34#include <stdio.h>
35#include <stdlib.h>
36#include <math.h> // rint()
37#include <string.h> // strlen()
38#include <gtk/gtk.h>
39#include "gtkpapertape.h"
40
41#include <time.h> // NUR WAEHREND DEBUGGING
42
43#define WINDOW_TITLE "Lochstreifen-Visualisierung" /* Standardtitel */
44
45// Muss leider global sein, damit ein Zugriff von mehreren Funktionen moeglich ist
46GtkWidget *window; // Hauptfenster
47GTimer *last_statusbar_update; // fuer Statusbar-Prioritaetenbehandlung
48GtkWidget *fit_screen_toggle; // Auswahlbox im Ansichtmenue, um Autozoom umzuschalten.
49gboolean startsequence_running = FALSE; // Ist TRUE, wenn die Startanimation laeuft
50
51// Die Daten, die bei der Startsequenz angezeigt werden, liegen hier als Bytearray
52// vor. Generierung mit
53// $ [generatorprogramm] | hexdump -e '11/1 "0x%02x, " "\n"'
54// "0x  , "-Zeichen wegschneiden.
55// Laenge feststellen mit wc -c
56
57int startsequence_length = 205;
58byte_t startsequence_data[] = {
590xfc, 0x01, 0x02, 0x01, 0xfc, 0x00, 0x81, 0xff, 0x81, 0x00, 0xff,
600x01, 0x01, 0x00, 0xff, 0x01, 0x01, 0x00, 0xff, 0x18, 0xc7, 0x00,
610xff, 0x81, 0xff, 0x00, 0xff, 0x80, 0x60, 0x80, 0xff, 0x00, 0xff,
620x80, 0x60, 0x80, 0xff, 0x00, 0xff, 0x91, 0x91, 0x00, 0xff, 0x40,
630x3c, 0x02, 0xff, 0x00, 0x00, 0x00, 0x83, 0xb9, 0xc1, 0x00, 0xff,
640x01, 0xff, 0x00, 0xff, 0x80, 0x60, 0x80, 0xff, 0x00, 0x00, 0x00,
650x81, 0xff, 0x81, 0x00, 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0x80,
660xff, 0x80, 0x00, 0xff, 0x91, 0x91, 0x00, 0xff, 0x88, 0xf7, 0x00,
670xff, 0x88, 0x88, 0xff, 0x00, 0xff, 0x18, 0xc7, 0x00, 0x80, 0xff,
680x80, 0x00, 0x81, 0xff, 0x81, 0x00, 0xfc, 0x01, 0xfc, 0x00, 0xff,
690x91, 0x91, 0x00, 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0x00, 0x00,
700xff, 0x01, 0x01, 0x00, 0xff, 0x81, 0xff, 0x00, 0xff, 0x81, 0x81,
710x00, 0xff, 0x10, 0xff, 0x00, 0xf0, 0x91, 0x9f, 0x00, 0x80, 0xff,
720x80, 0x00, 0xff, 0x88, 0xf7, 0x00, 0xff, 0x91, 0x91, 0x00, 0x81,
730xff, 0x81, 0x00, 0xff, 0x90, 0x90, 0x00, 0xff, 0x91, 0x91, 0x00,
740xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0x83, 0xb9, 0xc1, 0x00, 0xff,
750x91, 0x91, 0x00, 0x81, 0xff, 0x81, 0x00, 0xff, 0x81, 0x81, 0x00,
760xff, 0x10, 0xff, 0x00, 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0xff,
770x91, 0x91, 0x00, 0xff, 0x88, 0xf7, 0x00
78};
79
80// zum Testen:
81/*int startsequence_length = 4;
82byte_t startsequence_data[] = { 0x00, 0x01, 0x02, 0x03 };*/
83
84void message_statusbar(char *msg);
85void message_error(gchar *heading, gchar *text);
86
87
88gboolean open_lochstreifen_file(char *filename) {
89    /**
90     * Oeffnet die gewuenschte Datei.
91     * Bei Fehler wird FALSE zurueckgegeben
92     **/
93     int length; gchar *data;
94     gboolean ret;
95     GError *err;
96
97     ret = g_file_get_contents(filename, &data, &length, &err);
98
99     if(ret == FALSE) {
100          message_error("Fehler beim Oeffnen",
101              g_strdup_printf("Konnte die Datei '%s' nicht oeffnen: %s", filename,
102                  err->message)
103          );
104          return;
105     }
106
107     if(startsequence_running) {
108         // Startsequenz (wenn Programm ohne Lochstreifendatei gestartet wird) laeuft noch
109         // beenden, in dem startsequence_running auf FALSE gesetzt wird.
110         startsequence_running = FALSE;
111     }
112
113     lochstreifen_set_data(lochstreifen, length, (byte_t *)data, -1, -1);
114     message_statusbar("Die Datei wurde geoeffnet.");
115     gtk_window_set_title(GTK_WINDOW (window),
116         g_strdup_printf("%s - %s", basename(filename), WINDOW_TITLE)
117    );
118
119     // Neuzeichnen, usw.
120     redraw_lochstreifen(TRUE);
121}
122
123gboolean open_lochstreifen_file_dialog(GtkWidget *widget, GtkWidget *parentWindow) {
124    /**
125     * Zeigt den Datei-Oeffnen-Dialog an (als Callback-Funktion fuer das Datei-Menue)
126     *
127     *
128     **/
129    GtkWidget *chooser;
130    chooser = gtk_file_chooser_dialog_new(
131        "(Binaer-)datei zur Darstellung als Lochstreifen auswaehlen",
132        GTK_WINDOW(parentWindow),
133        GTK_FILE_CHOOSER_ACTION_OPEN,
134        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
135        GTK_STOCK_OPEN, GTK_RESPONSE_OK,
136        NULL);
137    if(gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) {
138        char *filename;
139        FILE *file;
140
141        filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (chooser));
142        if(filename == NULL) {
143            message_error("Keine Datei geoeffnet.", NULL);
144            gtk_widget_destroy(GTK_WIDGET(chooser));
145            return FALSE;
146        }
147
148        /*file = fopen(filename, "r");
149        if(file == NULL) {
150            message_error("Fehler beim Oeffnen",
151                g_strdup_printf("Konnte die Datei '%s' nicht oeffnen: %s", filename,
152                    g_strerror (errno))
153            );
154            return;
155        }
156        open_lochstreifen_file(file);*/
157        open_lochstreifen_file(filename);
158        g_free(filename);
159    }
160    gtk_widget_destroy(chooser);
161    return FALSE;
162}
163
164void message_error(gchar *heading, gchar *text) {
165    GtkWidget *dialog;
166    dialog = gtk_message_dialog_new(GTK_WINDOW(window),
167        GTK_DIALOG_MODAL,
168        GTK_MESSAGE_ERROR,
169        GTK_BUTTONS_OK,
170        heading);
171    if(text != NULL) gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), text);
172    gtk_dialog_run(GTK_DIALOG(dialog));
173    gtk_widget_destroy(GTK_WIDGET(dialog));
174}
175
176
177gboolean startup_sequence_loop(gpointer state) { //real_data_length) {
178    // siehe startup_sequence
179    //int state = *((int *)state_pointer);
180
181    // Schleife wird deaktiviert, in dem startsequence_running auf false gesetzt wird.
182    if(!startsequence_running)
183        return FALSE;
184
185    if(*((int*)state) <= startsequence_length) {
186        lochstreifen->data++; // Zeiger zeigt aufs naechse Byte
187        *((int*)state) += 1;
188    } else {
189        lochstreifen->data -= startsequence_length;
190        *((int*)state) = 0;
191    }
192
193
194    // einfach erst mal die Lochstreifendaten um eins verschieben.
195    /*if(lochstreifen->data_length < length) {
196        lochstreifen->data_length++;
197    }*/
198    /*
199    byte_t buf;
200    int x;
201    for(x = 1; x < lochstreifen->data_length;x++) {
202        buf = lochstreifen->data[x-1];
203        lochstreifen->data[x-1] = lochstreifen->data[x];
204        lochstreifen->data[x] = buf;
205    }*/
206
207    // neuzeichnen.
208    redraw_lochstreifen(TRUE);
209    printf("Neugezeichnet.\n");
210
211    return TRUE;
212    // true zurueckgeben, wenns weitergehen soll.
213}
214
215gboolean startup_sequence(GtkWidget *widget, gpointer datas) {
216    /**
217     * Die kleine "Startup-Sequenz" wird gezeigt, wenn es keine Daten anzuzeigen gibt.
218     * Dabei scrollt ein Text (eigene Darstellung) als Lochstreifen durch die Gegend.
219     *
220     **/
221    // Integer, um aktuelle Position zu speichern
222    int *state = malloc(sizeof(int));
223    *state = 0;
224    // Array mit gerade 2x Datenarray hintereinander erstellen.
225    byte_t *bufdata = malloc(startsequence_length*2); // Buffer mit doppelter Laenge erstellen
226    memcpy(bufdata, startsequence_data, startsequence_length); // Bufarray fuellen
227    memcpy(bufdata+startsequence_length, startsequence_data, startsequence_length); // und ein zweites mal
228    /*int x;
229    byte_t *data = malloc(sizeof(byte_t)*256);
230    for(x=0;x<256;x++) {
231        data[x] = (byte_t) (255-x);
232    }
233    */
234
235    /*int length_ = 256;
236    for(x=0; x<length_; x++) {
237        printf("%i von %i: 0x%x (=%c)\n", x, length_, data[x], data[x]);
238    }*/
239
240    lochstreifen_set_data(lochstreifen, startsequence_length, bufdata, 0, 0); // schon mal den ersten Wert.
241    //*length = 256;
242    g_timeout_add(1000, startup_sequence_loop, state); //length); // zur Main Loop hinzufuegen.
243    return FALSE;
244}
245
246int main(int argc, char *argv[]) {
247    GtkWidget *mainbox;
248    GtkWidget *menubar, *menuitem, *menu;
249    GtkSizeGroup *color_sizes; // Damit Farbmenue einheitlich aussieht
250    GtkWidget *scroll;
251    GtkWidget *statusbar;
252    lochstreifen = lochstreifen_new(); // muss hier bereit zugewiesen werden weil benutzt
253
254    gtk_init (&argc, &argv);
255
256    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
257    gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
258    gtk_window_set_title(GTK_WINDOW (window), WINDOW_TITLE);
259    g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
260
261    mainbox = gtk_vbox_new(FALSE, 0);
262    gtk_container_add(GTK_CONTAINER (window), mainbox);
263    gtk_widget_show(mainbox);
264
265    statusbar = gtk_statusbar_new(); // erst nach Inhaltswidget hinzufuegen
266    lochstreifen_statusbar = statusbar; // quick & dirty global machen...
267
268    /* Menü */
269    menubar = gtk_menu_bar_new();
270    gtk_box_pack_start (GTK_BOX (mainbox), menubar, FALSE, TRUE, 0);
271    gtk_widget_show(menubar);
272
273    // Erstes Menue: Datei
274    menu = gtk_menu_new();
275    // Oeffnen
276    g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_OPEN)),
277        "activate", G_CALLBACK(open_lochstreifen_file_dialog), window);
278    fast_menu_seperator(menu);
279    gtk_paper_tape_menu_export(menu);
280    fast_menu_seperator(menu);
281    g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_QUIT)),
282        "activate", G_CALLBACK(gtk_main_quit), NULL);
283
284    menuitem = gtk_menu_item_new_with_mnemonic("_Datei");
285    gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
286    gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
287    gtk_widget_show (menuitem);
288
289    // Zweites Menue: Ansicht
290    menu = gtk_menu_new();
291    gtk_paper_tape_menu_view(menu);
292
293    menuitem = gtk_menu_item_new_with_mnemonic("_Ansicht");
294    gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
295    gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
296    gtk_widget_show (menuitem);
297
298    // Drittes Menue: Farben
299    menu = gtk_menu_new();
300    gtk_paper_tape_menu_colors(menu);
301
302    menuitem = gtk_menu_item_new_with_mnemonic("_Farben");
303    gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
304    gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
305    gtk_widget_show (menuitem);
306
307
308
309    // Daten einlesen.
310    {
311        char *filename = NULL;
312        gboolean read_from_stdin = FALSE;
313        gboolean no_splash = FALSE;
314        GError *error = NULL;
315        GOptionContext *context;
316        byte_t show_mystart = 0; // eigene Startprozedur anzeigen?
317        GOptionEntry option_entries[] = {
318           { "filename", 'f', 0, G_OPTION_ARG_FILENAME, &filename, "Datei zu oeffnen", NULL },
319           { "stdin", 's', 0, G_OPTION_ARG_NONE, &read_from_stdin, "Von Standardeingabe lesen", NULL },
320           { "no-splash", 'n', 0, G_OPTION_ARG_NONE, &no_splash,   "Keine Startanimation anzeigen, wenn ohne Datei gestartet", NULL },
321           { NULL }
322        };
323
324        context = g_option_context_new(" - Lochstreifenvisualisierung");
325        g_option_context_add_main_entries(context, option_entries, NULL);
326        g_option_context_add_group(context, gtk_get_option_group(TRUE));
327        g_option_context_parse(context, &argc, &argv, &error);
328
329        if(read_from_stdin) {
330            printf("%s: Lese Daten von Standardeingabe, erst nach EOF wird Fenster geoeffnet.\n",argv[0]);
331            byte_t *data;
332            int length = file_get_contents(stdin, &data);
333            lochstreifen_set_data(lochstreifen, length, data, 6, 6);
334        } else if(filename != NULL) {
335             // eine Datei einlesen
336             printf("Von Datei %s lesen\n", filename);
337             if(!open_lochstreifen_file(argv[1]))
338                 show_mystart = 1;
339        } else if(!no_splash) {
340            // Splash (=Start)-Sequenz anzeigen
341            show_mystart = 1;
342        }
343
344        // Daten wurde eingelesen -- oder auch nicht:
345        if(show_mystart != 0) {
346            g_signal_connect_after(G_OBJECT(window), "show", G_CALLBACK(startup_sequence), NULL);
347            startsequence_running = show_mystart;
348        } else startsequence_running = FALSE;
349    }
350
351    papertape = gtk_paper_tape_new();
352    gtk_box_pack_start(GTK_BOX(mainbox), papertape->scroll, TRUE, TRUE, 0);
353
354    /// signal für Statusbar verbinden zu lokaler Funktion!
355
356    // Statusbar hinzufuegen.
357    // Ich haette ja gerne eine maechtigere Statusbar, aber das geht wohl
358    // leider nicht. Ein paar Versuche, das Label dort wenigstens Pango-Formatierungs-Faehig
359    // zu machen:
360    /*gtk_container_forall(GTK_CONTAINER(statusbar), G_CALLBACK(fast_nicer_statusbar), NULL);
361    gboolean fast_nicer_statusbar(GtkWidget *statusbar_child, gpointer egal) {
362        GList *children;
363        gpointer child;
364        children = gtk_container_get_children(GTK_CONTAINER(statusbar));
365       
366        gtk_container_forall                (GtkContainer *container,
367                                                         GtkCallback callback,
368                                                         gpointer callback_data);
369       
370        //printf("Checke Kindelement von statusbar (%d)\n", g_list_length(children));
371        //while((child = g_list_next(children)) != NULL) {
372            if(GTK_IS_LABEL(statusbar_child)) {
373                printf("LABEL GEFUNDEN!\n");
374                gtk_label_set_use_markup(GTK_LABEL(statusbar_child), TRUE); // :-)
375            }
376            printf("Fand ein %s-Objekt.\n", G_OBJECT_TYPE_NAME(statusbar_child));
377        //}
378        //printf("Fertig.\n");
379    }    */
380    gtk_box_pack_start(GTK_BOX(mainbox), statusbar, FALSE, TRUE, 0);
381    gtk_widget_show(statusbar);
382
383    // TEST DEBUG:
384    //gtk_widget_set_redraw_on_allocate(lochstreifen_widget, TRUE);
385    //gtk_widget_set_double_buffered(lochstreifen_widget, FALSE);
386
387    gtk_widget_show(window);
388    gtk_main();
389    return 0;
390}
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