Index: subform_element/subform_element.module
===================================================================
--- subform_element.module	(revision 20597)
+++ subform_element.module	(working copy)
@@ -79,7 +79,8 @@
 
   $state['values'] = array();
   $subform['#after_build'][] = 'subform_cleanup_ie_cleanup';
-  $subform = form_builder($id, $subform, $state);
+  subform_element_form_builder($id, $subform, $state, TRUE);
+  $subform = subform_element_form_builder($id, $subform, $state);
 
 
   subform_propagate_state_up($subform_id, $form_state, $state);
@@ -90,10 +91,131 @@
   //add a reference to the element for later use
   $form_state['subform'][$subform_id]['element'] = &$element;
 
+
   return $element;
 }
 
 /**
+ * Walk through the structured form array, adding any required
+ * properties to each element and mapping the incoming $_POST
+ * data to the proper elements.
+ *
+ * @param $form_id
+ *   A unique string identifying the form for validation, submission,
+ *   theming, and hook_form_alter functions.
+ * @param $form
+ *   An associative array containing the structure of the form.
+ * @param $form_state
+ *   A keyed array containing the current state of the form. In this
+ *   context, it is used to accumulate information about which button
+ *   was clicked when the form was submitted, as well as the sanitized
+ *   $_POST data.
+ */
+function subform_element_form_builder($form_id, $form, &$form_state, $reset = FALSE) {
+  static $complete_form, $cache;
+
+  if ($reset === TRUE) {
+    unset($complete_form, $cache);
+    return;
+  }
+
+  // Initialize as unprocessed.
+  $form['#processed'] = FALSE;
+
+  // Use element defaults.
+  if ((!empty($form['#type'])) && ($info = _element_info($form['#type']))) {
+    // Overlay $info onto $form, retaining preexisting keys in $form.
+    $form += $info;
+  }
+
+  if (isset($form['#type']) && $form['#type'] == 'form') {
+    $cache = NULL;
+    $complete_form = $form;
+    if (!empty($form['#programmed'])) {
+      $form_state['submitted'] = TRUE;
+    }
+  }
+
+  if (isset($form['#input']) && $form['#input']) {
+    _form_builder_handle_input_element($form_id, $form, $form_state, $complete_form);
+  }
+  $form['#defaults_loaded'] = TRUE;
+
+  // We start off assuming all form elements are in the correct order.
+  $form['#sorted'] = TRUE;
+
+  // Recurse through all child elements.
+  $count = 0;
+  foreach (element_children($form) as $key) {
+    $form[$key]['#post'] = $form['#post'];
+    $form[$key]['#programmed'] = $form['#programmed'];
+    // Don't squash an existing tree value.
+    if (!isset($form[$key]['#tree'])) {
+      $form[$key]['#tree'] = $form['#tree'];
+    }
+
+    // Deny access to child elements if parent is denied.
+    if (isset($form['#access']) && !$form['#access']) {
+      $form[$key]['#access'] = FALSE;
+    }
+
+    // Don't squash existing parents value.
+    if (!isset($form[$key]['#parents'])) {
+      // Check to see if a tree of child elements is present. If so,
+      // continue down the tree if required.
+      $form[$key]['#parents'] = $form[$key]['#tree'] && $form['#tree'] ? array_merge($form['#parents'], array($key)) : array($key);
+      $array_parents = isset($form['#array_parents']) ? $form['#array_parents'] : array();
+      $array_parents[] = $key;
+      $form[$key]['#array_parents'] = $array_parents;
+    }
+
+    // Assign a decimal placeholder weight to preserve original array order.
+    if (!isset($form[$key]['#weight'])) {
+      $form[$key]['#weight'] = $count/1000;
+    }
+    else {
+      // If one of the child elements has a weight then we will need to sort
+      // later.
+      unset($form['#sorted']);
+    }
+    $form[$key] = subform_element_form_builder($form_id, $form[$key], $form_state);
+    $count++;
+  }
+
+  // The #after_build flag allows any piece of a form to be altered
+  // after normal input parsing has been completed.
+  if (isset($form['#after_build']) && !isset($form['#after_build_done'])) {
+    foreach ($form['#after_build'] as $function) {
+      $form = $function($form, $form_state);
+      $form['#after_build_done'] = TRUE;
+    }
+  }
+
+  // Now that we've processed everything, we can go back to handle the funky
+  // Internet Explorer button-click scenario.
+  _form_builder_ie_cleanup($form, $form_state);
+
+  // We shoud keep the buttons array until the IE clean up function
+  // has recognized the submit button so the form has been marked
+  // as submitted. If we already know which button was submitted,
+  // we don't need the array.
+  if (!empty($form_state['submitted'])) {
+    unset($form_state['buttons']);
+  }
+
+  // If some callback set #cache, we need to flip a static flag so later it
+  // can be found.
+  if (!empty($form['#cache'])) {
+    $cache = $form['#cache'];
+  }
+  // We are on the top form, we can copy back #cache if it's set.
+  if (isset($form['#type']) && $form['#type'] == 'form' && isset($cache)) {
+    $form['#cache'] = TRUE;
+  }
+  return $form;
+}
+
+/**
  * Initialies the form_state if necessary and returns a reference on it
  */
 function &subform_element_get_element_state($subform_id, &$form_state) {
