Skip to content
Snippets Groups Projects
Select Git revision
  • 8cd443d18a48f745c5d927328ae6f402296e0b29
  • master default protected
  • alphashapes
  • quadMeshingTools
  • cygwin_conv_path
  • macos_arm64
  • add-transfiniteautomatic-to-geo
  • patch_releases_4_10
  • HierarchicalHDiv
  • isuruf-master-patch-63355
  • hyperbolic
  • hexdom
  • hxt_update
  • jf
  • 1618-pythonocc-and-gmsh-api-integration
  • octreeSizeField
  • hexbl
  • alignIrregularVertices
  • getEdges
  • patch_releases_4_8
  • isuruf-master-patch-51992
  • gmsh_4_11_0
  • gmsh_4_10_5
  • gmsh_4_10_4
  • gmsh_4_10_3
  • gmsh_4_10_2
  • gmsh_4_10_1
  • gmsh_4_10_0
  • gmsh_4_9_5
  • gmsh_4_9_4
  • gmsh_4_9_3
  • gmsh_4_9_2
  • gmsh_4_9_1
  • gmsh_4_9_0
  • gmsh_4_8_4
  • gmsh_4_8_3
  • gmsh_4_8_2
  • gmsh_4_8_1
  • gmsh_4_8_0
  • gmsh_4_7_1
  • gmsh_4_7_0
41 results

OptHomRun.cpp

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    onelab2Group.cpp 26.28 KiB
    #include "onelab2Group.h"
    
    #include "FlGui.h"
    #include <FL/Fl_Box.H>
    #include <FL/Fl_Check_Button.H>
    #include <FL/Fl_Input_Choice.H>
    #include <FL/Fl_Choice.H>
    #include <FL/Fl_Menu_Item.H>
    #include "inputRange.h"
    #include "outputRange.h"
    #include "inputRegion.h"
    #include "drawContext.h"
    #include "viewButton.h"
    #include "solverButton.h"
    
    #include "Gmsh.h"
    #include "onelabUtils.h"
    #include "OnelabDatabase.h"
    #include "Options.h"
    #include "Context.h"
    
    static void initializeLoops()
    {
      onelabUtils::initializeLoop("1");
      onelabUtils::initializeLoop("2");
      onelabUtils::initializeLoop("3");
    
      if(FlGui::available() && onelab::server::instance()->getChanged())
        FlGui::instance()->rebuildTree(false);
    }
    
    static bool incrementLoops()
    {
      bool ret = (onelabUtils::incrementLoop("3") ||
        onelabUtils::incrementLoop("2") ||
        onelabUtils::incrementLoop("1"));
    
      //Define ONELAB parameter indicating whether or not in a loop
      onelab::number n("0Metamodel/Loop",ret?1:0);
      n.setVisible(false);
      onelab::server::instance()->set(n);
    
      if(FlGui::available() && onelab::server::instance()->getChanged())
        FlGui::instance()->rebuildTree(false);
    
      return ret;
    }
    
    static void updateGraphs()
    {
      bool redraw = false;
      for(int i = 0; i < 18; i++){
        std::ostringstream tmp;
        tmp << i;
        bool ret = onelabUtils::updateGraph(tmp.str());
        redraw = redraw || ret;
      }
      if(redraw){
        // don't delete the widgets, as this is called in widget callbacks
        FlGui::instance()->updateViews(true, false);
        drawContext::global()->draw();
      }
    }
    
    void connect_cb(Fl_Widget *w, void *arg)
    {
      if(!arg) return;
      onelabGroup *obj = (onelabGroup *)arg;
      if(strcmp(w->label(), "Connect") == 0) {
        if(!obj->useServer()) return;
        obj->clearTree();
        GmshNetworkClient *cli = OnelabDatabase::instance()->useAsNetworkClient(obj->getServerIP(), obj->getServerPort());
        if(cli) {
          cli->setCallback(obj);
          w->label("Disconnect");
        }
        else
          fl_alert("Unable to connect to server");
      }
      else {
        obj->clearTree();
        OnelabDatabase::instance()->useAsClient()->setCallback(obj);
        w->label("Connect");
      }
    }
    
    void useserver_cb(Fl_Widget *w, void *arg)
    {
      if(!arg) return;
      Fl_Check_Button *checkbox = (Fl_Check_Button *)w;
      onelabGroup *obj = (onelabGroup *)arg;
      obj->useServer(checkbox->value() == 1);
    }
    
    void onelab_cb(Fl_Widget *w, void *data)
    {
      if(!data) return;
    
      std::string action((const char*)data);
    
      if(action == "refresh"){
        updateGraphs();
        return;
      }
    
      if(FlGui::instance()->onelab->isBusy()){
        Msg::Info("I'm busy! Ask me that later...");
        return;
      }
      Msg::Info("Try to %s", action.c_str());
      
      Msg::ResetErrorCounter();
    
      //TODO FlGui::instance()->onelab->setButtonMode("", "stop");
    
      OnelabDatabase::instance()->run(action);
    }
    
    
    void solver_cb(Fl_Widget *w, void *data)
    {
      if(!FlGui::instance()->onelab) return;
    
      int num = (intptr_t)data;
      if(num >= 0){
        std::string name = opt_solver_name(num, GMSH_GET, "");
        if(name.empty()) return;// TODO
        std::string exe = opt_solver_executable(num, GMSH_GET, "");
        std::string host = opt_solver_remote_login(num, GMSH_GET, "");
        OnelabDatabase::instance()->run("initialize", name);
      }
    
      if(FlGui::instance()->onelab->isBusy())
        FlGui::instance()->onelab->show();
      else{
        if(CTX::instance()->solverToRun >= 0){
          onelab_cb(0, (void*)"reset");
          onelabUtils::setFirstComputationFlag(true);
        }
        else if(num >= 0) {
          onelab_cb(0, (void*)"check");
        }
        else {
          onelab_cb(0, (void*)"refresh");
        }
        FlGui::instance()->onelab->updateGearMenu();
      }
    }
    void solver_batch_cb(Fl_Widget *w, void *data)
    {
      int num = (intptr_t)data;
      if(num >= 0) {
        std::string name = opt_solver_name(num, GMSH_GET, "");
        std::string exe = opt_solver_executable(num, GMSH_GET, "");
        if(exe.empty()){
          Msg::Error("Solver executable name not provided");
          return;
        }
      }
      Msg::Warning("solver_batch_cb TODO");
      // TODO
    }
    
    static bool getFlColor(const std::string &str, Fl_Color &c)
    {
      if(str == "1"){
        c = FL_YELLOW;
        return true;
      }
      int r, g, b;
      if(str.size() && GetRGBForString(str.c_str(), r, g, b)){
        c = fl_color_cube(r * (FL_NUM_RED - 1) / 255,
                          g * (FL_NUM_GREEN - 1) / 255,
                          b * (FL_NUM_BLUE - 1) / 255);
        return true;
      }
      c = FL_BLACK;
      return false;
    }
    
    onelabGroup::onelabGroup(int x, int y, int w, int h, const char *l)
      : Fl_Group(x, y, w, h, l), _stop(false), _enableTreeWidgetResize(false)
    {
      int col = FL_BACKGROUND2_COLOR;
      color(col);
    
      box(GMSH_SIMPLE_RIGHT_BOX);
      int dx = Fl::box_dx(box());
      int dy = Fl::box_dy(box());
      int dw = Fl::box_dw(box());
      int dh = Fl::box_dh(box());
    
      _tree = new Fl_Tree(x + dx, y + dy + 6*BH, w - dw, h - dh - BH - 2 * WB - 6*BH);
      _tree->color(col);
      // TODO _tree->callback(onelab_tree_cb);
      _tree->connectorstyle(FL_TREE_CONNECTOR_SOLID);
      _tree->showroot(0);
      _tree->box(FL_FLAT_BOX);
      _tree->scrollbar_size(std::max(10, FL_NORMAL_SIZE - 2));
      _tree->end();
    
      int BB2 = BB / 2 + 4;
      _butt[0] = new Fl_Button(x + w - 3 * WB - 3 * BB2, y + h - WB - BH, BB2, BH, "Check");
      _butt[0]->callback(onelab_cb, (void*)"check");
    
      _butt[1] = new Fl_Button(x + w - 2 * WB - 2 * BB2, y + h - WB - BH, BB2, BH, "Run");
      _butt[1]->callback(onelab_cb, (void*)"compute");
    
      Fl_Check_Button *useServer = new Fl_Check_Button(x+WB, y, w-2*WB, BH, "Use a remote server");
      useServer->callback(useserver_cb, this);
      /*Fl_Box *ip_lbl = */new Fl_Box(x+WB , y+BH, w-2*WB, BH, "Server IP address:");
      server_ip = new Fl_Input(x+WB, y+2*BH, w-2*WB, BH, "");
      server_ip->value("127.0.0.1");
      server_ip->readonly(true);
      /*Fl_Box *port_lbl = */new Fl_Box(x+WB , y+3*BH, w-2*WB, BH, "Server port:");
      server_port = new Fl_Input(x+WB, y+4*BH, w-2*WB, BH, "");
      server_port->value("1148");
      server_port->readonly(true);
      Fl_Button *connect_btn = new Fl_Button(x+WB, y+5*BH, w-2*WB, BH, "Connect");
      connect_btn->callback(connect_cb, this);
    
      _computeWidths();
      _widgetLabelRatio = 0.48;
      OnelabDatabase::instance()->useAsClient()->setCallback(this);
    }
    onelabGroup::~onelabGroup()
    {
      Fl::delete_widget(_tree);
    }
    
    void onelabGroup::clearTree(bool deleteWidgets)
    {
      _tree->clear();
      _tree->sortorder(FL_TREE_SORT_ASCENDING);
      _tree->selectmode(FL_TREE_SELECT_NONE);
    
      std::vector<Fl_Widget*> delWidgets;
      std::vector<char*> delStrings;
      if(deleteWidgets){
        delWidgets = _treeWidgets;
        delStrings = _treeStrings;
        _treeWidgets.clear();
        _treeStrings.clear();
       }
      FlGui::check();
      if(deleteWidgets){
        for(unsigned int i = 0; i < delWidgets.size(); i++)
          Fl::delete_widget(delWidgets[i]);
        for(unsigned int i = 0; i < delStrings.size(); i++)
          free(delStrings[i]);
      }
    }
    
    void onelabGroup::openTreeItem(const std::string &name)
    {
      Fl_Tree_Item *n = _tree->find_item(name.c_str());
      if(n && n->has_children()){
        n->open();
        _tree->redraw();
      }
    }
    
    void onelabGroup::updateGearMenu()
    {
      return; // TODO
      Fl_Menu_Item* menu = (Fl_Menu_Item*)_gear->menu();
      int values[8] = {CTX::instance()->solver.autoSaveDatabase,
                       CTX::instance()->solver.autoArchiveOutputFiles,
                       CTX::instance()->solver.autoCheck,
                       CTX::instance()->solver.autoMesh,
                       CTX::instance()->solver.autoMergeFile,
                       CTX::instance()->solver.autoShowViews,
                       CTX::instance()->solver.autoShowLastStep,
                       CTX::instance()->solver.showInvisibleParameters};
      for(int i = 0; i < 8; i++){
        int idx = _gearOptionsStart - 1 + i;
        if(values[i])
          menu[idx].set();
        else
          menu[idx].clear();
      }
    }
    
    void onelabGroup::rebuildSolverList()
    {
      updateGearMenu();
    
      std::vector<std::string> names, exes, hosts;
      for(int i = 0; i < NUM_SOLVERS; i++){
        if(opt_solver_name(i, GMSH_GET, "").size()){
          names.push_back(opt_solver_name(i, GMSH_GET, ""));
          exes.push_back(opt_solver_executable(i, GMSH_GET, ""));
          hosts.push_back(opt_solver_remote_login(i, GMSH_GET, ""));
        }
      }
      for(unsigned int i = 0; i < NUM_SOLVERS; i++){
        if(i < names.size()){
          onelab::server::citer it = onelab::server::instance()->findClient(names[i]);
          if(it != onelab::server::instance()->lastClient())
            it->second->setIndex(i);
          opt_solver_name(i, GMSH_SET, names[i]);
          opt_solver_executable(i, GMSH_SET, exes[i]);
          opt_solver_remote_login(i, GMSH_SET, hosts[i]);
        }
        else{
          opt_solver_name(i, GMSH_SET, "");
          opt_solver_executable(i, GMSH_SET, "");
          opt_solver_remote_login(i, GMSH_SET, "");
        }
      }
    
      //TODO setButtonVisibility();
      rebuildTree(true);
    }
    bool onelabGroup::useServer() {return !server_ip->readonly();}
    void onelabGroup::useServer(bool use=false)
    {
      server_ip->readonly(!use);
      server_port->readonly(!use);
    }
    
    void onelabGroup::addParameter(onelab::parameter &p)
    {
      if(!p.getVisible() || CTX::instance()->solver.showInvisibleParameters) return;
      bool highlight = false;
      Fl_Color c;
      if(getFlColor(p.getAttribute("Highlight"), c)) highlight = true;
      Fl_Tree_Item *n = _tree->add(p.getName().c_str());
      n->labelsize(FL_NORMAL_SIZE + 4);
      int ww = _baseWidth - (n->depth() + 1) * _indent;
      ww *= _widgetLabelRatio; // FIXME CHANGE THIS
      int hh = n->labelsize() + 4;
      Fl_Group *grp = new Fl_Group(1, 1, ww, hh);
      Fl_Widget *widget = _addParameterWidget(p, ww, hh, n, highlight, c);
      grp->end();
      if(!_enableTreeWidgetResize) grp->resizable(0);
      _treeWidgets.push_back(grp);
      widget->copy_label(p.getShortName().c_str());
      std::string help = p.getLabel().size() ? p.getLabel() : p.getShortName();
      if(p.getHelp().size()) help += ":\n" + p.getHelp();
      widget->copy_tooltip(help.c_str());
      n->widget(grp);
      _tree->end();
      _tree->redraw();
    }
    Fl_Widget *onelabGroup::_addParameterWidget(onelab::parameter &p, int ww, int hh, Fl_Tree_Item *n, bool highlight, Fl_Color c)
    {
      int type = p.getAttributeType();
      if(type == onelab::number::attributeType())
          return _addParameterWidget(*(onelab::number *)&p, ww, hh, n, highlight, c);
      if(type == onelab::string::attributeType())
          return _addParameterWidget(*(onelab::string *)&p, ww, hh, n, highlight, c);
      if(type == onelab::region::attributeType())
          return _addParameterWidget(*(onelab::region *)&p, ww, hh, n, highlight, c);
      if(type == onelab::function::attributeType())
          return _addParameterWidget(*(onelab::function *)&p, ww, hh, n, highlight, c);
      return NULL;
    }
    
    template<class T>
    static void autoCheck(const T &pold, const T &pnew, bool force=false)
    {
      if(onelabUtils::getFirstComputationFlag()){
        if(pold.getValue() != pnew.getValue())
          onelabUtils::setFirstComputationFlag(false);
      }
    
      if((CTX::instance()->solver.autoCheck && pnew.getAttribute("AutoCheck") != "0") ||
         pnew.getAttribute("AutoCheck") == "1"){
        if(force || pold.getValue() != pnew.getValue())
          onelab_cb(0, (void*)"check");
      }
    }
    
    template <class T>
    static void setGmshOption(T &n)
    {
      std::string opt = n.getAttribute("GmshOption");
      if(opt.empty()) return;
      /*if(opt == "ResetDatabase"){ // special option to reset the onelab db
        resetDb(false);
        FlGui::instance()->rebuildTree(false);
        return;
      }
      if(opt == "Reset"){ // reset db + models except current one
        resetDb(false);
        for(int i = PView::list.size() - 1; i >= 0; i--)
          delete PView::list[i];
        for(int i = GModel::list.size() - 1; i >= 0; i--)
          if(GModel::list[i] != GModel::current()) delete GModel::list[i];
        FlGui::instance()->rebuildTree(false);
        return;
      }*/
      std::string::size_type dot = opt.find('.');
      if(dot == std::string::npos) return;
      GmshSetOption(opt.substr(0, dot), opt.substr(dot + 1), n.getValue());
      drawContext::global()->draw();
    }
    
    // callback for number
    static void onelab_number_input_range_cb(Fl_Widget *w, void *data)
    {
      if(!data) return;
      std::string name((char*)data);
      std::vector<onelab::number> numbers;
      OnelabDatabase::instance()->get(numbers, name);
      if(numbers.size()){
        inputRange *o = (inputRange*)w;
        onelab::number old = numbers[0];
        if(o->doCallbackOnValues()){
          numbers[0].setValue(o->value());
          numbers[0].setMin(o->minimum());
          numbers[0].setMax(o->maximum());
          numbers[0].setStep(o->step());
          numbers[0].setChoices(o->choices());
        }
        o->doCallbackOnValues(true);
        numbers[0].setAttribute("Loop", o->loop());
        numbers[0].setAttribute("Graph", o->graph());
        setGmshOption(numbers[0]);
        OnelabDatabase::instance()->set(numbers[0], std::string("localGUI"));
        updateGraphs();
        autoCheck(old, numbers[0]);
      }
    }
    static void onelab_number_choice_cb(Fl_Widget *w, void *data)
    {
      if(!data) return;
      std::string name((char*)data);
      std::vector<onelab::number> numbers;
      OnelabDatabase::instance()->get(numbers, name);
      if(numbers.size()){
        Fl_Choice *o = (Fl_Choice*)w;
        std::vector<double> choices = numbers[0].getChoices();
        onelab::number old = numbers[0];
        if(o->value() < (int)choices.size()) numbers[0].setValue(choices[o->value()]);
        setGmshOption(numbers[0]);
        OnelabDatabase::instance()->set(numbers[0], std::string("localGUI"));
        autoCheck(old, numbers[0]);
      }
    }
    static void onelab_number_check_button_cb(Fl_Widget *w, void *data)
    {
      if(!data) return;
      std::string name((char*)data);
      std::vector<onelab::number> numbers;
      OnelabDatabase::instance()->get(numbers, name);
      if(numbers.size()){
        Fl_Check_Button *o = (Fl_Check_Button*)w;
        onelab::number old = numbers[0];
        numbers[0].setValue(o->value());
        setGmshOption(numbers[0]);
        OnelabDatabase::instance()->set(numbers[0], std::string("localGUI"));
        autoCheck(old, numbers[0]);
      }
    }
    // add a parameter number to the tree
    Fl_Widget *onelabGroup::_addParameterWidget(onelab::number &p, int ww, int hh, Fl_Tree_Item *n, bool highlight, Fl_Color c)
    {
      char *path = strdup(getPath(n).c_str());
      _treeStrings.push_back(path);
    
      // enumeration (display choices as value labels, not numbers)
      if(p.getChoices().size() &&
         p.getChoices().size() == p.getValueLabels().size()){
        Fl_Choice *but = new Fl_Choice(1, 1, ww, hh);
        std::vector<Fl_Menu_Item> menu;
        std::map<double, std::string> labels(p.getValueLabels());
        for(std::map<double, std::string>::iterator it = labels.begin();
            it != labels.end(); it++){
          char *str = strdup(it->second.c_str());
          _treeStrings.push_back(str);
          Fl_Menu_Item menuItem = {str, 0, 0, 0, 0};
          if(highlight) menuItem.labelcolor(c);
          menu.push_back(menuItem);
        }
        Fl_Menu_Item it = {0};
        menu.push_back(it);
        but->copy(&menu[0]);
        for(unsigned int i = 0; i < p.getChoices().size(); i++){
          if(p.getValue() == p.getChoices()[i]){
            but->value(i);
            break;
          }
        }
        but->callback(onelab_number_choice_cb, (void*)path);
        but->align(FL_ALIGN_RIGHT);
        if(p.getReadOnly()) but->deactivate();
        return but;
      }
    
      // check box (boolean choice)
      if(p.getChoices().size() == 2 &&
         p.getChoices()[0] == 0 && p.getChoices()[1] == 1){
        n->labelsize(FL_NORMAL_SIZE + 2);
        Fl_Check_Button *but = new Fl_Check_Button(1, 1, ww / _widgetLabelRatio, hh);
        but->box(FL_FLAT_BOX);
        but->color(_tree->color());
        but->value(p.getValue());
        but->callback(onelab_number_check_button_cb, (void*)path);
        if(highlight) but->color(c);
        if(p.getReadOnly()) but->deactivate();
        return but;
      }
    
      // non-editable value
      if(p.getReadOnly()){
        outputRange *but = new outputRange(1, 1, ww, hh);
        //TODO but->callback(onelab_number_output_range_cb, (void*)path);
        but->value(p.getValue());
        but->align(FL_ALIGN_RIGHT);
        but->graph(p.getAttribute("Graph"));
        if(highlight) but->color(c);
        return but;
      }
    
      // general number input
      inputRange *but = new inputRange(1, 1, ww, hh, onelab::parameter::maxNumber(),
                                       p.getAttribute("ReadOnlyRange") == "1");
      but->value(p.getValue());
      but->minimum(p.getMin());
      but->maximum(p.getMax());
      but->step(p.getStep());
      but->choices(p.getChoices());
      but->loop(p.getAttribute("Loop"));
      but->graph(p.getAttribute("Graph"));
      but->callback(onelab_number_input_range_cb, (void*)path);
      but->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY);
      but->align(FL_ALIGN_RIGHT);
      if(highlight) but->color(c);
      return but;
    }
    // callback for string
    static void onelab_string_input_choice_cb(Fl_Widget *w, void *data)
    {
      if(!data) return;
      std::string name((char*)data);
      std::vector<onelab::string> strings;
      OnelabDatabase::instance()->get(strings, name);
      if(strings.size()){
        Fl_Input_Choice *o = (Fl_Input_Choice*)w;
        onelab::string old = strings[0];
        strings[0].setValue(o->value());
        std::string choices;
        for(int i = 0; i < o->menubutton()->menu()->size(); i++){
          if(o->menubutton()->menu()[i].flags & FL_MENU_TOGGLE){
            if(o->menubutton()->menu()[i].flags & FL_MENU_VALUE)
              choices += "1";
            else
              choices += "0";
          }
        }
        if(choices.size())
          strings[0].setAttribute("MultipleSelection", choices);
        //setGmshOption(strings[0]);
        OnelabDatabase::instance()->set(strings[0], "localGUI");
        autoCheck(old, strings[0]);
      }
    }
    // add parameter string to tree
    Fl_Widget *onelabGroup::_addParameterWidget(onelab::string &p, int ww, int hh,
                                                Fl_Tree_Item *n, bool highlight, Fl_Color c)
    {
      char *path = strdup(getPath(n).c_str());
      _treeStrings.push_back(path);
    
      // macro button
      if(p.getAttribute("Macro") == "Gmsh"){
        Fl_Button *but = new Fl_Button(1, 1, ww / _widgetLabelRatio, hh);
        but->box(FL_FLAT_BOX);
        but->color(_tree->color());
        but->selection_color(_tree->color());
        but->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
        //TODO but->callback(onelab_string_button_cb, (void*)path);
        if(highlight) but->color(c);
        return but;
      }
    
      // non-editable value
      if(p.getReadOnly()){
        Fl_Output *but = new Fl_Output(1, 1, ww, hh);
        but->value(p.getValue().c_str());
        but->align(FL_ALIGN_RIGHT);
        if(highlight) but->color(c);
        return but;
      }
    
      // simple string (no menu)
      if(p.getChoices().empty() && p.getKind() != "file"){
        Fl_Input *but = new Fl_Input(1, 1, ww, hh);
        but->value(p.getValue().c_str());
        //TODO but->callback(onelab_string_input_cb, (void*)path);
        but->when(FL_WHEN_ENTER_KEY);
        but->align(FL_ALIGN_RIGHT);
        if(highlight) but->color(c);
        return but;
      }
    
      // general string input
      Fl_Input_Choice *but = new Fl_Input_Choice(1, 1, ww, hh);
      std::string multipleSelection = p.getAttribute("MultipleSelection");
      if(multipleSelection.size())
        ;//but->menubutton()->callback(multiple_selection_menu_cb, but);
      std::vector<Fl_Menu_Item> menu;
      for(unsigned int j = 0; j < p.getChoices().size(); j++){
        char *str = strdup(p.getChoices()[j].c_str());
        _treeStrings.push_back(str);
        bool divider = (p.getKind() == "file" &&
                        j == p.getChoices().size() - 1);
        int choice = multipleSelection.size() ? FL_MENU_TOGGLE : 0;
        if(multipleSelection.size() > j && multipleSelection[j] == '1')
          choice |= FL_MENU_VALUE;
        Fl_Menu_Item it = {str, 0, 0, 0, divider ? FL_MENU_DIVIDER : choice};
        menu.push_back(it);
      }
      //if(p.getKind() == "file"){
      //  Fl_Menu_Item it = {"Choose...", 0, onelab_input_choice_file_chooser_cb, (void*)n};
      //  menu.push_back(it);
      //  Fl_Menu_Item it2 = {"Edit...", 0, onelab_input_choice_file_edit_cb, (void*)n};
      //  menu.push_back(it2);
      //  if(GuessFileFormatFromFileName(p.getValue()) >= 0){
      //    Fl_Menu_Item it3 = {"Merge...", 0, onelab_input_choice_file_merge_cb, (void*)n};
      //    menu.push_back(it3);
      //  }
      //}
      Fl_Menu_Item it = {0};
      menu.push_back(it);
      but->menubutton()->copy(&menu[0]);
      but->value(p.getValue().c_str());
      but->callback(onelab_string_input_choice_cb, (void*)path);
      but->input()->when(FL_WHEN_ENTER_KEY);
      but->align(FL_ALIGN_RIGHT);
      if(highlight) but->input()->color(c);
      return but;
    }
    Fl_Widget *onelabGroup::_addParameterWidget(onelab::region &p, int ww, int hh,
                                                Fl_Tree_Item *n, bool highlight, Fl_Color c)
    {
      char *path = strdup(getPath(n).c_str());
      _treeStrings.push_back(path);
    
      // non-editable value
      if(p.getReadOnly()){
        inputRegion *but = new inputRegion(1, 1, ww, hh, true);
        but->value(p.getValue());
        but->align(FL_ALIGN_RIGHT);
        if(highlight) but->color(c);
        return but;
      }
    
      inputRegion *but = new inputRegion(1, 1, ww, hh, false);
      but->value(p.getValue());
      but->align(FL_ALIGN_RIGHT);
      //TODO but->callback(onelab_region_input_cb, (void*)path);
      if(highlight) but->color(c);
      return but;
    }
    
    Fl_Widget *onelabGroup::_addParameterWidget(onelab::function &p, int ww, int hh,
                                                Fl_Tree_Item *n, bool highlight, Fl_Color c)
    {
      // non-editable value
      if(1 || p.getReadOnly()){
        Fl_Output *but = new Fl_Output(1, 1, ww, hh);
        but->value("TODO function");
        but->align(FL_ALIGN_RIGHT);
        if(highlight) but->color(c);
        return but;
      }
    }
    
    void onelabGroup::updateParameter(onelab::parameter &p)
    {
      int type = p.getAttributeType();
      if(type == onelab::number::attributeType())
          return updateParameter(*(onelab::number *)&p);
      if(type == onelab::string::attributeType())
          return updateParameter(*(onelab::string *)&p);
    }
    void onelabGroup::updateParameter(onelab::number &p)
    {
      Fl_Tree_Item *n = _tree->find_item(p.getName().c_str());
      if(!n) {
        addParameter(p);
        return;
      }
      Fl_Group *grp = (Fl_Group *)n->widget();
      // enumeration (display choices as value labels, not numbers)
      if(p.getChoices().size() &&
         p.getChoices().size() == p.getValueLabels().size()){
        Fl_Choice *but = (Fl_Choice *)grp->child(0);
        //std::vector<Fl_Menu_Item> menu;
        //std::map<double, std::string> labels(p.getValueLabels());
        //for(std::map<double, std::string>::iterator it = labels.begin();
        //    it != labels.end(); it++){
        //  char *str = strdup(it->second.c_str());
        //  _treeStrings.push_back(str);
        //  Fl_Menu_Item menuItem = {str, 0, 0, 0, 0};
        //  if(highlight) menuItem.labelcolor(c);
        //  menu.push_back(menuItem);
        //}
        //Fl_Menu_Item it = {0};
        //menu.push_back(it);
        //but->copy(&menu[0]);
        for(unsigned int i = 0; i < p.getChoices().size(); i++){
          if(p.getValue() == p.getChoices()[i]){
            but->value(i);
            break;
          }
        }
        return;
      }
    
      // check box (boolean choice)
      if(p.getChoices().size() == 2 &&
         p.getChoices()[0] == 0 && p.getChoices()[1] == 1){
        Fl_Check_Button *but = (Fl_Check_Button *)grp->child(0);
        but->value(p.getValue());
        return;
      }
    
      // non-editable value FIXME
      if(p.getReadOnly()){
        outputRange *but = (outputRange *)grp->child(0);;
        but->value(p.getValue());
        but->graph(p.getAttribute("Graph"));
        return;
      }
    
      // general number input
      inputRange *but = (inputRange *)grp->child(0);
      but->value(p.getValue());
      but->minimum(p.getMin());
      but->maximum(p.getMax());
      but->step(p.getStep());
      but->choices(p.getChoices());
      but->loop(p.getAttribute("Loop"));
      but->graph(p.getAttribute("Graph"));
    }
    void onelabGroup::updateParameter(onelab::string &p)
    {
      Fl_Tree_Item *n = _tree->find_item(p.getName().c_str());
      if(!n) {
        addParameter(p);
        return;
      }
      Fl_Group *grp = (Fl_Group *)n->widget();
      // macro button
      if(p.getAttribute("Macro") == "Gmsh"){
        return;
      }
    
      // non-editable value FIXME
      if(p.getReadOnly()){
        Fl_Output *but = (Fl_Output *)grp->child(0);
        but->value(p.getValue().c_str());
        return;
      }
    
      // simple string (no menu)
      if(p.getChoices().empty() && p.getKind() != "file"){
        Fl_Input *but = (Fl_Input *)grp->child(0);
        but->value(p.getValue().c_str());
        return;
      }
    
      // general string input TODO
      Fl_Input_Choice *but = (Fl_Input_Choice *)grp->child(0);
      but->value(p.getValue().c_str());
    }
    
    void onelabGroup::removeParameter(onelab::parameter &p)
    {
      Fl_Tree_Item *n = _tree->find_item(p.getName().c_str());
      _tree->remove(n);
    }
    
    void onelabGroup::_computeWidths()
    {
      _baseWidth = (int)(_tree->w() - _tree->marginleft());
      _indent = (int)(_tree->connectorwidth() / 2. + _tree->openicon()->w() / 2.);
    }
    
    bool onelabGroup::isBusy()
    {
      std::string s(_butt[1]->label());
      if(s == "Run") return false;
      return true;
    }
    
    std::string onelabGroup::getPath(Fl_Tree_Item *item)
    {
      if(!item){
        Msg::Error("No item for path");
        return "";
      }
      char path[1024];
      if(_tree->item_pathname(path, sizeof(path), item)){
        Msg::Error("Could not get path for item");
        return "";
      }
      return std::string(path);
    }
    
    void onelabGroup::_addMenu(const std::string &path, Fl_Callback *callback, void *data)
    {
      Fl_Tree_Item *n = _tree->add(path.c_str());
      _tree->begin();
      int ww = _baseWidth - (n->depth() + 1) * _indent;
      int hh = n->labelsize() + 4;
      Fl_Group *grp = new Fl_Group(1, 1, ww, hh);
      Fl_Button *but = new Fl_Button(1, 1, ww, hh);
      but->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
      but->callback(callback, data);
      but->box(FL_FLAT_BOX);
      but->color(_tree->color());
      but->selection_color(_tree->color());
      grp->end();
      if(!_enableTreeWidgetResize) grp->resizable(0);
      _treeWidgets.push_back(grp);
      std::string label = path;
      std::string::size_type last = path.find_last_of('/');
      if(last != std::string::npos) label = path.substr(last + 1);
      but->copy_label(label.c_str());
      n->widget(grp);
      _tree->end();
    }
    
    void onelabGroup::_addSolverMenu(int num)
    {
      std::ostringstream path;
      path << "0Modules/Solver/Solver" << num;
      Fl_Tree_Item *n = _tree->add(path.str().c_str());
      int ww = _baseWidth - (n->depth() + 1) * _indent;
      int hh = n->labelsize() + 4;
      _tree->begin();
      Fl_Group *grp = new Fl_Group(1, 1, ww, hh);
      new solverButton(1, 1, ww, hh, num, _tree->color());
      grp->end();
      if(!_enableTreeWidgetResize) grp->resizable(0);
      _treeWidgets.push_back(grp);
      n->widget(grp);
      _tree->end();
    }
    
    void onelabGroup::_addViewMenu(int num)
    {
      std::ostringstream path;
      path << "0Modules/Post-processing/View" << num;
      Fl_Tree_Item *n = _tree->add(path.str().c_str());
      int ww = _baseWidth - (n->depth() + 1) * _indent;
      int hh = n->labelsize() + 4;
      _tree->begin();
      Fl_Group *grp = new Fl_Group(1, 1, ww, hh);
      new viewButton(1, 1, ww, hh, num, _tree->color());
      grp->end();
      if(!_enableTreeWidgetResize) grp->resizable(0);
      _treeWidgets.push_back(grp);
      n->widget(grp);
      _tree->end();
    }
    
    viewButton *onelabGroup::getViewButton(int num)
    {
      char tmp[256];
      sprintf(tmp, "0Modules/Post-processing/View%d", num);
      Fl_Tree_Item *n = _tree->find_item(tmp);
      if(n){
        Fl_Group *grp = (Fl_Group*)n->widget();
        return (viewButton*)grp->child(0);
      }
      return 0;
    }