core/vgui/vgui_composite_tableau.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_composite_tableau.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Philip C. Pritchett, RRG, University of Oxford
00008 // \date   15 Sep 99
00009 // \brief  See vgui_composite_tableau.h for a description of this file.
00010 
00011 
00012 #include "vgui_composite_tableau.h"
00013 
00014 #include <vcl_iostream.h>
00015 #include <vcl_sstream.h>
00016 #include <vcl_vector.h>
00017 
00018 #include <vgui/vgui.h>
00019 #include <vgui/vgui_gl.h>
00020 #include <vgui/vgui_event.h>
00021 #include <vgui/vgui_matrix_state.h>
00022 
00023 static vgui_event_condition default_c_enable_key_bindings(vgui_key_CTRL('c'));
00024 
00025 //----------------------------------------------------------------------------
00026 //: Prints info about this tableau - called when '?' is pressed.
00027 bool vgui_composite_tableau::help()
00028 {
00029   vcl_cerr << "\n+- vgui_composite_tableau -----+\n"
00030            << "|     keys                     |\n"
00031            << "| `1' to `9'  toggle child `n' |\n"
00032            << "+------------------------------+\n\n";
00033   return false;
00034 }
00035 
00036 //----------------------------------------------------------------------------
00037 //: Constructor - don't use this, use vgui_composite_tableau_new.
00038 //  Creates an empty composite tableau.
00039 vgui_composite_tableau::vgui_composite_tableau()
00040   : c_enable_key_bindings(default_c_enable_key_bindings)
00041 {
00042   enable_key_bindings = false;
00043 }
00044 
00045 //----------------------------------------------------------------------------
00046 //: Constructor - don't use this, use vgui_composite_tableau_new.
00047 //  Takes 2 children: the first is on top, the second below.
00048 vgui_composite_tableau::vgui_composite_tableau(vgui_tableau_sptr const& child0,
00049                                                vgui_tableau_sptr const& child1)
00050   : c_enable_key_bindings(default_c_enable_key_bindings)
00051 {
00052   add(child0);
00053   add(child1);
00054   enable_key_bindings = false;
00055 }
00056 
00057 //----------------------------------------------------------------------------
00058 //: Constructor - don't use this, use vgui_composite_tableau_new.
00059 // Three children, top to bottom.
00060 vgui_composite_tableau::vgui_composite_tableau(vgui_tableau_sptr const& child0,
00061                                                vgui_tableau_sptr const& child1,
00062                                                vgui_tableau_sptr const& child2)
00063   : c_enable_key_bindings(default_c_enable_key_bindings)
00064 {
00065   add(child0);
00066   add(child1);
00067   add(child2);
00068   enable_key_bindings = false;
00069 }
00070 
00071 //----------------------------------------------------------------------------
00072 //: Constructor - don't use this, use vgui_composite_tableau_new.
00073 // Many children, top to bottom.
00074 vgui_composite_tableau::vgui_composite_tableau(vcl_vector<vgui_tableau_sptr> const& the_children)
00075   : c_enable_key_bindings(default_c_enable_key_bindings)
00076 {
00077   for (unsigned int i = 0; i < the_children.size(); ++i)
00078     add(the_children[i]);
00079   enable_key_bindings = false;
00080 }
00081 
00082 //----------------------------------------------------------------------------
00083 //: Returns a nice version of the name, including info on the children.
00084 vcl_string vgui_composite_tableau::pretty_name() const
00085 {
00086   vcl_stringstream s; s << type_name() << "[#kids=" << children.size() << ']';
00087   return s.str();
00088 }
00089 
00090 //----------------------------------------------------------------------------
00091 //: Handle all events sent to this tableau.
00092 //  All events (except key-presses '0'-'9' and draw events) are passed
00093 //  to each child until the event is handled.
00094 //  Key presses '0'-'9' toggle the activeness of the children and
00095 //  draw events are sent to all children.
00096 //  Key-press '?' prints info on this file, before being sent to the children.
00097 bool vgui_composite_tableau::handle(const vgui_event& event)
00098 {
00099   // Save current matrix state. Each active child will be
00100   // invoked with this matrix state.
00101   vgui_matrix_state PM;
00102   unsigned int n = children.size();
00103 
00104   // "DRAW" events. Return true unless some child returns false.
00105   // What is the logic behind this? I'm no longer sure....
00106   // Worse, draws should be upside down...
00107   if (event.type==vgui_DRAW || event.type==vgui_DRAW_OVERLAY) {
00108     bool retv = true;
00109 
00110     for (unsigned ia = 0; ia<n; ++ia) {
00111       if (active[ia] && children[ia]) {
00112         PM.restore();
00113         if ( !children[ia]->handle(event) )
00114           retv=false;
00115       }
00116     }
00117 
00118     return retv;
00119   }
00120 
00121   // "normal" events :
00122   // Alt-C enables / disables key bindings
00123   if (c_enable_key_bindings(event)) {
00124     vcl_cerr << "Toggle keybindings\n";
00125     vgui::out << "Toggle keybindings";
00126     enable_key_bindings = !enable_key_bindings;
00127   }
00128 
00129   // First check if the composite itself wants it :
00130   if (event.type == vgui_KEY_PRESS && enable_key_bindings) {
00131     int key = event.key;
00132     if (key == '?')
00133       help();
00134 
00135     if (key >= '1' && key <= '9') {
00136       toggle(key-'1');
00137       post_redraw();
00138       return true;
00139     }
00140   }
00141 
00142   // If not, pass it on till some child handles it :
00143   for (int ia = (int)n-1; ia>=0; --ia) {
00144     if (active[ia] && children[ia]) {
00145       PM.restore();
00146       if ( children[ia]->handle(event) )
00147         return true;
00148     }
00149   }
00150 
00151   // Noone was interested....
00152   return false;
00153 }
00154 
00155 //----------------------------------------------------------------------------
00156 //: Calls notify for the observers.
00157 void vgui_composite_tableau::notify() const
00158 {
00159   observers.notify();
00160 }
00161 
00162 //----------------------------------------------------------------------------
00163 //: Returns a bounding box large enough to contain all the child bounding boxes.
00164 bool vgui_composite_tableau::get_bounding_box(float lo[3], float hi[3]) const
00165 {
00166   // it would be nice if we could return an empty bounding box.
00167   if (children.empty())
00168     return false;
00169 
00170   // get bbox of first child.
00171   if (!children[0]->get_bounding_box(lo, hi))
00172     return false;
00173 
00174   for (unsigned i=1; i<children.size(); ++i) {
00175     // get bbox of child i.
00176     float l[3], h[3];
00177     if (!children[i]->get_bounding_box(l, h))
00178       return false;
00179 
00180     // enlarge if necessary.
00181     for (unsigned j=0; j<3; ++j) {
00182       if (l[j] < lo[j]) lo[j] = l[j];
00183       if (h[j] > hi[j]) hi[j] = h[j];
00184     }
00185   }
00186   return true;
00187 }
00188 
00189 //----------------------------------------------------------------------------
00190 //: Add to list of child tableaux.
00191 // virtual
00192 bool vgui_composite_tableau::add_child(vgui_tableau_sptr const& t)
00193 {
00194   children.push_back( vgui_parent_child_link(this,t) );
00195   active.push_back(true);
00196   notify();
00197   return true;
00198 }
00199 
00200 //----------------------------------------------------------------------------
00201 //: Remove given tableau from list of child tableaux.
00202 void vgui_composite_tableau::remove(vgui_tableau_sptr const& t)
00203 {
00204   if (!remove_child(t))
00205     vcl_cerr << __FILE__ " : no such child tableau\n";
00206 }
00207 
00208 //----------------------------------------------------------------------------
00209 void vgui_composite_tableau::clear()
00210 {
00211   children.clear();
00212   active.clear();
00213   notify();
00214 }
00215 
00216 //----------------------------------------------------------------------------
00217 // virtual
00218 bool vgui_composite_tableau::remove_child(vgui_tableau_sptr const &t)
00219 {
00220   vcl_vector<bool>::iterator ia = active.begin();
00221   for (vcl_vector<vgui_parent_child_link>::iterator i=children.begin() ; i!=children.end() ; ++i, ++ia)
00222     if ( (*i) == t ) {
00223       children.erase(i);
00224       active.erase(ia);
00225       notify();
00226       return true;
00227     }
00228   return false;
00229 }
00230 
00231 
00232 //----------------------------------------------------------------------------
00233 //: Returns true if given integer could be an index to the child tableaux.
00234 bool vgui_composite_tableau::index_ok(int v)
00235 {
00236   return v >= 0 && v < int(children.size());
00237 }
00238 
00239 
00240 //----------------------------------------------------------------------------
00241 bool vgui_composite_tableau::toggle(int v)
00242 {
00243   if (!index_ok(v)) return false;
00244   bool state = active[v];
00245   active[v] = !state;
00246 
00247   return true;
00248 }
00249 
00250 //----------------------------------------------------------------------------
00251 bool vgui_composite_tableau::is_active(int v)
00252 {
00253   if (!index_ok(v)) return false;
00254   return active[v];
00255 }