00001 // Filename: modifierButtons.cxx 00002 // Created by: drose (01Mar00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "modifierButtons.h" 00020 00021 #include <notify.h> 00022 00023 //////////////////////////////////////////////////////////////////// 00024 // Function: ModifierButtons::Constructor 00025 // Access: Published 00026 // Description: 00027 //////////////////////////////////////////////////////////////////// 00028 ModifierButtons:: 00029 ModifierButtons() : 00030 _state(0) 00031 { 00032 _button_list= PTA(ButtonHandle)::empty_array(0); 00033 } 00034 00035 //////////////////////////////////////////////////////////////////// 00036 // Function: ModifierButtons::Copy Constructor 00037 // Access: Published 00038 // Description: 00039 //////////////////////////////////////////////////////////////////// 00040 ModifierButtons:: 00041 ModifierButtons(const ModifierButtons ©) : 00042 _button_list(copy._button_list), 00043 _state(copy._state) 00044 { 00045 } 00046 00047 //////////////////////////////////////////////////////////////////// 00048 // Function: ModifierButtons::Destructor 00049 // Access: Published 00050 // Description: 00051 //////////////////////////////////////////////////////////////////// 00052 ModifierButtons:: 00053 ~ModifierButtons() { 00054 } 00055 00056 //////////////////////////////////////////////////////////////////// 00057 // Function: ModifierButtons::matches 00058 // Access: Published 00059 // Description: Returns true if the set of buttons indicated as down 00060 // by this ModifierButtons object is the same set of 00061 // buttons indicated as down by the other 00062 // ModifierButtons object. The buttons indicated as up 00063 // are not relevant. 00064 //////////////////////////////////////////////////////////////////// 00065 bool ModifierButtons:: 00066 matches(const ModifierButtons &other) const { 00067 if (_button_list == other._button_list) { 00068 // If the two objects share the same array, we only need to check 00069 // the bitmask. This is a simple optimization. 00070 return (_state == other._state); 00071 } 00072 00073 // The two objects do not share the same array; thus we have to do 00074 // this one button at a time. This is an n-squared operation, but 00075 // presumably there will not be hundreds of buttons to compare. 00076 00077 // First, check that all the buttons indicated as down in our object 00078 // are also indicated as down in the other object. 00079 int num_down = 0; 00080 00081 int i; 00082 for (i = 0; i < (int)_button_list.size(); i++) { 00083 if (is_down(i)) { 00084 if (!other.is_down(_button_list[i])) { 00085 return false; 00086 } 00087 num_down++; 00088 } 00089 } 00090 00091 // Now make sure the total number of buttons indicated as down in 00092 // our object matches the number indicated as down in the other 00093 // object. This ensures there aren't any additional buttons 00094 // indicated down in the other object. 00095 int num_other_buttons = other.get_num_buttons(); 00096 int num_other_down = 0; 00097 for (i = 0; i < num_other_buttons; i++) { 00098 if (other.is_down(i)) { 00099 num_other_down++; 00100 } 00101 } 00102 00103 return (num_down == num_other_down); 00104 } 00105 00106 //////////////////////////////////////////////////////////////////// 00107 // Function: ModifierButtons::add_button 00108 // Access: Published 00109 // Description: Adds the indicated button to the set of buttons that 00110 // will be monitored for upness and downness. Returns 00111 // true if the button was added, false if it was already 00112 // being monitored or if too many buttons are currently 00113 // being monitored. 00114 //////////////////////////////////////////////////////////////////// 00115 bool ModifierButtons:: 00116 add_button(ButtonHandle button) { 00117 nassertr(button != ButtonHandle::none(), false); 00118 00119 static const int max_buttons = sizeof(BitmaskType) * 8; 00120 00121 if ((int)_button_list.size() >= max_buttons) { 00122 return false; 00123 } 00124 00125 // First, check to see if the button is already being monitored. 00126 if (has_button(button)) { 00127 return false; 00128 } 00129 00130 // Ok, it's not; add it. 00131 modify_button_list(); 00132 _button_list.push_back(button); 00133 00134 return true; 00135 } 00136 00137 //////////////////////////////////////////////////////////////////// 00138 // Function: ModifierButtons::has_button 00139 // Access: Published 00140 // Description: Returns true if the indicated button is in the set of 00141 // buttons being monitored, false otherwise. 00142 //////////////////////////////////////////////////////////////////// 00143 bool ModifierButtons:: 00144 has_button(ButtonHandle button) const { 00145 PTA(ButtonHandle)::const_iterator bi; 00146 for (bi = _button_list.begin(); bi != _button_list.end(); ++bi) { 00147 if (button == (*bi)) { 00148 return true; 00149 } 00150 } 00151 00152 return false; 00153 } 00154 00155 //////////////////////////////////////////////////////////////////// 00156 // Function: ModifierButtons::remove_button 00157 // Access: Published 00158 // Description: Removes the indicated button from the set of buttons 00159 // being monitored. Returns true if the button was 00160 // removed, false if it was not being monitored in the 00161 // first place. 00162 //////////////////////////////////////////////////////////////////// 00163 bool ModifierButtons:: 00164 remove_button(ButtonHandle button) { 00165 // We use i instead of an iterator, because we need to call 00166 // modify_button_list() just before we remove the button, and that 00167 // may invalidate all of the iterators. 00168 00169 for (int i = 0; i < (int)_button_list.size(); i++) { 00170 if (button == _button_list[i]) { 00171 modify_button_list(); 00172 _button_list.erase(_button_list.begin() + i); 00173 00174 // Now remove the corresponding bit from the bitmask and shift 00175 // all the bits above it down. 00176 BitmaskType mask = ((BitmaskType)1 << i); 00177 BitmaskType below = mask - 1; 00178 BitmaskType above = (~below) & (~mask); 00179 00180 _state = ((_state & above) >> 1) | (_state & below); 00181 return true; 00182 } 00183 } 00184 00185 return false; 00186 } 00187 00188 //////////////////////////////////////////////////////////////////// 00189 // Function: ModifierButtons::button_down 00190 // Access: Published 00191 // Description: Records that a particular button has been pressed. 00192 // If the given button is one of the buttons that is 00193 // currently being monitored, this will update the 00194 // internal state appropriately; otherwise, it will do 00195 // nothing. Returns true if the button is one that was 00196 // monitored, or false otherwise. 00197 //////////////////////////////////////////////////////////////////// 00198 bool ModifierButtons:: 00199 button_down(ButtonHandle button) { 00200 for (int i = 0; i < (int)_button_list.size(); i++) { 00201 if (button == _button_list[i]) { 00202 _state |= ((BitmaskType)1 << i); 00203 return true; 00204 } 00205 } 00206 00207 return false; 00208 } 00209 00210 //////////////////////////////////////////////////////////////////// 00211 // Function: ModifierButtons::button_up 00212 // Access: Published 00213 // Description: Records that a particular button has been released. 00214 // If the given button is one of the buttons that is 00215 // currently being monitored, this will update the 00216 // internal state appropriately; otherwise, it will do 00217 // nothing. Returns true if the button is one that was 00218 // monitored, or false otherwise. 00219 //////////////////////////////////////////////////////////////////// 00220 bool ModifierButtons:: 00221 button_up(ButtonHandle button) { 00222 for (int i = 0; i < (int)_button_list.size(); i++) { 00223 if (button == _button_list[i]) { 00224 _state &= ~((BitmaskType)1 << i); 00225 return true; 00226 } 00227 } 00228 00229 return false; 00230 } 00231 00232 //////////////////////////////////////////////////////////////////// 00233 // Function: ModifierButtons::is_down 00234 // Access: Published 00235 // Description: Returns true if the indicated button is known to be 00236 // down, or false if it is known to be up or if it is 00237 // not in the set of buttons being tracked. 00238 //////////////////////////////////////////////////////////////////// 00239 bool ModifierButtons:: 00240 is_down(ButtonHandle button) const { 00241 for (int i = 0; i < (int)_button_list.size(); i++) { 00242 if (button == _button_list[i]) { 00243 return ((_state & ((BitmaskType)1 << i)) != 0); 00244 } 00245 } 00246 00247 return false; 00248 } 00249 00250 //////////////////////////////////////////////////////////////////// 00251 // Function: ModifierButtons::get_prefix 00252 // Access: Published 00253 // Description: Returns a string which can be used to prefix any 00254 // button name or event name with the unique set of 00255 // modifier buttons currently being held. 00256 //////////////////////////////////////////////////////////////////// 00257 string ModifierButtons:: 00258 get_prefix() const { 00259 string prefix; 00260 for (int i = 0; i < (int)_button_list.size(); i++) { 00261 if ((_state & ((BitmaskType)1 << i)) != 0) { 00262 prefix += _button_list[i].get_name(); 00263 prefix += '-'; 00264 } 00265 } 00266 00267 return prefix; 00268 } 00269 00270 //////////////////////////////////////////////////////////////////// 00271 // Function: ModifierButtons::output 00272 // Access: Published 00273 // Description: Writes a one-line summary of the buttons known to be 00274 // down. 00275 //////////////////////////////////////////////////////////////////// 00276 void ModifierButtons:: 00277 output(ostream &out) const { 00278 out << "["; 00279 for (int i = 0; i < (int)_button_list.size(); i++) { 00280 if ((_state & ((BitmaskType)1 << i)) != 0) { 00281 out << " " << _button_list[i]; 00282 } 00283 } 00284 out << " ]"; 00285 } 00286 00287 //////////////////////////////////////////////////////////////////// 00288 // Function: ModifierButtons::write 00289 // Access: Published 00290 // Description: Writes a multi-line summary including all of the 00291 // buttons being monitored and which ones are known to 00292 // be down. 00293 //////////////////////////////////////////////////////////////////// 00294 void ModifierButtons:: 00295 write(ostream &out) const { 00296 out << "ModifierButtons:\n"; 00297 for (int i = 0; i < (int)_button_list.size(); i++) { 00298 out << " " << _button_list[i]; 00299 if ((_state & ((BitmaskType)1 << i)) != 0) { 00300 out << " (down)"; 00301 } 00302 out << "\n"; 00303 } 00304 } 00305 00306 //////////////////////////////////////////////////////////////////// 00307 // Function: ModifierButtons::modify_button_list 00308 // Access: Private 00309 // Description: Implements a poor-man's copy-on-write for the 00310 // ModifierButtons class. If any reference counts are 00311 // held on our _button_list, besides ourselves, then 00312 // allocates and copies a brand new copy of the 00313 // _button_list. This should be done in preparation for 00314 // any modifications to the _button_list, since multiple 00315 // instances of the ModifierButtons object may share the 00316 // same _button_list pointer. 00317 //////////////////////////////////////////////////////////////////// 00318 void ModifierButtons:: 00319 modify_button_list() { 00320 if (_button_list.get_ref_count() > 1) { 00321 PTA(ButtonHandle) old_list = _button_list; 00322 00323 _button_list = PTA(ButtonHandle)::empty_array(0); 00324 00325 // This forces a new allocation and memberwise copy, instead of 00326 // just a reference-counting pointer copy. 00327 _button_list.v() = old_list.v(); 00328 } 00329 00330 // Now we should be the only ones holding a count. 00331 nassertv(_button_list.get_ref_count() == 1); 00332 }