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 gattrib. 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 libgeda. 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 systems? 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 libguile). * 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! Stuart _______________________________________________ geda-dev mailing list [email protected] http://www.seul.org/cgi-bin/mailman/listinfo/geda-dev
