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