diff --git a/uc_attribute/uc_attribute.admin.inc b/uc_attribute/uc_attribute.admin.inc
index b9a978a..ef33ca3 100644
--- a/uc_attribute/uc_attribute.admin.inc
+++ b/uc_attribute/uc_attribute.admin.inc
@@ -1162,21 +1162,35 @@ function theme_uc_object_options_form($form) {
  *   Themed set of attribute options.
  */
 function theme_uc_product_attributes($element) {
+  $product = $element['#product']['#value'];
   $option_rows = array();
-
   foreach (element_children($element) as $key) {
     $optionstr = '';
 
-    foreach ((array)$element[$key]['#options'] as $option) {
+    foreach ((array)$element[$key]['#options'] as $option_key => $option) {
+      $append = $option['name'];
+
+      // Show quantity for grid
+      if ($element[$key]['#display'] == 4) {
+        $context['type'] = 'amount';
+        $context['subject']['node'] = $product;
+        $price_info = array(
+          'price' => $element[$key]['#options'][$option_key]['price_each'],
+          'qty' => 1,
+        );
+
+        $append = t('@qty&times;', array('@qty' => $element[$key]['#options'][$option_key]['quantity'])) . ' ' . $option['name'] . ' (' . uc_price($price_info, $context) . ' ' . t('each') . ')';
+      }
+
       // We only need to allow translation from the second option onward
       if (empty($optionstr)) {
-        $optionstr .= $option;
+        $optionstr .= $append;
       }
       else {
-        $optionstr .= t(', !option', array('!option' => $option));
+        $optionstr .= t(', !option', array('!option' => $append));
       }
     }
-    $option_rows[$key] = t('@attribute: @option', array('@attribute' => $element[$key]['#attribute_name'], '@option' => $optionstr));
+    $option_rows[$key] = t('@attribute: !option', array('@attribute' => $element[$key]['#attribute_name'], '!option' => $optionstr));
   }
 
   if (!empty($option_rows)) {
diff --git a/uc_attribute/uc_attribute.module b/uc_attribute/uc_attribute.module
index 03daf9e..88b967a 100644
--- a/uc_attribute/uc_attribute.module
+++ b/uc_attribute/uc_attribute.module
@@ -18,6 +18,77 @@ require_once('uc_attribute.ca.inc');
  * Drupal Hooks                                                               *
  ******************************************************************************/
 
+
+function uc_attribute_elements() {
+  $type['uc_quantity_grid'] = array(
+    '#input' => TRUE,
+    '#process' => array('expand_uc_quantity_grid'),
+    '#tree' => TRUE
+  );
+  return $type;
+}
+
+function expand_uc_quantity_grid($element) {
+  $element['#tree'] = TRUE;
+  if (count($element['#grid']) > 0) {
+    foreach ($element['#grid'] as $key => $choice) {
+      if (!isset($element[$key])) {
+        $element[$key] = array(
+          '#type' => 'textfield',
+          '#processed' => TRUE,
+          '#title' => $choice,
+          '#attributes' => $element['#attributes'],
+          '#ahah' => isset($element['#ahah']) ? $element['#ahah'] : NULL,
+          '#theme' => 'uc_quantity_grid_textfield',
+          '#size' => 2,
+          '#maxlength' => 4,
+          '#default_value' => 0
+        );
+      }
+    }
+  }
+  return $element;
+}
+
+function theme_uc_quantity_grid($element) {
+  $class = 'form-uc-attribute-quantity-grid';
+  if (isset($element['#attributes']['class'])) {
+    $class .= ' '. $element['#attributes']['class'];
+  }
+  $element['#children'] = '<div class="'. $class .'">'. (!empty($element['#children']) ? $element['#children'] : '') .'</div>';
+  if ($element['#title'] || $element['#description']) {
+    unset($element['#id']);
+    return theme('form_element', $element, $element['#children']);
+  }
+  else {
+    return $element['#children'];
+  }
+}
+
+function theme_uc_quantity_grid_textfield($element) {
+  $size = empty($element['#size']) ? '' : ' size="'. $element['#size'] .'"';
+  $maxlength = empty($element['#maxlength']) ? '' : ' maxlength="'. $element['#maxlength'] .'"';
+  $class = array('form-text');
+  $extra = '';
+  _form_set_class($element, $class);
+
+  $output = '<div class="form-item uc-attribute-quantity-grid-wrapper">' . "\n";
+  if (!empty($element['#title'])) {
+    $title = $element['#title'];
+    $output .= ' <span class="uc-attribute-quantity-grid-title">'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</span>\n";
+  }
+
+  $output .= '<span class="uc-attribute-quantity-grid-quantity">' . t('Quantity:') . '</span>';
+  $output .= '<input type="text"'. $maxlength .' name="'. $element['#name'] .'" id="'. $element['#id'] .'"'. $size .' value="'. check_plain($element['#value']) .'"'. drupal_attributes($element['#attributes']) .' />';
+
+  if (!empty($element['#description'])) {
+    $output .= ' <div class="description">'. $element['#description'] ."</div>\n";
+  }
+
+  $output .= "</div>\n";
+  return $output;
+}
+
 /**
  * Implements hook_help().
  */
@@ -274,6 +345,12 @@ function uc_attribute_theme() {
     'uc_attribute_option' => array(
       'arguments' => array('option' => '', 'price' => ''),
     ),
+		'uc_quantity_grid' => array(
+			'arguments' => array('element' => NULL),
+    ),
+    'uc_quantity_grid_textfield' => array(
+			'arguments' => array('element' => NULL),
+    ),
     'uc_attribute_add_to_cart' => array(
       'arguments' => array('form' => NULL),
     ),
@@ -561,12 +638,10 @@ function uc_attribute_product_description($product) {
   if (empty($product->order_id)) {
     foreach (_uc_cart_product_get_options($product) as $option) {
       if (!isset($desc[$option['aid']])) {
+        $desc[$option['aid']]['#display'] = $option['display'];
         $desc[$option['aid']]['#attribute_name'] = $option['attribute'];
-        $desc[$option['aid']]['#options'] = array($option['name']);
-      }
-      else {
-        $desc[$option['aid']]['#options'][] = $option['name'];
       }
+      $desc[$option['aid']]['#options'][] = $option;
       $desc[$option['aid']]['#weight'] = $weight++;
     }
   }
@@ -1176,12 +1251,33 @@ function _uc_cart_product_get_options($item) {
       if (isset($node->attributes[$aid])) {
         $attribute = $node->attributes[$aid];
         $name = _uc_attribute_get_name($attribute);
+        // Quantity grids are handled differently
+        if ($attribute->display == 4) {
+          // There may be many selected options, or just one.
+          foreach ((array)$selected as $oid => $quantity) {
+            if ($oid > 0) {
+              $options[$index] = (array) $attribute->options[$oid];
+              $options[$index]['display'] = $attribute->display;
+              $options[$index]['attribute'] = $name;
+              // Store cost/each and quantity for theme_uc_product_attributes
+              $options[$index]['cost_each'] = $options[$index]['cost'];
+              $options[$index]['price_each'] = $options[$index]['price'];
+              $options[$index]['weight_each'] = $options[$index]['weight'];
+              $options[$index]['quantity'] = $quantity;
+              $options[$index]['cost'] = $options[$index]['cost'] * $quantity;
+              $options[$index]['price'] = $options[$index]['price'] * $quantity;
+              $options[$index]['weight'] = $options[$index]['weight'] * $quantity;
+              $index++;
+            }
+          }
+        }
         // Only discrete options can affect the price of an item.
-        if ($attribute->display && count($attribute->options)) {
+        else if ($attribute->display && count($attribute->options)) {
           // There may be many selected options, or just one.
           foreach ((array)$selected as $oid) {
             if ($oid > 0) {
               $options[$index] = (array)$attribute->options[$oid];
+              $options[$index]['display'] = $attribute->display;
               $options[$index]['attribute'] = $name;
               $index++;
             }
@@ -1190,6 +1286,7 @@ function _uc_cart_product_get_options($item) {
         else {
           // Handle textfield attributes.
           $options[$index] = array(
+            'display' => $attribute->display,
             'attribute' => $name,
             'aid' => $aid,
             'oid' => 0,
@@ -1288,13 +1385,23 @@ function _uc_attribute_alter_form($product) {
           $attr_type = 'checkboxes';
           break;
       }
-      $form_attributes[$attribute->aid] = array(
-        '#type' => $attr_type,
-        '#description' => check_markup($attribute->description),
-        '#default_value' => ($attr_type == "checkboxes" ? array() : $attribute->default_option),
-        '#options' => $options,
-        '#required' => $attribute->required,
-      );
+      if ($attribute->display != 4) {
+        $form_attributes[$attribute->aid] = array(
+          '#type' => $attr_type,
+          '#description' => check_markup($attribute->description),
+          '#default_value' => ($attr_type == "checkboxes" ? array() : $attribute->default_option),
+          '#options' => $options,
+          '#required' => $attribute->required,
+        );
+      }
+      else {
+        $form_attributes[$attribute->aid] = array(
+          '#type' => 'uc_quantity_grid',
+          '#description' => check_markup($attribute->description),
+          '#grid' => $options,
+          '#required' => $attribute->required,
+        );
+      }
     }
     else {
       $form_attributes[$attribute->aid] = array(
@@ -1327,6 +1434,7 @@ function _uc_attribute_display_types() {
     1 => t('Select box'),
     2 => t('Radio buttons'),
     3 => t('Checkboxes'),
+    4 => t('Quantity Grid'),
   );
 }
 
