#include "interface_callbacks.h"
#include "fileIO.h"
#include "ndisplay.h"
#include "geometry.h"
#include <iostream>
#include <sstream>
#include <set>
#include <list>

void drawsb(data_env* current);

int mycallbacks::key_callback(int key, const char* str)
{
  properties pr;
  pr.c=color(255,0,0);
  pr.pointsize=7;
  properties pr2;
  pr2.c=color(255,0,0,64);
  pr2.pointsize=7;
  double radius;
  if (str)
    switch ( str[0] )
    {
      case 'k' :  
      case 'K' :  pts.clear();env.buffer[2].clear();donec=false;donep=false;
                  env.buffer[2].setproppoints(pr);break;
      case 's' :
      case 'S' :  for (auto i=pts.begin();i!=pts.end();++i) std::cout << *i << std::endl;break;
      case 'g' :
      case 'G' :  {
                    std::vector<npoint3> pts_tmp;pts_tmp.reserve(pts.size());
                    std::vector<npoint3> pts_out;pts_out.reserve(pts.size());
                    for (auto i=pts.begin();i!=pts.end();++i) pts_tmp.push_back(*i);
                    get_cyl(pts_tmp,basec,normalc,radius,pts_out);
//                    pts_tmp=pts_out;
                    get_cyl_fine(pts_tmp,basec,normalc,radius,pts_out,true);
                    donec=true;
                    pts.clear();
                    env.buffer[2].clear();
                    env.buffer[2].setproppoints(pr2);
                    for(int i=0;i<pts_out.size();++i)
                    {
                      env.buffer[2].add_point(pts_out[i]);
    //                    pts.insert(pts_out[i]);
                    }
                    env.buffer[2].setproppoints(pr);
                  }
                  break;
      case 't' :  
      case 'T' :  {
                    std::vector<npoint3> pts_tmp;pts_tmp.reserve(pts.size());
                    std::vector<npoint3> pts_out;pts_out.reserve(pts.size());
                    for (auto i=pts.begin();i!=pts.end();++i) pts_tmp.push_back(*i);
                    get_plane(pts_tmp,basep,normalp,pts_out);
                    donep=true;
                    pts.clear();
                    env.buffer[2].clear();
                    env.buffer[2].setproppoints(pr2);
                    for(int i=0;i<pts_out.size();++i)
                    {
                      env.buffer[2].add_point(pts_out[i]);
    //                   pts.insert(pts_out[i]);
                    }                   
                    env.buffer[2].setproppoints(pr);
                  }
                  break;
      case 'v' :  
      case 'V' :  {
                    std::vector<npoint3> pts_tmp;pts_tmp.reserve(pts.size());
                    std::vector<npoint3> pts_out;pts_out.reserve(pts.size());
                    for (auto i=pts.begin();i!=pts.end();++i) pts_tmp.push_back(*i);
                    double angle;//unused
                    get_cone(pts_tmp,basep,normalp,angle,pts_out);
                    donep=true;
                    pts.clear();
                    env.buffer[2].clear();
                    env.buffer[2].setproppoints(pr2);
                    for(int i=0;i<pts_out.size();++i)
                    {
                      env.buffer[2].add_point(pts_out[i]);
    //                   pts.insert(pts_out[i]);
                    }                   
                    env.buffer[2].setproppoints(pr);
/*                    std::pair<npoint3,npoint3> sc(basep,normalp);
                    env.scanbodies.push_back(sc);
                    env.display->up_to_date=false;
                    drawsb(&env);
                    env.display->update_bb();*/
                  }
                  break;
      case ' ' :  env.display->setpick(!env.display->getpick());
                  break;
      case 'd' :  
      case 'D' :  if (env.scanbodies.size())
                  {
                    env.scanbodies.pop_back();
                    std::cout << "deleted sc num. " << env.scanbodies.size()+1 << std::endl;
                    env.display->up_to_date=false;
                    drawsb(&env);
                    env.display->update_bb();
                  }
                  break;
      case 'q' :  
      case 'Q' :  std::cout << "exited digitize mode" << std::endl;
                  pts.clear();env.buffer[2].clear();donec=false;donep=false;
                  env.buffer[2].setproppoints(pr);
                  env.display->up_to_date=false;
                  env.display->allow_picks(false);
                  env.display->individual_picks(false);
                  break;
      case 'r' :  
      case 'R' :  if (env.scanbodies.size())
                  {
                    env.scanbodies.rbegin()->second=env.scanbodies.rbegin()->second*-1;
                    env.display->up_to_date=false;
                    drawsb(&env);
                    env.display->update_bb();
                  }
                  break;
      default :   return 0;
  }
  if (donec&&donep)
  {
    donec=false;
    donep=false;
    npoint3 res;
    int_line_plane(basec, normalc, basep, normalp, res);
    npoint3 orinor=res-basec;
    orinor.normalize();
    npoint3 vec=orinor*env.sbh;
    res-=vec;
    std::cout << "base point : [ "
        << res[0] << " , "
        << res[1] << " , "
        << res[2] << " ]" << std::endl;

    std::cout << "normal : [ "
        << orinor[0] << " , "
        << orinor[1] << " , "
        << orinor[2] << " ]" << std::endl;
    std::pair<npoint3,npoint3> sc(res,orinor);
    env.scanbodies.push_back(sc);
    std::cout << "inserted sc num. " << env.scanbodies.size() << std::endl;
    env.display->up_to_date=false;
    drawsb(&env);
    env.display->update_bb();
  }
  return 1; // nothing to be done
}

int mycallbacks::pick_callback(int nb, pickinfo picks[],npoint3 p)
{
/*  std::cout << "num=" << nb << std::endl;
  std::cout << p(0) << " " << p(1) << " " << p(2) << std::endl;
  for(unsigned int j = 0; j < nb; j++)
  {
    std::cout << "t=" << picks[j].type << " id=" << picks[j].id << " ";
    for (int i=0;i<picks[j].nb_uid;++i) 
      std::cout << "uid" << i << "=" << picks[j].uids[i] << " ";
    std::cout << picks[j].z  << std::endl;
  }*/
  if (nb)
  {
    if ((picks[0].id!=-1) && (picks[0].seg==0)&& (picks[0].type==3)) //pick only triangles from the STL
    {
        
//        pts.push_back((npoint3)p);
//        env.buffer[2].add_point((npoint3)p);
//      std::cout << picks[0].id << " " << picks[0].type << " " << p(0) << " " << p(1) << " " << p(2) << std::endl;
      triangle& tr=env.buffer[0].get_triangle(picks[0].id);
      for (int i=0;i<3;++i)
      {
        env.buffer[2].add_point(tr.pts[i]);
        pts.insert(tr.pts[i]);
      }
      return 0; // first element in the stack (closest to the eye) is chosen (-1 if no pick wanted)
    }
  }
  else
  {
    const int nb_pts=1;
    unsigned int tab[nb_pts];
    double dist[nb_pts];

    int res=env.mesh.search(p,nb_pts,tab,dist);
//    std::cout << dist[0] << std::endl;
//    pts.insert((npoint3)p);
//    env.buffer[2].add_point((npoint3)p);
    std::unordered_set<int> tabele;
    std::list<int> bnd;
    npoint3 vec(0.);
    npoint3 vec2(0.);
    for (int i=0;i<res;++i)
    {
      pts.insert(env.mesh.vertices[tab[i]].first);
      env.buffer[2].add_point(env.mesh.vertices[tab[i]].first);
      for (int j=0;j<env.mesh.vertices[tab[i]].second.size();++j)
      {
        auto result=tabele.insert(env.mesh.vertices[tab[i]].second[j]);
        if (result.second)
        {
          bnd.push_back(env.mesh.vertices[tab[i]].second[j]);
          vec+=env.mesh.facets[env.mesh.vertices[tab[i]].second[j]].normal;
        }
      }
      vec.normalize();
    }
    if (env.bulk_select)
    while (bnd.size())
    {
      int it=bnd.front();
      bnd.pop_front();
      {
        for(int itb=0;itb!=env.mesh.neighbors[it].tab.size();++itb)
        {
          int nei=env.mesh.neighbors[it].tab[itb];
          auto result=tabele.insert(nei);
          if (result.second)
          {
            vec2=env.mesh.facets[nei].normal;
            vec2.normalize();

            if (((!donep)&&(vec.dotprod(vec2)>0.995))||(donep&&(fabs(normalp.dotprod(vec2))<0.05)))
            {
              bnd.push_back(nei);
              for(int k=0;k<3;++k)
              {
                pts.insert(env.mesh.facets[nei].pts[k]);
                env.buffer[2].add_point(env.mesh.facets[nei].pts[k]);
              }
            }
          }
        }
      }
    }
  }
  return -1;
}


#ifdef INTERFACE_TYPE_FLTK
#include <FL/Fl_Native_File_Chooser.H>
#include <FL/Fl_Menu_Item.H>
#include "nfltkwindow.h"

void STLedges_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  const Fl_Menu_Item *mi = ((Fl_Menu_ *)w)->mvalue(); // get the modified menu item ...
  auto v = mi->checked();  
  if (v) current->edgeon=true;
  else
    current->edgeon=false;
  current->buffer[0].clear();
  properties pp;
  pp.edgeon=current->edgeon;
  current->buffer[0].setproptriangles(pp);
  current->mesh.Display(current->buffer[0]);
  current->display->redraw();  
}

void LoadSTL_callback(Fl_Widget* w, void* p)
{
  stlmesh_nn mesh2;
  data_env* current=(data_env*)p;
  Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
  chooser->type(Fl_Native_File_Chooser::BROWSE_FILE);
  chooser->filter("STL files\t*.stl");
  chooser->title("Read STL file");
  switch ( chooser->show() )
  {
    case -1:    // ERROR
      std::cout << "*** ERROR show() failed:" << chooser->errmsg()<< std::endl;
      break;
    case 1:     // CANCEL
      break;
    default:    // USER PICKED A FILE
      try
      {
        loadmesh(chooser->filename(),current->mesh);
      }
      catch (int)
      {
        std::cout << "Problem reading STL" << std::endl;
//        current->mesh.clear();
        current->buffer[0].clear();
        break;
      }
  //    current->mesh=mesh2;
      current->mesh.build_kdtree();
      current->buffer[0].clear();
      properties p;
      p.edgeon=current->edgeon;
      current->buffer[0].setproptriangles(p);
      current->mesh.Display(current->buffer[0]);
      current->display->init_data(current->buffer);
      current->display->reset_view();
      std::string path=chooser->filename();
      current->STLname = path.substr(path.find_last_of("/\\") + 1);
      std::string msg  = "|  " + current->STLname+"  |  "+ current->SBname+"  |  "+current->RSBname + "  |";
      current->display->win->copy_label(msg.c_str());
      break;
  }
  delete chooser;
}

void drawsb(data_env* current)
{
  std::vector<std::pair<npoint3,npoint3> > &sb1=current->scanbodies;
  std::vector<std::pair<npoint3,npoint3> > &sb2=current->ref_scanbodies;
  current->buffer[1].clear();
  properties p;
  p.c=color(255,0,0);
  p.pointsize=7;
  current->buffer[1].setproppoints(p);
  double sbz=current->sbh*2;
  if (sbz==0.0) sbz=10.;
  for(int i=0;i<sb1.size();++i)
  {
    current->buffer[1].add_point(sb1[i].first);
//    current->buffer[1].add_point(sb1[i].first+sb1[i].second*current->sbh);
    current->buffer[1].add_line(line(sb1[i].first,sb1[i].first+sb1[i].second*sbz));
  }
  p.c=color(0,255,0);
  current->buffer[1].setproppoints(p);
  for(int i=0;i<sb2.size();++i)
  {
    current->buffer[1].add_point(sb2[i].first);
//    current->buffer[1].add_point(sb2[i].first+sb2[i].second*current->sbh);
    current->buffer[1].add_line(line(sb2[i].first,sb2[i].first+sb2[i].second*sbz));
  }
  current->display->init_data(current->buffer);
}

void clearsb(data_env* current)
{
  current->SBname="";
  std::string msg  = "|  " + current->STLname+"  |  "+ current->SBname+"  |  "+current->RSBname + "  |";
  current->display->win->copy_label(msg.c_str());
  current->scanbodies.clear();
  drawsb(current);
  current->display->update_bb();
}

void clearrsb(data_env* current)
{
  current->RSBname="";
  std::string msg  = "|  " + current->STLname+"  |  "+ current->SBname+"  |  "+current->RSBname + "  |";
  current->display->win->copy_label(msg.c_str());
  current->ref_scanbodies.clear();
  drawsb(current);
  current->display->update_bb();
}


void Loadsb(data_env *current,std::vector<std::pair<npoint3,npoint3> > &sb,std::string &name)
{
  Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
  chooser->type(Fl_Native_File_Chooser::BROWSE_FILE);
  chooser->filter("Scanbodies files\t*.txt");
  chooser->title("Read Scanbodies");
  switch ( chooser->show() )
  {
    case -1:    // ERROR
      std::cout << "*** ERROR show() failed:" << chooser->errmsg()<< std::endl;
      break;
    case 1:     // CANCEL
      break;
    default:    // USER PICKED A FILE
      try
      {
        loadSB(chooser->filename(),sb);
      }
      catch (int)
      {
        std::cout << "Problem reading scanbodies" << std::endl;
        break;
      }
      std::string path=chooser->filename();
      name = path.substr(path.find_last_of("/\\") + 1);
      drawsb(current);
      current->display->reset_view();
      break;
  }
  delete chooser;
}


void LoadPoints(data_env *current,std::vector<std::pair<npoint3,npoint3> > &sb,std::vector<npoint3> &pts,std::string &name)
{
  Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
  chooser->type(Fl_Native_File_Chooser::BROWSE_FILE);
  chooser->filter("Points files\t*.txt");
  chooser->title("Read Points");
  switch ( chooser->show() )
  {
    case -1:    // ERROR
      std::cout << "*** ERROR show() failed:" << chooser->errmsg()<< std::endl;
      break;
    case 1:     // CANCEL
      break;
    default:    // USER PICKED A FILE
      try
      {
        pts.clear();
        loadPoints(chooser->filename(),sb,pts,current->sbh);
      }
      catch (int)
      {
        std::cout << "Problem reading points" << std::endl;
        break;
      }
      std::string path=chooser->filename();
      name = path.substr(path.find_last_of("/\\") + 1);
      for (int i=0;i<pts.size();++i) current->buffer[2].add_point(pts[i]);
      drawsb(current);
      current->display->reset_view();
      break;
  }
  delete chooser;
}

void LoadSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  std::vector<std::pair<npoint3,npoint3> > &sb=current->scanbodies;
  std::string name;
  Loadsb(current,sb,name);
  if (name.length())
  {
    current->SBname=name;
    std::string msg  = "|  " + current->STLname+"  |  "+ current->SBname+"  |  "+current->RSBname + "  |";
    current->display->win->copy_label(msg.c_str());
  }
}

void LoadSBR_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  std::vector<std::pair<npoint3,npoint3> > &sbr=current->ref_scanbodies;
  std::string name;
  Loadsb(current,sbr,name);
  if (name.length())
  {
    current->RSBname=name;
    std::string msg  = "|  " + current->STLname+"  |  "+ current->SBname+"  |  "+current->RSBname + "  |";
    current->display->win->copy_label(msg.c_str());
  }
}

void SetAsRefSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  std::vector<std::pair<npoint3,npoint3> > &sb=current->scanbodies;
  std::vector<std::pair<npoint3,npoint3> > &sbr=current->ref_scanbodies;
  sbr=sb;
  current->RSBname=current->SBname;
  current->SBname.clear();
  sb.clear();
  std::string msg  = "|  " + current->STLname+"  |  "+ current->SBname+"  |  "+current->RSBname + "  |";
  current->display->win->copy_label(msg.c_str());
  drawsb(current);
  current->display->update_bb();
  current->display->up_to_date=false;
}


void RevertnumSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  std::vector<std::pair<npoint3,npoint3> > &sb=current->scanbodies;
  reverse(sb.begin(), sb.end());
  drawsb(current);
  current->display->update_bb();
  current->display->up_to_date=false;
}

void TranslateSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  std::vector<std::pair<npoint3,npoint3> > &sb=current->scanbodies;
  char str[255];
  sprintf(str,"%.3f",0.0);
  const char *res=fl_input("Enter translation height (in mm) ",str);
  if (res)
  {
    double val=atof(res);
    for (auto it=sb.begin();it!=sb.end();++it)
    {
      it->first=it->first+it->second*val;
    }  
    drawsb(current);
    current->display->update_bb();
    current->display->up_to_date=false;
  }
}


void InvertSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  std::vector<std::pair<npoint3,npoint3> > &sb=current->scanbodies;
  for (auto it=sb.begin();it!=sb.end();++it)
  {
    it->second=it->second*-1;
  }  
  drawsb(current);
  current->display->update_bb();
  current->display->up_to_date=false;
}

void LoadPoints_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  std::vector<std::pair<npoint3,npoint3> > &sb=current->scanbodies;
  std::vector<npoint3> pts;
  
  std::string name;
  LoadPoints(current,sb,pts,name);
  if (name.length())
  {
    current->SBname=name;
    std::string msg  = "|  " + current->STLname+"  |  "+ current->SBname+"  |  "+current->RSBname + "  |";
    current->display->win->copy_label(msg.c_str());
  }
}


void compare(std::vector<std::pair<npoint3,npoint3> > &sb, std::vector<std::pair<npoint3,npoint3> > &sbr, std::stringstream &buffer)
{
  if (sb.size() && sbr.size())
  {
    adjustsb(sb,sbr);
    int max;
    if (sb.size()<=sbr.size()) max=sb.size(); else max=sbr.size();
    double d=0;
    std::vector<int> tab(max);
    std::vector<double> dd(max);
    std::vector<npoint3> pp(max);
    for (int i=0;i<max;++i)
    {
      dd[i]=-1;
      for (int j=0;j<max;++j)
      {
        npoint3 p=sb[i].first-sbr[j].first;
        if (dd[i]<0 || p.norm()<dd[i])
        {dd[i]=p.norm();pp[i]=p;tab[i]=j;}
      }
      d+=dd[i]*dd[i];
    }

    for (int i=0;i<max;++i)
    {
      npoint3 pp_; //dans le repere lié au SB de reference
      npoint3 rot[3]; // repere lié au SB de reference
      rot[0]=sbr[tab[i]].second; //axe vertical
      if (i==0) rot[1]=sbr[tab[i+1]].first-sbr[tab[i]].first;
      else
        if (i==max-1) rot[1]=sbr[tab[i]].first-sbr[tab[i-1]].first;
      else
        rot[1]=sbr[tab[i+1]].first-sbr[tab[i-1]].first;
      
      rot[1].normalize();
      double psca=rot[1].dotprod(rot[0]);
      rot[0]-=psca*rot[1];
      rot[0].normalize();
      rot[2].crossprod(rot[0],rot[1]);
      buffer << "errp " <<i<< "<->" << tab[i] << " : " <<  pp[i].norm() << std::endl;
      buffer << "dx=" << pp[i].x() << " dy=" << pp[i].y() << " dz=" << pp[i].z() <<  std::endl;
  //      buffer << rot[0] << std::endl;
  //      buffer << rot[1] << std::endl;
  //      buffer << rot[2] << std::endl;
      for (int k=0;k<3;++k)
      {
        pp_[k]=0.;
        for (int l=0;l<3;++l)
          pp_[k]+=rot[k][l]*pp[i][l]; // utilisation de la transpose : matrice de transformation orthogonale
      }
      buffer << "dv=" <<  pp_.x() << " dn=" << pp_.y() << " dt=" << pp_.z() << std::endl;
    }

    buffer << "RMS " << " : " <<  sqrt(d/max) <<std::endl;
    d=0;
    double dist=0;
    int imax,jmax;
    double distseq[max-1];
    int nb=0;
    for (int i=0;i<max;++i)
    {
      for (int j=i+1;j<max;++j)
      {
        npoint3 p=sb[i].first-sb[j].first;
        npoint3 pp=sbr[tab[i]].first-sbr[tab[j]].first;
        nb++;
        double dd= fabs(p.norm()-pp.norm());
        if (j==i+1) distseq[i]=dd;
        if (dd>dist) {imax=i;jmax=j; dist=dd;}
      }
    }
    
    for (int i=0;i<max-1;++i) buffer << "dist " <<i << "->"<<i+1 << " : " << distseq[i] << std::endl;
    buffer << "Maxd " << imax << "->" << jmax << " : " <<  dist <<std::endl;
    
    for (int i=0;i<max;++i)
    {
      npoint3 p=sb[i].second-sbr[tab[i]].second;
      double dd=p.norm();
      buffer << "errv (°) " <<i << "<->" << tab[i] << " : " <<  180*dd/3.1415926536   <<std::endl;
      d+=dd;
    }
    buffer << "meanv (°)" << " : " <<  180*d/(max*3.1415926536) <<std::endl;
  }
  else
    buffer << "no data !" << std::endl;
}

void AdjustSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  std::vector<std::pair<npoint3,npoint3> > &sb=current->scanbodies;
  std::vector<std::pair<npoint3,npoint3> > &sbr=current->ref_scanbodies;
  std::stringstream buffer;
  compare(sb,sbr,buffer);
  drawsb(current);
  current->display->update_bb();
  std::string str=buffer.str();
  std::cout <<  str << std::endl;
  fl_message("%s",str.c_str());
}

void SaveSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  std::vector<std::pair<npoint3,npoint3> > &sb=current->scanbodies;
  Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
  chooser->type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
  chooser->filter("Scanbodies files\t*.txt");
  chooser->title("Save Scanbodies");
  std::string name=current->STLname+".txt";
  chooser->preset_file(name.c_str());
  
  switch ( chooser->show() )
  {
    case -1:    // ERROR
      std::cout << "*** ERROR show() failed:" << chooser->errmsg()<< std::endl;
      break;
    case 1:     // CANCEL
      break;
    default:    // USER PICKED A FILE
      try
      {
        saveSB(chooser->filename(),sb);
      }
      catch (int)
      {
        std::cout << "Problem saving scanbodies" << std::endl;
        break;
      }
      break;
  }
  delete chooser;
}

void ClearSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  clearsb(current);
}

void ClearRSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  clearrsb(current);
}

void DigitizeSB_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  ndisplay *win = current->display;
  clearsb(current);
  char str[255];
  sprintf(str,"%.3f",current->sbh);
  const char *res=fl_input("Hit space to start picking, then : \n1 - Pick flat top of scanbody OR conical top \n2 - press <t> if plane or <v> if cone \n3 - pick cylindrical side of scanbody\n4 - press <g>\n5 - repeat \n\nAt any time : <space> toggles picking or no picking, <k> empties the current pick list,\n <s> prints current points, <d> deletes the last scanbody, <q> leaves digitize mode.\n\nWhen all scanbodies have beed digitized, simply save them using the menu [Scanbodies]->[Save scanbodies]\n\nEnter SB height",str);
  if (res)
  {
    double val=atof(res);
    if (val>=0.0) current->sbh=val;
  }
  win->allow_picks();
  win->individual_picks();
//  current->display.update_bb();
//  current->display.draw();
}

void ToggleSMode_callback(Fl_Widget* w, void* p)
{
  data_env* current=(data_env*)p;
  const Fl_Menu_Item *mi = ((Fl_Menu_ *)w)->mvalue(); // get the modified menu item ...
  auto v = mi->checked();  
  if (v) current->bulk_select=false; else current->bulk_select=true;
}

const Fl_Menu_Item custom_menu_items[] = {
//  { "NO_DEFAULT_MENU" },
  { "&STL",              0, 0, 0, FL_SUBMENU},
      { "Load S&TL",  0, (Fl_Callback *)LoadSTL_callback},
      { "Show STL edges",              0, (Fl_Callback *)STLedges_callback, 0, FL_MENU_TOGGLE},
      { "Individual &selection mode",  0, (Fl_Callback *)ToggleSMode_callback,0,FL_MENU_TOGGLE},
      { 0 } ,
  { "Scan&bodies",              0, 0, 0, FL_SUBMENU },
    { "Load &Points",  0, (Fl_Callback *)LoadPoints_callback},
    { "&Load scanbodies",  0, (Fl_Callback *)LoadSB_callback},
    { "Load &Reference scanbodies",  0, (Fl_Callback *)LoadSBR_callback},
    { "Set &as Reference scanbodies",  0, (Fl_Callback *)SetAsRefSB_callback},
    { "Revert SB numbering",  0, (Fl_Callback *)RevertnumSB_callback},
    { "Translate SBs along normal",  0, (Fl_Callback *)TranslateSB_callback},
    { "Invert normals",  0, (Fl_Callback *)InvertSB_callback},
    { "Adjust & measure error",  0, (Fl_Callback *)AdjustSB_callback},
    { "&Save scanbodies",  0, (Fl_Callback *)SaveSB_callback},
    { "Clear scanbodies",  0, (Fl_Callback *)ClearSB_callback},
    { "Clear reference scanbodies",  0, (Fl_Callback *)ClearRSB_callback},
    { "&Digitize scanbodies",  0, (Fl_Callback *)DigitizeSB_callback},
    { 0 },
  { "USER_MENU_END" },
};
#endif
