333 lines
11 KiB
C++
333 lines
11 KiB
C++
// Filename: modifierButtons.cxx
|
|
// Created by: drose (01Mar00)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://www.panda3d.org/license.txt .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d@yahoogroups.com .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "modifierButtons.h"
|
|
|
|
#include <notify.h>
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::Constructor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
ModifierButtons::
|
|
ModifierButtons() :
|
|
_state(0)
|
|
{
|
|
_button_list= PTA(ButtonHandle)::empty_array(0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::Copy Constructor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
ModifierButtons::
|
|
ModifierButtons(const ModifierButtons ©) :
|
|
_button_list(copy._button_list),
|
|
_state(copy._state)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::Destructor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
ModifierButtons::
|
|
~ModifierButtons() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::matches
|
|
// Access: Published
|
|
// Description: Returns true if the set of buttons indicated as down
|
|
// by this ModifierButtons object is the same set of
|
|
// buttons indicated as down by the other
|
|
// ModifierButtons object. The buttons indicated as up
|
|
// are not relevant.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool ModifierButtons::
|
|
matches(const ModifierButtons &other) const {
|
|
if (_button_list == other._button_list) {
|
|
// If the two objects share the same array, we only need to check
|
|
// the bitmask. This is a simple optimization.
|
|
return (_state == other._state);
|
|
}
|
|
|
|
// The two objects do not share the same array; thus we have to do
|
|
// this one button at a time. This is an n-squared operation, but
|
|
// presumably there will not be hundreds of buttons to compare.
|
|
|
|
// First, check that all the buttons indicated as down in our object
|
|
// are also indicated as down in the other object.
|
|
int num_down = 0;
|
|
|
|
int i;
|
|
for (i = 0; i < (int)_button_list.size(); i++) {
|
|
if (is_down(i)) {
|
|
if (!other.is_down(_button_list[i])) {
|
|
return false;
|
|
}
|
|
num_down++;
|
|
}
|
|
}
|
|
|
|
// Now make sure the total number of buttons indicated as down in
|
|
// our object matches the number indicated as down in the other
|
|
// object. This ensures there aren't any additional buttons
|
|
// indicated down in the other object.
|
|
int num_other_buttons = other.get_num_buttons();
|
|
int num_other_down = 0;
|
|
for (i = 0; i < num_other_buttons; i++) {
|
|
if (other.is_down(i)) {
|
|
num_other_down++;
|
|
}
|
|
}
|
|
|
|
return (num_down == num_other_down);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::add_button
|
|
// Access: Published
|
|
// Description: Adds the indicated button to the set of buttons that
|
|
// will be monitored for upness and downness. Returns
|
|
// true if the button was added, false if it was already
|
|
// being monitored or if too many buttons are currently
|
|
// being monitored.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool ModifierButtons::
|
|
add_button(ButtonHandle button) {
|
|
nassertr(button != ButtonHandle::none(), false);
|
|
|
|
static const int max_buttons = sizeof(BitmaskType) * 8;
|
|
|
|
if ((int)_button_list.size() >= max_buttons) {
|
|
return false;
|
|
}
|
|
|
|
// First, check to see if the button is already being monitored.
|
|
if (has_button(button)) {
|
|
return false;
|
|
}
|
|
|
|
// Ok, it's not; add it.
|
|
modify_button_list();
|
|
_button_list.push_back(button);
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::has_button
|
|
// Access: Published
|
|
// Description: Returns true if the indicated button is in the set of
|
|
// buttons being monitored, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool ModifierButtons::
|
|
has_button(ButtonHandle button) const {
|
|
PTA(ButtonHandle)::const_iterator bi;
|
|
for (bi = _button_list.begin(); bi != _button_list.end(); ++bi) {
|
|
if (button == (*bi)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::remove_button
|
|
// Access: Published
|
|
// Description: Removes the indicated button from the set of buttons
|
|
// being monitored. Returns true if the button was
|
|
// removed, false if it was not being monitored in the
|
|
// first place.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool ModifierButtons::
|
|
remove_button(ButtonHandle button) {
|
|
// We use i instead of an iterator, because we need to call
|
|
// modify_button_list() just before we remove the button, and that
|
|
// may invalidate all of the iterators.
|
|
|
|
for (int i = 0; i < (int)_button_list.size(); i++) {
|
|
if (button == _button_list[i]) {
|
|
modify_button_list();
|
|
_button_list.erase(_button_list.begin() + i);
|
|
|
|
// Now remove the corresponding bit from the bitmask and shift
|
|
// all the bits above it down.
|
|
BitmaskType mask = ((BitmaskType)1 << i);
|
|
BitmaskType below = mask - 1;
|
|
BitmaskType above = (~below) & (~mask);
|
|
|
|
_state = ((_state & above) >> 1) | (_state & below);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::button_down
|
|
// Access: Published
|
|
// Description: Records that a particular button has been pressed.
|
|
// If the given button is one of the buttons that is
|
|
// currently being monitored, this will update the
|
|
// internal state appropriately; otherwise, it will do
|
|
// nothing. Returns true if the button is one that was
|
|
// monitored, or false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool ModifierButtons::
|
|
button_down(ButtonHandle button) {
|
|
for (int i = 0; i < (int)_button_list.size(); i++) {
|
|
if (button == _button_list[i]) {
|
|
_state |= ((BitmaskType)1 << i);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::button_up
|
|
// Access: Published
|
|
// Description: Records that a particular button has been released.
|
|
// If the given button is one of the buttons that is
|
|
// currently being monitored, this will update the
|
|
// internal state appropriately; otherwise, it will do
|
|
// nothing. Returns true if the button is one that was
|
|
// monitored, or false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool ModifierButtons::
|
|
button_up(ButtonHandle button) {
|
|
for (int i = 0; i < (int)_button_list.size(); i++) {
|
|
if (button == _button_list[i]) {
|
|
_state &= ~((BitmaskType)1 << i);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::is_down
|
|
// Access: Published
|
|
// Description: Returns true if the indicated button is known to be
|
|
// down, or false if it is known to be up or if it is
|
|
// not in the set of buttons being tracked.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool ModifierButtons::
|
|
is_down(ButtonHandle button) const {
|
|
for (int i = 0; i < (int)_button_list.size(); i++) {
|
|
if (button == _button_list[i]) {
|
|
return ((_state & ((BitmaskType)1 << i)) != 0);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::get_prefix
|
|
// Access: Published
|
|
// Description: Returns a string which can be used to prefix any
|
|
// button name or event name with the unique set of
|
|
// modifier buttons currently being held.
|
|
////////////////////////////////////////////////////////////////////
|
|
string ModifierButtons::
|
|
get_prefix() const {
|
|
string prefix;
|
|
for (int i = 0; i < (int)_button_list.size(); i++) {
|
|
if ((_state & ((BitmaskType)1 << i)) != 0) {
|
|
prefix += _button_list[i].get_name();
|
|
prefix += '-';
|
|
}
|
|
}
|
|
|
|
return prefix;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::output
|
|
// Access: Published
|
|
// Description: Writes a one-line summary of the buttons known to be
|
|
// down.
|
|
////////////////////////////////////////////////////////////////////
|
|
void ModifierButtons::
|
|
output(ostream &out) const {
|
|
out << "[";
|
|
for (int i = 0; i < (int)_button_list.size(); i++) {
|
|
if ((_state & ((BitmaskType)1 << i)) != 0) {
|
|
out << " " << _button_list[i];
|
|
}
|
|
}
|
|
out << " ]";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::write
|
|
// Access: Published
|
|
// Description: Writes a multi-line summary including all of the
|
|
// buttons being monitored and which ones are known to
|
|
// be down.
|
|
////////////////////////////////////////////////////////////////////
|
|
void ModifierButtons::
|
|
write(ostream &out) const {
|
|
out << "ModifierButtons:\n";
|
|
for (int i = 0; i < (int)_button_list.size(); i++) {
|
|
out << " " << _button_list[i];
|
|
if ((_state & ((BitmaskType)1 << i)) != 0) {
|
|
out << " (down)";
|
|
}
|
|
out << "\n";
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: ModifierButtons::modify_button_list
|
|
// Access: Private
|
|
// Description: Implements a poor-man's copy-on-write for the
|
|
// ModifierButtons class. If any reference counts are
|
|
// held on our _button_list, besides ourselves, then
|
|
// allocates and copies a brand new copy of the
|
|
// _button_list. This should be done in preparation for
|
|
// any modifications to the _button_list, since multiple
|
|
// instances of the ModifierButtons object may share the
|
|
// same _button_list pointer.
|
|
////////////////////////////////////////////////////////////////////
|
|
void ModifierButtons::
|
|
modify_button_list() {
|
|
if (_button_list.get_ref_count() > 1) {
|
|
PTA(ButtonHandle) old_list = _button_list;
|
|
|
|
_button_list = PTA(ButtonHandle)::empty_array(0);
|
|
|
|
// This forces a new allocation and memberwise copy, instead of
|
|
// just a reference-counting pointer copy.
|
|
_button_list.v() = old_list.v();
|
|
}
|
|
|
|
// Now we should be the only ones holding a count.
|
|
nassertv(_button_list.get_ref_count() == 1);
|
|
}
|