r5374 - in trunk/eda: . fped

werner at docs.openmoko.org werner at docs.openmoko.org
Mon Aug 3 18:12:47 CEST 2009


Author: werner
Date: 2009-08-03 18:12:47 +0200 (Mon, 03 Aug 2009)
New Revision: 5374

Added:
   trunk/eda/fped/
   trunk/eda/fped/Makefile
   trunk/eda/fped/README
   trunk/eda/fped/TODO
   trunk/eda/fped/coord.c
   trunk/eda/fped/coord.h
   trunk/eda/fped/error.c
   trunk/eda/fped/error.h
   trunk/eda/fped/expr.c
   trunk/eda/fped/expr.h
   trunk/eda/fped/fpd.l
   trunk/eda/fped/fpd.y
   trunk/eda/fped/fped.c
   trunk/eda/fped/gui.c
   trunk/eda/fped/gui.h
   trunk/eda/fped/gui_canvas.c
   trunk/eda/fped/gui_canvas.h
   trunk/eda/fped/gui_icons.c
   trunk/eda/fped/gui_icons.h
   trunk/eda/fped/gui_inst.c
   trunk/eda/fped/gui_inst.h
   trunk/eda/fped/gui_status.c
   trunk/eda/fped/gui_status.h
   trunk/eda/fped/gui_style.c
   trunk/eda/fped/gui_style.h
   trunk/eda/fped/gui_util.c
   trunk/eda/fped/gui_util.h
   trunk/eda/fped/icons/
   trunk/eda/fped/inst.c
   trunk/eda/fped/inst.h
   trunk/eda/fped/obj.c
   trunk/eda/fped/obj.h
   trunk/eda/fped/qfn.fpd
   trunk/eda/fped/unparse.c
   trunk/eda/fped/unparse.h
   trunk/eda/fped/util.c
   trunk/eda/fped/util.h
Removed:
   trunk/eda/fped/Makefile
   trunk/eda/fped/TODO
   trunk/eda/fped/coord.c
   trunk/eda/fped/coord.h
   trunk/eda/fped/error.c
   trunk/eda/fped/error.h
   trunk/eda/fped/expr.c
   trunk/eda/fped/expr.h
   trunk/eda/fped/fpd.l
   trunk/eda/fped/fpd.y
   trunk/eda/fped/fped.c
   trunk/eda/fped/gui.c
   trunk/eda/fped/gui.h
   trunk/eda/fped/gui_canvas.c
   trunk/eda/fped/gui_canvas.h
   trunk/eda/fped/gui_inst.c
   trunk/eda/fped/gui_inst.h
   trunk/eda/fped/gui_status.c
   trunk/eda/fped/gui_status.h
   trunk/eda/fped/gui_style.c
   trunk/eda/fped/gui_style.h
   trunk/eda/fped/inst.c
   trunk/eda/fped/inst.h
   trunk/eda/fped/obj.c
   trunk/eda/fped/obj.h
   trunk/eda/fped/qfn.fpd
   trunk/eda/fped/util.c
   trunk/eda/fped/util.h
Log:
Moved fped over to /trunk/eda



Copied: trunk/eda/fped (from rev 5332, developers/werner/fped)

Deleted: trunk/eda/fped/Makefile
===================================================================
--- developers/werner/fped/Makefile	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/Makefile	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,91 +0,0 @@
-#
-# Makefile - Makefile of fped, the footprint editor
-#
-# 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.
-#
-
-OBJS = fped.o expr.o coord.o obj.o inst.o util.o error.o \
-       cpp.o lex.yy.o y.tab.o \
-       gui.o gui_style.o gui_inst.o gui_status.o gui_canvas.o
-
-CFLAGS_GTK = `pkg-config --cflags gtk+-2.0`
-LIBS_GTK = `pkg-config --libs gtk+-2.0`
-
-CFLAGS_WARN=-Wall -Wshadow -Wmissing-prototypes \
-            -Wmissing-declarations
-CFLAGS=-g $(CFLAGS_GTK) -DCPP='"cpp"' $(CFLAGS_WARN)
-SLOPPY=-Wno-unused -Wno-implicit-function-declaration -Wno-missing-prototypes \
-       -Wno-missing-declarations
-LDLIBS = -lm -lfl $(LIBS_GTK)
-YACC=bison -y
-YYFLAGS=-v
-
-# ----- Verbosity control -----------------------------------------------------
-
-CPP := $(CPP)   # make sure changing CC won't affect CPP
-
-CC_normal	:= $(CC)
-YACC_normal	:= $(YACC)
-LEX_normal	:= $(LEX)
-DEPEND_normal = \
-  $(CPP) $(CFLAGS) -MM -MG *.c >.depend || \
-  { rm -f .depend; exit 1; }
-
-CC_quiet	= @echo "  CC       " $@ && $(CC_normal)
-YACC_quiet	= @echo "  YACC     " $@ && $(YACC_normal)
-LEX_quiet	= @echo "  LEX      " $@ && $(LEX_normal)
-GEN_quiet	= @echo "  GENERATE " $@ &&
-DEPEND_quiet	= @echo "  DEPENDENCIES" && $(DEPEND_normal)
-
-ifeq ($(V),1)
-    CC		= $(CC_normal)
-    LEX		= $(LEX_normal)
-    YACC	= $(YACC_normal)
-    GEN		=
-    DEPEND	= $(DEPEND_normal)
-else
-    CC		= $(CC_quiet)
-    LEX		= $(LEX_quiet)
-    YACC	= $(YACC_quiet)
-    GEN		= $(GEN_quiet)
-    DEPEND	= $(DEPEND_quiet)
-endif
-
-# ----- Rules -----------------------------------------------------------------
-
-all:		fped
-
-fped:		$(OBJS)
-		$(CC) -o $@ $(OBJS) $(LDLIBS)
-
-lex.yy.c:	fpd.l y.tab.h
-		$(LEX) fpd.l
-
-lex.yy.o:	lex.yy.c y.tab.h
-		$(CC) -c $(CFLAGS) $(SLOPPY) lex.yy.c
-
-y.tab.c y.tab.h: fpd.y
-		$(YACC) $(YYFLAGS) -d fpd.y
-
-y.tab.o:	y.tab.c
-		$(CC) -c $(CFLAGS) $(SLOPPY) y.tab.c
-
-# ----- Dependencies ----------------------------------------------------------
-
-dep depend .depend: lex.yy.c y.tab.h y.tab.c
-		$(DEPEND)
-
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
-# ----- Cleanup ---------------------------------------------------------------
-
-clean:
-		rm -f $(OBJS) lex.yy.c y.tab.c y.tab.h y.output

Copied: trunk/eda/fped/Makefile (from rev 5363, developers/werner/fped/Makefile)
===================================================================
--- trunk/eda/fped/Makefile	                        (rev 0)
+++ trunk/eda/fped/Makefile	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,113 @@
+#
+# Makefile - Makefile of fped, the footprint editor
+#
+# 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.
+#
+
+OBJS = fped.o expr.o coord.o obj.o inst.o util.o error.o \
+       unparse.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_icons.o
+
+XPMS = point.xpm vec.xpm frame.xpm \
+       line.xpm rect.xpm pad.xpm circ.xpm arc.xpm meas.xpm
+
+CFLAGS_GTK = `pkg-config --cflags gtk+-2.0`
+LIBS_GTK = `pkg-config --libs gtk+-2.0`
+
+CFLAGS_WARN=-Wall -Wshadow -Wmissing-prototypes \
+            -Wmissing-declarations
+CFLAGS=-g $(CFLAGS_GTK) -DCPP='"cpp"' $(CFLAGS_WARN)
+SLOPPY=-Wno-unused -Wno-implicit-function-declaration -Wno-missing-prototypes \
+       -Wno-missing-declarations
+LDLIBS = -lm -lfl $(LIBS_GTK)
+YACC=bison -y
+YYFLAGS=-v
+
+# ----- Verbosity control -----------------------------------------------------
+
+CPP := $(CPP)   # make sure changing CC won't affect CPP
+
+CC_normal	:= $(CC)
+YACC_normal	:= $(YACC)
+LEX_normal	:= $(LEX)
+DEPEND_normal = \
+  $(CPP) $(CFLAGS) -MM -MG *.c >.depend || \
+  { rm -f .depend; exit 1; }
+
+CC_quiet	= @echo "  CC       " $@ && $(CC_normal)
+YACC_quiet	= @echo "  YACC     " $@ && $(YACC_normal)
+LEX_quiet	= @echo "  LEX      " $@ && $(LEX_normal)
+GEN_quiet	= @echo "  GENERATE " $@ &&
+DEPEND_quiet	= @echo "  DEPENDENCIES" && $(DEPEND_normal)
+
+ifeq ($(V),1)
+    CC		= $(CC_normal)
+    LEX		= $(LEX_normal)
+    YACC	= $(YACC_normal)
+    GEN		=
+    DEPEND	= $(DEPEND_normal)
+else
+    CC		= $(CC_quiet)
+    LEX		= $(LEX_quiet)
+    YACC	= $(YACC_quiet)
+    GEN		= $(GEN_quiet)
+    DEPEND	= $(DEPEND_quiet)
+endif
+
+# ----- Rules -----------------------------------------------------------------
+
+.PHONY:		all dep depend clean
+
+.SUFFIXES:	.fig .xpm
+
+# generate 26x26 pixels icons, then drop the 1-pixel frame
+
+# this adds a magenta border
+# sed '/2 2 0 1 /{s//2 2 0 15 /;s/ 0 7 / 22 7 /;}' $< | \
+
+.fig.xpm:
+		fig2dev -L xpm -Z 0.32 -S 4 $< | \
+		  convert -crop 24x24+1+1 - - | \
+		  sed s/xpm__/xpm_`basename $@ .xpm`/ >$@
+
+all:		fped
+
+fped:		$(OBJS)
+		$(CC) -o $@ $(OBJS) $(LDLIBS)
+
+lex.yy.c:	fpd.l y.tab.h
+		$(LEX) fpd.l
+
+lex.yy.o:	lex.yy.c y.tab.h
+		$(CC) -c $(CFLAGS) $(SLOPPY) lex.yy.c
+
+y.tab.c y.tab.h: fpd.y
+		$(YACC) $(YYFLAGS) -d fpd.y
+
+y.tab.o:	y.tab.c
+		$(CC) -c $(CFLAGS) $(SLOPPY) y.tab.c
+
+gui_icons.o:	$(XPMS:%=icons/%)
+
+# ----- Dependencies ----------------------------------------------------------
+
+dep depend .depend: lex.yy.c y.tab.h y.tab.c
+		$(DEPEND)
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+# ----- Cleanup ---------------------------------------------------------------
+
+      clean:
+		rm -f $(OBJS) $(XPMS:%=icons/%)
+		rm -f lex.yy.c y.tab.c y.tab.h y.output .depend

Copied: trunk/eda/fped/README (from rev 5367, developers/werner/fped/README)
===================================================================
--- trunk/eda/fped/README	                        (rev 0)
+++ trunk/eda/fped/README	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,339 @@
+fped - Footprint editor
+=======================
+
+fped is an editor that allows the interactive creation of footprints of
+electronic components. Footprint definitions are stored in a text format
+that resembles a programming language.
+
+The language is constrained such that anything that can be expressed in
+the textual definition also has a straightforward equivalent operation
+that can be performed through the GUI.
+
+
+Motivation
+----------
+
+KiCad already includes a footprint ("module") editor, so why do we need
+a new one ? The issue with footprint generation for KiCad is that the
+built-in module editor is basically a drawing program that only captures
+the result of the module author's interpretation of a footprint drawing,
+but does not include the steps that led to this construction.
+
+Furthermore, accurate measuring of dimensions in the drawing can only be
+done manually in the module editor, which makes review difficult and
+time-consuming.
+
+In fped, the construction process is made explicit and each step can be
+expressed in terms of the parameters that appear in the vendor's
+drawing. Dimensions can be explicitly measured and the results can be
+included in the graphical output generated by fped.
+
+Directly using parameters and construction steps from the reference
+drawing reduces the risk of mistakes. Visualizing the construction
+process and verificative measurements helps efficient and accurate
+review.
+
+
+Footprint definition file format
+--------------------------------
+
+Footprint definitions are stored in text files. The program "fped" reads
+and (soon) writes such files, visualizes their content, and provides a
+graphical editor for them.
+
+The syntax is unique and draws from elements of a variety of languages
+commonly found on unix systems. One specialty is that there are no
+reserved words - the language keywords appear only at the beginning of
+a line and can thus be recognized as such without restricting their use
+for identifiers. This reduces the risk of creating incompatibilities
+with existing designs when introduction future language features.
+
+fped uses the C preprocessor for comments, conditional compilation,
+and - to a limited extent - also macros. Long lines can be split by
+ending them with a backslash.
+
+
+Geometry model
+--------------
+
+The geometry model consists of frames, vectors, and objects. The shape of
+objects is defined by a number of points. These points are produced by
+concatenating vectors.
+
+E.g., to draw a line from (1mm, 1mm) to (2mm, 2mm), one would make a
+vector from the origin to (1mm, 1mm) and one either from the origin or
+from the previous vector to (2mm, 2mm), and then make a line connecting
+the two points.
+
+
+Units
+- - -
+
+fped can calculate in mm and mil. Units are specified by following a
+number with "mm" or "mil", separated by zero or more spaces or tabs.
+
+Examples:
+
+1mm
+2 mil
+
+Units can be mixed in calculations, e.g.,
+
+set a = 1mm+20mil
+set b = 10*1mm
+
+All values used as dimensions must be either mm or mil.
+
+
+Vectors
+- - - -
+
+Vectors can be anonymous or they can be named for future reference:
+
+vec <base> ( <x-expr>, <y-expr> )
+<identifier>: vec <base>  ( <x-expr>, <y-expr> )
+
+The base can be one of the following items:
+
+- @ is the origin of the frame containing the vector
+- . is the end of the previous vector in this frame
+- <identifier> is the name of a previous vector in the same frame
+
+The following example would draw the line described in the previous
+section:
+
+a: vec @(1mm, 1mm)
+b: vec .(1mm, 1mm)
+line a b
+
+
+Silk screen objects
+- - - - - - - - - -
+
+The output of fped is a footprint definition that contains pads and silk
+screen drawings (we may add more layers in the future). These items are
+called "objects". Their geometry is defined through points obtained with
+vectors.
+
+A line connects two points:
+
+line <point-a> <point-b> [<width>]
+
+The points can be specified with @, ., and an identifier, just like
+a vector base. The option width specifies the thickness of the silk
+screen line. If omitted, a hard-coded default of 15 mil is used.
+
+A rectangle has sides parallel to the x and y axis and is defined
+by two diagonally opposite corners:
+
+rect <point-a> <point-b> [<width>]
+
+A circle is defined by its center and a point on the circle:
+
+circ <center> <point> [<width>]
+
+This example draws a unit circle:
+
+vec @(1mm, 0mm)
+circ @ .
+
+An arc is like a circle, but the part of the circle drawn is determined
+by two points. The first point determines the radius and the starting
+angle. The second point only determines the end angle but its distance
+from the center is ignored.
+
+arc <center> <radius> <end> [<width>]
+
+The arc is drawn in a counter-clockwise direction. The following example
+draws an arc of the unit circle in the x > 0, y > 0 quadrant:
+
+from: vec @(1mm, 0mm)
+to: vec @(0mm, 1mm)
+arc @ from to
+
+
+Pads
+- -
+
+Pads are similar to rectangles, but they also have a name.
+
+pad "<name>" <point-a> <point-b>
+
+Variables can be expanded in a pad's name by prefixing their name with
+a dollar sign. The ${name} syntax is also available.
+
+Example:
+
+vec @(1mm, 1mm)
+pad "1" @ .
+
+
+Measurements
+- - - - - -
+
+Measurements show the distance between two points:
+
+meas <point-a> <point-b> <offset>
+
+The offset is the distance from the imaginary line connecting points A
+and B the measurement line is draw:
+
+- if the offset is 0mm, the line will connect A and B
+- if the offset is positive, the line would be on the left-hand side when
+  traveling from A to B
+- if the offset is negative , the line would be on the right-hand side when
+  traveling from A to B
+
+Example:
+
+a: vec @(-1mm, 1mm)
+b: vec @(1mm, 1mm)
+meas a b 0.2 mm
+
+
+Frames
+- - -
+
+Frames are used to group things and to reuse them multiple times. Frames
+must be defined before they can be used:
+
+frame <name> {
+    ... items ...
+}
+
+Once defined, a frame is placed at a given location with
+
+frame <name> <point>
+
+The frame definitions must precede all other items in a footprint
+description. Frames cannot be defined inside other frames, but frames
+can invoke each other recursively.
+
+For example, this puts two unity squares, one centered at (0 mm, 0 mm),
+the other at (2 mm, 0 mm):
+
+frame unit_square {
+	a: vec @(-0.5mm, -0.5mm)
+	b: vec .(1mm, 1mm)
+	rect a b
+}
+
+frame unit_square @
+vec @(2mm, 0mm)
+frame unit_square .
+
+
+Names and variables
+-------------------
+
+fped uses several name spaces:
+
+- frame names occupy one global name space
+
+- vector names occupy name spaces delimited by the frame they're
+  contained in. A vector name is only visible inside the frame in which
+  it is defined.
+  
+- variable names occupy name spaces delimited by the frame they're
+  contained in. A variable lookup starts in the frame in which the
+  corresponding expression appears and propagates to outer frames
+  until the variable is found.
+
+- pads occupy one global name space (this is currently not enforced)
+
+Note that names cannot be redefined. E.g., this does not work:
+
+set a = 1
+set a = a+1
+
+The names spaces of frames, vectors, variables, and pads are separate
+from each other.
+
+
+Simple variables
+- - - - - - - -
+
+A variable with a single value is defined with the following
+assignment syntax:
+
+set <identifier> = <expression>
+
+Example:
+
+set a = b+2
+
+
+Loops
+- - -
+
+A loop is a variable with a range of values:
+
+loop <identifier> = <from>, <to>
+
+The variable assumes all the values i for <from> <= i <= <to>, in
+increments of one. E.g.,
+
+loop n = 1, 3
+
+and
+
+loop n = 1, 3
+
+both assigns the values 1, 2, and 3 to the variable "n".
+
+When a loop is executed, the objects contained in the body of the
+enclosing frame are generated for each value of the variable. If
+a frame contains multiple loops, all possible combinations of the
+values are generated.
+
+The following example draws three concentric circles around the
+origin, with radii 1, 2, and 3:
+
+loop x = 1, 3
+vec @(x*1mm, 0mm)
+circ @ .
+
+
+Tables
+- - -
+
+Tables combine values for multiple variables. Like loops, they are
+used to iteratively generate objects. A table begins with a row of
+variable names, followed by one or more rows with values. Rows are
+enclosed in curly braces and their elements are separated by commas.
+
+table
+    { <identifier>, ... }
+    { <expression>, ... }
+    ...
+
+Like loops, tables are iterated to generate objects. The following
+example is equivalent to the one in the previous section:
+
+table
+    { x }
+    { 1mm }
+    { 2mm }
+    { 3mm }
+vec @(x, 0mm)
+circ @ .
+
+Note that we can set the unit of the values directly in this case.
+
+Iteration is performed over rows. All variables of the table are set
+to the value in the respective row at the same time. For example, in
+
+table
+    { x, y }
+    { 1, 2 }
+    { 3, 4 }
+
+(x, y) assume the values (1, 2) and (3, 4).
+
+
+Expressions
+-----------
+
+Expressions can contain numeric constants (in non-exponential notation),
+variable names, the arithmetic operations +, -, *, /, and unary -.
+Parentheses can be used to change precedence.

Deleted: trunk/eda/fped/TODO
===================================================================
--- developers/werner/fped/TODO	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/TODO	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,27 +0,0 @@
-- make frame selection work
-- add table/var/loop representation
-- Q: should loop be (start, last) or (start, iterations) ?
-- add row selection
-- change vector circle color (also, highlight on hover ?)
-- stack elements (1): frames, pads, silk, vecs
-- stack elements (2): all unselected below all selected
-- stack elements (3): circle on top of vec
-- detect recursive evaluation (through variables)
-- eliminate duplicate instances
-- populate input area (still needed: mm/mil, rezoom)
-- add vec editor
-- add obj editor
-- decide on table presentation
-- add table/var/loop editor
-- add incremental expression parser (for editor)
-- make units part of value and check for conformity
-- add default unit (combine with grid unit selection ?)
-- consider adding auto/mm/mil selection for each dimension
-- syntax seems a little cryptic. too many dots and at signs.
-- add measurements
-- arc syntax is weird, with comma where we use spaces
-- Q: allow reassignment of vector names ?
-- add KiCad output
-- add postscript output
-- add option to include/omit helper vecs and frames (display and postscript)
-- Q: how do we handle stacks of objects ?

Copied: trunk/eda/fped/TODO (from rev 5373, developers/werner/fped/TODO)
===================================================================
--- trunk/eda/fped/TODO	                        (rev 0)
+++ trunk/eda/fped/TODO	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,54 @@
+Missing features:
+- add row selection
+- populate input area (still needed: mm/mil, rezoom)
+- add vec editor (need to be able to edit name, x, and y)
+- add obj editor
+- add table/var/loop editor (missing: add col/row, add/del var/table/loop)
+- add default unit (combine with grid unit selection ?)
+- consider adding auto/mm/mil selection for each dimension
+- add measurements (partly done. still needed: find out how to define
+  non-trivial endpoints, e.g., some vector in last iteration of loop)
+- add KiCad output
+- add postscript output
+- add option to include/omit helper vecs and frames (display and postscript)
+
+Error detection:
+- eliminate duplicate instances
+
+Style:
+- make column of entry field greedily consume all unallocated space
+
+Bugs:
+- default silk width has no business being hard-coded in obj.c
+
+Code cleanup:
+- merge edit_unique with edit_name
+- merge find_var_in_frame with similar mechanisms in expr.c and fpd.y
+- add regression tests
+
+Open decisions:
+- decide on table presentation (merge frame and vars into single entity ?)
+- Q: should loop be (start, last) or (start, iterations) ? or start ... last ?
+- change vector circle color ? (also, highlight on hover ?)
+- Q: allow reassignment of vector names ?
+  A1: no: would cause confusion in GUI (vectors could become orphaned)
+  A2: yes. but we don't change the linkage.
+- Q: how do we handle stacks of objects ?
+  A: we don't but we make it easy to avoid them, by giving a good zoom,
+     flexible selection, and by disallowing stacks of identical objects in the
+     first place.
+- Q: add frame arguments ? (e.g., .frame pad(pin_num_offset) ...)
+  we can already approximate this by introducing an intermediate table that
+  sets up the arguments (provided that we don't consider vectors as well)
+- Q: should we make it a requirement to generate objects only once ?
+  A: almost certainly yes.
+
+Future directions:
+- future: consider using cairo instead of gdk
+- live update of value when entering strings and expressions ?
+- advanced: non-standard solder mask
+- advanced: solder paste exceptions (subtractive, additive)
+- advanced: silk line width
+- future: when encountering an error after a change, we could try to find the
+  same element in the old instance, and select it
+- future: consider editing off-canvas items in place

Deleted: trunk/eda/fped/coord.c
===================================================================
--- developers/werner/fped/coord.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/coord.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,62 +0,0 @@
-/*
- * coord.c - Coordinate representation and basic operations
- *
- * 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 <math.h>
-
-#include "coord.h"
-
-
-struct coord normalize(struct coord v, unit_type len)
-{
-	double f;
-
-	f = len/hypot(v.x, v.y);
-	v.x *= f;
-	v.y *= f;
-	return v;
-}
-
-
-struct coord rotate(struct coord v, double angle)
-{
-	double rad = M_PI*angle/180.0;
-	struct coord res;
-
-	res.x = v.x*cos(rad)-v.y*sin(rad);
-	res.y = v.y*cos(rad)+v.x*sin(rad);
-	return res;
-}
-
-
-struct coord add_vec(struct coord a, struct coord b)
-{
-	a.x += b.x;
-	a.y += b.y;
-	return a;
-}
-
-
-struct coord sub_vec(struct coord a, struct coord b)
-{
-	a.x -= b.x;
-	a.y -= b.y;
-	return a;
-}
-
-
-struct coord neg_vec(struct coord v)
-{
-	v.x = -v.x; 
-	v.y = -v.y;
-	return v;
-}

Copied: trunk/eda/fped/coord.c (from rev 5368, developers/werner/fped/coord.c)
===================================================================
--- trunk/eda/fped/coord.c	                        (rev 0)
+++ trunk/eda/fped/coord.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,164 @@
+/*
+ * coord.c - Coordinate representation and basic operations
+ *
+ * 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 <math.h>
+
+#include "coord.h"
+
+
+/* ----- unit conversion --------------------------------------------------- */
+
+
+double mm_to_mil(double mm, int exponent)
+{
+	return mm*pow(MIL_IN_MM, -exponent);
+}
+
+
+double mil_to_mm(double mil, int exponent)
+{
+        return mil*pow(MIL_IN_MM, exponent);
+}
+
+/* ----- vector operations ------------------------------------------------- */
+
+
+struct coord normalize(struct coord v, unit_type len)
+{
+	double f;
+
+	f = len/hypot(v.x, v.y);
+	v.x *= f;
+	v.y *= f;
+	return v;
+}
+
+
+struct coord rotate(struct coord v, double angle)
+{
+	double rad = M_PI*angle/180.0;
+	struct coord res;
+
+	res.x = v.x*cos(rad)-v.y*sin(rad);
+	res.y = v.y*cos(rad)+v.x*sin(rad);
+	return res;
+}
+
+
+struct coord add_vec(struct coord a, struct coord b)
+{
+	a.x += b.x;
+	a.y += b.y;
+	return a;
+}
+
+
+struct coord sub_vec(struct coord a, struct coord b)
+{
+	a.x -= b.x;
+	a.y -= b.y;
+	return a;
+}
+
+
+struct coord neg_vec(struct coord v)
+{
+	v.x = -v.x; 
+	v.y = -v.y;
+	return v;
+}
+
+
+/* ----- distance calculations --------------------------------------------- */
+
+
+unit_type dist_point(struct coord a, struct coord b)
+{
+	return hypot(a.x-b.x, a.y-b.y);
+}
+
+
+static unit_type dist_line_xy(unit_type px, unit_type py,
+    unit_type ax, unit_type ay, unit_type bx, unit_type by)
+{
+	unit_type d_min, d;
+	double a, f;
+
+	d_min = hypot(ax-px, ay-py);
+	d = hypot(bx-px, by-py);
+	if (d < d_min)
+		d_min = d;
+	if (ax != bx || ay != by) {
+		/*
+		 * We make a the line vector from point B and b the vector from
+		 * B to point P. Then we calculate the projection of b on a.
+		 */
+		ax -= bx;
+		ay -= by;
+		bx = px-bx;
+		by = py-by;
+		a = hypot(ax, ay);
+		f = ((double) ax*bx+(double) ay*by)/a/a;
+		if (f >= 0 && f <= 1) {
+			bx -= f*ax;
+			by -= f*ay;
+			d = hypot(bx, by);
+			if (d < d_min)
+				d_min = d;
+		}
+	}
+	return d_min;
+}
+
+
+unit_type dist_line(struct coord p, struct coord a, struct coord b)
+{
+	return dist_line_xy(p.x, p.y, a.x, a.y, b.x, b.y);
+}
+
+
+unit_type dist_rect(struct coord p, struct coord min, struct coord max)
+{
+	unit_type d_min, d;
+
+	d_min = dist_line_xy(p.x, p.y, min.x, min.y, max.x, min.y);
+	d = dist_line_xy(p.x, p.y, min.x, min.y, min.x, max.y);
+	if (d < d_min)
+		d_min = d;
+	d = dist_line_xy(p.x, p.y, min.x, max.y, max.x, max.y);
+	if (d < d_min)
+		d_min = d;
+	d = dist_line_xy(p.x, p.y, max.x, min.y, max.x, max.y);
+	if (d < d_min)
+		d_min = d;
+	return d_min;
+}
+
+
+int inside_rect(struct coord p, struct coord min, struct coord max)
+{
+	if (p.x < min.x || p.x > max.x)
+		return 0;
+	if (p.y < min.y || p.y > max.y)
+		return 0;
+	return 1;
+}
+
+
+unit_type dist_circle(struct coord p, struct coord c, unit_type r)
+{
+	unit_type d;
+
+	d = hypot(p.x-c.x, p.y-c.y);
+        return fabs(d-r);
+}

Deleted: trunk/eda/fped/coord.h
===================================================================
--- developers/werner/fped/coord.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/coord.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,67 +0,0 @@
-/*
- * coord.h - Coordinate representation and basic operations
- *
- * 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 COORD_H
-#define COORD_H
-
-#include <stdint.h>
-
-
-#define MICRON_UNITS	10
-#define	MIL_UNITS	(25.4*MICRON_UNITS)
-#define	MM_UNITS	(1000.0*MICRON_UNITS)
-#define	KICAD_UNIT	(10.0*MIL_UNITS)
-
-
-typedef int32_t unit_type;
-
-
-#define	UNIT_ERROR	((unit_type) 1 << (sizeof(unit_type)*8-1))
-
-
-struct coord {
-	unit_type x, y;
-};
-
-
-static inline unit_type mil_to_units(double mil)
-{
-	return mil*MIL_UNITS;
-}
-
-
-static inline unit_type mm_to_units(double mm)
-{
-	return mm*MM_UNITS;
-}
-
-
-static inline double units_to_mm(unit_type u)
-{
-	return (double) u/MM_UNITS;
-}
-
-
-static inline double units_to_kicad(unit_type u)
-{
-	return (double) u/KICAD_UNIT;
-}
-
-
-struct coord normalize(struct coord v, unit_type len);
-struct coord rotate(struct coord v, double angle);
-struct coord add_vec(struct coord a, struct coord b);
-struct coord sub_vec(struct coord a, struct coord b);
-struct coord neg_vec(struct coord v);
-
-#endif /* !COORD_H */

Copied: trunk/eda/fped/coord.h (from rev 5341, developers/werner/fped/coord.h)
===================================================================
--- trunk/eda/fped/coord.h	                        (rev 0)
+++ trunk/eda/fped/coord.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,78 @@
+/*
+ * coord.h - Coordinate representation and basic operations
+ *
+ * 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 COORD_H
+#define COORD_H
+
+#include <stdint.h>
+
+
+#define MICRON_UNITS	10
+#define	MIL_UNITS	(25.4*MICRON_UNITS)
+#define	MM_UNITS	(1000.0*MICRON_UNITS)
+#define	KICAD_UNIT	(10.0*MIL_UNITS)
+
+#define	MIL_IN_MM	0.0254
+
+
+typedef int32_t unit_type;
+
+
+#define	UNIT_ERROR	((unit_type) 1 << (sizeof(unit_type)*8-1))
+
+
+struct coord {
+	unit_type x, y;
+};
+
+
+static inline unit_type mil_to_units(double mil)
+{
+	return mil*MIL_UNITS;
+}
+
+
+static inline unit_type mm_to_units(double mm)
+{
+	return mm*MM_UNITS;
+}
+
+
+static inline double units_to_mm(unit_type u)
+{
+	return (double) u/MM_UNITS;
+}
+
+
+static inline double units_to_kicad(unit_type u)
+{
+	return (double) u/KICAD_UNIT;
+}
+
+
+double mm_to_mil(double mm, int exponent);
+double mil_to_mm(double mil, int exponent);
+
+struct coord normalize(struct coord v, unit_type len);
+struct coord rotate(struct coord v, double angle);
+struct coord add_vec(struct coord a, struct coord b);
+struct coord sub_vec(struct coord a, struct coord b);
+struct coord neg_vec(struct coord v);
+
+unit_type dist_point(struct coord a, struct coord b);
+unit_type dist_line(struct coord p, struct coord a, struct coord b);
+unit_type dist_rect(struct coord p, struct coord min, struct coord max);
+int inside_rect(struct coord p, struct coord min, struct coord max);
+unit_type dist_circle(struct coord p, struct coord c, unit_type r);
+
+#endif /* !COORD_H */

Deleted: trunk/eda/fped/error.c
===================================================================
--- developers/werner/fped/error.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/error.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,55 +0,0 @@
-/*
- * error.c - Error reporting
- *
- * 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 <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "error.h"
-
-
-int lineno = 1;
-
-extern char *yytext;
-
-
-void __attribute__((noreturn)) yyerrorf(const char *fmt, ...)
-{
-	va_list ap;
-
-	fprintf(stderr, "%d: ", lineno);
-	va_start(ap, fmt);
-	vfprintf(stderr, fmt, ap);
-	va_end(ap);
-	fprintf(stderr, "near \"%s\"\n", yytext);
-	exit(1);
-}
-
-
-void __attribute__((noreturn)) yyerror(const char *s)
-{
-	yyerrorf("%s", s);
-}
-
-
-void fail(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vfprintf(stderr, fmt, ap);
-	va_end(ap);
-	fprintf(stderr, "\n");
-	exit(1);
-}
-

Copied: trunk/eda/fped/error.c (from rev 5357, developers/werner/fped/error.c)
===================================================================
--- trunk/eda/fped/error.c	                        (rev 0)
+++ trunk/eda/fped/error.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,76 @@
+/*
+ * error.c - Error reporting
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "error.h"
+
+
+extern char *yytext;
+
+int lineno = 1;
+void (*reporter)(const char *s) = report_to_stderr;
+
+
+void yyerrorf(const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	int n;
+
+	va_start(ap, fmt);
+	n = vsnprintf(NULL, 0, fmt, ap);
+	va_end(ap);
+	buf = alloc_size(n+1);
+	va_start(ap, fmt);
+	vsnprintf(buf, n+1, fmt, ap);
+	va_end(ap);
+	fail(buf);
+	free(buf);
+}
+
+
+void yyerror(const char *s)
+{
+	yyerrorf("%s", s);
+}
+
+
+void report_parse_error(const char *s)
+{
+	fprintf(stderr, "%d: %s near \"%s\" ", lineno, s, yytext);
+	exit(1);
+}
+
+
+void report_to_stderr(const char *s)
+{
+	fprintf(stderr, "%s\n", s);
+	exit(1);
+}
+
+
+void fail(const char *fmt, ...)
+{
+	va_list ap;
+	char *s;
+
+	va_start(ap, fmt);
+	s = stralloc_vprintf(fmt, ap);
+	va_end(ap);
+	reporter(s);
+	free(s);
+}

Deleted: trunk/eda/fped/error.h
===================================================================
--- developers/werner/fped/error.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/error.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,26 +0,0 @@
-/*
- * error.h - Error reporting
- *
- * 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 ERROR_H
-#define ERROR_H
-
-
-int lineno;
-
-
-void __attribute__((noreturn)) yyerrorf(const char *fmt, ...);
-void __attribute__((noreturn)) yyerror(const char *s);
-
-void __attribute__((noreturn)) fail(const char *fmt, ...);
-
-#endif /* !ERROR_H */

Copied: trunk/eda/fped/error.h (from rev 5357, developers/werner/fped/error.h)
===================================================================
--- trunk/eda/fped/error.h	                        (rev 0)
+++ trunk/eda/fped/error.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,30 @@
+/*
+ * error.h - Error reporting
+ *
+ * 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 ERROR_H
+#define ERROR_H
+
+
+extern int lineno;
+
+extern void (*reporter)(const char *s);
+
+
+void yyerrorf(const char *fmt, ...);
+void yyerror(const char *s);
+
+void report_to_stderr(const char *s);
+void report_parse_error(const char *s);
+void fail(const char *fmt, ...);
+
+#endif /* !ERROR_H */

Deleted: trunk/eda/fped/expr.c
===================================================================
--- developers/werner/fped/expr.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/expr.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,143 +0,0 @@
-/*
- * expr.c - Expressions and values
- *
- * 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 <stdlib.h>
-
-#include "util.h"
-#include "error.h"
-#include "obj.h"
-#include "expr.h"
-
-
-double op_num(const struct expr *self, const struct frame *frame)
-{
-	return self->u.num;
-}
-
-
-double eval_var(const struct frame *frame, const char *name)
-{
-	const struct table *table;
-	const struct loop *loop;
-	const struct value *value;
-	const struct var *var;
-
-	for (table = frame->tables; table; table = table->next) {
-		value = table->curr_row->values;
-		for (var = table->vars; var; var = var->next) {
-			if (var->name == name)
-				return eval_num(value->expr, frame);
-			value = value->next;
-		}
-	}
-	for (loop = frame->loops; loop; loop = loop->next)
-		if (loop->var == name)
-			return loop->curr_value;
-	if (frame->curr_parent)
-		return eval_var(frame->curr_parent, name);
-	return UNDEF;
-}
-
-
-double op_var(const struct expr *self, const struct frame *frame)
-{
-	double res;
-
-	res = eval_var(frame, self->u.var);
-	if (res == UNDEF)
-		fail("undefined variable \"%s\"", self->u.var);
-	return res;
-}
-
-
-double op_minus(const struct expr *self, const struct frame *frame)
-{
-	double res;
-
-	res = eval_num(self->u.op.a, frame);
-	return res == UNDEF ? UNDEF : -res;
-}
-
-
-#define	BINARY					\
-	double a, b;				\
-						\
-	a = eval_num(self->u.op.a, frame);	\
-	b = eval_num(self->u.op.b, frame);	\
-	if (a == UNDEF || b == UNDEF)		\
-		return UNDEF;			\
-
-
-double op_add(const struct expr *self, const struct frame *frame)
-{
-	BINARY;
-	return a+b;
-}
-
-
-double op_sub(const struct expr *self, const struct frame *frame)
-{
-	BINARY;
-	return a-b;
-}
-
-
-double op_mult(const struct expr *self, const struct frame *frame)
-{
-	BINARY;
-	return a*b;
-}
-
-
-double op_div(const struct expr *self, const struct frame *frame)
-{
-	BINARY;
-	if (!b) {
-		fail("Division by zero");
-		return UNDEF;
-	}
-	return a/b;
-}
-
-
-struct expr *new_op(op_type op)
-{
-	struct expr *expr;
-
-	expr = alloc_type(struct expr);
-	expr->op = op;
-	return expr;
-}
-
-
-struct expr *binary_op(op_type op, struct expr *a, struct expr *b)
-{
-	struct expr *expr;
-
-	expr = new_op(op);
-	expr->u.op.a = a;
-	expr->u.op.b = b;
-	return expr;
-}
-
-
-char *eval_str(const struct frame *frame, const struct expr *expr)
-{
-	abort();
-}
-
-
-double eval_num(const struct expr *expr, const struct frame *frame)
-{
-	return expr->op(expr, frame);
-}

Copied: trunk/eda/fped/expr.c (from rev 5373, developers/werner/fped/expr.c)
===================================================================
--- trunk/eda/fped/expr.c	                        (rev 0)
+++ trunk/eda/fped/expr.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,423 @@
+/*
+ * expr.c - Expressions and values
+ *
+ * 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 <stdlib.h>
+#include <math.h>
+
+#include "util.h"
+#include "error.h"
+#include "obj.h"
+#include "unparse.h"
+#include "expr.h"
+
+
+struct num undef = { .type = nt_none };
+
+
+/* ----- error reporting --------------------------------------------------- */
+
+
+void fail_expr(const struct expr *expr)
+{
+	char *s;
+
+	s = unparse(expr);
+	fail("in \"%s\" at line %d", s, expr->lineno);
+	free(s);
+}
+
+
+/* ----- unit conversion --------------------------------------------------- */
+
+
+const char *str_unit(struct num n)
+{
+	if (n.exponent == 0)
+		return "";
+	if (n.type == nt_mm) {
+		switch (n.exponent) {
+		case -2:
+			return "mm^-2";
+		case -1:
+			return "mm^-1";
+		case 1:
+			return "mm";
+		case 2:
+			return "mm^2";
+		default:
+			abort();
+		}
+	}
+	if (n.type == nt_mil) {
+		switch (n.exponent) {
+		case -2:
+			return "mil^(-2)";
+		case -1:
+			return "mil^(-1)";
+		case 1:
+			return "mil";
+		case 2:
+			return "mil^2";
+		default:
+			abort();
+		}
+	}
+	abort();
+}
+
+
+int to_unit(struct num *n)
+{
+	if (!is_distance(*n)) {
+		fail("%s^%d is not a distance",
+		    n->type == nt_mm ? "mm" : n->type == nt_mil ? "mil" : "?",
+		    n->exponent);
+		return 0;
+	}
+	switch (n->type) {
+	case nt_mil:
+		n->n = mil_to_units(n->n);
+		break;
+	case nt_mm:
+		n->n = mm_to_units(n->n);
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+
+/* ----- primary expressions ----------------------------------------------- */
+
+
+struct num op_num(const struct expr *self, const struct frame *frame)
+{
+	return self->u.num;
+}
+
+
+struct num eval_var(const struct frame *frame, const char *name)
+{
+	const struct table *table;
+	const struct loop *loop;
+	const struct value *value;
+	struct var *var;
+	struct num res;
+
+	for (table = frame->tables; table; table = table->next) {
+		value = table->curr_row->values;
+		for (var = table->vars; var; var = var->next) {
+			if (var->name == name) {
+				if (var->visited) {
+					fail("recursive evaluation through "
+					    "\"%s\"", name);
+					return undef;
+				}
+				var->visited = 1;
+				res = eval_num(value->expr, frame);
+				var->visited = 0;
+				return res;
+				
+			}
+			value = value->next;
+		}
+	}
+	for (loop = frame->loops; loop; loop = loop->next)
+		if (loop->var.name == name) {
+			if (!loop->initialized) {
+				fail("uninitialized loop \"%s\"", name);
+				return undef;
+			}
+			return make_num(loop->curr_value);
+		}
+	if (frame->curr_parent)
+		return eval_var(frame->curr_parent, name);
+	return undef;
+}
+
+
+struct num op_var(const struct expr *self, const struct frame *frame)
+{
+	struct num res;
+
+	res = eval_var(frame, self->u.var);
+	if (is_undef(res))
+		fail("undefined variable \"%s\"", self->u.var);
+	return res;
+}
+
+
+/* ----- arithmetic -------------------------------------------------------- */
+
+
+static struct num compatible_sum(struct num *a, struct num *b)
+{
+	struct num res;
+
+	if (a->type != b->type) {
+		if (a->type == nt_mil) {
+			a->type = nt_mm;
+			a->n = mil_to_mm(a->n, a->exponent);
+		}
+		if (b->type == nt_mil) {
+			b->type = nt_mm;
+			b->n = mil_to_mm(b->n, a->exponent);
+		}
+	}
+	if (a->exponent != b->exponent) {
+		fail("incompatible exponents (%d, %d)",
+		    a->exponent, b->exponent);
+		return undef;
+	}
+	res.type = a->type;
+	res.exponent = a->exponent;
+	return res;
+}
+
+
+static struct num compatible_mult(struct num *a, struct num *b,
+    int exponent)
+{
+	struct num res;
+
+	if (a->type != b->type) {
+		if (a->type == nt_mil) {
+			a->type = nt_mm;
+			a->n = mil_to_mm(a->n, a->exponent);
+		}
+		if (b->type == nt_mil) {
+			b->type = nt_mm;
+			b->n = mil_to_mm(b->n, b->exponent);
+		}
+	}
+	res.type = a->type;
+	res.exponent = exponent;
+	return res;
+}
+
+
+struct num op_minus(const struct expr *self, const struct frame *frame)
+{
+	struct num res;
+
+	res = eval_num(self->u.op.a, frame);
+	if (!is_undef(res))
+		res.n = -res.n;
+	return res;
+}
+
+
+#define	BINARY						\
+	struct num a, b, res;				\
+							\
+	a = eval_num(self->u.op.a, frame);		\
+	if (is_undef(a))				\
+		return undef;				\
+	b = eval_num(self->u.op.b, frame);		\
+	if (is_undef(b))				\
+		return undef;
+
+
+struct num op_add(const struct expr *self, const struct frame *frame)
+{
+	BINARY;
+	res = compatible_sum(&a, &b);
+	if (is_undef(res))
+		return undef;
+	res.n = a.n+b.n;
+	return res;
+}
+
+
+struct num op_sub(const struct expr *self, const struct frame *frame)
+{
+	BINARY;
+	res = compatible_sum(&a, &b);
+	if (is_undef(res))
+		return undef;
+	res.n = a.n-b.n;
+	return res;
+}
+
+
+struct num op_mult(const struct expr *self, const struct frame *frame)
+{
+	BINARY;
+	res = compatible_mult(&a, &b, a.exponent+b.exponent);
+	res.n = a.n*b.n;
+	return res;
+}
+
+
+struct num op_div(const struct expr *self, const struct frame *frame)
+{
+	BINARY;
+	if (!b.n) {
+		fail("Division by zero");
+		return undef;
+	}
+	res = compatible_mult(&a, &b, a.exponent-b.exponent);
+	res.n = a.n/b.n;
+	return res;
+}
+
+
+/* ----- expression construction ------------------------------------------- */
+
+
+struct expr *new_op(op_type op)
+{
+	struct expr *expr;
+
+	expr = alloc_type(struct expr);
+	expr->op = op;
+	expr->lineno = lineno;
+	return expr;
+}
+
+
+struct expr *binary_op(op_type op, struct expr *a, struct expr *b)
+{
+	struct expr *expr;
+
+	expr = new_op(op);
+	expr->u.op.a = a;
+	expr->u.op.b = b;
+	return expr;
+}
+
+
+char *eval_str(const struct frame *frame, const struct expr *expr)
+{
+	abort();
+}
+
+
+struct num eval_num(const struct expr *expr, const struct frame *frame)
+{
+	return expr->op(expr, frame);
+}
+
+
+/* ----- string expansion -------------------------------------------------- */
+
+
+char *expand(const char *name, const struct frame *frame)
+{
+	int len = strlen(name);
+	char *buf = alloc_size(len+1);
+	char num_buf[100]; /* enough :-) */
+	const char *s, *s0;
+	char *var;
+	const char *var_unique;
+	struct num value;
+	int i, value_len;
+
+	i = 0;
+	for (s = name; *s; s++) {
+		if (*s != '$') {
+			buf[i++] = *s;
+			continue;
+		}
+		s0 = ++s;
+		if (*s != '{') {
+			while (is_id_char(*s, s == s0))
+				s++;
+			if (s == s0)
+				goto invalid;
+			var = strnalloc(s0, s-s0);
+			len -= s-s0+1;
+			s--;
+		} else {
+			s++;
+			while (*s != '}') {
+				if (!*s) {
+					fail("unfinished \"${...}\"");
+					goto fail;
+				}
+				if (!is_id_char(*s, s == s0+1))
+					goto invalid;
+				s++;
+			}
+			var = strnalloc(s0+1, s-s0-1);
+			len -= s-s0+2;
+		}
+		if (!frame)
+			continue;
+		var_unique = unique(var);
+		free(var);
+		value = eval_var(frame, var_unique);
+		if (is_undef(value)) {
+			fail("undefined variable \"%s\"", var_unique);
+			goto fail;
+		}
+		value_len = snprintf(num_buf, sizeof(num_buf), "%lg%s",
+		    value.n, str_unit(value));
+		len += value_len;
+		buf = realloc(buf, len);
+		if (!buf)
+			abort();
+		strcpy(buf+i, num_buf);
+		i += value_len;
+	}
+	buf[i] = 0;
+	return buf;
+
+invalid:
+	fail("invalid character in variable name");
+fail:
+	free(buf);
+	return NULL;
+}
+
+
+/* ----- expression-only parser -------------------------------------------- */
+
+
+void scan_expr(const char *s);
+int yyparse(void);
+
+struct expr *expr_result;
+
+
+struct expr *parse_expr(const char *s)
+{
+	scan_expr(s);
+	return yyparse() ? NULL : expr_result;
+}
+
+
+static void vacate_op(struct expr *expr)
+{
+	if (expr->op == &op_num || expr->op == &op_var)
+		return;
+	if (expr->op == &op_minus) {
+		free_expr(expr->u.op.a);
+		return;
+	}
+	if (expr->op == &op_add || expr->op == &op_sub ||
+	    expr->op == &op_mult || expr->op == &op_div) {
+		free_expr(expr->u.op.a);
+		free_expr(expr->u.op.b);
+		return;
+	}
+	abort();
+}
+
+
+void free_expr(struct expr *expr)
+{
+	vacate_op(expr);
+	free(expr);
+}

Deleted: trunk/eda/fped/expr.h
===================================================================
--- developers/werner/fped/expr.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/expr.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,59 +0,0 @@
-/*
- * expr.h - Expressions and values
- *
- * 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 EXPR_H
-#define EXPR_H
-
-#include <math.h>
-
-
-#define UNDEF HUGE_VAL
-
-
-struct frame;
-struct expr;
-
-
-typedef double (*op_type)(const struct expr *self, const struct frame *frame);
-
-struct expr {
-	op_type op;
-	union {
-		double num;
-		const char *var;
-		struct {
-			struct expr *a;
-			struct expr *b;
-		} op;
-	} u;
-};
-
-
-double op_num(const struct expr *self, const struct frame *frame);
-double op_var(const struct expr *self, const struct frame *frame);
-
-double op_minus(const struct expr *self, const struct frame *frame);
-
-double op_add(const struct expr *self, const struct frame *frame);
-double op_sub(const struct expr *self, const struct frame *frame);
-double op_mult(const struct expr *self, const struct frame *frame);
-double op_div(const struct expr *self, const struct frame *frame);
-
-struct expr *new_op(op_type op);
-struct expr *binary_op(op_type op, struct expr *a, struct expr *b);
-
-double eval_var(const struct frame *frame, const char *name);
-char *eval_str(const struct frame *frame, const struct expr *expr);
-double eval_num(const struct expr *expr, const struct frame *frame);
-
-#endif /* !EXPR_H */

Copied: trunk/eda/fped/expr.h (from rev 5367, developers/werner/fped/expr.h)
===================================================================
--- trunk/eda/fped/expr.h	                        (rev 0)
+++ trunk/eda/fped/expr.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,120 @@
+/*
+ * expr.h - Expressions and values
+ *
+ * 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 EXPR_H
+#define EXPR_H
+
+#include <math.h>
+
+
+#define UNDEF HUGE_VAL
+
+
+struct frame;
+struct expr;
+
+enum num_type {
+	nt_none,
+	nt_mm,
+	nt_mil,
+};
+
+struct num {
+	enum num_type type;
+	int exponent;
+	double n;
+};
+
+typedef struct num (*op_type)(const struct expr *self,
+    const struct frame *frame);
+
+struct expr {
+	op_type op;
+	union {
+		struct num num;
+		const char *var;
+		struct {
+			struct expr *a;
+			struct expr *b;
+		} op;
+	} u;
+	int lineno;
+};
+
+
+extern struct num undef;
+
+
+#define	is_undef(num)		((num).type == nt_none)
+#define	is_dimensionless(num)	(!(num).exponent)
+
+
+static inline int is_distance(struct num num)
+{
+	return (num.type == nt_mm || num.type == nt_mil) && num.exponent == 1;
+}
+
+
+void fail_expr(const struct expr *expr);
+
+const char *str_unit(struct num n);
+
+
+static inline struct num make_num(double n)
+{
+	struct num res;
+
+	res.type = nt_mm;
+	res.exponent = 0;
+	res.n = n;
+	return res;
+}
+
+
+static inline struct num make_mil(double mil)
+{
+	struct num res;
+
+	res.type = nt_mil;
+	res.exponent = 1;
+	res.n = mil;
+	return res;
+}
+
+
+int to_unit(struct num *n);
+
+struct num op_num(const struct expr *self, const struct frame *frame);
+struct num op_var(const struct expr *self, const struct frame *frame);
+
+struct num op_minus(const struct expr *self, const struct frame *frame);
+
+struct num op_add(const struct expr *self, const struct frame *frame);
+struct num op_sub(const struct expr *self, const struct frame *frame);
+struct num op_mult(const struct expr *self, const struct frame *frame);
+struct num op_div(const struct expr *self, const struct frame *frame);
+
+struct expr *new_op(op_type op);
+struct expr *binary_op(op_type op, struct expr *a, struct expr *b);
+
+struct num eval_var(const struct frame *frame, const char *name);
+char *eval_str(const struct frame *frame, const struct expr *expr);
+struct num eval_num(const struct expr *expr, const struct frame *frame);
+
+/* if frame == NULL, we only check the syntax without expanding */
+char *expand(const char *name, const struct frame *frame);
+
+struct expr *parse_expr(const char *s);
+void free_expr(struct expr *expr);
+
+#endif /* !EXPR_H */

Deleted: trunk/eda/fped/fpd.l
===================================================================
--- developers/werner/fped/fpd.l	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/fpd.l	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,59 +0,0 @@
-%{
-/*
- * fpd.l - FootPrint Definition language
- *
- * 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 "util.h"
-#include "coord.h"
-#include "error.h"
-
-#include "y.tab.h"
-
-%}
-
-
-NUM	[0-9]+\.?[0-9]*
-SP	[\t ]*
-
-
-%%
-
-
-".frame"			return TOK_FRAME;
-".table"			return TOK_TABLE;
-".vec"				return TOK_VEC;
-".pad"				return TOK_PAD;
-".rect"				return TOK_RECT;
-".line"				return TOK_LINE;
-".arc"				return TOK_ARC;
-
-[a-zA-Z_][a-zA-Z_0-9]*		{ yylval.id = unique(yytext);
-				  return ID; }
-
-{NUM}{SP}mm			{ sscanf(yytext, "%lf", &yylval.num);
-				  yylval.num = mm_to_units(yylval.num);
-				  return NUMBER; }
-{NUM}{SP}mil			{ sscanf(yytext, "%lf", &yylval.num);
-				  yylval.num = mil_to_units(yylval.num);
-				  return NUMBER; }
-{NUM}				{ sscanf(yytext, "%lf", &yylval.num);
-				  return NUMBER; }
-
-\"(\\[^\n\t]|[^\\"\n\t])*\"	{ *strrchr(yytext, '"') = 0;
-				  yylval.str = stralloc(yytext+1);
-				  return STRING; }
-
-{SP}				;
-\n				lineno++;
-^#.*\n				lineno++;
-
-.				return *yytext;

Copied: trunk/eda/fped/fpd.l (from rev 5364, developers/werner/fped/fpd.l)
===================================================================
--- trunk/eda/fped/fpd.l	                        (rev 0)
+++ trunk/eda/fped/fpd.l	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,135 @@
+%{
+/*
+ * fpd.l - FootPrint Definition language
+ *
+ * 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 <stdlib.h>
+
+#include "util.h"
+#include "coord.h"
+#include "expr.h"
+#include "error.h"
+
+#include "y.tab.h"
+
+
+int start_token = START_FPD;
+
+static int disable_keywords = 0;
+static int is_table = 0;
+
+
+void scan_empty(void)
+{
+	yy_scan_string("");
+}
+
+
+void scan_expr(const char *s)
+{
+	start_token = START_EXPR;
+	yy_scan_string(s);
+}
+
+%}
+
+
+/* keywords are only accepted at the beginning of a line */
+%s NOKEYWORD
+
+NUM	[0-9]+\.?[0-9]*
+SP	[\t ]*
+
+
+%%
+
+%{
+	/*
+	 * Nice hack:
+	 *
+	 * http://www.gnu.org/software/bison/manual/bison.html#
+	 *   Multiple-start_002dsymbols
+	 */
+
+	if (start_token) {
+		int tmp = start_token;
+		start_token = 0;
+		return tmp;
+	}
+%}
+
+
+<INITIAL>"set"			{ BEGIN(NOKEYWORD);
+				  return TOK_SET; }
+<INITIAL>"loop"			{ BEGIN(NOKEYWORD);
+				  return TOK_LOOP; }
+<INITIAL>"frame"		{ BEGIN(NOKEYWORD);
+				  is_table = 0;
+				  return TOK_FRAME; }
+<INITIAL>"table"		{ BEGIN(NOKEYWORD);
+				  is_table = 1;
+				  return TOK_TABLE; }
+<INITIAL>"vec"			{ BEGIN(NOKEYWORD);
+				  return TOK_VEC; }
+<INITIAL>"pad"			{ BEGIN(NOKEYWORD);
+				  return TOK_PAD; }
+<INITIAL>"rect"			{ BEGIN(NOKEYWORD);
+				  return TOK_RECT; }
+<INITIAL>"line"			{ BEGIN(NOKEYWORD);
+				  return TOK_LINE; }
+<INITIAL>"circ"			{ BEGIN(NOKEYWORD);
+				  return TOK_CIRC; }
+<INITIAL>"arc"			{ BEGIN(NOKEYWORD);
+				  return TOK_ARC; }
+<INITIAL>"meas"			{ BEGIN(NOKEYWORD);
+				  return TOK_MEAS; }
+
+[a-zA-Z_][a-zA-Z_0-9]*:		{ *strchr(yytext, ':') = 0;
+				  yylval.id = unique(yytext);
+				  return LABEL; }
+[a-zA-Z_][a-zA-Z_0-9]*		{ yylval.id = unique(yytext);
+				  return ID; }
+
+{NUM}{SP}mm			{ yylval.num.type = nt_mm;
+				  yylval.num.exponent = 1;
+				  sscanf(yytext, "%lf", &yylval.num.n);
+				  return NUMBER; }
+{NUM}{SP}mil			{ yylval.num.type = nt_mil;
+				  yylval.num.exponent = 1;
+				  sscanf(yytext, "%lf", &yylval.num.n);
+				  return NUMBER; }
+{NUM}				{ yylval.num.type = nt_mm; /* mm or mil */
+				  yylval.num.exponent = 0;
+				  sscanf(yytext, "%lf", &yylval.num.n);
+				  return NUMBER; }
+
+\"(\\[^\n\t]|[^\\"\n\t])*\"	{ *strrchr(yytext, '"') = 0;
+				  yylval.str = stralloc(yytext+1);
+				  return STRING; }
+
+{SP}				;
+\n				{ if (!disable_keywords)
+					BEGIN(INITIAL);
+				  lineno++; }
+
+"{"				{ BEGIN(NOKEYWORD);
+				  disable_keywords = is_table;
+				  return '{'; }
+"}"				{ disable_keywords = 0;
+				  return '}'; }
+
+^#\ [0-9]+\ \"[^"]*\"(\ [0-9]+)*\n {
+				  if (!disable_keywords)
+				  	BEGIN(INITIAL);
+				  lineno = strtol(yytext+2, NULL, 0); }
+
+.				return *yytext;

Deleted: trunk/eda/fped/fpd.y
===================================================================
--- developers/werner/fped/fpd.y	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/fpd.y	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,444 +0,0 @@
-%{
-/*
- * fpd.y - FootPrint Definition language
- *
- * 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 <stdlib.h>
-
-#include "util.h"
-#include "error.h"
-#include "expr.h"
-#include "obj.h"
-
-
-static struct frame *curr_frame;
-static struct frame **next_frame;
-static struct table **next_table;
-static struct loop **next_loop;
-static struct vec **next_vec;
-static struct obj **next_obj;
-static int n_vars, n_values;
-static struct vec *last_vec = NULL;
-
-
-static struct frame *find_frame(const char *name)
-{
-	struct frame *f;
-
-	for (f = frames; f; f = f->next)
-		if (f->name == name)
-			return f;
-	return NULL;
-}
-
-
-static struct vec *find_vec(const char *name)
-{
-	struct vec *v;
-
-	for (v = curr_frame->vecs; v; v = v->next)
-		if (v->name == name)
-			return v;
-	return NULL;
-}
-
-
-static void set_frame(struct frame *frame)
-{
-	curr_frame = frame;
-	next_table = &frame->tables;
-	next_loop = &frame->loops;
-	next_vec = &frame->vecs;
-	next_obj = &frame->objs;
-	last_vec = NULL;
-}
-
-
-static void make_var(const char *id, struct expr *expr)
-{
-	struct table *table;
-
-	table = zalloc_type(struct table);
-	table->vars = zalloc_type(struct var);
-	table->vars->name = id;
-	table->rows = zalloc_type(struct row);
-	table->rows->values = zalloc_type(struct value);
-	table->rows->values->expr = expr;
-	*next_table = table;
-	next_table = &table->next;
-}
-
-
-static void make_loop(const char *id, struct expr *from, struct expr *to)
-{
-	struct loop *loop;
-
-	loop = alloc_type(struct loop);
-	loop->var = id;
-	loop->from = from;
-	loop->to = to;
-	loop->next = NULL;
-	*next_loop = loop;
-	next_loop = &loop->next;
-}
-
-
-static struct obj *new_obj(enum obj_type type)
-{
-	struct obj *obj;
-
-	obj = alloc_type(struct obj);
-	obj->type = type;
-	obj->next = NULL;
-	return obj;
-}
-
-
-%}
-
-
-%union {
-	double num;
-	char *str;
-	const char *id;
-	struct expr *expr;
-	struct frame *frame;
-	struct table *table;
-	struct var *var;
-	struct row *row;
-	struct value *value;
-	struct vec *vec;
-	struct obj *obj;
-};
-
-
-%token		TOK_FRAME TOK_TABLE TOK_VEC TOK_PAD TOK_RECT TOK_LINE TOK_ARC
-
-%token	<num>	NUMBER
-%token	<str>	STRING
-%token	<id>	ID
-
-%type	<table>	table
-%type	<var>	vars var
-%type	<row>	rows
-%type	<value>	row value
-%type	<vec>	vec base opt_base
-%type	<obj>	obj
-%type	<expr>	opt_range
-%type	<expr>	expr add_expr mult_expr unary_expr primary_expr
-
-%%
-
-all:
-		{
-			frames = zalloc_type(struct frame);
-			next_frame = &frames->next;
-			set_frame(frames);
-		}
-	frame_defs frame_items
-	;
-
-frame_defs:
-	| frame_defs frame_def
-	;
-
-frame_def:
-	TOK_FRAME ID '{'
-		{
-			if (find_frame($2))
-				yyerrorf("duplicate frame \"%s\"", $2);
-			*next_frame = zalloc_type(struct frame);
-			(*next_frame)->name = $2;
-			set_frame(*next_frame);
-			next_frame = &(*next_frame)->next;
-
-		}
-	    frame_items '}'
-		{
-			set_frame(frames);
-		}
-	;
-
-frame_items:
-	| frame_item frame_items
-	;
-
-frame_item:
-	table
-	| ID '=' expr opt_range
-		{
-			if ($4)
-				make_loop($1, $3, $4);
-			else
-				make_var($1, $3);
-		}
-	| vec
-	| ID '=' vec
-		{
-			if (find_vec($1))
-				yyerrorf("duplicate vector \"%s\"", $1);
-			$3->name = $1;
-		}
-	| obj
-		{
-			*next_obj = $1;
-			next_obj = &$1->next;
-		}
-	;
-
-opt_range:
-		{
-			$$ = NULL;
-		}
-	| ',' expr
-		{
-			$$ = $2;
-		}
-	;
-
-table:
-	TOK_TABLE
-		{
-			$<table>$ = zalloc_type(struct table);
-			*next_table = $<table>$;
-			n_vars = 0;
-		}
-	    '{' vars '}' rows
-		{
-			$$ = $<table>2;
-			$$->vars = $4;
-			$$->rows = $6;
-			next_table = &$$->next;
-		}
-	;
-
-vars:
-	var
-		{
-			$$ = $1;
-		}
-	| vars ',' var
-		{
-			struct var **walk;
-
-			$$ = $1;
-			for (walk = &$$; *walk; walk = &(*walk)->next);
-			*walk = $3;
-		}
-	;
-
-var:
-	ID
-		{
-			$$ = alloc_type(struct var);
-			$$->name = $1;
-			$$->next = NULL;
-			n_vars++;
-		}
-	;
-	
-	
-rows:
-		{
-			$$ = NULL;
-		}
-	| '{'
-		{
-			n_values = 0;
-		}
-	    row '}'
-		{
-			if (n_vars != n_values)
-				yyerrorf("table has %d variables but row has "
-				    "%d values", n_vars, n_values);
-			$<row>$ = alloc_type(struct row);
-			$<row>$->values = $3;
-		}
-	    rows
-		{
-			$$ = $<row>5;
-			$$->next = $6;
-		}
-	;
-
-row:
-	value
-		{
-			$$ = $1;
-		}
-	| row ',' value
-		{
-			struct value **walk;
-
-			$$ = $1;
-			for (walk = &$$; *walk; walk = &(*walk)->next);
-			*walk = $3;
-		}
-	;
-
-value:
-	expr
-		{
-			$$ = alloc_type(struct value);
-			$$->expr = $1;
-			$$->next = NULL;
-			n_values++;
-		}
-	;
-
-vec:
-	TOK_VEC base expr ',' expr
-		{
-			$$ = alloc_type(struct vec);
-			$$->base = $2;
-			if ($2)
-				$2->n_refs++;
-			$$->x = $3;
-			$$->y = $5;
-			$$->n_refs = 0;
-			$$->next = NULL;
-			last_vec = $$;
-			*next_vec = $$;
-			next_vec = &$$->next;
-		}
-	;
-
-base:
-	'@'
-		{
-			$$ = NULL;
-		}
-	| '.'
-		{
-			$$ = last_vec;
-			if (!$$)
-				yyerrorf(". without predecessor");
-		}
-	| ID
-		{
-			$$ = find_vec($1);
-			if (!$$)
-				yyerrorf("unknown vector \"%s\"", $1);
-		}
-	;
-
-obj:
-	TOK_PAD STRING base base
-		{
-			$$ = new_obj(ot_pad);
-			$$->base = $3;
-			$$->u.pad.name = $2;
-			$$->u.pad.other = $4;
-		}
-	| TOK_RECT base base
-		{
-			$$ = new_obj(ot_rect);
-			$$->base = $2;
-			$$->u.rect.other = $3;
-		}
-	| TOK_LINE base base
-		{
-			$$ = new_obj(ot_line);
-			$$->base = $2;
-			$$->u.line.other = $3;
-		}
-	| TOK_ARC base base opt_base
-		{
-			$$ = new_obj(ot_arc);
-			$$->base = $2;
-			$$->u.arc.start = $3;
-			$$->u.arc.end = $4 ? $4 : $3;
-		}
-	| TOK_FRAME ID base
-		{
-			$$ = new_obj(ot_frame);
-			$$->base = $3;
-			$$->u.frame = find_frame($2);
-			if (!$$->u.frame)
-				yyerrorf("unknown frame \"%s\"", $2);
-		}
-	;
-
-opt_base:
-		{
-			$$ = NULL;
-		}
-	| ',' base
-		{
-			$$ = $2;
-		}
-	;
-
-expr:
-	add_expr
-		{
-			$$ = $1;
-		}
-	;
-
-add_expr:
-	mult_expr
-		{
-			$$ = $1;
-		}
-	| add_expr '+' mult_expr
-		{
-			$$ = binary_op(op_add, $1, $3);
-		}
-	| add_expr '-' mult_expr
-		{
-			$$ = binary_op(op_sub, $1, $3);
-		}
-	;
-
-mult_expr:
-	unary_expr
-		{
-			$$ = $1;
-		}
-	| mult_expr '*' unary_expr
-		{
-			$$ = binary_op(op_mult, $1, $3);
-		}
-	| mult_expr '/' unary_expr
-		{
-			$$ = binary_op(op_div, $1, $3);
-		}
-	;
-
-unary_expr:
-	primary_expr
-		{
-			$$ = $1;
-		}
-	| '-' primary_expr
-		{
-			$$ = binary_op(op_minus, $2, NULL);
-		}
-	;
-
-primary_expr:
-	NUMBER
-		{
-			$$ = new_op(op_num);
-			$$->u.num = $1;
-		}
-	| ID
-		{
-			$$ = new_op(op_var);
-			$$->u.var = $1;
-		}
-	| '(' expr ')'
-		{
-			$$ = $2;
-		}
-	;

Copied: trunk/eda/fped/fpd.y (from rev 5373, developers/werner/fped/fpd.y)
===================================================================
--- trunk/eda/fped/fpd.y	                        (rev 0)
+++ trunk/eda/fped/fpd.y	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,509 @@
+%{
+/*
+ * fpd.y - FootPrint Definition language
+ *
+ * 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 <stdlib.h>
+
+#include "util.h"
+#include "error.h"
+#include "expr.h"
+#include "obj.h"
+
+
+extern struct expr *expr_result;
+
+static struct frame *curr_frame;
+static struct table *curr_table;
+static struct row *curr_row;
+
+static struct frame *last_frame = NULL;
+static struct vec *last_vec = NULL;
+
+static struct table **next_table;
+static struct loop **next_loop;
+static struct vec **next_vec;
+static struct obj **next_obj;
+
+static int n_vars, n_values;
+
+
+static struct frame *find_frame(const char *name)
+{
+	struct frame *f;
+
+	for (f = frames; f; f = f->next)
+		if (f->name == name)
+			return f;
+	return NULL;
+}
+
+
+static struct vec *find_vec(const char *name)
+{
+	struct vec *v;
+
+	for (v = curr_frame->vecs; v; v = v->next)
+		if (v->name == name)
+			return v;
+	return NULL;
+}
+
+
+static void set_frame(struct frame *frame)
+{
+	curr_frame = frame;
+	next_table = &frame->tables;
+	next_loop = &frame->loops;
+	next_vec = &frame->vecs;
+	next_obj = &frame->objs;
+	last_vec = NULL;
+}
+
+
+static void make_var(const char *id, struct expr *expr)
+{
+	struct table *table;
+
+	table = zalloc_type(struct table);
+	table->vars = zalloc_type(struct var);
+	table->vars->name = id;
+	table->vars->frame = curr_frame;
+	table->rows = zalloc_type(struct row);
+	table->rows->values = zalloc_type(struct value);
+	table->rows->values->expr = expr;
+	table->rows->values->row = table->rows;
+	*next_table = table;
+	next_table = &table->next;
+}
+
+
+static void make_loop(const char *id, struct expr *from, struct expr *to)
+{
+	struct loop *loop;
+
+	loop = alloc_type(struct loop);
+	loop->var.name = id;
+	loop->var.next = NULL;
+	loop->var.frame = curr_frame;
+	loop->from.expr = from;
+	loop->from.row = NULL;
+	loop->from.next = NULL;
+	loop->to.expr = to;
+	loop->to.row = NULL;
+	loop->to.next = NULL;
+	loop->next = NULL;
+	loop->active = 0;
+	loop->initialized = 0;
+	*next_loop = loop;
+	next_loop = &loop->next;
+}
+
+
+static struct obj *new_obj(enum obj_type type)
+{
+	struct obj *obj;
+
+	obj = alloc_type(struct obj);
+	obj->type = type;
+	obj->next = NULL;
+	return obj;
+}
+
+
+%}
+
+
+%union {
+	struct num num;
+	char *str;
+	const char *id;
+	struct expr *expr;
+	struct frame *frame;
+	struct table *table;
+	struct var *var;
+	struct row *row;
+	struct value *value;
+	struct vec *vec;
+	struct obj *obj;
+};
+
+
+%token		START_FPD START_EXPR
+%token		TOK_SET TOK_LOOP TOK_FRAME TOK_TABLE TOK_VEC
+%token		TOK_PAD TOK_RECT TOK_LINE TOK_CIRC TOK_ARC TOK_MEAS
+
+%token	<num>	NUMBER
+%token	<str>	STRING
+%token	<id>	ID LABEL
+
+%type	<table>	table
+%type	<var>	vars var
+%type	<row>	rows
+%type	<value>	row value
+%type	<vec>	vec base
+%type	<obj>	obj
+%type	<expr>	expr opt_expr add_expr mult_expr unary_expr primary_expr
+
+%%
+
+all:
+	START_FPD fpd
+	| START_EXPR expr
+		{
+			expr_result = $2;
+		}
+	;
+
+fpd:
+		{
+			root_frame = zalloc_type(struct frame);
+			set_frame(root_frame);
+		}
+	frame_defs frame_items
+		{
+			root_frame->prev = last_frame;
+			if (last_frame)
+				last_frame->next = root_frame;
+			else
+				frames = root_frame;
+		}
+	;
+
+frame_defs:
+	| frame_defs frame_def
+	;
+
+frame_def:
+	TOK_FRAME ID '{'
+		{
+			if (find_frame($2)) {
+				yyerrorf("duplicate frame \"%s\"", $2);
+				YYABORT;
+			}
+			curr_frame = zalloc_type(struct frame);
+			curr_frame->name = $2;
+			set_frame(curr_frame);
+			curr_frame->prev = last_frame;
+			if (last_frame)
+				last_frame->next = curr_frame;
+			else
+				frames = curr_frame;
+			last_frame = curr_frame;
+		}
+	    frame_items '}'
+		{
+			set_frame(root_frame);
+		}
+	;
+
+frame_items:
+	| frame_item frame_items
+	;
+
+frame_item:
+	table
+	| TOK_SET ID '=' expr
+		{
+			make_var($2, $4);
+		}
+	| TOK_LOOP ID '=' expr ',' expr
+		{
+			make_loop($2, $4, $6);
+		}
+	| vec
+	| LABEL vec
+		{
+			if (find_vec($1)) {
+				yyerrorf("duplicate vector \"%s\"", $1);
+				YYABORT;
+			}
+			$2->name = $1;
+		}
+	| obj
+		{
+			*next_obj = $1;
+			next_obj = &$1->next;
+		}
+	;
+
+table:
+	TOK_TABLE
+		{
+			$<table>$ = zalloc_type(struct table);
+			*next_table = $<table>$;
+			curr_table = $<table>$;
+			n_vars = 0;
+		}
+	    '{' vars '}' rows
+		{
+			$$ = $<table>2;
+			$$->vars = $4;
+			$$->rows = $6;
+			$$->active = 0;
+			next_table = &$$->next;
+		}
+	;
+
+vars:
+	var
+		{
+			$$ = $1;
+		}
+	| vars ',' var
+		{
+			struct var **walk;
+
+			$$ = $1;
+			for (walk = &$$; *walk; walk = &(*walk)->next);
+			*walk = $3;
+		}
+	;
+
+var:
+	ID
+		{
+			$$ = alloc_type(struct var);
+			$$->name = $1;
+			$$->frame = curr_frame;
+			$$->next = NULL;
+			n_vars++;
+		}
+	;
+	
+	
+rows:
+		{
+			$$ = NULL;
+		}
+	| '{'
+		{
+			$<row>$ = alloc_type(struct row);
+			$<row>$->table = curr_table;
+			curr_row = $<row>$;;
+			n_values = 0;
+		}
+	    row '}'
+		{
+			if (n_vars != n_values) {
+				yyerrorf("table has %d variables but row has "
+				    "%d values", n_vars, n_values);
+				YYABORT;
+			}
+			$<row>2->values = $3;
+		}
+	    rows
+		{
+			$$ = $<row>2;
+			$$->next = $6;
+		}
+	;
+
+row:
+	value
+		{
+			$$ = $1;
+		}
+	| row ',' value
+		{
+			struct value **walk;
+
+			$$ = $1;
+			for (walk = &$$; *walk; walk = &(*walk)->next);
+			*walk = $3;
+		}
+	;
+
+value:
+	expr
+		{
+			$$ = alloc_type(struct value);
+			$$->expr = $1;
+			$$->row = curr_row;
+			$$->next = NULL;
+			n_values++;
+		}
+	;
+
+vec:
+	TOK_VEC base '(' expr ',' expr ')'
+		{
+			$$ = alloc_type(struct vec);
+			$$->name = NULL;
+			$$->base = $2;
+			if ($2)
+				$2->n_refs++;
+			$$->x = $4;
+			$$->y = $6;
+			$$->n_refs = 0;
+			$$->frame = curr_frame;
+			$$->next = NULL;
+			last_vec = $$;
+			*next_vec = $$;
+			next_vec = &$$->next;
+		}
+	;
+
+base:
+	'@'
+		{
+			$$ = NULL;
+		}
+	| '.'
+		{
+			$$ = last_vec;
+			if (!$$) {
+				yyerrorf(". without predecessor");
+				YYABORT;
+			}
+		}
+	| ID
+		{
+			$$ = find_vec($1);
+			if (!$$) {
+				yyerrorf("unknown vector \"%s\"", $1);
+				YYABORT;
+			}
+		}
+	;
+
+obj:
+	TOK_PAD STRING base base
+		{
+			$$ = new_obj(ot_pad);
+			$$->base = $3;
+			$$->u.pad.name = $2;
+			$$->u.pad.other = $4;
+		}
+	| TOK_RECT base base opt_expr
+		{
+			$$ = new_obj(ot_rect);
+			$$->base = $2;
+			$$->u.rect.other = $3;
+			$$->u.rect.width = $4;
+		}
+	| TOK_LINE base base opt_expr
+		{
+			$$ = new_obj(ot_line);
+			$$->base = $2;
+			$$->u.line.other = $3;
+			$$->u.line.width = $4;
+		}
+	| TOK_CIRC base base opt_expr
+		{
+			$$ = new_obj(ot_arc);
+			$$->base = $2;
+			$$->u.arc.start = $3;
+			$$->u.arc.end = $3;
+			$$->u.arc.width = $4;
+		}
+	| TOK_ARC base base base opt_expr
+		{
+			$$ = new_obj(ot_arc);
+			$$->base = $2;
+			$$->u.arc.start = $3;
+			$$->u.arc.end = $4;
+			$$->u.arc.width = $5;
+		}
+	| TOK_MEAS base base expr
+		{
+			$$ = new_obj(ot_meas);
+			$$->base = $2;
+			$$->u.meas.other = $3;
+			$$->u.meas.offset = $4;
+		}
+	| TOK_FRAME ID base
+		{
+			$$ = new_obj(ot_frame);
+			$$->base = $3;
+			$$->u.frame = find_frame($2);
+			if (!$$->u.frame) {
+				yyerrorf("unknown frame \"%s\"", $2);
+				YYABORT;
+			}
+		}
+	;
+
+opt_expr:
+		{
+			$$ = NULL;
+		}
+	| expr
+		{
+			$$ = $1;
+		}
+	;
+
+expr:
+	add_expr
+		{
+			$$ = $1;
+		}
+	;
+
+add_expr:
+	mult_expr
+		{
+			$$ = $1;
+		}
+	| add_expr '+' mult_expr
+		{
+			$$ = binary_op(op_add, $1, $3);
+		}
+	| add_expr '-' mult_expr
+		{
+			$$ = binary_op(op_sub, $1, $3);
+		}
+	;
+
+mult_expr:
+	unary_expr
+		{
+			$$ = $1;
+		}
+	| mult_expr '*' unary_expr
+		{
+			$$ = binary_op(op_mult, $1, $3);
+		}
+	| mult_expr '/' unary_expr
+		{
+			$$ = binary_op(op_div, $1, $3);
+		}
+	;
+
+unary_expr:
+	primary_expr
+		{
+			$$ = $1;
+		}
+	| '-' primary_expr
+		{
+			$$ = binary_op(op_minus, $2, NULL);
+		}
+	;
+
+primary_expr:
+	NUMBER
+		{
+			$$ = new_op(op_num);
+			$$->u.num = $1;
+		}
+	| ID
+		{
+			$$ = new_op(op_var);
+			$$->u.var = $1;
+		}
+	| '(' expr ')'
+		{
+			$$ = $2;
+		}
+	;

Deleted: trunk/eda/fped/fped.c
===================================================================
--- developers/werner/fped/fped.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/fped.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,49 +0,0 @@
-/*
- * fped.c - Footprint editor, main function
- *
- * 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 "cpp.h"
-#include "obj.h"
-#include "inst.h"
-#include "gui.h"
-
-
-int yyparse(void);
-
-
-static void load_file(const char *name)
-{
-	run_cpp_on_file(name);
-	(void) yyparse();
-}
-
-
-int main(int argc, char **argv)
-{
-	int error;
-
-	error = gui_init(&argc, &argv);
-	if (error)
-		return error;
-	if (argc > 1) {
-		load_file(argv[1]);
-		argc--;
-		argv++;
-	}
-	instantiate();
-	inst_debug();
-	error = gui_main(argc, argv);
-	if (error)
-		return error;
-	return 0;
-}

Copied: trunk/eda/fped/fped.c (from rev 5361, developers/werner/fped/fped.c)
===================================================================
--- trunk/eda/fped/fped.c	                        (rev 0)
+++ trunk/eda/fped/fped.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,57 @@
+/*
+ * fped.c - Footprint editor, main function
+ *
+ * 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 "cpp.h"
+#include "error.h"
+#include "obj.h"
+#include "inst.h"
+#include "gui.h"
+
+
+extern void scan_empty(void);
+extern int yyparse(void);
+
+
+static void load_file(const char *name)
+{
+	reporter = report_parse_error;
+	run_cpp_on_file(name);
+	(void) yyparse();
+}
+
+
+int main(int argc, char **argv)
+{
+	int error;
+
+	error = gui_init(&argc, &argv);
+	if (error)
+		return error;
+	if (argc == 1) {
+		scan_empty();
+		(void) yyparse();
+	} else {
+		load_file(argv[1]);
+		argc--;
+		argv++;
+	}
+	reporter = report_to_stderr;
+	if (!instantiate())
+		return 1;
+//	inst_debug();
+	error = gui_main(argc, argv);
+	if (error)
+		return error;
+	return 0;
+}

Deleted: trunk/eda/fped/gui.c
===================================================================
--- developers/werner/fped/gui.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,199 +0,0 @@
-/*
- * gui.c - Editor GUI core
- *
- * 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 <math.h>
-#include <gtk/gtk.h>
-
-#include "obj.h"
-#include "gui_status.h"
-#include "gui_canvas.h"
-#include "gui.h"
-
-
-static void make_menu_bar(GtkWidget *vbox)
-{
-	GtkWidget *bar;
-	GtkWidget *file_menu, *file, *quit;
-
-	bar = gtk_menu_bar_new();
-	gtk_box_pack_start(GTK_BOX(vbox), bar, FALSE, FALSE, 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);
-
-	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);
-}
-
-
-static void add_frame(GtkListStore  *list, const char *name)
-{
-	GtkTreeIter iter;
-
-	gtk_list_store_append(list, &iter);
-	gtk_list_store_set(list, &iter, 0, name, -1);
-}
-
-
-static void show_frames(GtkWidget *frame_list)
-{
-	GtkListStore *list;
-	struct frame *f;
-
-	list = gtk_list_store_new(1, G_TYPE_STRING);
-
-	for (f = frames; f; f = f->next)
-		add_frame(list, f->name ? f->name : "(root)");
-
-	gtk_tree_view_set_model(GTK_TREE_VIEW(frame_list),
-	    GTK_TREE_MODEL(list));
-	g_object_unref(list);
-}
-
-
-static void show_vars(GtkWidget *var_list)
-{
-	GtkListStore *list;
-
-	list = gtk_list_store_new(1, G_TYPE_STRING);
-
-	gtk_tree_view_set_model(GTK_TREE_VIEW(var_list),
-	    GTK_TREE_MODEL(list));
-	g_object_unref(list);
-}
-
-
-static void show_rows(GtkWidget *row_list)
-{
-	GtkListStore *list;
-
-	list = gtk_list_store_new(1, G_TYPE_STRING);
-
-	gtk_tree_view_set_model(GTK_TREE_VIEW(row_list),
-	    GTK_TREE_MODEL(list));
-	g_object_unref(list);
-}
-
-
-static void make_center_area(GtkWidget *vbox)
-{
-	GtkWidget *hbox;
-	GtkWidget *frame_list, *var_list, *row_list;
-	GtkWidget *sep;
-	GdkColor black = { 0, 0, 0, 0 };
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
-
-	/* Frame list */
-
-	frame_list = gtk_tree_view_new();
-	gtk_box_pack_start(GTK_BOX(hbox), frame_list, FALSE, TRUE, 0);
-
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(frame_list),
-	    -1, "Frame", gtk_cell_renderer_text_new(), "text", 0, NULL);
-
-	show_frames(frame_list);
-
-	sep = gtk_drawing_area_new();
-	gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, TRUE, 2);
-	gtk_widget_modify_bg(sep, GTK_STATE_NORMAL, &black);
-
-	/*
-	 * @@@ is this really a good way to present variables ?
-	 *
-	 * a way to show entire tables may be preferable. also, showing all
-	 * tables of a frame at the same time may be more convenient than such
-	 * a "peephole" access.
-	 */
-
-	/* Variable list */
-
-	var_list = gtk_tree_view_new();
-	gtk_box_pack_start(GTK_BOX(hbox), var_list, FALSE, TRUE, 0);
-
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(var_list),
-	    -1, "Variable", gtk_cell_renderer_text_new(), "text", 0, NULL);
-
-	show_vars(var_list);
-
-	sep = gtk_drawing_area_new();
-	gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, TRUE, 2);
-	gtk_widget_modify_bg(sep, GTK_STATE_NORMAL, &black);
-
-	/* Row list */
-
-	row_list = gtk_tree_view_new();
-	gtk_box_pack_start(GTK_BOX(hbox), row_list, FALSE, TRUE, 0);
-
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(row_list),
-	    -1, "Row", gtk_cell_renderer_text_new(), "text", 0, NULL);
-
-	show_rows(row_list);
-
-	sep = gtk_drawing_area_new();
-	gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, TRUE, 2);
-	gtk_widget_modify_bg(sep, GTK_STATE_NORMAL, &black);
-
-	/* Canvas */
-
-	make_canvas(hbox);
-}
-
-
-static void make_screen(GtkWidget *root)
-{
-	GtkWidget *vbox;
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(root), vbox);
-
-	make_menu_bar(vbox);
-	make_center_area(vbox);
-	make_status_area(vbox);
-}
-
-
-int gui_init(int *argc, char ***argv)
-{
-	gtk_init(argc, argv);
-	return 0;
-}
-
-
-int gui_main(int argc, char **argv)
-{
-	GtkWidget *root;
-
-	root = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	gtk_window_set_position(GTK_WINDOW(root), GTK_WIN_POS_CENTER);
-	gtk_window_set_default_size(GTK_WINDOW(root), 600, 400);
-	gtk_window_set_title(GTK_WINDOW(root), "fped");
-
-	g_signal_connect_swapped(G_OBJECT(root), "destroy",
-	    G_CALLBACK(gtk_main_quit), NULL);
-
-	make_screen(root);
-
-	gtk_widget_show_all(root);
-
-	gtk_main();
-
-	return 0;
-}

Copied: trunk/eda/fped/gui.c (from rev 5363, developers/werner/fped/gui.c)
===================================================================
--- trunk/eda/fped/gui.c	                        (rev 0)
+++ trunk/eda/fped/gui.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,588 @@
+/*
+ * gui.c - Editor GUI core
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <gtk/gtk.h>
+
+#include "util.h"
+#include "inst.h"
+#include "obj.h"
+#include "unparse.h"
+#include "gui_util.h"
+#include "gui_style.h"
+#include "gui_status.h"
+#include "gui_canvas.h"
+#include "gui_icons.h"
+#include "gui.h"
+
+
+GtkWidget *root;
+
+static GtkWidget *frames_box;
+static GtkWidget *vars_box;
+
+
+/* ----- menu bar ---------------------------------------------------------- */
+
+
+static void make_menu_bar(GtkWidget *vbox)
+{
+	GtkWidget *bar;
+	GtkWidget *file_menu, *file, *quit;
+
+	bar = gtk_menu_bar_new();
+	gtk_box_pack_start(GTK_BOX(vbox), bar, FALSE, FALSE, 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);
+
+	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);
+}
+
+
+/* ----- variable list ----------------------------------------------------- */
+
+
+static void add_sep(GtkWidget *box, int size)
+{
+	GtkWidget *sep;
+	GdkColor black = { 0, 0, 0, 0 };
+
+	sep = gtk_drawing_area_new();
+	gtk_box_pack_start(GTK_BOX(box), sep, FALSE, TRUE, size);
+	gtk_widget_modify_bg(sep, GTK_STATE_NORMAL, &black);
+}
+
+
+/* ----- variable name editor ---------------------------------------------- */
+
+
+static int find_var_in_frame(const struct frame *frame, const char *name)
+{
+	const struct table *table;
+	const struct loop *loop;
+	const struct var *var;
+
+	for (table = frame->tables; table; table = table->next)
+		for (var = table->vars; var; var = var->next)
+			if (!strcmp(var->name, name))
+				return 1;
+	for (loop = frame->loops; loop; loop = loop->next)
+		if (!strcmp(loop->var.name, name))
+			return 1;
+        return 0;
+}
+
+
+static int validate_var_name(const char *s, void *ctx)
+{
+	struct var *var = ctx;
+
+	if (!is_id(s))
+		return 0;
+	return !find_var_in_frame(var->frame, s);
+}
+
+
+static void unselect_var(void *data)
+{
+	struct var *var = data;
+
+        label_in_box_bg(var->widget, COLOR_VAR_PASSIVE);
+}
+
+
+static void edit_var(struct var *var)
+{
+	inst_select_outside(var, unselect_var);
+        label_in_box_bg(var->widget, COLOR_VAR_EDITING);
+	status_set_name(var->name);
+	edit_unique(&var->name, validate_var_name, var);
+}
+
+
+/* ----- value editor ------------------------------------------------------ */
+
+
+static void unselect_value(void *data)
+{
+	struct value *value = data;
+
+        label_in_box_bg(value->widget,
+	    value->row && value->row->table && value->row->table->curr_row ==
+	     value->row ? COLOR_CHOICE_SELECTED : COLOR_EXPR_PASSIVE);
+}
+
+
+static void edit_value(struct value *value)
+{
+	inst_select_outside(value, unselect_value);
+        label_in_box_bg(value->widget, COLOR_EXPR_EDITING);
+	edit_expr(&value->expr);
+}
+
+
+
+/* ----- assignments ------------------------------------------------------- */
+
+
+static gboolean assignment_var_select_event(GtkWidget *widget,
+     GdkEventButton *event, gpointer data)
+{
+	edit_var(data);
+	return TRUE;
+}
+
+
+static gboolean assignment_value_select_event(GtkWidget *widget,
+     GdkEventButton *event, gpointer data)
+{
+	edit_value(data);
+	return TRUE;
+}
+
+
+static void build_assignment(GtkWidget *vbox, struct frame *frame,
+     struct table *table)
+{
+	GtkWidget *hbox, *field;
+	char *expr;
+
+	if (!table->vars || table->vars->next)
+		return;
+	if (!table->rows || table->rows->next)
+		return;
+
+	hbox = gtk_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+	field = label_in_box_new(table->vars->name);
+	gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
+	label_in_box_bg(field, COLOR_VAR_PASSIVE);
+	table->vars->widget = field;
+	g_signal_connect(G_OBJECT(box_of_label(field)),
+	    "button_press_event",
+	    G_CALLBACK(assignment_var_select_event), table->vars);
+
+	gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" = "),
+	    FALSE, FALSE, 0);
+
+	expr = unparse(table->rows->values->expr);
+	field = label_in_box_new(expr);
+	free(expr);
+	gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
+	label_in_box_bg(field, COLOR_EXPR_PASSIVE);
+	table->rows->values->widget = field;
+	g_signal_connect(G_OBJECT(box_of_label(field)),
+	    "button_press_event",
+	    G_CALLBACK(assignment_value_select_event), table->rows->values);
+}
+
+
+/* ----- tables ------------------------------------------------------------ */
+
+
+static gboolean table_var_select_event(GtkWidget *widget,
+     GdkEventButton *event, gpointer data)
+{
+	edit_var(data);
+	return TRUE;
+}
+
+
+static gboolean table_value_select_event(GtkWidget *widget,
+     GdkEventButton *event, gpointer data)
+{
+	edit_value(data);
+	return TRUE;
+}
+
+
+static void build_table(GtkWidget *vbox, struct frame *frame,
+     struct table *table)
+{
+	GtkWidget *tab, *field;
+	GtkWidget *evbox;
+	struct var *var;
+	struct row *row;
+	struct value *value;
+	int n_vars = 0, n_rows = 0;
+	char *expr;
+	GdkColor col;
+
+	for (var = table->vars; var; var = var->next)
+		n_vars++;
+	for (row = table->rows; row; row = row->next)
+		n_rows++;
+
+	if (n_vars == 1 && n_rows == 1)
+		return;
+
+	evbox = gtk_event_box_new();
+	gtk_box_pack_start(GTK_BOX(vbox), evbox, FALSE, FALSE, 0);
+
+	tab = gtk_table_new(n_rows+1, n_vars, FALSE);
+	gtk_container_add(GTK_CONTAINER(evbox), tab);
+	col = get_color(COLOR_VAR_TABLE_SEP);
+	gtk_widget_modify_bg(GTK_WIDGET(evbox),
+            GTK_STATE_NORMAL, &col);
+
+	gtk_table_set_row_spacings(GTK_TABLE(tab), 1);
+	gtk_table_set_col_spacings(GTK_TABLE(tab), 1);
+
+	n_vars = 0;
+	for (var = table->vars; var; var = var->next) {
+		field = label_in_box_new(var->name);
+		gtk_table_attach_defaults(GTK_TABLE(tab), box_of_label(field),
+		    n_vars, n_vars+1, 0, 1);
+		label_in_box_bg(field, COLOR_VAR_PASSIVE);
+		g_signal_connect(G_OBJECT(box_of_label(field)),
+		    "button_press_event",
+		    G_CALLBACK(table_var_select_event), var);
+		var->widget = field;
+		n_vars++;
+	}
+	n_rows = 0;
+	for (row = table->rows; row; row = row->next) {
+		n_vars = 0;
+		for (value = row->values; value; value = value->next) {
+			expr = unparse(value->expr);
+			field = label_in_box_new(expr);
+			free(expr);
+			gtk_table_attach_defaults(GTK_TABLE(tab),
+			    box_of_label(field),
+			    n_vars, n_vars+1,
+			    n_rows+1, n_rows+2);
+			label_in_box_bg(field, table->active == n_rows ?
+			    COLOR_ROW_SELECTED : COLOR_ROW_UNSELECTED);
+			g_signal_connect(G_OBJECT(box_of_label(field)),
+			    "button_press_event",
+			    G_CALLBACK(table_value_select_event), value);
+			value->widget = field;
+			n_vars++;
+		}
+		n_rows++;
+	}
+}
+
+
+/* ----- loops ------------------------------------------------------------- */
+
+
+static gboolean loop_var_select_event(GtkWidget *widget,
+     GdkEventButton *event, gpointer data)
+{
+	struct loop *loop = data;
+
+	edit_var(&loop->var);
+	return TRUE;
+}
+
+
+static gboolean loop_from_select_event(GtkWidget *widget,
+     GdkEventButton *event, gpointer data)
+{
+	struct loop *loop = data;
+
+	edit_value(&loop->from);
+	return TRUE;
+}
+
+
+static gboolean loop_to_select_event(GtkWidget *widget,
+     GdkEventButton *event, gpointer data)
+{
+	struct loop *loop = data;
+
+	edit_value(&loop->to);
+	return TRUE;
+}
+
+
+static void build_loop(GtkWidget *vbox, struct frame *frame,
+     struct loop *loop)
+{
+	GtkWidget *hbox, *field;
+	char *expr;
+
+	hbox = gtk_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+	field = label_in_box_new(loop->var.name);
+	gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
+	label_in_box_bg(field, COLOR_VAR_PASSIVE);
+	g_signal_connect(G_OBJECT(box_of_label(field)),
+	    "button_press_event",
+	    G_CALLBACK(loop_var_select_event), loop);
+	loop->var.widget = field;
+
+	gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" = "),
+	    FALSE, FALSE, 0);
+
+	expr = unparse(loop->from.expr);
+	field = label_in_box_new(expr);
+	free(expr);
+	gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
+	label_in_box_bg(field, COLOR_EXPR_PASSIVE);
+	g_signal_connect(G_OBJECT(box_of_label(field)),
+	    "button_press_event",
+	    G_CALLBACK(loop_from_select_event), loop);
+	loop->from.widget = field;
+
+	gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" ... "),
+	    FALSE, FALSE, 0);
+
+	expr = unparse(loop->to.expr);
+	field = label_in_box_new(expr);
+	free(expr);
+	gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
+	label_in_box_bg(field, COLOR_EXPR_PASSIVE);
+	g_signal_connect(G_OBJECT(box_of_label(field)),
+	    "button_press_event",
+	    G_CALLBACK(loop_to_select_event), loop);
+	loop->to.widget = field;
+}
+
+
+/* ----- the list of variables, tables, and loops -------------------------- */
+
+
+static void build_vars(GtkWidget *vbox, struct frame *frame)
+{
+	struct table *table;
+	struct loop *loop;
+
+	destroy_all_children(GTK_CONTAINER(vbox));
+	for (table = frame->tables; table; table = table->next) {
+		add_sep(vbox, 3);
+		build_assignment(vbox, frame, table);
+		build_table(vbox, frame, table);
+	}
+	for (loop = frame->loops; loop; loop = loop->next) {
+		add_sep(vbox, 3);
+		build_loop(vbox, frame, loop);
+	}
+	gtk_widget_show_all(vbox);
+}
+
+
+/* ----- frame list -------------------------------------------------------- */
+
+
+static int validate_frame_name(const char *s, void *ctx)
+{
+	struct frame *f;
+
+	if (!is_id(s))
+		return 0;
+	for (f = frames; f; f = f->next)
+		if (f->name && !strcmp(f->name, s))
+			return 0;
+	return 1;
+}
+
+
+static void unselect_frame(void *data)
+{
+	struct frame *frame= data;
+
+	/*
+	 * "unselect" means in this context that the selection has moved
+	 * elsewhere. However, this does not necessarily change the frame.
+	 * (And, in fact, since we rebuild the frame list anyway, the color
+	 * change here doesn't matter if selecting a different frame.)
+	 * So we revert from "editing" to "selected".
+	 */
+        label_in_box_bg(frame->label, COLOR_FRAME_SELECTED);
+}
+
+
+static void edit_frame(struct frame *frame)
+{
+	inst_select_outside(frame, unselect_frame);
+	label_in_box_bg(frame->label, COLOR_FRAME_EDITING);
+	status_set_name(frame->name);
+	edit_unique(&frame->name, validate_frame_name, frame);
+}
+
+
+static void select_frame(struct frame *frame)
+{
+	if (active_frame) {
+		label_in_box_bg(active_frame->label, COLOR_FRAME_UNSELECTED);
+		inst_deselect();
+	}
+	active_frame = frame;
+	change_world();
+}
+
+
+static gboolean frame_select_event(GtkWidget *widget, GdkEventButton *event,
+     gpointer data)
+{
+	if (active_frame != data)
+		select_frame(data);
+	else {
+		if (active_frame->name)
+			edit_frame(data);
+	}
+	return TRUE;
+}
+
+
+static void build_frames(GtkWidget *vbox)
+{
+	struct frame *f;
+	GtkWidget *label;
+
+	destroy_all_children(GTK_CONTAINER(vbox));
+	for (f = root_frame; f; f = f->prev) {
+		label = label_in_box_new(f->name ? f->name : "(root)");
+		gtk_box_pack_start(GTK_BOX(vbox), box_of_label(label),
+		    FALSE, TRUE, 0);
+		gtk_misc_set_padding(GTK_MISC(label), 2, 2);
+		gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+
+		label_in_box_bg(label, active_frame == f ?
+		    COLOR_FRAME_SELECTED : COLOR_FRAME_UNSELECTED);
+
+		g_signal_connect(G_OBJECT(box_of_label(label)),
+		    "button_press_event", G_CALLBACK(frame_select_event), f);
+		f->label = label;
+	}
+	gtk_widget_show_all(vbox);
+}
+
+
+/* ----- central screen area ----------------------------------------------- */
+
+
+static void make_center_area(GtkWidget *vbox)
+{
+	GtkWidget *hbox, *vars, *paned;
+	GtkWidget *frame_list, *icons;
+
+	hbox = gtk_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
+
+	/* Frame list */
+
+	frame_list = gtk_scrolled_window_new(NULL, NULL);
+	gtk_box_pack_start(GTK_BOX(hbox), frame_list, FALSE, TRUE, 0);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(frame_list),
+	    GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
+	frames_box = gtk_vbox_new(FALSE, 0);
+	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(frame_list),
+	    frames_box);
+
+	build_frames(frames_box);
+
+	add_sep(hbox, 2);
+
+	paned = gtk_hpaned_new();
+	gtk_box_pack_start(GTK_BOX(hbox), paned, TRUE, TRUE, 0);
+	
+	/* Variables */
+
+	vars = gtk_scrolled_window_new(NULL, NULL);
+	gtk_paned_add1(GTK_PANED(paned), vars);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vars),
+	    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_widget_set_size_request(vars, 150, 100);
+	vars_box = gtk_vbox_new(FALSE, 0);
+
+	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(vars),
+	    vars_box);
+
+	/* Canvas */
+
+	gtk_paned_add2(GTK_PANED(paned), make_canvas());
+
+	/* Icon bar */
+
+	icons = gui_setup_icons(root->window);
+	gtk_box_pack_end(GTK_BOX(hbox), icons, FALSE, FALSE, 0);
+}
+
+
+/* ----- GUI construction -------------------------------------------------- */
+
+
+void change_world(void)
+{
+	status_begin_reporting();
+	instantiate();
+	label_in_box_bg(active_frame->label, COLOR_FRAME_SELECTED);
+	build_frames(frames_box);
+	build_vars(vars_box, active_frame);
+	redraw();
+}
+
+
+static void make_screen(GtkWidget *window)
+{
+	GtkWidget *vbox;
+
+	vbox = gtk_vbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(window), vbox);
+
+	make_menu_bar(vbox);
+	make_center_area(vbox);
+	make_status_area(vbox);
+}
+
+
+int gui_init(int *argc, char ***argv)
+{
+	gtk_init(argc, argv);
+	return 0;
+}
+
+
+int gui_main(int argc, char **argv)
+{
+	root = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_position(GTK_WINDOW(root), GTK_WIN_POS_CENTER);
+	gtk_window_set_default_size(GTK_WINDOW(root), 600, 400);
+	gtk_window_set_title(GTK_WINDOW(root), "fped");
+
+	/* get root->window */
+	gtk_widget_show_all(root);
+
+	g_signal_connect_swapped(G_OBJECT(root), "destroy",
+	    G_CALLBACK(gtk_main_quit), NULL);
+
+	make_screen(root);
+	build_vars(vars_box, root_frame);
+
+	gtk_widget_show_all(root);
+
+	gui_setup_style(root->window);
+	init_canvas();
+	edit_nothing();
+	select_frame(root_frame);
+
+	gtk_main();
+
+	return 0;
+}

Deleted: trunk/eda/fped/gui.h
===================================================================
--- developers/werner/fped/gui.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,23 +0,0 @@
-/*
- * gui.h - Editor GUI core
- *
- * 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 GUI_H
-#define GUI_H
-
-#include <gtk/gtk.h>
-
-
-int gui_init(int *argc, char ***argv);
-int gui_main(int argc, char **argv);
-
-#endif /* !GUI_H */

Copied: trunk/eda/fped/gui.h (from rev 5351, developers/werner/fped/gui.h)
===================================================================
--- trunk/eda/fped/gui.h	                        (rev 0)
+++ trunk/eda/fped/gui.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,29 @@
+/*
+ * gui.h - Editor GUI core
+ *
+ * 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 GUI_H
+#define GUI_H
+
+#include <gtk/gtk.h>
+
+
+extern GtkWidget *root;
+
+
+/* update everything after a model change */
+void change_world(void);
+
+int gui_init(int *argc, char ***argv);
+int gui_main(int argc, char **argv);
+
+#endif /* !GUI_H */

Deleted: trunk/eda/fped/gui_canvas.c
===================================================================
--- developers/werner/fped/gui_canvas.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui_canvas.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,313 +0,0 @@
-/*
- * gui_canvas.c - GUI, canvas
- *
- * 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 <math.h>
-#include <gtk/gtk.h>
-
-#include "obj.h"
-#include "inst.h"
-#include "gui_inst.h"
-#include "gui_style.h"
-#include "gui_status.h"
-#include "gui.h"
-#include "gui_canvas.h"
-
-
-static struct draw_ctx ctx;
-static struct coord curr_pos;
-static struct coord user_origin = { 0, 0 };
-
-
-/* ----- status display ---------------------------------------------------- */
-
-
-static void update_zoom(void)
-{
-	status_set_zoom("x%d", ctx.scale);
-}
-
-
-static void update_pos(struct coord pos)
-{
-	status_set_sys_pos("%5.2lf %5.2lf mm",
-	    units_to_mm(pos.x), units_to_mm(pos.y));
-	status_set_user_pos("%5.2lf %5.2lf mm",
-	    units_to_mm(pos.x-user_origin.x), units_to_mm(pos.y-user_origin.y));
-}
-
-
-/* ----- coordinate system ------------------------------------------------- */
-
-
-static void center(void)
-{
-	struct bbox bbox;
-
-	bbox = inst_get_bbox();
-	ctx.center.x = (bbox.min.x+bbox.max.x)/2;
-	ctx.center.y = (bbox.min.y+bbox.max.y)/2;
-}
-
-
-static void auto_scale(void)
-{
-	struct bbox bbox;
-	unit_type h, w;
-	int sx, sy;
-	float aw, ah;
-
-	bbox = inst_get_bbox();
-	aw = ctx.widget->allocation.width;
-	ah = ctx.widget->allocation.height;
-	h = bbox.max.x-bbox.min.x;
-	w = bbox.max.y-bbox.min.y;
-	aw -= 2*CANVAS_CLEARANCE;
-	ah -= 2*CANVAS_CLEARANCE;
-	if (aw < 1)
-		aw = 1;
-	if (ah < 1)
-		ah = 1;
-	sx = ceil(h/aw);
-	sy = ceil(w/ah);
-	ctx.scale = sx > sy ? sx : sy > 0 ? sy : 1;
-
-	update_zoom();
-}
-
-
-/* ----- drawing ----------------------------------------------------------- */
-
-
-static void redraw(void)
-{
-	float aw, ah;
-
-	aw = ctx.widget->allocation.width;
-	ah = ctx.widget->allocation.height;
-	gdk_draw_rectangle(ctx.widget->window, gc_bg, TRUE, 0, 0, aw, ah);
-
-	inst_draw(&ctx);
-}
-
-
-/* ----- drag -------------------------------------------------------------- */
-
-
-static void drag_left(struct coord pos)
-{
-}
-
-
-static void drag_middle(struct coord pos)
-{
-}
-
-
-static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event,
-     gpointer data)
-{
-	struct coord pos = canvas_to_coord(&ctx, event->x, event->y);
-
-	curr_pos.x = event->x;
-	curr_pos.y = event->y;
-	if (event->state & GDK_BUTTON1_MASK)
-		drag_left(pos);
-	if (event->state & GDK_BUTTON2_MASK)
-		drag_middle(pos);
-	update_pos(pos);
-	return TRUE;
-}
-
-
-/* ----- button press and release ------------------------------------------ */
-
-
-static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
-     gpointer data)
-{
-	struct coord pos = canvas_to_coord(&ctx, event->x, event->y);
-
-	switch (event->button) {
-	case 1:
-		/* select */ ;
-		break;
-	case 2:
-		ctx.center = pos;
-		redraw();
-		break;
-	}
-	return TRUE;
-}
-
-
-static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
-     gpointer data)
-{
-	return TRUE;
-}
-
-
-/* ----- zoom control ------------------------------------------------------ */
-
-
-static void zoom_in(struct coord pos)
-{
-	if (ctx.scale < 2)
-		return;
-	ctx.scale /= 2;
-	ctx.center.x = (ctx.center.x+pos.x)/2;
-	ctx.center.y = (ctx.center.y+pos.y)/2;
-	update_zoom();
-	redraw();
-}
-
-
-static void zoom_out(struct coord pos)
-{
-	struct bbox bbox;
-
-	bbox = inst_get_bbox();
-	bbox.min = translate(&ctx, bbox.min);
-	bbox.max = translate(&ctx, bbox.max);
-	if (bbox.min.x >= 0 && bbox.max.y >= 0 &&
-	    bbox.max.x < ctx.widget->allocation.width &&
-	    bbox.min.y < ctx.widget->allocation.height)
-		return;
-	ctx.scale *= 2;
-	ctx.center.x = 2*ctx.center.x-pos.x;
-	ctx.center.y = 2*ctx.center.y-pos.y;
-	update_zoom();
-	redraw();
-}
-
-
-static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event,
-     gpointer data)
-{
-	struct coord pos = canvas_to_coord(&ctx, event->x, event->y);
-
-	switch (event->direction) {
-	case GDK_SCROLL_UP:
-		zoom_in(pos);
-		break;
-	case GDK_SCROLL_DOWN:
-		zoom_out(pos);
-		break;
-	default:
-		/* ignore */;
-	}
-	return TRUE;
-}
-
-
-/* ----- keys -------------------------------------------------------------- */
-
-
-static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event,
-     gpointer data)
-{
-	struct coord pos = canvas_to_coord(&ctx, curr_pos.x, curr_pos.y);
-
-	switch (event->keyval) {
-	case ' ':
-		user_origin = pos;
-		update_pos(pos);
-		break;
-	}
-	return TRUE;
-}
-
-
-/* ----- expose event ------------------------------------------------------ */
-
-
-static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event,
-     gpointer data)
-{
-	static int first = 1;
-
-	if (first) {
-		gui_setup_style(widget->window);
-		center();
-		auto_scale();
-		first = 0;
-	}
-
-	redraw();
-
-	return TRUE;
-}
-
-
-/* ----- enter/leave ------------------------------------------------------- */
-
-
-static gboolean enter_notify_event(GtkWidget *widget, GdkEventCrossing *event,
-     gpointer data)
-{
-	gtk_widget_grab_focus(widget);
-	return TRUE;
-}
-
-
-static gboolean leave_notify_event(GtkWidget *widget, GdkEventCrossing *event,
-     gpointer data)
-{
-	return TRUE;
-}
-
-
-/* ----- canvas setup ------------------------------------------------------ */
-
-
-void make_canvas(GtkWidget *hbox)
-{
-	GtkWidget *canvas;
-	GdkColor black = { 0, 0, 0, 0 };
-
-	/* Canvas */
-
-	canvas = gtk_drawing_area_new();
-	gtk_box_pack_start(GTK_BOX(hbox), canvas, TRUE, TRUE, 0);
-	gtk_widget_modify_bg(canvas, GTK_STATE_NORMAL, &black);
-
-	g_signal_connect(G_OBJECT(canvas), "motion_notify_event",
-	    G_CALLBACK(motion_notify_event), NULL);
-	g_signal_connect(G_OBJECT(canvas), "button_press_event",
-	    G_CALLBACK(button_press_event), NULL);
-	g_signal_connect(G_OBJECT(canvas), "button_release_event",
-	    G_CALLBACK(button_release_event), NULL);
-	g_signal_connect(G_OBJECT(canvas), "scroll_event",
-	    G_CALLBACK(scroll_event), NULL);
-
-	GTK_WIDGET_SET_FLAGS(canvas, GTK_CAN_FOCUS);
-
-	g_signal_connect(G_OBJECT(canvas), "key_press_event",
-	    G_CALLBACK(key_press_event), NULL);
-
-	g_signal_connect(G_OBJECT(canvas), "expose_event",
-	    G_CALLBACK(expose_event), NULL);
-	g_signal_connect(G_OBJECT(canvas), "enter_notify_event",
-	    G_CALLBACK(enter_notify_event), NULL);
-	g_signal_connect(G_OBJECT(canvas), "leave_notify_event",
-	    G_CALLBACK(leave_notify_event), NULL);
-
-	gtk_widget_set_events(canvas,
-	    GDK_EXPOSE | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
-	    GDK_KEY_PRESS_MASK |
-	    GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
-	    GDK_SCROLL |
-	    GDK_POINTER_MOTION_MASK);
-
-	ctx.widget = canvas;
-}

Copied: trunk/eda/fped/gui_canvas.c (from rev 5349, developers/werner/fped/gui_canvas.c)
===================================================================
--- trunk/eda/fped/gui_canvas.c	                        (rev 0)
+++ trunk/eda/fped/gui_canvas.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,327 @@
+/*
+ * gui_canvas.c - GUI, canvas
+ *
+ * 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 <math.h>
+#include <gtk/gtk.h>
+
+#include "obj.h"
+#include "inst.h"
+#include "gui_inst.h"
+#include "gui_style.h"
+#include "gui_status.h"
+#include "gui.h"
+#include "gui_canvas.h"
+
+
+static struct draw_ctx ctx;
+static struct coord curr_pos;
+static struct coord user_origin = { 0, 0 };
+
+
+/* ----- status display ---------------------------------------------------- */
+
+
+static void update_zoom(void)
+{
+	status_set_zoom("x%d", ctx.scale);
+}
+
+
+static void update_pos(struct coord pos)
+{
+	status_set_sys_pos("X %5.2lf  Y %5.2lf mm",
+	    units_to_mm(pos.x), units_to_mm(pos.y));
+	status_set_user_pos("x %5.2lf  y  %5.2lf mm",
+	    units_to_mm(pos.x-user_origin.x), units_to_mm(pos.y-user_origin.y));
+}
+
+
+/* ----- coordinate system ------------------------------------------------- */
+
+
+static void center(void)
+{
+	struct bbox bbox;
+
+	bbox = inst_get_bbox();
+	ctx.center.x = (bbox.min.x+bbox.max.x)/2;
+	ctx.center.y = (bbox.min.y+bbox.max.y)/2;
+}
+
+
+static void auto_scale(void)
+{
+	struct bbox bbox;
+	unit_type h, w;
+	int sx, sy;
+	float aw, ah;
+
+	bbox = inst_get_bbox();
+	aw = ctx.widget->allocation.width;
+	ah = ctx.widget->allocation.height;
+	h = bbox.max.x-bbox.min.x;
+	w = bbox.max.y-bbox.min.y;
+	aw -= 2*CANVAS_CLEARANCE;
+	ah -= 2*CANVAS_CLEARANCE;
+	if (aw < 1)
+		aw = 1;
+	if (ah < 1)
+		ah = 1;
+	sx = ceil(h/aw);
+	sy = ceil(w/ah);
+	ctx.scale = sx > sy ? sx : sy > 0 ? sy : 1;
+
+	update_zoom();
+}
+
+
+/* ----- drawing ----------------------------------------------------------- */
+
+
+void redraw(void)
+{
+	float aw, ah;
+
+	aw = ctx.widget->allocation.width;
+	ah = ctx.widget->allocation.height;
+	gdk_draw_rectangle(ctx.widget->window, gc_bg, TRUE, 0, 0, aw, ah);
+
+	inst_draw(&ctx);
+}
+
+
+/* ----- drag -------------------------------------------------------------- */
+
+
+static void drag_left(struct coord pos)
+{
+}
+
+
+static void drag_middle(struct coord pos)
+{
+}
+
+
+static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event,
+     gpointer data)
+{
+	struct coord pos = canvas_to_coord(&ctx, event->x, event->y);
+
+	curr_pos.x = event->x;
+	curr_pos.y = event->y;
+	if (event->state & GDK_BUTTON1_MASK)
+		drag_left(pos);
+	if (event->state & GDK_BUTTON2_MASK)
+		drag_middle(pos);
+	update_pos(pos);
+	return TRUE;
+}
+
+
+/* ----- button press and release ------------------------------------------ */
+
+
+static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
+     gpointer data)
+{
+	struct coord pos = canvas_to_coord(&ctx, event->x, event->y);
+	const struct inst *prev;
+
+	switch (event->button) {
+	case 1:
+		prev = selected_inst;
+		inst_deselect();
+		inst_select(&ctx, pos);
+		if (prev != selected_inst)
+			redraw();
+		break;
+	case 2:
+		ctx.center = pos;
+		redraw();
+		break;
+	}
+	return TRUE;
+}
+
+
+static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
+     gpointer data)
+{
+	return TRUE;
+}
+
+
+/* ----- zoom control ------------------------------------------------------ */
+
+
+static void zoom_in(struct coord pos)
+{
+	if (ctx.scale < 2)
+		return;
+	ctx.scale /= 2;
+	ctx.center.x = (ctx.center.x+pos.x)/2;
+	ctx.center.y = (ctx.center.y+pos.y)/2;
+	update_zoom();
+	redraw();
+}
+
+
+static void zoom_out(struct coord pos)
+{
+	struct bbox bbox;
+
+	bbox = inst_get_bbox();
+	bbox.min = translate(&ctx, bbox.min);
+	bbox.max = translate(&ctx, bbox.max);
+	if (bbox.min.x >= 0 && bbox.max.y >= 0 &&
+	    bbox.max.x < ctx.widget->allocation.width &&
+	    bbox.min.y < ctx.widget->allocation.height)
+		return;
+	ctx.scale *= 2;
+	ctx.center.x = 2*ctx.center.x-pos.x;
+	ctx.center.y = 2*ctx.center.y-pos.y;
+	update_zoom();
+	redraw();
+}
+
+
+static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event,
+     gpointer data)
+{
+	struct coord pos = canvas_to_coord(&ctx, event->x, event->y);
+
+	switch (event->direction) {
+	case GDK_SCROLL_UP:
+		zoom_in(pos);
+		break;
+	case GDK_SCROLL_DOWN:
+		zoom_out(pos);
+		break;
+	default:
+		/* ignore */;
+	}
+	return TRUE;
+}
+
+
+/* ----- keys -------------------------------------------------------------- */
+
+
+static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event,
+     gpointer data)
+{
+	struct coord pos = canvas_to_coord(&ctx, curr_pos.x, curr_pos.y);
+
+	switch (event->keyval) {
+	case ' ':
+		user_origin = pos;
+		update_pos(pos);
+		break;
+	}
+	return TRUE;
+}
+
+
+/* ----- expose event ------------------------------------------------------ */
+
+
+static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event,
+     gpointer data)
+{
+	static int first = 1;
+	if (first) {
+		init_canvas();
+		first = 0;
+	}
+	redraw();
+	return TRUE;
+}
+
+
+/* ----- enter/leave ------------------------------------------------------- */
+
+
+static gboolean enter_notify_event(GtkWidget *widget, GdkEventCrossing *event,
+     gpointer data)
+{
+	gtk_widget_grab_focus(widget);
+	return TRUE;
+}
+
+
+static gboolean leave_notify_event(GtkWidget *widget, GdkEventCrossing *event,
+     gpointer data)
+{
+	return TRUE;
+}
+
+
+/* ----- canvas setup ------------------------------------------------------ */
+
+
+/*
+ * Note that we call init_canvas twice: first to make sure we'll make it safely
+ * through select_frame, and the second time to set the geometry for the actual
+ * screen.
+ */
+
+void init_canvas(void)
+{
+	center();
+	auto_scale();
+}
+
+
+GtkWidget *make_canvas(void)
+{
+	GtkWidget *canvas;
+	GdkColor black = { 0, 0, 0, 0 };
+
+	/* Canvas */
+
+	canvas = gtk_drawing_area_new();
+	gtk_widget_modify_bg(canvas, GTK_STATE_NORMAL, &black);
+
+	g_signal_connect(G_OBJECT(canvas), "motion_notify_event",
+	    G_CALLBACK(motion_notify_event), NULL);
+	g_signal_connect(G_OBJECT(canvas), "button_press_event",
+	    G_CALLBACK(button_press_event), NULL);
+	g_signal_connect(G_OBJECT(canvas), "button_release_event",
+	    G_CALLBACK(button_release_event), NULL);
+	g_signal_connect(G_OBJECT(canvas), "scroll_event",
+	    G_CALLBACK(scroll_event), NULL);
+
+	GTK_WIDGET_SET_FLAGS(canvas, GTK_CAN_FOCUS);
+
+	g_signal_connect(G_OBJECT(canvas), "key_press_event",
+	    G_CALLBACK(key_press_event), NULL);
+
+	g_signal_connect(G_OBJECT(canvas), "expose_event",
+	    G_CALLBACK(expose_event), NULL);
+	g_signal_connect(G_OBJECT(canvas), "enter_notify_event",
+	    G_CALLBACK(enter_notify_event), NULL);
+	g_signal_connect(G_OBJECT(canvas), "leave_notify_event",
+	    G_CALLBACK(leave_notify_event), NULL);
+
+	gtk_widget_set_events(canvas,
+	    GDK_EXPOSE | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+	    GDK_KEY_PRESS_MASK |
+	    GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+	    GDK_SCROLL |
+	    GDK_POINTER_MOTION_MASK);
+
+	ctx.widget = canvas;
+
+	return canvas;
+}

Deleted: trunk/eda/fped/gui_canvas.h
===================================================================
--- developers/werner/fped/gui_canvas.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui_canvas.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,22 +0,0 @@
-/*
- * gui_canvas.h - GUI, canvas
- *
- * 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 GUI_CANVAS_H
-#define GUI_CANVAS_H
-
-#include <gtk/gtk.h>
-
-
-void make_canvas(GtkWidget *vbox) ;
-
-#endif /* !GUI_CANVAS_H */

Copied: trunk/eda/fped/gui_canvas.h (from rev 5343, developers/werner/fped/gui_canvas.h)
===================================================================
--- trunk/eda/fped/gui_canvas.h	                        (rev 0)
+++ trunk/eda/fped/gui_canvas.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,25 @@
+/*
+ * gui_canvas.h - GUI, canvas
+ *
+ * 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 GUI_CANVAS_H
+#define GUI_CANVAS_H
+
+#include <gtk/gtk.h>
+
+
+void redraw(void);
+
+GtkWidget *make_canvas(void);
+void init_canvas(void);
+
+#endif /* !GUI_CANVAS_H */

Copied: trunk/eda/fped/gui_icons.c (from rev 5365, developers/werner/fped/gui_icons.c)
===================================================================
--- trunk/eda/fped/gui_icons.c	                        (rev 0)
+++ trunk/eda/fped/gui_icons.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,87 @@
+/*
+ * gui_icons.c - GUI, icon bar
+ *
+ * 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 <gtk/gtk.h>
+
+#include "gui_util.h"
+#include "gui_icons.h"
+
+
+#include "icons/arc.xpm"
+#include "icons/circ.xpm"
+#include "icons/frame.xpm"
+#include "icons/line.xpm"
+#include "icons/meas.xpm"
+#include "icons/pad.xpm"
+#include "icons/point.xpm"
+#include "icons/rect.xpm"
+#include "icons/vec.xpm"
+
+
+static GtkToolItem *icon_button(GtkWidget *bar, GdkDrawable *drawable,
+     char **xpm, GtkToolItem *last)
+{
+	GdkPixmap *pixmap;
+	GtkWidget *image;	
+	GtkToolItem *item;
+
+	pixmap = gdk_pixmap_create_from_xpm_d(drawable, NULL, NULL, xpm);
+	image = gtk_image_new_from_pixmap(pixmap, NULL);
+
+/*
+ * gtk_radio_tool_button_new_from_widget is *huge*. we try to do things in a
+ * more compact way.
+ */
+#if 0
+	if (last)
+		item = gtk_radio_tool_button_new_from_widget(
+		    GTK_RADIO_TOOL_BUTTON(last));
+	else
+		item = gtk_radio_tool_button_new(NULL);
+	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item), image);
+#else
+	item = gtk_tool_item_new();
+	gtk_container_add(GTK_CONTAINER(item), image);
+
+	gtk_container_set_border_width(GTK_CONTAINER(item), 1);
+#endif
+
+	gtk_toolbar_insert(GTK_TOOLBAR(bar), item, -1);
+
+	return item;
+}
+
+
+GtkWidget *gui_setup_icons(GdkDrawable *drawable)
+{
+	GtkWidget *bar;
+	GtkToolItem *last;
+
+	bar = gtk_toolbar_new();
+	gtk_toolbar_set_style(GTK_TOOLBAR(bar), GTK_TOOLBAR_ICONS);
+	gtk_toolbar_set_orientation(GTK_TOOLBAR(bar),
+	    GTK_ORIENTATION_VERTICAL);
+//gtk_container_set_border_width(GTK_CONTAINER(bar), 5);
+
+	last = icon_button(bar, drawable, xpm_point, NULL);
+	last = icon_button(bar, drawable, xpm_vec, last);
+	last = icon_button(bar, drawable, xpm_frame, last);
+	last = icon_button(bar, drawable, xpm_pad, last);
+	last = icon_button(bar, drawable, xpm_line, last);
+	last = icon_button(bar, drawable, xpm_rect, last);
+	last = icon_button(bar, drawable, xpm_circ, last);
+	last = icon_button(bar, drawable, xpm_arc, last);
+	last = icon_button(bar, drawable, xpm_meas, last);
+
+	return bar;
+}

Copied: trunk/eda/fped/gui_icons.h (from rev 5363, developers/werner/fped/gui_icons.h)
===================================================================
--- trunk/eda/fped/gui_icons.h	                        (rev 0)
+++ trunk/eda/fped/gui_icons.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,22 @@
+/*
+ * gui_icons.h - GUI, icon bar
+ *
+ * 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 GUI_ICONS_H
+#define	GUI_ICONS_H
+
+#include <gtk/gtk.h>
+
+
+GtkWidget *gui_setup_icons(GdkDrawable *drawable);
+
+#endif /* !GUI_ICONS_H */

Deleted: trunk/eda/fped/gui_inst.c
===================================================================
--- developers/werner/fped/gui_inst.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui_inst.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,197 +0,0 @@
-/*
- * gui_inst.c - GUI, instance functions
- *
- * 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 <stdlib.h>
-#include <gtk/gtk.h>
-
-#include "inst.h"
-#include "gui.h"
-#include "gui_style.h"
-#include "gui_inst.h"
-
-
-#define DA	GDK_DRAWABLE(ctx->widget->window)
-
-
-struct coord translate(const struct draw_ctx *ctx, struct coord pos)
-{
-	pos.x -= ctx->center.x;
-	pos.y -= ctx->center.y;
-	pos.x /= ctx->scale;
-	pos.y /= ctx->scale;
-	pos.y = -pos.y;
-	pos.x += ctx->widget->allocation.width/2;
-	pos.y += ctx->widget->allocation.height/2;
-//fprintf(stderr, "%d %d\n", (int) pos.x, (int) pos.y);
-	return pos;
-}
-
-
-struct coord canvas_to_coord(const struct draw_ctx *ctx, int x, int y)
-{
-	struct coord pos;
-
-	x -= ctx->widget->allocation.width/2;
-	y -= ctx->widget->allocation.height/2;
-        y = -y;
-        pos.x = x*ctx->scale+ctx->center.x;
-        pos.y = y*ctx->scale+ctx->center.y;
-	return pos;
-}
-
-
-/* ----- drawing primitives ------------------------------------------------ */
-
-
-static void draw_arc(struct draw_ctx *ctx, GdkGC *gc, int fill,
-    int x, int y, int r, double a1, double a2)
-{
-	if (a1 == a2)
-		a2 = a1+360;
-	gdk_draw_arc(DA, gc, fill, x-r, y-r, 2*r, 2*r, a1*64, (a2-a1)*64);
-}
-
-
-static void draw_circle(struct draw_ctx *ctx, GdkGC *gc, int fill,
-    int x, int y, int r)
-{
-	draw_arc(ctx, gc, fill, x, y, r, 0, 360);
-}
-
-
-static void draw_eye(struct draw_ctx *ctx, GdkGC *gc, struct coord center,
-    int r1, int r2)
-{
-	draw_circle(ctx, gc, TRUE, center.x, center.y, r1);
-	draw_circle(ctx, gc, FALSE, center.x, center.y, r2);
-}
-
-
-#define MAX_POINTS	10
-
-
-static void draw_poly(struct draw_ctx *ctx, GdkGC *gc, int fill,
-    const struct coord *points, int n_points)
-{
-	GdkPoint gp[MAX_POINTS];
-	int i;
-
-	if (n_points > MAX_POINTS)
-		abort();
-	for (i = 0; i != n_points; i++) {
-		gp[i].x = points[i].x;
-		gp[i].y = points[i].y;
-	}
-	gdk_draw_polygon(DA, gc, fill, gp, n_points);
-}
-
-
-static void draw_arrow(struct draw_ctx *ctx, GdkGC *gc, int fill,
-    struct coord from, struct coord to, int len, double angle)
-{
-	struct coord p[3];
-	struct coord side;
-
-	side = normalize(sub_vec(to, from), VEC_ARROW_LEN);
-	p[0] = to;
-	p[1] = add_vec(to, rotate(side, 180-VEC_ARROW_ANGLE));
-	p[2] = add_vec(to, rotate(side, 180+VEC_ARROW_ANGLE));
-	draw_poly(ctx, gc, fill, p, 3);
-}
-
-
-/* ----- vec --------------------------------------------------------------- */
-
-
-void gui_draw_vec(struct inst *self, struct draw_ctx *ctx)
-{
-	struct coord from = translate(ctx, self->base);
-	struct coord to = translate(ctx, self->u.end);
-
-	draw_arrow(ctx, gc_vec_bg, TRUE, from, to,
-	  VEC_ARROW_LEN, VEC_ARROW_ANGLE);
-	gdk_draw_line(DA, gc_vec_bg, from.x, from.y, to.x, to.y);
-	draw_circle(ctx, gc_vec_bg, FALSE, to.x, to.y, VEC_EYE_R);
-}
-
-
-/* ----- line -------------------------------------------------------------- */
-
-
-void gui_draw_line(struct inst *self, struct draw_ctx *ctx)
-{
-	struct coord min = translate(ctx, self->bbox.min);
-	struct coord max = translate(ctx, self->bbox.max);
-
-	gdk_draw_line(DA, gc_line_bg, min.x, min.x, max.x, max.y);
-}
-
-
-/* ----- rect -------------------------------------------------------------- */
-
-
-void gui_draw_rect(struct inst *self, struct draw_ctx *ctx)
-{
-	struct coord min = translate(ctx, self->bbox.min);
-	struct coord max = translate(ctx, self->bbox.max);
-
-	gdk_draw_rectangle(DA, gc_rect_bg, FALSE,
-	    min.x, max.y, max.x-min.x, min.y-max.y);
-}
-
-
-/* ----- pad --------------------------------------------------------------- */
-
-
-void gui_draw_pad(struct inst *self, struct draw_ctx *ctx)
-{
-	struct coord min = translate(ctx, self->bbox.min);
-	struct coord max = translate(ctx, self->bbox.max);
-
-	/* @@@ name */
-	gdk_draw_rectangle(DA, gc_pad_bg, TRUE,
-	    min.x, max.y, max.x-min.x, min.y-max.y);
-}
-
-
-/* ----- arc --------------------------------------------------------------- */
-
-
-void gui_draw_arc(struct inst *self, struct draw_ctx *ctx)
-{
-	struct coord center = translate(ctx, self->base);
-
-	draw_arc(ctx, gc_arc_bg, FALSE, center.x, center.y,
-	    self->u.arc.r/ctx->scale, self->u.arc.a1, self->u.arc.a2);
-}
-
-
-/* ----- frame ------------------------------------------------------------- */
-
-
-void gui_draw_frame(struct inst *self, struct draw_ctx *ctx)
-{
-	struct coord center = translate(ctx, self->base);
-	struct coord corner = { self->bbox.min.x, self->bbox.max.y };
-
-	draw_eye(ctx, gc_frame_bg, center, FRAME_EYE_R1, FRAME_EYE_R2);
-	if (!self->u.frame.ref->name)
-		return;
-	corner = translate(ctx, corner);
-	corner.x -= FRAME_CLEARANCE;
-	corner.y -= FRAME_CLEARANCE;
-	gdk_draw_line(DA, gc_frame_bg,
-	    corner.x, corner.y, corner.x+100, corner.y);
-	gdk_draw_line(DA, gc_frame_bg,
-	    corner.x, corner.y, corner.x, corner.y+20);
-}

Copied: trunk/eda/fped/gui_inst.c (from rev 5367, developers/werner/fped/gui_inst.c)
===================================================================
--- trunk/eda/fped/gui_inst.c	                        (rev 0)
+++ trunk/eda/fped/gui_inst.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,421 @@
+/*
+ * gui_inst.c - GUI, instance functions
+ *
+ * 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 <stdlib.h>
+#include <math.h>
+#include <gtk/gtk.h>
+
+#include "util.h"
+#include "inst.h"
+#include "gui.h"
+#include "gui_util.h"
+#include "gui_style.h"
+#include "gui_inst.h"
+
+
+#define DA	GDK_DRAWABLE(ctx->widget->window)
+
+
+/* ----- coordinate translation -------------------------------------------- */
+
+
+struct coord translate(const struct draw_ctx *ctx, struct coord pos)
+{
+	pos.x -= ctx->center.x;
+	pos.y -= ctx->center.y;
+	pos.x /= ctx->scale;
+	pos.y /= ctx->scale;
+	pos.y = -pos.y;
+	pos.x += ctx->widget->allocation.width/2;
+	pos.y += ctx->widget->allocation.height/2;
+//fprintf(stderr, "%d %d\n", (int) pos.x, (int) pos.y);
+	return pos;
+}
+
+
+struct coord canvas_to_coord(const struct draw_ctx *ctx, int x, int y)
+{
+	struct coord pos;
+
+	x -= ctx->widget->allocation.width/2;
+	y -= ctx->widget->allocation.height/2;
+        y = -y;
+        pos.x = x*ctx->scale+ctx->center.x;
+        pos.y = y*ctx->scale+ctx->center.y;
+	return pos;
+}
+
+
+/* ----- drawing primitives ------------------------------------------------ */
+
+
+static void draw_arc(struct draw_ctx *ctx, GdkGC *gc, int fill,
+    int x, int y, int r, double a1, double a2)
+{
+	if (a1 == a2)
+		a2 = a1+360;
+	gdk_draw_arc(DA, gc, fill, x-r, y-r, 2*r, 2*r, a1*64, (a2-a1)*64);
+}
+
+
+static void draw_circle(struct draw_ctx *ctx, GdkGC *gc, int fill,
+    int x, int y, int r)
+{
+	draw_arc(ctx, gc, fill, x, y, r, 0, 360);
+}
+
+
+static void draw_eye(struct draw_ctx *ctx, GdkGC *gc, struct coord center,
+    int r1, int r2)
+{
+	draw_circle(ctx, gc, TRUE, center.x, center.y, r1);
+	draw_circle(ctx, gc, FALSE, center.x, center.y, r2);
+}
+
+
+#define MAX_POINTS	10
+
+
+static void draw_poly(struct draw_ctx *ctx, GdkGC *gc, int fill,
+    const struct coord *points, int n_points)
+{
+	GdkPoint gp[MAX_POINTS];
+	int i;
+
+	if (n_points > MAX_POINTS)
+		abort();
+	for (i = 0; i != n_points; i++) {
+		gp[i].x = points[i].x;
+		gp[i].y = points[i].y;
+	}
+	if (fill)
+		gdk_draw_polygon(DA, gc, fill, gp, n_points);
+	else {
+		gdk_draw_line(DA, gc, gp[0].x, gp[0].y, gp[1].x, gp[1].y);
+		gdk_draw_line(DA, gc, gp[1].x, gp[1].y, gp[2].x, gp[2].y);
+	}
+}
+
+
+static void draw_arrow(struct draw_ctx *ctx, GdkGC *gc, int fill,
+    struct coord from, struct coord to, int len, double angle)
+{
+	struct coord p[3];
+	struct coord side;
+
+	side = normalize(sub_vec(to, from), len);
+	p[0] = add_vec(to, rotate(side, 180-angle));
+	p[1] = to;
+	p[2] = add_vec(to, rotate(side, 180+angle));
+	draw_poly(ctx, gc, fill, p, 3);
+}
+
+
+static enum mode get_mode(struct inst *self)
+{
+	if (selected_inst == self)
+		return mode_selected;
+	if (self->active)
+		return self->in_path ? mode_active_in_path : mode_active;
+	return self->in_path ? mode_inactive_in_path : mode_inactive;
+}
+
+
+/* ----- vec --------------------------------------------------------------- */
+
+
+unit_type gui_dist_vec(struct inst *self, struct coord pos, unit_type scale)
+{
+	unit_type d;
+
+	d = dist_point(pos, self->u.rect.end)/scale;
+	return d > VEC_EYE_R ? -1 : d;
+}
+
+
+/*
+ * The circles at a vector's tip enjoy the highest selection priority. However,
+ * users will probably also expected a click on a nicely exposed stem to work.
+ * So we give it second look after having exhausted all other options.
+ */
+
+unit_type gui_dist_vec_fallback(struct inst *self, struct coord pos,
+    unit_type scale)
+{
+	unit_type d;
+
+	d = dist_line(pos, self->base, self->u.rect.end)/scale;
+	return d > SELECT_R ? -1 : d;
+}
+
+
+void gui_draw_vec(struct inst *self, struct draw_ctx *ctx)
+{
+	struct coord from = translate(ctx, self->base);
+	struct coord to = translate(ctx, self->u.rect.end);
+	GdkGC *gc;
+
+	gc = gc_vec[get_mode(self)];
+	draw_arrow(ctx, gc, TRUE, from, to, VEC_ARROW_LEN, VEC_ARROW_ANGLE);
+	gdk_draw_line(DA, gc, from.x, from.y, to.x, to.y);
+	draw_circle(ctx, gc, FALSE, to.x, to.y, VEC_EYE_R);
+}
+
+
+/* ----- line -------------------------------------------------------------- */
+
+
+unit_type gui_dist_line(struct inst *self, struct coord pos, unit_type scale)
+{
+	unit_type r, d;
+
+	r = self->u.rect.width/scale/2;
+	if (r < SELECT_R)
+		r = SELECT_R;
+	d = dist_line(pos, self->bbox.min, self->bbox.max)/scale;
+	return d > r ? -1 : d;
+}
+
+
+void gui_draw_line(struct inst *self, struct draw_ctx *ctx)
+{
+	struct coord min = translate(ctx, self->base);
+	struct coord max = translate(ctx, self->u.rect.end);
+	GdkGC *gc;
+
+	gc = gc_obj[get_mode(self)];
+	set_width(gc, self->u.rect.width/ctx->scale);
+	gdk_draw_line(DA, gc, min.x, min.y, max.x, max.y);
+}
+
+
+/* ----- rect -------------------------------------------------------------- */
+
+
+unit_type gui_dist_rect(struct inst *self, struct coord pos, unit_type scale)
+{
+	unit_type r, d;
+
+	r = self->u.rect.width/scale/2;
+	if (r < SELECT_R)
+		r = SELECT_R;
+	d = dist_rect(pos, self->bbox.min, self->bbox.max)/scale;
+	return d > r ? -1 : d;
+}
+
+
+void gui_draw_rect(struct inst *self, struct draw_ctx *ctx)
+{
+	struct coord min = translate(ctx, self->bbox.min);
+	struct coord max = translate(ctx, self->bbox.max);
+	GdkGC *gc;
+
+	gc = gc_obj[get_mode(self)];
+	set_width(gc, self->u.rect.width/ctx->scale);
+	gdk_draw_rectangle(DA, gc, FALSE,
+	    min.x, max.y, max.x-min.x, min.y-max.y);
+}
+
+
+/* ----- pad --------------------------------------------------------------- */
+
+
+unit_type gui_dist_pad(struct inst *self, struct coord pos, unit_type scale)
+{
+	unit_type d;
+
+	if (inside_rect(pos, self->bbox.min, self->bbox.max))
+		return SELECT_R;
+	d = dist_rect(pos, self->bbox.min, self->bbox.max)/scale;
+	return d > SELECT_R ? -1 : d;
+}
+
+
+void gui_draw_pad(struct inst *self, struct draw_ctx *ctx)
+{
+	struct coord min = translate(ctx, self->bbox.min);
+	struct coord max = translate(ctx, self->bbox.max);
+	GdkGC *gc;
+	struct coord c;
+	unit_type h, w;
+
+	gc = gc_pad[get_mode(self)];
+	gdk_draw_rectangle(DA, gc, TRUE,
+	    min.x, max.y, max.x-min.x, min.y-max.y);
+
+	gc = gc_ptext[get_mode(self)];
+	c = add_vec(min, max);
+	h = min.y-max.y;
+	w = max.x-min.x;
+	render_text(DA, gc, c.x/2, c.y/2, w <= h ? 0 : 90, self->u.name,
+	    PAD_FONT, 0.5, 0.5,
+	    w-2*PAD_BORDER, h-2*PAD_BORDER);
+}
+
+
+/* ----- arc --------------------------------------------------------------- */
+
+
+static struct coord rotate_r(struct coord center, unit_type r, double angle)
+{
+	struct coord res;
+
+	angle = angle/180.0*M_PI;
+	res.x = center.x+r*cos(angle);
+	res.y = center.y+r*sin(angle);
+	return res;
+}
+
+
+unit_type gui_dist_arc(struct inst *self, struct coord pos, unit_type scale)
+{
+	struct coord c = self->base;
+	struct coord p;
+	unit_type r, d_min, d;
+	double angle, a2;
+
+	r = self->u.arc.width/scale/2;
+	if (r < SELECT_R)
+		r = SELECT_R;
+
+	/* check endpoints */
+
+	p = rotate_r(c, self->u.arc.r, self->u.arc.a1);
+	d_min = hypot(pos.x-p.x, pos.y-p.y);
+
+	p = rotate_r(c, self->u.arc.r, self->u.arc.a2);
+	d = hypot(pos.x-p.x, pos.y-p.y);
+        if (d < d_min)
+                d_min = d;
+
+	if (d_min/scale <= r)
+		return d;
+
+	/* distance from the circle containing the arc */
+
+	d = dist_circle(pos, c, self->u.arc.r)/scale;
+	if (d > r)
+		return -1;
+	if (self->u.arc.a1 == self->u.arc.a2)
+		return d;
+
+	/* see if we're close to the part that's actually drawn */
+
+	angle = atan2(pos.y-c.y, pos.x-c.x)/M_PI*180.0;
+	if (angle < 0)
+		angle += 180;
+	a2 = self->u.arc.a2;
+	if (a2 < self->u.arc.a1)
+		a2 += 180;
+	return angle >= self->u.arc.a1 && angle <= a2 ? d : -1;
+}
+
+
+void gui_draw_arc(struct inst *self, struct draw_ctx *ctx)
+{
+	struct coord center = translate(ctx, self->base);
+	GdkGC *gc;
+
+	gc = gc_obj[get_mode(self)];
+	set_width(gc, self->u.arc.width/ctx->scale);
+	draw_arc(ctx, gc, FALSE, center.x, center.y,
+	    self->u.arc.r/ctx->scale, self->u.arc.a1, self->u.arc.a2);
+}
+
+
+/* ----- meas -------------------------------------------------------------- */
+
+
+static struct coord offset_vec(const struct inst *self)
+{
+	struct coord a, b, res;
+	double f;
+
+	a = self->base;
+	b = self->u.meas.end;
+	res.x = a.y-b.y;
+	res.y = b.x-a.x;
+	if (res.x == 0 && res.y == 0)
+		return res;
+	f = self->u.meas.offset/hypot(res.x, res.y);
+	res.x *= f;
+	res.y *= f;
+	return res;
+}
+
+
+unit_type gui_dist_meas(struct inst *self, struct coord pos, unit_type scale)
+{
+	struct coord a, b, off;
+	unit_type d;
+
+	off = offset_vec(self);
+	a = add_vec(self->base, off);
+	b = add_vec(self->u.meas.end, off);
+	d = dist_line(pos, a, b)/scale;
+	return d > SELECT_R ? -1 : d;
+}
+
+
+void gui_draw_meas(struct inst *self, struct draw_ctx *ctx)
+{
+	struct coord a0, b0, a1, b1, off, c, d;
+	GdkGC *gc;
+	char *s;
+
+	off = offset_vec(self);
+	a0 = translate(ctx, self->base);
+	b0 = translate(ctx, self->u.meas.end);
+	a1 = translate(ctx, add_vec(self->base, off));
+	b1 = translate(ctx, add_vec(self->u.meas.end, off));
+	gc = gc_meas[get_mode(self)];
+	gdk_draw_line(DA, gc, a0.x, a0.y, a1.x, a1.y);
+	gdk_draw_line(DA, gc, b0.x, b0.y, b1.x, b1.y);
+	gdk_draw_line(DA, gc, a1.x, a1.y, b1.x, b1.y);
+	draw_arrow(ctx, gc, FALSE, a1, b1, MEAS_ARROW_LEN, MEAS_ARROW_ANGLE);
+	draw_arrow(ctx, gc, FALSE, b1, a1, MEAS_ARROW_LEN, MEAS_ARROW_ANGLE);
+
+	c = add_vec(a1, b1);
+	d = sub_vec(b0, a0);
+	s = stralloc_printf("%lgmm",
+	    units_to_mm(dist_point(self->base, self->u.meas.end)));
+	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);
+	free(s);
+}
+
+
+/* ----- frame ------------------------------------------------------------- */
+
+
+void gui_draw_frame(struct inst *self, struct draw_ctx *ctx)
+{
+	struct coord center = translate(ctx, self->base);
+	struct coord corner = { self->bbox.min.x, self->bbox.max.y };
+	GdkGC *gc;
+
+	gc = gc_frame[get_mode(self)];
+	draw_eye(ctx, gc, center, FRAME_EYE_R1, FRAME_EYE_R2);
+	if (!self->u.frame.ref->name)
+		return;
+	corner = translate(ctx, corner);
+	corner.x -= FRAME_CLEARANCE;
+	corner.y -= FRAME_CLEARANCE;
+	gdk_draw_line(DA, gc, corner.x, corner.y,
+	    corner.x+FRAME_SHORT_X, corner.y);
+	gdk_draw_line(DA, gc, corner.x, corner.y,
+	    corner.x, corner.y+FRAME_SHORT_Y);
+	render_text(DA, gc, corner.x, corner.y, 0, self->u.frame.ref->name,
+	    FRAME_FONT, 0, -FRAME_BASELINE_OFFSET, 0, 0);
+}

Deleted: trunk/eda/fped/gui_inst.h
===================================================================
--- developers/werner/fped/gui_inst.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui_inst.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,40 +0,0 @@
-/*
- * gui_inst.h - GUI, instance functions
- *
- * 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 GUI_INST_H
-#define GUI_INST_H
-
-#include <gtk/gtk.h>
-
-#include "coord.h"
-#include "inst.h"
-
-
-struct draw_ctx {
-	GtkWidget *widget;
-	int scale;
-	struct coord center;
-};
-
-
-struct coord translate(const struct draw_ctx *ctx, struct coord pos);
-struct coord canvas_to_coord(const struct draw_ctx *ctx, int x, int y);
-
-void gui_draw_vec(struct inst *self, struct draw_ctx *ctx);
-void gui_draw_line(struct inst *self, struct draw_ctx *ctx);
-void gui_draw_rect(struct inst *self, struct draw_ctx *ctx);
-void gui_draw_pad(struct inst *self, struct draw_ctx *ctx);
-void gui_draw_arc(struct inst *self, struct draw_ctx *ctx);
-void gui_draw_frame(struct inst *self, struct draw_ctx *ctx);
-
-#endif /* !GUI_INST_H */

Copied: trunk/eda/fped/gui_inst.h (from rev 5366, developers/werner/fped/gui_inst.h)
===================================================================
--- trunk/eda/fped/gui_inst.h	                        (rev 0)
+++ trunk/eda/fped/gui_inst.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,50 @@
+/*
+ * gui_inst.h - GUI, instance functions
+ *
+ * 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 GUI_INST_H
+#define GUI_INST_H
+
+#include <gtk/gtk.h>
+
+#include "coord.h"
+#include "inst.h"
+
+
+struct draw_ctx {
+	GtkWidget *widget;
+	int scale;
+	struct coord center;
+};
+
+
+struct coord translate(const struct draw_ctx *ctx, struct coord pos);
+struct coord canvas_to_coord(const struct draw_ctx *ctx, int x, int y);
+
+unit_type gui_dist_vec(struct inst *self, struct coord pos, unit_type scale);
+unit_type gui_dist_vec_fallback(struct inst *self, struct coord pos,
+    unit_type scale);
+unit_type gui_dist_line(struct inst *self, struct coord pos, unit_type scale);
+unit_type gui_dist_rect(struct inst *self, struct coord pos, unit_type scale);
+unit_type gui_dist_pad(struct inst *self, struct coord pos, unit_type scale);
+unit_type gui_dist_arc(struct inst *self, struct coord pos, unit_type scale);
+unit_type gui_dist_meas(struct inst *self, struct coord pos, unit_type scale);
+
+void gui_draw_vec(struct inst *self, struct draw_ctx *ctx);
+void gui_draw_line(struct inst *self, struct draw_ctx *ctx);
+void gui_draw_rect(struct inst *self, struct draw_ctx *ctx);
+void gui_draw_pad(struct inst *self, struct draw_ctx *ctx);
+void gui_draw_arc(struct inst *self, struct draw_ctx *ctx);
+void gui_draw_meas(struct inst *self, struct draw_ctx *ctx);
+void gui_draw_frame(struct inst *self, struct draw_ctx *ctx);
+
+#endif /* !GUI_INST_H */

Deleted: trunk/eda/fped/gui_status.c
===================================================================
--- developers/werner/fped/gui_status.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui_status.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,128 +0,0 @@
-/*
- * gui_status.c - GUI, status area
- *
- * 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 <stdarg.h>
-#include <stdio.h>
-#include <gtk/gtk.h>
-
-#include "gui_status.h"
-
-
-static GtkWidget *status_name, *status_entry;
-static GtkWidget *status_x, *status_y;
-static GtkWidget *status_r, *status_angle;
-static GtkWidget *status_sys_pos, *status_user_pos;
-static GtkWidget *status_zoom, *status_grid;
-static GtkWidget *status_msg;
-
-
-static void set_label(GtkWidget *label, const char *fmt, va_list ap)
-{
-	char buf[100]; /* @@@ enough :-) */
-
-	vsprintf(buf, fmt, ap);
-	gtk_label_set_text(GTK_LABEL(label), buf);
-}
-
-
-#define	SETTER(name)					\
-	void status_set_##name(const char *fmt, ...)	\
-	{						\
-		va_list ap;				\
-							\
-		va_start(ap, fmt);			\
-		set_label(status_##name, fmt, ap);	\
-		va_end(ap);				\
-	}
-
-SETTER(name)
-SETTER(x)
-SETTER(y)
-SETTER(r)
-SETTER(angle)
-SETTER(sys_pos)
-SETTER(user_pos)
-SETTER(zoom)
-SETTER(grid)
-
-
-void make_status_area(GtkWidget *vbox)
-{
-	GtkWidget *hbox, *v2box;
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-	/* name and input */
-
-	v2box = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), v2box, TRUE, TRUE, 1);
-
-	status_name = gtk_label_new("<name>");
-	gtk_box_pack_start(GTK_BOX(v2box), status_name, FALSE, FALSE, 1);
-	/* @@@ how to make label fill the space on the right - add a hbox ? */
-//	gtk_label_set_justify(GTK_LABEL(status_name), GTK_JUSTIFY_LEFT);
-	gtk_label_set_selectable(GTK_LABEL(status_name), TRUE);
-
-	status_entry = gtk_entry_new();
-	gtk_box_pack_start(GTK_BOX(v2box), status_entry, TRUE, FALSE, 1);
-
-	/* x / y */
-
-	v2box = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), v2box, FALSE, FALSE, 1);
-
-	status_x = gtk_label_new("x = ...");
-	gtk_box_pack_start(GTK_BOX(v2box), status_x, TRUE, FALSE, 1);
-
-	status_y = gtk_label_new("y = ...");
-	gtk_box_pack_start(GTK_BOX(v2box), status_y, FALSE, FALSE, 1);
-
-	/* r / angle */
-
-	v2box = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), v2box, FALSE, FALSE, 1);
-
-	status_r = gtk_label_new("r = ...");
-	gtk_box_pack_start(GTK_BOX(v2box), status_r, TRUE, FALSE, 1);
-
-	status_angle = gtk_label_new("a = ...");
-	gtk_box_pack_start(GTK_BOX(v2box), status_angle, TRUE, FALSE, 1);
-
-	/* sys / user pos */
-
-	v2box = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), v2box, TRUE, TRUE, 1);
-
-	status_sys_pos = gtk_label_new("1 / 2");
-	gtk_box_pack_start(GTK_BOX(v2box), status_sys_pos, TRUE, FALSE, 1);
-
-	status_user_pos = gtk_label_new("1 / 2");
-	gtk_box_pack_start(GTK_BOX(v2box), status_user_pos, TRUE, FALSE, 1);
-
-	/* zoom / grid */
-
-	v2box = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_end(GTK_BOX(hbox), v2box, FALSE, FALSE, 1);
-
-	status_zoom = gtk_label_new("1x");
-	gtk_box_pack_start(GTK_BOX(v2box), status_zoom, TRUE, FALSE, 1);
-
-	status_grid = gtk_label_new("10mil");
-	gtk_box_pack_start(GTK_BOX(v2box), status_grid, TRUE, FALSE, 1);
-
-	/* message bar */
-
-	status_msg = gtk_statusbar_new();
-	gtk_box_pack_start(GTK_BOX(vbox), status_msg, FALSE, FALSE, 0);
-}

Copied: trunk/eda/fped/gui_status.c (from rev 5361, developers/werner/fped/gui_status.c)
===================================================================
--- trunk/eda/fped/gui_status.c	                        (rev 0)
+++ trunk/eda/fped/gui_status.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,476 @@
+/*
+ * gui_status.c - GUI, status area
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <gtk/gtk.h>
+
+#include "util.h"
+#include "coord.h"
+#include "error.h"
+#include "unparse.h"
+#include "gui_util.h"
+#include "gui_style.h"
+#include "gui.h"
+#include "gui_status.h"
+
+
+struct edit_ops {
+	int (*changed)(GtkWidget *widget, const char *s, void *ctx);
+	int (*activate)(GtkWidget *widget, const char *s, void *ctx);
+};
+
+static struct edit_ops *edit_ops = NULL;
+static void *edit_ctx;
+
+
+/* ----- setter functions -------------------------------------------------- */
+
+
+static GtkWidget *status_name, *status_entry;
+static GtkWidget *status_x, *status_y;
+static GtkWidget *status_r, *status_angle;
+static GtkWidget *status_sys_pos, *status_user_pos;
+static GtkWidget *status_zoom, *status_grid;
+static GtkWidget *status_msg;
+
+
+static void set_label(GtkWidget *label, const char *fmt, va_list ap)
+{
+	char *s;
+
+	s = stralloc_vprintf(fmt, ap);
+	gtk_label_set_text(GTK_LABEL(label), s);
+	free(s);
+}
+
+
+#define	SETTER(name)					\
+	void status_set_##name(const char *fmt, ...)	\
+	{						\
+		va_list ap;				\
+							\
+		va_start(ap, fmt);			\
+		set_label(status_##name, fmt, ap);	\
+		va_end(ap);				\
+	}
+
+SETTER(name)
+SETTER(x)
+SETTER(y)
+SETTER(r)
+SETTER(angle)
+SETTER(sys_pos)
+SETTER(user_pos)
+SETTER(zoom)
+SETTER(grid)
+
+
+/* ----- complex status updates -------------------------------------------- */
+
+
+void status_set_xy(struct coord coord)
+{
+	status_set_x("x = %5.2f mm", units_to_mm(coord.x));
+	status_set_y("y = %5.2f mm", units_to_mm(coord.y));
+}
+
+
+static void entry_color(const char *color)
+{
+	GdkColor col;
+
+	col = get_color(color);
+	gtk_widget_modify_base(GTK_WIDGET(status_entry),
+	    GTK_STATE_NORMAL, &col);
+}
+
+
+/* ----- identifier fields ------------------------------------------------- */
+
+
+struct edit_unique_ctx {
+	const char **s;
+	int (*validate)(const char *s, void *ctx);
+	void *ctx;
+};
+
+
+static int unique_changed(GtkWidget *widget, const char *s, void *ctx)
+{
+	const struct edit_unique_ctx *unique_ctx = ctx;
+	int ok;
+
+	if (!strcmp(s, *unique_ctx->s)) {
+		entry_color(COLOR_EDIT_ASIS);
+		return 1;
+	}
+	ok = !unique_ctx->validate || unique_ctx->validate(s, unique_ctx->ctx);
+	entry_color(ok ? COLOR_EDIT_GOOD : COLOR_EDIT_BAD);
+	return ok;
+}
+
+
+static int unique_activate(GtkWidget *widget, const char *s, void *ctx)
+{
+	const struct edit_unique_ctx *unique_ctx = ctx;
+
+	if (strcmp(s, *unique_ctx->s) &&
+	     unique_ctx->validate && !unique_ctx->validate(s, unique_ctx->ctx))
+		return 0;
+	*unique_ctx->s = unique(s);
+	entry_color(COLOR_EDIT_ASIS);
+	return 1;
+}
+
+
+static struct edit_ops edit_ops_unique = {
+	.changed	= unique_changed,
+	.activate	= unique_activate,
+};
+
+
+void edit_unique(const char **s, int (*validate)(const char *s, void *ctx), 
+    void *ctx)
+{
+	static struct edit_unique_ctx unique_ctx;
+
+	unique_ctx.s = s;
+	unique_ctx.validate = validate;
+	unique_ctx.ctx = ctx;
+	edit_ops = &edit_ops_unique;
+	edit_ctx = &unique_ctx;
+	gtk_entry_set_text(GTK_ENTRY(status_entry), *s);
+	entry_color(COLOR_EDIT_ASIS);
+	gtk_widget_show(status_entry);
+}
+
+
+/* ----- identifier fields with NULL --------------------------------------- */
+
+
+static int unique_null_changed(GtkWidget *widget, const char *s, void *ctx)
+{
+	const struct edit_unique_ctx *unique_ctx = ctx;
+	int ok;
+
+	if (!strcmp(s, *unique_ctx->s ? *unique_ctx->s : "")) {
+		entry_color(COLOR_EDIT_ASIS);
+		return 1;
+	}
+	ok = !*s;
+	if (!ok)
+		ok = !unique_ctx->validate ||
+		     unique_ctx->validate(s, unique_ctx->ctx);
+	entry_color(ok ? COLOR_EDIT_GOOD : COLOR_EDIT_BAD);
+	return ok;
+}
+
+
+static int unique_null_activate(GtkWidget *widget, const char *s, void *ctx)
+{
+	const struct edit_unique_ctx *unique_ctx = ctx;
+
+	if (!*s)
+		 *unique_ctx->s = NULL;
+	else {
+		if (unique_ctx->validate &&
+		    !unique_ctx->validate(s, unique_ctx->ctx))
+			return 0;
+		*unique_ctx->s = unique(s);
+	}
+	entry_color(COLOR_EDIT_ASIS);
+	return 1;
+}
+
+
+static struct edit_ops edit_ops_null_unique = {
+	.changed	= unique_null_changed,
+	.activate	= unique_null_activate,
+};
+
+
+void edit_unique_null(const char **s,
+    int (*validate)(const char *s, void *ctx), void *ctx)
+{
+	static struct edit_unique_ctx unique_ctx;
+
+	unique_ctx.s = s;
+	unique_ctx.validate = validate;
+	unique_ctx.ctx = ctx;
+	edit_ops = &edit_ops_null_unique;
+	edit_ctx = &unique_ctx;
+	gtk_entry_set_text(GTK_ENTRY(status_entry), *s ? *s : "");
+	entry_color(COLOR_EDIT_ASIS);
+	gtk_widget_show(status_entry);
+}
+
+
+/* ----- string fields ----------------------------------------------------- */
+
+
+struct edit_name_ctx {
+	char **s;
+	int (*validate)(const char *s, void *ctx);
+	void *ctx;
+};
+
+
+static int name_changed(GtkWidget *widget, const char *s, void *ctx)
+{
+	const struct edit_name_ctx *name_ctx = ctx;
+	int ok;
+
+	if (!strcmp(s, *name_ctx->s)) {
+		entry_color(COLOR_EDIT_ASIS);
+		return 1;
+	}
+	ok = !name_ctx->validate || name_ctx->validate(s, name_ctx->ctx);
+	entry_color(ok ? COLOR_EDIT_GOOD : COLOR_EDIT_BAD);
+	return ok;
+}
+
+
+static int name_activate(GtkWidget *widget, const char *s, void *ctx)
+{
+	const struct edit_name_ctx *name_ctx = ctx;
+
+	if (name_ctx->validate && !name_ctx->validate(s, name_ctx->ctx))
+		return 0;
+	free(*name_ctx->s);
+	*name_ctx->s = stralloc(s);
+	entry_color(COLOR_EDIT_ASIS);
+	return 1;
+}
+
+
+static struct edit_ops edit_ops_name = {
+	.changed	= name_changed,
+	.activate	= name_activate,
+};
+
+
+void edit_name(char **s, int (*validate)(const char *s, void *ctx), void *ctx)
+{
+	static struct edit_name_ctx name_ctx;
+
+	name_ctx.s = s;
+	name_ctx.validate = validate;
+	name_ctx.ctx = ctx;
+	edit_ops = &edit_ops_name;
+	edit_ctx = &name_ctx;
+	gtk_entry_set_text(GTK_ENTRY(status_entry), *s);
+	entry_color(COLOR_EDIT_ASIS);
+	gtk_widget_show(status_entry);
+}
+
+
+/* ----- expression fields ------------------------------------------------- */
+
+
+static struct expr *try_parse_expr(const char *s)
+{
+	status_begin_reporting();
+	return parse_expr(s);
+}
+
+
+static int expr_changed(GtkWidget *widget, const char *s, void *ctx)
+{
+	struct expr *expr;
+
+	expr = try_parse_expr(s);
+	if (!expr) {
+		entry_color(COLOR_EDIT_BAD);
+		return 0;
+	}
+	entry_color(COLOR_EDIT_GOOD);
+	free_expr(expr);
+	return 1;
+}
+
+
+static int expr_activate(GtkWidget *widget, const char *s, void *ctx)
+{
+	struct expr **anchor = ctx;
+	struct expr *expr;
+
+	expr = try_parse_expr(s);
+	if (!expr)
+		return 0;
+	free_expr(*anchor);
+	*anchor = expr;
+	entry_color(COLOR_EDIT_ASIS);
+	return 1;
+}
+
+
+static struct edit_ops edit_ops_expr = {
+	.changed	= expr_changed,
+	.activate	= expr_activate,
+};
+
+
+void edit_expr(struct expr **expr)
+{
+	char *s;
+
+	edit_ops = &edit_ops_expr;
+	edit_ctx = expr;
+	s = unparse(*expr);
+	gtk_entry_set_text(GTK_ENTRY(status_entry), s);
+	free(s);
+	entry_color(COLOR_EDIT_ASIS);
+	gtk_widget_show(status_entry);
+}
+
+
+/* ----- text entry -------------------------------------------------------- */
+
+
+static gboolean changed(GtkWidget *widget, GdkEventMotion *event,
+     gpointer data)
+{
+	if (edit_ops && edit_ops->changed)
+		edit_ops->changed(widget,
+		    gtk_entry_get_text(GTK_ENTRY(widget)), edit_ctx);
+	return TRUE;
+}
+
+
+static gboolean activate(GtkWidget *widget, GdkEventMotion *event,
+     gpointer data)
+{
+	if (edit_ops && edit_ops->activate)
+		if (edit_ops->activate(widget,
+		    gtk_entry_get_text(GTK_ENTRY(widget)), edit_ctx)) {
+			inst_deselect();
+			change_world();
+		}
+	return TRUE;
+}
+
+
+void edit_nothing(void)
+{
+	edit_ops = NULL;
+	gtk_widget_hide(status_entry);
+}
+
+
+/* ----- status reports ---------------------------------------------------- */
+
+
+static gint context_id;
+static int have_msg = 0;
+
+
+static void clear_status_msg(void)
+{
+	if (have_msg) {
+		gtk_statusbar_pop(GTK_STATUSBAR(status_msg), context_id);
+		have_msg = 0;
+	}
+}
+
+
+static void report_to_gui(const char *s)
+{
+	if (!have_msg)
+		gtk_statusbar_push(GTK_STATUSBAR(status_msg), context_id, s);
+	have_msg = 1;
+}
+
+
+void status_begin_reporting(void)
+{
+	clear_status_msg();
+	reporter = report_to_gui;
+}
+
+
+/* ----- setup ------------------------------------------------------------- */
+
+
+static GtkWidget *add_label(GtkWidget *tab, int col, int row)
+{
+	GtkWidget *label;
+
+	label = label_in_box_new(NULL);
+	gtk_table_attach_defaults(GTK_TABLE(tab), box_of_label(label),
+	    col, col+1, row, row+1);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+	gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+	return label;
+}
+
+
+void make_status_area(GtkWidget *vbox)
+{
+	GtkWidget *tab, *hbox;
+
+	tab = gtk_table_new(5, 2, FALSE);
+	gtk_box_pack_start(GTK_BOX(vbox), tab, FALSE, TRUE, 0);
+
+	/* name and input */
+
+	status_name = add_label(tab, 0, 0);
+
+	/*
+	 * @@@ this should make the entry consume all available space. alas, it
+	 * doesn't work like that :-(
+	 */
+	hbox = gtk_hbox_new(TRUE, 0);
+	gtk_table_attach_defaults(GTK_TABLE(tab), hbox,
+	    0, 1, 1, 2);
+	
+	status_entry = gtk_entry_new();
+	gtk_box_pack_start(GTK_BOX(hbox), status_entry, TRUE, TRUE, 0);
+
+	gtk_entry_set_has_frame(GTK_ENTRY(status_entry), FALSE);
+
+	g_signal_connect(G_OBJECT(status_entry), "changed",
+            G_CALLBACK(changed), status_entry);
+	g_signal_connect(G_OBJECT(status_entry), "activate",
+            G_CALLBACK(activate), status_entry);
+
+	/* x / y */
+
+	status_x = add_label(tab, 1, 0);
+	status_y = add_label(tab, 1, 1);
+
+	/* r / angle */
+
+	status_r = add_label(tab, 2, 0);
+	status_angle = add_label(tab, 2, 1);
+
+	/* sys / user pos */
+
+	status_sys_pos = add_label(tab, 3, 0);
+	status_user_pos = add_label(tab, 3, 1);
+
+	/* zoom / grid */
+
+	status_zoom = add_label(tab, 4, 0);
+	status_grid = add_label(tab, 4, 1);
+
+	/* message bar */
+
+	status_msg = gtk_statusbar_new();
+	gtk_box_pack_start(GTK_BOX(vbox), status_msg, FALSE, FALSE, 0);
+
+	context_id = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_msg),
+	    "messages");
+}

Deleted: trunk/eda/fped/gui_status.h
===================================================================
--- developers/werner/fped/gui_status.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui_status.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,32 +0,0 @@
-/*
- * gui_status.h - GUI, status area
- *
- * 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 GUI_STATUS_H
-#define GUI_STATUS_H
-
-#include <gtk/gtk.h>
-
-
-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_pos(const char *fmt, ...);
-void status_set_user_pos(const char *fmt, ...);
-void status_set_zoom(const char *fmt, ...);
-void status_set_grid(const char *fmt, ...);
-
-void make_status_area(GtkWidget *vbox) ;
-
-#endif /* !GUI_STATUS_H */

Copied: trunk/eda/fped/gui_status.h (from rev 5361, developers/werner/fped/gui_status.h)
===================================================================
--- trunk/eda/fped/gui_status.h	                        (rev 0)
+++ trunk/eda/fped/gui_status.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,47 @@
+/*
+ * gui_status.h - GUI, status area
+ *
+ * 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 GUI_STATUS_H
+#define GUI_STATUS_H
+
+#include <gtk/gtk.h>
+
+#include "coord.h"
+#include "expr.h"
+
+
+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),
+    void *ctx);
+void edit_name(char **s, int (*validate)(const char *s, void *ctx), void *ctx);
+void edit_expr(struct expr **expr);
+void edit_nothing(void);
+
+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_pos(const char *fmt, ...);
+void status_set_user_pos(const char *fmt, ...);
+void status_set_zoom(const char *fmt, ...);
+void status_set_grid(const char *fmt, ...);
+
+void status_set_xy(struct coord coord);
+
+void status_begin_reporting(void);
+
+void make_status_area(GtkWidget *vbox) ;
+
+#endif /* !GUI_STATUS_H */

Deleted: trunk/eda/fped/gui_style.c
===================================================================
--- developers/werner/fped/gui_style.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui_style.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,64 +0,0 @@
-/*
- * gui_style.c - GUI, style definitions
- *
- * 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 <stdlib.h>
-#include <gtk/gtk.h>
-
-#include "gui_style.h"
-
-
-#define	GC(spec)	gc(drawable, (spec))
-
-
-static GdkColor get_color(GdkColormap *cmap, const char *spec)
-{
-	GdkColor color;
-
-	if (!gdk_color_parse(spec, &color))
-		abort();
-	if (!gdk_colormap_alloc_color(cmap, &color, FALSE, TRUE))
-		abort();
-	return color;
-}
-
-
-static GdkGC *gc(GdkDrawable *drawable, const char *spec)
-{
-	GdkGCValues gc_values = {
-		.background = get_color(gdk_drawable_get_colormap(drawable),
-		    "black"),
-		.foreground = get_color(gdk_drawable_get_colormap(drawable),
-		    spec),
-	};
-
-	return gdk_gc_new_with_values(drawable, &gc_values,
-	     GDK_GC_FOREGROUND | GDK_GC_BACKGROUND);
-}
-
-
-void gui_setup_style(GdkDrawable *drawable)
-{
-	gc_bg = GC("#000000");
-	gc_vec_bg = GC("#ffff00");
-	gc_vec_fg = GC("#ffff00");
-	gc_line_bg = GC("#ffffff");
-	gc_line_fg = GC("#ffffff");
-	gc_rect_bg = gc_line_bg;
-	gc_rect_fg = gc_line_fg;
-	gc_pad_bg = GC("#ff0000");
-	gc_pad_fg = GC("#ff0000");
-	gc_arc_bg = gc_line_bg;
-	gc_arc_fg = gc_line_fg;
-	gc_frame_bg = GC("#00ff00");
-	gc_frame_fg = GC("#00ff00");
-}

Copied: trunk/eda/fped/gui_style.c (from rev 5367, developers/werner/fped/gui_style.c)
===================================================================
--- trunk/eda/fped/gui_style.c	                        (rev 0)
+++ trunk/eda/fped/gui_style.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,69 @@
+/*
+ * gui_style.c - GUI, style definitions
+ *
+ * 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 <gtk/gtk.h>
+
+#include "inst.h"
+#include "gui_util.h"
+#include "gui.h"
+#include "gui_style.h"
+
+
+#define	INVALID	"#00ffff"
+
+
+GdkGC *gc_bg;
+GdkGC *gc_vec[mode_n];
+GdkGC *gc_obj[mode_n];
+GdkGC *gc_pad[mode_n];
+GdkGC *gc_ptext[mode_n];
+GdkGC *gc_meas[mode_n];
+GdkGC *gc_frame[mode_n];
+
+
+static GdkGC *gc(const char *spec, int width)
+{
+	GdkGCValues gc_values = {
+		.background = get_color("black"),
+		.foreground = get_color(spec),
+		.line_width = width,
+	};
+
+	return gdk_gc_new_with_values(root->window, &gc_values,
+	     GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_LINE_WIDTH);
+}
+
+
+static void style(GdkGC *gcs[mode_n],
+    const char *in, const char *in_path, const char *act, const char *act_path,
+    const char *sel)
+{
+	gcs[mode_inactive]		= gc(in, 1);
+	gcs[mode_inactive_in_path]	= gc(in_path, 1);
+	gcs[mode_active]		= gc(act, 1);
+	gcs[mode_active_in_path]	= gc(act_path, 1);
+	gcs[mode_selected]		= gc(sel, 2);
+}
+
+
+void gui_setup_style(GdkDrawable *drawable)
+{
+	gc_bg = gc("#000000", 0);
+	/*		inactive   in+path    active     act+path   selected */
+	style(gc_vec,	"#202000", "#404020", "#909040", "#c0c080", "#ffff80");
+	style(gc_obj,	"#006060", INVALID,   "#00ffff", INVALID,   "#ffff80");
+	style(gc_pad,	"#400000", INVALID,   "#ff0000", INVALID,   "#ffff80");
+	style(gc_ptext,	"#404040", INVALID,   "#ffffff", INVALID,   "#ffffff");
+	style(gc_meas,	"#280040", INVALID,   "#ff00ff", INVALID,   "#ffff80");
+	style(gc_frame,	"#004000", "#205020", "#00ff00", INVALID,   INVALID);
+}

Deleted: trunk/eda/fped/gui_style.h
===================================================================
--- developers/werner/fped/gui_style.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/gui_style.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,38 +0,0 @@
-/*
- * gui_style.h - GUI, style definitions
- *
- * 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 GUI_STYLE_H
-#define	GUI_STYLE_H
-
-#define	CANVAS_CLEARANCE	10
-
-#define	VEC_ARROW_LEN		10
-#define	VEC_ARROW_ANGLE		20
-#define	VEC_EYE_R		5
-
-#define	FRAME_CLEARANCE		5
-#define	FRAME_EYE_R1		3
-#define	FRAME_EYE_R2		5
-
-
-GdkGC *gc_bg;
-GdkGC *gc_vec_bg, *gc_vec_fg;
-GdkGC *gc_line_bg, *gc_line_fg;
-GdkGC *gc_rect_bg, *gc_rect_fg;
-GdkGC *gc_pad_bg, *gc_pad_fg;
-GdkGC *gc_arc_bg, *gc_arc_fg;
-GdkGC *gc_frame_bg, *gc_frame_fg;
-
-void gui_setup_style(GdkDrawable *drawable);
-
-#endif /* !GUI_STYLE_H */

Copied: trunk/eda/fped/gui_style.h (from rev 5367, developers/werner/fped/gui_style.h)
===================================================================
--- trunk/eda/fped/gui_style.h	                        (rev 0)
+++ trunk/eda/fped/gui_style.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,91 @@
+/*
+ * gui_style.h - GUI, style definitions
+ *
+ * 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 GUI_STYLE_H
+#define	GUI_STYLE_H
+
+#include <gtk/gtk.h>
+
+#include "inst.h"
+
+
+/* ----- screen distances, etc. -------------------------------------------- */
+
+
+#define	CANVAS_CLEARANCE	10
+
+#define	VEC_ARROW_LEN		10
+#define	VEC_ARROW_ANGLE		20
+#define	VEC_EYE_R		5
+
+#define	PAD_FONT		"Sans Bold 24"
+#define	PAD_BORDER		2
+
+#define	MEAS_FONT		"Sans 8"
+#define	MEAS_BASELINE_OFFSET	0.1
+#define	MEAS_ARROW_LEN		9
+#define MEAS_ARROW_ANGLE	30
+
+#define	FRAME_FONT		"Sans 8"
+#define	FRAME_BASELINE_OFFSET	0.1
+#define	FRAME_SHORT_X		100
+#define	FRAME_SHORT_Y		20
+#define	FRAME_CLEARANCE		5
+#define	FRAME_EYE_R1		3
+#define	FRAME_EYE_R2		5
+
+#define	SELECT_R		6	/* pixels within which we select */
+
+#define	MIN_FONT_SCALE		0.20	/* don't scale fonts below this */
+
+
+/* ----- assorted colors --------------------------------------------------- */
+
+
+#define COLOR_EDIT_ASIS	"#ffffff"
+#define COLOR_EDIT_GOOD	"#a0ffa0"
+#define COLOR_EDIT_BAD	"#ffa0a0"
+
+#define	COLOR_EDITING	"#ff00ff"
+
+#define	COLOR_FRAME_UNSELECTED	"#c0c0c0"
+#define COLOR_FRAME_SELECTED	"#fff0a0"
+#define COLOR_FRAME_EDITING	COLOR_EDITING
+
+#define	COLOR_VAR_PASSIVE	COLOR_FRAME_UNSELECTED
+#define	COLOR_VAR_EDITING	COLOR_EDITING
+#define	COLOR_EXPR_PASSIVE	"#f0f0ff"
+#define	COLOR_EXPR_EDITING	COLOR_EDITING
+#define	COLOR_CHOICE_UNSELECTED	COLOR_EXPR_PASSIVE
+#define	COLOR_CHOICE_SELECTED	"#9090ff"
+#define	COLOR_ROW_UNSELECTED	COLOR_CHOICE_UNSELECTED
+#define	COLOR_ROW_SELECTED	COLOR_CHOICE_SELECTED
+
+#define	COLOR_VAR_TABLE_SEP	"black"
+
+
+/* ----- canvas drawing styles --------------------------------------------- */
+
+
+extern GdkGC *gc_bg;
+extern GdkGC *gc_vec[mode_n];
+extern GdkGC *gc_obj[mode_n];
+extern GdkGC *gc_pad[mode_n];
+extern GdkGC *gc_ptext[mode_n];
+extern GdkGC *gc_meas[mode_n];
+extern GdkGC *gc_frame[mode_n];
+
+
+void gui_setup_style(GdkDrawable *drawable);
+
+#endif /* !GUI_STYLE_H */

Copied: trunk/eda/fped/gui_util.c (from rev 5367, developers/werner/fped/gui_util.c)
===================================================================
--- trunk/eda/fped/gui_util.c	                        (rev 0)
+++ trunk/eda/fped/gui_util.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,167 @@
+/*
+ * gui_util.c - GUI helper functions
+ *
+ * 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 <stdlib.h>
+#include <math.h>
+#include <gtk/gtk.h>
+
+#include "gui_style.h"
+#include "gui.h"
+#include "gui_util.h"
+
+
+/* ----- look up a color --------------------------------------------------- */
+
+
+GdkColor get_color(const char *spec)
+{
+	GdkColormap *cmap;
+	GdkColor color;
+
+	cmap = gdk_drawable_get_colormap(root->window);
+	if (!gdk_color_parse(spec, &color))
+		abort();
+	if (!gdk_colormap_alloc_color(cmap, &color, FALSE, TRUE))
+		abort();
+	return color;
+}
+
+
+/* ----- lines with a width ------------------------------------------------ */
+
+
+void set_width(GdkGC *gc, int width)
+{
+	gdk_gc_set_line_attributes(gc, width < 1 ? 1 : width,
+	    GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+}
+
+
+/* ----- labels in a box --------------------------------------------------- */
+
+
+GtkWidget *label_in_box_new(const char *s)
+{
+	GtkWidget *evbox, *label;
+
+	evbox = gtk_event_box_new();
+	label = gtk_label_new(s);
+	gtk_misc_set_padding(GTK_MISC(label), 1, 1);
+	gtk_container_add(GTK_CONTAINER(evbox), label);
+	return label;
+}
+
+
+GtkWidget *box_of_label(GtkWidget *label)
+{
+	return gtk_widget_get_ancestor(label, GTK_TYPE_EVENT_BOX);
+}
+
+
+void label_in_box_bg(GtkWidget *label, const char *color)
+{
+	GtkWidget *box;
+	GdkColor col = get_color(color);
+
+	box = box_of_label(label);
+	gtk_widget_modify_bg(box, GTK_STATE_NORMAL, &col);
+}
+
+
+/* ----- render a text string ---------------------------------------------- */
+
+
+void render_text(GdkDrawable *da, GdkGC *gc, int x, int y, double angle,
+    const char *s, const char *font, double xalign, double yalign,
+    int xmax, int ymax)
+{
+	GdkScreen *screen;
+	PangoRenderer *renderer;
+	PangoContext *context;
+	PangoLayout *layout;
+	PangoFontDescription *desc;
+	int width, height;
+	PangoMatrix m = PANGO_MATRIX_INIT;
+	double f_min, f;
+
+	/* set up the renderer */
+
+	screen = gdk_drawable_get_screen(da);
+	renderer = gdk_pango_renderer_get_default(screen);
+	gdk_pango_renderer_set_drawable(GDK_PANGO_RENDERER(renderer), da);
+	gdk_pango_renderer_set_gc(GDK_PANGO_RENDERER(renderer), gc);
+
+	/* start preparing the layout */
+
+	context = gdk_pango_context_get_for_screen(screen);
+	layout = pango_layout_new(context);
+	pango_layout_set_text(layout, s, -1);
+
+	/* apply the font */
+
+	desc = pango_font_description_from_string(font);
+	pango_layout_set_font_description(layout, desc);
+	pango_font_description_free(desc);
+
+	/* align and position the text */
+
+	pango_layout_get_size(layout, &width, &height);
+	f_min = 1.0;
+	if (xmax) {
+		f = xmax/((double) width/PANGO_SCALE);
+		if (f < f_min)
+			f_min = f;
+	}
+	if (ymax) {
+		f = ymax/((double) height/PANGO_SCALE);
+		if (f < f_min)
+			f_min = f;
+	}
+	if (f_min < MIN_FONT_SCALE)
+		f_min = MIN_FONT_SCALE;
+	pango_matrix_translate(&m, x, y);
+	pango_matrix_rotate(&m, angle);
+	pango_matrix_translate(&m,
+	    -xalign*f_min*width/PANGO_SCALE,
+	    (yalign-1)*f_min*height/PANGO_SCALE);
+	pango_matrix_scale(&m, f_min, f_min);
+
+	pango_context_set_matrix(context, &m);
+	pango_layout_context_changed(layout);
+	pango_renderer_draw_layout(renderer, layout, 0, 0);
+
+	/* clean up renderer */
+
+	gdk_pango_renderer_set_drawable(GDK_PANGO_RENDERER(renderer), NULL);
+	gdk_pango_renderer_set_gc(GDK_PANGO_RENDERER(renderer), NULL);
+
+	/* free objects */
+
+	g_object_unref(layout);
+	g_object_unref(context);
+}
+
+
+/* ----- kill the content of a container ----------------------------------- */
+
+
+static void destroy_callback(GtkWidget *widget, gpointer data)
+{
+	gtk_widget_destroy(widget);
+}
+
+
+void destroy_all_children(GtkContainer *container)
+{
+	gtk_container_foreach(container, destroy_callback, NULL);
+}

Copied: trunk/eda/fped/gui_util.h (from rev 5367, developers/werner/fped/gui_util.h)
===================================================================
--- trunk/eda/fped/gui_util.h	                        (rev 0)
+++ trunk/eda/fped/gui_util.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,34 @@
+/*
+ * gui_util.h - GUI helper functions
+ *
+ * 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 GUI_UTIL_H
+#define	GUI_UTIL_H
+
+#include <gtk/gtk.h>
+
+
+GdkColor get_color(const char *spec);
+
+void set_width(GdkGC *gc, int width);
+
+GtkWidget *label_in_box_new(const char *s);
+GtkWidget *box_of_label(GtkWidget *label);
+void label_in_box_bg(GtkWidget *box, const char *color);
+
+void render_text(GdkDrawable *da, GdkGC *gc, int x, int y, double angle,
+    const char *s, const char *font, double xalign, double yalign,
+    int xmax, int ymax);
+
+void destroy_all_children(GtkContainer *container);
+
+#endif /* !GUI_UTIL_H */

Copied: trunk/eda/fped/icons (from rev 5363, developers/werner/fped/icons)

Deleted: trunk/eda/fped/inst.c
===================================================================
--- developers/werner/fped/inst.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/inst.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,305 +0,0 @@
-/*
- * inst.c - Instance structures
- *
- * 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 <stdlib.h>
-#include <stdio.h>
-#include <math.h>
-
-#include "util.h"
-#include "coord.h"
-#include "obj.h"
-#include "gui_inst.h"
-#include "inst.h"
-
-
-static struct inst *insts = NULL, **next_inst;
-struct inst *curr_frame = NULL;
-
-
-static void update_bbox(struct bbox *bbox, struct coord coord)
-{
-	if (bbox->min.x > coord.x)
-		bbox->min.x = coord.x;
-	if (bbox->max.x < coord.x)
-		bbox->max.x = coord.x;
-	if (bbox->min.y > coord.y)
-		bbox->min.y = coord.y;
-	if (bbox->max.y < coord.y)
-		bbox->max.y = coord.y;
-}
-
-
-static void propagate_bbox(const struct inst *inst)
-{
-	update_bbox(&curr_frame->bbox, inst->bbox.min);
-	update_bbox(&curr_frame->bbox, inst->bbox.max);
-}
-
-
-static struct inst *add_inst(const struct inst_ops *ops, struct coord base)
-{
-	struct inst *inst;
-
-	inst = alloc_type(struct inst);
-	inst->ops = ops;
-	inst->base = inst->bbox.min = inst->bbox.max = base;
-	inst->next = NULL;
-	*next_inst = inst;
-	next_inst = &inst->next;
-	return inst;
-}
-
-
-/* ----- vec --------------------------------------------------------------- */
-
-
-static void vec_op_debug(struct inst *self)
-{
-	printf("vec %lg, %lg -> %lg, %lg\n",
-	    units_to_mm(self->base.x), units_to_mm(self->base.y),
-	    units_to_mm(self->u.end.x), units_to_mm(self->u.end.y));
-}
-
-
-static struct inst_ops vec_ops = {
-	.debug	= vec_op_debug,
-	.draw	= gui_draw_vec,
-};
-
-
-int inst_vec(struct vec *vec, struct coord base)
-{
-	struct inst *inst;
-
-	inst = add_inst(&vec_ops, base);
-	inst->u.end = vec->pos;
-	update_bbox(&inst->bbox, vec->pos);
-	propagate_bbox(inst);
-	return 1;
-}
-
-
-/* ----- line -------------------------------------------------------------- */
-
-
-static void line_op_debug(struct inst *self)
-{
-	printf("line %lg, %lg / %lg, %lg\n",
-	    units_to_mm(self->base.x), units_to_mm(self->base.y),
-	    units_to_mm(self->u.end.x), units_to_mm(self->u.end.y));
-}
-
-
-static struct inst_ops line_ops = {
-	.debug	= line_op_debug,
-	.draw	= gui_draw_line,
-};
-
-
-int inst_line(struct coord a, struct coord b)
-{
-	struct inst *inst;
-
-	inst = add_inst(&line_ops, a);
-	inst->u.end = b;
-	update_bbox(&inst->bbox, b);
-	propagate_bbox(inst);
-	return 1;
-}
-
-
-/* ----- rect -------------------------------------------------------------- */
-
-
-static void rect_op_debug(struct inst *self)
-{
-	printf("rect %lg, %lg / %lg, %lg\n",
-	    units_to_mm(self->base.x), units_to_mm(self->base.y),
-	    units_to_mm(self->u.end.x), units_to_mm(self->u.end.y));
-}
-
-
-static struct inst_ops rect_ops = {
-	.debug	= rect_op_debug,
-	.draw	= gui_draw_rect,
-};
-
-
-int inst_rect(struct coord a, struct coord b)
-{
-	struct inst *inst;
-
-	inst = add_inst(&rect_ops, a);
-	inst->u.end = b;
-	update_bbox(&inst->bbox, b);
-	propagate_bbox(inst);
-	return 1;
-}
-
-
-/* ----- pad --------------------------------------------------------------- */
-
-
-static void pad_op_debug(struct inst *self)
-{
-	printf("pad \"%s\" %lg, %lg / %lg, %lg\n", self->u.name,
-	    units_to_mm(self->bbox.min.x), units_to_mm(self->bbox.min.y),
-	    units_to_mm(self->bbox.max.x), units_to_mm(self->bbox.max.y));
-}
-
-
-static struct inst_ops pad_ops = {
-	.debug	= pad_op_debug,
-	.draw	= gui_draw_pad,
-};
-
-
-int inst_pad(const char *name, struct coord a, struct coord b)
-{
-	struct inst *inst;
-
-	inst = add_inst(&pad_ops, a);
-	inst->u.name = stralloc(name);
-	update_bbox(&inst->bbox, b);
-	propagate_bbox(inst);
-	return 1;
-}
-
-
-/* ----- arc --------------------------------------------------------------- */
-
-
-static void arc_op_debug(struct inst *self)
-{
-	printf("arc %lg, %lg radius %lg %lg ... %lg\n",
-	    units_to_mm(self->base.x), units_to_mm(self->base.y),
-	    units_to_mm(self->u.arc.r), self->u.arc.a1, self->u.arc.a2);
-}
-
-
-static struct inst_ops arc_ops = {
-	.debug	= arc_op_debug,
-	.draw	= gui_draw_arc,
-};
-
-
-int inst_arc(struct coord center, struct coord start, struct coord end)
-{
-	struct inst *inst;
-	double r, a1, a2;
-
-	inst = add_inst(&arc_ops, center);
-	r = hypot(start.x-center.x, start.y-center.y);
-	a1 = atan2(start.y-center.y, start.x-center.x)/M_PI*180.0;
-	a2 = atan2(end.y-center.y, end.x-center.x)/M_PI*180.0;
-	if (a1 < 0)
-		a1 += 360.0;
-	if (a2 < 0)
-		a2 += 360.0;
-	inst->u.arc.r = r;
-	inst->u.arc.a1 = a1;
-	inst->u.arc.a2 = a2;
-	inst->bbox.min.x = center.x-r;
-	inst->bbox.max.x = center.x+r;
-	inst->bbox.min.y = center.x-r;
-	inst->bbox.max.y = center.x+r;
-	propagate_bbox(inst);
-	return 1;
-}
-
-
-/* ----- frame ------------------------------------------------------------- */
-
-
-static void frame_op_debug(struct inst *self)
-{
-	printf("frame %s @ %lg, %lg\n",
-	    self->u.frame.ref->name ? self->u.frame.ref->name : "(root)",
-	    units_to_mm(self->base.x), units_to_mm(self->base.y));
-}
-
-
-static struct inst_ops frame_ops = {
-	.debug	= frame_op_debug,
-	.draw	= gui_draw_frame,
-};
-
-
-void inst_begin_frame(const struct frame *frame, struct coord base)
-{
-	struct inst *inst;
-
-	inst = add_inst(&frame_ops, base);
-	inst->u.frame.ref = frame;
-	inst->u.frame.outer = curr_frame;
-	curr_frame = inst;
-}
-
-
-void inst_end_frame(const struct frame *frame)
-{
-	struct inst *inst = curr_frame;
-
-	curr_frame = curr_frame->u.frame.outer;
-	if (curr_frame)
-		propagate_bbox(inst);
-}
-
-
-/* ----- misc. ------------------------------------------------------------- */
-
-
-struct bbox inst_get_bbox(void)
-{
-	static struct bbox bbox_zero;
-
-	return insts ? insts->bbox : bbox_zero;
-}
-
-
-static void inst_free(void)
-{
-	struct inst *next;
-
-	while (insts) {
-		next = insts->next;
-		free(insts);
-		insts = next;
-	}
-	next_inst = &insts;
-}
-
-
-void inst_reset(void)
-{
-	inst_free();
-}
-
-
-void inst_draw(struct draw_ctx *ctx)
-{
-	struct inst *walk;
-
-	for (walk = insts; walk; walk = walk->next)
-		if (walk->ops->draw)
-			walk->ops->draw(walk, ctx);
-}
-
-
-void inst_debug(void)
-{
-	struct inst *walk;
-
-	for (walk = insts; walk; walk = walk->next)
-		walk->ops->debug(walk);
-}

Copied: trunk/eda/fped/inst.c (from rev 5368, developers/werner/fped/inst.c)
===================================================================
--- trunk/eda/fped/inst.c	                        (rev 0)
+++ trunk/eda/fped/inst.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,665 @@
+/*
+ * inst.c - Instance structures
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "util.h"
+#include "coord.h"
+#include "expr.h"
+#include "obj.h"
+#include "gui_status.h"
+#include "gui_inst.h"
+#include "inst.h"
+
+
+struct inst_ops {
+	void (*debug)(struct inst *self);
+	void (*save)(FILE *file, struct inst *self);
+	void (*draw)(struct inst *self, struct draw_ctx *ctx);
+	unit_type (*distance)(struct inst *self, struct coord pos, 
+            unit_type scale);
+	void (*select)(struct inst *self);
+};
+
+enum inst_prio {
+	ip_frame,	/* frames have their own selection */
+	ip_pad,		/* pads also accept clicks inside */
+	ip_circ,	/* circles don't overlap easily */
+	ip_arc,		/* arc are like circles, just shorter */
+	ip_rect,	/* rectangles have plenty of sides */
+	ip_meas,	/* mesurements are like lines but set a bit apart */
+	ip_line,	/* lines are easly overlapped by other things */
+	ip_vec,		/* vectors only have the end point */
+	ip_n,		/* number of priorities */
+};
+
+
+#define FOR_INST_PRIOS_UP(prio)					\
+	for (prio = 0; prio != ip_n; prio++)
+
+#define FOR_INST_PRIOS_DOWN(prio)				\
+	for (prio = ip_n-1; prio != (enum inst_prio) -1; prio--)
+
+#define	FOR_INSTS_UP(prio, inst)				\
+	FOR_INST_PRIOS_UP(prio)					\
+		for (inst = insts[prio]; inst; inst = inst->next)
+
+#define	FOR_INSTS_DOWN(prio, inst)				\
+	FOR_INST_PRIOS_DOWN(prio)				\
+		for (inst = insts[prio]; inst; inst = inst->next)
+
+
+struct inst *curr_frame = NULL;
+struct inst *selected_inst = NULL;
+
+static struct inst *insts[ip_n], **next_inst[ip_n];
+static struct inst *prev_insts[ip_n];
+
+static unsigned long active_set = 0;
+
+
+#define	IS_ACTIVE	((active_set & 1))
+
+
+/* ----- selection of items not on the canvas ------------------------------ */
+
+
+static void *selected_outside = NULL;
+static void (*outside_deselect)(void *item);
+
+
+static void deselect_outside(void)
+{
+	if (selected_outside && outside_deselect)
+		outside_deselect(selected_outside);
+	selected_outside = NULL;
+}
+
+
+void inst_select_outside(void *item, void (*deselect)(void *item))
+{
+	if (item == selected_outside)
+		return;
+	deselect_outside();
+	inst_deselect();
+	selected_outside = item;
+	outside_deselect = deselect;
+}
+
+
+/* ----- selection --------------------------------------------------------- */
+
+
+static struct inst_ops vec_ops;
+static struct inst_ops frame_ops;
+
+
+static void set_path(int on)
+{
+	struct inst *inst;
+return;
+	if (inst->ops != &vec_ops && inst->ops != &frame_ops)
+		return;
+/* @@@ wrong */
+	for (inst = selected_inst; inst; inst = inst->outer) {
+		if (inst->ops != &vec_ops && inst->ops != &frame_ops)
+			break;
+		inst->in_path = on;
+	}
+}
+
+
+int inst_select(const struct draw_ctx *ctx, struct coord pos)
+{
+	enum inst_prio prio;
+	struct inst *inst;
+	int best_dist, dist;
+
+	deselect_outside();
+	edit_nothing();
+	selected_inst = NULL;
+	FOR_INST_PRIOS_DOWN(prio) {
+		for (inst = insts[prio]; inst; inst = inst->next) {
+			if (!inst->active || !inst->ops->distance)
+				continue;
+			dist = inst->ops->distance(inst, pos, ctx->scale);
+			if (dist >= 0 && (!selected_inst || best_dist > dist)) {
+				selected_inst = inst;
+				best_dist = dist;
+			}
+		}
+		if (selected_inst)
+			goto selected;
+	}
+
+	/* give vectors a second chance */
+
+	for (inst = insts[ip_vec]; inst; inst = inst->next) {
+		if (!inst->active)
+			continue;
+		dist = gui_dist_vec_fallback(inst, pos, ctx->scale);
+		if (dist >= 0 && (!selected_inst || best_dist > dist)) {
+			selected_inst = inst;
+			best_dist = dist;
+		}
+	}
+	
+	if (!selected_inst)
+		return 0;
+
+selected:
+	set_path(1);
+	if (selected_inst->ops->select)
+		selected_inst->ops->select(selected_inst);
+	return 1;
+}
+
+
+void inst_deselect(void)
+{
+	if (selected_inst)
+		set_path(0);
+	deselect_outside();
+	status_set_name("");
+	status_set_x("");
+	status_set_y("");
+	status_set_r("");
+	status_set_angle("");
+	selected_inst = NULL;
+	edit_nothing();
+}
+
+
+static void rect_status(struct coord a, struct coord b, unit_type width)
+{
+	struct coord d = sub_vec(b, a);
+	double angle;
+	
+	status_set_xy(d);
+	if (!d.x && !d.y)
+		status_set_angle("a = 0 deg");
+	else {
+		angle = atan2(d.y, d.x)/M_PI*180.0;
+		if (angle < 0)
+			angle += 360;
+		status_set_angle("a = %3.1f deg", angle);
+	}
+	status_set_r("r = %5.2f mm", hypot(units_to_mm(d.x), units_to_mm(d.y)));
+	if (width != -1)
+		status_set_name("width = %5.2f mm", units_to_mm(width));
+}
+
+
+/* ----- helper functions for instance creation ---------------------------- */
+
+
+static void update_bbox(struct bbox *bbox, struct coord coord)
+{
+	if (bbox->min.x > coord.x)
+		bbox->min.x = coord.x;
+	if (bbox->max.x < coord.x)
+		bbox->max.x = coord.x;
+	if (bbox->min.y > coord.y)
+		bbox->min.y = coord.y;
+	if (bbox->max.y < coord.y)
+		bbox->max.y = coord.y;
+}
+
+
+static void propagate_bbox(const struct inst *inst)
+{
+	update_bbox(&curr_frame->bbox, inst->bbox.min);
+	update_bbox(&curr_frame->bbox, inst->bbox.max);
+}
+
+static struct inst *add_inst(const struct inst_ops *ops, enum inst_prio prio,
+    struct coord base)
+{
+	struct inst *inst;
+
+	inst = alloc_type(struct inst);
+	inst->ops = ops;
+	inst->base = inst->bbox.min = inst->bbox.max = base;
+	inst->outer = curr_frame;
+	inst->active = IS_ACTIVE;
+	inst->in_path = 0;
+	inst->next = NULL;
+	*next_inst[prio] = inst;
+	next_inst[prio] = &inst->next;
+	return inst;
+}
+
+
+/* ----- vec --------------------------------------------------------------- */
+
+
+static void vec_op_debug(struct inst *self)
+{
+	printf("vec %lg, %lg -> %lg, %lg\n",
+	    units_to_mm(self->base.x), units_to_mm(self->base.y),
+	    units_to_mm(self->u.rect.end.x), units_to_mm(self->u.rect.end.y));
+}
+
+
+static int validate_vec_name(const char *s, void *ctx)
+{
+	struct vec *vec = ctx;
+	const struct vec *walk;
+
+	if (!is_id(s))
+		return 0;
+	for (walk = vec->frame->vecs; walk; walk = walk->next)
+		if (walk->name && !strcmp(walk->name, s))
+			return 0;
+	return 1;
+}
+
+
+static void vec_op_select(struct inst *self)
+{
+	status_set_name(self->vec->name ? self->vec->name : "");
+	rect_status(self->base, self->u.rect.end, -1);
+	edit_unique_null(&self->vec->name, validate_vec_name, self->vec);
+}
+
+
+static struct inst_ops vec_ops = {
+	.debug		= vec_op_debug,
+	.draw		= gui_draw_vec,
+	.distance	= gui_dist_vec,
+	.select		= vec_op_select,
+};
+
+
+int inst_vec(struct vec *vec, struct coord base)
+{
+	struct inst *inst;
+
+	inst = add_inst(&vec_ops, ip_vec, base);
+	inst->vec = vec;
+	inst->u.rect.end = vec->pos;
+	update_bbox(&inst->bbox, vec->pos);
+	propagate_bbox(inst);
+	return 1;
+}
+
+
+/* ----- line -------------------------------------------------------------- */
+
+
+static void line_op_debug(struct inst *self)
+{
+	printf("line %lg, %lg / %lg, %lg\n",
+	    units_to_mm(self->base.x), units_to_mm(self->base.y),
+	    units_to_mm(self->u.rect.end.x), units_to_mm(self->u.rect.end.y));
+}
+
+
+static void line_op_select(struct inst *self)
+{
+	rect_status(self->bbox.min, self->bbox.max, self->u.rect.width);
+	edit_expr(&self->obj->u.line.width);
+}
+
+
+static struct inst_ops line_ops = {
+	.debug		= line_op_debug,
+	.draw		= gui_draw_line,
+	.distance	= gui_dist_line,
+	.select		= line_op_select,
+};
+
+
+int inst_line(struct obj *obj, struct coord a, struct coord b, unit_type width)
+{
+	struct inst *inst;
+
+	inst = add_inst(&line_ops, ip_line, a);
+	inst->obj = obj;
+	inst->u.rect.end = b;
+	inst->u.rect.width = width;
+	update_bbox(&inst->bbox, b);
+	propagate_bbox(inst);
+	return 1;
+}
+
+
+/* ----- rect -------------------------------------------------------------- */
+
+
+static void rect_op_debug(struct inst *self)
+{
+	printf("rect %lg, %lg / %lg, %lg\n",
+	    units_to_mm(self->base.x), units_to_mm(self->base.y),
+	    units_to_mm(self->u.rect.end.x), units_to_mm(self->u.rect.end.y));
+}
+
+
+static void rect_op_select(struct inst *self)
+{
+	rect_status(self->bbox.min, self->bbox.max, self->u.rect.width);
+	edit_expr(&self->obj->u.rect.width);
+}
+
+
+static struct inst_ops rect_ops = {
+	.debug		= rect_op_debug,
+	.draw		= gui_draw_rect,
+	.distance	= gui_dist_rect,
+	.select		= rect_op_select,
+};
+
+
+int inst_rect(struct obj *obj, struct coord a, struct coord b, unit_type width)
+{
+	struct inst *inst;
+
+	inst = add_inst(&rect_ops, ip_rect, a);
+	inst->obj = obj;
+	inst->u.rect.end = b;
+	inst->u.rect.width = width;
+	update_bbox(&inst->bbox, b);
+	propagate_bbox(inst);
+	return 1;
+}
+
+
+/* ----- pad --------------------------------------------------------------- */
+
+
+static void pad_op_debug(struct inst *self)
+{
+	printf("pad \"%s\" %lg, %lg / %lg, %lg\n", self->u.name,
+	    units_to_mm(self->bbox.min.x), units_to_mm(self->bbox.min.y),
+	    units_to_mm(self->bbox.max.x), units_to_mm(self->bbox.max.y));
+}
+
+
+static int validate_pad_name(const char *s, void *ctx)
+{
+	char *tmp;
+
+	tmp = expand(s, NULL);
+	if (!tmp)
+		return 0;
+	free(tmp);
+	return 1;
+}
+
+
+static void pad_op_select(struct inst *self)
+{
+	status_set_name(self->u.name);
+	rect_status(self->bbox.min, self->bbox.max, -1);
+	edit_name(&self->obj->u.pad.name, validate_pad_name, NULL);
+}
+
+
+static struct inst_ops pad_ops = {
+	.debug		= pad_op_debug,
+	.draw		= gui_draw_pad,
+	.distance	= gui_dist_pad,
+	.select		= pad_op_select,
+};
+
+
+int inst_pad(struct obj *obj, const char *name, struct coord a, struct coord b)
+{
+	struct inst *inst;
+
+	inst = add_inst(&pad_ops, ip_pad, a);
+	inst->obj = obj;
+	inst->u.name = stralloc(name);
+	update_bbox(&inst->bbox, b);
+	propagate_bbox(inst);
+	return 1;
+}
+
+
+/* ----- arc --------------------------------------------------------------- */
+
+
+static void arc_op_debug(struct inst *self)
+{
+	printf("arc %lg, %lg radius %lg %lg ... %lg\n",
+	    units_to_mm(self->base.x), units_to_mm(self->base.y),
+	    units_to_mm(self->u.arc.r), self->u.arc.a1, self->u.arc.a2);
+}
+
+
+static void arc_op_select(struct inst *self)
+{
+	status_set_xy(self->base);
+	status_set_angle("a = %3.1f deg",
+	    self->u.arc.a1 == self->u.arc.a2 ? 360 :
+	    self->u.arc.a2-self->u.arc.a1);
+	status_set_r("r = %5.2f mm", units_to_mm(self->u.arc.r));
+	status_set_name("width = %5.2f mm", units_to_mm(self->u.arc.width));
+	edit_expr(&self->obj->u.arc.width);
+}
+
+
+static struct inst_ops arc_ops = {
+	.debug		= arc_op_debug,
+	.draw		= gui_draw_arc,
+	.distance	= gui_dist_arc,
+	.select		= arc_op_select,
+};
+
+
+int inst_arc(struct obj *obj, struct coord center, struct coord start,
+    struct coord end, unit_type width)
+{
+	struct inst *inst;
+	double r, a1, a2;
+
+	inst = add_inst(&arc_ops, ip_arc, center);
+	inst->obj = obj;
+	r = hypot(start.x-center.x, start.y-center.y);
+	a1 = atan2(start.y-center.y, start.x-center.x)/M_PI*180.0;
+	a2 = atan2(end.y-center.y, end.x-center.x)/M_PI*180.0;
+	if (a1 < 0)
+		a1 += 360.0;
+	if (a2 < 0)
+		a2 += 360.0;
+	inst->u.arc.r = r;
+	inst->u.arc.a1 = a1;
+	inst->u.arc.a2 = a2;
+	inst->u.arc.width = width;
+	inst->bbox.min.x = center.x-r;
+	inst->bbox.max.x = center.x+r;
+	inst->bbox.min.y = center.x-r;
+	inst->bbox.max.y = center.x+r;
+	propagate_bbox(inst);
+	return 1;
+}
+
+
+/* ----- measurement ------------------------------------------------------- */
+
+
+static void meas_op_debug(struct inst *self)
+{
+	printf("meas %lg, %lg / %lg, %lg offset %lg\n",
+	    units_to_mm(self->base.x), units_to_mm(self->base.y),
+	    units_to_mm(self->u.meas.end.x), units_to_mm(self->u.meas.end.y),
+	    units_to_mm(self->u.meas.offset));
+}
+
+
+static void meas_op_select(struct inst *self)
+{
+	rect_status(self->bbox.min, self->bbox.max, -1);
+	status_set_name("offset = %5.2f mm", units_to_mm(self->u.meas.offset));
+	edit_expr(&self->obj->u.meas.offset);
+}
+
+
+static struct inst_ops meas_ops = {
+	.debug		= meas_op_debug,
+	.draw		= gui_draw_meas,
+	.distance	= gui_dist_meas,
+	.select		= meas_op_select,
+};
+
+
+int inst_meas(struct obj *obj, struct coord from, struct coord to,
+    unit_type offset)
+{
+	struct inst *inst;
+
+	inst = add_inst(&meas_ops, ip_meas, from);
+	inst->obj = obj;
+	inst->u.meas.end = to;
+	inst->u.meas.offset = offset;
+	/* @@@ our bbox is actually a bit more complex than this */
+	update_bbox(&inst->bbox, to);
+	propagate_bbox(inst);
+	return 1;
+}
+
+
+/* ----- active instance --------------------------------------------------- */
+
+
+void inst_begin_active(int active)
+{
+	active_set = (active_set << 1) | active;
+}
+
+
+void inst_end_active(void)
+{
+	active_set >>= 1;
+}
+
+
+/* ----- frame ------------------------------------------------------------- */
+
+
+static void frame_op_debug(struct inst *self)
+{
+	printf("frame %s @ %lg, %lg\n",
+	    self->u.frame.ref->name ? self->u.frame.ref->name : "(root)",
+	    units_to_mm(self->base.x), units_to_mm(self->base.y));
+}
+
+
+static struct inst_ops frame_ops = {
+	.debug	= frame_op_debug,
+	.draw	= gui_draw_frame,
+};
+
+
+void inst_begin_frame(const struct frame *frame, struct coord base, int active)
+{
+	struct inst *inst;
+
+	inst = add_inst(&frame_ops, ip_frame, base);
+	inst->u.frame.ref = frame;
+	inst->active = active;
+	curr_frame = inst;
+}
+
+
+void inst_end_frame(const struct frame *frame)
+{
+	struct inst *inst = curr_frame;
+
+	curr_frame = curr_frame->outer;
+	if (curr_frame)
+		propagate_bbox(inst);
+}
+
+
+/* ----- misc. ------------------------------------------------------------- */
+
+
+struct bbox inst_get_bbox(void)
+{
+	return insts[ip_frame]->bbox;
+}
+
+
+static void inst_free(struct inst *list[ip_n])
+{
+	enum inst_prio prio;
+	struct inst *next;
+
+	FOR_INST_PRIOS_UP(prio)
+		while (list[prio]) {
+			next = list[prio]->next;
+			free(list[prio]);
+			list[prio] = next;
+		}
+}
+
+
+void inst_start(void)
+{
+	enum inst_prio prio;
+
+	FOR_INST_PRIOS_UP(prio) {
+		prev_insts[prio] = insts[prio];
+		insts[prio] = NULL;
+		next_inst[prio] = &insts[prio];
+	}
+}
+
+
+void inst_commit(void)
+{
+	inst_free(prev_insts);
+}
+
+
+void inst_revert(void)
+{
+	enum inst_prio prio;
+
+	inst_free(insts);
+	FOR_INST_PRIOS_UP(prio)
+		insts[prio] = prev_insts[prio];
+}
+
+
+void inst_draw(struct draw_ctx *ctx)
+{
+	enum inst_prio prio;
+	struct inst *inst;
+
+	FOR_INSTS_UP(prio, inst)
+		if (!inst->active && inst->ops->draw)
+			inst->ops->draw(inst, ctx);
+	FOR_INSTS_UP(prio, inst)
+		if (prio != ip_frame && inst->active &&
+		    inst != selected_inst && inst->ops->draw)
+			inst->ops->draw(inst, ctx);
+	for (inst = insts[ip_frame]; inst; inst = inst->next)
+		if (inst->active && inst != selected_inst && inst->ops->draw)
+			inst->ops->draw(inst, ctx);
+	if (selected_inst && selected_inst->ops->draw)
+		selected_inst->ops->draw(selected_inst, ctx);
+}
+
+
+void inst_debug(void)
+{
+	enum inst_prio prio;
+	struct inst *inst;
+
+	FOR_INSTS_UP(prio, inst)
+		inst->ops->debug(inst);
+}

Deleted: trunk/eda/fped/inst.h
===================================================================
--- developers/werner/fped/inst.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/inst.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,69 +0,0 @@
-/*
- * inst.h - Instance structures
- *
- * 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 INST_H
-#define INST_H
-
-#include <stdio.h>
-
-#include "coord.h"
-#include "obj.h"
-
-
-struct bbox {
-	struct coord min;
-	struct coord max;
-};
-
-struct inst;
-struct draw_ctx;
-
-struct inst_ops {
-	void (*debug)(struct inst *self);
-	void (*save)(FILE *file, struct inst *self);
-	void (*draw)(struct inst *self, struct draw_ctx *ctx);
-};
-
-struct inst {
-	const struct inst_ops *ops;
-	struct coord base;
-	struct bbox bbox;
-	union {
-		struct {
-			const struct frame *ref;
-			struct inst *outer;
-		} frame;
-		const char *name;
-		struct coord end;
-		struct {
-			unit_type r;
-			double a1, a2;
-		} arc;
-	} u;
-	struct inst *next;
-};
-
-
-int inst_vec(struct vec *vec, struct coord base);
-int inst_line(struct coord a, struct coord b);
-int inst_rect(struct coord a, struct coord b);
-int inst_pad(const char *name, struct coord a, struct coord b);
-int inst_arc(struct coord center, struct coord start, struct coord stop);
-void inst_begin_frame(const struct frame *frame, struct coord base); 
-void inst_end_frame(const struct frame *frame);
-struct bbox inst_get_bbox(void);
-void inst_reset(void);
-void inst_draw(struct draw_ctx *ctx);
-void inst_debug(void);
-
-#endif /* !INST_H */

Copied: trunk/eda/fped/inst.h (from rev 5367, developers/werner/fped/inst.h)
===================================================================
--- trunk/eda/fped/inst.h	                        (rev 0)
+++ trunk/eda/fped/inst.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,104 @@
+/*
+ * inst.h - Instance structures
+ *
+ * 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 INST_H
+#define INST_H
+
+#include <stdio.h>
+
+#include "coord.h"
+#include "obj.h"
+
+
+enum mode {
+	mode_inactive,		/* on inactive frame */
+	mode_inactive_in_path,	/* inactive but is in path to selected */
+	mode_active,		/* on active frame */
+	mode_active_in_path,	/* active and is in path to selected */
+	mode_selected,		/* item is selected */
+	mode_n			/* number of modes */
+};
+
+struct bbox {
+	struct coord min;
+	struct coord max;
+};
+
+struct inst_ops;
+struct draw_ctx;
+
+struct inst {
+	const struct inst_ops *ops;
+	struct coord base;
+//	struct inst *base_inst; /* frame or vector leading to this item */
+	struct bbox bbox;
+	struct vec *vec; /* undefined if not vector */
+	struct obj *obj; /* undefined if not object */
+	struct inst *outer; /* frame containing this item */
+	int active;
+	int in_path;
+	union {
+		struct {
+			const struct frame *ref;
+		} frame;
+		const char *name;
+		struct {
+			struct coord end;
+			unit_type width;
+		} rect;
+		struct {
+			unit_type r;
+			double a1, a2;
+			unit_type width;
+		} arc;
+		struct {
+			struct coord end;
+			double offset;
+		} meas;
+	} u;
+	struct inst *next;
+};
+
+
+extern struct inst *selected_inst;
+
+
+void inst_select_outside(void *item, void (*deselect)(void *item));
+int inst_select(const struct draw_ctx *ctx, struct coord pos);
+void inst_deselect(void);
+
+int inst_vec(struct vec *vec, struct coord base);
+int inst_line(struct obj *obj, struct coord a, struct coord b, unit_type width);
+int inst_rect(struct obj *obj, struct coord a, struct coord b, unit_type width);
+int inst_pad(struct obj *obj, const char *name, struct coord a, struct coord b);
+int inst_arc(struct obj *obj, struct coord center, struct coord start,
+    struct coord stop, unit_type width);
+int inst_meas(struct obj *obj, struct coord from, struct coord to,
+    unit_type offset);
+
+void inst_begin_active(int active);
+void inst_end_active(void);
+
+void inst_begin_frame(const struct frame *frame, struct coord base, int active);
+void inst_end_frame(const struct frame *frame);
+
+struct bbox inst_get_bbox(void);
+
+void inst_start(void);
+void inst_commit(void);
+void inst_revert(void);
+
+void inst_draw(struct draw_ctx *ctx);
+void inst_debug(void);
+
+#endif /* !INST_H */

Deleted: trunk/eda/fped/obj.c
===================================================================
--- developers/werner/fped/obj.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/obj.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,223 +0,0 @@
-/*
- * obj.c - Object definition model
- *
- * 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 <stdlib.h>
-#include <string.h>
-
-#include "util.h"
-#include "error.h"
-#include "expr.h"
-#include "obj.h"
-#include "inst.h"
-
-
-struct frame *frames = NULL;
-
-
-static int generate_frame(struct frame *frame, struct coord base,
-    const struct frame *parent);
-
-
-static int is_id(char c, int first)
-{
-	if ((c >= 'A' && c <= 'Z') ||
-	    (c >= 'a' && c <= 'z') ||
-	    c == '_')
-		return 1;
-	if (first)
-		return 0;
-	return c >= '0' && c <= '9';
-}
-
-
-static char *expand(const char *name, const struct frame *frame)
-{
-	int len = strlen(name);
-	char *buf = alloc_size(len+1);
-	char num_buf[100]; /* enough :-) */
-	const char *s, *s0;
-	char *var;
-	const char *var_unique;
-	double value;
-	int i, value_len;
-
-	i = 0;
-	for (s = name; *s; s++) {
-		if (*s != '$') {
-			buf[i++] = *s;
-			continue;
-		}
-		s0 = ++s;
-		if (*s != '{') {
-			while (is_id(*s, s == s0))
-				s++;
-			var = strnalloc(s0, s-s0);
-			len -= s-s0+1;
-			s--;
-		} else {
-			s++;
-			while (*s != '}') {
-				if (!is_id(*s, s == s0+1))
-					goto invalid;
-				s++;
-			}
-			var = strnalloc(s0+1, s-s0-1);
-			len -= s-s0+2;
-		}
-		var_unique = unique(var);
-		free(var);
-		value = eval_var(frame, var_unique);
-		if (value == UNDEF) {
-			fail("undefined variable \"%s\"", var_unique);
-			goto fail;
-		}
-		value_len = snprintf(num_buf, sizeof(num_buf), "%lg", value);
-		len += value_len;
-		buf = realloc(buf, len);
-		if (!buf)
-			abort();
-		strcpy(buf+i, num_buf);
-		i += value_len;
-	}
-	buf[i] = 0;
-	return buf;
-
-invalid:
-	fail("invalid character in variable name");
-fail:
-	free(buf);
-	return NULL;
-}
-
-
-static int generate_objects(struct frame *frame, struct coord base)
-{
-	struct coord vec_base;
-	struct vec *vec;
-	struct obj *obj;
-	double x, y;
-	char *name;
-	int res;
-
-	for (vec = frame->vecs; vec; vec = vec->next) {
-		x = eval_num(vec->x, frame);
-		if (x == UNDEF)
-			return 0;
-		y = eval_num(vec->y, frame);
-		if (y == UNDEF)
-			return 0;
-		vec_base = vec->base ? vec->base->pos : base;
-		vec->pos = vec_base;
-		vec->pos.x += x;
-		vec->pos.y += y;
-		if (!inst_vec(vec, vec_base))
-			return 0;
-	}
-	for (obj = frame->objs; obj; obj = obj->next)
-		switch (obj->type) {
-		case ot_frame:
-			if (!generate_frame(obj->u.frame,
-			    obj->base ? obj->base->pos : base, frame))
-				return 0;
-			break;
-		case ot_line:
-			if (!inst_line(obj->base ? obj->base->pos : base,
-			    obj->u.line.other ? obj->u.line.other->pos : base))
-				return 0;
-			break;
-		case ot_rect:
-			if (!inst_rect(obj->base ? obj->base->pos : base,
-			    obj->u.rect.other ? obj->u.rect.other->pos : base))
-				return 0;
-			break;
-		case ot_pad:
-			name = expand(obj->u.pad.name, frame);
-			if (!name)
-				return 0;
-			res = inst_pad(name,
-			    obj->base ? obj->base->pos : base,
-			    obj->u.pad.other ? obj->u.pad.other->pos : base);
-			free(name);
-			if (!res)
-				return 0;
-			break;
-		case ot_arc:
-			if (!inst_arc(obj->base ? obj->base->pos : base,
-			    obj->u.arc.start ? obj->u.arc.start->pos : base,
-			    obj->u.arc.end ? obj->u.arc.end->pos : base))
-				return 0;
-			break;
-		default:
-			abort();
-		}
-	return 1;
-}
-
-
-static int run_loops(struct frame *frame, struct loop *loop,
-    struct coord base)
-{
-	double from, to;
-
-	if (!loop)
-		return generate_objects(frame, base);
-	from = eval_num(loop->from, frame);
-	if (from == UNDEF)
-		return 0;
-	to = eval_num(loop->to, frame);
-	if (from == UNDEF)
-		return 0;
-	for (loop->curr_value = from; loop->curr_value <= to;
-	    loop->curr_value += 1)
-		if (!run_loops(frame, loop->next, base))
-			return 0;
-	return 1;
-}
-
-
-static int iterate_tables(struct frame *frame, struct table *table,
-    struct coord base)
-{
-	if (!table)
-		return run_loops(frame, frame->loops, base);
-	for (table->curr_row = table->rows; table->curr_row;
-	    table->curr_row = table->curr_row->next)
-		if (!iterate_tables(frame, table->next, base))
-			return 0;
-	return 1;
-}
-
-
-static int generate_frame(struct frame *frame, struct coord base,
-    const struct frame *parent)
-{
-	int res;
-
-	/*
-	 * We ensure during construction that frames can never recurse.
-	 */
-	inst_begin_frame(frame, base);
-	frame->curr_parent = parent;
-	res = iterate_tables(frame, frame->tables, base);
-	inst_end_frame(frame);
-	return res;
-}
-
-
-void instantiate(void)
-{
-	struct coord zero = { 0, 0 };
-
-	inst_reset();
-	generate_frame(frames, zero, NULL);
-}

Copied: trunk/eda/fped/obj.c (from rev 5373, developers/werner/fped/obj.c)
===================================================================
--- trunk/eda/fped/obj.c	                        (rev 0)
+++ trunk/eda/fped/obj.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,270 @@
+/*
+ * obj.c - Object definition model
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+#include "error.h"
+#include "expr.h"
+#include "inst.h"
+#include "obj.h"
+
+
+#define	DEFAULT_SILK_WIDTH	make_mil(15)	/* @@@ */
+
+#define	MAX_ITERATIONS	1000	/* abort "loop"s at this limit */
+
+
+struct frame *frames = NULL;
+struct frame *root_frame = NULL;
+struct frame *active_frame = NULL;
+
+
+static int generate_frame(struct frame *frame, struct coord base,
+    const struct frame *parent, int active);
+
+
+static struct num eval_unit(const struct expr *expr, const struct frame *frame)
+{
+	struct num d;
+
+	d = eval_num(expr, frame);
+	if (!is_undef(d) && to_unit(&d))
+		return d;
+	fail_expr(expr);
+	return undef;
+}
+
+
+static struct num eval_unit_default(const struct expr *expr,
+    const struct frame *frame, struct num def)
+{
+	if (expr)
+		return eval_unit(expr, frame);
+	to_unit(&def);
+	return def;
+}
+
+
+static int generate_vecs(struct frame *frame, struct coord base)
+{
+	struct coord vec_base;
+	struct vec *vec;
+	struct num x, y;
+
+	for (vec = frame->vecs; vec; vec = vec->next) {
+		x = eval_unit(vec->x, frame);
+		if (is_undef(x))
+			return 0;
+		y = eval_unit(vec->y, frame);
+		if (is_undef(y))
+			return 0;
+		vec_base = vec->base ? vec->base->pos : base;
+		vec->pos = vec_base;
+		vec->pos.x += x.n;
+		vec->pos.y += y.n;
+		if (!inst_vec(vec, vec_base))
+			return 0;
+	}
+	return 1;
+}
+
+
+static int generate_objs(struct frame *frame, struct coord base, int active)
+{
+	struct obj *obj;
+	char *name;
+	int ok;
+	struct num width, offset;
+
+	for (obj = frame->objs; obj; obj = obj->next)
+		switch (obj->type) {
+		case ot_frame:
+			if (!generate_frame(obj->u.frame,
+			    obj->base ? obj->base->pos : base, frame, active))
+				return 0;
+			break;
+		case ot_line:
+			width = eval_unit_default(obj->u.line.width, frame,
+			    DEFAULT_SILK_WIDTH);
+			if (is_undef(width))
+				return 0;
+			if (!inst_line(obj, obj->base ? obj->base->pos : base,
+			    obj->u.line.other ? obj->u.line.other->pos : base,
+			    width.n))
+				return 0;
+			break;
+		case ot_rect:
+			width = eval_unit_default(obj->u.rect.width, frame,
+			    DEFAULT_SILK_WIDTH);
+			if (is_undef(width))
+				return 0;
+			if (!inst_rect(obj, obj->base ? obj->base->pos : base,
+			    obj->u.rect.other ? obj->u.rect.other->pos : base,
+			    width.n))
+				return 0;
+			break;
+		case ot_pad:
+			name = expand(obj->u.pad.name, frame);
+			if (!name)
+				return 0;
+			ok = inst_pad(obj, name,
+			    obj->base ? obj->base->pos : base,
+			    obj->u.pad.other ? obj->u.pad.other->pos : base);
+			free(name);
+			if (!ok)
+				return 0;
+			break;
+		case ot_arc:
+			width = eval_unit_default(obj->u.arc.width, frame,
+			    DEFAULT_SILK_WIDTH);
+			if (is_undef(width))
+				return 0;
+			if (!inst_arc(obj, obj->base ? obj->base->pos : base,
+			    obj->u.arc.start ? obj->u.arc.start->pos : base,
+			    obj->u.arc.end ? obj->u.arc.end->pos : base,
+			    width.n))
+				return 0;
+			break;
+		case ot_meas:
+			offset = eval_unit(obj->u.meas.offset, frame);
+			if (is_undef(offset))
+				return 0;
+			if (!inst_meas(obj, obj->base ? obj->base->pos : base,
+			    obj->u.meas.other ? obj->u.meas.other->pos : base,
+			    offset.n))
+				return 0;
+			break;
+		default:
+			abort();
+		}
+	return 1;
+}
+
+
+static int generate_items(struct frame *frame, struct coord base, int active)
+{
+	int ok;
+
+	inst_begin_active(active && frame == active_frame);
+	ok = generate_vecs(frame, base) && generate_objs(frame, base, active);
+	inst_end_active();
+	return ok;
+}
+
+
+static int run_loops(struct frame *frame, struct loop *loop,
+    struct coord base, int active)
+{
+	struct num from, to;
+	int n;
+
+	if (!loop)
+		return generate_items(frame, base, active);
+	from = eval_num(loop->from.expr, frame);
+	if (is_undef(from)) {
+		fail_expr(loop->from.expr);
+		return 0;
+	}
+	if (!is_dimensionless(from)) {
+		fail("incompatible type for start value");
+		fail_expr(loop->from.expr);
+		return 0;
+	}
+
+	to = eval_num(loop->to.expr, frame);
+	if (is_undef(to)) {
+		fail_expr(loop->to.expr);
+		return 0;
+	}
+	if (!is_dimensionless(to)) {
+		fail("incompatible type for end value");
+		fail_expr(loop->to.expr);
+		return 0;
+	}
+
+	assert(!loop->initialized);
+	loop->curr_value = from.n;
+	loop->initialized = 1;
+
+	n = 0;
+	for (; loop->curr_value <= to.n; loop->curr_value += 1) {
+		if (n >= MAX_ITERATIONS) {
+			fail("%s: too many iterations (%d)", loop->var.name,
+			    MAX_ITERATIONS);
+			goto fail;
+		}
+		if (!run_loops(frame, loop->next, base,
+		    active && loop->active == n))
+			goto fail;
+		n++;
+	}
+	loop->initialized = 0;
+	return 1;
+
+fail:
+	loop->initialized = 0;
+	return 0;
+}
+
+
+static int iterate_tables(struct frame *frame, struct table *table,
+    struct coord base, int active)
+{
+	int n;
+
+	if (!table)
+		return run_loops(frame, frame->loops, base, active);
+	n = 0;
+	for (table->curr_row = table->rows; table->curr_row;
+	    table->curr_row = table->curr_row->next) {
+		if (!iterate_tables(frame, table->next, base,
+		    active && table->active == n))
+			return 0;
+		n++;
+	}
+	return 1;
+}
+
+
+static int generate_frame(struct frame *frame, struct coord base,
+    const struct frame *parent, int active)
+{
+	int ok;
+
+	/*
+	 * We ensure during construction that frames can never recurse.
+	 */
+	inst_begin_frame(frame, base, active && frame == active_frame);
+	frame->curr_parent = parent;
+	ok = iterate_tables(frame, frame->tables, base, active);
+	inst_end_frame(frame);
+	return ok;
+}
+
+
+int instantiate(void)
+{
+	struct coord zero = { 0, 0 };
+	int ok;
+
+	inst_start();
+	ok = generate_frame(root_frame, zero, NULL, 1);
+	if (ok)
+		inst_commit();
+	else
+		inst_revert();
+	return ok;
+}

Deleted: trunk/eda/fped/obj.h
===================================================================
--- developers/werner/fped/obj.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/obj.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,120 +0,0 @@
-/*
- * obj.h - Object definition model
- *
- * 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 OBJ_H
-#define OBJ_H
-
-#include "expr.h"
-#include "coord.h"
-
-
-struct var {
-	const char *name;
-	struct var *next;
-};
-
-struct value {
-	struct expr *expr;
-	struct value *next;
-};
-
-struct row {
-	struct value *values;
-	struct row *next;
-};
-
-struct table {
-	struct var *vars;
-	struct row *rows;
-	struct table *next;
-
-	/* used during generation and when editing */
-	struct row *curr_row;
-};
-
-struct loop {
-	const char *var;
-	struct expr *from;
-	struct expr *to;
-	struct loop *next;
-
-	/* used during generation */
-	double curr_value;
-};
-
-struct vec {
-	const char *name; /* NULL if anonymous */
-	struct expr *x;
-	struct expr *y;
-	struct vec *base; /* NULL if frame */
-	int n_refs;
-	struct vec *next;
-
-	/* used during generation */
-	struct coord pos;
-};
-
-struct frame {
-	const char *name; /* NULL if top-level */
-	struct table *tables;
-	struct loop *loops;
-	struct vec *vecs;
-	struct obj *objs;
-	struct frame *next;
-
-	/* used during generation */
-	const struct frame *curr_parent;
-};
-
-enum obj_type {
-	ot_frame,
-	ot_rect,
-	ot_pad,
-	ot_line,
-	ot_arc,
-};
-
-struct rect {
-	struct vec *other; /* NULL if frame origin */
-};
-
-struct pad {
-	const char *name;
-	struct vec *other; /* NULL if frame origin */
-};
-
-struct arc {
-	struct vec *start; /* NULL if frame origin */
-	struct vec *end; /* NULL if this is a circle */
-};
-
-struct obj {
-	enum obj_type type;
-	union {
-		struct frame *frame;
-		struct rect rect;
-		struct rect line;
-		struct pad pad;
-		struct arc arc;
-	} u;
-	struct vec *base;
-	struct obj *next;
-};
-
-
-struct frame *frames;
-
-
-void instantiate(void);
-
-#endif /* !OBJ_H */

Copied: trunk/eda/fped/obj.h (from rev 5373, developers/werner/fped/obj.h)
===================================================================
--- trunk/eda/fped/obj.h	                        (rev 0)
+++ trunk/eda/fped/obj.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,167 @@
+/*
+ * obj.h - Object definition model
+ *
+ * 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 OBJ_H
+#define OBJ_H
+
+#include <gtk/gtk.h>
+
+#include "expr.h"
+#include "coord.h"
+
+
+struct var {
+	const char *name;
+	struct var *next;
+
+	/* back reference */
+	struct frame *frame;
+
+	/* for the GUI */
+	GtkWidget *widget;
+
+	/* for evaluation */
+	int visited;
+};
+
+struct value {
+	struct expr *expr;
+	struct value *next;
+
+	/* back reference */
+	struct row *row;
+
+	/* for the GUI */
+	GtkWidget *widget;
+};
+
+struct row {
+	struct value *values;
+	struct row *next;
+
+	/* back reference */
+	struct table *table;
+};
+
+struct table {
+	struct var *vars;
+	struct row *rows;
+	struct table *next;
+
+	/* used during generation and when editing */
+	struct row *curr_row;
+
+	/* GUI use */
+	int active;	/* n-th row is active, 0 based */
+};
+
+struct loop {
+	struct var var;
+	struct value from;
+	struct value to;
+	struct loop *next;
+
+	/* used during generation */
+	double curr_value;
+
+	/* GUI use */
+	int active;	/* n-th iteration is active, 0 based */
+
+	/* for evaluation */
+	int initialized;
+};
+
+struct vec {
+	const char *name; /* NULL if anonymous */
+	struct expr *x;
+	struct expr *y;
+	struct vec *base; /* NULL if frame */
+	int n_refs;
+	struct vec *next;
+
+	/* used during generation */
+	struct coord pos;
+
+	/* used when editing */
+	struct frame *frame;
+};
+
+struct frame {
+	const char *name; /* NULL if top-level */
+	struct table *tables;
+	struct loop *loops;
+	struct vec *vecs;
+	struct obj *objs;
+	struct frame *next;
+	struct frame *prev; /* for the list of frames in the GUI */
+
+	/* used during generation */
+	const struct frame *curr_parent;
+
+	/* for the GUI */
+	GtkWidget *label;
+};
+
+enum obj_type {
+	ot_frame,
+	ot_rect,
+	ot_pad,
+	ot_line,
+	ot_arc,
+	ot_meas,
+};
+
+struct rect {
+	struct vec *other; /* NULL if frame origin */
+	struct expr *width;
+};
+
+struct pad {
+	char *name;
+	struct vec *other; /* NULL if frame origin */
+};
+
+struct arc {
+	struct vec *start; /* NULL if frame origin */
+	struct vec *end; /* NULL if this is a circle */
+	struct expr *width;
+};
+
+struct meas {
+	struct vec *other; /* NULL if frame origin */
+	struct expr *offset;
+};
+
+struct obj {
+	enum obj_type type;
+	union {
+		struct frame *frame;
+		struct rect rect;
+		struct rect line;
+		struct pad pad;
+		struct arc arc;
+		struct meas meas;
+	} u;
+	struct vec *base;
+	struct obj *next;
+};
+
+
+extern struct frame *frames;
+extern struct frame *root_frame;
+extern struct frame *active_frame;
+
+
+int instantiate(void);
+
+#endif /* !OBJ_H */

Deleted: trunk/eda/fped/qfn.fpd
===================================================================
--- developers/werner/fped/qfn.fpd	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/qfn.fpd	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,38 +0,0 @@
-// http://www.nxp.com/acrobat/packages/footprint/SOT616-1_fp_reflow.pdf
-
-.frame pad_up {
-	c = .vec @ -D/2, 0
-	.vec . D, C
-	pad = n+1
-	.pad "$pad" c .
-}
-
-N = 24
-
-.table
-    { P, Ax, Ay, Bx, By, C, D, SLx, SLy, SPx_tot, SPy_tot, SPx, SPy, Gx, Gy, Hx, Hy }
-    { 0.5mm, 5mm, 5mm, 3.2mm, 3.2mm, 0.9mm, 0.24mm, 2.1mm, 2.1mm, 1.2mm,
-      1.2mm, 0.45mm, 0.45mm, 4.3mm, 4.3mm, 5.25mm, 5.25mm }
-
-h_x0y0 = .vec @ -Hx/2, -Hy/2
-h_x1y1 = .vec . Hx, Hy
-.rect h_x0y0 h_x1y1
-
-g_x0y0 = .vec @ -Gx/2, -Gy/2
-g_x1y1 = .vec . Gx, Gy
-.rect g_x0y0 g_x1y1
-
-n = 0, N/4-1
-
-.vec @ P*(n-(N/4-1)/2), -Ay/2
-.frame pad_up .
-
-// ARC, just for testing
-
-c = .vec @ -1mm, 1mm
-r = .vec c 0mm, 0.5mm
-e = .vec c -0.5mm, 0mm
-.arc c r, e
-
-r2 = .vec c 0mm, 0.8mm
-.arc c r2

Copied: trunk/eda/fped/qfn.fpd (from rev 5367, developers/werner/fped/qfn.fpd)
===================================================================
--- trunk/eda/fped/qfn.fpd	                        (rev 0)
+++ trunk/eda/fped/qfn.fpd	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,70 @@
+/*
+ * Example of a QFN package (and general construction site to experiment with
+ * fped features during development)
+ *
+ * Everything you see here is likely to change sooner or later.
+ *
+ * http://www.nxp.com/acrobat/packages/footprint/SOT616-1_fp_reflow.pdf
+ */
+
+frame pad_up {
+	c: vec @(-D/2, 0mm)
+	vec .(0mm, C)
+	meas c . 0.2mm
+	vec c(D, C)
+	set pad = n+1
+	pad "$pad" c .
+}
+
+frame pads {
+	loop n = 0, N/4-1
+
+	vec @(P*(n-(N/4-1)/2), -Ay/2)
+	frame pad_up .
+
+}
+
+
+set N = 24
+
+/*
+ * Note that this table is not a great example because it contains lots of
+ * fields we don't really need for iterations. But it's useful for driving
+ * the GUI to extremes.
+ */
+
+table
+    { P, Ax, Ay, Bx, By, C, D, SLx, SLy, SPx_tot, SPy_tot, SPx, SPy, Gx, Gy, Hx, Hy }
+    { 0.5mm, 5mm, 5mm, 3.2mm, 3.2mm, 0.9mm, 0.24mm, 2.1mm, 2.1mm, 1.2mm,
+      1.2mm, 0.45mm, 0.45mm, 4.3mm, 4.3mm, 5.25mm, 5.25mm }
+
+h_x0y0: vec @(-Hx/2, -Hy/2)
+h_x1y1: vec .(Hx, Hy)
+rect h_x0y0 h_x1y1 8mil
+
+/*
+ * we can't draw the package outline on the silk screen for it would print
+ * over the pads.
+ */
+#if 0
+g_x0y0: vec @(-Gx/2, -Gy/2)
+g_x1y1: vec .(Gx, Gy)
+#endif
+
+frame pads @
+
+// ARC, just for testing
+
+c: vec @(-1mm, 1mm)
+r: vec c(0mm, 0.5mm)
+e: vec c(-0.5mm, 0mm)
+arc c r e 2mil
+
+r2: vec c(0mm, 0.8mm)
+circ c r2 5mil
+
+/*
+x1 = 1+2*3
+x2 = (1+2)*3
+x3 = 1-(2+3)
+*/

Copied: trunk/eda/fped/unparse.c (from rev 5335, developers/werner/fped/unparse.c)
===================================================================
--- trunk/eda/fped/unparse.c	                        (rev 0)
+++ trunk/eda/fped/unparse.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,111 @@
+/*
+ * unparse.c - Dump an expression tree into a string
+ *
+ * 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.
+ */
+
+/*
+ * This is crazily inefficient but who cares :-)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "expr.h"
+#include "unparse.h"
+
+
+enum prec {
+	prec_add,
+	prec_mult,
+	prec_unary,
+	prec_primary,
+};
+
+
+static int precedence(op_type op)
+{
+	if (op == op_add || op == op_sub)
+		return prec_add;
+	if (op == op_mult || op == op_div)
+		return prec_mult;
+	if (op == op_minus)
+		return prec_unary;
+	if (op == op_num || op == op_var)
+		return prec_primary;
+	abort();
+}
+
+
+static char *merge3(char *a, const char *op, char *b)
+{
+	char *buf;
+
+	buf = alloc_size(strlen(op)+strlen(a)+strlen(b)+1);
+	sprintf(buf, "%s%s%s", a, op, b);
+	free(a);
+	free(b);
+	return buf;
+}
+
+
+static char *merge2(const char *op, char *a)
+{
+	char *buf;
+
+	buf = alloc_size(strlen(op)+strlen(a)+1);
+	sprintf(buf, "%s%s", op, a);
+	free(a);
+	return buf;
+}
+
+
+static char *unparse_op(const struct expr *expr, enum prec prec)
+{
+	char tmp[100];
+	char *buf, *temp;
+
+	
+	if (prec > precedence(expr->op)) {
+		temp = unparse_op(expr, prec_add);
+		buf = alloc_size(strlen(temp)+3);
+		sprintf(buf, "(%s)", temp);
+		free(temp);
+		return buf;
+	}
+	if (expr->op == op_num) {
+		snprintf(tmp, sizeof(tmp), "%lg%s",
+		    expr->u.num.n, str_unit(expr->u.num));
+		return stralloc(tmp);
+	}
+	if (expr->op == op_var)
+		return stralloc(expr->u.var);
+	if (expr->op == op_minus)
+		return merge2("-", unparse_op(expr->u.op.a, prec_add));
+	if (expr->op == op_add)
+		return merge3(unparse_op(expr->u.op.a, prec_add), "+",
+		    unparse_op(expr->u.op.b, prec_add));
+	if (expr->op == op_sub)
+		return merge3(unparse_op(expr->u.op.a, prec_add), "-",
+		    unparse_op(expr->u.op.b, prec_mult));
+	if (expr->op == op_mult)
+		return merge3(unparse_op(expr->u.op.a, prec_mult), "*",
+		    unparse_op(expr->u.op.b, prec_mult));
+	if (expr->op == op_div)
+		return merge3(unparse_op(expr->u.op.a, prec_mult), "/",
+		    unparse_op(expr->u.op.b, prec_primary));
+	abort();
+}
+
+
+char *unparse(const struct expr *expr)
+{
+	return expr ? unparse_op(expr, prec_add) : stralloc("");
+}

Copied: trunk/eda/fped/unparse.h (from rev 5335, developers/werner/fped/unparse.h)
===================================================================
--- trunk/eda/fped/unparse.h	                        (rev 0)
+++ trunk/eda/fped/unparse.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,22 @@
+/*
+ * unparse.h - Dump an expression tree into a string
+ *
+ * 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 UNPARSE_H
+#define UNPARSE_H
+
+#include "expr.h"
+
+
+char *unparse(const struct expr *expr);
+
+#endif /* !UNPARSE_H */

Deleted: trunk/eda/fped/util.c
===================================================================
--- developers/werner/fped/util.c	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/util.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,38 +0,0 @@
-/*
- * util.c - Common utility functions
- *
- * 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 <string.h>
-
-#include "util.h"
-
-
-static struct unique {
-	const char *s;
-	struct unique *next;
-} *uniques = NULL;
-
-
-/* @@@ consider using rb trees */
-
-const char *unique(const char *s)
-{
-	struct unique **walk;
-
-	for (walk = &uniques; *walk; walk = &(*walk)->next)
-		if (!strcmp(s, (*walk)->s))
-			return (*walk)->s;
-	*walk = alloc_type(struct unique);
-	(*walk)->s = stralloc(s);
-	(*walk)->next = NULL;
-	return (*walk)->s;
-}

Copied: trunk/eda/fped/util.c (from rev 5361, developers/werner/fped/util.c)
===================================================================
--- trunk/eda/fped/util.c	                        (rev 0)
+++ trunk/eda/fped/util.c	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,100 @@
+/*
+ * util.c - Common utility functions
+ *
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "util.h"
+
+
+
+/* ----- printf buffer allocation ------------------------------------------ */
+
+
+char *stralloc_vprintf(const char *fmt, va_list ap)
+{
+	va_list aq;
+	char *buf;
+	int n;
+
+	va_copy(aq, ap);
+	n = snprintf(NULL, 0, fmt, aq);
+	va_end(aq);
+	buf = alloc_size(n+1);
+	vsnprintf(buf, n+1, fmt, ap);
+	return buf;
+}
+
+
+char *stralloc_printf(const char *fmt, ...)
+{
+	va_list ap;
+	char *s;
+
+	va_start(ap, fmt);
+	s = stralloc_vprintf(fmt, ap);
+	va_end(ap);
+	return s;
+}
+
+
+/* ----- identifier syntax check ------------------------------------------- */
+
+
+int is_id_char(char c, int first) 
+{
+	if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
+		return 1;
+	if (first)
+		return 0;
+	return c >= '0' && c <= '9';
+}
+
+
+int is_id(const char *s)
+{
+	const char *p;
+
+	if (!*s)
+		return 0;
+	for (p = s; *p; p++)
+		if (!is_id_char(*p, s == p))
+			return 0;
+	return 1;
+}
+
+
+/* ----- unique identifiers ------------------------------------------------ */
+
+
+static struct unique {
+	const char *s;
+	struct unique *next;
+} *uniques = NULL;
+
+
+/* @@@ consider using rb trees */
+
+const char *unique(const char *s)
+{
+	struct unique **walk;
+
+	for (walk = &uniques; *walk; walk = &(*walk)->next)
+		if (!strcmp(s, (*walk)->s))
+			return (*walk)->s;
+	*walk = alloc_type(struct unique);
+	(*walk)->s = stralloc(s);
+	(*walk)->next = NULL;
+	return (*walk)->s;
+}

Deleted: trunk/eda/fped/util.h
===================================================================
--- developers/werner/fped/util.h	2009-07-28 21:50:48 UTC (rev 5332)
+++ trunk/eda/fped/util.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -1,50 +0,0 @@
-/*
- * util.h - Common utility functions
- *
- * Written 2006, 2009 by Werner Almesberger
- * Copyright 2006, 2009 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 UTIL_H
-#define UTIL_H
-
-#include <stdlib.h>
-#include <string.h>
-
-
-#define alloc_size(s)					\
-    ({	void *alloc_size_tmp = malloc(s);		\
-	if (!alloc_size_tmp)				\
-		abort();				\
-	alloc_size_tmp; })
-
-#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
-
-#define zalloc_type(t)					\
-    ({	t *zalloc_type_tmp = alloc_type(t);		\
-	memset(zalloc_type_tmp, 0, sizeof(t));		\
-	zalloc_type_tmp; })
-
-#define stralloc(s)					\
-    ({	char *stralloc_tmp = strdup(s);			\
-	if (!stralloc_tmp)				\
-		abort();				\
-	stralloc_tmp; })
-
-#define strnalloc(s, n)					\
-    ({	char *strnalloc_tmp = alloc_size((n)+1);	\
-	if (!strnalloc_tmp)				\
-		abort();				\
-	strncpy(strnalloc_tmp, (s), (n));		\
-	strnalloc_tmp[n] = 0;				\
-	strnalloc_tmp; })
-
-const char *unique(const char *s);
-
-#endif /* !UTIL_H */

Copied: trunk/eda/fped/util.h (from rev 5361, developers/werner/fped/util.h)
===================================================================
--- trunk/eda/fped/util.h	                        (rev 0)
+++ trunk/eda/fped/util.h	2009-08-03 16:12:47 UTC (rev 5374)
@@ -0,0 +1,58 @@
+/*
+ * util.h - Common utility functions
+ *
+ * Written 2006, 2009 by Werner Almesberger
+ * Copyright 2006, 2009 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 UTIL_H
+#define UTIL_H
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define alloc_size(s)					\
+    ({	void *alloc_size_tmp = malloc(s);		\
+	if (!alloc_size_tmp)				\
+		abort();				\
+	alloc_size_tmp; })
+
+#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
+
+#define zalloc_type(t)					\
+    ({	t *zalloc_type_tmp = alloc_type(t);		\
+	memset(zalloc_type_tmp, 0, sizeof(t));		\
+	zalloc_type_tmp; })
+
+#define stralloc(s)					\
+    ({	char *stralloc_tmp = strdup(s);			\
+	if (!stralloc_tmp)				\
+		abort();				\
+	stralloc_tmp; })
+
+#define strnalloc(s, n)					\
+    ({	char *strnalloc_tmp = alloc_size((n)+1);	\
+	if (!strnalloc_tmp)				\
+		abort();				\
+	strncpy(strnalloc_tmp, (s), (n));		\
+	strnalloc_tmp[n] = 0;				\
+	strnalloc_tmp; })
+
+
+char *stralloc_vprintf(const char *fmt, va_list ap);
+char *stralloc_printf(const char *fmt, ...);
+
+int is_id_char(char c, int first);
+int is_id(const char *s);
+
+const char *unique(const char *s);
+
+#endif /* !UTIL_H */




More information about the commitlog mailing list