Ivan working on gattrib, yay!

Hi Guys --

>> By the way, I am planning to fix gattrib related bugs from
>> the SF tracker, but it seems impossible without doing
>> major code surgery.... :(
> Go for it. ;)

Yes, please feel encouraged to refactor, slim down, and otherwise
improve gattrib. I will be happy to offer pointers & advice & try to
answer any questions you might have. If my response delay is long,
well, that's 'cause I have a lot of non-gEDA things going on now.....

To help you get your head around the code, here's a quick
explanation of how gattrib is architected:

Gattrib has three major components:

1. It manipulates objects held in the TOPLEVEL data structure. It
does this by importing structs and functions from libgeda.

2. Gattrib defines its own layer of structs, notably SHEET_DATA,
which holds a table of attrib name=value pairs, and also holds a
couple of linked lists corresponding to all component's refdeses, and
to all attribute names found in the design. This stuff is native to

3. Gattrib uses a spreadsheet widget called GtkSheet. This stuff
came from the GtkExtra project, which at one time offered a bunch of
interesting widgets for graphing and visualization. I think they're
still around; you can do a Google search for them. I stole the two
.h files defining the spreadsheet widgets, and also stole code from
the program itself to implement the run-time functions which deal with
the spreadsheet.

When run, gattrib does this:

1. It uses libgeda functions to read in your design, and fill up the
TOPLEVEL struct.

2. It then loops over everything in TOPLEVEL and fills out the refdes
list and the attribute name list. It sticks these into a STRING_LIST
whcih is associated with the SHEET_DATA struct.

3. Then, knowing all the refdeses and all the attribute names, it
creates a TABLE data struct (a member of SHEET_DATA), and loops over
each cell in the TABLE. For each cell, it queries TOPLEVEL for the
corresponding name=value pair, and sticks the value in the TABLE.

4. When done with that, it then creates a GtkSheet and populates it
by looping over TABLE.

5. Then it turns over control to the user, who can manipulate the
GtkSheet. As the user adds and deletes values from the GtkSheet, the
values are stored locally there. The GtkSheet is the master
repository of all attributes at that point; the other data structures
are not updated.

Saving out a design is similar, except the process runs in reverse:

1. The program loops over all cells in GtkSheet, and sticks the
values found into SHEET_DATA. Handling issues like added/deleted
columns happens first at the GtkSheet, and then to SHEET_DATA and
TOPLEVEL. I've kind of forgotten how I implemented these feaures,
however. :-S

2. Then, the program loops over the cells in SHEET_DATA, and updates
the attributes in TOPLEVEL using functions from libgeda, as well as by
reaching directly into the TOPLEVEL data structure (a software
engineering no-no). If a previously existing attrib has been removed,
then it is removed from TOPLEVEL. If a new attrib has been attached
to a component, then it is added to TOPLEVEL.

3. Then the design is saved out using the save function from

Therefore, think of SHEET_DATA and the other gattrib data structures
as a thin layer between GtkSheet and TOPLEVEL. The gattrib data
structures are used basically for convenience while trying to build or
update either of the two other, more important data structures.

Some areas for improvement in gattrib:

* In many places, I just reached into the TOPLEVEL data structures to
manipulate attributes. That is, I did things like
TOPLEVEL->foo->bar->value = woof; Of course, much better would be to
use functions in the libgeda API, like this:
libgeda_setBarValue(woof); When I wrote gattrib many of the required
libgeda functions didn't exist in the API, so I just manipulated the
data myself. At this point, however, the functions may exist, or it
may be time to write them.

* I "stole" the (GPL) code from GtkExtra to implement the
spreadsheet. It still has lots of gnarly cruft left in it which has
nothing to do with gattrib. Therefore, cleaning out and rationalizing
the GtkItem, GtkItemEntry, and related stuff would be a good idea.
This would also make it much easier to fix some of the more glaring
issues with the behavior of the widget. For example, nobody likes the
way the arrow keys are handled. However, the way that callbacks work
is kind of obscure, at least partially because the GtkSheet widget is
still crufty. Therefore, fixing the arrow keys has been put off since
the callbacks are still obscure.

By the way, *don't* succumb to the temptation to simply link to a
GtkExtra library. Rather, just maintain the GtkSheet widget in the
code itself. There are two reasons for this:

1. Linking to a GtkExtra library adds another dependency to the
project. Even if it is distributed with Gtk itself (I don't know if
it is), is it present and working on BSD, OSX, and other non-Linux

2. My experience with linking to external libraries just to implement
some simple function has been bad. The external library API is always
in flux, and your particular project is never on the
library's developers radar screen (think libguile). Better, IMO, to
steal the relevant code (which is what the GPL is for, after all), and
incorporate the relevant functions into *your* code, where *you*
control it. Otherwise, you're going to be on a constant support
treadmill, as the library changes and evolves over time (think

* Many users have submitted feature requests and bug reports to gEDA's
SF tracker. Please feel free to look at those reports.

There are lots of comments in the code to help you understand what is
going on, and I also placed a lot of explanatory material in various
places in the gattrib and gattrib/design directory.

In summary: Please feel encouraged to hack on gattrib! Have fun!


geda-dev mailing list