core/vgui/vgui_tableau.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_tableau.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Philip C. Pritchett, Robotics Research Group, University of Oxford
00008 // \date   11 Sep 99
00009 // \brief  See vgui_tableau.h for a description of this file.
00010 //
00011 // \verbatim
00012 //  Modifications
00013 //   11-SEP-1999 P.Pritchett - Initial version.
00014 //   08-OCT-2002 K.Y.McGaul - Removed unused adopt and disown functions.
00015 // \endverbatim
00016 
00017 #include "vgui_tableau.h"
00018 
00019 #include <vcl_cassert.h>
00020 #include <vcl_iostream.h>
00021 #include <vcl_vector.h>
00022 #include <vcl_algorithm.h>
00023 
00024 #include <vgui/vgui_macro.h>
00025 #include <vgui/vgui_event.h>
00026 #include <vgui/vgui_parent_child_link.h>
00027 #include <vgui/vgui_menu.h>
00028 #include <vgui/vgui_popup_params.h>
00029 #include <vgui/vgui_tableau_sptr.h>
00030 
00031 // static data
00032 //------------
00033 // Every tableau is on this array.
00034 // It must be a ptr as must live longer than any vgui_tableau_sptr
00035 static vgui_DLLDATA vcl_vector<vgui_tableau*>* all = 0;
00036 
00037 //-----------------------------------------------------------------------------
00038 //: Constructor.
00039 //  Don't use the constructor for a tableau, use vgui_tableau_sptr to get
00040 //  a smart-pointer to your tableau.
00041 vgui_tableau::vgui_tableau()
00042   : references(0)
00043 {
00044 #ifdef DEBUG
00045   vcl_cerr << "vgui_tableau constructor: this = " << (void*)this << '\n';
00046 #endif
00047   // register :
00048   if (all == 0) {
00049     all = new vcl_vector<vgui_tableau*>;
00050   }
00051   all->push_back(this);
00052 }
00053 
00054 //-----------------------------------------------------------------------------
00055 //: Destructor - called by vgui_tableau_sptr when ref count is zero.
00056 vgui_tableau::~vgui_tableau()
00057 {
00058 #ifdef DEBUG
00059   vcl_cerr << "vgui_tableau destructor : this = " << (void*)this << '\n';
00060 #endif
00061 
00062   if (references != 0)
00063     vgui_macro_warning << "there are still " << references
00064                        << " references. this=" << (void*)this << vcl_endl;
00065 
00066   // deregister :
00067   vcl_vector<vgui_tableau*>::iterator i=vcl_find(all->begin(), all->end(), this);
00068   assert(i != all->end());
00069   all->erase(i);
00070   if (all->size() == 0)
00071   {
00072     delete all;
00073     all = 0;
00074   }
00075 }
00076 
00077 //-----------------------------------------------------------------------------
00078 //: Increase the reference count by one (for smart-pointers).
00079 void vgui_tableau::ref() const
00080 {
00081   ++ const_cast<int &>(references);
00082 }
00083 
00084 //-----------------------------------------------------------------------------
00085 //: Decrease the reference count by one (for smart-pointers).
00086 //  If the reference count reaches zero then delete the object.
00087 void vgui_tableau::unref() const
00088 {
00089   assert(references > 0); // fatal if not
00090 
00091   if (-- const_cast<int &>(references) == 0) {
00092     delete const_cast<vgui_tableau*>(this);
00093   }
00094 }
00095 
00096 //-----------------------------------------------------------------------------
00097 //: Handle all events sent to this tableau.
00098 //  Override in subclasses to give the tableau some appearance and behaviour.
00099 bool vgui_tableau::handle(vgui_event const &event)
00100 {
00101   vgui_macro_report_errors;
00102 
00103   switch (event.type) {
00104    case vgui_DRAW:
00105     return draw();
00106    case vgui_BUTTON_DOWN:
00107     return mouse_down (event.wx, event.wy, event.button, event.modifier);
00108    case vgui_MOTION:
00109     return motion     (event.wx, event.wy);
00110    case vgui_BUTTON_UP:
00111     return mouse_up   (event.wx, event.wy, event.button, event.modifier);
00112    case vgui_KEY_PRESS:
00113     if (event.key == '?' || event.key == '/')
00114       return help();
00115     else
00116       return key_press(event.wx, event.wy, event.key, event.modifier);
00117    case vgui_IDLE:
00118     return idle();
00119    default:
00120     return false;
00121   }
00122 }
00123 
00124 //-----------------------------------------------------------------------------
00125 //: Called by default handle when it receives a mouse down event.
00126 bool vgui_tableau::mouse_down(int, int, vgui_button, vgui_modifier)
00127 {
00128 #ifdef DEBUG
00129   vcl_cerr << "vgui_tableau::mouse_down\n";
00130 #endif
00131   return false;
00132 }
00133 
00134 //-----------------------------------------------------------------------------
00135 //: Called by default handle when it receives a mouse up event.
00136 bool vgui_tableau::mouse_up(int, int, vgui_button, vgui_modifier)
00137 {
00138 #ifdef DEBUG
00139   vcl_cerr << "vgui_tableau::mouse_up\n";
00140 #endif
00141   return false;
00142 }
00143 
00144 //-----------------------------------------------------------------------------
00145 //: Called by default handle when it receives a mouse motion event.
00146 bool vgui_tableau::motion(int, int)
00147 {
00148 #ifdef DEBUG
00149   vcl_cerr << "vgui_tableau::motion\n";
00150 #endif
00151   return false;
00152 }
00153 
00154 //-----------------------------------------------------------------------------
00155 //: Caled by default handle when it receives a key press event.
00156 bool vgui_tableau::key_press(int, int, vgui_key, vgui_modifier)
00157 {
00158 #ifdef DEBUG
00159   vcl_cerr << "vgui_tableau::key_press\n";
00160 #endif
00161   return false;
00162 }
00163 
00164 //-----------------------------------------------------------------------------
00165 //: Called by default handle when it receives a '?' pressed event.
00166 bool vgui_tableau::help()
00167 {
00168 #ifdef DEBUG
00169   vcl_cerr << "vgui_tableau::help\n";
00170 #endif
00171   return false;
00172 }
00173 
00174 //-----------------------------------------------------------------------------
00175 //: Called by default handle when it receives a draw event.
00176 bool vgui_tableau::draw()
00177 {
00178 #ifdef DEBUG
00179   vcl_cerr << "vgui_tableau::draw\n";
00180 #endif
00181   return false;
00182 }
00183 
00184 
00185 bool vgui_tableau::idle()
00186 {
00187 #ifdef DEBUG
00188   vcl_cerr << "vgui_tableau::idle\n";
00189 #endif
00190   return false; // no idle processing
00191 }
00192 
00193 
00194 //-----------------------------------------------------------------------------
00195 //: Return the bounding box of this tableau.
00196 //  If infinite in extent, or nothing is drawn, or you can't be bothered to
00197 //  implement it, return false.
00198 bool vgui_tableau::get_bounding_box(float /*low*/[3], float /*high*/[3]) const
00199 {
00200   return false;
00201 }
00202 
00203 //-----------------------------------------------------------------------------
00204 //: Post a message event.
00205 void vgui_tableau::post_message(char const *msg, void const *data)
00206 {
00207   vcl_vector<vgui_tableau_sptr> ps;
00208   get_parents(&ps);
00209   for (unsigned i=0; i<ps.size(); ++i)
00210     ps[i]->post_message(msg, data);
00211 }
00212 
00213 //-----------------------------------------------------------------------------
00214 //: Post a draw event.
00215 void vgui_tableau::post_redraw()
00216 {
00217   vcl_vector<vgui_tableau_sptr> ps;
00218   get_parents(&ps);
00219   for (unsigned i=0; i<ps.size(); ++i)
00220     ps[i]->post_redraw();
00221 }
00222 
00223 //-----------------------------------------------------------------------------
00224 //: Post an overlay redraw event.
00225 void vgui_tableau::post_overlay_redraw()
00226 {
00227   vcl_vector<vgui_tableau_sptr> ps;
00228   get_parents(&ps);
00229   for (unsigned i=0; i<ps.size(); ++i)
00230     ps[i]->post_overlay_redraw();
00231 }
00232 
00233 
00234 //-----------------------------------------------------------------------------
00235 void vgui_tableau::post_idle_request()
00236 {
00237   vcl_vector<vgui_tableau_sptr> ps;
00238   get_parents(&ps);
00239   for (unsigned i=0; i<ps.size(); ++i)
00240     ps[i]->post_idle_request();
00241 }
00242 
00243 
00244 //-----------------------------------------------------------------------------
00245 //: Return the name of the most derived (tableau) class.
00246 //  Virtual. This ought never to be called as derived classes should
00247 //  implement type_name().
00248 vcl_string vgui_tableau::type_name() const
00249 {
00250   static bool warned=false;
00251   if (!warned) {
00252     vgui_macro_warning << "WARNING: vgui_tableau::type_name() called\n";
00253     warned=true;
00254   }
00255   return "vgui_tableau";
00256 }
00257 
00258 //-----------------------------------------------------------------------------
00259 //: Push parents onto the given vcl_vector.
00260 void vgui_tableau::get_parents(vcl_vector<vgui_tableau_sptr> *v) const
00261 {
00262   vgui_parent_child_link::get_parents_of(const_cast<vgui_tableau*>(this),v);
00263 }
00264 
00265 //-----------------------------------------------------------------------------
00266 //: Push children onto the given vcl_vector.
00267 void vgui_tableau::get_children(vcl_vector<vgui_tableau_sptr> *v) const
00268 {
00269   vgui_parent_child_link::get_children_of(const_cast<vgui_tableau*>(this),v);
00270 }
00271 
00272 //-----------------------------------------------------------------------------
00273 //: Get the ith child, or return 0.
00274 vgui_tableau_sptr vgui_tableau::get_child(unsigned i) const
00275 {
00276   vcl_vector<vgui_tableau_sptr> children;
00277   get_children(&children);
00278   return i<children.size() ? children[i] : vgui_tableau_sptr();
00279 }
00280 
00281 //-----------------------------------------------------------------------------
00282 //: Add the given tableau to the list of child tableaux.
00283 //  Virtual overridden by consenting parents.
00284 bool vgui_tableau::add_child(vgui_tableau_sptr const &)
00285 {
00286   return false;
00287 }
00288 
00289 //-----------------------------------------------------------------------------
00290 //: Remove the given tableau from the list of child tableaux.
00291 bool vgui_tableau::remove_child(vgui_tableau_sptr const&)
00292 {
00293   return false;
00294 }
00295 
00296 //-----------------------------------------------------------------------------
00297 //: Called when a child of this tableau is forcibly replaced.
00298 //  This method is called when some part of the program (typically the
00299 //  parent_child_link mechanism) is about to forcibly replace a child of this
00300 //  tableau.
00301 //  The canonical reason to override this is in order to invalidate caches.
00302 bool vgui_tableau::notify_replaced_child(vgui_tableau_sptr const& /*old_child*/,
00303                                          vgui_tableau_sptr const& /*new_child*/)
00304 {
00305   return true;
00306 }
00307 
00308 //-----------------------------------------------------------------------------
00309 //: Add given menu to the tableau popup menu.
00310 //  This method is for tableaux to implement if they want to _add_ some items to
00311 //  the popup menu. They can assign to or clear 'menu', but that is not
00312 //  recommended as it would remove what other tableaux put there.
00313 //  The recommended usage is to .add() items or to .include() another menu.
00314 //
00315 //  ** This is an interface method. it abstracts a behaviour. **
00316 void vgui_tableau::add_popup(vgui_menu &/*menu*/)
00317 {
00318   // do nothing by default.
00319 }
00320 
00321 //-----------------------------------------------------------------------------
00322 //: Gets popup menu for this tableau.
00323 // If recurse is, true, recursively add the popup menus for children and
00324 // children's children etc.
00325 //
00326 // ** this is a mixin method. it does some work for you. **
00327 void vgui_tableau::get_popup(vgui_popup_params const &params, vgui_menu &menu)
00328 {
00329   // extract this tableau's popup menu into 'submenu'.
00330   vgui_menu submenu;
00331   add_popup(submenu);
00332 
00333   if (params.nested) { // nested menu style.
00334     // get list of children of this tableau.
00335     vcl_vector<vgui_tableau_sptr> children;
00336     get_children(&children);
00337 
00338     if (params.defaults && !children.empty())
00339       submenu.separator();
00340 
00341     for (unsigned i=0; i<children.size(); ++i)
00342       if (children[i])
00343         children[i]->get_popup(params, submenu);
00344 
00345     menu.add(type_name(), submenu);
00346   }
00347   else {
00348     // not nested.
00349     if (submenu.size() > 0) // do not add empty submenus.
00350       menu.include(submenu);
00351 
00352     if (params.recurse) {
00353       vcl_vector<vgui_tableau_sptr> children;
00354       get_children(&children);
00355 
00356       for (unsigned i=0; i<children.size(); ++i)
00357         if (children[i])
00358           children[i]->get_popup(params, menu);
00359     }
00360   }
00361 }
00362 
00363 //-----------------------------------------------------------------------------
00364 //: Prints pretty name and address of tableau.
00365 //  eg : pig.jpg[vgui_composite:0xeffff728]
00366 vcl_ostream &operator<<(vcl_ostream &os, vgui_tableau_sptr const &t)
00367 {
00368   if (t)
00369     return os << t->pretty_name() << '[' << t->type_name() << ':' << static_cast<const void*>(t.operator->()) << ']';
00370   else
00371     return os << "(empty vgui_tableau_sptr)" << vcl_flush;
00372 }
00373 
00374 //-----------------------------------------------------------------------------
00375 //: Push all tableaux onto the given vector.
00376 void vgui_tableau::get_all(vcl_vector<vgui_tableau_sptr> *v)
00377 {
00378   //v->insert(v->begin(), all->begin(), all->end());
00379   for (unsigned i=0; i<all->size(); ++i)
00380     v->push_back((*all)[i]);
00381 }
00382 
00383 //-----------------------------------------------------------------------------
00384 //: Returns true if the given address points to a valid tableau.
00385 bool vgui_tableau::exists(vgui_tableau_sptr const& ptr)
00386 {
00387   return vcl_find(all->begin(), all->end(), ptr.operator->()) != all->end();
00388 }