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

Tekkotsu v2.4.1
Generated Tue Aug 16 16:32:46 2005 by Doxygen 1.4.4