--- spritemenu.module
+++ (clipboard)
@@ -9,6 +9,7 @@
  */
 
 define('SPRITEMENU_DEFAULT_EXTRACSS', 'ul.primary-links li');
+define('SPRITEMENU_STATES', 'active,visited,hover,link');
 
 function _spritemenu_css_path() {
   $directory = file_directory_path() .'/'. variable_get('spritemenu_path', 'spritemenu');
@@ -33,67 +34,51 @@
   
   $css = _spritemenu_css_filepath();
   $result = db_query("SELECT * FROM {spritemenu}");
+  $states = explode(',', SPRITEMENU_STATES);
 
   while ($spritemenu = db_fetch_object($result)) {
-    if (!$f) {
+    if (!(isset($f) && $f)) {
       $f = fopen($css, 'w+');
     }
 
     $img = basename($spritemenu->filepath);
     $css = '';
-
-    // Link
-    $position_link = $spritemenu->link;
-    $css_selectors = array();
-    foreach ($selectors as $selector) {
-      if ($selector) {
-        $selector .= ' ';
-      }
-      $css_selectors[] = "{$selector}a.spritemenu-{$spritemenu->mid},\n{$selector}a.spritemenu-{$spritemenu->mid}:link";
-    }
-    $css .= implode($css_selectors, ",\n") . " {\n  text-indent: -9999px; \n  text-decoration: none; \n  width: 100%; \n  background: transparent url($img) no-repeat scroll $position_link;\n}\n";
-
-    // Visited
-    $position_visited = $spritemenu->visited;
-    if (!$postition_visited) {
-      $position_visited = $position_link;
-    }
-    $css_selectors = array();
-    foreach ($selectors as $selector) {
-      if ($selector) {
-        $selector .= ' ';
-      }
-      $css_selectors[] = "{$selector}a.spritemenu-{$spritemenu->mid}:visited";
-    }
-    $css .= implode($css_selectors, ",\n") . " {\n  text-indent: -9999px; \n  text-decoration: none; \n  width: 100%; \n  background: transparent url($img) no-repeat scroll $position_visited;\n}\n";
-
-    // Hover
-    $position_hover = $spritemenu->hover;
-    if (!$position_hover) {
-      $position_hover = $position_link;
-    }
-    $css_selectors = array();
-    foreach ($selectors as $selector) {
-      if ($selector) {
-        $selector .= ' ';
+    $data = unserialize($spritemenu->data);
+    foreach($states as $state) {
+      $state_enabled = $data[$state . '_enabled'];
+      if($state_enabled) {
+        $state_position = $data[$state . '_position'];
+        $state_height = $data[$state . '_height'];
+        $state_width = $data[$state . '_width'];
+        $css_selectors = array();
+      
+        foreach($selectors as $selector) {
+          if(isset($select) && $select) {
+            $selector .= ' ';
+          }
+          $css_selectors[] = "{$selector} a.spritemenu-{$spritemenu->mid},\n{$selector} a.spritemenu-{$spritemenu->mid}:$state,\n{$selector} span.spritemenu-{$spritemenu->mid},\n{$selector} span.spritemenu-{$spritemenu->mid}:$state";
+        }
+        
+        $display = '';
+        if(is_numeric($state_width)) {
+          $state_width .= 'px';
+          $display = 'display: block;';
+        }
+        if(is_numeric($state_height)) {
+          $state_height .= 'px';
+          $display = 'display: block;';
+        }
+        
+        $css .= implode($css_selectors, ",\n") . '{
+          text-indent: -9999px;
+          text-decoration: none;
+          width: ' . $state_width . ';
+          ' . $display . '
+          height: ' . $state_height . ';
+          background: transparent url(' . $img . ') no-repeat scroll ' . $state_position . ';
+        }';
       }
-      $css_selectors[] = "{$selector}a.spritemenu-{$spritemenu->mid}:hover";
     }
-    $css .= implode($css_selectors, ",\n") . " {\n  text-indent: -9999px; \n  text-decoration: none; \n  width: 100%; \n  background: transparent url($img) no-repeat scroll $position_hover;\n}\n";
-
-    // Active
-    $position_active = $spritemenu->active;
-    if (!$position_active) {
-      $position_active = $position_link;
-    }
-    $css_selectors = array();
-    foreach ($selectors as $selector) {
-      if ($selector) {
-        $selector .= ' ';
-      }
-      $css_selectors[] = "{$selector}a.spritemenu-{$spritemenu->mid}.active";
-    }
-    $css .= implode($css_selectors, ",\n") . " {\n  text-indent: -9999px; \n  text-decoration: none; \n  width: 100%; \n  background: transparent url($img) no-repeat scroll $position_active;\n}\n";
     fwrite($f, $css);
   }
   
@@ -131,50 +116,36 @@
   else {
     $filepath = $spritemenu->filepath;
   }
-  if ($file || $spritemenu && ($spritemenu->link != $form_state['values']['spritemenu']['link'] || $spritemenu->visited != $form_state['values']['spritemenu']['visited'] || $spritemenu->hover != $form_state['values']['spritemenu']['hover'] || $spritemenu->active != $form_state['values']['spritemenu']['active'])) {
+  if($form_state['values']['spritemenu']['image_remove']) {
+    // check if the user wants to remove the image
+    if ($form_state['values']['spritemenu']['image_remove']) {
+      db_query("DELETE FROM {spritemenu} WHERE mid = %d", $mid);
+      file_delete($spritemenu->filepath);
+      $build = TRUE;
+    }
+  }
+  else if ($file || $spritemenu) {
+    $states = explode(',', SPRITEMENU_STATES);
+    $fields = array();
+    foreach($states as $state) {
+      $fields[$state . '_position'] = $form_state['values']['spritemenu'][$state][$state . '_position'];
+      $fields[$state . '_height'] = $form_state['values']['spritemenu'][$state][$state . '_height'];
+      $fields[$state . '_width'] = $form_state['values']['spritemenu'][$state][$state . '_width'];
+      $fields[$state . '_enabled'] = $form_state['values']['spritemenu'][$state][$state . '_enabled'];
+    }
+    $fields_serialized = serialize($fields);
+    
     if (!$spritemenu) {
-      db_query(
-        "INSERT INTO {spritemenu}
-        (mid, path, filepath, link, visited, hover, active)
-        VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s')",
-        $mid,
-        '',
-        //$form['#post']['path'] ? $form['#post']['path'] : $form['path']['#value'],
-        $filepath,
-        $form_state['values']['spritemenu']['link'],
-        $form_state['values']['spritemenu']['visited'],
-        $form_state['values']['spritemenu']['hover'],
-        $form_state['values']['spritemenu']['active']
-      );
+    db_query("INSERT INTO {spritemenu} (mid, path, filepath, data) VALUES (%d, '%s', '%s', '%s')", $mid, '', $filepath, $fields_serialized);
     }
     else {
       if ($file && $spritemenu->filepath && $spritemenu->filepath != $filepath) {
         file_delete($spritemenu->filepath);
       }
-      db_query(
-        "UPDATE {spritemenu} SET
-        path = '%s', filepath = '%s', link = '%s', visited = '%s', hover = '%s', active = '%s'
-        WHERE mid = %d",
-        '',
-        //$form['#post']['path'] ? $form['#post']['path'] : $form['path']['#value'],
-        $filepath,
-        $form_state['values']['spritemenu']['link'],
-        $form_state['values']['spritemenu']['visited'],
-        $form_state['values']['spritemenu']['hover'],
-        $form_state['values']['spritemenu']['active'],
-        $mid
-      );
+      db_query("UPDATE {spritemenu} SET path = '%s', filepath = '%s', data = '%s' WHERE mid = %d", '', $filepath, $fields_serialized, $mid);
     }
     $build = TRUE;
   }
-  else {
-    // check if the user wants to remove the image
-    if ($form_state['values']['spritemenu']['image_remove']) {
-      db_query("DELETE FROM {spritemenu} WHERE mid = %d", $mid);
-      file_delete($spritemenu->filepath);
-      $build = TRUE;
-    }
-  }
 
   if ($build) {
     drupal_set_message(t('Sprite Graphic Menu: Information saved and CSS rebuilt. Please Ctrl+Refresh the page to reflect the changes.'));
@@ -212,6 +183,7 @@
     $form['#attributes'] = array('enctype' => 'multipart/form-data');
 
     $spritemenu = db_fetch_object(db_query("SELECT * FROM {spritemenu} WHERE mid = %d", $mid));
+    $data = unserialize($spritemenu->data);
 
     $form['spritemenu'] = array(
       '#type' => 'fieldset',
@@ -238,32 +210,57 @@
       '#type' => 'file',
       '#title' => t('Image file'),
      );
-
-    $form['spritemenu']['link'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Link'),
-      '#description' => t('Enter the CSS positioning corresponding to the sprite of the image you want to use.'),
-      '#default_value' => ($spritemenu->link ? $spritemenu->link : 'left top'),
-      '#required' => TRUE,
-     );
-    $form['spritemenu']['visited'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Visited'),
-      '#description' => t('Enter the CSS positioning corresponding to the sprite of the image you want to use.'),
-      '#default_value' => ($spritemenu->visited ? $spritemenu->visited: ''),
-     );
-    $form['spritemenu']['hover'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Hover'),
-      '#description' => t('Enter the CSS positioning corresponding to the sprite of the image you want to use.'),
-      '#default_value' => ($spritemenu->hover ? $spritemenu->hover: 'left bottom'),
-     );
-    $form['spritemenu']['active'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Active'),
-      '#description' => t('Enter the CSS positioning corresponding to the sprite of the image you want to use. This uses the active class of the link, not the CSS :active pseudo class.'),
-      '#default_value' => ($spritemenu->active ? $spritemenu->active: ''),
-     );
+     
+     $states = explode(',', SPRITEMENU_STATES);
+     $weight = 5;
+     foreach($states as $state) {       
+       $state_position = $state . '_position';
+       $state_width = $state . '_width';
+       $state_height = $state . '_height';
+       $state_enabled = $state . '_enabled';
+       
+       // pop out first option
+       $collapsed = TRUE;
+       if($weight == 5) {
+         $collapsed = FALSE;
+       }
+       $form['spritemenu'][$state] = array(
+         '#type' => 'fieldset',
+         '#title' => t($state),
+         '#weight' => $weight,
+         '#collapsible' => TRUE,
+         '#collapsed' => $collapsed,
+       );
+       $form['spritemenu'][$state][$state_enabled] = array(
+          '#type' => 'checkbox',
+          '#title' => t('Enabled'),
+          '#default_value' => ($data[$state_enabled] ? $data[$state_enabled] : '0'),
+          '#required' => TRUE,
+         );
+       $form['spritemenu'][$state][$state_position] = array(
+         '#type' => 'textfield',
+         '#title' => t('CSS background position'),
+         '#description' => t('Enter the CSS positioning corresponding to the sprite of the image you want to use.'),
+         '#default_value' => ($data[$state_position] ? $data[$state_position] : 'left top'),
+         '#required' => TRUE,
+        );
+        $form['spritemenu'][$state][$state_width] = array(
+          '#type' => 'textfield',
+          '#title' => t('Width'),
+          '#description' => t('Enter the width in pixels of the element corresponding to the sprite of the image you want to use.'),
+          '#default_value' => ($data[$state_width] ? $data[$state_width] : 'auto'),
+          '#required' => TRUE,
+       );
+       $form['spritemenu'][$state][$state_height] = array(
+         '#type' => 'textfield',
+         '#title' => t('Height'),
+         '#description' => t('Enter the height in pixels of the element corresponding to the sprite of the image you want to use.'),
+         '#default_value' => ($data[$state_height] ? $data[$state_height] : 'auto'),
+         '#required' => TRUE,
+       );
+       
+       $weight++;
+    }
   }
 
   if ($form_id == 'menu_configure') {
@@ -291,29 +288,40 @@
 }
 
 function spritemenu_menu_link_alter(&$item, $menu) {
-  $spritemenu = db_fetch_object(db_query("SELECT * FROM {spritemenu} WHERE mid = %d", $item['mlid']));
-  $match = preg_match("/spritemenu-([0-9]*)(\W|$)/", $item['options']['attributes']['class']);
-  if ($spritemenu) {
-    if ($match) {
-      $class = preg_replace("/spritemenu-([0-9]*)/", 'spritemenu-' . $item['mlid'], $item['options']['attributes']['class']);
+  if(isset($item['mlid'])) {
+    $spritemenu = db_fetch_object(db_query("SELECT * FROM {spritemenu} WHERE mid = %d", $item['mlid']));
+    $class = '';
+    if(isset($item['options']['attributes']['class'])) {
+      $class = $item['options']['attributes']['class'];
+    }
+    $match = preg_match("/spritemenu-([0-9]*)(\W|$)/", $class);
+
+    if($spritemenu && $match) {
+      $class = preg_replace("/spritemenu-([0-9]*)/", 'spritemenu-' . $item['mlid'], $class);
+    }
+    else if($spritemenu) {
+      $class = 'spritemenu-' . $item['mlid'] . ' spritemenu ' . $class;
+    }
+    // Remove the class if the spritemenu info was removed
+    else if($match) {
+      $class = preg_replace("/spritemenu-([0-9]*)/", '', $class);
+      $class = str_replace("spritemenu", '', $class);
     }
-    else {
-      $class .= ' spritemenu-' . $item['mlid'];
-    }
-  }
-  // Remove the class if the spritemenu info was removed
-  else if ($match) {
-    $class = preg_replace("/spritemenu-([0-9]*)/", '', $item['options']['attributes']['class']);
-  }
-
-  if (!is_null($class)) {
-    if ($class == '' || $class == ' ') {
-      unset($item['options']['attributes']['class']);
-    }
-    else {
-      $item['options']['attributes']['class'] = $class;
+  
+    // remove extra spaces
+    $class_array = explode(' ', $class);
+    $class_string = '';
+    foreach($class_array as $class_value) {
+      $trimmed = trim($class_value);
+      if(strlen($trimmed) > 0) {
+        $class_string .= $trimmed . ' ';  
+      }
     }
+    trim($class_string);
+    $item['options']['attributes']['class'] = $class_string;
   }
+  trim($class_string);
+  $item['options']['attributes']['class'] = $class_string;
 }
 
 function spritemenu_menu() {
@@ -353,4 +361,8 @@
 
 function spritemenu_clean_orphaned() {
   return confirm_form($form, t('Are you sure you want to clean the spritemenu orphaned items?'), 'admin/reports/status');
-}
\ No newline at end of file
+}
+
+function _spritemenu_trim_value(&$value) {
+  $value = trim($value);
+}
