Index: trunk/Changes
===================================================================
--- trunk/Changes	(revision 29)
+++ trunk/Changes	(revision 30)
@@ -10,4 +10,6 @@
       string values
     * allow for validated but not required fields
+    * added a !section directive that splits up a form into
+      sub-tables with their own ids and captions
     
 0.05 -  9 Nov 2004
Index: trunk/lib/Text/FormBuilder.pm
===================================================================
--- trunk/lib/Text/FormBuilder.pm	(revision 29)
+++ trunk/lib/Text/FormBuilder.pm	(revision 30)
@@ -18,4 +18,17 @@
     keepextras => 1,
 );
+
+# the built in CSS for the template
+my $DEFAULT_CSS = <<END;
+table { padding: 1em; }
+#author, #footer { font-style: italic; }
+caption h2 { padding: .125em .5em; background: #ccc; text-align: left; }
+th { text-align: left; }
+th h3 { padding: .125em .5em; background: #eee; }
+th.label { font-weight: normal; text-align: right; vertical-align: top; }
+td ul { list-style: none; padding-left: 0; margin-left: 0; }
+.sublabel { color: #999; }
+.invalid { background: red; }
+END
 
 sub new {
@@ -74,5 +87,10 @@
     # form_only: use only the form part of the template
     my $form_only = $options{form_only};
-    delete $options{form_only};
+    my $css;
+    $css = $options{css} || $DEFAULT_CSS;
+    $css .= $options{extra_css} if $options{extra_css};
+    
+    # remove our custom options
+    delete $options{$_} foreach qw(form_only css extra_css);
     
     # substitute in custom pattern definitions for field validation
@@ -139,5 +157,12 @@
     } continue {
         delete $$_{list};
-    }    
+    }
+    
+    # special case single-value checkboxes
+    foreach (grep { $$_{type} && $$_{type} eq 'checkbox' } @{ $self->{form_spec}{fields} }) {
+        unless ($$_{options}) {
+            $$_{options} = [ { $$_{name} => $$_{label} || ucfirst join(' ',split(/_/,$$_{name})) } ];
+        }
+    }
     
     # TODO: configurable threshold for this
@@ -167,5 +192,5 @@
             engine => {
                 TYPE       => 'STRING',
-                SOURCE     => $form_only ? $self->_form_template : $self->_template,
+                SOURCE     => $form_only ? $self->_form_template : $self->_template($css),
                 DELIMITERS => [ qw(<% %>) ],
             },
@@ -218,4 +243,8 @@
     $Data::Dumper::Terse = 1;
     
+    my $css;
+    $css = $self->{build_options}{css} || $DEFAULT_CSS;
+    $css .= $self->{build_options}{extra_css} if $self->{build_options}{extra_css};
+    
     my %options = (
         %DEFAULT_OPTIONS,
@@ -228,5 +257,5 @@
             engine => {
                 TYPE       => 'STRING',
-                SOURCE     => $self->{build_options}{form_only} ? $self->_form_template : $self->_template,
+                SOURCE     => $self->{build_options}{form_only} ? $self->_form_template : $self->_template($css),
                 DELIMITERS => [ qw(<% %>) ],
             },
@@ -242,5 +271,6 @@
     my $source = $options{form_only} ? $self->_form_template : $self->_template;
     
-    delete $options{form_only};
+    # remove our custom options
+    delete $options{$_} foreach qw(form_only css extra_css);
     
     my $form_options = keys %options > 0 ? Data::Dumper->Dump([\%options],['*options']) : '';
@@ -310,9 +340,9 @@
 <%
     SECTION: while (my $section = shift @sections) {
-        $OUT .= qq[<table id="$$section{id}">\n];
-        $OUT .= qq[  <caption><h2>$$section{head}</h2></caption>] if $$section{head};
+        $OUT .= qq[<table id="] . ($$section{id} || '_default') . qq[">\n];
+        $OUT .= qq[  <caption><h2 class="sectionhead">$$section{head}</h2></caption>] if $$section{head};
         TABLE_LINE: for my $line (@{ $$section{lines} }) {
             if ($$line[0] eq 'head') {
-                $OUT .= qq[  <tr><th class="sectionhead" colspan="2"><h3>$$line[1]</h3></th></tr>\n]
+                $OUT .= qq[  <tr><th class="subhead" colspan="2"><h3>$$line[1]</h3></th></tr>\n]
             } elsif ($$line[0] eq 'field') {
                 #TODO: we only need the field names, not the full field spec in the lines strucutre
@@ -322,10 +352,18 @@
                 
                 $OUT .= $$_{invalid} ? qq[  <tr class="invalid">] : qq[  <tr>];
-                $OUT .= '<th class="label">' . ($$_{required} ? qq[<strong class="required">$$_{label}:</strong>] : "$$_{label}:") . '</th>';
+                
+                # special case single value checkboxes
+                if ($$_{type} eq 'checkbox' && @{ $$_{options} } == 1) {
+                    $OUT .= qq[<th></th>];
+                } else {
+                    $OUT .= '<th class="label">' . ($$_{required} ? qq[<strong class="required">$$_{label}:</strong>] : "$$_{label}:") . '</th>';
+                }
                 if ($$_{invalid}) {
-                    $OUT .= qq[<td>$$_{field} $$_{comment} Missing or invalid value.</td></tr>\n];
+                    $OUT .= qq[<td>$$_{field} $$_{comment} Missing or invalid value.</td>];
                 } else {
-                    $OUT .= qq[<td>$$_{field} $$_{comment}</td></tr>\n];
+                    $OUT .= qq[<td>$$_{field} $$_{comment}</td>];
                 }
+                $OUT .= qq[</tr>\n];
+                
             } elsif ($$line[0] eq 'group') {
                 my @field_names = map { $$_{name} } @{ $$line[1]{group} };
@@ -356,17 +394,10 @@
 sub _template {
     my $self = shift;
+    my $css = shift || $DEFAULT_CSS;
 q[<html>
 <head>
   <title><% $title %><% $author ? ' - ' . ucfirst $author : '' %></title>
-  <style type="text/css">
-    table { margin: .5em 1em; }
-    #author, #footer { font-style: italic; }
-    caption h2 { padding: .125em .5em; background: #ddd; text-align: left; }
-    th { text-align: left; }
-    th h3 { padding: .125em .5em; background: #eee; }
-    th.label { font-weight: normal; text-align: right; vertical-align: top; }
-    td ul { list-style: none; padding-left: 0; margin-left: 0; }
-    .sublabel { color: #999; }
-    .invalid { background: red; }
+  <style type="text/css">] .
+$css . q[
   </style>
 </head>
@@ -461,4 +492,12 @@
 description as specified with the C<!description> directive.
 
+=item C<css>, C<extra_css>
+
+These options allow you to tell Text::FormBuilder to use different
+CSS styles for the built in template. A value given a C<css> will
+replace the existing CSS, and a value given as C<extra_css> will be
+appended to the CSS. If both options are given, then the CSS that is
+used will be C<css> concatenated with C<extra_css>.
+
 =back
 
@@ -703,8 +742,6 @@
     moreinfo|I want to recieve more information:checkbox
 
-The one drawback to this is that the label to the checkbox will still appear
-to the left of the field. I am leaving it this way for now, but if enough
-people would like this to change, I may make single-option checkboxes a special
-case and put the label on the right.
+In this case, the label ``I want to recieve more information'' will be
+printed to the right of the checkbox.
 
 You can also supply a default value to the field. To get a default value of
@@ -749,7 +786,5 @@
 Use the custom message file format for messages in the built in template
 
-Custom CSS, both in addition to, and replacing the built in.
-
-Use HTML::Template instead of Text::Template for the built in template
+Maybe use HTML::Template instead of Text::Template for the built in template
 (since CGI::FormBuilder users may be more likely to already have HTML::Template)
 
@@ -764,6 +799,5 @@
 =head1 BUGS
 
-For now, checkboxes with a single value still display their labels on
-the left.
+I'm sure they're in there, I just haven't tripped over any new ones lately. :-)
 
 =head1 SEE ALSO
