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 }