diff --git a/Fltk/inputRange.h b/Fltk/inputRange.h
index 29806d0586ad4ff83987afc77460bd2b2462357d..d5c1eefc9952035d277a04956964063114d455d6 100644
--- a/Fltk/inputRange.h
+++ b/Fltk/inputRange.h
@@ -18,50 +18,94 @@ class inputRange : public Fl_Group {
   Fl_Input *_range;
   Fl_Toggle_Button *_range_butt, *_loop_butt;
   double _min, _max, _step, _max_number;
+  std::vector<double> _choices;
   void _values2string()
   {
-    // construct range string from min/max/step
     std::ostringstream tmp;
-    if(_min != -_max_number){
-      tmp << _min;
-      _input->minimum(_min);
+    if(_choices.size()){
+      // construct range string using choices
+      for(unsigned int i = 0; i < _choices.size(); i++){
+        if(i) tmp << ", ";
+        tmp << _choices[i];
+      }
+      if(_choices.size() > 1){
+        _input->minimum(_choices[0]);
+        _input->maximum(_choices[_choices.size() - 1]);
+        _input->step(_choices[1] - _choices[0]);
+      }
+      _step = 0.;
     }
-    tmp << ":";
-    if(_max != _max_number){
-      tmp << _max;
-      _input->maximum(_max);
-    }
-    if(_step){
+    else{
+      // construct range string from min/max/step
+      if(_min != -_max_number){
+        tmp << _min;
+        _input->minimum(_min);
+      }
+      tmp << ":";
+      if(_max != _max_number){
+        tmp << _max;
+        _input->maximum(_max);
+      }
+      if(_step == 0.) _step = 1.;
       if(_step != 1.) tmp << ":" << _step;
       _input->step(_step);
+      _choices.clear();
     }
     _range->value(tmp.str().c_str());
   }
   void _string2values()
   {
-    // parse range string and affect min/max/step
-    std::string str(_range->value()), min, max, step;
-    std::string::size_type first = 0, last;
-    last = str.find_first_of(':', first);
-    min = str.substr(first, last - first);
-    if(last != std::string::npos){
-      first = last + 1;
-      last = str.find_first_of(':', first);
-      max = str.substr(first, last - first);
-      if(last != std::string::npos)
-        step = str.substr(last + 1, str.size());
-    }
-    if(min.size()){
-      _min = atof(min.c_str());
-      _input->minimum(_min);
+    std::string str(_range->value());
+    if(str.find_first_of(',') != std::string::npos){
+      // parse list of values
+      std::string::size_type first = 0;
+      while(1){
+        std::string::size_type last = str.find_first_of(',', first);
+        std::string val = str.substr(first, last - first);
+        _choices.push_back(atof(val.c_str()));
+        if(last == std::string::npos) 
+          break;
+        else
+          first = last + 1;
+      }
+      if(_choices.size() > 1){
+        _input->minimum(_choices[0]);
+        _input->maximum(_choices[_choices.size() - 1]);
+        _input->step(_choices[1] - _choices[0]);
+      }
+      _step = 0.;
     }
-    if(max.size()){
-      _max = atof(max.c_str());
-      _input->maximum(_max);
-    }
-    if(step.size()){
-      _step = atof(step.c_str());
+    else{
+      // parse min/max/step
+      std::string min, max, step;
+      std::string::size_type first = 0;
+      std::string::size_type last = str.find_first_of(':', first);
+      min = str.substr(first, last - first);
+      if(last != std::string::npos){
+        first = last + 1;
+        last = str.find_first_of(':', first);
+        max = str.substr(first, last - first);
+        if(last != std::string::npos)
+          step = str.substr(last + 1, str.size());
+      }
+      if(min.size()){
+        _min = atof(min.c_str());
+        _input->minimum(_min);
+      }
+      else
+        _min = -_max_number;
+      if(max.size()){
+        _max = atof(max.c_str());
+        _input->maximum(_max);
+      }
+      else
+        _max = _max_number;
+      if(step.size())
+        _step = atof(step.c_str());
+      else
+        _step = 1.;
       _input->step(_step);
+      _choices.clear();
     }
   }
   void _show_range()
@@ -126,6 +170,8 @@ class inputRange : public Fl_Group {
   }
   double value() { return _input->value(); }
   void value(double val) { _input->value(val); }
+  void choices(const std::vector<double> &val) { _choices = val; _values2string(); }
+  std::vector<double> choices() { return _choices; }
   void minimum(double val) { _min = val; _values2string(); }
   double minimum() { return _min; }
   void maximum(double val) { _max = val; _values2string(); }
diff --git a/Fltk/onelabWindow.cpp b/Fltk/onelabWindow.cpp
index 30cb5e2c251f1ca67ea7561aa0f576221376c3d1..2dc8713efb4754b04a31fe7cdb48085c7a8e9656 100644
--- a/Fltk/onelabWindow.cpp
+++ b/Fltk/onelabWindow.cpp
@@ -320,6 +320,30 @@ static std::string getModelName(onelab::client *c)
   }
 }
 
+static void initCompute()
+{
+  bool changed = false;
+  std::vector<onelab::number> numbers;
+  onelab::server::instance()->get(numbers);
+  for(unsigned int i = 0; i < numbers.size(); i++){
+    if(numbers[i].getAttribute("loop") == "true"){
+      if(numbers[i].getChoices().size() > 1){
+        numbers[i].setValue(numbers[i].getChoices()[0]);
+        onelab::server::instance()->set(numbers[i]);
+        changed = true;
+      }
+      else if(numbers[i].getMin() != -onelab::parameter::maxNumber() &&
+              numbers[i].getStep()){
+        numbers[i].setValue(numbers[i].getMin());
+        onelab::server::instance()->set(numbers[i]);
+        changed = true;
+      }
+    }
+  }
+  if(changed)
+    FlGui::instance()->onelab->rebuildTree();
+}
+
 static bool shouldRecompute()
 {
   bool recompute = false;
@@ -327,13 +351,25 @@ static bool shouldRecompute()
   onelab::server::instance()->get(numbers);
   for(unsigned int i = 0; i < numbers.size(); i++){
     if(numbers[i].getAttribute("loop") == "true"){
-      if(numbers[i].getMax() != onelab::parameter::maxNumber() &&
-         numbers[i].getValue() < numbers[i].getMax() && 
-         numbers[i].getStep()){
+      if(numbers[i].getChoices().size() > 1){
+        std::vector<double> choices(numbers[i].getChoices());
+        for(unsigned int j = 0; j < choices.size() - 1; j++){
+          if(numbers[i].getValue() == choices[j]){
+            numbers[i].setValue(choices[j + 1]);
+            onelab::server::instance()->set(numbers[i]);
+            Msg::Info("Recomputing with new choice %s=%g", 
+                      numbers[i].getName().c_str(), numbers[i].getValue());
+            recompute = true;
+          }
+        }
+      }
+      else if(numbers[i].getMax() != onelab::parameter::maxNumber() &&
+              numbers[i].getValue() < numbers[i].getMax() && 
+              numbers[i].getStep()){
         numbers[i].setValue(numbers[i].getValue() + numbers[i].getStep());
         onelab::server::instance()->set(numbers[i]);
-        Msg::Info("Recomputing with %s=%g", numbers[i].getName().c_str(),
-                  numbers[i].getValue());
+        Msg::Info("Recomputing with new step %s=%g",
+                  numbers[i].getName().c_str(), numbers[i].getValue());
         recompute = true;
       }
     }
@@ -370,77 +406,79 @@ void onelab_cb(Fl_Widget *w, void *data)
   }
 
   FlGui::instance()->onelab->deactivate();
-  
- recompute:
 
-  // the Gmsh client is special: it always gets executed first. (The
-  // meta-model will allow more flexibility: but in the simple GUI we
-  // can assume this)
-  onelab::server::citer it = onelab::server::instance()->findClient("Gmsh");
-  if(it != onelab::server::instance()->lastClient()){
-    onelab::client *c = it->second;
-    std::string mshFileName = getMshFileName(c);
-    static std::string modelName = GModel::current()->getName();
-    if(action == "check"){
-      if(onelab::server::instance()->getChanged("Gmsh") ||
-         modelName != GModel::current()->getName()){
-        // reload geometry if Gmsh parameters have been modified or if
-        // the model name has changed
-        modelName = GModel::current()->getName();
-        geometry_reload_cb(0, 0);
-      }
-    }
-    else if(action == "compute"){
-      if(onelab::server::instance()->getChanged("Gmsh") ||
-         modelName != GModel::current()->getName()){
-        // reload the geometry, mesh it and save the mesh if Gmsh
-        // parameters have been modified or if the model name has
-        // changed
-        modelName = GModel::current()->getName();
-        geometry_reload_cb(0, 0);
-        if(FlGui::instance()->onelab->meshAuto()){
-          mesh_3d_cb(0, 0);
-          CreateOutputFile(mshFileName, CTX::instance()->mesh.fileFormat);
+  if(action == "compute") initCompute();
+
+  do{ // enter computation loop
+
+    // the Gmsh client is special: it always gets executed first. (The
+    // meta-model will allow more flexibility: but in the simple GUI we
+    // can assume this)
+    onelab::server::citer it = onelab::server::instance()->findClient("Gmsh");
+    if(it != onelab::server::instance()->lastClient()){
+      onelab::client *c = it->second;
+      std::string mshFileName = getMshFileName(c);
+      static std::string modelName = GModel::current()->getName();
+      if(action == "check"){
+        if(onelab::server::instance()->getChanged("Gmsh") ||
+           modelName != GModel::current()->getName()){
+          // reload geometry if Gmsh parameters have been modified or if
+          // the model name has changed
+          modelName = GModel::current()->getName();
+          geometry_reload_cb(0, 0);
         }
       }
-      else if(StatFile(mshFileName)){
-        // mesh+save if the mesh file does not exist
-        if(FlGui::instance()->onelab->meshAuto()){
-          mesh_3d_cb(0, 0);
-          CreateOutputFile(mshFileName, CTX::instance()->mesh.fileFormat);
+      else if(action == "compute"){
+        if(onelab::server::instance()->getChanged("Gmsh") ||
+           modelName != GModel::current()->getName()){
+          // reload the geometry, mesh it and save the mesh if Gmsh
+          // parameters have been modified or if the model name has
+          // changed
+          modelName = GModel::current()->getName();
+          geometry_reload_cb(0, 0);
+          if(FlGui::instance()->onelab->meshAuto()){
+            mesh_3d_cb(0, 0);
+            CreateOutputFile(mshFileName, CTX::instance()->mesh.fileFormat);
+          }
+        }
+        else if(StatFile(mshFileName)){
+          // mesh+save if the mesh file does not exist
+          if(FlGui::instance()->onelab->meshAuto()){
+            mesh_3d_cb(0, 0);
+            CreateOutputFile(mshFileName, CTX::instance()->mesh.fileFormat);
+          }
         }
+        onelab::server::instance()->setChanged(false, "Gmsh");
       }
-      onelab::server::instance()->setChanged(false, "Gmsh");
     }
-  }
-
-  // Iterate over all other clients
-  for(onelab::server::citer it = onelab::server::instance()->firstClient();
-      it != onelab::server::instance()->lastClient(); it++){
-    onelab::client *c = it->second;
-    if(c->getName() == "Gmsh" || // local Gmsh client
-       c->getName() == "Listen" || // unknown client connecting through "-listen"
-       c->getName() == "GmshRemote") // distant post-processing Gmsh client
-      continue;
-    std::string what = getModelName(c);
-    if(action == "initial check" || action == "check"){
-      c->run(what);
-    }
-    else if(action == "compute"){
-      // get command line from the server
-      std::vector<onelab::string> ps;
-      onelab::server::instance()->get(ps, c->getName() + "/9Compute");
-      if(ps.size()) what += " " + ps[0].getValue();
-      c->run(what);
-    }
-    else if(action == "kill"){
-      c->kill();
+    
+    // Iterate over all other clients
+    for(onelab::server::citer it = onelab::server::instance()->firstClient();
+        it != onelab::server::instance()->lastClient(); it++){
+      onelab::client *c = it->second;
+      if(c->getName() == "Gmsh" || // local Gmsh client
+         c->getName() == "Listen" || // unknown client connecting through "-listen"
+         c->getName() == "GmshRemote") // distant post-processing Gmsh client
+        continue;
+      std::string what = getModelName(c);
+      if(action == "initial check" || action == "check"){
+        c->run(what);
+      }
+      else if(action == "compute"){
+        // get command line from the server
+        std::vector<onelab::string> ps;
+        onelab::server::instance()->get(ps, c->getName() + "/9Compute");
+        if(ps.size()) what += " " + ps[0].getValue();
+        c->run(what);
+      }
+      else if(action == "kill"){
+        c->kill();
+      }
     }
-  }
 
-  printf("Gmsh ONELAB db:\n%s\n", onelab::server::instance()->toChar().c_str());
+    printf("Gmsh ONELAB db:\n%s\n", onelab::server::instance()->toChar().c_str());
 
-  if(action == "compute" && shouldRecompute()) goto recompute;
+  } while(action == "compute" && shouldRecompute());
 
   FlGui::instance()->onelab->activate();
   FlGui::instance()->onelab->rebuildTree();
@@ -472,6 +510,7 @@ static void onelab_input_range_cb(Fl_Widget *w, void *data)
     numbers[0].setMin(o->minimum());
     numbers[0].setMax(o->maximum());
     numbers[0].setStep(o->step());
+    numbers[0].setChoices(o->choices());
     numbers[0].setAttribute("loop", o->loop() ? "true" : "false");
     onelab::server::instance()->set(numbers[0]);
   }
@@ -614,6 +653,7 @@ void onelabWindow::rebuildTree()
       but->minimum(numbers[i].getMin());
       but->maximum(numbers[i].getMax());
       but->step(numbers[i].getStep());
+      but->choices(numbers[i].getChoices());
       but->loop(numbers[i].getAttribute("loop") == "true");
       but->align(FL_ALIGN_RIGHT);
       but->callback(onelab_input_range_cb, (void*)n);