Index: /trunk/admin/configuration.php
===================================================================
--- /trunk/admin/configuration.php	(revision 14220)
+++ /trunk/admin/configuration.php	(revision 14221)
@@ -176,30 +176,5 @@
     case 'sizes' :
     {
-      $fields = array(
-        'original_resize',
-        'original_resize_maxwidth',
-        'original_resize_maxheight',
-        'original_resize_quality',
-        );
-
-      $updates = array();
-      
-      foreach ($fields as $field)
-      {
-        $value = !empty($_POST[$field]) ? $_POST[$field] : null;
-        $form_values[$field] = $value;
-        $updates[$field] = $value;
-      }
-
-      save_upload_form_config($updates, $page['errors']);
-  
-      if (count($page['errors']) == 0)
-      {
-        array_push(
-          $page['infos'],
-          l10n('Your configuration settings are saved')
-          );
-      }
-
+      include(PHPWG_ROOT_PATH.'admin/include/configuration_sizes_process.inc.php');        
       break;
     }
@@ -429,67 +404,80 @@
   case 'sizes' :
   {
-    $template->assign(
-      'sizes',
-      array(
-        'original_resize_maxwidth' => $conf['original_resize_maxwidth'],
-        'original_resize_maxheight' => $conf['original_resize_maxheight'],
-        'original_resize_quality' => $conf['original_resize_quality'],
-        )
-      );
-    
-    foreach ($sizes_checkboxes as $checkbox)
-    {
-      $template->append(
+    // we only load the derivatives if it was not already loaded: it occurs
+    // when submitting the form and an error remains
+    if (!isset($page['sizes_loaded_in_tpl']))
+    {
+      $template->assign(
         'sizes',
         array(
-          $checkbox => $conf[$checkbox]
-          ),
-        true
+          'original_resize_maxwidth' => $conf['original_resize_maxwidth'],
+          'original_resize_maxheight' => $conf['original_resize_maxheight'],
+          'original_resize_quality' => $conf['original_resize_quality'],
+          )
         );
-    }
-
-    // derivaties = multiple size
-    $enabled = ImageStdParams::get_defined_type_map();
-    $disabled = @unserialize(@$conf['disabled_derivatives']);
-    if ($disabled === false)
-    {
-      $disabled = array();
-    }
-
-    $tpl_vars = array();
-    foreach(ImageStdParams::get_all_types() as $type)
-    {
-      $tpl_var = array();
       
-      $tpl_var['must_square'] = ($type==IMG_SQUARE ? true : false);
-      $tpl_var['must_enable'] = ($type==IMG_SQUARE || $type==IMG_THUMB)? true : false;
+      foreach ($sizes_checkboxes as $checkbox)
+      {
+        $template->append(
+          'sizes',
+          array(
+            $checkbox => $conf[$checkbox]
+            ),
+          true
+          );
+      }
       
-      if ($params=@$enabled[$type])
-      {
-        $tpl_var['enabled']=true;
-      }
-      else
-      {
-        $tpl_var['enabled']=false;
-        $params=@$disabled[$type];
-      }
-      
-      if ($params)
-      {
-        list($tpl_var['w'],$tpl_var['h']) = $params->sizing->ideal_size;
-        if ( ($tpl_var['crop'] = round(100*$params->sizing->max_crop)) > 0)
+      // derivatives = multiple size
+      $enabled = ImageStdParams::get_defined_type_map();
+      $disabled = @unserialize(@$conf['disabled_derivatives']);
+      if ($disabled === false)
+      {
+        $disabled = array();
+      }
+
+      $common_quality = 50;
+
+      $tpl_vars = array();
+      foreach(ImageStdParams::get_all_types() as $type)
+      {
+        $tpl_var = array();
+        
+        $tpl_var['must_square'] = ($type==IMG_SQUARE ? true : false);
+        $tpl_var['must_enable'] = ($type==IMG_SQUARE || $type==IMG_THUMB)? true : false;
+        
+        if ($params = @$enabled[$type])
         {
-          list($tpl_var['minw'],$tpl_var['minh']) = $params->sizing->min_size;
+          $tpl_var['enabled'] = true;
         }
         else
         {
-          $tpl_var['minw'] = $tpl_var['minh'] = "";
-        }
-        $tpl_var['sharpen'] = $params->sharpen;
-        $tpl_var['quality'] = $params->quality;
-      }
-      $tpl_vars[$type]=$tpl_var;
-    }
-    $template->assign('derivatives', $tpl_vars);
+          $tpl_var['enabled']=false;
+          $params=@$disabled[$type];
+        }
+        
+        if ($params)
+        {
+          list($tpl_var['w'],$tpl_var['h']) = $params->sizing->ideal_size;
+          if ( ($tpl_var['crop'] = round(100*$params->sizing->max_crop)) > 0)
+          {
+            list($tpl_var['minw'],$tpl_var['minh']) = $params->sizing->min_size;
+          }
+          else
+          {
+            $tpl_var['minw'] = $tpl_var['minh'] = "";
+          }
+          $tpl_var['sharpen'] = $params->sharpen;
+          $tpl_var['quality'] = $params->quality;
+          
+          if ($params->quality > $common_quality and $tpl_var['enabled'])
+          {
+            $common_quality = $params->quality;
+          }
+        }
+        $tpl_vars[$type]=$tpl_var;
+      }
+      $template->assign('derivatives', $tpl_vars);
+      $template->assign('resize_quality', $common_quality);
+    }
 
     break;
Index: /trunk/admin/include/configuration_sizes_process.inc.php
===================================================================
--- /trunk/admin/include/configuration_sizes_process.inc.php	(revision 14221)
+++ /trunk/admin/include/configuration_sizes_process.inc.php	(revision 14221)
@@ -0,0 +1,265 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+  die ("Hacking attempt!");
+}
+
+$errors = array();
+
+// original resize
+$original_fields = array(
+  'original_resize',
+  'original_resize_maxwidth',
+  'original_resize_maxheight',
+  'original_resize_quality',
+  );
+
+$updates = array();
+
+foreach ($original_fields as $field)
+{
+  $value = !empty($_POST[$field]) ? $_POST[$field] : null;
+  $updates[$field] = $value;
+}
+
+save_upload_form_config($updates, $page['errors'], $errors);
+
+if ($_POST['resize_quality'] < 50 or $_POST['resize_quality'] > 98)
+{
+  $errors['resize_quality'] = '[50..98]';
+}
+
+$pderivatives = $_POST['d'];
+
+// step 1 - sanitize HTML input
+foreach ($pderivatives as $type => &$pderivative)
+{
+  if ($pderivative['must_square'] = ($type==IMG_SQUARE ? true : false))
+  {
+    $pderivative['h'] = $pderivative['w'];
+    $pderivative['minh'] = $pderivative['minw'] = $pderivative['w'];
+    $pderivative['crop'] = 100;
+  }
+  $pderivative['must_enable'] = ($type==IMG_SQUARE || $type==IMG_THUMB)? true : false;
+  $pderivative['enabled'] = isset($pderivative['enabled']) || $pderivative['must_enable'] ? true : false;
+
+  if (isset($pderivative['crop']))
+  {
+    $pderivative['crop'] = 100;
+    $pderivative['minw'] = $pderivative['w'];
+    $pderivative['minh'] = $pderivative['h'];
+  }
+  else
+  {
+    $pderivative['crop'] = 0;
+    $pderivative['minw'] = null;
+    $pderivative['minh'] = null;
+  }
+}
+unset($pderivative);
+
+// step 2 - check validity
+$prev_w = $prev_h = 0;
+foreach(ImageStdParams::get_all_types() as $type)
+{
+  $pderivative = $pderivatives[$type];
+  if (!$pderivative['enabled'])
+  {
+    continue;
+  }
+
+  if ($type == IMG_THUMB)
+  {
+    $w = intval($pderivative['w']);
+    if ($w <= 0)
+    {
+      $errors[$type]['w'] = '>0';
+    }
+    
+    $h = intval($pderivative['h']);
+    if ($h <= 0)
+    {
+      $errors[$type]['h'] = '>0';
+    }
+    
+    if (max($w,$h) <= $prev_w)
+    {
+      $errors[$type]['w'] = $errors[$type]['h'] = '>'.$prev_w;
+    }
+  }
+  else
+  {
+    $v = intval($pderivative['w']);
+    if ($v <= 0 or $v <= $prev_w)
+    {
+      $errors[$type]['w'] = '>'.$prev_w;
+    }
+    
+    $v = intval($pderivative['h']);
+    if ($v <= 0 or $v <= $prev_h)
+    {
+      $errors[$type]['h'] = '>'.$prev_h;
+    }
+  }
+  
+  if (count($errors) == 0)
+  {
+    $prev_w = intval($pderivative['w']);
+    $prev_h = intval($pderivative['h']);
+  }
+}
+
+// step 3 - save data
+if (count($errors) == 0)
+{
+  $enabled = ImageStdParams::get_defined_type_map();
+  $disabled = @unserialize( @$conf['disabled_derivatives'] );
+  if ($disabled === false)
+  {
+    $disabled = array();
+  }
+  $changed_types = array();
+
+  foreach (ImageStdParams::get_all_types() as $type)
+  {
+    $pderivative = $pderivatives[$type];
+    
+    if ($pderivative['enabled'])
+    {
+      $new_params = new DerivativeParams(
+        new SizingParams(
+          array(intval($pderivative['w']), intval($pderivative['h'])),
+          round($pderivative['crop'] / 100, 2),
+          array(intval($pderivative['minw']), intval($pderivative['minh']))
+          )
+        );
+      
+      $new_params->quality = intval($_POST['resize_quality']);
+      
+      ImageStdParams::apply_global($new_params);
+      
+      if (isset($enabled[$type]))
+      {
+        $old_params = $enabled[$type];
+        $same = true;
+        if (!size_equals($old_params->sizing->ideal_size, $new_params->sizing->ideal_size)
+            or $old_params->sizing->max_crop != $new_params->sizing->max_crop)
+        {
+          $same = false;
+        }
+        
+        if ($same
+            and $new_params->sizing->max_crop != 0
+            and !size_equals($old_params->sizing->min_size, $new_params->sizing->min_size))
+        {
+          $same = false;
+        }
+        
+        if ($new_params->quality != $old_params->quality)
+        {
+          $same = false;
+        }
+        
+        if (!$same)
+        {
+          $new_params->last_mod_time = time();
+          $changed_types[] = $type;
+        }
+        else
+        {
+          $new_params->last_mod_time = $old_params->last_mod_time;
+        }
+        $enabled[$type] = $new_params;
+      }
+      else
+      {// now enabled, before was disabled
+        $enabled[$type] = $new_params;
+        unset($disabled[$type]);
+      }
+    }
+    else
+    {// disabled
+      if (isset($enabled[$type]))
+      {// now disabled, before was enabled
+        $changed_types[] = $type;
+        $disabled[$type] = $enabled[$type];
+        unset($enabled[$type]);
+      }
+    }
+  }
+  
+  $enabled_by = array(); // keys ordered by all types
+  foreach(ImageStdParams::get_all_types() as $type)
+  {
+    if (isset($enabled[$type]))
+    {
+      $enabled_by[$type] = $enabled[$type];
+    }
+  }
+  
+  ImageStdParams::set_and_save($enabled_by);
+  if (count($disabled) == 0)
+  {
+    $query='DELETE FROM '.CONFIG_TABLE.' WHERE param = \'disabled_derivatives\'';
+    pwg_query($query);
+  }
+  else
+  {
+    conf_update_param('disabled_derivatives', addslashes(serialize($disabled)) );
+  }
+  $conf['disabled_derivatives'] = serialize($disabled);
+  
+  if (count($changed_types))
+  {
+    clear_derivative_cache($changed_types);
+  }
+  
+  array_push(
+    $page['infos'],
+    l10n('Your configuration settings are saved')
+    );
+}
+else
+{
+  foreach ($original_fields as $field)
+  {
+    if (isset($_POST[$field]))
+    {
+      $template->append(
+        'sizes',
+        array(
+          $field => $_POST[$field]
+          ),
+        true
+        );
+    }
+  }
+  
+  $template->assign('derivatives', $pderivatives);
+  $template->assign('ferrors', $errors);
+  $template->assign('resize_quality', $_POST['resize_quality']);
+  $page['sizes_loaded_in_tpl'] = true;
+}
+?>
Index: /trunk/admin/include/functions_upload.inc.php
===================================================================
--- /trunk/admin/include/functions_upload.inc.php	(revision 14220)
+++ /trunk/admin/include/functions_upload.inc.php	(revision 14221)
@@ -69,5 +69,5 @@
 }
 
-function save_upload_form_config($data, &$errors=array())
+function save_upload_form_config($data, &$errors=array(), &$form_errors=array())
 {
   if (!is_array($data) or empty($data))
@@ -131,4 +131,6 @@
             )
           );
+        
+        $form_errors[$field] = '['.$min.' .. '.$max.']';
       }
     }
Index: /trunk/admin/themes/default/template/configuration.tpl
===================================================================
--- /trunk/admin/themes/default/template/configuration.tpl	(revision 14220)
+++ /trunk/admin/themes/default/template/configuration.tpl	(revision 14221)
@@ -320,6 +320,8 @@
 {/literal}{/footer_script}
 
-{literal}
-<style>
+{html_head}{literal}
+<style type="text/css">
+input[type="text"].dError {border-color:#ff7070; background-color:#FFe5e5;}
+.dErrorDesc {background-color:red; color:white; padding:0 5px;border-radius:10px; font-weight:bold;cursor:help;}
 .sizeEnable {width:50px;}
 .sizeEditForm {margin:0 0 10px 20px;}
@@ -330,5 +332,5 @@
 .sizeEditOpen {margin-left:10px;}
 </style>
-{/literal}
+{/literal}{/html_head}
 
 <fieldset id="sizesConf">
@@ -345,13 +347,22 @@
     <tr>
       <th>{'Maximum Width'|@translate}</th>
-      <td><input type="text" name="original_resize_maxwidth" value="{$sizes.original_resize_maxwidth}" size="4" maxlength="4"> {'pixels'|@translate}</td>
+      <td>
+        <input type="text" name="original_resize_maxwidth" value="{$sizes.original_resize_maxwidth}" size="4" maxlength="4"{if isset($ferrors.original_resize_maxwidth)} class="dError"{/if}> {'pixels'|@translate}
+        {if isset($ferrors.original_resize_maxwidth)}<span class="dErrorDesc" title="{$ferrors.original_resize_maxwidth}">!</span>{/if}
+      </td>
     </tr>
     <tr>
       <th>{'Maximum Height'|@translate}</th>
-      <td><input type="text" name="original_resize_maxheight" value="{$sizes.original_resize_maxheight}" size="4" maxlength="4"> {'pixels'|@translate}</td>
+      <td>
+        <input type="text" name="original_resize_maxheight" value="{$sizes.original_resize_maxheight}" size="4" maxlength="4"{if isset($ferrors.original_resize_maxheight)} class="dError"{/if}> {'pixels'|@translate}
+        {if isset($ferrors.original_resize_maxheight)}<span class="dErrorDesc" title="{$ferrors.original_resize_maxheight}">!</span>{/if}
+      </td>
     </tr>
     <tr>
       <th>{'Image Quality'|@translate}</th>
-      <td><input type="text" name="original_resize_quality" value="{$sizes.original_resize_quality}" size="3" maxlength="3"> %</td>
+      <td>
+        <input type="text" name="original_resize_quality" value="{$sizes.original_resize_quality}" size="3" maxlength="3"{if isset($ferrors.original_resize_quality)} class="dError"{/if}> %
+        {if isset($ferrors.original_resize_quality)}<span class="dErrorDesc" title="{$ferrors.original_resize_quality}">!</span>{/if}
+      </td>
     </tr>
   </table>
@@ -359,11 +370,9 @@
 </fieldset>
 
-<div class="warnings">Warning: the following fields are for test "user interface" test only. Any change won't be saved.<br>See screen [Administration > Configuration > Multiple Size] to configure sizes.</div>
-
 <fieldset id="multiSizesConf">
   <legend>{'Multiple Size'|@translate}</legend>
 
 <div class="showDetails">
-  <a href="#" id="showDetails"{if $show_details} style="display:none"{/if}>{'show details'|@translate}</a>
+  <a href="#" id="showDetails"{if $show_details or isset($ferrors)} style="display:none"{/if}>{'show details'|@translate}</a>
 </div>
 
@@ -385,9 +394,9 @@
 
     <td>
-      <span class="sizeDetails">{$d.w} x {$d.h} {'pixels'|@translate}{if $d.crop}, {'Crop'|@translate|lower}{/if}</span>
+      <span class="sizeDetails"{if isset($ferrors)} style="display:inline"{/if}>{$d.w} x {$d.h} {'pixels'|@translate}{if $d.crop}, {'Crop'|@translate|lower}{/if}</span>
     </td>
 
     <td>
-      <span class="sizeDetails">
+      <span class="sizeDetails"{if isset($ferrors) and !isset($ferrors.$type)} style="display:inline"{/if}>
         <a href="#" id="sizeEditOpen-{$type}" class="sizeEditOpen">{'edit'|@translate}</a>
       </span>
@@ -395,5 +404,5 @@
   </tr>
 
-  <tr id="sizeEdit-{$type}" class="sizeEdit">
+  <tr id="sizeEdit-{$type}" class="sizeEdit" {if isset($ferrors.$type)} style="display:block"{/if}>
     <td colspan="3">
       <table class="sizeEditForm">
@@ -412,5 +421,5 @@
           <td class="sizeEditWidth">{if $d.must_square or $d.crop}{'Width'|@translate}{else}{'Maximum Width'|@translate}{/if}</td>
           <td>
-            <input type="text" name="d[{$type}][w]" maxlength="4" size="4" value="{$d.w}"{if isset($ferrors.$type.w)}class="dError"{/if}>
+            <input type="text" name="d[{$type}][w]" maxlength="4" size="4" value="{$d.w}"{if isset($ferrors.$type.w)} class="dError"{/if}>
             {'pixels'|@translate}
             {if isset($ferrors.$type.w)}<span class="dErrorDesc" title="{$ferrors.$type.w}">!</span>{/if}
@@ -422,5 +431,5 @@
           <td class="sizeEditHeight">{if $d.crop}{'Height'|@translate}{else}{'Maximum Height'|@translate}{/if}</td>
           <td>
-            <input type="text" name="d[{$type}][h]" maxlength="4" size="4"  value="{$d.h}"{if isset($ferrors.$type.h)}class="dError"{/if}>
+            <input type="text" name="d[{$type}][h]" maxlength="4" size="4"  value="{$d.h}"{if isset($ferrors.$type.h)} class="dError"{/if}>
             {'pixels'|@translate}
             {if isset($ferrors.$type.h)}<span class="dErrorDesc" title="{$ferrors.$type.h}">!</span>{/if}
@@ -434,7 +443,8 @@
 </table>
 
-<p style="margin:20px 0 0 0" class="sizeDetails">
+<p style="margin:20px 0 0 0;{if isset($ferrors)} display:block;{/if}" class="sizeDetails">
   {'Image Quality'|@translate}
-  <input type="text" name="original_resize_quality" value="{$sizes.original_resize_quality}" size="3" maxlength="3"> %
+  <input type="text" name="resize_quality" value="{$resize_quality}" size="3" maxlength="3"{if isset($ferrors.resize_quality)} class="dError"{/if}> %
+  {if isset($ferrors.resize_quality)}<span class="dErrorDesc" title="{$ferrors.resize_quality}">!</span>{/if}
 </p>
 </fieldset>
Index: /trunk/include/derivative_params.inc.php
===================================================================
--- /trunk/include/derivative_params.inc.php	(revision 14220)
+++ /trunk/include/derivative_params.inc.php	(revision 14221)
@@ -241,5 +241,5 @@
   public $sizing;
   public $sharpen = 0;
-  public $quality = 85;
+  public $quality = 95;
 
   function __construct($sizing)
