Well, I spent the weekend learning to write widgets. Thanks to Karl
for pointing me to the Fieldset widget as a good container example.
I'm not convinced I have all the details right yet, but I now have a
set of widgets for doing table layout that is not input-form oriented.
The widgets consist of Table, TableBody, TableHeader, TableFooter,
TableRow, TableCell, and 'cause I needed something to put in a cell,
Text. These widgets successfully encapsulate html table layout such
that you don't need to worry about it; just set up your tree of
objects.
Here's a small example, formatted for clarity:
myTable = Table(\
header=TableHeader(\
rows=[\
TableRow(\
cells=[\
TableCell(\
widgets=[Text("Column 1 Label")]\
),\
TableCell(\
widgets=[Text("Column 2 Label")]\
)\
]\
)\
]\
),
bodies=[\
TableBody(\
rows=[\
TableRow(\
cells=[\
TableCell(\
widgets=[Text("Column 1 Data")]\
),\
TableCell(\
widgets=[Text("Column 2 Data")]\
)\
]\
)\
]\
)\
],\
attrs=dict(cellpadding="4")\
)
I tried to make these widgets yield decent-looking, but not bloated,
HTML. Executing 'myTable.render() yields the following output:
<TABLE CELLPADDING="4" ID="table">\n <THEAD ID="table_head">\n
<TR ID="table_row">\n <TD ID="table_cell">\n
<SPAN ID="text">Column 1 Label</SPAN>\n </TD>\n
<TD ID="table_cell">\n <SPAN ID="text">Column 2
Label</SPAN>\n </TD>\n </TR>\n </THEAD>\n
<TBODY ID="table_body">\n <TR ID="table_row">\n <TD
ID="table_cell">\n <SPAN ID="text">Column 1 Data</SPAN>\n
</TD>\n <TD ID="table_cell">\n <SPAN
ID="text">Column 2 Data</SPAN>\n </TD>\n </TR>\n
</TBODY>\n</TABLE>
A TableCell can contain any number of other widgets of any widget type.
Hopefully, if I've gotten all this right, these widgets give us the
ability to do any kind of table layout that we can do in straight HTML.
We could even create a Form widget, put these table widgets inside the
Form widget, put various Label and Field-type widgets in the table
cells, and have the equivalent of a TableForm widget, but with better
flexibility.
I'll be happy to donate these widgets to the TG project if there is
interest in me doing so. I think it would be a good idea for some,
more widget-knowledgeable, person to look them over.
One thing I learned while doing this project is the current Widget base
class is very form-input oriented. I see from comments from Kevin and
Karl that what I set out to do is not really in line with the original
intended use for widgets. It may be a mistake to limit our scope. We
might want to take a look at refactoring the current Widget base class
to move the form-input code out to a new 'FormWidget' class that would
be the base class of form-oriented classes.