Panda3D
 All Classes Functions Variables Enumerations
modifierButtons.cxx
1 // Filename: modifierButtons.cxx
2 // Created by: drose (01Mar00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "modifierButtons.h"
16 
17 #include "pnotify.h"
18 
19 ////////////////////////////////////////////////////////////////////
20 // Function: ModifierButtons::Constructor
21 // Access: Published
22 // Description:
23 ////////////////////////////////////////////////////////////////////
24 ModifierButtons::
25 ModifierButtons() :
26  _state(0)
27 {
28  _button_list = PTA(ButtonHandle)::empty_array(0);
29 }
30 
31 ////////////////////////////////////////////////////////////////////
32 // Function: ModifierButtons::Copy Constructor
33 // Access: Published
34 // Description:
35 ////////////////////////////////////////////////////////////////////
36 ModifierButtons::
37 ModifierButtons(const ModifierButtons &copy) :
38  _button_list(copy._button_list),
39  _state(copy._state)
40 {
41 }
42 
43 ////////////////////////////////////////////////////////////////////
44 // Function: ModifierButtons::Destructor
45 // Access: Published
46 // Description:
47 ////////////////////////////////////////////////////////////////////
48 ModifierButtons::
49 ~ModifierButtons() {
50 }
51 
52 ////////////////////////////////////////////////////////////////////
53 // Function: ModifierButtons::operator &=
54 // Access: Published
55 // Description: Sets is_down() true for any button that is already
56 // true for this object and the other object.
57 ////////////////////////////////////////////////////////////////////
60  if (_button_list == other._button_list) {
61  // Trivially easy case: if the button lists are the same, we can
62  // do this using a bitmask operation.
63  _state &= other._state;
64 
65  } else {
66  // More complicated case: if the button lists are different, we
67  // have to iterate through the buttons and compare them
68  // case-by-case. This becomes an n^2 operation, but fortunately
69  // there won't be more than a handful of buttons.
70  int num_buttons = get_num_buttons();
71  for (int i = 0; i < num_buttons; i++) {
72  if (is_down(i) && !other.is_down(get_button(i))) {
73  _state &= ~((BitmaskType)1 << i);
74  }
75  }
76  }
77 }
78 
79 ////////////////////////////////////////////////////////////////////
80 // Function: ModifierButtons::operator |=
81 // Access: Published
82 // Description: Sets is_down() true for any button that is already
83 // true for this object and the other object. Adds
84 // whatever buttons are necessary to the list to make
85 // this so
86 ////////////////////////////////////////////////////////////////////
89  if (_button_list == other._button_list) {
90  // Trivially easy case: if the button lists are the same, we can
91  // do this using a bitmask operation.
92  _state |= other._state;
93 
94  } else {
95  // More complicated case: if the button lists are different, we
96  // have to iterate through the buttons and compare them
97  // case-by-case. This becomes an n^2 operation, but fortunately
98  // there won't be more than a handful of buttons.
99  int num_buttons = other.get_num_buttons();
100  for (int i = 0; i < num_buttons; i++) {
101  if (other.is_down(i)) {
102  add_button(other.get_button(i));
103  button_down(other.get_button(i));
104  }
105  }
106  }
107 }
108 
109 ////////////////////////////////////////////////////////////////////
110 // Function: ModifierButtons::set_button_list
111 // Access: Published
112 // Description: Sets the list of buttons to watch to be the same as
113 // that of the other ModifierButtons object. This makes
114 // the lists pointer equivalent (until one or the other
115 // is later modified).
116 //
117 // This will preserve the state of any button that was
118 // on the original list and is also on the new lists.
119 // Any other buttons will get reset to the default state
120 // of "up".
121 ////////////////////////////////////////////////////////////////////
124  if (_button_list != other._button_list) {
125  if (_state != 0) {
126  // If we have some buttons already down, we have to copy them to
127  // the new state.
128  BitmaskType new_state = 0;
129  int num_buttons = other.get_num_buttons();
130  for (int i = 0; i < num_buttons; i++) {
131  if (is_down(other.get_button(i))) {
132  new_state |= ((BitmaskType)1 << i);
133  }
134  }
135 
136  _state = new_state;
137  }
138 
139  _button_list = other._button_list;
140  }
141 }
142 
143 ////////////////////////////////////////////////////////////////////
144 // Function: ModifierButtons::matches
145 // Access: Published
146 // Description: Returns true if the set of buttons indicated as down
147 // by this ModifierButtons object is the same set of
148 // buttons indicated as down by the other
149 // ModifierButtons object. The buttons indicated as up
150 // are not relevant.
151 ////////////////////////////////////////////////////////////////////
153 matches(const ModifierButtons &other) const {
154  if (_button_list == other._button_list) {
155  // If the two objects share the same array, we only need to check
156  // the bitmask. This is a simple optimization.
157  return (_state == other._state);
158  }
159 
160  // The two objects do not share the same array; thus we have to do
161  // this one button at a time. This is an n-squared operation, but
162  // presumably there will not be hundreds of buttons to compare.
163 
164  // First, check that all the buttons indicated as down in our object
165  // are also indicated as down in the other object.
166  int num_down = 0;
167 
168  int i;
169  for (i = 0; i < (int)_button_list.size(); i++) {
170  if (is_down(i)) {
171  if (!other.is_down(_button_list[i])) {
172  return false;
173  }
174  num_down++;
175  }
176  }
177 
178  // Now make sure the total number of buttons indicated as down in
179  // our object matches the number indicated as down in the other
180  // object. This ensures there aren't any additional buttons
181  // indicated down in the other object.
182  int num_other_buttons = other.get_num_buttons();
183  int num_other_down = 0;
184  for (i = 0; i < num_other_buttons; i++) {
185  if (other.is_down(i)) {
186  num_other_down++;
187  }
188  }
189 
190  return (num_down == num_other_down);
191 }
192 
193 ////////////////////////////////////////////////////////////////////
194 // Function: ModifierButtons::add_button
195 // Access: Published
196 // Description: Adds the indicated button to the set of buttons that
197 // will be monitored for upness and downness. Returns
198 // true if the button was added, false if it was already
199 // being monitored or if too many buttons are currently
200 // being monitored.
201 ////////////////////////////////////////////////////////////////////
204  nassertr(button != ButtonHandle::none(), false);
205 
206  static const int max_buttons = sizeof(BitmaskType) * 8;
207 
208  if ((int)_button_list.size() >= max_buttons) {
209  return false;
210  }
211 
212  // First, check to see if the button is already being monitored.
213  if (has_button(button)) {
214  return false;
215  }
216 
217  // Ok, it's not; add it.
218  modify_button_list();
219  _button_list.push_back(button);
220 
221  return true;
222 }
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: ModifierButtons::has_button
226 // Access: Published
227 // Description: Returns true if the indicated button is in the set of
228 // buttons being monitored, false otherwise.
229 ////////////////////////////////////////////////////////////////////
231 has_button(ButtonHandle button) const {
232  PTA(ButtonHandle)::const_iterator bi;
233  for (bi = _button_list.begin(); bi != _button_list.end(); ++bi) {
234  if (button.matches(*bi)) {
235  return true;
236  }
237  }
238 
239  return false;
240 }
241 
242 ////////////////////////////////////////////////////////////////////
243 // Function: ModifierButtons::remove_button
244 // Access: Published
245 // Description: Removes the indicated button from the set of buttons
246 // being monitored. Returns true if the button was
247 // removed, false if it was not being monitored in the
248 // first place.
249 //
250 // Unlike the other methods, you cannot remove a button
251 // by removing its alias; you have to remove exactly the
252 // button itself.
253 ////////////////////////////////////////////////////////////////////
256  // We use i instead of an iterator, because we need to call
257  // modify_button_list() just before we remove the button, and that
258  // may invalidate all of the iterators.
259 
260  for (int i = 0; i < (int)_button_list.size(); i++) {
261  if (button == _button_list[i]) {
262  modify_button_list();
263  _button_list.erase(_button_list.begin() + i);
264 
265  // Now remove the corresponding bit from the bitmask and shift
266  // all the bits above it down.
267  BitmaskType mask = ((BitmaskType)1 << i);
268  BitmaskType below = mask - 1;
269  BitmaskType above = (~below) & (~mask);
270 
271  _state = ((_state & above) >> 1) | (_state & below);
272  return true;
273  }
274  }
275 
276  return false;
277 }
278 
279 ////////////////////////////////////////////////////////////////////
280 // Function: ModifierButtons::button_down
281 // Access: Published
282 // Description: Records that a particular button has been pressed.
283 // If the given button is one of the buttons that is
284 // currently being monitored, this will update the
285 // internal state appropriately; otherwise, it will do
286 // nothing. Returns true if the button is one that was
287 // monitored, or false otherwise.
288 ////////////////////////////////////////////////////////////////////
291  for (int i = 0; i < (int)_button_list.size(); i++) {
292  if (button.matches(_button_list[i])) {
293  _state |= ((BitmaskType)1 << i);
294  return true;
295  }
296  }
297 
298  return false;
299 }
300 
301 ////////////////////////////////////////////////////////////////////
302 // Function: ModifierButtons::button_up
303 // Access: Published
304 // Description: Records that a particular button has been released.
305 // If the given button is one of the buttons that is
306 // currently being monitored, this will update the
307 // internal state appropriately; otherwise, it will do
308 // nothing. Returns true if the button is one that was
309 // monitored, or false otherwise.
310 ////////////////////////////////////////////////////////////////////
313  for (int i = 0; i < (int)_button_list.size(); i++) {
314  if (button.matches(_button_list[i])) {
315  _state &= ~((BitmaskType)1 << i);
316  return true;
317  }
318  }
319 
320  return false;
321 }
322 
323 ////////////////////////////////////////////////////////////////////
324 // Function: ModifierButtons::is_down
325 // Access: Published
326 // Description: Returns true if the indicated button is known to be
327 // down, or false if it is known to be up or if it is
328 // not in the set of buttons being tracked.
329 ////////////////////////////////////////////////////////////////////
331 is_down(ButtonHandle button) const {
332  for (int i = 0; i < (int)_button_list.size(); i++) {
333  if (button.matches(_button_list[i])) {
334  return ((_state & ((BitmaskType)1 << i)) != 0);
335  }
336  }
337 
338  return false;
339 }
340 
341 ////////////////////////////////////////////////////////////////////
342 // Function: ModifierButtons::get_prefix
343 // Access: Published
344 // Description: Returns a string which can be used to prefix any
345 // button name or event name with the unique set of
346 // modifier buttons currently being held.
347 ////////////////////////////////////////////////////////////////////
348 string ModifierButtons::
349 get_prefix() const {
350  string prefix;
351  for (int i = 0; i < (int)_button_list.size(); i++) {
352  if ((_state & ((BitmaskType)1 << i)) != 0) {
353  prefix += _button_list[i].get_name();
354  prefix += '-';
355  }
356  }
357 
358  return prefix;
359 }
360 
361 ////////////////////////////////////////////////////////////////////
362 // Function: ModifierButtons::output
363 // Access: Published
364 // Description: Writes a one-line summary of the buttons known to be
365 // down.
366 ////////////////////////////////////////////////////////////////////
368 output(ostream &out) const {
369  out << "[";
370  for (int i = 0; i < (int)_button_list.size(); i++) {
371  if ((_state & ((BitmaskType)1 << i)) != 0) {
372  out << " " << _button_list[i];
373  }
374  }
375  out << " ]";
376 }
377 
378 ////////////////////////////////////////////////////////////////////
379 // Function: ModifierButtons::write
380 // Access: Published
381 // Description: Writes a multi-line summary including all of the
382 // buttons being monitored and which ones are known to
383 // be down.
384 ////////////////////////////////////////////////////////////////////
386 write(ostream &out) const {
387  out << "ModifierButtons:\n";
388  for (int i = 0; i < (int)_button_list.size(); i++) {
389  out << " " << _button_list[i];
390  if ((_state & ((BitmaskType)1 << i)) != 0) {
391  out << " (down)";
392  }
393  out << "\n";
394  }
395 }
396 
397 ////////////////////////////////////////////////////////////////////
398 // Function: ModifierButtons::modify_button_list
399 // Access: Private
400 // Description: Implements a poor-man's copy-on-write for the
401 // ModifierButtons class. If any reference counts are
402 // held on our _button_list, besides ourselves, then
403 // allocates and copies a brand new copy of the
404 // _button_list. This should be done in preparation for
405 // any modifications to the _button_list, since multiple
406 // instances of the ModifierButtons object may share the
407 // same _button_list pointer.
408 ////////////////////////////////////////////////////////////////////
409 void ModifierButtons::
410 modify_button_list() {
411  if (_button_list.get_ref_count() > 1) {
412  PTA(ButtonHandle) old_list = _button_list;
413 
414  _button_list = PTA(ButtonHandle)::empty_array(0);
415 
416  // This forces a new allocation and memberwise copy, instead of
417  // just a reference-counting pointer copy.
418  _button_list.v() = old_list.v();
419  }
420 
421  // Now we should be the only ones holding a count.
422  nassertv(_button_list.get_ref_count() == 1);
423 }
bool button_down(ButtonHandle button)
Records that a particular button has been pressed.
static ButtonHandle none()
Returns a special zero-valued ButtonHandle that is used to indicate no button.
Definition: buttonHandle.I:205
This class monitors the state of a number of individual buttons and tracks whether each button is kno...
bool remove_button(ButtonHandle button)
Removes the indicated button from the set of buttons being monitored.
bool matches(const ModifierButtons &other) const
Returns true if the set of buttons indicated as down by this ModifierButtons object is the same set o...
ButtonHandle get_button(int index) const
Returns the nth button that the ModifierButtons object is monitoring (the nth button passed to add_bu...
bool button_up(ButtonHandle button)
Records that a particular button has been released.
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:28
void write(ostream &out) const
Writes a multi-line summary including all of the buttons being monitored and which ones are known to ...
bool add_button(ButtonHandle button)
Adds the indicated button to the set of buttons that will be monitored for upness and downness...
void output(ostream &out) const
Writes a one-line summary of the buttons known to be down.
bool matches(const ButtonHandle &other) const
Returns true if this ButtonHandle is the same as the other one, or if the other one is an alias for t...
Definition: buttonHandle.I:166
int get_num_buttons() const
Returns the number of buttons that the ModifierButtons object is monitoring (e.g. ...
void operator&=(const ModifierButtons &other)
Sets is_down() true for any button that is already true for this object and the other object...
string get_prefix() const
Returns a string which can be used to prefix any button name or event name with the unique set of mod...
void set_button_list(const ModifierButtons &other)
Sets the list of buttons to watch to be the same as that of the other ModifierButtons object...
bool has_button(ButtonHandle button) const
Returns true if the indicated button is in the set of buttons being monitored, false otherwise...
bool is_down(ButtonHandle button) const
Returns true if the indicated button is known to be down, or false if it is known to be up or if it i...
void operator|=(const ModifierButtons &other)
Sets is_down() true for any button that is already true for this object and the other object...