Index: uc_attribute.install
--- uc_attribute.install Base (BASE)
+++ uc_attribute.install Locally Modified (Based On LOCAL)
@@ -19,6 +19,7 @@
         `oid` mediumint(9) NOT NULL auto_increment,
         `name` varchar(255) NOT NULL,
         `cost` decimal(10,2) NOT NULL,
+        `operator` tinyint(2) NOT NULL default 0,
         `price` decimal(10,2) NOT NULL,
         `weight` float NOT NULL,
         `ordering` tinyint(2) NOT NULL default 0,
@@ -37,6 +38,7 @@
         `pcid` varchar(32) NOT NULL,
         `oid` mediumint(9) NOT NULL,
         `cost` decimal(10,2) NOT NULL,
+        `operator` tinyint(2) NOT NULL default 0,
         `price` decimal(10,2) NOT NULL,
         `weight` float NOT NULL,
         `ordering` tinyint(2) NOT NULL default 0,
@@ -55,6 +57,7 @@
         `nid` mediumint(9) NOT NULL,
         `oid` mediumint(9) NOT NULL,
         `cost` decimal(10,2) NOT NULL,
+        `operator` tinyint(2) NOT NULL default 0,
         `price` decimal(10,2) NOT NULL,
         `weight` float NOT NULL,
         `ordering` tinyint(2) NOT NULL default 0,
@@ -82,6 +85,7 @@
         oid serial NOT NULL,
         name varchar(255) NOT NULL default '',
         cost decimal(10,2) NOT NULL default 0.00,
+        operator smallint NOT NULL default 0,
         price decimal(10,2) NOT NULL default 0.00,
         weight float NOT NULL default 0.0,
         ordering smallint NOT NULL default 0,
@@ -100,6 +104,7 @@
         pcid varchar(32) NOT NULL default '',
         oid integer NOT NULL default 0,
         cost decimal(10,2) NOT NULL default 0.00,
+        operator smallint NOT NULL default 0,
         price decimal(10,2) NOT NULL default 0.00,
         weight float NOT NULL default 0.0,
         ordering smallint NOT NULL default 0,
@@ -118,6 +123,7 @@
         nid integer NOT NULL default 0,
         oid integer NOT NULL default 0,
         cost decimal(10,2) NOT NULL default 0.00,
+        operator smallint NOT NULL default 0,
         price decimal(10,2) NOT NULL default 0.00,
         weight float NOT NULL default 0,
         ordering smallint NOT NULL default 0,
@@ -336,3 +342,21 @@
   }
   return $ret;
 }
+
+function uc_attribute_update_11() {
+  $ret = array();
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("ALTER TABLE {uc_attribute_options} ADD COLUMN operator tinyint(2) NOT NULL default 0 AFTER cost");
+      $ret[] = update_sql("ALTER TABLE {uc_class_attribute_options} ADD COLUMN operator tinyint(2) NOT NULL default 0 AFTER cost");
+      $ret[] = update_sql("ALTER TABLE {uc_product_options} ADD COLUMN operator tinyint(2) NOT NULL default 0 AFTER cost");
+    break;
+    case 'pgsql':
+      db_add_column($ret, 'uc_attribute_options', 'operator', 'smallint', array('not null' => true, 'default' => 0));
+      db_add_column($ret, 'uc_class_attribute_options', 'operator', 'smallint', array('not null' => true, 'default' => 0));
+      db_add_column($ret, 'uc_product_options', 'operator', 'smallint', array('not null' => true, 'default' => 0));
+    break;
+  }
+  return $ret;
+}
Index: uc_attribute.module
--- uc_attribute.module Base (BASE)
+++ uc_attribute.module Locally Modified (Based On LOCAL)
@@ -233,11 +233,11 @@
           case 'mysqli':
           case 'mysql':
             db_query("INSERT IGNORE INTO {uc_product_attributes} (nid, aid, ordering, required, display, default_option) SELECT %d, aid, ordering, required, display, default_option FROM {uc_class_attributes} WHERE pcid = '%s'", $node->nid, $node->type);
-            db_query("INSERT IGNORE INTO {uc_product_options} (nid, oid, cost, price, weight, ordering) SELECT %d, oid, cost, price, weight, ordering FROM {uc_class_attribute_options} WHERE pcid = '%s'", $node->nid, $node->type);
+            db_query("INSERT IGNORE INTO {uc_product_options} (nid, oid, cost, operator, price, weight, ordering) SELECT %d, oid, cost, operator, price, weight, ordering FROM {uc_class_attribute_options} WHERE pcid = '%s'", $node->nid, $node->type);
             break;
           case 'pgsql':
             db_query("INSERT INTO {uc_product_attributes} (nid, aid, ordering, required, display, default_option) SELECT %d, aid, ordering, required, display, default_option FROM {uc_class_attributes} WHERE pcid = '%s'", $node->nid, $node->type);
-            db_query("INSERT INTO {uc_product_options} (nid, oid, cost, price, weight, ordering) SELECT %d, oid, cost, price, weight, ordering FROM {uc_class_attribute_options} WHERE pcid = '%s'", $node->nid, $node->type);
+            db_query("INSERT INTO {uc_product_options} (nid, oid, cost, operator, price, weight, ordering) SELECT %d, oid, cost, operator, price, weight, ordering FROM {uc_class_attribute_options} WHERE pcid = '%s'", $node->nid, $node->type);
             break;
         }
 
@@ -303,7 +303,7 @@
 }
 
 /**
- * Implementation of hook_cart_item().
+ * FIXME Implementation of hook_cart_item().
  */
 function uc_attribute_cart_item($op, &$item) {
   switch ($op) {
@@ -314,11 +314,10 @@
       $op_weight = 0;
       foreach ($item->options as $option) {
         $op_costs += $option['cost'];
-        $op_prices += $option['price'];
+        $item->price = _uc_attribute_adjust_price($item->price, $option['operator'], $option['price']);
         $op_weight += $option['weight'];
       }
       $item->cost += $op_costs;
-      $item->price += $op_prices;
       $item->weight += $op_weight;
       if (!empty($item->data['model'])) {
         $item->model = $item->data['model'];
@@ -521,8 +520,16 @@
       l(t('edit'), 'admin/store/products/attributes/'. $aid .'/options/'. $key .'/edit'),
       l(t('delete'), 'admin/store/products/attributes/'. $aid .'/options/'. $key .'/delete'),
     );
-    $rows[] = array($data->name, $data->cost, $data->price, $data->weight, $data->ordering, implode(' ', $ops));
+
+    if ($data->price == 0) {
+      $price = $data->price;
   }
+    else {
+      // Only format this string if the default price is not zero.
+      $price = _uc_attribute_get_operator($data->operator) . $data->price;
+    }
+    $rows[] = array($data->name, $data->cost, $price, $data->weight, $data->ordering, implode(' ', $ops));
+  }
   if (count($rows) == 0) {
     $rows[] = array(
       array('data' => t('No options for this attribute have been added yet.'), 'colspan' => '6')
@@ -593,17 +600,27 @@
     '#default_value' => $option->cost,
     '#weight' => 1,
   );
+  $form['adjustments']['operator'] = array(
+    '#type' => 'select',
+    '#title' => t('Price'),
+    '#options' => _uc_attribute_option_operators(),
+    '#prefix' => '<table><tr><td>',
+    '#suffix' => '</td>',
+    '#default_value' => $option->operator,
+    '#weight' => 2,
+  );
   $form['adjustments']['price'] = array(
     '#type' => 'textfield',
-    '#title' => t('Price'),
+    '#prefix' => '<td>',
+    '#suffix' => '</td></tr></table>',
     '#default_value' => $option->price,
-    '#weight' => 2,
+    '#weight' => 3,
   );
   $form['adjustments']['weight'] = array(
     '#type' => 'textfield',
     '#title' => t('Weight'),
     '#default_value' => $option->weight,
-    '#weight' => 3,
+    '#weight' => 4,
   );
 
   $form['submit'] = array(
@@ -638,12 +655,12 @@
  */
 function uc_attribute_option_form_submit($form_id, $form_values) {
   if (!isset($form_values['oid'])) {
-    db_query("INSERT INTO {uc_attribute_options} (aid, name, cost, price, weight, ordering) VALUES (%d, '%s', %f, %f, %f, %d)",
-      $form_values['aid'], $form_values['name'], $form_values['cost'], $form_values['price'], $form_values['weight'], $form_values['ordering']);
+    db_query("INSERT INTO {uc_attribute_options} (aid, name, cost, operator, price, weight, ordering) VALUES (%d, '%s', %f, %d, %f, %f, %d)",
+      $form_values['aid'], $form_values['name'], $form_values['cost'], $form_values['operator'], $form_values['price'], $form_values['weight'], $form_values['ordering']);
   }
   else {
-    db_query("UPDATE {uc_attribute_options} SET name = '%s', cost = %f, price = %f, weight = %f, ordering = %d WHERE aid = %d AND oid = %d",
-      $form_values['name'], $form_values['cost'], $form_values['price'], $form_values['weight'], $form_values['ordering'], $form_values['aid'], $form_values['oid']);
+    db_query("UPDATE {uc_attribute_options} SET name = '%s', operator = %d, cost = %f, price = %f, weight = %f, ordering = %d WHERE aid = %d AND oid = %d",
+      $form_values['name'], $form_values['cost'], $form_values['operator'], $form_values['price'], $form_values['weight'], $form_values['ordering'], $form_values['aid'], $form_values['oid']);
   }
   return 'admin/store/products/attributes/'. $form_values['aid'] .'/options';
 }
@@ -871,7 +888,7 @@
       // Enable all options for added attributes.
       $attribute = uc_attribute_load($aid);
       foreach ($attribute->options as $option) {
-        db_query("INSERT INTO $opt_table ($id, oid, cost, price, weight, ordering) VALUES ($sql_type, %d, %f, %f, %f, %d)", $form_values['id'], $option->oid, $option->cost, $option->price, $option->weight, $option->ordering);
+      	db_query("INSERT INTO $opt_table ($id, oid, cost, operator, price, weight, ordering) VALUES ($sql_type, %d, %f, %d, %f, %f, %d)", $form_values['id'], $option->oid, $option->cost, $option->operator, $option->price, $option->weight, $option->ordering);
       }
       // Make the first option (if any) the default.
       $option = reset($attribute->options);
@@ -938,7 +955,7 @@
     if ($base_attr->options) {
       $options = array();
 
-      $result = db_query("SELECT ao.aid, ao.oid, ao.name, ao.cost AS default_cost, ao.price AS default_price, ao.weight AS default_weight, ao.ordering AS default_ordering, po.cost, po.price, po.weight, po.ordering, po.ordering IS NULL AS null_order FROM {uc_attribute_options} AS ao LEFT JOIN $table AS po ON ao.oid = po.oid AND po.$id_type = $sql_type WHERE aid = %d ORDER BY null_order, po.ordering, default_ordering, ao.name", $id, $attribute->aid);
+      $result = db_query("SELECT ao.aid, ao.oid, ao.name, ao.cost AS default_cost, ao.price AS default_price, ao.weight AS default_weight, ao.ordering AS default_ordering, po.cost, po.operator, po.price, po.weight, po.ordering, po.ordering IS NULL AS null_order FROM {uc_attribute_options} AS ao LEFT JOIN $table AS po ON ao.oid = po.oid AND po.$id_type = $sql_type WHERE aid = %d ORDER BY null_order, po.ordering, default_ordering, ao.name", $id, $attribute->aid);
       while ($option = db_fetch_object($result)) {
         $oid = $option->oid;
         $options[$oid] = '';
@@ -953,6 +970,11 @@
           '#default_value' => is_null($option->cost) ? $option->default_cost : $option->cost,
           '#size' => 6,
         );
+        $form['attributes'][$aid]['options'][$oid]['operator'] = array(
+          '#type' => 'select',
+          '#options' => _uc_attribute_option_operators(),
+          '#default_value' => $option->operator,
+        );
         $form['attributes'][$aid]['options'][$oid]['price'] = array(
           '#type' => 'textfield',
           '#default_value' => is_null($option->price) ? $option->default_price : $option->price,
@@ -1011,7 +1033,7 @@
  * @ingroup themeable
  */
 function theme_uc_object_options_form($form) {
-  $header = array(t('Attribute'), t('Options'), t('Default'), t('Cost'), t('Price'), t('Weight'), t('Order'));
+  $header = array(t('Attribute'), t('Options'), t('Default'), t('Cost'), t('Operator'), t('Price'), t('Weight'), t('Order'));
 
   foreach (element_children($form['attributes']) as $key) {
     $row = array();
@@ -1023,12 +1045,13 @@
         $row[] = drupal_render($form['attributes'][$key]['options'][$oid]['select']);
         $row[] = drupal_render($form['attributes'][$key]['default'][$oid]);
         $row[] = drupal_render($form['attributes'][$key]['options'][$oid]['cost']);
+        $row[] = drupal_render($form['attributes'][$key]['options'][$oid]['operator']);
         $row[] = drupal_render($form['attributes'][$key]['options'][$oid]['price']);
         $row[] = drupal_render($form['attributes'][$key]['options'][$oid]['weight']);
         $row[] = drupal_render($form['attributes'][$key]['options'][$oid]['ordering']);
 
         if (!$first) {
-          $row = array_pad($row, -7, '');
+          $row = array_pad($row, -8, '');
         }
         else {
           $first = FALSE;
@@ -1104,8 +1127,8 @@
         db_query("DELETE FROM $opt_table WHERE $id = $sql_type AND oid = %d", $form_values['id'], $oid);
 
         if ($option['select']) {
-          db_query("INSERT INTO $opt_table ($id, oid, cost, price, weight, ordering) VALUES ($sql_type, %d, %f, %f, %f, %d)",
-                   $form_values['id'], $oid, $option['cost'], $option['price'], $option['weight'], $option['ordering']);
+          db_query("INSERT INTO $opt_table ($id, oid, cost, operator, price, weight, ordering) VALUES ($sql_type, %d, %f, %d, %f, %f, %d)",
+                   $form_values['id'], $oid, $option['cost'], $option['operator'], $option['price'], $option['weight'], $option['ordering']);
         }
         else if ($form_values['type'] == 'product') {
           $aid = $attribute['aid'];
@@ -1295,11 +1318,11 @@
     switch ($type) {
       case 'product':
         $attribute = db_fetch_object(db_query("SELECT a.aid, a.name, a.ordering AS default_ordering, a.required AS default_required, a.display AS default_display, a.description, pa.default_option, pa.required, pa.ordering, pa.display FROM {uc_attributes} AS a LEFT JOIN {uc_product_attributes} AS pa ON a.aid = pa.aid AND pa.nid = %d WHERE a.aid = %d", $nid, $attr_id));
-        $result = db_query("SELECT po.nid, po.oid, po.cost, po.price, po.weight, po.ordering, ao.name, ao.aid FROM {uc_product_options} AS po LEFT JOIN {uc_attribute_options} AS ao ON po.oid = ao.oid AND nid = %d WHERE aid = %d ORDER BY po.ordering, ao.name", $nid, $attr_id);
+        $result = db_query("SELECT po.nid, po.oid, po.cost, po.operator, po.price, po.weight, po.ordering, ao.name, ao.aid FROM {uc_product_options} AS po LEFT JOIN {uc_attribute_options} AS ao ON po.oid = ao.oid AND nid = %d WHERE aid = %d ORDER BY po.ordering, ao.name", $nid, $attr_id);
         break;
       case 'class':
         $attribute = db_fetch_object(db_query("SELECT a.aid, a.name, a.ordering AS default_ordering, a.required AS default_required, a.display AS default_display, a.description, ca.default_option, ca.required, ca.ordering, ca.display FROM {uc_attributes} AS a LEFT JOIN {uc_class_attributes} AS ca ON a.aid = ca.aid AND ca.pcid = '%s' WHERE a.aid = %d", $nid, $attr_id));
-        $result = db_query("SELECT co.pcid, co.oid, co.cost, co.price, co.weight, co.ordering, ao.name, ao.aid FROM {uc_class_attribute_options} AS co LEFT JOIN {uc_attribute_options} AS ao ON co.oid = ao.oid AND co.pcid = '%s' WHERE ao.aid = %d ORDER BY co.ordering, ao.name", $nid, $attr_id);
+        $result = db_query("SELECT co.pcid, co.oid, co.cost, co.operator, co.price, co.weight, co.ordering, ao.name, ao.aid FROM {uc_class_attribute_options} AS co LEFT JOIN {uc_attribute_options} AS ao ON co.oid = ao.oid AND co.pcid = '%s' WHERE ao.aid = %d ORDER BY co.ordering, ao.name", $nid, $attr_id);
         break;
       default:
         $attribute = db_fetch_object(db_query("SELECT * FROM {uc_attributes} WHERE aid = %d", $attr_id));
@@ -1446,6 +1469,7 @@
           'oid' => 0,
           'name' => $oid,
           'cost' => 0,
+          'operator' => 0,
           'price' => 0,
           'weight' => 0,
         );
@@ -1483,12 +1507,12 @@
       foreach ($attribute->options as $option) {
         switch (variable_get('uc_attribute_option_price_format', 'adjustment')) {
           case 'total':
-            $display_price = in_array($relation->aid, $priced_attributes) ? ', '. uc_currency_format(($node->sell_price + $option->price) * $qty) : '';
+            $display_price = in_array($relation->aid, $priced_attributes) ? ', '. uc_currency_format(_uc_attribute_adjust_price($node->sell_price, $option->operator, $option->price) * $qty) : '';
             if (count($priced_attributes) == 1) {
               break;
             }
           case 'adjustment':
-            $display_price = ($option->price != 0 ? ', '. ($option->price > 0 ? '+' : '') . uc_currency_format($option->price * $qty) : '');
+            $display_price = ($option->price != 0 ? ', '. ($option->price > 0 ? _uc_attribute_get_operator($option->operator) : '') . uc_currency_format($option->price * $qty) : '');
             break;
           case 'none':
           default:
@@ -1538,6 +1562,52 @@
   );
 }
 
+// Returns an array of operators used when creating options.
+function _uc_attribute_option_operators() {
+  return array(
+    0 => '+',
+    1 => '-',
+    2 => '*',
+    3 => '/',
+    );
+}
+
+// Returns an array of operators used when creating options.
+function _uc_attribute_get_operator($op) {
+  $operators = _uc_attribute_option_operators();
+
+  return $operators[$op];
+}
+
+// Adjusts the price based on the operator and price adjustment
+function _uc_attribute_adjust_price($price, $op, $adj) {
+  $newprice = 0.0;
+
+  switch ($op) {
+    case 0:
+      $newprice = $price + $adj;
+      break;
+
+    case 1:
+      $newprice = $price - $adj;
+      break;
+
+    case 2:
+      $newprice = $price * $adj;
+      break;
+
+    case 3:
+      $newprice = $price / $adj;
+      break;
+
+    default:
+      $newprice = $price + $adj;
+      break;
+  }
+
+  return $newprice;
+}
+
 /**
  * Get the price affecting attributes for a product
  *

