Changeset 3 in projects
- Timestamp:
- Jul 19, 2008, 2:16:27 PM (15 years ago)
- Location:
- visualisator
- Files:
-
- 2 added
- 1 deleted
- 4 edited
- 1 copied
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
visualisator/Makefile
r1 r3 12 12 gcc -o binary $(CAIROFLAGS) create-image.c $(BACKEND) 13 13 14 gtk: gtk program.c $(BACKEND)15 gcc -o gtkprogram $(GTKFLAGS) gtkp rogram.c $(BACKEND)14 gtk: gtk.c $(BACKEND) 15 gcc -o gtkprogram $(GTKFLAGS) gtkpapertape.c gtk.c $(BACKEND) 16 16 17 17 -
visualisator/gtk-ohne-widget.c
r1 r3 37 37 #include <string.h> // strlen() 38 38 #include <gtk/gtk.h> 39 #include " lochstreifen.h"39 #include "gtkpapertape.h" 40 40 41 41 #include <time.h> // NUR WAEHREND DEBUGGING … … 45 45 // Muss leider global sein, damit ein Zugriff von mehreren Funktionen moeglich ist 46 46 GtkWidget *window; // Hauptfenster 47 GtkWidget *lochstreifen_widget, *lochstreifen_statusbar; // Widget, das Lochstreifen haelt, Statusleiste48 LOCHSTREIFEN *lochstreifen; // das Lochstreifen-Objekt49 47 GTimer *last_statusbar_update; // fuer Statusbar-Prioritaetenbehandlung 50 48 GtkWidget *fit_screen_toggle; // Auswahlbox im Ansichtmenue, um Autozoom umzuschalten. … … 87 85 void message_error(gchar *heading, gchar *text); 88 86 89 GtkWidget *fast_stock_menuitem(const GtkWidget *parentmenu, const gchar *stock_id) {90 /* erzeugt schnell mal ein menuitem mit dem entsprechenden Stock-Dingsda91 und gibt es zurueck */92 GtkWidget *menuitem;93 menuitem = gtk_image_menu_item_new_from_stock(stock_id, NULL);94 gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);95 gtk_widget_show (menuitem);96 return menuitem;97 }98 99 GtkWidget *fast_menuitem(const GtkWidget *parentmenu, const gchar *label) {100 /* erzeugt schnell mal ein menuitem mit der entsprechenden Beschriftung und gibts101 zurueck */102 GtkWidget *menuitem;103 menuitem = gtk_menu_item_new_with_label(label);104 gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);105 gtk_widget_show (menuitem);106 return menuitem;107 }108 109 110 GtkWidget *fast_menu_tearoff(const GtkWidget *parentmenu) {111 /* Schnell mal ein Abreissitem hinzufuegen */112 GtkWidget *menuitem;113 menuitem = gtk_tearoff_menu_item_new ();114 gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);115 gtk_widget_show (menuitem);116 return menuitem;117 }118 119 GtkWidget *fast_menu_seperator(const GtkWidget *parentmenu) {120 /* Schnell einen Seperator */121 GtkWidget *menuitem;122 menuitem = gtk_separator_menu_item_new();123 gtk_menu_shell_append(GTK_MENU_SHELL(parentmenu), menuitem);124 gtk_widget_show(menuitem);125 return menuitem;126 }127 128 void redraw_lochstreifen(gboolean i_have_resized_the_lochstreifen) {129 /**130 * Zentrale Funktion zum Aufrufen um den Lochstreifen manuell neu131 * zu zeichnen. Wenn der Parameter TRUE ist, wird signalisiert,132 * dass die Groesse des Lochstreifens sich (wie auch immer) geaendert133 * hat (neue Daten, Zoom, etc. pp) -- also wird ggf. ein neues134 * size request abgesetzt, je nach Zoomeinstellungen (Autozoom!)135 **/136 if(i_have_resized_the_lochstreifen) {137 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle))) {138 // Lochstreifengroesse wird automatisch dem Fenster angepasst,139 // dafuer werden die size requests anders gestellt, damit kein nervender140 // Scrollbalken fuer die angepasste Dimension kommt.141 // siehe transform_fit_lochstreifen142 if(lochstreifen_get_orientation(lochstreifen) == 1)143 // Mindestdimensionen: Breite festgelegt durch Daten, Hoehe variabel144 gtk_widget_set_size_request(lochstreifen_widget, lochstreifen_get_width(lochstreifen), -1);145 else146 gtk_widget_set_size_request(lochstreifen_widget, -1, lochstreifen_get_height(lochstreifen));147 } else {148 // Lochstreifengroesse wird nicht automatisch dem Fenster angepasst.149 // Ganz normal Breite und Hoehe wuenschen.150 gtk_widget_set_size_request(lochstreifen_widget, // neue Groesse erfordern.151 lochstreifen_get_width(lochstreifen),152 lochstreifen_get_height(lochstreifen));153 }154 } // i have resized...155 gtk_widget_queue_draw(lochstreifen_widget); // neuzeichnen.156 }157 158 gboolean export_lochstreifen(GtkWidget *widget, gchar *format) {159 cairo_surface_t *surface;160 cairo_t *cr;161 cairo_status_t status;162 GtkWidget *chooser;163 char *filename;164 165 // gewuenschten Dateinamen kriegen166 chooser = gtk_file_chooser_dialog_new(167 g_strdup_printf("Dateiname fuer %s-Export auswaehlen", format),168 GTK_WINDOW(window),169 GTK_FILE_CHOOSER_ACTION_SAVE,170 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,171 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,172 NULL);173 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser), TRUE);174 175 if(gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) {176 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));177 }178 gtk_widget_destroy(chooser);179 180 lochstreifen_flush_only_start_area(lochstreifen); // damit der ganze Lochstreifen gezeichnet wird, vgl. expose_lochstreifen181 if(strcmp(format, "PNG") == 0) {182 // PNG erstellen183 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,184 lochstreifen_get_width(lochstreifen),185 lochstreifen_get_height(lochstreifen)186 );187 cr = cairo_create(surface);188 lochstreifen_draw(lochstreifen, cr);189 status = cairo_surface_write_to_png (surface, filename);190 message_statusbar(191 g_strdup_printf("PNG-Datei (%d x %d Pixel, 24bit) wurde exportiert: %s",192 lochstreifen_get_width(lochstreifen),193 lochstreifen_get_height(lochstreifen),194 cairo_status_to_string(status))195 );196 } else if(strcmp(format, "SVG") == 0) {197 // SVG erstellen198 double width,height;199 // SVG-Surface erwartet Breite in Punkt, 1pt = 1/72 inch200 width = 72 * lochstreifen_get_width(lochstreifen) / (double)fast_get_dpi();201 height = 72 * lochstreifen_get_height(lochstreifen) / (double)fast_get_dpi();202 // irgendwie spinnt der Compiler und meint ohne den folgenden unsinnigen203 // exipliten Typcastings "Warnung: Zuweisung erzeugt Zeiger von Ganzzahl ohne Typkonvertierung"204 surface = (cairo_surface_t *)cairo_svg_surface_create((char*)filename, (double)width, (double)height);205 206 cr = cairo_create(surface);207 lochstreifen_draw(lochstreifen, cr);208 209 message_statusbar(210 g_strdup_printf("SVG-Datei (%.2f x %.2f Punkt) wurde exportiert: %s",211 width, height,212 cairo_status_to_string(cairo_surface_status(surface))213 )214 );215 } else {216 message_statusbar("Gewuenschter Exporttyp nicht feststellbar!");217 }218 219 cairo_surface_destroy(surface);220 cairo_destroy(cr);221 g_free(filename);222 }223 224 gboolean null_bytes_dialog (GtkWidget *widget, gpointer data) {225 GtkWidget *dialog, *table, *input_start, *input_end, *label;226 GtkWidget *box;227 228 dialog = gtk_message_dialog_new(GTK_WINDOW(window),229 GTK_DIALOG_DESTROY_WITH_PARENT,230 GTK_MESSAGE_QUESTION,231 GTK_BUTTONS_OK_CANCEL,232 "Nullbytes");233 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),234 "Am Anfang und am Ende der angezeigten Datei koennen\n"235 "zusaetzliche \"virtuelle\" Nullbytes angezeigt werden,\n"236 "die in der Datei nicht gespeichert sind. Je nach Farbeinstellung\n"237 "sieht man nur Fuehrungsloecher - damit sieht der\n"238 "Lochstreifen realistischer aus.");239 240 input_start = gtk_spin_button_new_with_range(0., 10000., 1.);241 gtk_spin_button_set_value(GTK_SPIN_BUTTON(input_start), (gdouble)lochstreifen->empty_start);242 input_end = gtk_spin_button_new_with_range(0., 10000., 1.);243 gtk_spin_button_set_value(GTK_SPIN_BUTTON(input_end), (gdouble)lochstreifen->empty_end);244 245 box = gtk_table_new(2, 2, FALSE);246 gtk_table_set_row_spacings(GTK_TABLE(box), 5);247 label = gtk_label_new("Nullbytes am Anfang: ");248 gtk_table_attach_defaults(GTK_TABLE(box), label,249 0, 1, 0, 1);250 gtk_table_attach_defaults(GTK_TABLE(box), input_start,251 1, 2, 0, 1);252 label = gtk_label_new("Nullbytes am Ende: ");253 gtk_table_attach_defaults(GTK_TABLE(box), label,254 0, 1, 1, 2);255 gtk_table_attach_defaults(GTK_TABLE(box), input_end,256 1, 2, 1, 2);257 258 gtk_container_add(GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),259 box);260 gtk_widget_show_all (dialog);261 262 if(gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {263 lochstreifen->empty_start = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(input_start));264 lochstreifen->empty_end = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(input_end));265 message_statusbar(266 g_strdup_printf("Vorne werden nun %d Nullbytes angezeigt, hinten %d.",267 lochstreifen->empty_start, lochstreifen->empty_end)268 );269 270 redraw_lochstreifen(TRUE);271 } else272 message_statusbar("Anzahl der Nullbytes wurde nicht veraendert.");273 gtk_widget_destroy (dialog);274 }275 276 gboolean expose_lochstreifen(GtkWidget *widget, GdkEventExpose *event, gpointer data) {277 /* Calllback für das "expose_event" - Zeichenevent */278 cairo_t *cr;279 time_t TIME;280 time(&TIME);281 //LOCHSTREIFEN *l;282 283 // mal testen:284 gdk_window_clear_area(widget->window,285 event->area.x, event->area.y, event->area.width, event->area.height);286 287 cr = gdk_cairo_create(widget->window);288 //l = (LOCHSTREIFEN *)data;289 290 printf("%d Neuzeichnen: x|y = (%d|%d), width*height = %d * %d\n", TIME,291 event->area.x, event->area.y,292 event->area.width, event->area.height);293 // Clipping, um das Neuzeichnen zu beschleunigen. Ist das sinnvoll?294 /*cairo_rectangle (cr,295 event->area.x, event->area.y,296 event->area.width, event->area.height);297 cairo_clip (cr);*/298 299 300 lochstreifen_set_only_start_area(lochstreifen,301 event->area.x, event->area.y,302 event->area.width, event->area.height);303 304 lochstreifen_draw(lochstreifen, cr);305 /*printf("Fertig (real width*height = %d * %d)\n", lochstreifen_get_width(lochstreifen),306 lochstreifen_get_height(lochstreifen));307 */308 cairo_destroy(cr);309 return FALSE;310 }311 312 int fast_get_dpi() {313 /**314 * Mal schnell die Aufloesung als Ganzzahl zurueckgeben.315 * Der Rueckgabewert gibt also die Anzahl der Pixel an, die auf dem Monitor316 * einen Zoll breit sein sollten...317 **/318 GdkScreen *screen = gdk_screen_get_default();319 if(screen == NULL) {320 printf("Konnte GdkScreen zwecks DPI-Auslesung nicht erkennen!\n");321 return;322 }323 324 gdouble dpi = gdk_screen_get_resolution(screen);325 if(dpi < 0) {326 printf("Screenresolution (%f) nicht feststellbar\n", dpi);327 return;328 }329 return (int)rint(dpi); // noch sauber runden.330 }331 332 gboolean transform_fit_lochstreifen(GtkWidget *widget, GdkEventConfigure *event, gpointer data) {333 // Bei Groessenveraenderungen des Lochstreifenwidgets wird dies334 // aufgerufen, wenn "an Bildschirmgroesse anpassen" gewuenscht ist335 336 // Das Scrollwidget davon unterrichten, nur noch in einer Richtung zu scrollen, damit337 // es beim Verkleinern des Fensters nicht meint, genug Platz zu haben und sich die Lochstreifen-338 // groesse gar nicht anpasst.339 // muss bloederweise hier gemacht werden, weil man ja nachtraeglich die Ausrichtung des340 // Lochstreifens aendern koennte.341 int orientation = lochstreifen_get_orientation(lochstreifen); // 1 = horizontal342 343 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtk_widget_get_parent(gtk_widget_get_parent(lochstreifen_widget))),344 orientation == 1 ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER,345 orientation == 1 ? GTK_POLICY_NEVER : GTK_POLICY_AUTOMATIC);346 347 // Mindestgroessenberechnungen nach redraw_lochstreifen verlagert.348 if(lochstreifen_get_orientation(lochstreifen) == 1) {349 // horizontal ausgerichteter Lochstreifen => Hoehe fixieren.350 lochstreifen_set_d_by_height(lochstreifen, event->height);351 // Mindestdimensionssetzen verlagert nach redraw_lochstreifen,352 // damit nicht Datengroessenaenderung die Sachen wieder kaputtmachen353 // Mindestdimensionen: Breite festgelegt durch Daten, Hoehe variabel354 } else {355 // vertikal ausgerichtet => Breite fixieren356 lochstreifen_set_d_by_width(lochstreifen, event->width);357 // set size request verschoben nach redraw_lochstreifen, siehe oben358 }359 360 redraw_lochstreifen(TRUE);361 return FALSE;362 }363 364 void transform_lochstreifen(GtkWidget *widget, gpointer data) {365 char action = *((char *)data);366 char *status_comment;367 byte_t status_type = 0; // 0 = nix ersetzen, 1 = Ansicht in % einsetzen, 2 = Drehausrichtung einsetzen368 if(action == '+') {369 lochstreifen_set_d(lochstreifen, lochstreifen->d + 3); // vergroessern370 status_comment = "Ansicht vergroessert auf %d%%";371 status_type = 1;372 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle), FALSE); // nicht automatisch anpassen373 } else if(action == '-') {374 if(lochstreifen->d - 3 < 1) {375 message_statusbar("Der Lochstreifen kann nicht kleiner gezeichnet werden!");376 return;377 }378 lochstreifen_set_d(lochstreifen, lochstreifen->d - 3); // verkleinern379 status_comment = "Ansicht verkleinert auf %d%%";380 status_type = 1;381 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle), FALSE); // nicht automatisch anpassen382 } else if(action == '=') { // 100% = "Lebensgroesse2383 lochstreifen_set_d(lochstreifen, (int)rint((float)fast_get_dpi()/(float)16)); // ein Loch ist etwa 1/16 Zoll breit384 status_comment = "Wirkliche Lebensgroesse eingestellt (kann bei falscher Monitoreinstellung abweichen)";385 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle), FALSE); // nicht automatisch anpassen386 } else if(action == '[') { // an Bildschirmgroesse anpassen387 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {388 // Checkbox wurde aktiviert389 g_signal_connect(G_OBJECT(lochstreifen_widget), "configure_event", G_CALLBACK(transform_fit_lochstreifen), NULL);390 // den Container resizen damit die erste Anpassung inkraft tritt391 gtk_widget_queue_resize_no_redraw(lochstreifen_widget); // neugezeichnet wird unten.392 status_comment = "Lochstreifen passt sich nun stets dem Anzeigebereich an";393 } else {394 // Checkbox wurde deaktiviert395 g_signal_handlers_disconnect_by_func(G_OBJECT(lochstreifen_widget), G_CALLBACK(transform_fit_lochstreifen), NULL);396 // Scrollwidget wieder zuruecksetzen.397 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtk_widget_get_parent(gtk_widget_get_parent(lochstreifen_widget))),398 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);399 400 return;401 // nichts ausgeben, weil auch durch andere Sachen aufgerufen402 }403 } else if(action == 'S') { // Statusleiste einblenden/ausblenden404 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {405 // Checkbox wurde aktiviert406 gtk_widget_show(lochstreifen_statusbar);407 status_comment = "Statusleiste wird (wieder) angezeigt.";408 } else gtk_widget_hide(lochstreifen_statusbar);409 } else if(action == '>') { // Drehen mit Uhrzeigersinn410 //lochstreifen_rotate(lochstreifen);411 lochstreifen_set_direction(lochstreifen, 4, -1,-1);412 status_comment = "Lochstreifen im Uhrzeigersinn gedreht (%s)";413 status_type = 2;414 } else if(action == '<') { // Drehen gegen Uhrzeigersinn415 lochstreifen_set_direction(lochstreifen, 5, -1,-1);416 status_comment = "Lochstreifen gegen Uhrzeigersinn gedreht (%s)";417 status_type = 2;418 } else if(action == '_') { // horizontal Spiegeln419 lochstreifen_set_direction(lochstreifen, -1, 2, -1);420 status_comment = "Lochstreifen wurde vertikal gespiegelt (Datenreihenfolge umgedreht, d.h. links und rechts vertauscht)";421 } else if(action == '|') { // vertikal spiegeln422 lochstreifen_set_direction(lochstreifen, -1, -1, 2);423 status_comment = "Lochstreifen wurde horizontal gespiegelt (unten und oben vertauscht)";424 }425 redraw_lochstreifen(TRUE);426 427 // Ausgaben fuer Statuszeile vorbereiten428 if(status_comment == NULL || strlen(status_comment) == 0) return; // gibt nichts zu sagen429 if(status_type == 1) {430 // % von realer Groesse angeben.431 message_statusbar(432 g_strdup_printf(status_comment, (int)((float)lochstreifen->d / ((float)fast_get_dpi()/(float)16) * 100)) // siehe action=='='433 );434 } else if(status_type == 2) {435 // Ausrichtung angeben als String436 char *ausrichtung;437 switch(lochstreifen->drehung) {438 case 0: ausrichtung = "horizontal, von links nach rechts"; break;439 case 1: ausrichtung = "vertikal, von oben nach unten"; break;440 case 2: ausrichtung = "horizontal, von rechts nach links"; break;441 case 3: ausrichtung = "vertikal, von unten nach oben"; break;442 default: ausrichtung = "*** ERROR - ungueltige Ausrichtung";443 }444 message_statusbar(445 g_strdup_printf(status_comment, ausrichtung)446 );447 } else // status_type == 0448 message_statusbar(status_comment);449 }450 451 void change_constant_gui(GtkWidget *widget, gpointer data) {452 // GUI zur Aenderung der Konstanten anzeigen...453 printf("Pending...\n");454 }455 456 GdkColor *color_cairo2gdk(cairo_pattern_t *pattern);457 87 458 88 gboolean open_lochstreifen_file(char *filename) { … … 544 174 } 545 175 546 void colorize_lochstreifen(GtkWidget *widget, gpointer data) {547 cairo_pattern_t **target = (cairo_pattern_t **)data; // Doppellink noetig weil Adressaenderung548 GdkColor color;549 gtk_color_button_get_color(GTK_COLOR_BUTTON(widget), &color);550 /*double red, green, blue;551 printf("Farben gewaehlt: R=%i G=%i B=%i\n",color.red, color.green, color.blue);552 red = ((double)color.red / (double)G_MAXUINT16); // G_MAXUINT16 = 2^16 weil Farben = guint16553 green = ((double)color.green / (double)G_MAXUINT16);554 blue = ((double)color.blue / (double)G_MAXUINT16);555 556 printf("Farben == R=%f G=%f B=%f\n",557 red,green,blue);*/558 559 //if(*target != NULL) cairo_pattern_destroy(*target); // damit nicht sinnlos Speicher zugemuellt wird560 *target = cairo_pattern_create_rgb(561 // darauf muss man erst mal kommen: Vorher in double casten, denn sonst562 // berechnet er einen unsigned short (=guint16), der einfach auf 0 ab oder563 // auf 1 hochrundet. (double)(guint16/G_MAXUNIT16) gibt also stets 0,000 oder 1,000.564 (double)((double)color.red / (double)G_MAXUINT16), // G_MAXUINT16 = 2^16 weil Farben = guint16565 (double)((double)color.green / (double)G_MAXUINT16),566 (double)((double)color.blue / (double)G_MAXUINT16));567 //printf("%s\n", cairo_status_to_string(cairo_pattern_status(*target)));568 569 GdkColor *g = color_cairo2gdk(*target);570 //printf("Farben zurueck: R=%d G=%d B=%d\n", g->red, g->green, g->blue);571 //gtk_color_button_get_alpha(GTK_COLOR_BUTTON(widget)) / 65535);572 redraw_lochstreifen(FALSE);573 // gtk_color_button_get_alpha(GTK_COLOR_BUTTON(widget)) / 65535);574 575 // noch mal schnell RGB-Wert fuer Statuszeile ausgeben576 message_statusbar(577 g_strdup_printf("Farbe geaendert auf RGB (%d|%d|%d)",578 (int)((double)color.red / (double)G_MAXUINT16 * 255),579 (int)((double)color.red / (double)G_MAXUINT16 * 255),580 (int)((double)color.red / (double)G_MAXUINT16 * 255)581 )582 );583 }584 585 586 GtkWidget *fast_color_menuitem(const GtkWidget *parentmenu, const char *dialog_title, const char *labeltext, GdkColor *initialColor, GtkSizeGroup *label_nice_sizegroup) {587 /* Schnell ein Colorchooser-Button inklusive Richtextlabel in einem588 Menuitem einbauen. Gibt das Colorchooserbutton-Widget zurück,589 initialColor kann NULL sein. GtkSizeGroup auch. */590 GtkWidget *menuitem, *menubox, *colorbutton, *label;591 menuitem = gtk_menu_item_new();592 menubox = gtk_hbox_new(FALSE, 4);593 gtk_container_add(GTK_CONTAINER(menuitem), menubox);594 gtk_widget_show(menubox);595 596 colorbutton = gtk_color_button_new();597 //gtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(colorbutton), TRUE); // doch kein Alpha, das bringt nichts.598 gtk_color_button_set_title(GTK_COLOR_BUTTON(colorbutton), dialog_title);599 gtk_box_pack_start(GTK_BOX(menubox), colorbutton, FALSE, FALSE, 0);600 gtk_widget_show(colorbutton);601 602 label = gtk_label_new(NULL);603 gtk_label_set_markup(GTK_LABEL(label), labeltext);604 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);605 gtk_box_pack_start(GTK_BOX(menubox), label, TRUE, TRUE, 0);606 gtk_widget_show(label);607 608 g_signal_connect_swapped(menuitem, "activate", G_CALLBACK(gtk_button_clicked), colorbutton);609 610 if(initialColor != NULL) {611 //printf("Farben:\n");612 //printf("\tr%i g%i b%i\n", initialColor->red, initialColor->green, initialColor->blue);613 gtk_color_button_set_color(GTK_COLOR_BUTTON(colorbutton), initialColor);614 }615 if(label_nice_sizegroup != NULL) {616 gtk_size_group_add_widget(label_nice_sizegroup, label);617 }618 619 gtk_widget_show (menuitem);620 gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);621 return colorbutton;622 }623 624 GdkColor *color_cairo2gdk(cairo_pattern_t *pattern) {625 /** Kleine Behelfsfunktion, um von einem Cairopattern die Farbe im GDK-format zu ziehen626 ALPHA wird ganz nett ignoriert :) */627 GdkColor *c = malloc(sizeof(GdkColor));628 double red, green, blue, alpha;629 if(pattern != NULL)630 cairo_pattern_get_rgba(pattern, &red, &green, &blue, &alpha);631 else632 { red=1; green=1; blue=1; } // pattern ist NULL => nehmen mir mal weiss ;-)633 c->red = red * 65535; // 2^16634 c->green = green * 65535;635 c->blue = blue * 65535;636 return c;637 }638 176 639 177 gboolean startup_sequence_loop(gpointer state) { //real_data_length) { … … 706 244 } 707 245 708 gboolean update_statusbar(GtkWidget *lochstreifenwidget, GdkEventMotion *event, gpointer egal) {709 /**710 * In der Statuszeile beim Ueberfahren des Lochstreifens die aktuellen711 * Werte anzeigen :-)712 *713 **/714 gchar *msg;715 int x,y,byte;716 717 // erst nach 4 Sekunden einer "wichtigen" Nachricht wieder die Statuszeile718 // mit diesen weniger wichtigen Infos befoelkern.719 if(last_statusbar_update != NULL && g_timer_elapsed(last_statusbar_update, NULL) < 4) return;720 721 // Statuszeile auf jeden Fall leeren.722 gtk_statusbar_pop(GTK_STATUSBAR(lochstreifen_statusbar), 0);723 byte = lochstreifen_byte_by_coordinate(lochstreifen, (int)event->x, (int)event->y);724 if(byte > 0) {725 gchar *msg; byte_t value,bit;726 value = lochstreifen->data[byte-1]; // weil ab 1 zaehlen => -1 weil array ab 0 zaehlt727 728 // Bitdarstellung selbst machen (printf hat sowas wohl nicht)729 char bitdarstellung[9]; bitdarstellung[8] = '\0'; // Nullterminierung730 for(bit=0; bit<8; bit++) {bitdarstellung[bit] = (((value >> bit) & 0x01) == 0x01) ? '1':'0';}731 732 msg = g_strdup_printf("Byte %03d von %03d: Wert dez=%03d bin=%s okt=%03o hex=%02X",733 byte, lochstreifen->data_length,734 value, bitdarstellung, value, value);735 gtk_statusbar_push(GTK_STATUSBAR(lochstreifen_statusbar), 0, msg);736 g_free(msg);737 } else if(byte == 0) {738 //gtk_statusbar_push(statusbar, 0, "Zeiger befindet sich außerhalb");739 // Zeiger befindet sich ausserhalb. Nichts hier ausgeben.740 // d.h. Statusbar wurde exiplit geleert und bleibt leer.741 } else if(byte == -1) {742 gtk_statusbar_push(GTK_STATUSBAR(lochstreifen_statusbar), 0,743 "Mauszeiger befindet sich auf den zusaetzlichen Nullbytes.");744 }745 746 return FALSE;747 }748 749 void message_statusbar(char *msg) {750 /**751 * Kurze Nachrichten in der Statuszeile anzeigen.752 * Diese Nachrichten bleiben mindestens 4 Sekunden lang sichtbar, bevor z.B.753 * die Position des Mauscursors wieder erscheint. Dafuer dient der Timer.754 **/755 gtk_statusbar_pop(GTK_STATUSBAR(lochstreifen_statusbar), 0);756 gtk_statusbar_push(GTK_STATUSBAR(lochstreifen_statusbar), 0, msg);757 // Statusbar-Timer erst hier einrichten, damit nach Programmstart man nicht758 // erst 4 Sekunden warten muss.759 if(last_statusbar_update == NULL)760 last_statusbar_update = g_timer_new(); // wird automatisch gestartet761 else762 g_timer_start(last_statusbar_update); // Timer zuruecksetzen763 }764 765 gboolean scroll_lochstreifen(GtkWidget *lochstreifenwidget, GdkEventScroll *event, gpointer user_data) {766 /**767 Beim Scrollen auf dem Widget wird das GTK_SCROLLED_WINDOW (user_data) gescrollt, je nach768 Ausrichtung des Streifens. Nur eindimensionales Scrolling, nicht 2d. (wer hat schon eine769 Apple Mighty Mouse ;-) )770 **/771 GtkAdjustment* adjustment;772 gdouble t;773 if(lochstreifen->drehung % 2 == 0) {774 // Lochstreifen ist horizontal ausgreichtet775 adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(user_data));776 if(adjustment == NULL) { printf("hadjustment = NULL!\n"); return FALSE; }777 t = gtk_adjustment_get_value(adjustment) + lochstreifen->d * // um eine Lochbreite scrollen778 ((event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) ? -1 : 1);779 // nach rechts oder links scrollen780 /* );781 printf("Set to %f\n", gtk_adjustment_get_value(adjustment) + (gdouble)adjustment->step_increment *782 (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) ? (gdouble)1 : (gdouble)-1);*/783 } else {784 // nach oben bzw. unten scrollen785 adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(user_data));786 if(adjustment == NULL) { printf("vadjustment = NULL!\n"); return FALSE; }787 t = gtk_adjustment_get_value(adjustment) + lochstreifen->d *788 ((event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) ? -1 : 1);789 // nach oben oder unten scrollen790 }791 printf("Scroll Is: %f | up: %f | down: %f | shall be: %f\n", gtk_adjustment_get_value(adjustment), adjustment->lower, adjustment->upper, t);792 793 if(t < adjustment->lower) t = adjustment->lower;794 if(t > adjustment->upper) t = adjustment->upper;795 gtk_adjustment_set_value(adjustment, t);796 // geht nicht:797 //g_signal_emit_by_name(lochstreifen_widget, "motion-notify-event"); // Mauszeigerbewegung simulieren => Statuszeile updaten798 }799 800 246 int main(int argc, char *argv[]) { 801 247 GtkWidget *mainbox; … … 831 277 "activate", G_CALLBACK(open_lochstreifen_file_dialog), window); 832 278 fast_menu_seperator(menu); 833 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Grafik als PNG exportieren...")), 834 "activate", G_CALLBACK(export_lochstreifen), "PNG"); 835 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Grafik als SVG exportieren...")), 836 "activate", G_CALLBACK(export_lochstreifen), "SVG"); 279 gtk_paper_tape_menu_export(menu); 837 280 fast_menu_seperator(menu); 838 281 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_QUIT)), … … 846 289 // Zweites Menue: Ansicht 847 290 menu = gtk_menu_new(); 848 fast_menu_tearoff(menu); 849 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_IN)), 850 "activate", G_CALLBACK(transform_lochstreifen), "+"); 851 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_OUT)), 852 "activate", G_CALLBACK(transform_lochstreifen), "-"); 853 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_100)), 854 "activate", G_CALLBACK(transform_lochstreifen), "="); 855 //g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_FIT)), 856 // "activate", G_CALLBACK(transform_lochstreifen), "["); 857 menuitem = gtk_check_menu_item_new_with_mnemonic("Groesse dem Fenster _anpassen"); 858 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), FALSE); 859 g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(transform_lochstreifen), "["); 860 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); 861 gtk_widget_show (menuitem); 862 fit_screen_toggle = menuitem; // auch hier global speichern, weil es in einer Funktion gebraucht wird. 863 864 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_PROPERTIES)), //"Groessenverhaeltnisse aendern...")), 865 "activate", G_CALLBACK(change_constant_gui), NULL); 866 fast_menu_seperator(menu); 867 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Drehen im Uhrzeigersinn")), 868 "activate", G_CALLBACK(transform_lochstreifen), ">"); 869 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Drehen gegen den Uhrzeigersinn")), 870 "activate", G_CALLBACK(transform_lochstreifen), "<"); 871 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Horizontal spiegeln (Datenreihenfolge umkehren)")), 872 "activate", G_CALLBACK(transform_lochstreifen), "|"); 873 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Vertikal spiegeln (Bitpositionen drehen)")), 874 "activate", G_CALLBACK(transform_lochstreifen), "_"); 875 fast_menu_seperator(menu); 876 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Anzahl Nullbytes einstellen...")), 877 "activate", G_CALLBACK(null_bytes_dialog), NULL); 878 menuitem = gtk_check_menu_item_new_with_mnemonic("_Statusleiste anzeigen"); 879 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE); 880 g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(transform_lochstreifen), "S"); 881 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); 882 gtk_widget_show (menuitem); 291 gtk_paper_tape_menu_view(menu); 883 292 884 293 menuitem = gtk_menu_item_new_with_mnemonic("_Ansicht"); … … 889 298 // Drittes Menue: Farben 890 299 menu = gtk_menu_new(); 891 color_sizes = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); 892 fast_menu_tearoff(menu); 893 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe des Lochstreifens waehlen", 894 "Farbe des <b>Lochstreifens</b>", color_cairo2gdk(lochstreifen->streifenbg), color_sizes)), 895 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->streifenbg)); 896 //gtk_color_button_set_color(GTK_COLOR_BUTTON(menuitem), color_cairo2gdk(lochstreifen->streifenbg)); 897 898 fast_menu_seperator(menu); 899 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Loecher waehlen", 900 "Farbe der <b>Loecher</b> waehlen\n(binaere einsen)", color_cairo2gdk(lochstreifen->punched), color_sizes)), 901 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->punched)); 902 fast_menu_seperator(menu); 903 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Nicht-Loecher waehlen", 904 "Farbe der <b>Nullen</b> waehlen\n(nicht gelochte Bits)", color_cairo2gdk(lochstreifen->notpunched), color_sizes)), 905 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->notpunched)); 906 fast_menu_seperator(menu); 907 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Lochstreifen-Fuehrungsloecher waehlen", 908 "Farbe der <b>Fuehrungs-loecher</b>\nwaehlen (kleine Loecher)", color_cairo2gdk(lochstreifen->fuehrung), color_sizes)), 909 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->fuehrung)); 910 fast_menu_seperator(menu); 911 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Hintergrund waehlen", 912 "<b>Hintergrundfarbe</b> waehlen\n(um dem Streifen rum)", color_cairo2gdk(lochstreifen->hintergrund), color_sizes)), 913 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->hintergrund)); 300 gtk_paper_tape_menu_colors(menu); 914 301 915 302 menuitem = gtk_menu_item_new_with_mnemonic("_Farben"); … … 918 305 gtk_widget_show (menuitem); 919 306 920 // So jetzt aber Inhalt: Das Hauptwidget. 921 lochstreifen_set_d(lochstreifen, 20); 307 922 308 923 309 // Daten einlesen. … … 963 349 } 964 350 965 lochstreifen_widget = gtk_drawing_area_new(); 966 gtk_widget_set_size_request (GTK_WIDGET (lochstreifen_widget), 967 lochstreifen_get_width(lochstreifen), 968 lochstreifen_get_height(lochstreifen)); // erst mal spasseshalber 969 970 scroll = gtk_scrolled_window_new(NULL, NULL); 971 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), lochstreifen_widget); // weil nicht scrollable 972 // Scrollbalken nur anzeigen wenn benoetigt 973 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 974 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_NONE); 975 gtk_box_pack_start(GTK_BOX(mainbox), scroll, TRUE, TRUE, 0); 976 gtk_widget_show(scroll); 977 978 gtk_widget_show(lochstreifen_widget); 979 g_signal_connect(G_OBJECT(lochstreifen_widget), "expose_event", G_CALLBACK(expose_lochstreifen), NULL); 980 gtk_widget_add_events(lochstreifen_widget, GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK); // Mauscursor kriegen, Mausscrolling kriegen 981 g_signal_connect(G_OBJECT(lochstreifen_widget), "motion-notify-event", G_CALLBACK(update_statusbar), NULL); 982 g_signal_connect(G_OBJECT(lochstreifen_widget), "scroll-event", G_CALLBACK(scroll_lochstreifen), scroll); 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! 983 355 984 356 // Statusbar hinzufuegen. -
visualisator/gtk.c
r1 r3 1 1 /** 2 * GTK-Programm, welches mit dem per Cairo gezeichneten Lochstreifen3 * Dateien visualisieren kann.2 * A simple example GTK program which uses all features of the GtkPaperTape 3 * widget in one window. No extra features, except of: 4 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. 5 * * handling of command line options by using the glib parser, thus 6 * * being able to read from stdin or any files 7 * * menu item to open files in the GUI 14 8 * 15 * Die aktuelle Ansicht des Lochstreifens kann einfach als PNG-Bild oder16 * SVG-Vektorgrafik in eine Datei exportiert werden. Die Aenderung der Datei17 * à la "Hexeditor" ist nicht vorgesehen, dafuer werden aber beim Ueberfahren18 * des Lochstreifens in der Statusleiste die Werte des Bytes, ueber dem man19 * sich befindet, aufgeschluesselt.20 9 * 21 * Das Programm ist bewusst unaufdringlich gehalten; die meisten Nachrichten 22 * werden ueber die Statuszeile ausgegeben. Die Bedienung erfolgt massgeblich 23 * ueber das Menue. 10 * rewritten on 21.06.2008 24 11 * 25 * Je nach Kommandozeilenparameter wird von STDIN gelesen oder eine Datei26 * geoeffnet (mehr Informationen mit Aufruf --help).27 * Wird gar kein Parameter angegeben, dann wird eine kleine Startanimation28 * angezeigt, die von der Perfomance und Flexibilitaet des Zeichenprogramms29 * zeugt ;-)30 *31 * -- Sven, November 200732 12 * 33 13 **/ 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 "lochstreifen.h"40 41 #include <time.h> // NUR WAEHREND DEBUGGING42 43 #define WINDOW_TITLE "Lochstreifen-Visualisierung" /* Standardtitel */44 45 // Muss leider global sein, damit ein Zugriff von mehreren Funktionen moeglich ist46 GtkWidget *window; // Hauptfenster47 GtkWidget *lochstreifen_widget, *lochstreifen_statusbar; // Widget, das Lochstreifen haelt, Statusleiste48 LOCHSTREIFEN *lochstreifen; // das Lochstreifen-Objekt49 GTimer *last_statusbar_update; // fuer Statusbar-Prioritaetenbehandlung50 GtkWidget *fit_screen_toggle; // Auswahlbox im Ansichtmenue, um Autozoom umzuschalten.51 gboolean startsequence_running = FALSE; // Ist TRUE, wenn die Startanimation laeuft52 53 // Die Daten, die bei der Startsequenz angezeigt werden, liegen hier als Bytearray54 // vor. Generierung mit55 // $ [generatorprogramm] | hexdump -e '11/1 "0x%02x, " "\n"'56 // "0x , "-Zeichen wegschneiden.57 // Laenge feststellen mit wc -c58 59 int startsequence_length = 205;60 byte_t startsequence_data[] = {61 0xfc, 0x01, 0x02, 0x01, 0xfc, 0x00, 0x81, 0xff, 0x81, 0x00, 0xff,62 0x01, 0x01, 0x00, 0xff, 0x01, 0x01, 0x00, 0xff, 0x18, 0xc7, 0x00,63 0xff, 0x81, 0xff, 0x00, 0xff, 0x80, 0x60, 0x80, 0xff, 0x00, 0xff,64 0x80, 0x60, 0x80, 0xff, 0x00, 0xff, 0x91, 0x91, 0x00, 0xff, 0x40,65 0x3c, 0x02, 0xff, 0x00, 0x00, 0x00, 0x83, 0xb9, 0xc1, 0x00, 0xff,66 0x01, 0xff, 0x00, 0xff, 0x80, 0x60, 0x80, 0xff, 0x00, 0x00, 0x00,67 0x81, 0xff, 0x81, 0x00, 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0x80,68 0xff, 0x80, 0x00, 0xff, 0x91, 0x91, 0x00, 0xff, 0x88, 0xf7, 0x00,69 0xff, 0x88, 0x88, 0xff, 0x00, 0xff, 0x18, 0xc7, 0x00, 0x80, 0xff,70 0x80, 0x00, 0x81, 0xff, 0x81, 0x00, 0xfc, 0x01, 0xfc, 0x00, 0xff,71 0x91, 0x91, 0x00, 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0x00, 0x00,72 0xff, 0x01, 0x01, 0x00, 0xff, 0x81, 0xff, 0x00, 0xff, 0x81, 0x81,73 0x00, 0xff, 0x10, 0xff, 0x00, 0xf0, 0x91, 0x9f, 0x00, 0x80, 0xff,74 0x80, 0x00, 0xff, 0x88, 0xf7, 0x00, 0xff, 0x91, 0x91, 0x00, 0x81,75 0xff, 0x81, 0x00, 0xff, 0x90, 0x90, 0x00, 0xff, 0x91, 0x91, 0x00,76 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0x83, 0xb9, 0xc1, 0x00, 0xff,77 0x91, 0x91, 0x00, 0x81, 0xff, 0x81, 0x00, 0xff, 0x81, 0x81, 0x00,78 0xff, 0x10, 0xff, 0x00, 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0xff,79 0x91, 0x91, 0x00, 0xff, 0x88, 0xf7, 0x0080 };81 82 // zum Testen:83 /*int startsequence_length = 4;84 byte_t startsequence_data[] = { 0x00, 0x01, 0x02, 0x03 };*/85 86 void message_statusbar(char *msg);87 void message_error(gchar *heading, gchar *text);88 89 GtkWidget *fast_stock_menuitem(const GtkWidget *parentmenu, const gchar *stock_id) {90 /* erzeugt schnell mal ein menuitem mit dem entsprechenden Stock-Dingsda91 und gibt es zurueck */92 GtkWidget *menuitem;93 menuitem = gtk_image_menu_item_new_from_stock(stock_id, NULL);94 gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);95 gtk_widget_show (menuitem);96 return menuitem;97 }98 99 GtkWidget *fast_menuitem(const GtkWidget *parentmenu, const gchar *label) {100 /* erzeugt schnell mal ein menuitem mit der entsprechenden Beschriftung und gibts101 zurueck */102 GtkWidget *menuitem;103 menuitem = gtk_menu_item_new_with_label(label);104 gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);105 gtk_widget_show (menuitem);106 return menuitem;107 }108 14 109 15 110 GtkWidget *fast_menu_tearoff(const GtkWidget *parentmenu) { 111 /* Schnell mal ein Abreissitem hinzufuegen */ 112 GtkWidget *menuitem; 113 menuitem = gtk_tearoff_menu_item_new (); 114 gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem); 115 gtk_widget_show (menuitem); 116 return menuitem; 117 } 16 #include <gtk/gtk.h> 17 #include "gtkpapertape.h" 118 18 119 GtkWidget *fast_menu_seperator(const GtkWidget *parentmenu) { 120 /* Schnell einen Seperator */ 121 GtkWidget *menuitem; 122 menuitem = gtk_separator_menu_item_new(); 123 gtk_menu_shell_append(GTK_MENU_SHELL(parentmenu), menuitem); 124 gtk_widget_show(menuitem); 125 return menuitem; 126 } 19 #define _(a) (a) 127 20 128 void redraw_lochstreifen(gboolean i_have_resized_the_lochstreifen) { 129 /** 130 * Zentrale Funktion zum Aufrufen um den Lochstreifen manuell neu 131 * zu zeichnen. Wenn der Parameter TRUE ist, wird signalisiert, 132 * dass die Groesse des Lochstreifens sich (wie auch immer) geaendert 133 * hat (neue Daten, Zoom, etc. pp) -- also wird ggf. ein neues 134 * size request abgesetzt, je nach Zoomeinstellungen (Autozoom!) 135 **/ 136 if(i_have_resized_the_lochstreifen) { 137 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle))) { 138 // Lochstreifengroesse wird automatisch dem Fenster angepasst, 139 // dafuer werden die size requests anders gestellt, damit kein nervender 140 // Scrollbalken fuer die angepasste Dimension kommt. 141 // siehe transform_fit_lochstreifen 142 if(lochstreifen_get_orientation(lochstreifen) == 1) 143 // Mindestdimensionen: Breite festgelegt durch Daten, Hoehe variabel 144 gtk_widget_set_size_request(lochstreifen_widget, lochstreifen_get_width(lochstreifen), -1); 145 else 146 gtk_widget_set_size_request(lochstreifen_widget, -1, lochstreifen_get_height(lochstreifen)); 147 } else { 148 // Lochstreifengroesse wird nicht automatisch dem Fenster angepasst. 149 // Ganz normal Breite und Hoehe wuenschen. 150 gtk_widget_set_size_request(lochstreifen_widget, // neue Groesse erfordern. 151 lochstreifen_get_width(lochstreifen), 152 lochstreifen_get_height(lochstreifen)); 153 } 154 } // i have resized... 155 gtk_widget_queue_draw(lochstreifen_widget); // neuzeichnen. 156 } 21 gboolean open_file_dialog(GtkWidget *menuitem, GtkPaperTape* papertape) { 22 /** 23 * displays an "open file" dialog which runs gtk_paper_tape_read_from_file() if success, 24 * is run by the menu item "open file" 25 **/ 157 26 158 gboolean export_lochstreifen(GtkWidget *widget, gchar *format) { 159 cairo_surface_t *surface; 160 cairo_t *cr; 161 cairo_status_t status; 162 GtkWidget *chooser; 163 char *filename; 27 GtkWidget *chooser; 28 chooser = gtk_file_chooser_dialog_new( 29 _("Select (binary) file to display as a paper tape"), 30 GTK_WINDOW(papertape->parent_window), 31 GTK_FILE_CHOOSER_ACTION_OPEN, 32 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 33 GTK_STOCK_OPEN, GTK_RESPONSE_OK, 34 NULL); 164 35 165 // gewuenschten Dateinamen kriegen 166 chooser = gtk_file_chooser_dialog_new( 167 g_strdup_printf("Dateiname fuer %s-Export auswaehlen", format), 168 GTK_WINDOW(window), 169 GTK_FILE_CHOOSER_ACTION_SAVE, 170 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 171 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, 172 NULL); 173 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser), TRUE); 36 if(gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) { 37 char *filename; 38 FILE *file; 174 39 175 if(gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) { 176 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser)); 177 } 178 gtk_widget_destroy(chooser); 40 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (chooser)); 41 if(filename == NULL) { 42 g_printf(_("No file selected to open.\n")); 43 gtk_widget_destroy(GTK_WIDGET(chooser)); 44 return FALSE; 45 } else { 46 gtk_paper_tape_read_from_file(papertape, filename); 47 g_free(filename); 48 gtk_widget_destroy(GTK_WIDGET(chooser)); 49 return TRUE; 50 } 51 } 52 gtk_widget_destroy(chooser); 53 return FALSE; 54 } // open_file_dialog 179 55 180 lochstreifen_flush_only_start_area(lochstreifen); // damit der ganze Lochstreifen gezeichnet wird, vgl. expose_lochstreifen 181 if(strcmp(format, "PNG") == 0) { 182 // PNG erstellen 183 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 184 lochstreifen_get_width(lochstreifen), 185 lochstreifen_get_height(lochstreifen) 186 ); 187 cr = cairo_create(surface); 188 lochstreifen_draw(lochstreifen, cr); 189 status = cairo_surface_write_to_png (surface, filename); 190 message_statusbar( 191 g_strdup_printf("PNG-Datei (%d x %d Pixel, 24bit) wurde exportiert: %s", 192 lochstreifen_get_width(lochstreifen), 193 lochstreifen_get_height(lochstreifen), 194 cairo_status_to_string(status)) 195 ); 196 } else if(strcmp(format, "SVG") == 0) { 197 // SVG erstellen 198 double width,height; 199 // SVG-Surface erwartet Breite in Punkt, 1pt = 1/72 inch 200 width = 72 * lochstreifen_get_width(lochstreifen) / (double)fast_get_dpi(); 201 height = 72 * lochstreifen_get_height(lochstreifen) / (double)fast_get_dpi(); 202 // irgendwie spinnt der Compiler und meint ohne den folgenden unsinnigen 203 // exipliten Typcastings "Warnung: Zuweisung erzeugt Zeiger von Ganzzahl ohne Typkonvertierung" 204 surface = (cairo_surface_t *)cairo_svg_surface_create((char*)filename, (double)width, (double)height); 56 int main(int argc, char *argv[]) { 57 GtkWidget *window, *mainbox, *statusbar; 58 GtkPaperTape *papertape; 59 gtk_init(&argc, &argv); 60 61 // main window generation 62 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 63 gtk_window_set_default_size(GTK_WINDOW(window), 600, 600); 64 gtk_window_set_title(GTK_WINDOW(window), "GtkPaperTape Demo"); 65 g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); 66 67 // generate main box (menubar + papertape whole widget) 68 mainbox = gtk_vbox_new(FALSE, 0); 69 gtk_container_add(GTK_CONTAINER(window), mainbox); 70 gtk_widget_show(mainbox); 71 72 // main widget generation 73 papertape = GTK_PAPER_TAPE(gtk_paper_tape_new(window)); 74 75 // menus start 76 { 77 GtkWidget *menu, *menubar, *menuitem; 78 // menus 79 menubar = gtk_menu_bar_new(); 80 gtk_box_pack_start(GTK_BOX(mainbox), menubar, FALSE, TRUE, 0); 81 gtk_widget_show(menubar); 82 83 // FIRST menu: File {{{ 84 menu = gtk_menu_new(); 85 // Oeffnen 86 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_OPEN)), 87 "activate", G_CALLBACK(open_file_dialog), papertape); 88 fast_menu_seperator(menu); 89 gtk_paper_tape_menu_export(papertape, menu); 90 fast_menu_seperator(menu); 91 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_QUIT)), 92 "activate", G_CALLBACK(gtk_main_quit), NULL); 93 94 menuitem = gtk_menu_item_new_with_mnemonic("_Datei"); 95 gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu); 96 gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem); 97 gtk_widget_show (menuitem); 98 99 // Zweites Menue: Ansicht 100 menu = gtk_menu_new(); 101 gtk_paper_tape_menu_view(papertape, menu); 102 103 menuitem = gtk_menu_item_new_with_mnemonic("_Ansicht"); 104 gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu); 105 gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem); 106 gtk_widget_show (menuitem); 107 108 // Drittes Menue: Farben 109 menu = gtk_menu_new(); 110 gtk_paper_tape_menu_colors(papertape, menu); 111 112 menuitem = gtk_menu_item_new_with_mnemonic("_Farben"); 113 gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu); 114 gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem); 115 gtk_widget_show (menuitem); 116 } 117 // menus end 205 118 206 cr = cairo_create(surface); 207 lochstreifen_draw(lochstreifen, cr); 208 209 message_statusbar( 210 g_strdup_printf("SVG-Datei (%.2f x %.2f Punkt) wurde exportiert: %s", 211 width, height, 212 cairo_status_to_string(cairo_surface_status(surface)) 213 ) 214 ); 215 } else { 216 message_statusbar("Gewuenschter Exporttyp nicht feststellbar!"); 217 } 218 219 cairo_surface_destroy(surface); 220 cairo_destroy(cr); 221 g_free(filename); 222 } 223 224 gboolean null_bytes_dialog (GtkWidget *widget, gpointer data) { 225 GtkWidget *dialog, *table, *input_start, *input_end, *label; 226 GtkWidget *box; 227 228 dialog = gtk_message_dialog_new(GTK_WINDOW(window), 229 GTK_DIALOG_DESTROY_WITH_PARENT, 230 GTK_MESSAGE_QUESTION, 231 GTK_BUTTONS_OK_CANCEL, 232 "Nullbytes"); 233 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), 234 "Am Anfang und am Ende der angezeigten Datei koennen\n" 235 "zusaetzliche \"virtuelle\" Nullbytes angezeigt werden,\n" 236 "die in der Datei nicht gespeichert sind. Je nach Farbeinstellung\n" 237 "sieht man nur Fuehrungsloecher - damit sieht der\n" 238 "Lochstreifen realistischer aus."); 239 240 input_start = gtk_spin_button_new_with_range(0., 10000., 1.); 241 gtk_spin_button_set_value(GTK_SPIN_BUTTON(input_start), (gdouble)lochstreifen->empty_start); 242 input_end = gtk_spin_button_new_with_range(0., 10000., 1.); 243 gtk_spin_button_set_value(GTK_SPIN_BUTTON(input_end), (gdouble)lochstreifen->empty_end); 244 245 box = gtk_table_new(2, 2, FALSE); 246 gtk_table_set_row_spacings(GTK_TABLE(box), 5); 247 label = gtk_label_new("Nullbytes am Anfang: "); 248 gtk_table_attach_defaults(GTK_TABLE(box), label, 249 0, 1, 0, 1); 250 gtk_table_attach_defaults(GTK_TABLE(box), input_start, 251 1, 2, 0, 1); 252 label = gtk_label_new("Nullbytes am Ende: "); 253 gtk_table_attach_defaults(GTK_TABLE(box), label, 254 0, 1, 1, 2); 255 gtk_table_attach_defaults(GTK_TABLE(box), input_end, 256 1, 2, 1, 2); 257 258 gtk_container_add(GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 259 box); 260 gtk_widget_show_all (dialog); 261 262 if(gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 263 lochstreifen->empty_start = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(input_start)); 264 lochstreifen->empty_end = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(input_end)); 265 message_statusbar( 266 g_strdup_printf("Vorne werden nun %d Nullbytes angezeigt, hinten %d.", 267 lochstreifen->empty_start, lochstreifen->empty_end) 268 ); 269 270 redraw_lochstreifen(TRUE); 271 } else 272 message_statusbar("Anzahl der Nullbytes wurde nicht veraendert."); 273 gtk_widget_destroy (dialog); 274 } 275 276 gboolean expose_lochstreifen(GtkWidget *widget, GdkEventExpose *event, gpointer data) { 277 /* Calllback für das "expose_event" - Zeichenevent */ 278 cairo_t *cr; 279 time_t TIME; 280 time(&TIME); 281 //LOCHSTREIFEN *l; 282 283 // mal testen: 284 gdk_window_clear_area(widget->window, 285 event->area.x, event->area.y, event->area.width, event->area.height); 286 287 cr = gdk_cairo_create(widget->window); 288 //l = (LOCHSTREIFEN *)data; 289 290 printf("%d Neuzeichnen: x|y = (%d|%d), width*height = %d * %d\n", TIME, 291 event->area.x, event->area.y, 292 event->area.width, event->area.height); 293 // Clipping, um das Neuzeichnen zu beschleunigen. Ist das sinnvoll? 294 /*cairo_rectangle (cr, 295 event->area.x, event->area.y, 296 event->area.width, event->area.height); 297 cairo_clip (cr);*/ 298 299 300 lochstreifen_set_only_start_area(lochstreifen, 301 event->area.x, event->area.y, 302 event->area.width, event->area.height); 303 304 lochstreifen_draw(lochstreifen, cr); 305 /*printf("Fertig (real width*height = %d * %d)\n", lochstreifen_get_width(lochstreifen), 306 lochstreifen_get_height(lochstreifen)); 307 */ 308 cairo_destroy(cr); 309 return FALSE; 310 } 311 312 int fast_get_dpi() { 313 /** 314 * Mal schnell die Aufloesung als Ganzzahl zurueckgeben. 315 * Der Rueckgabewert gibt also die Anzahl der Pixel an, die auf dem Monitor 316 * einen Zoll breit sein sollten... 317 **/ 318 GdkScreen *screen = gdk_screen_get_default(); 319 if(screen == NULL) { 320 printf("Konnte GdkScreen zwecks DPI-Auslesung nicht erkennen!\n"); 321 return; 322 } 323 324 gdouble dpi = gdk_screen_get_resolution(screen); 325 if(dpi < 0) { 326 printf("Screenresolution (%f) nicht feststellbar\n", dpi); 327 return; 328 } 329 return (int)rint(dpi); // noch sauber runden. 330 } 331 332 gboolean transform_fit_lochstreifen(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { 333 // Bei Groessenveraenderungen des Lochstreifenwidgets wird dies 334 // aufgerufen, wenn "an Bildschirmgroesse anpassen" gewuenscht ist 335 336 // Das Scrollwidget davon unterrichten, nur noch in einer Richtung zu scrollen, damit 337 // es beim Verkleinern des Fensters nicht meint, genug Platz zu haben und sich die Lochstreifen- 338 // groesse gar nicht anpasst. 339 // muss bloederweise hier gemacht werden, weil man ja nachtraeglich die Ausrichtung des 340 // Lochstreifens aendern koennte. 341 int orientation = lochstreifen_get_orientation(lochstreifen); // 1 = horizontal 342 343 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtk_widget_get_parent(gtk_widget_get_parent(lochstreifen_widget))), 344 orientation == 1 ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER, 345 orientation == 1 ? GTK_POLICY_NEVER : GTK_POLICY_AUTOMATIC); 346 347 // Mindestgroessenberechnungen nach redraw_lochstreifen verlagert. 348 if(lochstreifen_get_orientation(lochstreifen) == 1) { 349 // horizontal ausgerichteter Lochstreifen => Hoehe fixieren. 350 lochstreifen_set_d_by_height(lochstreifen, event->height); 351 // Mindestdimensionssetzen verlagert nach redraw_lochstreifen, 352 // damit nicht Datengroessenaenderung die Sachen wieder kaputtmachen 353 // Mindestdimensionen: Breite festgelegt durch Daten, Hoehe variabel 354 } else { 355 // vertikal ausgerichtet => Breite fixieren 356 lochstreifen_set_d_by_width(lochstreifen, event->width); 357 // set size request verschoben nach redraw_lochstreifen, siehe oben 358 } 359 360 redraw_lochstreifen(TRUE); 361 return FALSE; 362 } 363 364 void transform_lochstreifen(GtkWidget *widget, gpointer data) { 365 char action = *((char *)data); 366 char *status_comment; 367 byte_t status_type = 0; // 0 = nix ersetzen, 1 = Ansicht in % einsetzen, 2 = Drehausrichtung einsetzen 368 if(action == '+') { 369 lochstreifen_set_d(lochstreifen, lochstreifen->d + 3); // vergroessern 370 status_comment = "Ansicht vergroessert auf %d%%"; 371 status_type = 1; 372 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle), FALSE); // nicht automatisch anpassen 373 } else if(action == '-') { 374 if(lochstreifen->d - 3 < 1) { 375 message_statusbar("Der Lochstreifen kann nicht kleiner gezeichnet werden!"); 376 return; 377 } 378 lochstreifen_set_d(lochstreifen, lochstreifen->d - 3); // verkleinern 379 status_comment = "Ansicht verkleinert auf %d%%"; 380 status_type = 1; 381 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle), FALSE); // nicht automatisch anpassen 382 } else if(action == '=') { // 100% = "Lebensgroesse2 383 lochstreifen_set_d(lochstreifen, (int)rint((float)fast_get_dpi()/(float)16)); // ein Loch ist etwa 1/16 Zoll breit 384 status_comment = "Wirkliche Lebensgroesse eingestellt (kann bei falscher Monitoreinstellung abweichen)"; 385 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle), FALSE); // nicht automatisch anpassen 386 } else if(action == '[') { // an Bildschirmgroesse anpassen 387 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) { 388 // Checkbox wurde aktiviert 389 g_signal_connect(G_OBJECT(lochstreifen_widget), "configure_event", G_CALLBACK(transform_fit_lochstreifen), NULL); 390 // den Container resizen damit die erste Anpassung inkraft tritt 391 gtk_widget_queue_resize_no_redraw(lochstreifen_widget); // neugezeichnet wird unten. 392 status_comment = "Lochstreifen passt sich nun stets dem Anzeigebereich an"; 393 } else { 394 // Checkbox wurde deaktiviert 395 g_signal_handlers_disconnect_by_func(G_OBJECT(lochstreifen_widget), G_CALLBACK(transform_fit_lochstreifen), NULL); 396 // Scrollwidget wieder zuruecksetzen. 397 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtk_widget_get_parent(gtk_widget_get_parent(lochstreifen_widget))), 398 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 399 400 return; 401 // nichts ausgeben, weil auch durch andere Sachen aufgerufen 402 } 403 } else if(action == 'S') { // Statusleiste einblenden/ausblenden 404 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) { 405 // Checkbox wurde aktiviert 406 gtk_widget_show(lochstreifen_statusbar); 407 status_comment = "Statusleiste wird (wieder) angezeigt."; 408 } else gtk_widget_hide(lochstreifen_statusbar); 409 } else if(action == '>') { // Drehen mit Uhrzeigersinn 410 //lochstreifen_rotate(lochstreifen); 411 lochstreifen_set_direction(lochstreifen, 4, -1,-1); 412 status_comment = "Lochstreifen im Uhrzeigersinn gedreht (%s)"; 413 status_type = 2; 414 } else if(action == '<') { // Drehen gegen Uhrzeigersinn 415 lochstreifen_set_direction(lochstreifen, 5, -1,-1); 416 status_comment = "Lochstreifen gegen Uhrzeigersinn gedreht (%s)"; 417 status_type = 2; 418 } else if(action == '_') { // horizontal Spiegeln 419 lochstreifen_set_direction(lochstreifen, -1, 2, -1); 420 status_comment = "Lochstreifen wurde vertikal gespiegelt (Datenreihenfolge umgedreht, d.h. links und rechts vertauscht)"; 421 } else if(action == '|') { // vertikal spiegeln 422 lochstreifen_set_direction(lochstreifen, -1, -1, 2); 423 status_comment = "Lochstreifen wurde horizontal gespiegelt (unten und oben vertauscht)"; 424 } 425 redraw_lochstreifen(TRUE); 426 427 // Ausgaben fuer Statuszeile vorbereiten 428 if(status_comment == NULL || strlen(status_comment) == 0) return; // gibt nichts zu sagen 429 if(status_type == 1) { 430 // % von realer Groesse angeben. 431 message_statusbar( 432 g_strdup_printf(status_comment, (int)((float)lochstreifen->d / ((float)fast_get_dpi()/(float)16) * 100)) // siehe action=='=' 433 ); 434 } else if(status_type == 2) { 435 // Ausrichtung angeben als String 436 char *ausrichtung; 437 switch(lochstreifen->drehung) { 438 case 0: ausrichtung = "horizontal, von links nach rechts"; break; 439 case 1: ausrichtung = "vertikal, von oben nach unten"; break; 440 case 2: ausrichtung = "horizontal, von rechts nach links"; break; 441 case 3: ausrichtung = "vertikal, von unten nach oben"; break; 442 default: ausrichtung = "*** ERROR - ungueltige Ausrichtung"; 443 } 444 message_statusbar( 445 g_strdup_printf(status_comment, ausrichtung) 446 ); 447 } else // status_type == 0 448 message_statusbar(status_comment); 449 } 450 451 void change_constant_gui(GtkWidget *widget, gpointer data) { 452 // GUI zur Aenderung der Konstanten anzeigen... 453 printf("Pending...\n"); 454 } 455 456 GdkColor *color_cairo2gdk(cairo_pattern_t *pattern); 457 458 gboolean open_lochstreifen_file(char *filename) { 459 /** 460 * Oeffnet die gewuenschte Datei. 461 * Bei Fehler wird FALSE zurueckgegeben 462 **/ 463 int length; gchar *data; 464 gboolean ret; 465 GError *err; 466 467 ret = g_file_get_contents(filename, &data, &length, &err); 468 469 if(ret == FALSE) { 470 message_error("Fehler beim Oeffnen", 471 g_strdup_printf("Konnte die Datei '%s' nicht oeffnen: %s", filename, 472 err->message) 473 ); 474 return; 475 } 476 477 if(startsequence_running) { 478 // Startsequenz (wenn Programm ohne Lochstreifendatei gestartet wird) laeuft noch 479 // beenden, in dem startsequence_running auf FALSE gesetzt wird. 480 startsequence_running = FALSE; 481 } 482 483 lochstreifen_set_data(lochstreifen, length, (byte_t *)data, -1, -1); 484 message_statusbar("Die Datei wurde geoeffnet."); 485 gtk_window_set_title(GTK_WINDOW (window), 486 g_strdup_printf("%s - %s", basename(filename), WINDOW_TITLE) 487 ); 488 489 // Neuzeichnen, usw. 490 redraw_lochstreifen(TRUE); 491 } 492 493 gboolean open_lochstreifen_file_dialog(GtkWidget *widget, GtkWidget *parentWindow) { 494 /** 495 * Zeigt den Datei-Oeffnen-Dialog an (als Callback-Funktion fuer das Datei-Menue) 496 * 497 * 498 **/ 499 GtkWidget *chooser; 500 chooser = gtk_file_chooser_dialog_new( 501 "(Binaer-)datei zur Darstellung als Lochstreifen auswaehlen", 502 GTK_WINDOW(parentWindow), 503 GTK_FILE_CHOOSER_ACTION_OPEN, 504 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 505 GTK_STOCK_OPEN, GTK_RESPONSE_OK, 506 NULL); 507 if(gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) { 508 char *filename; 509 FILE *file; 510 511 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (chooser)); 512 if(filename == NULL) { 513 message_error("Keine Datei geoeffnet.", NULL); 514 gtk_widget_destroy(GTK_WIDGET(chooser)); 515 return FALSE; 516 } 517 518 /*file = fopen(filename, "r"); 519 if(file == NULL) { 520 message_error("Fehler beim Oeffnen", 521 g_strdup_printf("Konnte die Datei '%s' nicht oeffnen: %s", filename, 522 g_strerror (errno)) 523 ); 524 return; 525 } 526 open_lochstreifen_file(file);*/ 527 open_lochstreifen_file(filename); 528 g_free(filename); 529 } 530 gtk_widget_destroy(chooser); 531 return FALSE; 532 } 533 534 void message_error(gchar *heading, gchar *text) { 535 GtkWidget *dialog; 536 dialog = gtk_message_dialog_new(GTK_WINDOW(window), 537 GTK_DIALOG_MODAL, 538 GTK_MESSAGE_ERROR, 539 GTK_BUTTONS_OK, 540 heading); 541 if(text != NULL) gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), text); 542 gtk_dialog_run(GTK_DIALOG(dialog)); 543 gtk_widget_destroy(GTK_WIDGET(dialog)); 544 } 545 546 void colorize_lochstreifen(GtkWidget *widget, gpointer data) { 547 cairo_pattern_t **target = (cairo_pattern_t **)data; // Doppellink noetig weil Adressaenderung 548 GdkColor color; 549 gtk_color_button_get_color(GTK_COLOR_BUTTON(widget), &color); 550 /*double red, green, blue; 551 printf("Farben gewaehlt: R=%i G=%i B=%i\n",color.red, color.green, color.blue); 552 red = ((double)color.red / (double)G_MAXUINT16); // G_MAXUINT16 = 2^16 weil Farben = guint16 553 green = ((double)color.green / (double)G_MAXUINT16); 554 blue = ((double)color.blue / (double)G_MAXUINT16); 555 556 printf("Farben == R=%f G=%f B=%f\n", 557 red,green,blue);*/ 558 559 //if(*target != NULL) cairo_pattern_destroy(*target); // damit nicht sinnlos Speicher zugemuellt wird 560 *target = cairo_pattern_create_rgb( 561 // darauf muss man erst mal kommen: Vorher in double casten, denn sonst 562 // berechnet er einen unsigned short (=guint16), der einfach auf 0 ab oder 563 // auf 1 hochrundet. (double)(guint16/G_MAXUNIT16) gibt also stets 0,000 oder 1,000. 564 (double)((double)color.red / (double)G_MAXUINT16), // G_MAXUINT16 = 2^16 weil Farben = guint16 565 (double)((double)color.green / (double)G_MAXUINT16), 566 (double)((double)color.blue / (double)G_MAXUINT16)); 567 //printf("%s\n", cairo_status_to_string(cairo_pattern_status(*target))); 568 569 GdkColor *g = color_cairo2gdk(*target); 570 //printf("Farben zurueck: R=%d G=%d B=%d\n", g->red, g->green, g->blue); 571 //gtk_color_button_get_alpha(GTK_COLOR_BUTTON(widget)) / 65535); 572 redraw_lochstreifen(FALSE); 573 // gtk_color_button_get_alpha(GTK_COLOR_BUTTON(widget)) / 65535); 574 575 // noch mal schnell RGB-Wert fuer Statuszeile ausgeben 576 message_statusbar( 577 g_strdup_printf("Farbe geaendert auf RGB (%d|%d|%d)", 578 (int)((double)color.red / (double)G_MAXUINT16 * 255), 579 (int)((double)color.red / (double)G_MAXUINT16 * 255), 580 (int)((double)color.red / (double)G_MAXUINT16 * 255) 581 ) 582 ); 583 } 119 // attach papertape whole widget to mainbox 120 gtk_box_pack_start(GTK_BOX(mainbox), 121 GTK_WIDGET(gtk_paper_tape_get_whole_box(GTK_PAPER_TAPE(papertape))), 122 TRUE, TRUE, 0); 584 123 585 124 586 GtkWidget *fast_color_menuitem(const GtkWidget *parentmenu, const char *dialog_title, const char *labeltext, GdkColor *initialColor, GtkSizeGroup *label_nice_sizegroup) { 587 /* Schnell ein Colorchooser-Button inklusive Richtextlabel in einem 588 Menuitem einbauen. Gibt das Colorchooserbutton-Widget zurück, 589 initialColor kann NULL sein. GtkSizeGroup auch. */ 590 GtkWidget *menuitem, *menubox, *colorbutton, *label; 591 menuitem = gtk_menu_item_new(); 592 menubox = gtk_hbox_new(FALSE, 4); 593 gtk_container_add(GTK_CONTAINER(menuitem), menubox); 594 gtk_widget_show(menubox); 125 // parse command options 126 { 127 char *filename = NULL; 128 gboolean read_from_stdin = FALSE; 129 GError *error = NULL; 130 GOptionContext *context; 131 byte_t show_mystart = 0; // eigene Startprozedur anzeigen? 132 GOptionEntry option_entries[] = { 133 { "filename", 'f', 0, G_OPTION_ARG_FILENAME, &filename, _("file to open"), NULL }, 134 { "stdin", 's', 0, G_OPTION_ARG_NONE, &read_from_stdin, _("read from standard input"), NULL }, 135 { NULL } 136 }; 595 137 596 colorbutton = gtk_color_button_new(); 597 //gtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(colorbutton), TRUE); // doch kein Alpha, das bringt nichts. 598 gtk_color_button_set_title(GTK_COLOR_BUTTON(colorbutton), dialog_title); 599 gtk_box_pack_start(GTK_BOX(menubox), colorbutton, FALSE, FALSE, 0); 600 gtk_widget_show(colorbutton); 138 context = g_option_context_new(_(" - GtkPaperTape visualisation")); 139 g_option_context_add_main_entries(context, option_entries, NULL); 140 g_option_context_add_group(context, gtk_get_option_group(TRUE)); 141 g_option_context_parse(context, &argc, &argv, &error); 601 142 602 label = gtk_label_new(NULL); 603 gtk_label_set_markup(GTK_LABEL(label), labeltext); 604 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); 605 gtk_box_pack_start(GTK_BOX(menubox), label, TRUE, TRUE, 0); 606 gtk_widget_show(label); 143 if(read_from_stdin) { 144 printf(_("%s: Reading data from standard input, will open window after EOF.\n"), argv[0]); 145 byte_t *data; 146 int length = file_get_contents(stdin, &data); 147 gtk_paper_tape_set_data(papertape, length, data); 148 } else if(filename != NULL) { 149 // eine Datei einlesen 150 printf(_("Reading from file '%s'\n"), filename); 151 if(!gtk_paper_tape_read_from_file(papertape, argv[1])) { 152 printf(_("Failed to read from file!\n")); 153 return 1; 154 } 155 } 156 } 157 // end of parsing command options 607 158 608 g_signal_connect_swapped(menuitem, "activate", G_CALLBACK(gtk_button_clicked), colorbutton); 609 610 if(initialColor != NULL) { 611 //printf("Farben:\n"); 612 //printf("\tr%i g%i b%i\n", initialColor->red, initialColor->green, initialColor->blue); 613 gtk_color_button_set_color(GTK_COLOR_BUTTON(colorbutton), initialColor); 614 } 615 if(label_nice_sizegroup != NULL) { 616 gtk_size_group_add_widget(label_nice_sizegroup, label); 617 } 618 619 gtk_widget_show (menuitem); 620 gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem); 621 return colorbutton; 159 gtk_widget_show(window); 160 gtk_main(); 161 return 0; 622 162 } 623 624 GdkColor *color_cairo2gdk(cairo_pattern_t *pattern) {625 /** Kleine Behelfsfunktion, um von einem Cairopattern die Farbe im GDK-format zu ziehen626 ALPHA wird ganz nett ignoriert :) */627 GdkColor *c = malloc(sizeof(GdkColor));628 double red, green, blue, alpha;629 if(pattern != NULL)630 cairo_pattern_get_rgba(pattern, &red, &green, &blue, &alpha);631 else632 { red=1; green=1; blue=1; } // pattern ist NULL => nehmen mir mal weiss ;-)633 c->red = red * 65535; // 2^16634 c->green = green * 65535;635 c->blue = blue * 65535;636 return c;637 }638 639 gboolean startup_sequence_loop(gpointer state) { //real_data_length) {640 // siehe startup_sequence641 //int state = *((int *)state_pointer);642 643 // Schleife wird deaktiviert, in dem startsequence_running auf false gesetzt wird.644 if(!startsequence_running)645 return FALSE;646 647 if(*((int*)state) <= startsequence_length) {648 lochstreifen->data++; // Zeiger zeigt aufs naechse Byte649 *((int*)state) += 1;650 } else {651 lochstreifen->data -= startsequence_length;652 *((int*)state) = 0;653 }654 655 656 // einfach erst mal die Lochstreifendaten um eins verschieben.657 /*if(lochstreifen->data_length < length) {658 lochstreifen->data_length++;659 }*/660 /*661 byte_t buf;662 int x;663 for(x = 1; x < lochstreifen->data_length;x++) {664 buf = lochstreifen->data[x-1];665 lochstreifen->data[x-1] = lochstreifen->data[x];666 lochstreifen->data[x] = buf;667 }*/668 669 // neuzeichnen.670 redraw_lochstreifen(TRUE);671 printf("Neugezeichnet.\n");672 673 return TRUE;674 // true zurueckgeben, wenns weitergehen soll.675 }676 677 gboolean startup_sequence(GtkWidget *widget, gpointer datas) {678 /**679 * Die kleine "Startup-Sequenz" wird gezeigt, wenn es keine Daten anzuzeigen gibt.680 * Dabei scrollt ein Text (eigene Darstellung) als Lochstreifen durch die Gegend.681 *682 **/683 // Integer, um aktuelle Position zu speichern684 int *state = malloc(sizeof(int));685 *state = 0;686 // Array mit gerade 2x Datenarray hintereinander erstellen.687 byte_t *bufdata = malloc(startsequence_length*2); // Buffer mit doppelter Laenge erstellen688 memcpy(bufdata, startsequence_data, startsequence_length); // Bufarray fuellen689 memcpy(bufdata+startsequence_length, startsequence_data, startsequence_length); // und ein zweites mal690 /*int x;691 byte_t *data = malloc(sizeof(byte_t)*256);692 for(x=0;x<256;x++) {693 data[x] = (byte_t) (255-x);694 }695 */696 697 /*int length_ = 256;698 for(x=0; x<length_; x++) {699 printf("%i von %i: 0x%x (=%c)\n", x, length_, data[x], data[x]);700 }*/701 702 lochstreifen_set_data(lochstreifen, startsequence_length, bufdata, 0, 0); // schon mal den ersten Wert.703 //*length = 256;704 g_timeout_add(1000, startup_sequence_loop, state); //length); // zur Main Loop hinzufuegen.705 return FALSE;706 }707 708 gboolean update_statusbar(GtkWidget *lochstreifenwidget, GdkEventMotion *event, gpointer egal) {709 /**710 * In der Statuszeile beim Ueberfahren des Lochstreifens die aktuellen711 * Werte anzeigen :-)712 *713 **/714 gchar *msg;715 int x,y,byte;716 717 // erst nach 4 Sekunden einer "wichtigen" Nachricht wieder die Statuszeile718 // mit diesen weniger wichtigen Infos befoelkern.719 if(last_statusbar_update != NULL && g_timer_elapsed(last_statusbar_update, NULL) < 4) return;720 721 // Statuszeile auf jeden Fall leeren.722 gtk_statusbar_pop(GTK_STATUSBAR(lochstreifen_statusbar), 0);723 byte = lochstreifen_byte_by_coordinate(lochstreifen, (int)event->x, (int)event->y);724 if(byte > 0) {725 gchar *msg; byte_t value,bit;726 value = lochstreifen->data[byte-1]; // weil ab 1 zaehlen => -1 weil array ab 0 zaehlt727 728 // Bitdarstellung selbst machen (printf hat sowas wohl nicht)729 char bitdarstellung[9]; bitdarstellung[8] = '\0'; // Nullterminierung730 for(bit=0; bit<8; bit++) {bitdarstellung[bit] = (((value >> bit) & 0x01) == 0x01) ? '1':'0';}731 732 msg = g_strdup_printf("Byte %03d von %03d: Wert dez=%03d bin=%s okt=%03o hex=%02X",733 byte, lochstreifen->data_length,734 value, bitdarstellung, value, value);735 gtk_statusbar_push(GTK_STATUSBAR(lochstreifen_statusbar), 0, msg);736 g_free(msg);737 } else if(byte == 0) {738 //gtk_statusbar_push(statusbar, 0, "Zeiger befindet sich außerhalb");739 // Zeiger befindet sich ausserhalb. Nichts hier ausgeben.740 // d.h. Statusbar wurde exiplit geleert und bleibt leer.741 } else if(byte == -1) {742 gtk_statusbar_push(GTK_STATUSBAR(lochstreifen_statusbar), 0,743 "Mauszeiger befindet sich auf den zusaetzlichen Nullbytes.");744 }745 746 return FALSE;747 }748 749 void message_statusbar(char *msg) {750 /**751 * Kurze Nachrichten in der Statuszeile anzeigen.752 * Diese Nachrichten bleiben mindestens 4 Sekunden lang sichtbar, bevor z.B.753 * die Position des Mauscursors wieder erscheint. Dafuer dient der Timer.754 **/755 gtk_statusbar_pop(GTK_STATUSBAR(lochstreifen_statusbar), 0);756 gtk_statusbar_push(GTK_STATUSBAR(lochstreifen_statusbar), 0, msg);757 // Statusbar-Timer erst hier einrichten, damit nach Programmstart man nicht758 // erst 4 Sekunden warten muss.759 if(last_statusbar_update == NULL)760 last_statusbar_update = g_timer_new(); // wird automatisch gestartet761 else762 g_timer_start(last_statusbar_update); // Timer zuruecksetzen763 }764 765 gboolean scroll_lochstreifen(GtkWidget *lochstreifenwidget, GdkEventScroll *event, gpointer user_data) {766 /**767 Beim Scrollen auf dem Widget wird das GTK_SCROLLED_WINDOW (user_data) gescrollt, je nach768 Ausrichtung des Streifens. Nur eindimensionales Scrolling, nicht 2d. (wer hat schon eine769 Apple Mighty Mouse ;-) )770 **/771 GtkAdjustment* adjustment;772 gdouble t;773 if(lochstreifen->drehung % 2 == 0) {774 // Lochstreifen ist horizontal ausgreichtet775 adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(user_data));776 if(adjustment == NULL) { printf("hadjustment = NULL!\n"); return FALSE; }777 t = gtk_adjustment_get_value(adjustment) + lochstreifen->d * // um eine Lochbreite scrollen778 ((event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) ? -1 : 1);779 // nach rechts oder links scrollen780 /* );781 printf("Set to %f\n", gtk_adjustment_get_value(adjustment) + (gdouble)adjustment->step_increment *782 (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) ? (gdouble)1 : (gdouble)-1);*/783 } else {784 // nach oben bzw. unten scrollen785 adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(user_data));786 if(adjustment == NULL) { printf("vadjustment = NULL!\n"); return FALSE; }787 t = gtk_adjustment_get_value(adjustment) + lochstreifen->d *788 ((event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) ? -1 : 1);789 // nach oben oder unten scrollen790 }791 printf("Scroll Is: %f | up: %f | down: %f | shall be: %f\n", gtk_adjustment_get_value(adjustment), adjustment->lower, adjustment->upper, t);792 793 if(t < adjustment->lower) t = adjustment->lower;794 if(t > adjustment->upper) t = adjustment->upper;795 gtk_adjustment_set_value(adjustment, t);796 // geht nicht:797 //g_signal_emit_by_name(lochstreifen_widget, "motion-notify-event"); // Mauszeigerbewegung simulieren => Statuszeile updaten798 }799 800 int main(int argc, char *argv[]) {801 GtkWidget *mainbox;802 GtkWidget *menubar, *menuitem, *menu;803 GtkSizeGroup *color_sizes; // Damit Farbmenue einheitlich aussieht804 GtkWidget *scroll;805 GtkWidget *statusbar;806 lochstreifen = lochstreifen_new(); // muss hier bereit zugewiesen werden weil benutzt807 808 gtk_init (&argc, &argv);809 810 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);811 gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);812 gtk_window_set_title(GTK_WINDOW (window), WINDOW_TITLE);813 g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK (gtk_main_quit), NULL);814 815 mainbox = gtk_vbox_new(FALSE, 0);816 gtk_container_add(GTK_CONTAINER (window), mainbox);817 gtk_widget_show(mainbox);818 819 statusbar = gtk_statusbar_new(); // erst nach Inhaltswidget hinzufuegen820 lochstreifen_statusbar = statusbar; // quick & dirty global machen...821 822 /* Menü */823 menubar = gtk_menu_bar_new();824 gtk_box_pack_start (GTK_BOX (mainbox), menubar, FALSE, TRUE, 0);825 gtk_widget_show(menubar);826 827 // Erstes Menue: Datei828 menu = gtk_menu_new();829 // Oeffnen830 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_OPEN)),831 "activate", G_CALLBACK(open_lochstreifen_file_dialog), window);832 fast_menu_seperator(menu);833 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Grafik als PNG exportieren...")),834 "activate", G_CALLBACK(export_lochstreifen), "PNG");835 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Grafik als SVG exportieren...")),836 "activate", G_CALLBACK(export_lochstreifen), "SVG");837 fast_menu_seperator(menu);838 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_QUIT)),839 "activate", G_CALLBACK(gtk_main_quit), NULL);840 841 menuitem = gtk_menu_item_new_with_mnemonic("_Datei");842 gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);843 gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);844 gtk_widget_show (menuitem);845 846 // Zweites Menue: Ansicht847 menu = gtk_menu_new();848 fast_menu_tearoff(menu);849 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_IN)),850 "activate", G_CALLBACK(transform_lochstreifen), "+");851 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_OUT)),852 "activate", G_CALLBACK(transform_lochstreifen), "-");853 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_100)),854 "activate", G_CALLBACK(transform_lochstreifen), "=");855 //g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_FIT)),856 // "activate", G_CALLBACK(transform_lochstreifen), "[");857 menuitem = gtk_check_menu_item_new_with_mnemonic("Groesse dem Fenster _anpassen");858 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), FALSE);859 g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(transform_lochstreifen), "[");860 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);861 gtk_widget_show (menuitem);862 fit_screen_toggle = menuitem; // auch hier global speichern, weil es in einer Funktion gebraucht wird.863 864 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_PROPERTIES)), //"Groessenverhaeltnisse aendern...")),865 "activate", G_CALLBACK(change_constant_gui), NULL);866 fast_menu_seperator(menu);867 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Drehen im Uhrzeigersinn")),868 "activate", G_CALLBACK(transform_lochstreifen), ">");869 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Drehen gegen den Uhrzeigersinn")),870 "activate", G_CALLBACK(transform_lochstreifen), "<");871 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Horizontal spiegeln (Datenreihenfolge umkehren)")),872 "activate", G_CALLBACK(transform_lochstreifen), "|");873 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Vertikal spiegeln (Bitpositionen drehen)")),874 "activate", G_CALLBACK(transform_lochstreifen), "_");875 fast_menu_seperator(menu);876 g_signal_connect(G_OBJECT(fast_menuitem(menu, "Anzahl Nullbytes einstellen...")),877 "activate", G_CALLBACK(null_bytes_dialog), NULL);878 menuitem = gtk_check_menu_item_new_with_mnemonic("_Statusleiste anzeigen");879 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);880 g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(transform_lochstreifen), "S");881 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);882 gtk_widget_show (menuitem);883 884 menuitem = gtk_menu_item_new_with_mnemonic("_Ansicht");885 gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);886 gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);887 gtk_widget_show (menuitem);888 889 // Drittes Menue: Farben890 menu = gtk_menu_new();891 color_sizes = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);892 fast_menu_tearoff(menu);893 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe des Lochstreifens waehlen",894 "Farbe des <b>Lochstreifens</b>", color_cairo2gdk(lochstreifen->streifenbg), color_sizes)),895 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->streifenbg));896 //gtk_color_button_set_color(GTK_COLOR_BUTTON(menuitem), color_cairo2gdk(lochstreifen->streifenbg));897 898 fast_menu_seperator(menu);899 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Loecher waehlen",900 "Farbe der <b>Loecher</b> waehlen\n(binaere einsen)", color_cairo2gdk(lochstreifen->punched), color_sizes)),901 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->punched));902 fast_menu_seperator(menu);903 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Nicht-Loecher waehlen",904 "Farbe der <b>Nullen</b> waehlen\n(nicht gelochte Bits)", color_cairo2gdk(lochstreifen->notpunched), color_sizes)),905 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->notpunched));906 fast_menu_seperator(menu);907 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Lochstreifen-Fuehrungsloecher waehlen",908 "Farbe der <b>Fuehrungs-loecher</b>\nwaehlen (kleine Loecher)", color_cairo2gdk(lochstreifen->fuehrung), color_sizes)),909 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->fuehrung));910 fast_menu_seperator(menu);911 g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Hintergrund waehlen",912 "<b>Hintergrundfarbe</b> waehlen\n(um dem Streifen rum)", color_cairo2gdk(lochstreifen->hintergrund), color_sizes)),913 "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->hintergrund));914 915 menuitem = gtk_menu_item_new_with_mnemonic("_Farben");916 gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);917 gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);918 gtk_widget_show (menuitem);919 920 // So jetzt aber Inhalt: Das Hauptwidget.921 lochstreifen_set_d(lochstreifen, 20);922 923 // Daten einlesen.924 {925 char *filename = NULL;926 gboolean read_from_stdin = FALSE;927 gboolean no_splash = FALSE;928 GError *error = NULL;929 GOptionContext *context;930 byte_t show_mystart = 0; // eigene Startprozedur anzeigen?931 GOptionEntry option_entries[] = {932 { "filename", 'f', 0, G_OPTION_ARG_FILENAME, &filename, "Datei zu oeffnen", NULL },933 { "stdin", 's', 0, G_OPTION_ARG_NONE, &read_from_stdin, "Von Standardeingabe lesen", NULL },934 { "no-splash", 'n', 0, G_OPTION_ARG_NONE, &no_splash, "Keine Startanimation anzeigen, wenn ohne Datei gestartet", NULL },935 { NULL }936 };937 938 context = g_option_context_new(" - Lochstreifenvisualisierung");939 g_option_context_add_main_entries(context, option_entries, NULL);940 g_option_context_add_group(context, gtk_get_option_group(TRUE));941 g_option_context_parse(context, &argc, &argv, &error);942 943 if(read_from_stdin) {944 printf("%s: Lese Daten von Standardeingabe, erst nach EOF wird Fenster geoeffnet.\n",argv[0]);945 byte_t *data;946 int length = file_get_contents(stdin, &data);947 lochstreifen_set_data(lochstreifen, length, data, 6, 6);948 } else if(filename != NULL) {949 // eine Datei einlesen950 printf("Von Datei %s lesen\n", filename);951 if(!open_lochstreifen_file(argv[1]))952 show_mystart = 1;953 } else if(!no_splash) {954 // Splash (=Start)-Sequenz anzeigen955 show_mystart = 1;956 }957 958 // Daten wurde eingelesen -- oder auch nicht:959 if(show_mystart != 0) {960 g_signal_connect_after(G_OBJECT(window), "show", G_CALLBACK(startup_sequence), NULL);961 startsequence_running = show_mystart;962 } else startsequence_running = FALSE;963 }964 965 lochstreifen_widget = gtk_drawing_area_new();966 gtk_widget_set_size_request (GTK_WIDGET (lochstreifen_widget),967 lochstreifen_get_width(lochstreifen),968 lochstreifen_get_height(lochstreifen)); // erst mal spasseshalber969 970 scroll = gtk_scrolled_window_new(NULL, NULL);971 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), lochstreifen_widget); // weil nicht scrollable972 // Scrollbalken nur anzeigen wenn benoetigt973 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);974 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_NONE);975 gtk_box_pack_start(GTK_BOX(mainbox), scroll, TRUE, TRUE, 0);976 gtk_widget_show(scroll);977 978 gtk_widget_show(lochstreifen_widget);979 g_signal_connect(G_OBJECT(lochstreifen_widget), "expose_event", G_CALLBACK(expose_lochstreifen), NULL);980 gtk_widget_add_events(lochstreifen_widget, GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK); // Mauscursor kriegen, Mausscrolling kriegen981 g_signal_connect(G_OBJECT(lochstreifen_widget), "motion-notify-event", G_CALLBACK(update_statusbar), NULL);982 g_signal_connect(G_OBJECT(lochstreifen_widget), "scroll-event", G_CALLBACK(scroll_lochstreifen), scroll);983 984 // Statusbar hinzufuegen.985 // Ich haette ja gerne eine maechtigere Statusbar, aber das geht wohl986 // leider nicht. Ein paar Versuche, das Label dort wenigstens Pango-Formatierungs-Faehig987 // zu machen:988 /*gtk_container_forall(GTK_CONTAINER(statusbar), G_CALLBACK(fast_nicer_statusbar), NULL);989 gboolean fast_nicer_statusbar(GtkWidget *statusbar_child, gpointer egal) {990 GList *children;991 gpointer child;992 children = gtk_container_get_children(GTK_CONTAINER(statusbar));993 994 gtk_container_forall (GtkContainer *container,995 GtkCallback callback,996 gpointer callback_data);997 998 //printf("Checke Kindelement von statusbar (%d)\n", g_list_length(children));999 //while((child = g_list_next(children)) != NULL) {1000 if(GTK_IS_LABEL(statusbar_child)) {1001 printf("LABEL GEFUNDEN!\n");1002 gtk_label_set_use_markup(GTK_LABEL(statusbar_child), TRUE); // :-)1003 }1004 printf("Fand ein %s-Objekt.\n", G_OBJECT_TYPE_NAME(statusbar_child));1005 //}1006 //printf("Fertig.\n");1007 } */1008 gtk_box_pack_start(GTK_BOX(mainbox), statusbar, FALSE, TRUE, 0);1009 gtk_widget_show(statusbar);1010 1011 // TEST DEBUG:1012 //gtk_widget_set_redraw_on_allocate(lochstreifen_widget, TRUE);1013 //gtk_widget_set_double_buffered(lochstreifen_widget, FALSE);1014 1015 gtk_widget_show(window);1016 gtk_main();1017 return 0;1018 } -
visualisator/lochstreifen.c
r1 r3 157 157 l->d = 10; 158 158 l->data_length = 0; 159 l->data = NULL; 160 l->empty_start = 0; 161 l->empty_end = 0; 159 162 l->debug = 0; 160 163 l->hintergrund = NULL; // nicht zeichnen … … 168 171 l->spiegelung_hor = 0; 169 172 l->spiegelung_ver = 0; 173 l->highlight_byte = 0; 174 l->highlight_color = NULL; 170 175 lochstreifen_flush_only_start_area(l); 171 176 return l; … … 181 186 if(empty_start >= 0) l->empty_start = empty_start; 182 187 if(empty_end >= 0) l->empty_end = empty_end; 188 } 189 190 void lochstreifen_set_highlight(LOCHSTREIFEN* l, int byte_number) { 191 l->highlight_byte = byte_number; 192 if(l->highlight_color == NULL) 193 l->highlight_color = cairo_pattern_create_rgb(242/255, 255/255, 0); 183 194 } 184 195 … … 357 368 else if(byte > l->data_length) return -1; // im Emptyendbereich 358 369 else return byte; // im gueltigen Bereich -- Byte gefunden! 359 370 } 371 372 int lochstreifen_coordinate_by_byte(LOCHSTREIFEN *l, int byte) { 373 /** 374 * Anhang eines Bytes (fuers Datenarray, ab 0 zaehlend) wird -- abhaengig nach aktueller 375 * Ausrichtung des Lochstreifens -- die Koordinate des Bytes in der Dimension der 376 * Ausrichtung des Lochstreifens zurueckgegeben.. 377 * Liegt der Lochstreifen horizontal, so wird die x-Koordinate zurueckgegeben. Liegt er 378 * vertikal, dann die y-Koordinate. 379 * 380 **/ 381 int xy; 382 //if(lochstreifen_get_orientation(l)) { // horizontal = 1 | vertical = 0 383 xy = l->margin + l->abriss + (l->d + l->bspace) * (byte + l->empty_start); 384 //} 385 386 return xy; 387 // TODO! Richtige implementierung! 360 388 } 361 389 … … 375 403 x1 = l->only_start_x; y1 = l->only_start_y; 376 404 x2 = x1 + width; y2 = y1 + height; 377 405 378 406 /*int x1,y1,x2,y2,x3,y3,x4,y4; 379 407 x1 = l->only_start_x; y1 = l->only_start_y; … … 412 440 cairo_matrix_multiply(&matrix, &matrix, &temp); 413 441 } 414 442 415 443 //if(l->drehung > 0) { 416 444 /*cairo_matrix_rotate(&matrix, l->drehung/2 *M_PI); … … 428 456 cairo_set_matrix(cr, &matrix); 429 457 // -1, 0, 0, 1, width, 0 = spiegelung x-achse 430 458 431 459 //cairo_device_to_user(cr, (double*)&(l->only_start_x), (double*)&(l->only_start_y)); 432 460 cairo_device_to_user(cr, (double*)&(x1), (double*)&(y1)); … … 508 536 if(l->only_width != 0 && x > l->only_start_x + l->only_width) break; 509 537 538 // ggf. Byte hervorheben 539 if(byte == l->highlight_byte && l->highlight_color != NULL) { 540 cairo_set_source(cr, l->highlight_color); 541 cairo_rectangle(cr, x - l->bspace/2, l->margin, l->df*2 + l->bspace, height - 2*l->margin); 542 cairo_fill(cr); 543 } 544 510 545 // Bits des entsprechenden Bytes durchgehen 511 546 for(loch=0, y = l->margin + l->padding; loch < 8; y += l->d + l->hspace, loch++) { -
visualisator/lochstreifen.h
r1 r3 51 51 int only_height; // gezeichnet. 52 52 53 54 /* Feature: Ein bestimmtes Byte hervorheben */ 55 int highlight_byte; // Nummer des Bytes (von 0) 56 cairo_pattern_t *highlight_color; // Farben => wenn NULL, kein Highlight 57 53 58 /* Debugausgaben machen => wenn debug != 0 ist! */ 54 59 byte_t debug;
Note: See TracChangeset
for help on using the changeset viewer.