Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

ControlBase.cc

Go to the documentation of this file.
00001 #include "ControlBase.h"
00002 #include "Motion/MMAccessor.h"
00003 #include "Shared/Config.h"
00004 #ifdef TGT_HAS_LEDS
00005 #  include "Motion/LedMC.h"
00006 #endif
00007 #include "Shared/string_util.h"
00008 #include "Sound/SoundManager.h"
00009 #include "Wireless/Wireless.h"
00010 #include <iomanip>
00011 #include <sstream>
00012 
00013 ControlBase * ControlBase::activate(MC_ID display, Socket * gui) {
00014   display_id=display;
00015   gui_comm=gui;
00016   hilightFirst();
00017   refresh();
00018   return this;
00019 }
00020 
00021 void ControlBase::pause() {
00022   if(doRewrite) {
00023     doRewrite=false;
00024   }
00025 }
00026 
00027 void ControlBase::refresh() {
00028   //Level 1: LEDs
00029 #ifdef TGT_HAS_LEDS
00030   if(display_id!=invalid_MC_ID) {
00031     if(hilights.size()>0) {
00032       MMAccessor<LedMC> display(display_id);
00033       unsigned int cur=hilights.front();
00034       if(options.size()<=10)
00035         display.mc()->displayNumber(cur,LedEngine::onedigit);
00036       else
00037         display.mc()->displayNumber(cur,LedEngine::twodigit);
00038     }
00039   }
00040 #endif
00041 
00042   //Just do one of the other two levels to avoid over-redundancy
00043   if(gui_comm==NULL || !wireless->isConnected(gui_comm->sock)) {
00044 #ifndef PLATFORM_APERIOS
00045     if(!wireless->isConnected(sout->sock))
00046       return;
00047 #endif
00048     //Level 2: Console
00049     const char * const nosel="  ";
00050     const char * slctd="**";
00051     if(config->main.use_VT100) {
00052       slctd="\33[1m**\33[0m";
00053       if(doRewrite)
00054         clearMenu();
00055       sout->printf("\33[1m%s\33[0m:\n",getName().c_str()); //displays name in bold
00056     } else
00057       sout->printf("%s:\n",getName().c_str());
00058     unsigned int digits=0;
00059     for(unsigned int i=1; i<options.size(); i*=10)
00060       digits++;
00061     for(unsigned int i=0; i<options.size(); i++) {
00062       if(options[i]==NULL)
00063         for(unsigned int j=0; j<strlen(nosel)+digits+2; j++)
00064           sout->printf(" ");
00065       else
00066         sout->printf("%s%*d%s ",(find(hilights.begin(),hilights.end(),i)!=hilights.end()?slctd:nosel),digits,i,(options[i]->slotsSize()>0?">":"."));
00067       //cout << (find(hilights.begin(),hilights.end(),i)!=hilights.end()?slctd:nosel) << std::setw(digits) << i << "> ";
00068       sout->printf("%s\n",getSlotName(i).c_str());
00069     }
00070     if(options.size()==0)
00071       sout->printf("  Empty menu\n");
00072     doRewrite=true;
00073   } else {
00074     //Level 3: GUI
00075 
00076     //    cout << "REFRESHING " << getName() << endl;
00077     //try to get it all in one packet for better performance
00078     std::stringstream ss;
00079     ss << "refresh\n"
00080        << getName() << '\n'
00081        << options.size() << '\n';
00082     for(unsigned int i=0; i<options.size(); i++) {
00083       if(options[i]==NULL)
00084         ss << "0\n0\n----------\n0\n\n";
00085       else {
00086         std::string desc = options[i]->getDescription();
00087         ss << options[i]->options.size() << '\n'
00088            << (binary_search(hilights.begin(),hilights.end(),i)?1:0) << '\n'
00089            << options[i]->getName() << '\n'
00090            << std::count(desc.begin(),desc.end(),'\n') << '\n'
00091            << desc << '\n';
00092       }
00093     }
00094     //    do {
00095     //cout << "Writing " << ss.str().size() << "...";
00096     gui_comm->write((const byte*)ss.str().c_str(),ss.str().size());
00097     //    int cnt=gui_comm->printf("%s",(const byte*)ss.str().c_str());
00098     //cout << "wrote " << cnt << endl;
00099     //} while(cnt==-1);
00100   }
00101 }
00102 
00103 void ControlBase::deactivate() {
00104   hilights.clear();
00105 #ifdef TGT_HAS_LEDS
00106   if(display_id!=invalid_MC_ID) {
00107     MMAccessor<LedMC> display(display_id);
00108     display.mc()->clear();
00109   }
00110 #endif
00111   if(doRewrite) {
00112     if(config->main.use_VT100)
00113       clearMenu();
00114     doRewrite=false;
00115   }
00116   display_id=invalid_MC_ID;
00117 }
00118 
00119 ControlBase* ControlBase::doSelect() {
00120   //    cout << "ControlBase::doSelect()" << endl;
00121   //    cout << "cur==" << cur << endl;
00122   if(hilights.size()==0) {
00123     sndman->playFile(config->controller.select_snd);
00124     return this;
00125   }
00126   for(unsigned int i=0;i<hilights.size();i++) {
00127     unsigned int cur=hilights[i];
00128     if(cur>=options.size() || options[cur]==NULL) {
00129 #ifdef TGT_HAS_LEDS
00130       if(display_id!=invalid_MC_ID) {
00131         MMAccessor<LedMC> display(display_id);
00132         display.mc()->cflash(FaceLEDMask,.5f,100);
00133       }
00134 #endif
00135       if(cur>=options.size())
00136         sout->printf("Invalid choice\n");
00137       else
00138         sout->printf("NULL option\n");
00139       continue;
00140     }
00141 #ifdef TGT_HAS_LEDS
00142     if(display_id!=invalid_MC_ID) {
00143       MMAccessor<LedMC> display(display_id);
00144       display.mc()->flash(FaceLEDMask,100);
00145       display.mc()->clear();
00146     }
00147 #endif
00148     if(doRewrite) {
00149       if(config->main.use_VT100)
00150         clearMenu();
00151       doRewrite=false;
00152     }
00153     sndman->playFile(config->controller.select_snd);
00154     if(hilights.size()>1) {
00155       options[cur]->activate(display_id,gui_comm);
00156       options[cur]->deactivate();
00157     }
00158   }
00159   if(hilights.size()==1)
00160     return options[hilights.front()];
00161   return this;
00162 }
00163 
00164 ControlBase* ControlBase::doNextItem() {
00165   //    cout << "ControlBase::doNextItem()" << endl;
00166   if(options.size()==0)
00167     return this;
00168   unsigned int cur=0;
00169   for(unsigned int i=0; i<hilights.size(); i++)
00170     if(hilights[i]>=cur)
00171       cur=(hilights[i]+1)%options.size();
00172   while(options[cur]==NULL)
00173     cur=(cur+1)%options.size();
00174   hilights.clear();
00175   hilights.push_back(cur);
00176   sndman->playFile(config->controller.next_snd);
00177   refresh();
00178   //    cout << "cur==" << cur << endl;
00179   return this;
00180 }
00181 
00182 ControlBase* ControlBase::doPrevItem() {
00183   //    cout << "ControlBase::doPrevItem()" << endl;
00184   if(options.size()==0)
00185     return this;
00186   unsigned int cur=options.size()-1;
00187   for(unsigned int i=hilights.size(); i>0; i--)
00188     if(hilights[i-1]<=cur)
00189       cur=(hilights[i-1]+options.size()-1)%options.size();
00190   while(options[cur]==NULL)
00191     cur=(cur+options.size()-1)%options.size();
00192   hilights.clear();
00193   hilights.push_back(cur);
00194   sndman->playFile(config->controller.prev_snd);
00195   refresh();
00196   //    cout << "cur==" << cur << endl;
00197   return this;
00198 }
00199 
00200 ControlBase * ControlBase::doCancel() {
00201   sndman->playFile(config->controller.cancel_snd);
00202   return NULL;
00203 }
00204 
00205 
00206 ControlBase* ControlBase::doReadStdIn(const std::string& prompt/*=std::string()*/) {
00207   //Level 1: Local
00208 #ifdef TGT_HAS_LEDS
00209   if(display_id!=invalid_MC_ID) {
00210     MMAccessor<LedMC> display(display_id);
00211     display.mc()->cset(FaceLEDMask,.5f);
00212   }
00213 #endif
00214   sndman->playFile(config->controller.read_snd);
00215 
00216   //Just do one of the other two
00217   if(gui_comm==NULL || !wireless->isConnected(gui_comm->sock)) {
00218     //Level 2: Console
00219     if(prompt.size()>0)
00220       sout->printf("%s\n",prompt.c_str());
00221     sout->printf("#> ");
00222     if(!wireless->isConnected(sout->sock)) {
00223       std::string choice;
00224       std::cin >> choice;
00225       std::cout << std::endl;
00226       return takeInput(choice);
00227     }
00228     return this;
00229   } else {
00230     //Level 3: GUI
00231     if(prompt.size()>0) {
00232       unsigned int lines=std::count(prompt.begin(),prompt.end(),'\n');
00233       gui_comm->printf("status\n%u\n%s\n",lines,prompt.c_str());
00234     }
00235     return this;
00236   }
00237 }
00238 
00239 ControlBase* ControlBase::takeInput(const std::string& str) {
00240   std::vector<std::string> args;
00241   std::vector<unsigned int> offsets;
00242   if(!string_util::parseArgs(str,args,offsets)) {
00243     serr->printf("ControlBase::takeInput(\"%s\") was not understood.\n",str.c_str());
00244     refresh();
00245     return this;
00246   } else {
00247     //are there valid arguments?
00248     if(args.size()==0) {
00249       refresh();
00250       return this;
00251     }
00252     //let's see if the first arg matches an option name (case sensitive)
00253     unsigned int choice=-1U;
00254     bool ambiguous=false;
00255     for(unsigned int i=0; i<options.size(); i++) {
00256       if(options[i]!=NULL && options[i]->name == args[0]) {
00257         if(choice==-1U)
00258           choice=i;
00259         else
00260           ambiguous=true;
00261       }
00262     }
00263     //let's see if the first arg matches an option name (case insensitive)
00264     if(!ambiguous && choice==-1U) {
00265       std::string argname=string_util::makeLower(args[0]);
00266       for(unsigned int i=0; i<options.size(); i++) {
00267         if(options[i]!=NULL) {
00268           std::string optname=string_util::makeLower(options[i]->name);
00269           if(optname.compare(0,argname.size(),argname)==0) {
00270             if(choice==-1U)
00271               choice=i;
00272             else
00273               ambiguous=true;
00274           }
00275         }
00276       }
00277     }
00278     //if we didn't find one already, try treating the arg as an index number
00279     if(ambiguous || choice==-1U) {
00280       char* endp=NULL;
00281       choice=strtol(args[0].c_str(),&endp,10);
00282       if(endp==NULL || endp==args[0].c_str()) {
00283         if(config->main.use_VT100) {
00284           sout->printf("\r\33[1A");
00285           clearMenu();
00286           doRewrite=false;
00287         }
00288         return invalidInput(str,ambiguous);
00289       } else if(choice<options.size() && options[choice]!=NULL) {
00290         ambiguous=false;
00291       } else {
00292         if(config->main.use_VT100) {
00293           sout->printf("\r\33[1A");
00294           clearMenu();
00295           doRewrite=false;
00296         }
00297         return invalidInput(str,ambiguous);
00298       } 
00299     }
00300     //see what we got...
00301     if(args.size()>1)
00302       return options[choice]->takeInput(str.substr(offsets[1]));
00303     else {
00304       hilights.clear();
00305       hilights.push_back(choice);
00306       return doSelect();
00307     }
00308   }
00309   /*  std::string msg;
00310   {unsigned int i=0; while(i<str.size() && isspace(str[i])) i++; msg=str.substr(i);}
00311   if(isdigit(msg[0])) {
00312     char* endp=NULL;
00313     unsigned int choice=strtol(msg.c_str(),&endp,10);
00314     if(endp==NULL) {
00315       if(config->main.use_VT100) {
00316         sout->printf("\r\33[1A");
00317         clearMenu();
00318         doRewrite=false;
00319       }
00320       serr->printf("ControlBase::takeInput(\"%s\") was not understood.\n",str.c_str());
00321       refresh();
00322       return this;
00323     } else if(choice<options.size() && options[choice]!=NULL) {
00324       hilights.clear();
00325       hilights.push_back(choice);
00326       return doSelect();
00327     } else {
00328       if(config->main.use_VT100) {
00329         sout->printf("\r\33[1A");
00330         clearMenu();
00331         doRewrite=false;
00332       }
00333       sout->printf("%d is not a valid selection\n",choice);
00334       refresh();
00335       return this;
00336     } 
00337   } else {
00338     if(config->main.use_VT100) {
00339       sout->printf("\r\33[1A");
00340       clearMenu();
00341       doRewrite=false;
00342     }
00343     serr->printf("ControlBase::takeInput(\"%s\") was not understood.\nPlease enter the number of the index - string entry is not supported yet\n",str.c_str());
00344     refresh();
00345     return this;    
00346     }*/
00347   return this; //should never get here, but gcc 4 thinks we can
00348 }
00349 
00350 bool ControlBase::validInput(const std::string& str) {
00351   unsigned int choice=atoi(str.c_str());
00352   return (choice<options.size() && options[choice]!=NULL);
00353 }
00354 
00355 ControlBase* ControlBase::findSlot(const std::string& slotName) const {
00356   //let's see if the first arg matches an option name (case sensitive)
00357   for(unsigned int i=0; i<options.size(); i++) {
00358     if(options[i]!=NULL && options[i]->name.compare(0,slotName.size(),slotName)==0)
00359       return options[i];
00360   }
00361   //let's see if the first arg matches an option name (case insensitive)
00362   std::string argname=string_util::makeLower(slotName);
00363   bool ambiguous=false;
00364   unsigned int choice=-1U;
00365   for(unsigned int i=0; i<options.size(); i++) {
00366     if(options[i]!=NULL) {
00367       std::string optname=string_util::makeLower(options[i]->name);
00368       if(optname.compare(0,argname.size(),argname)==0) {
00369         if(choice==-1U)
00370           choice=i;
00371         else
00372           ambiguous=true;
00373       }
00374     }
00375   }
00376   //if we didn't find one already, try treating the arg as an index number
00377   if(ambiguous || choice==-1U) {
00378     char* endp=NULL;
00379     choice=strtol(slotName.c_str(),&endp,10);
00380     if(endp==NULL || endp==slotName.c_str()) {
00381       return NULL;
00382     } else if(choice<options.size() && options[choice]!=NULL) {
00383       ambiguous=false;
00384     } else {
00385       return NULL;
00386     }
00387   }
00388   return ambiguous ? NULL : options[choice];
00389 }
00390 
00391 std::string ControlBase::getSlotName(unsigned int i) const {
00392   if(options[i]!=NULL)
00393     return options[i]->getName();
00394   else {
00395     static std::string dashes("----------");
00396     return dashes;
00397   }
00398 }
00399 
00400 
00401 void ControlBase::setSlot(unsigned int i,ControlBase* o) {
00402   while(options.size()<=i)
00403     options.push_back(NULL);
00404   options[i]=o;
00405 }
00406 
00407 void ControlBase::pushSlot(ControlBase* o) {
00408   options.push_back(o);
00409 }
00410 
00411 void ControlBase::clearSlots() {
00412   for(unsigned int i=0; i<options.size(); i++)
00413     delete options[i];
00414   options.clear();
00415   hilights.clear();
00416 }
00417 
00418 void ControlBase::setHilights(const std::vector<unsigned int>& hi) {
00419   float avg=hilightsAvg();
00420   hilights.clear();
00421   for(unsigned int i=0; i<hi.size(); i++)
00422     if(hi[i]<options.size())
00423       hilights.push_back(hi[i]);
00424   float newavg=hilightsAvg();
00425   if(avg!=-1 || newavg!=-1) {
00426     if(avg<=newavg)
00427       sndman->playFile(config->controller.next_snd);
00428     else
00429       sndman->playFile(config->controller.prev_snd);
00430   }
00431   refresh();
00432 }
00433 
00434 void ControlBase::hilightFirst() {
00435   hilights.clear();
00436   for(unsigned int i=0; i<options.size(); i++)
00437     if(options[i]!=NULL) {
00438       hilights.push_back(i);
00439       return;
00440     }
00441 }
00442 
00443 ControlBase* ControlBase::registerControllerEntry(ControlBase* c, const std::string& menu, int flags/*=ControlBase::DEFAULTS*/) {
00444   ControlRegistry_t& reg = getControllerEntries();
00445   bool isnew = reg.find(menu)==reg.end() || reg[menu].find(c->getName())==reg[menu].end();
00446   reg[menu][c->getName()] = std::make_pair(c,flags);
00447   if(!isnew)
00448     std::cerr << "Warning: duplicate registation for " << c->getName() << " in Controller menu " << menu << std::endl;
00449   return c;
00450 }
00451 
00452 void ControlBase::clearMenu() {
00453   if(config->main.use_VT100) {
00454     sout->printf("\r\33[%luA",(unsigned long)(options.size()+1)); //moves cursor up to beginning of menu
00455     sout->printf("\33[J"); //clears to end of screen
00456   }
00457 }
00458 
00459 ControlBase* ControlBase::invalidInput(const std::string& msg, bool ambiguous) {
00460   if(ambiguous)
00461     serr->printf("ControlBase(\"%s\")::takeInput(\"%s\") was ambiguous\n",name.c_str(),msg.c_str());
00462   else
00463     serr->printf("ControlBase(\"%s\")::takeInput(\"%s\") was not a valid index or option name.\n",name.c_str(),msg.c_str());
00464   refresh();
00465   return this;
00466 }
00467 
00468 float ControlBase::hilightsAvg() const {
00469   if(hilights.size()==0)
00470     return -1;
00471   unsigned int total=0;
00472   for(unsigned int i=0; i<hilights.size(); i++)
00473     total+=hilights[i];
00474   return (float)total/(float)hilights.size();
00475 }
00476 
00477 
00478 /*! @file
00479  * @brief Implements ControlBase from which all items in the control system should inherit
00480  * @author ejt (Creator)
00481  */
00482 

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:37 2016 by Doxygen 1.6.3