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);