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

Tekkotsu v4.0
Generated Thu Nov 22 00:54:52 2007 by Doxygen 1.5.4