diff --git a/Makefile b/Makefile index bbff33c..822b710 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ CFLAGS_GTK = `pkg-config --cflags gtk+-2.0` LIBS_GTK = `pkg-config --libs gtk+-2.0` CFLAGS_WARN=-Wall -Wshadow -Wmissing-prototypes \ - -Wmissing-declarations + -Wmissing-declarations -Wno-format-zero-length CFLAGS=-g -std=gnu99 $(CFLAGS_GTK) -DCPP='"cpp"' $(CFLAGS_WARN) SLOPPY=-Wno-unused -Wno-implicit-function-declaration -Wno-missing-prototypes \ -Wno-missing-declarations diff --git a/TODO b/TODO index ec9f086..5039336 100644 --- a/TODO +++ b/TODO @@ -21,6 +21,10 @@ Style: - status area looks awful - add button with GTK_STOCK_UNDELETE for "undelete" to menu bar - edit names/values/etc. in place if possible +- maximizing pad name size creates uneven text sizes. Particularly "1" gets + excessively large. +- pango_layout_get_size doesn't seem to consider rotation, so we currently + don't properly size rotated text. Bugs: - default silk width has no business being hard-coded in obj.c diff --git a/error.c b/error.c index aec4d94..719b3f4 100644 --- a/error.c +++ b/error.c @@ -38,7 +38,7 @@ void yyerrorf(const char *fmt, ...) va_start(ap, fmt); vsnprintf(buf, n+1, fmt, ap); va_end(ap); - fail(buf); + fail("%s", buf); free(buf); } diff --git a/error.h b/error.h index 55b39ea..89be071 100644 --- a/error.h +++ b/error.h @@ -20,11 +20,13 @@ extern int lineno; extern void (*reporter)(const char *s); -void yyerrorf(const char *fmt, ...); +void yyerrorf(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); void yyerror(const char *s); void report_to_stderr(const char *s); void report_parse_error(const char *s); -void fail(const char *fmt, ...); +void fail(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); #endif /* !ERROR_H */ diff --git a/gui_canvas.c b/gui_canvas.c index 8c42d61..286eeb5 100644 --- a/gui_canvas.c +++ b/gui_canvas.c @@ -62,6 +62,12 @@ static void update_pos(struct coord pos) } +void refresh_pos(void) +{ + update_pos(curr_pos); +} + + /* ----- coordinate system ------------------------------------------------- */ diff --git a/gui_canvas.h b/gui_canvas.h index 64a15a8..ed21864 100644 --- a/gui_canvas.h +++ b/gui_canvas.h @@ -25,6 +25,8 @@ extern void (*highlight)(void); +void refresh_pos(void); + void redraw(void); GtkWidget *make_canvas(void); diff --git a/gui_inst.c b/gui_inst.c index 79086d7..72af68c 100644 --- a/gui_inst.c +++ b/gui_inst.c @@ -21,6 +21,7 @@ #include "gui.h" #include "gui_util.h" #include "gui_style.h" +#include "gui_status.h" #include "gui_inst.h" @@ -378,7 +379,7 @@ static struct coord offset_vec(struct coord a, struct coord b, } -static void project_meas(struct inst *inst, struct coord *a1, struct coord *b1) +void project_meas(const struct inst *inst, struct coord *a1, struct coord *b1) { const struct meas *meas = &inst->obj->u.meas; struct coord off; @@ -417,6 +418,35 @@ unit_type gui_dist_meas(struct inst *self, struct coord pos, unit_type scale) } +char *format_len(const char *label, unit_type len, enum curr_unit unit) +{ + const char *u = ""; + double n; + int mm; + + switch (unit) { + case curr_unit_mm: + n = units_to_mm(len); + mm = 1; + break; + case curr_unit_mil: + n = units_to_mil(len); + mm = 0; + break; + case curr_unit_auto: + n = units_to_best(len, &mm); + u = mm ? "mm" : "mil"; + break; + default: + abort(); + } + return stralloc_printf(mm ? + "%s" MM_FORMAT_SHORT "%s" : + "%s" MIL_FORMAT_SHORT "%s", + label, n, u); +} + + void gui_draw_meas(struct inst *self) { const struct meas *meas = &self->obj->u.meas; @@ -429,7 +459,7 @@ void gui_draw_meas(struct inst *self) b0 = translate(self->u.meas.end); project_meas(self, &a1, &b1); - len = units_to_mm(dist_point(a1, b1)); + len = dist_point(a1, b1); a1 = translate(a1); b1 = translate(b1); gc = gc_meas[get_mode(self)]; @@ -441,7 +471,7 @@ void gui_draw_meas(struct inst *self) c = add_vec(a1, b1); d = sub_vec(b1, a1); - s = stralloc_printf("%s%lgmm", meas->label ? meas->label : "", len); + s = format_len(meas->label ? meas->label : "", len, curr_unit); render_text(DA, gc, c.x/2, c.y/2, -atan2(d.y, d.x)/M_PI*180, s, MEAS_FONT, 0.5, -MEAS_BASELINE_OFFSET, dist_point(a1, b1)-1.5*MEAS_ARROW_LEN, 0); diff --git a/gui_inst.h b/gui_inst.h index 6205fd1..3397365 100644 --- a/gui_inst.h +++ b/gui_inst.h @@ -18,6 +18,7 @@ #include "coord.h" #include "inst.h" +#include "gui_status.h" struct coord translate(struct coord pos); @@ -35,6 +36,9 @@ unit_type gui_dist_frame(struct inst *self, struct coord pos, unit_type scale); unit_type gui_dist_frame_eye(struct inst *self, struct coord pos, unit_type scale); +void project_meas(const struct inst *inst, struct coord *a1, struct coord *b1); +char *format_len(const char *label, unit_type len, enum curr_unit unit); + void gui_draw_vec(struct inst *self); void gui_draw_line(struct inst *self); void gui_draw_rect(struct inst *self); diff --git a/gui_status.c b/gui_status.c index 9ce94f5..babd245 100644 --- a/gui_status.c +++ b/gui_status.c @@ -25,6 +25,7 @@ #include "unparse.h" #include "gui_util.h" #include "gui_style.h" +#include "gui_canvas.h" #include "gui.h" #include "gui_status.h" @@ -43,12 +44,7 @@ struct edit_ops { }; -static enum curr_unit { - unit_mm, - unit_mil, - unit_auto, - unit_n -} curr_unit = unit_mm; +enum curr_unit curr_unit = curr_unit_mm; static GtkWidget *open_edits = NULL; @@ -116,15 +112,15 @@ void set_with_units(void (*set)(const char *fmt, ...), const char *prefix, int mm; switch (curr_unit) { - case unit_mm: + case curr_unit_mm: n = units_to_mm(u); mm = 1; break; - case unit_mil: + case curr_unit_mil: n = units_to_mil(u); mm = 0; break; - case unit_auto: + case curr_unit_auto: n = units_to_best(u, &mm); break; default: @@ -132,10 +128,10 @@ void set_with_units(void (*set)(const char *fmt, ...), const char *prefix, } if (mm) { /* -NNN.NNN mm */ - set("%s%8.3f mm", prefix, n); + set("%s" MM_FORMAT_FIXED " mm", prefix, n); } else { /* -NNNN.N mil */ - set("%s%7.1f mil", prefix, n); + set("%s" MIL_FORMAT_FIXED " mil", prefix, n); } } @@ -745,15 +741,15 @@ static gboolean unit_button_press_event(GtkWidget *widget, { switch (event->button) { case 1: - curr_unit = (curr_unit+1) % unit_n; + curr_unit = (curr_unit+1) % curr_unit_n; switch (curr_unit) { - case unit_mm: + case curr_unit_mm: status_set_unit("mm"); break; - case unit_mil: + case curr_unit_mil: status_set_unit("mil"); break; - case unit_auto: + case curr_unit_auto: status_set_unit("auto"); break; default: @@ -761,6 +757,8 @@ static gboolean unit_button_press_event(GtkWidget *widget, } break; } + refresh_pos(); + change_world(); return TRUE; } @@ -860,6 +858,7 @@ void make_status_area(GtkWidget *vbox) /* unit selection */ + label_in_box_bg(status_unit, COLOR_UNIT_SELECTOR); status_set_unit("mm"); g_signal_connect(G_OBJECT(box_of_label(status_unit)), "button_press_event", G_CALLBACK(unit_button_press_event), NULL); diff --git a/gui_status.h b/gui_status.h index 325cd38..195f162 100644 --- a/gui_status.h +++ b/gui_status.h @@ -20,6 +20,17 @@ #include "expr.h" +enum curr_unit { + curr_unit_mm, + curr_unit_mil, + curr_unit_auto, + curr_unit_n +}; + + +extern enum curr_unit curr_unit; + + void edit_unique(const char **s, int (*validate)(const char *s, void *ctx), void *ctx); void edit_unique_null(const char **s, int (*validate)(const char *s, void *ctx), @@ -40,21 +51,36 @@ void edit_nothing(void); void set_with_units(void (*set)(const char *fmt, ...), const char *prefix, unit_type u); -void status_set_type_x(const char *fmt, ...); -void status_set_type_y(const char *fmt, ...); -void status_set_type_entry(const char *fmt, ...); -void status_set_name(const char *fmt, ...); -void status_set_x(const char *fmt, ...); -void status_set_y(const char *fmt, ...); -void status_set_r(const char *fmt, ...); -void status_set_angle(const char *fmt, ...); -void status_set_sys_x(const char *fmt, ...); -void status_set_sys_y(const char *fmt, ...); -void status_set_user_x(const char *fmt, ...); -void status_set_user_y(const char *fmt, ...); -void status_set_zoom(const char *fmt, ...); -void status_set_grid(const char *fmt, ...); -void status_set_unit(const char *fmt, ...); +void status_set_type_x(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_type_y(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_type_entry(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_name(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_x(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_y(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_r(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_angle(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_sys_x(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_sys_y(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_user_x(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_user_y(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_zoom(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_grid(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void status_set_unit(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); void status_set_xy(struct coord coord); diff --git a/gui_style.h b/gui_style.h index 87fe575..1fbdb0a 100644 --- a/gui_style.h +++ b/gui_style.h @@ -55,6 +55,11 @@ #define MIN_FONT_SCALE 0.20 /* don't scale fonts below this */ +#define MM_FORMAT_FIXED "%8.3f" /* -NNN.NNN */ +#define MIL_FORMAT_FIXED "%7.1f" /* -NNNN.N */ +#define MM_FORMAT_SHORT "%.4g" +#define MIL_FORMAT_SHORT "%.4g" + /* ----- assorted colors --------------------------------------------------- */ @@ -90,6 +95,8 @@ #define COLOR_ITEM_SELECTED COLOR_FRAME_SELECTED #define COLOR_ITEM_ERROR "red" +#define COLOR_UNIT_SELECTOR "white" + /* ----- canvas drawing styles --------------------------------------------- */ diff --git a/postscript.c b/postscript.c index 7220eef..6285abb 100644 --- a/postscript.c +++ b/postscript.c @@ -16,14 +16,21 @@ #include "coord.h" #include "inst.h" +#include "gui_status.h" +#include "gui_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) -#define FONT_OUTLINE mm_to_units(0.025) +#define PS_DOT_DIST mm_to_units(0.03) +#define PS_DOT_DIAM mm_to_units(0.01) +#define PS_HATCH mm_to_units(0.1) +#define PS_HATCH_LINE mm_to_units(0.015) +#define PS_FONT_OUTLINE mm_to_units(0.025) +#define PS_MEAS_LINE mm_to_units(0.015) +#define PS_MEAS_ARROW_LEN mm_to_units(0.07) +#define PS_MEAS_ARROW_ANGLE 30 +#define PS_MEAS_TEXT_HEIGHT mm_to_units(0.2) +#define PS_MEAS_BASE_OFFSET mm_to_units(0.05) struct postscript_params postscript_params = { @@ -31,7 +38,7 @@ struct postscript_params postscript_params = { .show_pad_names = 1, .show_stuff = 0, .label_vecs = 0, - .show_meas = 0, + .show_meas = 1, }; @@ -53,7 +60,7 @@ static void ps_pad_name(FILE *file, const struct inst *inst) fprintf(file, " maxfont scalefont setfont\n"); fprintf(file, " %d %d moveto\n", (a.x+b.x)/2, (a.y+b.y)/2); fprintf(file, " (%s) center %d showoutlined newpath\n", - inst->u.pad.name, FONT_OUTLINE); + inst->u.pad.name, PS_FONT_OUTLINE); } @@ -62,12 +69,12 @@ static void ps_pad(FILE *file, const struct inst *inst, int show_name) struct coord a = inst->base; struct coord b = inst->u.pad.other; - fprintf(file, "0 setgray %d setlinewidth\n", HATCH_LINE); + fprintf(file, "0 setgray %d setlinewidth\n", PS_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"); + fprintf(file, " closepath gsave crosspath grestore stroke\n"); if (show_name) ps_pad_name(file, inst); @@ -83,7 +90,7 @@ static void ps_rpad(FILE *file, const struct inst *inst, int show_name) sort_coord(&a, &b); h = b.y-a.y; w = b.x-a.x; - fprintf(file, "0 setgray %d setlinewidth\n", HATCH_LINE); + fprintf(file, "0 setgray %d setlinewidth\n", PS_HATCH_LINE); if (h > w) { r = w/2; fprintf(file, " %d %d moveto\n", b.x, b.y-r); @@ -157,8 +164,65 @@ static void ps_vec(FILE *file, const struct inst *inst) } -static void ps_meas(FILE *file, const struct inst *inst) +static void ps_arrow(FILE *file, struct coord from, struct coord to, int len, + int angle) { + struct coord side, p; + + if (from.x == to.x && from.y == to.y) { + side.x = 0; + side.y = -len; + } else { + side = normalize(sub_vec(to, from), len); + } + + p = add_vec(to, rotate(side, 180-angle)); + fprintf(file, " %d %d moveto\n", p.x, p.y); + fprintf(file, " %d %d lineto\n", to.x, to.y); + + p = add_vec(to, rotate(side, 180+angle)); + fprintf(file, " %d %d moveto\n", p.x, p.y); + fprintf(file, " %d %d lineto\n", to.x, to.y); + fprintf(file, " stroke\n"); +} + + +static void ps_meas(FILE *file, const struct inst *inst, + enum curr_unit unit) +{ + struct coord a0, b0, a1, b1; + struct coord c, d; + char *s; + + a0 = inst->base; + b0 = inst->u.meas.end; + project_meas(inst, &a1, &b1); + fprintf(file, "1 setlinecap 0 setgray %d setlinewidth\n", PS_MEAS_LINE); + fprintf(file, " %d %d moveto\n", a0.x, a0.y); + fprintf(file, " %d %d lineto\n", a1.x, a1.y); + fprintf(file, " %d %d lineto\n", b1.x, b1.y); + fprintf(file, " %d %d lineto\n", b0.x, b0.y); + fprintf(file, " stroke\n"); + + ps_arrow(file, a1, b1, PS_MEAS_ARROW_LEN, PS_MEAS_ARROW_ANGLE); + ps_arrow(file, b1, a1, PS_MEAS_ARROW_LEN, PS_MEAS_ARROW_ANGLE); + + s = format_len(inst->obj->u.meas.label ? inst->obj->u.meas.label : "", + dist_point(a1, b1), unit); + + c = add_vec(a1, b1); + d = sub_vec(b1, a1); +//s = stralloc_printf("%s%lgmm", meas->label ? meas->label : "", len); + fprintf(file, "gsave %d %d moveto\n", c.x/2, c.y/2); + fprintf(file, " /Helvetica-Bold findfont dup\n"); + fprintf(file, " (%s) %d %d\n", s, + (int) (dist_point(a1, b1)-1.5*PS_MEAS_ARROW_LEN), + PS_MEAS_TEXT_HEIGHT); + fprintf(file, " 4 copy 100 maxfont maxfont scalefont setfont\n"); + fprintf(file, " %f rotate\n", atan2(d.y, d.x)/M_PI*180); + fprintf(file, " (%s) %d hcenter\n", s, PS_MEAS_BASE_OFFSET); + fprintf(file, " show grestore\n"); + free(s); } @@ -202,7 +266,7 @@ static void ps_foreground(FILE *file, enum inst_prio prio, break; case ip_meas: if (postscript_params.show_meas) - ps_meas(file, inst); + ps_meas(file, inst, curr_unit); break; default: break; @@ -235,7 +299,7 @@ int postscript(FILE *file) " 1 index exch moveto 0 0 rlineto stroke\n" " } for\n" " } for\n" -" grestore newpath } def\n", DOT_DIAM, DOT_DIST, DOT_DIST); +" grestore newpath } def\n", PS_DOT_DIAM, PS_DOT_DIST, PS_DOT_DIST); fprintf(file, "/hatchpath {\n" @@ -245,7 +309,21 @@ int postscript(FILE *file) " llx add dup lly moveto\n" " ury lly sub add ury lineto stroke\n" " } for\n" -" grestore newpath } def\n", HATCH); +" grestore newpath } def\n", PS_HATCH); + + fprintf(file, +"/backhatchpath {\n" +" gsave pathbbox clip newpath\n" +" /ury exch def /urx exch def /lly exch def /llx exch def\n" +" 0 %d ury lly sub urx llx sub add {\n" /* for 0 to urx-llx_ury-lly */ +" llx add dup lly moveto\n" +" ury lly sub sub ury lineto stroke\n" +" } for\n" +" grestore newpath } def\n", PS_HATCH); + +fprintf(file, +"/crosspath {\n" +" gsave hatchpath grestore backhatchpath } def\n"); /* * Stack: font string width height factor -> factor @@ -272,6 +350,19 @@ int postscript(FILE *file) " grestore\n" " llx urx sub 2 div lly ury sub 2 div rmoveto } def\n"); + /* + * Stack: string dist -> string + */ + + fprintf(file, +"/hcenter {\n" +" /off exch def\n" +" gsave dup false charpath pathbbox\n" +" /ury exch def /urx exch def /lly exch def /llx exch def\n" +" grestore\n" +" llx urx sub 2 div\n" +" currentpoint exch pop lly sub off add rmoveto } def\n"); + /* * Stack: string outline_width -> - */ diff --git a/util.h b/util.h index 639984a..173b38f 100644 --- a/util.h +++ b/util.h @@ -48,7 +48,8 @@ char *stralloc_vprintf(const char *fmt, va_list ap); -char *stralloc_printf(const char *fmt, ...); +char *stralloc_printf(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); int is_id_char(char c, int first); int is_id(const char *s);