Panda3D
 All Classes Functions Variables Enumerations
modifierButtons.cxx
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 &copy) :
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 }
 All Classes Functions Variables Enumerations