MOOS 0.2375
|
00001 00002 // 00003 // MOOS - Mission Oriented Operating Suite 00004 // 00005 // A suit of Applications and Libraries for Mobile Robotics Research 00006 // Copyright (C) 2001-2005 Massachusetts Institute of Technology and 00007 // Oxford University. 00008 // 00009 // This software was written by Paul Newman at MIT 2001-2002 and Oxford 00010 // University 2003-2005. email: pnewman@robots.ox.ac.uk. 00011 // 00012 // This file is part of a MOOS Utility Component. 00013 // 00014 // This program is free software; you can redistribute it and/or 00015 // modify it under the terms of the GNU General Public License as 00016 // published by the Free Software Foundation; either version 2 of the 00017 // License, or (at your option) any later version. 00018 // 00019 // This program is distributed in the hope that it will be useful, 00020 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00022 // General Public License for more details. 00023 // 00024 // You should have received a copy of the GNU General Public License 00025 // along with this program; if not, write to the Free Software 00026 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 00027 // 02111-1307, USA. 00028 // 00030 // ScopeGrid.cpp: implementation of the CScopeGrid class. 00031 00032 00033 #ifdef _WIN32 00034 #pragma warning(disable : 4786) 00035 #endif 00036 00037 #include <string> 00038 #include "ScopeGrid.h" 00039 #include <FL/fl_draw.H> 00040 #include <MOOSGenLib/MOOSGenLibGlobalHelper.h> 00041 #include <FLTKVW/MOOSFLTKUI.h> 00042 #include <FL/Fl_Input.H> 00043 #include <FL/Fl_Menu_Button.H> 00044 #include <FL/Fl_Button.H> 00045 #include <FL/Fl_Round_Button.H> 00046 #include <FL/fl_ask.H> 00047 00048 00049 //this is a file scope utitlity class - used for poking the MOOS 00050 class CPokeDlg : public CMOOSFLTKUI 00051 { 00052 typedef CMOOSFLTKUI BASE; 00053 public: 00054 00055 enum{OK,CANCEL,STRING,NUMERIC,POKE}; 00056 std::string m_sVal,m_sType,m_sName; 00057 double m_dfVal; 00058 bool m_bGood; 00059 bool IsGood(){return m_bGood;}; 00060 bool IsDouble(){return m_sType=="D";}; 00061 bool IsString(){return m_sType=="$";}; 00062 std::string GetName(){return m_sName;}; 00063 std::string GetString(){return m_sVal;}; 00064 double GetDouble(){return m_dfVal;}; 00065 00066 00067 CPokeDlg(int x,int y, int w, int h, const char * Name=NULL):BASE(x,y,w,h,Name) 00068 { 00069 m_bGood = false; 00070 Fl_Input* pValue = new Fl_Input(10,20,w-20,20); 00071 SetID(pValue,POKE); 00072 pValue->align(FL_ALIGN_TOP); 00073 Fl_Button* pOK = new Fl_Button(w-70,h-30,60,20,"OK"); 00074 Fl_Button* pQuit = new Fl_Button(10,h-30,60,20,"Cancel"); 00075 SetID(pOK,OK); 00076 SetID(pQuit,CANCEL); 00077 } 00078 00079 void Configure(std::string sType, std::string sVal,std::string sName) 00080 { 00081 m_sVal = sVal; 00082 m_sName =sName; 00083 00084 ((Fl_Input*)GetByID(POKE))->value(m_sVal.c_str()); 00085 00086 if(sType=="*" || sType=="?") 00087 { 00088 if(sType=="*") 00089 { 00090 //this is a new variable - better ask for a name 00091 const char * pStr = fl_input("Enter name for new variable"); 00092 if(pStr==NULL) 00093 { 00094 return; 00095 } 00096 m_sName = std::string(pStr); 00097 } 00098 00099 int nChoice = fl_choice("Variable is ","cancel","numeric","string"); 00100 00101 switch(nChoice) 00102 { 00103 case 1: m_sType = "D"; break; 00104 case 2: m_sType = "$"; break; 00105 default : return; 00106 } 00107 00108 } 00109 else 00110 { 00111 m_sType = sType; 00112 } 00113 00114 static char Name[1024]; 00115 sprintf(Name,"new value for %s is....",m_sName.c_str()); 00116 ((Fl_Input*)GetByID(POKE))->label(Name); 00117 00118 } 00119 00120 void OnControlWidget(Fl_Widget * pW,int nID) 00121 { 00122 switch(nID) 00123 { 00124 case OK: 00125 { 00126 std::string sVal = ((Fl_Input*)GetByID(POKE))->value(); 00127 00128 if(m_sType=="$" ) 00129 { 00130 if(!MOOSIsNumeric(sVal) || sVal.empty()) 00131 m_sVal = sVal; 00132 else 00133 { 00134 fl_alert("must be string - this looks like a number"); 00135 return; 00136 } 00137 } 00138 else if(m_sType=="D") 00139 { 00140 if(MOOSIsNumeric(sVal) && !sVal.empty() ) 00141 m_dfVal = atof(sVal.c_str()); 00142 else 00143 { 00144 fl_alert("must be double - this looks like a string"); 00145 return; 00146 } 00147 } 00148 00149 //and we are all done! 00150 m_bGood = true; 00151 GetRootWindow()->hide(); 00152 } 00153 break; 00154 case CANCEL: 00155 GetRootWindow()->hide(); 00156 break; 00157 00158 } 00159 } 00160 00161 }; 00162 00163 00164 00166 00167 00168 CScopeGrid::CScopeGrid( int X, int Y, int W, int H, const char *l ) : Flv_Table(X,Y,W,H,l) 00169 { 00170 m_pDBImage = NULL; 00171 m_nCount = 0; 00172 m_pComms = NULL; 00173 //default size 00174 rows(500); 00175 cols(7); 00176 feature(FLVF_HEADERS|FLVF_DIVIDERS|FLVF_MULTI_SELECT|FLVF_FULL_RESIZE); 00177 feature_remove(FLVF_MULTI_SELECT | FLVF_COL_HEADER ); 00178 00179 //fonts etc for headers 00180 Flv_Style s; 00181 Flv_Table::get_style(s,-1,0); 00182 row_style[-1].align(FL_ALIGN_CLIP); 00183 row_style[-1].font( (Fl_Font)(s.font()+FL_BOLD)); 00184 col_style[1].align(FL_ALIGN_CENTER); 00185 col_style[2].align(FL_ALIGN_CENTER); 00186 col_style[3].align(FL_ALIGN_CENTER); 00187 col_style[4].align(FL_ALIGN_CENTER); 00188 col_style[5].align(FL_ALIGN_CENTER); 00189 col_style[6].align(FL_ALIGN_TOP_LEFT); 00190 00191 global_style.font_size(12); 00192 //set up callbacks 00193 callback_when( FLVEcb_CLICKED ); 00194 callback((Fl_Callback*)GridCallback); 00195 max_clicks(2); 00196 00197 //set up hint window for veiwing data 00198 Fl_Group *save = Fl_Group::current(); // save current widget.. 00199 m_pTW = new CTipWindow(); // ..because this trashes it 00200 m_pTW->hide(); 00201 Fl_Group::current(save); // ..then back to previous. 00202 00203 strcpy(m_csTitle,"Not connected"); 00204 label(m_csTitle); 00205 00206 // remove mouseover <-> on column/row separators 00207 // as these should not be adjustable 00208 for(int i = 0; i < 7; ++i) 00209 {col_resizable(false , i);} 00210 }; 00211 00212 00213 00214 void CScopeGrid::SetTitle(std::string sTitle) 00215 { 00216 strncpy(m_csTitle,sTitle.c_str(),sizeof(m_csTitle)); 00217 } 00218 00219 00220 std::string CScopeGrid::GetDataValue(int R,int C) 00221 { 00222 CDBImage::CVar Var; 00223 if(m_pDBImage!=NULL) 00224 { 00225 if(m_pDBImage->Get(Var,R)) 00226 { 00227 switch(C) 00228 { 00229 case 0: 00230 return Var.GetName(); 00231 break; 00232 case 1: 00233 return Var.GetTime(); 00234 break; 00235 case 2: 00236 return Var.GetType(); 00237 break; 00238 case 3: 00239 return Var.GetFrequency(); 00240 case 4: 00241 return Var.GetSource(); 00242 case 5: 00243 return Var.GetCommunity(); 00244 case 6: 00245 return Var.GetValue(); 00246 break; 00247 } 00248 } 00249 } 00250 return ""; 00251 } 00252 00253 00254 bool CScopeGrid::PokeMOOS(CDBImage::CVar & Var,bool bNew) 00255 { 00256 00257 Fl_Window W(20,20,400,100,"Poke the MOOS"); 00258 CPokeDlg D(0,0,400,100,"Poke the MOOS"); 00259 00260 if(bNew) 00261 { 00262 //user has clicked on empty cell - wanting to make a new variable 00263 D.Configure("*","",""); 00264 } 00265 else 00266 { 00267 D.Configure(Var.GetType(),Var.GetValue(),Var.GetName()); 00268 } 00269 00270 W.show(); 00271 while(W.shown()) 00272 Fl::wait(); 00273 00274 if(D.IsGood()) 00275 { 00276 if(m_pComms && m_pComms->IsConnected()) 00277 { 00278 if(D.IsDouble()) 00279 { 00280 m_pComms->Notify(D.GetName(),D.GetDouble()); 00281 } 00282 if(D.IsString()) 00283 { 00284 m_pComms->Notify(D.GetName(),D.GetString()); 00285 } 00286 } 00287 } 00288 00289 return true; 00290 00291 00292 } 00293 00294 void CScopeGrid::OnGridCallBack() 00295 { 00296 if(why_event()==FLVE_CLICKED) 00297 { 00298 //this is a double click 00299 int c = select_start_col(); 00300 int r = select_start_row(); 00301 std::string sVal = GetDataValue(r,c); 00302 00303 if(c==6) 00304 { 00305 m_pTW->value(sVal); 00306 } 00307 else 00308 { 00309 m_pTW->hide(); 00310 if(c==0) 00311 { 00312 //hold control down to poke... 00313 if((Fl::event_key(FL_Control_L)||Fl::event_key(FL_Control_R))) 00314 { 00315 CDBImage::CVar Var; 00316 if(m_pDBImage->Get(Var,r)) 00317 { 00318 PokeMOOS(Var,false); 00319 } 00320 else 00321 { 00322 PokeMOOS(Var,true); 00323 } 00324 } 00325 } 00326 } 00327 } 00328 } 00329 00330 00331 00332 00333 00334 void CScopeGrid::redraw() 00335 { 00336 int c = select_start_col(); 00337 int r = select_start_row(); 00338 if(c==6) 00339 { 00340 std::string sVal = GetDataValue(r,c); 00341 m_pTW->value(sVal); 00342 } 00343 00344 BASE::redraw(); 00345 } 00346 00347 int CScopeGrid::handle(int e) 00348 { 00349 switch(e) 00350 { 00351 case FL_PUSH: 00352 // XXX: if offscreen, move tip ABOVE mouse instead 00353 m_pTW->position(Fl::event_x_root(), Fl::event_y_root()); 00354 m_pTW->show(); 00355 break; 00356 case FL_HIDE: // valuator goes away 00357 case FL_RELEASE: // release mouse 00358 case FL_LEAVE: // leave focus 00359 // Make sure tipwin closes when app closes 00360 m_pTW->hide(); 00361 break; 00362 } 00363 return(BASE::handle(e)); 00364 } 00365 00366 00367 void CScopeGrid::draw_cell( int Offset, int &X, int &Y, int &W, int &H, int R, int C ) 00368 { 00369 Flv_Style s; 00370 get_style(s, R, C); 00371 00372 00373 Flv_Table::draw_cell(Offset,X,Y,W,H,R,C); 00374 00375 if(R==-1) 00376 { 00377 //this is the header: 00378 const char * ColumnNames[] = {"Name","Time","Type","Freq","Source","Community","Value"}; 00379 const char * pStr = C<sizeof(ColumnNames) ? ColumnNames[C] : ""; 00380 fl_draw(pStr, X-Offset, Y, W, H, s.align() ); 00381 } 00382 else 00383 { 00384 //FIX for FLTK escaping of "@" PMN May 2005 00385 std::string sStr = GetDataValue(R,C).c_str(); 00386 std::string sFLTK; 00387 while(!sStr.empty()) 00388 { 00389 sFLTK += MOOSChomp(sStr,"@"); 00390 if(!sStr.empty()) 00391 sFLTK+="@@"; 00392 } 00393 fl_draw(sFLTK.c_str(), X-Offset, Y, W, H, s.align() ); 00394 } 00395 } 00396 00397 00398 void CScopeGrid::get_style( Flv_Style &s, int R, int C ) 00399 { 00400 Flv_Table::get_style(s,R,C); // Get standard style 00401 if(R%2==0) 00402 { 00403 s.background( (Fl_Color)(FL_GRAY_RAMP+22) ); 00404 } 00405 if(C==6 && m_pDBImage->HasChanged(R)) 00406 { 00407 s.foreground( (Fl_Color)(FL_RED) ); 00408 } 00409 } 00410 00411 00412 00413 int CScopeGrid::col_width( int C ) 00414 { 00415 static int LW=-1; 00416 static int cw[7]; 00417 int scrollbar_width = (scrollbar.visible()?scrollbar.w():0); 00418 int W = w()- scrollbar_width-1; 00419 int ww, t; 00420 00421 // Either always calculate or be sure to check that width 00422 // hasn't changed. 00423 if (W!=LW) // Width change, recalculate 00424 { 00425 //char * ColumnNames[] = {"Name","Time","Type","Freq","Source","Community","Value"}; 00426 cw[0] = (W*20)/100; // 30 Name 00427 cw[1] = (W*10)/100; // 10 Time 00428 cw[2] = (W*4)/100; // 15% Type 00429 cw[3] = (W*6)/100; // 8% Freq 00430 cw[4] = (W*10)/100; // 15% Src 00431 cw[5] = (W*10)/100; // 15% Comm 00432 cw[6] = (W*30)/100; // 15% Val 00433 00434 00435 for (ww=0, t=0; t<6; t++ ) 00436 { 00437 ww += cw[t]; 00438 } 00439 cw[6] = W-ww-1; // ~30% +/- previous rounding errors 00440 LW = W; 00441 } 00442 return cw[C]; 00443 00444 } 00445 00446 void CScopeGrid::SetDBImage(CDBImage *pDBImage) 00447 { 00448 m_pDBImage = pDBImage; 00449 }