core/vgui/vgui_selector_tableau.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_selector_tableau.cxx
00002 #include "vgui_selector_tableau.h"
00003 //:
00004 // \file
00005 // \author Matthew Leotta
00006 // \date   November 5, 2003
00007 // \brief  See vgui_selector_tableau.h for a description of this file.
00008 
00009 #include <vcl_iostream.h>
00010 #include <vcl_sstream.h>
00011 #include <vcl_vector.h>
00012 #include <vcl_algorithm.h>
00013 #include <vcl_string.h>
00014 
00015 #include <vgui/vgui.h>
00016 #include <vgui/vgui_gl.h>
00017 #include <vgui/vgui_event.h>
00018 #include <vgui/vgui_command.h>
00019 #include <vgui/vgui_menu.h>
00020 #include <vgui/vgui_popup_params.h>
00021 #include <vgui/vgui_matrix_state.h>
00022 
00023 
00024 //----------------------------------------------------------------------------
00025 //: Constructor - don't use this, use vgui_selector_tableau_new.
00026 vgui_selector_tableau::vgui_selector_tableau()
00027 {
00028 }
00029 
00030 
00031 //----------------------------------------------------------------------------
00032 //: Constructor - don't use this, use vgui_selector_tableau_new.
00033 // Many children, top to bottom.
00034 vgui_selector_tableau::vgui_selector_tableau(vcl_vector<vgui_tableau_sptr> const& the_children)
00035 {
00036   for (unsigned int i = 0; i < the_children.size(); ++i)
00037     add(the_children[i]);
00038   active_child_ = render_order_.front();
00039 }
00040 
00041 //----------------------------------------------------------------------------
00042 //: Destructor - called by vgui_selector_tableau_sptr.
00043 vgui_selector_tableau::~vgui_selector_tableau()
00044 {
00045 }
00046 
00047 //----------------------------------------------------------------------------
00048 //: Return the file name of the active tableau or just return the type.
00049 vcl_string vgui_selector_tableau::file_name() const
00050 {
00051   vcl_map<vcl_string, vgui_parent_child_link>::const_iterator itr = child_map_.find(active_child_);
00052   if (itr != child_map_.end())
00053     return itr->second->file_name();
00054 
00055   return type_name();
00056 }
00057 
00058 
00059 //----------------------------------------------------------------------------
00060 //: Returns a nice version of the name, including info on the children.
00061 vcl_string vgui_selector_tableau::pretty_name() const
00062 {
00063   vcl_stringstream s; s << type_name() << "[#kids=" << child_map_.size() << ']';
00064   return s.str();
00065 }
00066 
00067 //----------------------------------------------------------------------------
00068 //: Handle all events sent to this tableau.
00069 bool vgui_selector_tableau::handle(const vgui_event& event)
00070 {
00071   // Save current matrix state. Each active child will be
00072   // invoked with this matrix state.
00073   vgui_matrix_state PM;
00074 
00075   // "DRAW" events. Return true unless some child returns false.
00076   if (event.type==vgui_DRAW || event.type==vgui_DRAW_OVERLAY) {
00077     bool retv = true;
00078 
00079     vcl_vector<vcl_string>::iterator itr = render_order_.begin();
00080     for (; itr != render_order_.end(); ++itr){
00081       if (visible_[*itr] && child_map_[*itr]) {
00082         PM.restore();
00083         if ( !child_map_[*itr]->handle(event) )
00084           retv=false;
00085       }
00086     }
00087 
00088     return retv;
00089   }
00090 
00091   // all other events :
00092 
00093   vcl_map<vcl_string, vgui_parent_child_link>::iterator itr = child_map_.find(active_child_);
00094   if (itr == child_map_.end() || !itr->second)
00095     return false;
00096 
00097   return itr->second->handle(event);
00098 }
00099 
00100 //----------------------------------------------------------------------------
00101 //: Returns a bounding box large enough to contain all the visible child bounding boxes.
00102 bool vgui_selector_tableau::get_bounding_box(float lo[3], float hi[3]) const
00103 {
00104   // it would be nice if we could return an empty bounding box.
00105   if (child_map_.empty())
00106     return false;
00107 
00108   // get bbox of first visible child.
00109   vcl_vector<vcl_string>::const_iterator o_itr = render_order_.begin();
00110   for (; o_itr!=render_order_.end(); ++o_itr ){
00111     vcl_map<vcl_string, bool>::const_iterator v_itr = visible_.find(*o_itr);
00112     if ((v_itr != visible_.end()) && v_itr->second){
00113       vcl_map<vcl_string, vgui_parent_child_link>::const_iterator t_itr = child_map_.find(*o_itr);
00114       if (!t_itr->second->get_bounding_box(lo, hi))
00115         return false;
00116       break;
00117     }
00118   }
00119   // See if any children where visible
00120   if (o_itr == render_order_.end())
00121     return false;
00122 
00123   for (; o_itr!=render_order_.end(); ++o_itr ){
00124     vcl_map<vcl_string, bool>::const_iterator v_itr = visible_.find(*o_itr);
00125     if ((v_itr != visible_.end()) && v_itr->second){
00126       // get bbox of child *o_itr.
00127       vcl_map<vcl_string, vgui_parent_child_link>::const_iterator t_itr = child_map_.find(*o_itr);
00128       float l[3], h[3];
00129       if (!t_itr->second->get_bounding_box(l, h))
00130         return false;
00131 
00132       // enlarge if necessary.
00133       for (unsigned j=0; j<3; ++j) {
00134         if (l[j] < lo[j]) lo[j] = l[j];
00135         if (h[j] > hi[j]) hi[j] = h[j];
00136       }
00137     }
00138   }
00139   return true;
00140 }
00141 
00142 //----------------------------------------------------------------------------
00143 void vgui_selector_tableau::add(vgui_tableau_sptr const& tab, vcl_string name)
00144 {
00145   if (name == "") name = tab->file_name();
00146 
00147   vcl_map<vcl_string, vgui_parent_child_link>::iterator itr = child_map_.find(name);
00148   bool exists = (itr != child_map_.end());
00149 
00150   child_map_[name] = vgui_parent_child_link(this,tab);
00151   if (!exists){
00152     render_order_.push_back(name);
00153     visible_[name] = true;
00154   }
00155   if (active_child_ == "") active_child_ = name;
00156 }
00157 
00158 //----------------------------------------------------------------------------
00159 //: Add to list of child tableaux.
00160 // virtual
00161 bool vgui_selector_tableau::add_child(vgui_tableau_sptr const& t)
00162 {
00163   this->add(t);
00164   return true;
00165 }
00166 
00167 //----------------------------------------------------------------------------
00168 //: Remove given tableau from list of child tableaux.
00169 void vgui_selector_tableau::remove(vgui_tableau_sptr const& t)
00170 {
00171   if (!remove_child(t))
00172     vcl_cerr << __FILE__ " : no such child tableau\n";
00173 }
00174 
00175 //----------------------------------------------------------------------------
00176 //: Remove given tableau from list of child tableaux.
00177 bool vgui_selector_tableau::remove(const vcl_string name)
00178 {
00179   vcl_map<vcl_string, vgui_parent_child_link>::iterator itr = child_map_.find(name);
00180   if (itr != child_map_.end())
00181     child_map_.erase(itr);
00182   else
00183     return false;
00184 
00185   vcl_map<vcl_string, bool>::iterator v_itr = visible_.find(name);
00186   if (v_itr != visible_.end())
00187     visible_.erase(v_itr);
00188 
00189   vcl_vector<vcl_string>::iterator o_itr = vcl_find(render_order_.begin(),
00190                                                     render_order_.end(),
00191                                                     name);
00192   if (o_itr != render_order_.end())
00193     render_order_.erase(o_itr);
00194 
00195   if (active_child_ == name){
00196     active_child_ = "";
00197     for (o_itr = render_order_.begin(); o_itr!=render_order_.end(); ++o_itr ){
00198       if (visible_[*o_itr]){
00199         active_child_ = *o_itr;
00200         break;
00201       }
00202     }
00203   }
00204   return true;
00205 }
00206 
00207 //----------------------------------------------------------------------------
00208 void vgui_selector_tableau::clear()
00209 {
00210   child_map_.clear();
00211   visible_.clear();
00212   render_order_.clear();
00213   active_child_ = "";
00214 }
00215 
00216 //----------------------------------------------------------------------------
00217 //: Returns a smart pointer to the active tableau
00218 vgui_tableau_sptr vgui_selector_tableau::active_tableau() const
00219 {
00220   vcl_map<vcl_string, vgui_parent_child_link>::const_iterator itr = child_map_.find(active_child_);
00221   if (itr == child_map_.end()) return NULL;
00222   return itr->second;
00223 }
00224 
00225 //----------------------------------------------------------------------------
00226 //: Returns a smart pointer to the tableau with the given name
00227 vgui_tableau_sptr vgui_selector_tableau::get_tableau(const vcl_string& name) const
00228 {
00229   vcl_map<vcl_string, vgui_parent_child_link>::const_iterator itr = child_map_.find(name);
00230   if (itr == child_map_.end()) return NULL;
00231   return itr->second;
00232 }
00233 
00234 //----------------------------------------------------------------------------
00235 // virtual
00236 bool vgui_selector_tableau::remove_child(vgui_tableau_sptr const &t)
00237 {
00238   bool retval = false;
00239 
00240   for (vcl_map<vcl_string, vgui_parent_child_link>::iterator itr=child_map_.begin();
00241        itr!=child_map_.end(); ++itr )
00242     if ( (itr->second.child()) == t )
00243       retval = this->remove(itr->first) || retval;
00244 
00245   return retval;
00246 }
00247 
00248 
00249 //----------------------------------------------------------------------------
00250 bool vgui_selector_tableau::toggle(const vcl_string& name)
00251 {
00252   vcl_map<vcl_string, bool>::iterator itr = visible_.find(name);
00253   if (itr == visible_.end()) return false;
00254   bool state = itr->second;
00255   itr->second = !state;
00256 
00257   return true;
00258 }
00259 
00260 //----------------------------------------------------------------------------
00261 bool vgui_selector_tableau::is_visible(const vcl_string& name) const
00262 {
00263   vcl_map<vcl_string, bool>::const_iterator itr = visible_.find(name);
00264   if (itr == visible_.end()) return false;
00265   return itr->second;
00266 }
00267 
00268 //----------------------------------------------------------------------------
00269 //: Make the child tableau with the given position the active child.
00270 void vgui_selector_tableau::set_active(const vcl_string& name)
00271 {
00272   vcl_map<vcl_string, vgui_parent_child_link>::iterator itr = child_map_.find(name);
00273   if (itr != child_map_.end()) active_child_ = name;
00274 }
00275 
00276 //----------------------------------------------------------------------------
00277 //: Move the active tableau up one position in the display list.
00278 void vgui_selector_tableau::active_raise()
00279 {
00280   vcl_vector<vcl_string>::iterator itr;
00281   itr = vcl_find(render_order_.begin(), render_order_.end(), active_child_);
00282   if (itr != render_order_.end() && itr+1 != render_order_.end()) {
00283     *itr = *(itr+1);
00284     *(itr+1) = active_child_;
00285   }
00286 }
00287 
00288 //----------------------------------------------------------------------------
00289 //: Move the active tableau down one position in the display list.
00290 void vgui_selector_tableau::active_lower()
00291 {
00292   vcl_vector<vcl_string>::iterator itr;
00293   itr = vcl_find(render_order_.begin(), render_order_.end(), active_child_);
00294   if (itr != render_order_.end() && itr != render_order_.begin()) {
00295     *itr = *(itr-1);
00296     *(itr-1) = active_child_;
00297   }
00298 }
00299 
00300 //----------------------------------------------------------------------------
00301 //: Move the active tableau to the top of the display list.
00302 void vgui_selector_tableau::active_to_top()
00303 {
00304   vcl_vector<vcl_string>::iterator itr;
00305   itr = vcl_find(render_order_.begin(), render_order_.end(), active_child_);
00306   while (itr != render_order_.end() && itr+1 != render_order_.end()) {
00307     *itr = *(itr+1);
00308     ++itr;
00309   }
00310   *(itr) = active_child_;
00311 }
00312 
00313 //----------------------------------------------------------------------------
00314 //: Move the active tableau to the bottom of the display list.
00315 void vgui_selector_tableau::active_to_bottom()
00316 {
00317   vcl_vector<vcl_string>::iterator itr;
00318   itr = vcl_find(render_order_.begin(), render_order_.end(), active_child_);
00319   while (itr != render_order_.end() && itr != render_order_.begin()) {
00320     *itr = *(itr-1);
00321     --itr;
00322   }
00323   *(itr) = active_child_;
00324 }
00325 
00326 //----------------------------------------------------------------------------
00327 class vgui_selector_switch_command : public vgui_command
00328 {
00329  public:
00330   vgui_selector_switch_command(vgui_selector_tableau* s, const vcl_string& n) : selector(s), name(n) {}
00331   void execute() { selector->set_active(name); selector->post_redraw(); }
00332 
00333   vgui_selector_tableau *selector;
00334   vcl_string name;
00335 };
00336 
00337 //----------------------------------------------------------------------------
00338 class vgui_selector_toggle_command : public vgui_command
00339 {
00340  public:
00341   vgui_selector_toggle_command(vgui_selector_tableau* s, const vcl_string& n) : selector(s), name(n) {}
00342   void execute() { selector->toggle(name); selector->post_redraw(); }
00343 
00344   vgui_selector_tableau *selector;
00345   vcl_string name;
00346 };
00347 
00348 //----------------------------------------------------------------------------
00349 class vgui_selector_position_command : public vgui_command
00350 {
00351  public:
00352   enum motion { TO_TOP, RAISE, LOWER, TO_BOTTOM };
00353   vgui_selector_position_command(vgui_selector_tableau* s, motion m) : selector(s), m_type(m) {}
00354   void execute()
00355   {
00356     switch (m_type)
00357     {
00358      case TO_TOP:
00359       selector->active_to_top();
00360       break;
00361      case RAISE:
00362       selector->active_raise();
00363       break;
00364      case LOWER:
00365       selector->active_lower();
00366       break;
00367      case TO_BOTTOM:
00368       selector->active_to_bottom();
00369       break;
00370      default: // should never be reached...
00371       break;
00372     };
00373     selector->post_redraw();
00374   }
00375 
00376   vgui_selector_tableau *selector;
00377   motion m_type;
00378 };
00379 
00380 
00381 //----------------------------------------------------------------------------
00382 //: Builds a popup menu for the user to select the active child.
00383 void vgui_selector_tableau::get_popup(const vgui_popup_params& params,
00384                                       vgui_menu &menu)
00385 {
00386   vgui_menu submenu;
00387 
00388   // build child selection menus
00389   vgui_menu active_menu;
00390   vgui_menu visible_menu;
00391   vgui_menu position_menu;
00392 
00393   vcl_string check;
00394   vcl_vector<vcl_string>::reverse_iterator itr = render_order_.rbegin();
00395   for ( ; itr != render_order_.rend() ; ++itr) {
00396     vcl_string box_head, box_tail, check;
00397     if ( !get_tableau(*itr) ){
00398       box_head = "(";
00399       box_tail = ") ";
00400     }
00401     else{
00402       box_head = "[";
00403       box_tail = "] ";
00404     }
00405 
00406     if ( *itr == active_child_ ) check = "x";
00407     else check = " ";
00408     active_menu.add(box_head+check+box_tail+(*itr),
00409                     new vgui_selector_switch_command(this,*itr));
00410 
00411     if ( is_visible(*itr) ) check = "x";
00412     else check = " ";
00413     visible_menu.add(box_head+check+box_tail+(*itr),
00414                      new vgui_selector_toggle_command(this,*itr));
00415   }
00416 
00417   position_menu.add("Move to Top", new vgui_selector_position_command(this, vgui_selector_position_command::TO_TOP));
00418   position_menu.add("Move Up", new vgui_selector_position_command(this, vgui_selector_position_command::RAISE));
00419   position_menu.add("Move Down", new vgui_selector_position_command(this,vgui_selector_position_command::LOWER));
00420   position_menu.add("Move to Bottom", new vgui_selector_position_command(this,vgui_selector_position_command::TO_BOTTOM));
00421 
00422   submenu.add("Toggle Visible", visible_menu);
00423   submenu.add("Select Active", active_menu);
00424   submenu.add("Position Active", position_menu);
00425   add_to_menu(submenu);
00426   if (params.nested)
00427   {
00428     // nested menu style
00429 
00430     vgui_tableau_sptr a = active_tableau();
00431 
00432     if (a && params.defaults) submenu.separator();
00433     a->get_popup(params, submenu);
00434     menu.add(type_name(), submenu);
00435   }
00436   else
00437   {
00438     menu.add(type_name(),submenu);
00439 
00440     if (params.recurse) {
00441       vgui_tableau_sptr a = active_tableau();
00442       if (a)
00443         a->get_popup(params, menu);
00444     }
00445   }
00446 }
00447