worldgui.cc
Go to the documentation of this file.
00001 /* worldgui.cc
00002     Implements a subclass of World that has an FLTK and OpenGL GUI
00003     Authors: Richard Vaughan (vaughan@sfu.ca)
00004              Alex Couture-Beil (asc17@sfu.ca)
00005              Jeremy Asher (jra11@sfu.ca)
00006     SVN: $Id$
00007 */
00008 
00138 #include <FL/Fl_Image.H>
00139 #include <FL/Fl_Shared_Image.H>
00140 #include <FL/Fl_PNG_Image.H>
00141 #include <FL/Fl_Output.H>
00142 #include <FL/Fl_Text_Display.H>
00143 #include <FL/Fl_File_Chooser.H>
00144 
00145 #include <set>
00146 #include <sstream>
00147 #include <iomanip>
00148 #include <algorithm> // for std::sort
00149 
00150 #include "canvas.hh"
00151 #include "region.hh"
00152 #include "worldfile.hh"
00153 #include "file_manager.hh"
00154 #include "options_dlg.hh"
00155 #include "config.h" // build options from CMake
00156 
00157 using namespace Stg;
00158 
00159 static const char* AboutText = 
00160         "\n" 
00161         "Part of the Player Project\n"
00162         "http://playerstage.org\n"
00163         "\n"
00164         "Copyright 2000-2008 Richard Vaughan,\n"
00165         "Brian Gerkey, Andrew Howard, Reed Hedges, \n"
00166         "Toby Collett, Alex Couture-Beil, Jeremy Asher \n"
00167         "and contributors\n" 
00168         "\n"
00169   "Distributed under the terms of the \n"
00170   "GNU General Public License v2";
00171 
00172 static const char* MoreHelpText = 
00173   "http://playerstage.org\n"
00174   "\n"
00175   "has these resources to help you:\n"
00176   "\n"
00177   "\t* A user manual including API documentation\n"
00178   "\t* A bug and feature request tracking system\n"
00179   "\t* Mailing lists for users and developers\n"
00180   "\t* A Wiki"
00181   "\n\n"
00182   "The user manual is included with the Stage source code but\n"
00183   "is not built by default. To build the manual, run \"make\"\n"
00184   "in the directory \"docsrc\" to produce \"docsrc/stage/index.html\" .\n"
00185   "(requires Doxygen and supporting programs to be installed first).\n";
00186 
00187 WorldGui::WorldGui(int W,int H,const char* L) : 
00188   Fl_Window(W,H,L ),
00189   canvas( new Canvas( this,0,30,W,H-30 ) ),
00190   drawOptions(),
00191   fileMan( new FileManager() ),
00192   interval_log(),
00193   speedup(1.0), // real time
00194   mbar( new Fl_Menu_Bar(0,0, W, 30)),
00195   oDlg( NULL ),
00196   pause_time( false ),  
00197   real_time_interval( sim_interval ),
00198   real_time_now( RealTimeNow() ),
00199   real_time_recorded( real_time_now ),
00200   timing_interval( 20 )
00201 {
00202   Fl::scheme( "" );
00203   resizable(canvas);
00204   label( PROJECT );
00205 
00206   end();
00207   
00208   // make this menu's shortcuts work whoever has focus
00209   mbar->global();
00210   mbar->textsize(12);
00211   
00212   mbar->add( "&File", 0, 0, 0, FL_SUBMENU );
00213   mbar->add( "File/&Load World...", FL_CTRL + 'l', (Fl_Callback*)fileLoadCb, this, FL_MENU_DIVIDER );
00214   mbar->add( "File/&Save World", FL_CTRL + 's', (Fl_Callback*)fileSaveCb, this );
00215   mbar->add( "File/Save World &As...", FL_CTRL + FL_SHIFT + 's', (Fl_Callback*)WorldGui::fileSaveAsCb, this, FL_MENU_DIVIDER );
00216   
00217   mbar->add( "File/E&xit", FL_CTRL+'q', (Fl_Callback*)fileExitCb, this );
00218   
00219   mbar->add( "&View", 0, 0, 0, FL_SUBMENU );
00220 
00221   mbar->add( "View/Reset", ' ', (Fl_Callback*)resetViewCb, this );
00222 
00223   mbar->add( "View/Filter data...", FL_SHIFT + 'd', (Fl_Callback*)viewOptionsCb, this );
00224   canvas->createMenuItems( mbar, "View" );
00225 
00226   mbar->add( "Run", 0,0,0, FL_SUBMENU );
00227   mbar->add( "Run/Pause", 'p', (Fl_Callback*)pauseCb, this );
00228   mbar->add( "Run/One step", '.', (Fl_Callback*)onceCb, this, FL_MENU_DIVIDER );
00229   mbar->add( "Run/Faster", ']', (Fl_Callback*)fasterCb, this );
00230   mbar->add( "Run/Slower", '[', (Fl_Callback*)slowerCb, this, FL_MENU_DIVIDER  );
00231   mbar->add( "Run/Realtime", '{', (Fl_Callback*)realtimeCb, this );
00232   mbar->add( "Run/Fast", '}', (Fl_Callback*)fasttimeCb, this );
00233   
00234   mbar->add( "&Help", 0, 0, 0, FL_SUBMENU );
00235   mbar->add( "Help/Getting help...", 0,  (Fl_Callback*)moreHelptCb, this, FL_MENU_DIVIDER );
00236   mbar->add( "Help/&About Stage...", 0, (Fl_Callback*)helpAboutCb, this );
00237   
00238   callback( (Fl_Callback*)windowCb, this );      
00239   
00240   show();       
00241 }
00242 
00243 WorldGui::~WorldGui()
00244 {
00245         if( mbar ) delete mbar;
00246   if( oDlg ) delete oDlg;
00247   if( canvas ) delete canvas;
00248 }
00249 
00250 
00251 void WorldGui::Show()
00252 {
00253   show(); // fltk
00254 }
00255 
00256 void WorldGui::Load( const std::string& filename )
00257 {
00258   PRINT_DEBUG1( "%s.Load()", token );
00259         
00260   // needs to happen before StgWorld load, or we segfault with GL calls on some graphics cards
00261   Fl::check();
00262 
00263   fileMan->newWorld( filename );
00264   
00265   const usec_t load_start_time = RealTimeNow();
00266   
00267   World::Load( filename );
00268   
00269   // worldgui exclusive properties live in the top-level section
00270   const int world_section = 0; 
00271   speedup = wf->ReadFloat( world_section, "speedup", speedup );    
00272   paused = wf->ReadInt( world_section, "paused", paused );
00273   
00274   // use the window section for the rest
00275   const int window_section = wf->LookupEntity( "window" );
00276   
00277   if( window_section > 0 ) 
00278     {   
00279       unsigned int width = w();
00280       unsigned int height = h();
00281       wf->ReadTuple(window_section, "size", 0, 2, "uu", &width, &height );
00282       
00283       
00284       size( width,height );
00285       size_range( 100, 100 ); // set min size to 100/100, max size to screen size
00286       
00287       // configure the canvas
00288       canvas->Load(  wf, window_section );
00289       
00290       std::string title = PROJECT;
00291       if ( wf->filename.size() ) {
00292         // improve the title bar to say "Stage: <worldfile name>"
00293         title += ": ";          
00294         title += wf->filename;
00295       }
00296       label( title.c_str() );
00297 
00298       FOR_EACH( it, option_table )
00299         (*it)->Load( wf, window_section );
00300 
00301       // warn about unused WF lines
00302       wf->WarnUnused();
00303     }
00304  
00305   const usec_t load_end_time = RealTimeNow();
00306         
00307   if( debug )
00308     printf( "[Load time %.3fsec]\n", 
00309             (load_end_time - load_start_time) / 1e6 );
00310   
00311   Show();
00312 }
00313 
00314 void WorldGui::UnLoad() 
00315 {
00316   World::UnLoad();
00317 }
00318 
00319 bool WorldGui::Save( const char* filename )
00320 {
00321   PRINT_DEBUG1( "%s.Save()", token );
00322   
00323   // worldgui exclusive properties live in the top-level section
00324   const int world_section = 0; 
00325   wf->WriteFloat( world_section, "speedup", speedup );    
00326   wf->WriteInt( world_section, "paused", paused );
00327 
00328   // use the window section for the rest
00329   const int window_section = wf->LookupEntity( "window" );
00330         
00331   if( window_section > 0 ) // section defined
00332     {
00333       unsigned int width = w();
00334       unsigned int height = h();
00335       wf->WriteTuple( window_section, "size", 0, 2, "uu", width, height );
00336             
00337       canvas->Save( wf, window_section );
00338             
00339     FOR_EACH( it, option_table )
00340         (*it)->Save( wf, window_section );
00341     }
00342         
00343         World::Save( filename );
00344         
00345   // TODO - error checking
00346   return true;
00347 }
00348 
00349 static void UpdateCallback( WorldGui* world )
00350 {       
00351   world->Update();
00352 }
00353 
00354 bool WorldGui::Update()
00355 { 
00356   if( speedup > 0 )
00357          Fl::repeat_timeout( (sim_interval/1e6) / speedup, (Fl_Timeout_Handler)UpdateCallback, this );
00358   // else we're called by an idle callback
00359 
00360   //printf( "speedup %.2f timeout %.6f\n", speedup, timeout );
00361   
00362   // occasionally we measure the real time elapsing, for reporting the
00363   // run speed
00364   if( updates % timing_interval == 0 )
00365          { 
00366                 const usec_t timenow = RealTimeNow();    
00367                 real_time_interval = timenow - real_time_recorded; 
00368                 real_time_recorded = timenow;
00369          }   
00370 
00371   // inherit
00372   const bool done = World::Update();
00373 
00374         if( Model::trail_length > 0 && updates % Model::trail_interval == 0 )
00375                 FOR_EACH( it, active_velocity )
00376                         (*it)->UpdateTrail();
00377 
00378   if( done )
00379     {
00380       quit_time = 0; // allows us to continue by un-pausing
00381       Stop();
00382     }
00383   
00384   return done;
00385 }
00386 
00387 std::string WorldGui::ClockString() const
00388 {
00389   std::string str = World::ClockString();
00390   
00391   const double localratio = 
00392                 (double)sim_interval / (double)(real_time_interval/timing_interval);
00393   
00394   char buf[32];
00395   snprintf( buf, 32, " [%.1f]", localratio );
00396   str += buf;
00397   
00398   if( paused == true )
00399          str += " [ PAUSED ]";
00400   
00401   return str;
00402 }
00403 
00404 
00405 void WorldGui::AddModel( Model*  mod  )
00406 {
00407   if( mod->parent == NULL )
00408          canvas->AddModel( mod );
00409   
00410   World::AddModel( mod );
00411 }
00412 
00413 
00414 void WorldGui::RemoveChild( Model* mod )
00415 {
00416   canvas->RemoveModel( mod );
00417   World::RemoveChild( mod );
00418 }
00419 
00420 
00421 std::string WorldGui::EnergyString() const
00422 {       
00423   char str[512]; 
00424   snprintf( str, 255, "Energy\n  stored:   %.0f / %.0f KJ\n  input:    %.0f KJ\n  output:   %.0f KJ at %.2f KW\n",
00425             PowerPack::global_stored / 1e3,
00426             PowerPack::global_capacity /1e3,
00427             PowerPack::global_input / 1e3,
00428             PowerPack::global_dissipated / 1e3,
00429             (PowerPack::global_dissipated / (sim_time / 1e6)) / 1e3 );
00430   
00431   return std::string( str );
00432 }
00433 
00434 void WorldGui::DrawOccupancy() const
00435 {  
00436 //      int count=0;
00437 //   FOR_EACH( it, superregions )
00438 //              printf( "sr %d [%d,%d]  %p\n", count++, it->first.x, it->first.y, it->second );
00439 //      printf( "done\n" );
00440 
00441 //  unsigned int layer( updates % 2 );
00442   
00443   FOR_EACH( it, superregions )
00444     it->second->DrawOccupancy();
00445   
00446   //     {
00447 
00448   // it->second->DrawOccupancy(0);
00449     //    it->second->DrawOccupancy(1);
00450 
00451   //     }
00452 }
00453 
00454 void WorldGui::DrawVoxels() const
00455 {  
00456   unsigned int layer( updates % 2 );
00457 
00458   FOR_EACH( it, superregions )
00459                 it->second->DrawVoxels( layer );
00460 }
00461 
00462 void WorldGui::windowCb( Fl_Widget* w, WorldGui* wg )
00463 {
00464   switch ( Fl::event() ) {
00465   case FL_SHORTCUT:
00466     if ( Fl::event_key() == FL_Escape )
00467       return;
00468   case FL_CLOSE: // clicked close button
00469     bool done = wg->closeWindowQuery();
00470     if ( !done )
00471       return;
00472   }
00473 
00474   puts( "Stage: User closed window" );
00475   exit(0);
00476 }
00477 
00478 void WorldGui::fileLoadCb( Fl_Widget* w, WorldGui* wg )
00479 {
00480   const char* filename;
00481   const char* pattern = "World Files (*.world)";
00482         
00483         std::string worldsPath = wg->fileMan->worldsRoot();
00484         worldsPath.append( "/" );
00485   Fl_File_Chooser fc( worldsPath.c_str(), pattern, Fl_File_Chooser::CREATE, "Load World File..." );
00486   fc.ok_label( "Load" );
00487         
00488   fc.show();
00489   while (fc.shown())
00490     Fl::wait();
00491         
00492   filename = fc.value();
00493         
00494   if (filename != NULL) { // chose something
00495     if ( FileManager::readable( filename ) ) {
00496       // file is readable, clear and load
00497 
00498       // if (initialized) {
00499       wg->Stop();
00500       wg->UnLoad();
00501       // }
00502                         
00503       // todo: make sure loading is successful
00504       wg->Load( filename );
00505       wg->Start(); // if (stopped)
00506     }
00507     else {
00508       fl_alert( "Unable to read selected world file." );
00509     }
00510                 
00511 
00512   }
00513 }
00514 
00515 void WorldGui::fileSaveCb( Fl_Widget* w, WorldGui* wg )
00516 {
00517   // save to current file
00518   const bool success =  wg->Save( NULL );
00519   if ( !success ) {
00520     fl_alert( "Error saving world file." );
00521   }
00522 }
00523 
00524 void WorldGui::fileSaveAsCb( Fl_Widget* w, WorldGui* wg )
00525 {
00526   wg->saveAsDialog();
00527 }
00528 
00529 void WorldGui::fileExitCb( Fl_Widget* w, WorldGui* wg ) 
00530 {
00531   const bool done = wg->closeWindowQuery();
00532   if (done) {
00533          puts( "User exited via menu" );
00534     exit(0);
00535   }
00536 }
00537 
00538 void WorldGui::resetViewCb( Fl_Widget* w, WorldGui* wg )
00539 {
00540   wg->canvas->current_camera->reset();
00541   
00542   if( Fl::event_state( FL_CTRL ) ) 
00543          {
00544                 wg->canvas->resetCamera();
00545          }
00546   wg->canvas->redraw();
00547 }
00548 
00549 void WorldGui::slowerCb( Fl_Widget* w, WorldGui* wg )
00550 {
00551   if( wg->speedup <= 0 )
00552          {
00553                 wg->speedup = 100.0;
00554                 wg->SetTimeouts();
00555          }
00556   else
00557          wg->speedup *= 0.8;  
00558 }
00559 
00560 void WorldGui::fasterCb( Fl_Widget* w, WorldGui* wg )
00561 {
00562   if( wg->speedup <= 0 )
00563          putchar( 7 ); // bell - can go no faster
00564   else
00565          wg->speedup *= 1.2;
00566 }
00567 
00568 void WorldGui::realtimeCb( Fl_Widget* w, WorldGui* wg )
00569 {
00570   //puts( "real time" );
00571   wg->speedup = 1.0;
00572 
00573   if( !wg->paused ) 
00574          wg->SetTimeouts();
00575 }
00576 
00577 void WorldGui::fasttimeCb( Fl_Widget* w, WorldGui* wg )
00578 {
00579   //puts( "fast time" );
00580   wg->speedup = -1;
00581  
00582   if( !wg->paused ) 
00583          wg->SetTimeouts();  
00584 }
00585 
00586 void WorldGui::Redraw()
00587 {
00588   //puts( "redrawing\n" );
00589         canvas->redraw();
00590 }
00591 
00592 void WorldGui::Start()
00593 {
00594   World::Start();
00595   
00596   // start the timer that causes regular redraws
00597   Fl::add_timeout( ((double)canvas->interval/1000), 
00598                                                  (Fl_Timeout_Handler)Canvas::TimerCallback, 
00599                                                  canvas );
00600   
00601   SetTimeouts();
00602 }
00603 
00604 
00605 void WorldGui::SetTimeouts()
00606 {
00607   // remove the old callback, wherever it was
00608   Fl::remove_idle( (Fl_Timeout_Handler)UpdateCallback, this );    
00609   Fl::remove_timeout( (Fl_Timeout_Handler)UpdateCallback, this );         
00610   
00611   if( speedup > 0.0 ) 
00612          // attempt some multiple of real time   
00613          Fl::add_timeout( (sim_interval/1e6) / speedup, (Fl_Timeout_Handler)UpdateCallback, this );
00614   else 
00615          // go as fast as possible
00616          Fl::add_idle( (Fl_Timeout_Handler)UpdateCallback, this );
00617 }
00618 
00619 void WorldGui::Stop()
00620 {
00621   World::Stop();
00622   
00623   Fl::remove_timeout( (Fl_Timeout_Handler)Canvas::TimerCallback );      
00624   Fl::remove_timeout( (Fl_Timeout_Handler)UpdateCallback );     
00625   Fl::remove_idle( (Fl_Timeout_Handler)UpdateCallback, this );    
00626 
00627   // drawn 'cos we cancelled the timeout
00628   canvas->redraw(); // in case something happened that will never be
00629                                                                                 // drawn otherwise
00630 }  
00631 
00632 void WorldGui::pauseCb( Fl_Widget* w, WorldGui* wg )
00633 {
00634   wg->TogglePause();
00635 }
00636 
00637 void WorldGui::onceCb( Fl_Widget* w, WorldGui* wg )
00638 {
00639   //wg->paused = true;
00640   wg->Stop();
00641 
00642   // run exactly once
00643   wg->World::Update();
00644 }
00645 
00646 void WorldGui::viewOptionsCb( OptionsDlg* oDlg, WorldGui* wg ) 
00647 {
00648   // sort the vector by option label alphabetically
00649   //std::sort();// wg->option_table.begin(), wg->option_table.end() );//, sort_option_pointer );
00650   //std::sort();// wg->option_table.begin(), wg->option_table.end() );//, sort_option_pointer );
00651 
00652   if ( !wg->oDlg ) 
00653     {
00654       int x = wg->w()+wg->x() + 10;
00655       int y = wg->y();
00656       OptionsDlg* oDlg = new OptionsDlg( x,y, 180,250 );
00657       oDlg->callback( (Fl_Callback*)optionsDlgCb, wg );
00658       
00659       oDlg->setOptions( wg->option_table );
00660       oDlg->showAllOpt( &wg->canvas->visualizeAll );
00661       wg->oDlg = oDlg;
00662       oDlg->show();
00663     }
00664   else 
00665     {
00666       wg->oDlg->hide();
00667       delete wg->oDlg;
00668       wg->oDlg = NULL;
00669     }
00670   
00671 }
00672 
00673 void WorldGui::optionsDlgCb( OptionsDlg* oDlg, WorldGui* wg ) 
00674 {
00675   // get event from dialog
00676   OptionsDlg::event_t event = oDlg->event();
00677         
00678   // Check FLTK events first
00679   switch ( Fl::event() ) {
00680   case FL_SHORTCUT:
00681     if ( Fl::event_key() != FL_Escape ) 
00682       break; //return
00683     // otherwise, ESC pressed-> do as below
00684   case FL_CLOSE: // clicked close button
00685     // override event to close          
00686     event = OptionsDlg::CLOSE;
00687     break;
00688   }
00689         
00690   switch ( event ) {
00691   case OptionsDlg::CHANGE: 
00692     {
00693       //Option* o = oDlg->changed();
00694       //printf( "\"%s\" changed to %d!\n", o->name().c_str(), o->val() );                       
00695       break;
00696     }                   
00697   case OptionsDlg::CLOSE:
00698     // invalidate the oDlg pointer from the Wg
00699     //   instance before the dialog is destroyed
00700     wg->oDlg = NULL; 
00701     oDlg->hide();
00702     Fl::delete_widget( oDlg );
00703     return;     
00704   case OptionsDlg::NO_EVENT:
00705   case OptionsDlg::CHANGE_ALL:
00706     break;
00707   }
00708 }
00709 
00710 void aboutOKBtnCb( Fl_Return_Button* btn, void* p ) 
00711 {
00712   btn->window()->do_callback();
00713 }
00714 
00715 void aboutCloseCb( Fl_Window* win, Fl_Text_Display* textDisplay ) 
00716 {
00717   Fl_Text_Buffer* tbuf = textDisplay->buffer();
00718   textDisplay->buffer( NULL );
00719   delete tbuf;
00720   Fl::delete_widget( win );
00721 }
00722 
00723 void WorldGui::helpAboutCb( Fl_Widget* w, WorldGui* wg ) 
00724 {
00725   const int Width = 420;
00726   const int Height = 330;
00727   const int Spc = 10;
00728   const int ButtonH = 25;
00729   const int ButtonW = 60;
00730   const int pngH = 82;
00731   //const int pngW = 264;
00732         
00733   Fl_Window* win = new Fl_Window( Width, Height ); // make a window
00734 
00735   Fl_Box* box = new Fl_Box( Spc, Spc, 
00736                             Width-2*Spc, pngH ); // widget that will contain image
00737         
00738   std::string fullpath = FileManager::findFile( "assets/stagelogo.png" );
00739         
00740   box->image( new Fl_PNG_Image( fullpath.c_str() )); // load image and attach image to box
00741         
00742         Fl_Text_Display* textDisplay = 
00743                 new Fl_Text_Display( Spc, pngH+2*Spc,
00744                                                                                                  Width-2*Spc, Height-pngH-ButtonH-4*Spc );
00745         
00746   textDisplay->box( FL_NO_BOX );
00747   textDisplay->color( win->color() );
00748   win->callback( (Fl_Callback*)aboutCloseCb, textDisplay );
00749                 
00750   Fl_Text_Buffer* tbuf = new Fl_Text_Buffer;
00751   tbuf->text( PROJECT );
00752   tbuf->append( "-" );
00753   tbuf->append( VERSION );
00754   tbuf->append( AboutText );
00755   //textDisplay->wrap_mode( true, 50 );
00756   textDisplay->buffer( tbuf );
00757         
00758   Fl_Return_Button* button = 
00759                 new Fl_Return_Button( (Width - ButtonW)/2, Height-Spc-ButtonH,
00760                                                                                                         ButtonW, ButtonH,
00761                                                                                                         "&OK" );
00762   button->callback( (Fl_Callback*)aboutOKBtnCb );
00763         
00764   win->show();
00765 }
00766 
00767 void WorldGui::moreHelptCb( Fl_Widget* w, WorldGui* wg ) 
00768 {
00769   const int Width =  500;
00770   const int Height = 250;
00771   const int Spc = 10;
00772         
00773   Fl_Window* win = new Fl_Window( Width, Height ); // make a window
00774         win->label( "Getting help with Stage" );
00775         
00776         Fl_Text_Display* textDisplay =
00777                 new Fl_Text_Display( Spc, Spc,
00778                                                                                                  Width-2*Spc, Height-2*Spc );
00779         
00780   win->resizable( textDisplay );
00781   textDisplay->box( FL_NO_BOX );
00782   textDisplay->color( win->color() );
00783                 
00784   Fl_Text_Buffer* tbuf = new Fl_Text_Buffer();
00785   tbuf->append( MoreHelpText );
00786   // textDisplay->wrap_mode( true, 50 );
00787   textDisplay->buffer( tbuf );
00788         
00789   win->show();
00790 }
00791 
00792 
00793 bool WorldGui::saveAsDialog()
00794 {
00795   const char* newFilename;
00796   bool success = false;
00797   const char* pattern = "World Files (*.world)";
00798 
00799   Fl_File_Chooser fc( wf->filename.c_str(), pattern, Fl_File_Chooser::CREATE, "Save File As..." );
00800   fc.ok_label( "Save" );
00801 
00802   fc.show();
00803   while (fc.shown())
00804     Fl::wait();
00805 
00806   newFilename = fc.value();
00807 
00808   if (newFilename != NULL) {
00809     // todo: make sure file ends in .world
00810     success = Save( newFilename );
00811     if ( !success ) {
00812       fl_alert( "Error saving world file." );
00813     }
00814   }
00815 
00816   return success;
00817 }
00818 
00819 bool WorldGui::closeWindowQuery()
00820 {
00821   int choice;
00822         
00823   if ( wf ) {
00824     // worldfile loaded, ask to save
00825     choice = fl_choice("Quitting Stage",
00826                        "&Cancel", // ->0: defaults to ESC
00827                        "&Save, then quit", // ->1
00828                        "&Quit without saving" // ->2
00829                        );
00830                 
00831     switch (choice) {
00832     case 1: // Save before quitting
00833       if ( saveAsDialog() ) 
00834         return true;      
00835       else 
00836         return false;
00837       
00838     case 2: // Quit without saving
00839       return true;
00840     }
00841                 
00842     // Cancel
00843     return false;
00844   }
00845   else {
00846     // nothing is loaded, just quit
00847     return true;
00848   }
00849 }
00850 
00851 void WorldGui::DrawBoundingBoxTree()
00852 {
00853   FOR_EACH( it, World::children )
00854     (*it)->DrawBoundingBoxTree();
00855 }
00856 
00857 void WorldGui::PushColor( Color col )
00858 { canvas->PushColor( col ); } 
00859 
00860 void WorldGui::PushColor( double r, double g, double b, double a )
00861 { canvas->PushColor( r,g,b,a ); }
00862 
00863 void WorldGui::PopColor()
00864 { canvas->PopColor(); }
00865 
00866 Model* WorldGui::RecentlySelectedModel() const
00867 { return canvas->last_selection; }
00868 
00869 usec_t WorldGui::RealTimeNow() const
00870 {
00871   struct timeval tv;
00872   gettimeofday( &tv, NULL );  // slow system call: use sparingly
00873   return( tv.tv_sec*1000000 + tv.tv_usec );
00874 }
00875 
00876 bool WorldGui::IsTopView()
00877 { return canvas->IsTopView(); }


stage
Author(s): Richard Vaughan , Brian Gerkey , Reed Hedges , Andrew Howard , Toby Collett , Pooya Karimian , Jeremy Asher , Alex Couture-Beil , Geoff Biggs , Rich Mattes , Abbas Sadat
autogenerated on Thu Aug 27 2015 15:20:57