diff -uPr uc_varprice_orig/uc_varprice.install uc_varprice/uc_varprice.install
--- uc_varprice_orig/uc_varprice.install	2009-05-15 14:40:04.000000000 -0700
+++ uc_varprice/uc_varprice.install	2009-06-08 10:19:37.000000000 -0700
@@ -56,6 +56,31 @@
         'not null' => TRUE,
         'default' => '',
       ),
+      'arbitrary' => array(
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'selectable' => array(
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'sel_widget' => array(
+        'type' => 'varchar',
+        'length' => 8,
+        'not null' => TRUE,
+        'default' => 'radios',
+      ),
+      'sel_options' => array(
+        'type' => 'text',
+        'not null' => TRUE,
+        'default' => '',
+      ),
     ),
     'indexes' => array(
       'pfid' => array('pfid'),
@@ -74,4 +99,22 @@
   drupal_uninstall_schema('uc_varprice');
   db_query("DELETE FROM {uc_product_features} WHERE fid = 'varprice'");
   variable_del('uc_varprice_global_default');
+	global $conf;
+	foreach (array_keys($conf) as $key) {
+		if (strpos($key, 'ucvp_class_def_') === 0) {
+			variable_del($key);
+		}
+	}
 }
+
+function uc_varprice_update_6001() {
+	$added = array();
+	$schema = uc_varprice_schema();
+	// Add new fields
+	foreach (array('arbitrary', 'selectable', 'sel_widget', 'sel_options') as $key) {
+		db_add_field($added, 'uc_varprice_products', $key, $schema['uc_varprice_products']['fields'][$key]);
+	}
+	// Define all currently-existing varprice fields as arbitrary price only fields
+	db_query('UPDATE {uc_varprice_products} SET arbitrary = 1');
+	return $added;
+}
\ No newline at end of file
diff -uPr uc_varprice_orig/uc_varprice.module uc_varprice/uc_varprice.module
--- uc_varprice_orig/uc_varprice.module	2009-05-18 21:58:30.000000000 -0700
+++ uc_varprice/uc_varprice.module	2009-06-08 10:24:22.000000000 -0700
@@ -43,26 +43,71 @@
     $data = uc_varprice_product_load($form['nid']['#value']);
 
     if ($data) {
-      $description = array();
-
-      if (!empty($data->price_minimum)) {
-        $description[] = t('Minimum: @price', array('@price' => uc_currency_format($data->price_minimum)));
+      
+      // Determine the default value
+      $default_val = !empty($data->price_default) ? $data->price_default : variable_get('uc_varprice_global_default', '0');
+      // Are we going to add a selectable widget?
+      if ($data->selectable) {
+        $options = $data->sel_options;
+        // Add "other" option if users can also enter arbitrary values
+        if ($data->arbitrary) {
+          $options['other'] = t('Other…');
+          drupal_add_js(drupal_get_path('module', 'uc_varprice') . '/uc_varprice_show_arb.js');
+        }
+        if (isset($options[$default_val])) {
+          // If the default value is in the options…
+          $sel_default = $default_val;
+          $default_val = FALSE;
+        }
+        elseif ($data->arbitrary) {
+          // If "other" is an option, select that by default and have the
+          // default value appear in the arbitrary value field.
+          $sel_default = 'other';
+        }
+        elseif (count($options)) {
+          // If all else fails, just select the first item.
+          $sel_default = array_shift(array_keys($options));
+        }
+        else {
+          // If we get here, then there aren't any options in the list anyway.
+          // What the heck?
+          $sel_default = '';
+        }
+        $form['varprice_sel'] = array(
+          '#type' => $data->sel_widget,
+          '#title' => !empty($data->amount_title) ? $data->amount_title : t('Amount'),
+          '#options' => $options,
+          '#default_value' => $sel_default,
+          '#weight' => -5.2,
+        );
       }
-      if (!empty($data->price_maximum)) {
-        $description[] = t('Maximum: @price', array('@price' => uc_currency_format($data->price_maximum)));
+      
+      if ($data->arbitrary) {
+        $description = array();
+        if ($data->selectable) {
+          $description[] = t('If you&rsquo;ve selected &ldquo;Other…&rdquo; above, enter the precise amount here.');
+        }
+        if (!empty($data->price_minimum)) {
+          $description[] = t('Minimum: @price', array('@price' => uc_currency_format($data->price_minimum)));
+        }
+        if (!empty($data->price_maximum)) {
+          $description[] = t('Maximum: @price', array('@price' => uc_currency_format($data->price_maximum)));
+        }
+        
+        // Add the amount textfield to the add to cart form.
+        $form['varprice_arb'] = array(
+          '#type' => 'textfield',
+          '#title' => $data->selectable ? '' : (!empty($data->amount_title) ? $data->amount_title : t('Amount')),
+          '#description' => implode('<br />', $description),
+          '#default_value' => !empty($default_val) ? $default_val : ($data->selectable ? '' : variable_get('uc_varprice_global_default', '0')),
+          '#size' => 8,
+          '#weight' => -5,
+          '#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
+          '#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
+          '#attributes' => array('class' => 'uc_varprice_arb'),
+        );
       }
-
-      // Add the amount textfield to the add to cart form.
-      $form['varprice'] = array(
-        '#type' => 'textfield',
-        '#title' => $data && !empty($data->amount_title) ? $data->amount_title : t('Amount'),
-        '#description' => implode('<br />', $description),
-        '#default_value' => $data ? $data->price_default : variable_get('uc_varprice_global_default', '0'),
-        '#size' => 8,
-        '#weight' => -5,
-        '#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
-        '#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
-      );
+      $form['#validate'][] = 'uc_varprice_add_to_cart_form_validate';
     }
   }
 
@@ -106,16 +151,37 @@
       '#default_value' => $data === FALSE ? FALSE : TRUE,
     );
     $form['varprice'] += _uc_varprice_feature_form($data);
-
+    
+    $form['#validate'][] = 'uc_varprice_feature_form_validate';
     $form['#submit'][] = 'uc_varprice_product_class_submit';
 
     $form['submit']['#weight'] = 10;
   }
 }
 
+// Validation handler to ensure that the submitted price is valid.
+function uc_varprice_add_to_cart_form_validate($form, &$form_state) {
+  $vp_data = uc_varprice_product_load($form_state['values']['nid']);
+  if (!isset($form_state['values']['varprice_sel']) || $form_state['values']['varprice_sel'] === 'other') {
+    if (empty($form_state['values']['varprice_arb']) || $form_state['values']['varprice_arb'] == 0) {
+      form_set_error('varprice_arb', t('You must specify a price.'));
+    }
+    elseif (!empty($vp_data->price_minimum) && $form_state['values']['varprice_arb'] < $vp_data->price_minimum) {
+      form_set_error('varprice_arb', t('You must specify an amount greater than or equal to @price.', array('@price' => uc_currency_format($vp_data->price_minimum))));
+    }
+    elseif (!empty($vp_data->price_maximum) && $form_state['values']['varprice_arb'] > $vp_data->price_maximum) {
+      form_set_error('varprice_arb', t('You must specify an amount less than or equal to @price.', array('@price' => uc_currency_format($vp_data->price_maximum))));
+    }
+  }
+}
+
 // Submit handler for the product class form for default Variable Price features.
 function uc_varprice_product_class_submit($form, &$form_state) {
   if ($form_state['values']['default_varprice']) {
+    // @TODO:
+    // The $data array building below is pretty much identical to what appears
+    // in uc_varprice_feature_form_submit() - maybe it should be in a helper
+    // function?
     $data = array(
       'price_default' => $form_state['values']['price_default'],
       'price_minimum' => $form_state['values']['price_minimum'],
@@ -124,6 +190,10 @@
       'add_to_cart_title' => $form_state['values']['override_add_to_cart_title'] ? $form_state['values']['add_to_cart_title'] : '',
       'override_amount_title' => $form_state['values']['override_amount_title'],
       'amount_title' => $form_state['values']['override_amount_title'] ? $form_state['values']['amount_title'] : '',
+      'arbitrary' => $form_state['values']['arbitrary'],
+      'selectable' => $form_state['values']['selectable'],
+      'sel_widget' => $form_state['values']['sel_widget'],
+      'sel_options' => $form_state['values']['sel_options_arr'],
     );
 
     variable_set('ucvp_class_def_'. $form_state['values']['pcid'], serialize($data));
@@ -142,7 +212,7 @@
  */
 function uc_varprice_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
   // When the node is being prepped for display...
-  if ($op == 'view') {
+  if ($op === 'view') {
     // If this node has a variable price product feature...
     if (db_result(db_query("SELECT pfid FROM {uc_product_features} WHERE fid = 'varprice' AND nid = %d", $node->nid))) {
       // Hide all the prices from display.
@@ -152,21 +222,31 @@
       $node->content['display_price']['#access'] = FALSE;
     }
   }
-
-  // When a product node is created...
-  if ($op == 'insert' && uc_product_is_product($node)) {
-    $data = variable_get('ucvp_class_def_'. $node->type, array());
-
-    // If the product class has a default Variable Price product feature...
-    if ($data) {
-      // Prepare the data as if it were from a form submission.
-      $data = unserialize($data);
-      $data['nid'] = $node->nid;
-      $data['pfid'] = '';
-      $form_state = array('values' => $data);
-
-      // Add the feature to the product by spoofing the normal form submission.
-      uc_varprice_feature_form_submit(array(), $form_state);
+  
+  elseif (uc_product_is_product($node)) {
+    // When a product node is created...
+    if ($op === 'insert') {
+      $data = variable_get('ucvp_class_def_'. $node->type, array());
+  
+      // If the product class has a default Variable Price product feature...
+      if ($data) {
+        // Prepare the data as if it were from a form submission.
+        $data = unserialize($data);
+        $data['nid'] = $node->nid;
+        $data['pfid'] = '';
+        $form_state = array('values' => $data);
+  
+        // Add the feature to the product by spoofing the normal form submission.
+        $form_state['values']['sel_options_arr'] = $form_state['values']['sel_options'];
+        uc_varprice_feature_form_submit(array(), $form_state);
+      }
+    }
+    // When a product node is deleted…
+    elseif ($op === 'delete') {
+      $data = uc_varprice_product_load($node->nid);
+      if ($data) {
+        db_query('DELETE FROM {uc_varprice_products} WHERE vpid = %d', $data->vpid);
+      }
     }
   }
 }
@@ -176,45 +256,14 @@
  */
 function uc_varprice_add_to_cart_data($form_values) {
   // Store the customer entered price in the product's data array.
-  if (!empty($form_values['varprice'])) {
-    return array('varprice' => $form_values['varprice'], 'uniqid' => uniqid());
+  if (isset($form_values['varprice_arb']) && (!isset($form_values['varprice_sel']) || $form_values['varprice_sel'] === 'other')) {
+    return array('varprice' => $form_values['varprice_arb'], 'uniqid' => uniqid());
   }
-}
-
-/**
- * Implementation of hook_add_to_cart().
- */
-function uc_varprice_add_to_cart($nid, $qty, $data) {
-  $result = array();
-
-  // If there is Variable Price data for this product...
-  if (isset($data['varprice'])) {
-    $message = '';
-
-    // Load the product feature data.
-    $vp_data = uc_varprice_product_load($nid);
-
-    // Fail if the customer failed to enter a price.
-    if (empty($data['varprice']) || $data['varprice'] == 0) {
-      $message = t('You must specify a price.');
-    }
-    // Fail if the customer entered a price lower than the minimum.
-    elseif (!empty($vp_data->price_minimum) && $data['varprice'] < $vp_data->price_minimum) {
-      $message = t('You must specify an amount greater than or equal to @price.', array('@price' => uc_currency_format($vp_data->price_minimum)));
-    }
-    // Fail if the customer entered a price above the maximum.
-    elseif (!empty($vp_data->price_maximum) && $data['varprice'] > $vp_data->price_maximum) {
-      $message = t('You must specify an amount less than or equal to @price.', array('@price' => uc_currency_format($vp_data->price_maximum)));
-    }
-
-    // If an error message was set, return the failure notification.
-    if (!empty($message)) {
-      return array(array('success' => FALSE, 'message' => $message));
-    }
+  elseif (isset($form_values['varprice_sel'])) {
+    return array('varprice' => $form_values['varprice_sel'], 'uniqid' => uniqid());
   }
 }
 
-
 /**
  * Implementation of hook_cart_item().
  */
@@ -272,7 +321,9 @@
   drupal_add_js(drupal_get_path('module', 'uc_varprice') .'/uc_varprice.js');
 
   // Load the Variable Price data specific to this product.
-  $data = db_fetch_object(db_query("SELECT * FROM {uc_varprice_products} WHERE pfid = %d", $feature['pfid']));
+  if ($data = db_fetch_object(db_query("SELECT * FROM {uc_varprice_products} WHERE pfid = %d", $feature['pfid']))) {
+    $data->sel_options = unserialize($data->sel_options);
+  }
 
   $form['nid'] = array(
     '#type' => 'value',
@@ -290,7 +341,9 @@
 
 function _uc_varprice_feature_form($data = FALSE) {
   $form = array();
-
+    
+  $form['#validate'] = array('uc_varprice_feature_form_validate');
+  
   $form['prices'] = array(
     '#type' => 'fieldset',
     '#title' => t('Price settings'),
@@ -299,12 +352,48 @@
     '#type' => 'textfield',
     '#title' => t('Default price'),
     '#size' => 8,
-    '#description' => t('The default price for this variable priced products.'),
+    '#description' => t('The default price for this variable priced product.'),
     '#default_value' => $data ? $data->price_default : variable_get('uc_varprice_global_default', '0'),
     '#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
     '#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
   );
-  $form['prices']['price_minimum'] = array(
+
+  $form['prices']['sel_fs'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Selectable price'),
+  );
+  $form['prices']['sel_fs']['selectable'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable selectable variable prices'),
+    '#description' => t('When enabled, visitors may select one of several pre-set values defined by you.'),
+    '#default_value' => $data ? $data->selectable : FALSE,
+  );
+  $form['prices']['sel_fs']['sel_widget'] = array(
+    '#type' => 'radios',
+    '#title' => t('Selection widget type'),
+    '#options' => array('radios' => t('Radio buttons'), 'select' => t('Drop-down menu')),
+    '#default_value' => $data ? $data->sel_widget : 'radios',
+  );
+  $form['prices']['sel_fs']['sel_options'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Selectable prices'),
+    '#description' => t('Enter one price per line, without currency symbols. If both selectable and arbitrary prices are enabled, an &ldquo;Other&rdquo; option will be automatically added to the end; when selected, the field to enter an arbitrary price will become available. If the value entered in the &ldquo;Default price&rdquo; field above matches one of these values, that option will be the default value of the price selection widget.'),
+    '#default_value' => $data ? implode("\n", array_keys($data->sel_options)) : '',
+    '#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
+    '#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
+  );
+
+  $form['prices']['arb_fs'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Arbitrary price'),
+  );
+  $form['prices']['arb_fs']['arbitrary'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable arbitrary variable prices'),
+    '#description' => t('When enabled, visitors will be able to enter any arbitrary price for this product, within the limits specified below.'),
+    '#default_value' => $data ? $data->arbitrary : TRUE,
+  );
+  $form['prices']['arb_fs']['price_minimum'] = array(
     '#type' => 'textfield',
     '#title' => t('Minimum price'),
     '#size' => 8,
@@ -313,7 +402,7 @@
     '#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
     '#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
   );
-  $form['prices']['price_maximum'] = array(
+  $form['prices']['arb_fs']['price_maximum'] = array(
     '#type' => 'textfield',
     '#title' => t('Maximum price'),
     '#size' => 8,
@@ -322,7 +411,7 @@
     '#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
     '#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
   );
-
+  
   $form['titles'] = array(
     '#type' => 'fieldset',
     '#title' => t('Add to cart form element titles'),
@@ -356,6 +445,26 @@
   return $form;
 }
 
+function uc_varprice_feature_form_validate($form, &$form_state) {
+  // Check for invalid text in the "Selectable prices" field
+  $form_state['values']['sel_options_arr'] = array();
+  foreach (array_unique(explode("\n", $form_state['values']['sel_options'])) as $value) {
+    // Be forgiving of spaces and blank lines
+    $value = trim($value);
+    if ($value !== '') {
+      if (!is_numeric($value)) {
+        form_set_error('sel_options', t('The value %val does not appear to be a number. Please enter only one number per line, without currency symbols.', array('%val' => $value)));
+      }
+      else {
+        // We want the keys of this array to be in the same format as the
+        // price_default field in the database (2 decimal points) so that we can
+        // properly select the default on the select widget.
+        $form_state['values']['sel_options_arr'][sprintf('%.2f', $value)] = uc_currency_format($value);
+      }
+    }
+  }
+}
+
 function uc_varprice_feature_form_submit($form, &$form_state) {
   // Build an array of Variable Price data from the form submission.
   $vp_data = array(
@@ -365,24 +474,41 @@
     'price_maximum' => $form_state['values']['price_maximum'],
     'add_to_cart_title' => $form_state['values']['override_add_to_cart_title'] ? $form_state['values']['add_to_cart_title'] : '',
     'amount_title' => $form_state['values']['override_amount_title'] ? $form_state['values']['amount_title'] : '',
-  );
+    'arbitrary' => intval($form_state['values']['arbitrary']),
+    'selectable' => intval($form_state['values']['selectable']),
+    'sel_widget' => $form_state['values']['sel_widget'],
+    'sel_options' => serialize($form_state['values']['sel_options_arr']),
+  );  
 
   // Build the product feature description.
   $description = array(
     t('Customers can specify a price for this product.'),
-    t('<b>Default price:</b> @price', array('@price' => uc_currency_format($vp_data['price_default']))),
+    t('<strong>Default price:</strong> @price', array('@price' => uc_currency_format($vp_data['price_default']))),
   );
-  if (!empty($vp_data['price_minimum'])) {
-    $description[] = t('<b>Minimum price:</b> @price', array('@price' => uc_currency_format($vp_data['price_minimum'])));
-  }
-  if (!empty($vp_data['price_maximum'])) {
-    $description[] = t('<b>Maximum price:</b> @price', array('@price' => uc_currency_format($vp_data['price_maximum'])));
+  if (!empty($vp_data['amount_title'])) {
+    $description[] = t('<strong>Amount field title:</strong> @title', array('@title' => $vp_data['amount_title']));
   }
-  if (!empty($vp_data['add_to_cart_title'])) {
-    $description[] = t('<b>Add to cart title:</b> @title', array('@title' => $vp_data['add_to_cart_title']));
+  if ($vp_data['selectable']) {
+    $description[] = t('Customers may select a price from a list.');
+    $description[] = t('<strong>Selectable prices:</strong> @prices', array('@prices' => implode(', ', $form_state['values']['sel_options_arr'])));
+    if ($form_state['values']['sel_widget'] === 'radios') {
+      $description[] = t('Prices are selected with <strong>radio buttons</strong>.');
+    }
+    elseif ($form_state['values']['sel_widget'] === 'select') {
+      $description[] = t('Prices are selected with a <strong>drop-down menu</strong>.');
+    }
   }
-  if (!empty($vp_data['amount_title'])) {
-    $description[] = t('<b>Amount field title:</b> @title', array('@title' => $vp_data['amount_title']));
+  if ($vp_data['arbitrary']) {
+    $description[] = t('Customers may enter an arbitrary price.');
+    if (!empty($vp_data['price_minimum'])) {
+      $description[] = t('<strong>Minimum price:</strong> @price', array('@price' => uc_currency_format($vp_data['price_minimum'])));
+    }
+    if (!empty($vp_data['price_maximum'])) {
+      $description[] = t('<strong>Maximum price:</strong> @price', array('@price' => uc_currency_format($vp_data['price_maximum'])));
+    }
+    if (!empty($vp_data['add_to_cart_title'])) {
+      $description[] = t('<strong>Add to cart title:</strong> @title', array('@title' => $vp_data['add_to_cart_title']));
+    }
   }
 
   // Save the basic product feature data.
@@ -415,7 +541,9 @@
 
 // Load the product feature data for a given node.
 function uc_varprice_product_load($nid) {
-  return db_fetch_object(db_query("SELECT vp.* FROM {uc_product_features} AS pf LEFT JOIN {uc_varprice_products} AS vp ON pf.pfid = vp.pfid WHERE pf.fid = 'varprice' AND pf.nid = %d", $nid));
+  $return = db_fetch_object(db_query("SELECT vp.* FROM {uc_product_features} AS pf LEFT JOIN {uc_varprice_products} AS vp ON pf.pfid = vp.pfid WHERE pf.fid = 'varprice' AND pf.nid = %d", $nid));
+  $return->sel_options = unserialize($return->sel_options);
+  return $return;
 }
 
 // Theme the Qty. field for products in the shopping cart with variable prices.
diff -uPr uc_varprice_orig/uc_varprice_show_arb.js uc_varprice/uc_varprice_show_arb.js
--- uc_varprice_orig/uc_varprice_show_arb.js	1969-12-31 16:00:00.000000000 -0800
+++ uc_varprice/uc_varprice_show_arb.js	2009-06-05 14:53:23.000000000 -0700
@@ -0,0 +1,41 @@
+// $Id$
+
+/**
+ * @file
+ * Customer-facing JavaScript for UC Variable Price.
+ */
+
+Drupal.behaviors.ucVarPriceShowArb = function(context) {
+  var varpriceSel = $('#edit-varprice-sel');
+  if (varpriceSel.length) {
+    // Using drop-down menu
+    if (varpriceSel.val() !== 'other') {
+      $('#edit-varprice-arb-wrapper:not(.processed)').addClass('processed').hide();
+    }
+    varpriceSel.change(function() {
+      if ($(this).val() === 'other') {
+        $('#edit-varprice-arb-wrapper').show('fast');
+        $('#edit-varprice-arb').focus();
+      }
+      else {
+        $('#edit-varprice-arb-wrapper').hide('fast');
+      }
+    });
+  }
+  else {
+    // Using radio buttons
+    if ($('input[name="varprice_sel"]:checked').val() !== 'other') {
+      $('#edit-varprice-arb-wrapper:not(.processed)').addClass('processed').hide();
+    }
+    $('input[name="varprice_sel"]').change(function() {
+      if ($('input[name="varprice_sel"]:checked').val() === 'other') {
+        $('#edit-varprice-arb-wrapper').show('fast');
+        $('#edit-varprice-arb').focus();
+      }
+      else {
+        $('#edit-varprice-arb-wrapper').hide('fast');
+      }
+    });
+    
+  }
+};
\ No newline at end of file
