From 1dfb8da99a4f186fc6a7f0b4cc16ca7be2f3fe26 Mon Sep 17 00:00:00 2001 From: werner Date: Tue, 11 Aug 2009 01:20:15 +0000 Subject: [PATCH] - change file save logic to write to a temporary file first, so that we don't leave an empty/corrupt main file if we crash during saving - started adding Postscript output - renamed "Save as KiCad" to "Write KiCad" - switched from "manual" menu bar creation to GtkItemFactory git-svn-id: http://svn.openmoko.org/trunk/eda/fped@5417 99fdad57-331a-0410-800a-d7fa5415bdb3 --- Makefile | 2 +- gui.c | 142 ++++++++++++++++++++++++------------ postscript.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++ postscript.h | 31 ++++++++ 4 files changed, 329 insertions(+), 47 deletions(-) create mode 100644 postscript.c create mode 100644 postscript.h diff --git a/Makefile b/Makefile index c92ba0a..3672954 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ # OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \ - unparse.o dump.o kicad.o meas.o \ + unparse.o dump.o kicad.o postscript.o meas.o \ cpp.o lex.yy.o y.tab.o \ gui.o gui_util.o gui_style.o gui_inst.o gui_status.o gui_canvas.o \ gui_tool.o gui_over.o gui_meas.o gui_frame.o diff --git a/gui.c b/gui.c index b08b736..b9e89dc 100644 --- a/gui.c +++ b/gui.c @@ -22,6 +22,7 @@ #include "obj.h" #include "dump.h" #include "kicad.h" +#include "postscript.h" #include "gui_util.h" #include "gui_style.h" #include "gui_status.h" @@ -48,7 +49,7 @@ static GtkWidget *ev_stuff, *ev_meas; static GtkWidget *stuff_image[2], *meas_image[2]; -/* ----- menu bar ---------------------------------------------------------- */ +/* ----- save/write operations --------------------------------------------- */ static char *set_extension(const char *name, const char *ext) @@ -67,57 +68,93 @@ static char *set_extension(const char *name, const char *ext) } -static void save_with_backup(const char *name, int (*fn)(FILE *file)) +static int save_to(const char *name, int (*fn)(FILE *file)) { FILE *file; + + file = fopen(name, "w"); + if (!file) { + perror(name); + return 0; + } + if (!fn(file)) { + perror(name); + return 0; + } + if (fclose(file) == EOF) { + perror(name); + return 0; + } + return 1; +} + + +static void save_with_backup(const char *name, int (*fn)(FILE *file)) +{ char *s = stralloc(name); - char *slash, *dot, *tmp; + char *back, *tmp; + char *slash, *dot; int n; struct stat st; + /* save to temporary file */ + slash = strrchr(s, '/'); + if (!slash) + tmp = stralloc_printf("~%s", s); + else { + *slash = 0; + tmp = stralloc_printf("%s/~%s", s, slash+1); + *slash = '/'; + } + + if (!save_to(tmp, fn)) + return; + + /* move existing file out of harm's way */ + dot = strrchr(slash ? slash : s, '.'); if (dot) *dot = 0; n = 0; while (1) { - tmp = stralloc_printf("%s~%d%s%s", + back = stralloc_printf("%s~%d%s%s", s, n, dot ? "." : "", dot ? dot+1 : ""); - if (stat(tmp, &st) < 0) { + if (stat(back, &st) < 0) { if (errno == ENOENT) break; - perror(tmp); - free(tmp); + perror(back); + free(back); return; } - free(tmp); + free(back); n++; } - if (rename(name, tmp) < 0) { + if (rename(name, back) < 0) { if (errno != ENOENT) { perror(name); - free(tmp); + free(back); return; } } else { - fprintf(stderr, "renamed %s to %s\n", name, tmp); + fprintf(stderr, "renamed %s to %s\n", name, back); + } + free(back); + + /* rename to final name */ + + if (rename(tmp, name) < 0) { + perror(name); + free(tmp); + return; } free(tmp); - file = fopen(name, "w"); - if (!file) { - perror(name); - return; - } - if (!fn(file)) - perror(name); - if (fclose(file) == EOF) - perror(name); fprintf(stderr, "saved to %s\n", name); } -static void menu_save(GtkWidget *widget, gpointer user) +static void menu_save(void) { if (save_file) save_with_backup(save_file, dump); @@ -128,13 +165,13 @@ static void menu_save(GtkWidget *widget, gpointer user) } -static void menu_save_kicad(GtkWidget *widget, gpointer user) +static void menu_write_kicad(void) { char *name; if (save_file) { name = set_extension(save_file, "mod"); - save_with_backup(name, kicad); + save_to(name, kicad); free(name); } else { if (!kicad(stdout)) @@ -143,34 +180,47 @@ static void menu_save_kicad(GtkWidget *widget, gpointer user) } +static void menu_write_ps(void) +{ + char *name; + + if (save_file) { + name = set_extension(save_file, "ps"); + save_to(name, postscript); + free(name); + } else { + if (!postscript(stdout)) + perror("stdout"); + } +} + + +/* ----- menu bar ---------------------------------------------------------- */ + + +static GtkItemFactoryEntry menu_entries[] = { + { "/File", NULL, NULL, 0, "" }, + { "/File/Save", NULL, menu_save, 0, "" }, + { "/File/sep0", NULL, NULL, 0, "" }, + { "/File/Write KiCad", NULL, menu_write_kicad, 0, "" }, + { "/File/Write Postscript", + NULL, menu_write_ps, 0, "" }, + { "/File/sep2", NULL, NULL, 0, "" }, + { "/File/Quit", NULL, gtk_main_quit, 0, "" }, +}; + + static void make_menu_bar(GtkWidget *hbox) { + GtkItemFactory *factory; GtkWidget *bar; - GtkWidget *file_menu, *file, *quit, *save; - bar = gtk_menu_bar_new(); + factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "", NULL); + gtk_item_factory_create_items(factory, + sizeof(menu_entries)/sizeof(*menu_entries), menu_entries, NULL); + + bar = gtk_item_factory_get_widget(factory, ""); gtk_box_pack_start(GTK_BOX(hbox), bar, TRUE, TRUE, 0); - - file_menu = gtk_menu_new(); - - file = gtk_menu_item_new_with_label("File"); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), file_menu); - gtk_menu_shell_append(GTK_MENU_SHELL(bar), file); - - save = gtk_menu_item_new_with_label("Save"); - gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), save); - g_signal_connect(G_OBJECT(save), "activate", - G_CALLBACK(menu_save), NULL); - - save = gtk_menu_item_new_with_label("Save as KiCad"); - gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), save); - g_signal_connect(G_OBJECT(save), "activate", - G_CALLBACK(menu_save_kicad), NULL); - - quit = gtk_menu_item_new_with_label("Quit"); - gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), quit); - g_signal_connect(G_OBJECT(quit), "activate", - G_CALLBACK(gtk_main_quit), NULL); } diff --git a/postscript.c b/postscript.c new file mode 100644 index 0000000..a9f3eda --- /dev/null +++ b/postscript.c @@ -0,0 +1,201 @@ +/* + * postscript.c - Dump objects in Postscript + * + * Written 2009 by Werner Almesberger + * Copyright 2009 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +#include +#include + +#include "coord.h" +#include "inst.h" +#include "postscript.h" + + +#define DOT_DIST mm_to_units(0.03) +#define DOT_DIAM mm_to_units(0.01) +#define HATCH mm_to_units(0.1) +#define HATCH_LINE mm_to_units(0.02) + + +struct postscript_params postscript_params = { + .zoom = 10.0, + .show_pad_names = 0, + .show_stuff = 0, + .label_vecs = 0, + .show_meas = 0, +}; + + +static void ps_pad(FILE *file, const struct inst *inst) +{ + struct coord a = inst->base; + struct coord b = inst->u.pad.other; + + fprintf(file, "0 setgray %d setlinewidth\n", HATCH_LINE); + fprintf(file, " %d %d moveto\n", a.x, a.y); + fprintf(file, " %d %d lineto\n", b.x, a.y); + fprintf(file, " %d %d lineto\n", b.x, b.y); + fprintf(file, " %d %d lineto\n", a.x, b.y); + fprintf(file, " closepath gsave hatchpath grestore stroke\n"); +} + + +static void ps_line(FILE *file, const struct inst *inst) +{ + struct coord a = inst->base; + struct coord b = inst->u.pad.other; + + fprintf(file, "1 setlinecap 0.5 setgray %d setlinewidth\n", + inst->u.rect.width); + fprintf(file, " %d %d moveto %d %d lineto stroke\n", + a.x, a.y, b.x, b.y); +} + + +static void ps_rect(FILE *file, const struct inst *inst) +{ + struct coord a = inst->base; + struct coord b = inst->u.rect.end; + + fprintf(file, "1 setlinecap 0.5 setgray %d setlinewidth\n", + inst->u.rect.width); + fprintf(file, " %d %d moveto\n", a.x, a.y); + fprintf(file, " %d %d lineto\n", b.x, a.y); + fprintf(file, " %d %d lineto\n", b.x, b.y); + fprintf(file, " %d %d lineto\n", a.x, b.y); + fprintf(file, " closepath stroke\n"); +} + + +static void ps_arc(FILE *file, const struct inst *inst) +{ + double a1, a2; + + a1 = inst->u.arc.a1; + a2 = inst->u.arc.a2; + if (a2 <= a1) + a2 += 360; + + fprintf(file, "1 setlinecap 0.5 setgray %d setlinewidth\n", + inst->u.arc.width); + fprintf(file, " newpath %d %d %d %f %f arc stroke\n", + inst->base.x, inst->base.y, inst->u.arc.r, a1, a2); +} + + +static void ps_frame(FILE *file, const struct inst *inst) +{ +} + + +static void ps_vec(FILE *file, const struct inst *inst) +{ +} + + +static void ps_meas(FILE *file, const struct inst *inst) +{ +} + + +static void ps_background(FILE *file, enum inst_prio prio, + const struct inst *inst) +{ + switch (prio) { + case ip_line: + ps_line(file, inst); + break; + case ip_rect: + ps_rect(file, inst); + break; + case ip_circ: + case ip_arc: + ps_arc(file, inst); + break; + default: + break; + } +} + + +static void ps_foreground(FILE *file, enum inst_prio prio, + const struct inst *inst) +{ + switch (prio) { + case ip_pad: + ps_pad(file, inst); + break; + case ip_vec: + if (postscript_params.show_stuff) + ps_vec(file, inst); + break; + case ip_frame: + if (postscript_params.show_stuff) + ps_frame(file, inst); + break; + case ip_meas: + if (postscript_params.show_meas) + ps_meas(file, inst); + break; + default: + break; + } +} + + +int postscript(FILE *file) +{ + enum inst_prio prio; + const struct inst *inst; + + fprintf(file, "%%!PS\n"); + + fprintf(file, +"currentpagedevice /PageSize get\n" +" aload pop\n" +" 2 div exch 2 div exch\n" +" translate\n" +" %f 72 mul %d div 1000 div dup scale\n", + (double) postscript_params.zoom , (int) MIL_UNITS); + + fprintf(file, +"/dotpath {\n" +" gsave pathbbox clip newpath\n" +" 1 setlinecap %d setlinewidth\n" +" /ury exch def /urx exch def /lly exch def /llx exch def\n" +" llx %d urx {\n" +" lly %d ury {\n" +" 1 index exch moveto 0 0 rlineto stroke\n" +" } for\n" +" } for\n" +" grestore newpath } def\n", DOT_DIAM, DOT_DIST, DOT_DIST); + + fprintf(file, +"/hatchpath {\n" +" gsave pathbbox clip newpath\n" +" /ury exch def /urx exch def /lly exch def /llx exch def\n" +" lly ury sub %d urx llx sub {\n" /* for -(ury-lly) to urx-llx */ +" llx add dup lly moveto\n" +" ury lly sub add ury lineto stroke\n" +" } for\n" +" grestore newpath } def\n", HATCH); + + FOR_INSTS_UP(prio, inst) + ps_background(file, prio, inst); + FOR_INSTS_UP(prio, inst) + ps_foreground(file, prio, inst); + + fprintf(file, "showpage\n"); + fprintf(file, "%%%%EOF\n"); + + fflush(file); + return !ferror(file); +} diff --git a/postscript.h b/postscript.h new file mode 100644 index 0000000..907cfad --- /dev/null +++ b/postscript.h @@ -0,0 +1,31 @@ +/* + * ps.h - Dump objects in Postscript + * + * Written 2009 by Werner Almesberger + * Copyright 2009 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +#ifndef POSTSCRIPT_H +#define POSTSCRIPT_H + +#include + + +struct postscript_params { + double zoom; + int show_pad_names; + int show_stuff; /* vecs and frames */ + int label_vecs; + int show_meas; +}; + + +int postscript(FILE *file); + +#endif /* !POSTSCRIPT_H */