Panda3D
|
00001 // Filename: modifierButtons.cxx 00002 // Created by: drose (01Mar00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "modifierButtons.h" 00016 00017 #include "pnotify.h" 00018 00019 //////////////////////////////////////////////////////////////////// 00020 // Function: ModifierButtons::Constructor 00021 // Access: Published 00022 // Description: 00023 //////////////////////////////////////////////////////////////////// 00024 ModifierButtons:: 00025 ModifierButtons() : 00026 _state(0) 00027 { 00028 _button_list = PTA(ButtonHandle)::empty_array(0); 00029 } 00030 00031 //////////////////////////////////////////////////////////////////// 00032 // Function: ModifierButtons::Copy Constructor 00033 // Access: Published 00034 // Description: 00035 //////////////////////////////////////////////////////////////////// 00036 ModifierButtons:: 00037 ModifierButtons(const ModifierButtons ©) : 00038 _button_list(copy._button_list), 00039 _state(copy._state) 00040 { 00041 } 00042 00043 //////////////////////////////////////////////////////////////////// 00044 // Function: ModifierButtons::Destructor 00045 // Access: Published 00046 // Description: 00047 //////////////////////////////////////////////////////////////////// 00048 ModifierButtons:: 00049 ~ModifierButtons() { 00050 } 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: ModifierButtons::operator &= 00054 // Access: Published 00055 // Description: Sets is_down() true for any button that is already 00056 // true for this object and the other object. 00057 //////////////////////////////////////////////////////////////////// 00058 void ModifierButtons:: 00059 operator &= (const ModifierButtons &other) { 00060 if (_button_list == other._button_list) { 00061 // Trivially easy case: if the button lists are the same, we can 00062 // do this using a bitmask operation. 00063 _state &= other._state; 00064 00065 } else { 00066 // More complicated case: if the button lists are different, we 00067 // have to iterate through the buttons and compare them 00068 // case-by-case. This becomes an n^2 operation, but fortunately 00069 // there won't be more than a handful of buttons. 00070 int num_buttons = get_num_buttons(); 00071 for (int i = 0; i < num_buttons; i++) { 00072 if (is_down(i) && !other.is_down(get_button(i))) { 00073 _state &= ~((BitmaskType)1 << i); 00074 } 00075 } 00076 } 00077 } 00078 00079 //////////////////////////////////////////////////////////////////// 00080 // Function: ModifierButtons::operator |= 00081 // Access: Published 00082 // Description: Sets is_down() true for any button that is already 00083 // true for this object and the other object. Adds 00084 // whatever buttons are necessary to the list to make 00085 // this so 00086 //////////////////////////////////////////////////////////////////// 00087 void ModifierButtons:: 00088 operator |= (const ModifierButtons &other) { 00089 if (_button_list == other._button_list) { 00090 // Trivially easy case: if the button lists are the same, we can 00091 // do this using a bitmask operation. 00092 _state |= other._state; 00093 00094 } else { 00095 // More complicated case: if the button lists are different, we 00096 // have to iterate through the buttons and compare them 00097 // case-by-case. This becomes an n^2 operation, but fortunately 00098 // there won't be more than a handful of buttons. 00099 int num_buttons = other.get_num_buttons(); 00100 for (int i = 0; i < num_buttons; i++) { 00101 if (other.is_down(i)) { 00102 add_button(other.get_button(i)); 00103 button_down(other.get_button(i)); 00104 } 00105 } 00106 } 00107 } 00108 00109 //////////////////////////////////////////////////////////////////// 00110 // Function: ModifierButtons::set_button_list 00111 // Access: Published 00112 // Description: Sets the list of buttons to watch to be the same as 00113 // that of the other ModifierButtons object. This makes 00114 // the lists pointer equivalent (until one or the other 00115 // is later modified). 00116 // 00117 // This will preserve the state of any button that was 00118 // on the original list and is also on the new lists. 00119 // Any other buttons will get reset to the default state 00120 // of "up". 00121 //////////////////////////////////////////////////////////////////// 00122 void ModifierButtons:: 00123 set_button_list(const ModifierButtons &other) { 00124 if (_button_list != other._button_list) { 00125 if (_state != 0) { 00126 // If we have some buttons already down, we have to copy them to 00127 // the new state. 00128 BitmaskType new_state = 0; 00129 int num_buttons = other.get_num_buttons(); 00130 for (int i = 0; i < num_buttons; i++) { 00131 if (is_down(other.get_button(i))) { 00132 new_state |= ((BitmaskType)1 << i); 00133 } 00134 } 00135 00136 _state = new_state; 00137 } 00138 00139 _button_list = other._button_list; 00140 } 00141 } 00142 00143 //////////////////////////////////////////////////////////////////// 00144 // Function: ModifierButtons::matches 00145 // Access: Published 00146 // Description: Returns true if the set of buttons indicated as down 00147 // by this ModifierButtons object is the same set of 00148 // buttons indicated as down by the other 00149 // ModifierButtons object. The buttons indicated as up 00150 // are not relevant. 00151 //////////////////////////////////////////////////////////////////// 00152 bool ModifierButtons:: 00153 matches(const ModifierButtons &other) const { 00154 if (_button_list == other._button_list) { 00155 // If the two objects share the same array, we only need to check 00156 // the bitmask. This is a simple optimization. 00157 return (_state == other._state); 00158 } 00159 00160 // The two objects do not share the same array; thus we have to do 00161 // this one button at a time. This is an n-squared operation, but 00162 // presumably there will not be hundreds of buttons to compare. 00163 00164 // First, check that all the buttons indicated as down in our object 00165 // are also indicated as down in the other object. 00166 int num_down = 0; 00167 00168 int i; 00169 for (i = 0; i < (int)_button_list.size(); i++) { 00170 if (is_down(i)) { 00171 if (!other.is_down(_button_list[i])) { 00172 return false; 00173 } 00174 num_down++; 00175 } 00176 } 00177 00178 // Now make sure the total number of buttons indicated as down in 00179 // our object matches the number indicated as down in the other 00180 // object. This ensures there aren't any additional buttons 00181 // indicated down in the other object. 00182 int num_other_buttons = other.get_num_buttons(); 00183 int num_other_down = 0; 00184 for (i = 0; i < num_other_buttons; i++) { 00185 if (other.is_down(i)) { 00186 num_other_down++; 00187 } 00188 } 00189 00190 return (num_down == num_other_down); 00191 } 00192 00193 //////////////////////////////////////////////////////////////////// 00194 // Function: ModifierButtons::add_button 00195 // Access: Published 00196 // Description: Adds the indicated button to the set of buttons that 00197 // will be monitored for upness and downness. Returns 00198 // true if the button was added, false if it was already 00199 // being monitored or if too many buttons are currently 00200 // being monitored. 00201 //////////////////////////////////////////////////////////////////// 00202 bool ModifierButtons:: 00203 add_button(ButtonHandle button) { 00204 nassertr(button != ButtonHandle::none(), false); 00205 00206 static const int max_buttons = sizeof(BitmaskType) * 8; 00207 00208 if ((int)_button_list.size() >= max_buttons) { 00209 return false; 00210 } 00211 00212 // First, check to see if the button is already being monitored. 00213 if (has_button(button)) { 00214 return false; 00215 } 00216 00217 // Ok, it's not; add it. 00218 modify_button_list(); 00219 _button_list.push_back(button); 00220 00221 return true; 00222 } 00223 00224 //////////////////////////////////////////////////////////////////// 00225 // Function: ModifierButtons::has_button 00226 // Access: Published 00227 // Description: Returns true if the indicated button is in the set of 00228 // buttons being monitored, false otherwise. 00229 //////////////////////////////////////////////////////////////////// 00230 bool ModifierButtons:: 00231 has_button(ButtonHandle button) const { 00232 PTA(ButtonHandle)::const_iterator bi; 00233 for (bi = _button_list.begin(); bi != _button_list.end(); ++bi) { 00234 if (button.matches(*bi)) { 00235 return true; 00236 } 00237 } 00238 00239 return false; 00240 } 00241 00242 //////////////////////////////////////////////////////////////////// 00243 // Function: ModifierButtons::remove_button 00244 // Access: Published 00245 // Description: Removes the indicated button from the set of buttons 00246 // being monitored. Returns true if the button was 00247 // removed, false if it was not being monitored in the 00248 // first place. 00249 // 00250 // Unlike the other methods, you cannot remove a button 00251 // by removing its alias; you have to remove exactly the 00252 // button itself. 00253 //////////////////////////////////////////////////////////////////// 00254 bool ModifierButtons:: 00255 remove_button(ButtonHandle button) { 00256 // We use i instead of an iterator, because we need to call 00257 // modify_button_list() just before we remove the button, and that 00258 // may invalidate all of the iterators. 00259 00260 for (int i = 0; i < (int)_button_list.size(); i++) { 00261 if (button == _button_list[i]) { 00262 modify_button_list(); 00263 _button_list.erase(_button_list.begin() + i); 00264 00265 // Now remove the corresponding bit from the bitmask and shift 00266 // all the bits above it down. 00267 BitmaskType mask = ((BitmaskType)1 << i); 00268 BitmaskType below = mask - 1; 00269 BitmaskType above = (~below) & (~mask); 00270 00271 _state = ((_state & above) >> 1) | (_state & below); 00272 return true; 00273 } 00274 } 00275 00276 return false; 00277 } 00278 00279 //////////////////////////////////////////////////////////////////// 00280 // Function: ModifierButtons::button_down 00281 // Access: Published 00282 // Description: Records that a particular button has been pressed. 00283 // If the given button is one of the buttons that is 00284 // currently being monitored, this will update the 00285 // internal state appropriately; otherwise, it will do 00286 // nothing. Returns true if the button is one that was 00287 // monitored, or false otherwise. 00288 //////////////////////////////////////////////////////////////////// 00289 bool ModifierButtons:: 00290 button_down(ButtonHandle button) { 00291 for (int i = 0; i < (int)_button_list.size(); i++) { 00292 if (button.matches(_button_list[i])) { 00293 _state |= ((BitmaskType)1 << i); 00294 return true; 00295 } 00296 } 00297 00298 return false; 00299 } 00300 00301 //////////////////////////////////////////////////////////////////// 00302 // Function: ModifierButtons::button_up 00303 // Access: Published 00304 // Description: Records that a particular button has been released. 00305 // If the given button is one of the buttons that is 00306 // currently being monitored, this will update the 00307 // internal state appropriately; otherwise, it will do 00308 // nothing. Returns true if the button is one that was 00309 // monitored, or false otherwise. 00310 //////////////////////////////////////////////////////////////////// 00311 bool ModifierButtons:: 00312 button_up(ButtonHandle button) { 00313 for (int i = 0; i < (int)_button_list.size(); i++) { 00314 if (button.matches(_button_list[i])) { 00315 _state &= ~((BitmaskType)1 << i); 00316 return true; 00317 } 00318 } 00319 00320 return false; 00321 } 00322 00323 //////////////////////////////////////////////////////////////////// 00324 // Function: ModifierButtons::is_down 00325 // Access: Published 00326 // Description: Returns true if the indicated button is known to be 00327 // down, or false if it is known to be up or if it is 00328 // not in the set of buttons being tracked. 00329 //////////////////////////////////////////////////////////////////// 00330 bool ModifierButtons:: 00331 is_down(ButtonHandle button) const { 00332 for (int i = 0; i < (int)_button_list.size(); i++) { 00333 if (button.matches(_button_list[i])) { 00334 return ((_state & ((BitmaskType)1 << i)) != 0); 00335 } 00336 } 00337 00338 return false; 00339 } 00340 00341 //////////////////////////////////////////////////////////////////// 00342 // Function: ModifierButtons::get_prefix 00343 // Access: Published 00344 // Description: Returns a string which can be used to prefix any 00345 // button name or event name with the unique set of 00346 // modifier buttons currently being held. 00347 //////////////////////////////////////////////////////////////////// 00348 string ModifierButtons:: 00349 get_prefix() const { 00350 string prefix; 00351 for (int i = 0; i < (int)_button_list.size(); i++) { 00352 if ((_state & ((BitmaskType)1 << i)) != 0) { 00353 prefix += _button_list[i].get_name(); 00354 prefix += '-'; 00355 } 00356 } 00357 00358 return prefix; 00359 } 00360 00361 //////////////////////////////////////////////////////////////////// 00362 // Function: ModifierButtons::output 00363 // Access: Published 00364 // Description: Writes a one-line summary of the buttons known to be 00365 // down. 00366 //////////////////////////////////////////////////////////////////// 00367 void ModifierButtons:: 00368 output(ostream &out) const { 00369 out << "["; 00370 for (int i = 0; i < (int)_button_list.size(); i++) { 00371 if ((_state & ((BitmaskType)1 << i)) != 0) { 00372 out << " " << _button_list[i]; 00373 } 00374 } 00375 out << " ]"; 00376 } 00377 00378 //////////////////////////////////////////////////////////////////// 00379 // Function: ModifierButtons::write 00380 // Access: Published 00381 // Description: Writes a multi-line summary including all of the 00382 // buttons being monitored and which ones are known to 00383 // be down. 00384 //////////////////////////////////////////////////////////////////// 00385 void ModifierButtons:: 00386 write(ostream &out) const { 00387 out << "ModifierButtons:\n"; 00388 for (int i = 0; i < (int)_button_list.size(); i++) { 00389 out << " " << _button_list[i]; 00390 if ((_state & ((BitmaskType)1 << i)) != 0) { 00391 out << " (down)"; 00392 } 00393 out << "\n"; 00394 } 00395 } 00396 00397 //////////////////////////////////////////////////////////////////// 00398 // Function: ModifierButtons::modify_button_list 00399 // Access: Private 00400 // Description: Implements a poor-man's copy-on-write for the 00401 // ModifierButtons class. If any reference counts are 00402 // held on our _button_list, besides ourselves, then 00403 // allocates and copies a brand new copy of the 00404 // _button_list. This should be done in preparation for 00405 // any modifications to the _button_list, since multiple 00406 // instances of the ModifierButtons object may share the 00407 // same _button_list pointer. 00408 //////////////////////////////////////////////////////////////////// 00409 void ModifierButtons:: 00410 modify_button_list() { 00411 if (_button_list.get_ref_count() > 1) { 00412 PTA(ButtonHandle) old_list = _button_list; 00413 00414 _button_list = PTA(ButtonHandle)::empty_array(0); 00415 00416 // This forces a new allocation and memberwise copy, instead of 00417 // just a reference-counting pointer copy. 00418 _button_list.v() = old_list.v(); 00419 } 00420 00421 // Now we should be the only ones holding a count. 00422 nassertv(_button_list.get_ref_count() == 1); 00423 }