define mouseInterfaceNode

This commit is contained in:
David Rose 2004-06-12 02:12:16 +00:00
parent 37ea14ed18
commit 081122fe3b
13 changed files with 441 additions and 60 deletions

View File

@ -66,6 +66,39 @@ operator < (const ModifierButtons &other) const {
return _state < other._state;
}
////////////////////////////////////////////////////////////////////
// Function: ModifierButtons::operator &
// Access: Published
// Description: Returns a new ModifierButtons object for which
// is_down() will be true only if it is true on both
// source objects. The set of buttons reported by
// has_button() is not completely defined if both source
// objects have a different set.
////////////////////////////////////////////////////////////////////
INLINE ModifierButtons ModifierButtons::
operator & (const ModifierButtons &other) const {
ModifierButtons result = *this;
result &= other;
return result;
}
////////////////////////////////////////////////////////////////////
// Function: ModifierButtons::operator |
// Access: Published
// Description: Returns a new ModifierButtons object for which
// is_down() will be true if it is true on either of the
// source objects. The set of buttons reported by
// has_button() is not completely defined if both source
// objects have a different set.
////////////////////////////////////////////////////////////////////
INLINE ModifierButtons ModifierButtons::
operator | (const ModifierButtons &other) const {
ModifierButtons result = *this;
result |= other;
return result;
}
////////////////////////////////////////////////////////////////////
// Function: ModifierButtons::get_num_buttons
// Access: Published

View File

@ -29,7 +29,7 @@ ModifierButtons::
ModifierButtons() :
_state(0)
{
_button_list= PTA(ButtonHandle)::empty_array(0);
_button_list = PTA(ButtonHandle)::empty_array(0);
}
////////////////////////////////////////////////////////////////////
@ -53,6 +53,97 @@ ModifierButtons::
~ModifierButtons() {
}
////////////////////////////////////////////////////////////////////
// Function: ModifierButtons::operator &=
// Access: Published
// Description: Sets is_down() true for any button that is already
// true for this object and the other object.
////////////////////////////////////////////////////////////////////
void ModifierButtons::
operator &= (const ModifierButtons &other) {
if (_button_list == other._button_list) {
// Trivially easy case: if the button lists are the same, we can
// do this using a bitmask operation.
_state &= other._state;
} else {
// More complicated case: if the button lists are different, we
// have to iterate through the buttons and compare them
// case-by-case. This becomes an n^2 operation, but fortunately
// there won't be more than a handful of buttons.
int num_buttons = get_num_buttons();
for (int i = 0; i < num_buttons; i++) {
if (is_down(i) && !other.is_down(get_button(i))) {
_state &= ~((BitmaskType)1 << i);
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: ModifierButtons::operator |=
// Access: Published
// Description: Sets is_down() true for any button that is already
// true for this object and the other object. Adds
// whatever buttons are necessary to the list to make
// this so
////////////////////////////////////////////////////////////////////
void ModifierButtons::
operator |= (const ModifierButtons &other) {
if (_button_list == other._button_list) {
// Trivially easy case: if the button lists are the same, we can
// do this using a bitmask operation.
_state |= other._state;
} else {
// More complicated case: if the button lists are different, we
// have to iterate through the buttons and compare them
// case-by-case. This becomes an n^2 operation, but fortunately
// there won't be more than a handful of buttons.
int num_buttons = other.get_num_buttons();
for (int i = 0; i < num_buttons; i++) {
if (other.is_down(i)) {
add_button(other.get_button(i));
button_down(other.get_button(i));
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: ModifierButtons::set_button_list
// Access: Published
// Description: Sets the list of buttons to watch to be the same as
// that of the other ModifierButtons object. This makes
// the lists pointer equivalent (until one or the other
// is later modified).
//
// This will preserve the state of any button that was
// on the original list and is also on the new lists.
// Any other buttons will get reset to the default state
// of "up".
////////////////////////////////////////////////////////////////////
void ModifierButtons::
set_button_list(const ModifierButtons &other) {
if (_button_list != other._button_list) {
if (_state != 0) {
// If we have some buttons already down, we have to copy them to
// the new state.
BitmaskType new_state = 0;
int num_buttons = other.get_num_buttons();
for (int i = 0; i < num_buttons; i++) {
if (is_down(other.get_button(i))) {
new_state |= ((BitmaskType)1 << i);
}
}
_state = new_state;
}
_button_list = other._button_list;
}
}
////////////////////////////////////////////////////////////////////
// Function: ModifierButtons::matches
// Access: Published

View File

@ -41,6 +41,14 @@ PUBLISHED:
INLINE bool operator != (const ModifierButtons &other) const;
INLINE bool operator < (const ModifierButtons &other) const;
INLINE ModifierButtons operator & (const ModifierButtons &other) const;
INLINE ModifierButtons operator | (const ModifierButtons &other) const;
void operator &= (const ModifierButtons &other);
void operator |= (const ModifierButtons &other);
void set_button_list(const ModifierButtons &other);
bool matches(const ModifierButtons &other) const;
bool add_button(ButtonHandle button);

View File

@ -13,6 +13,7 @@
buttonThrower.I buttonThrower.h \
config_tform.h \
driveInterface.I driveInterface.h \
mouseInterfaceNode.I mouseInterfaceNode.h \
mouseWatcher.I mouseWatcher.h \
mouseWatcherGroup.h \
mouseWatcherParameter.I mouseWatcherParameter.h \
@ -24,6 +25,7 @@
buttonThrower.cxx \
config_tform.cxx \
driveInterface.cxx \
mouseInterfaceNode.cxx \
mouseWatcher.cxx \
mouseWatcherGroup.cxx \
mouseWatcherParameter.cxx mouseWatcherRegion.cxx \
@ -33,6 +35,7 @@
#define INSTALL_HEADERS \
buttonThrower.I buttonThrower.h \
driveInterface.I driveInterface.h \
mouseInterfaceNode.I mouseInterfaceNode.h \
mouseWatcher.I mouseWatcher.h \
mouseWatcherGroup.h \
mouseWatcherParameter.I mouseWatcherParameter.h \

View File

@ -46,6 +46,7 @@ const double drive_horizontal_ramp_down_time = config_tform.GetDouble("drive-hor
ConfigureFn(config_tform) {
DriveInterface::init_type();
ButtonThrower::init_type();
MouseInterfaceNode::init_type();
MouseWatcher::init_type();
MouseWatcherGroup::init_type();
MouseWatcherRegion::init_type();

View File

@ -104,7 +104,7 @@ operator < (const DriveInterface::KeyHeld &other) const {
////////////////////////////////////////////////////////////////////
DriveInterface::
DriveInterface(const string &name) :
DataNode(name)
MouseInterfaceNode(name)
{
_xy_input = define_input("xy", EventStoreVec2::get_class_type());
_button_events_input = define_input("button_events", ButtonEventList::get_class_type());
@ -138,9 +138,7 @@ DriveInterface(const string &name) :
_force_mouse = false;
_stop_this_frame = false;
_mods.add_button(MouseButton::one());
_mods.add_button(MouseButton::two());
_mods.add_button(MouseButton::three());
watch_button(MouseButton::one());
}
@ -168,8 +166,6 @@ reset() {
_down_arrow.clear();
_left_arrow.clear();
_right_arrow.clear();
_mods.all_buttons_up();
}
@ -398,13 +394,17 @@ apply(double x, double y, bool any_button) {
////////////////////////////////////////////////////////////////////
void DriveInterface::
do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
// First, update our modifier buttons.
bool required_buttons_match;
const ButtonEventList *button_events = check_button_events(input, required_buttons_match);
// Look for mouse activity.
double x = 0.0f;
double y = 0.0f;
bool got_mouse = false;
if (input.has_data(_xy_input)) {
if (required_buttons_match && input.has_data(_xy_input)) {
const EventStoreVec2 *xy;
DCAST_INTO_V(xy, input.get_data(_xy_input).get_ptr());
const LVecBase2f &p = xy->get_value();
@ -415,28 +415,13 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
}
// Look for keyboard events.
if (input.has_data(_button_events_input)) {
const ButtonEventList *button_events;
DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
if (required_buttons_match && button_events != (const ButtonEventList *)NULL) {
int num_events = button_events->get_num_events();
for (int i = 0; i < num_events; i++) {
const ButtonEvent &be = button_events->get_event(i);
if (be._type != ButtonEvent::T_keystroke) {
bool down = (be._type == ButtonEvent::T_down);
if (down) {
// We only trap button down events if (a) the mouse is in the
// window, and (b) we aren't set to ignore the mouse.
if (got_mouse && !_ignore_mouse) {
be.update_mods(_mods);
}
} else {
// However, we always trap button up events, so we don't get
// confused and believe a button is still being held down when
// it is not.
be.update_mods(_mods);
}
if (be._button == KeyboardButton::up()) {
_up_arrow.set_key(down);
@ -451,7 +436,7 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
}
}
apply(x, y, _mods.is_any_down());
apply(x, y, !_ignore_mouse && is_down(MouseButton::one()));
_transform = TransformState::make_pos_hpr(_xyz, _hpr);
_velocity->set_value(_vel);
output.set_data(_transform_output, EventParameter(_transform));

View File

@ -21,7 +21,7 @@
#include "pandabase.h"
#include "dataNode.h"
#include "mouseInterfaceNode.h"
#include "modifierButtons.h"
#include "luse.h"
#include "linmath_events.h"
@ -35,7 +35,7 @@
// The basic motion is on a horizontal plane, as if
// driving a vehicle.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA DriveInterface : public DataNode {
class EXPCL_PANDA DriveInterface : public MouseInterfaceNode {
PUBLISHED:
DriveInterface(const string &name = "");
~DriveInterface();
@ -136,9 +136,6 @@ private:
// This is only used to return a temporary value in get_mat().
LMatrix4f _mat;
// Remember which mouse buttons are being held down.
ModifierButtons _mods;
// Remember which arrow keys are being held down and which aren't,
// and at what point they last changed state.
class KeyHeld {
@ -187,9 +184,9 @@ public:
return _type_handle;
}
static void init_type() {
DataNode::init_type();
MouseInterfaceNode::init_type();
register_type(_type_handle, "DriveInterface",
DataNode::get_class_type());
MouseInterfaceNode::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -0,0 +1,30 @@
// Filename: mouseInterfaceNode.I
// Created by: drose (11Jun04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: MouseInterfaceNode::is_down
// Access: Protected
// Description: Returns true if the indicated button (which must have
// been specified in a previous call to watch_button())
// is known to be held down, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool MouseInterfaceNode::
is_down(ButtonHandle button) const {
return _current_button_state.is_down(button);
}

View File

@ -0,0 +1,155 @@
// Filename: mouseInterfaceNode.cxx
// Created by: drose (11Jun04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "trackball.h"
#include "buttonEvent.h"
#include "buttonEventList.h"
#include "dataNodeTransmit.h"
#include "mouseData.h"
TypeHandle MouseInterfaceNode::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: MouseInterfaceNode::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
MouseInterfaceNode::
MouseInterfaceNode(const string &name) :
DataNode(name)
{
_button_events_input = define_input("button_events", ButtonEventList::get_class_type());
}
////////////////////////////////////////////////////////////////////
// Function: MouseInterfaceNode::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
MouseInterfaceNode::
~MouseInterfaceNode() {
}
////////////////////////////////////////////////////////////////////
// Function: MouseInterfaceNode::require_button
// Access: Published
// Description: Indicates that the indicated button must be in the
// required state (either up or down) in order for this
// particular MouseInterfaceNode to do anything. For
// instance, this may be called to make a Trackball
// object respect mouse input only when the control key
// is held down.
////////////////////////////////////////////////////////////////////
void MouseInterfaceNode::
require_button(const ButtonHandle &button, bool is_down) {
_required_buttons_mask.add_button(button);
_required_buttons_state.set_button_list(_required_buttons_mask);
_current_button_state.set_button_list(_required_buttons_mask);
_required_buttons_mask.button_down(button);
if (is_down) {
_required_buttons_state.button_down(button);
} else {
_required_buttons_state.button_up(button);
}
}
////////////////////////////////////////////////////////////////////
// Function: MouseInterfaceNode::clear_button
// Access: Published
// Description: Removes any requirement on the indicated button set
// by an earlier call to require_button().
////////////////////////////////////////////////////////////////////
void MouseInterfaceNode::
clear_button(const ButtonHandle &button) {
_required_buttons_mask.button_up(button);
_required_buttons_state.button_up(button);
// The _required_buttons_mask and state must always keep the buttons
// that are listed in _watched_buttons.
if (!_watched_buttons.has_button(button)) {
_required_buttons_mask.remove_button(button);
_required_buttons_state.set_button_list(_required_buttons_mask);
_current_button_state.set_button_list(_required_buttons_mask);
}
}
////////////////////////////////////////////////////////////////////
// Function: MouseInterfaceNode::clear_all_button
// Access: Published
// Description: Removes all requirements on buttons set by an earlier
// call to require_button().
////////////////////////////////////////////////////////////////////
void MouseInterfaceNode::
clear_all_buttons() {
_required_buttons_mask.all_buttons_up();
_required_buttons_state.all_buttons_up();
_required_buttons_mask.set_button_list(_watched_buttons);
_required_buttons_state.set_button_list(_watched_buttons);
_current_button_state.set_button_list(_watched_buttons);
}
////////////////////////////////////////////////////////////////////
// Function: MouseInterfaceNode::watch_button
// Access: Protected
// Description: Indicates that the derived class would like to know
// the state of the given button.
////////////////////////////////////////////////////////////////////
void MouseInterfaceNode::
watch_button(const ButtonHandle &button) {
_watched_buttons.add_button(button);
// We also add the button to _required_buttons_mask and
// _required_buttons_state, but it's left 'up' in these two.
_required_buttons_mask.add_button(button);
_required_buttons_state.set_button_list(_required_buttons_mask);
_current_button_state.set_button_list(_required_buttons_mask);
}
////////////////////////////////////////////////////////////////////
// Function: MouseInterfaceNode::check_button_events
// Access: Protected
// Description: Gets the button events from the data graph and
// updates the ModifierButtons objects appropriately.
//
// Sets required_buttons_match to true if the required
// combination of buttons are being held down, or false
// otherwise.
//
// The return value is the list of button events
// processed this frame, or NULL if there are no button
// events.
////////////////////////////////////////////////////////////////////
const ButtonEventList *MouseInterfaceNode::
check_button_events(const DataNodeTransmit &input,
bool &required_buttons_match) {
const ButtonEventList *button_events = NULL;
if (input.has_data(_button_events_input)) {
DCAST_INTO_R(button_events, input.get_data(_button_events_input).get_ptr(), false);
button_events->update_mods(_current_button_state);
}
required_buttons_match =
(_current_button_state & _required_buttons_mask) == _required_buttons_state;
return button_events;
}

View File

@ -0,0 +1,84 @@
// Filename: mouseInterfaceNode.h
// Created by: drose (11Jun04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef MOUSEINTERFACENODE_H
#define MOUSEINTERFACENODE_H
#include "pandabase.h"
#include "dataNode.h"
#include "modifierButtons.h"
class ButtonEventList;
////////////////////////////////////////////////////////////////////
// Class : MouseInterfaceNode
// Description : This is the base class for some classes that monitor
// the mouse and keyboard input and perform some action
// due to their state.
//
// It collects together some common interface; in
// particular, the require_button() and related methods.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA MouseInterfaceNode : public DataNode {
public:
MouseInterfaceNode(const string &name);
virtual ~MouseInterfaceNode();
PUBLISHED:
void require_button(const ButtonHandle &button, bool is_down);
void clear_button(const ButtonHandle &button);
void clear_all_buttons();
protected:
void watch_button(const ButtonHandle &button);
const ButtonEventList *check_button_events(const DataNodeTransmit &input,
bool &required_buttons_match);
INLINE bool is_down(ButtonHandle button) const;
private:
ModifierButtons _current_button_state;
ModifierButtons _watched_buttons;
ModifierButtons _required_buttons_mask;
ModifierButtons _required_buttons_state;
private:
int _button_events_input;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
DataNode::init_type();
register_type(_type_handle, "MouseInterfaceNode",
DataNode::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "mouseInterfaceNode.I"
#endif

View File

@ -1,4 +1,6 @@
#include "buttonThrower.cxx"
#include "config_tform.cxx"
#include "driveInterface.cxx"
#include "mouseInterfaceNode.cxx"

View File

@ -38,10 +38,9 @@ TypeHandle Trackball::_type_handle;
////////////////////////////////////////////////////////////////////
Trackball::
Trackball(const string &name) :
DataNode(name)
MouseInterfaceNode(name)
{
_pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type());
_button_events_input = define_input("button_events", ButtonEventList::get_class_type());
_transform_output = define_output("transform", TransformState::get_class_type());
@ -59,9 +58,10 @@ Trackball(const string &name) :
_invert = true;
_cs = default_coordinate_system;
_mods.add_button(MouseButton::one());
_mods.add_button(MouseButton::two());
_mods.add_button(MouseButton::three());
// We want to track the state of these buttons.
watch_button(MouseButton::one());
watch_button(MouseButton::two());
watch_button(MouseButton::three());
}
////////////////////////////////////////////////////////////////////
@ -535,36 +535,33 @@ recompute() {
void Trackball::
do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
// First, update our modifier buttons.
if (input.has_data(_button_events_input)) {
const ButtonEventList *button_events;
DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
button_events->update_mods(_mods);
}
bool required_buttons_match;
check_button_events(input, required_buttons_match);
// Now, check for mouse motion.
if (input.has_data(_pixel_xy_input)) {
if (required_buttons_match && input.has_data(_pixel_xy_input)) {
const EventStoreVec2 *pixel_xy;
DCAST_INTO_V(pixel_xy, input.get_data(_pixel_xy_input).get_ptr());
const LVecBase2f &p = pixel_xy->get_value();
float this_x = p[0];
float this_y = p[1];
int this_button = 0;
if (_mods.is_down(MouseButton::one())) {
if (is_down(MouseButton::one())) {
this_button |= B1_MASK;
}
if (_mods.is_down(MouseButton::two())) {
if (is_down(MouseButton::two())) {
this_button |= B2_MASK;
}
if (_mods.is_down(MouseButton::three())) {
if (is_down(MouseButton::three())) {
this_button |= B3_MASK;
}
float x = this_x - _lastx;
float y = this_y - _lasty;
apply(x, y, this_button);
_lastx = this_x;
_lasty = this_y;
}

View File

@ -21,7 +21,7 @@
#include "pandabase.h"
#include "dataNode.h"
#include "mouseInterfaceNode.h"
#include "nodePath.h"
#include "modifierButtons.h"
#include "luse.h"
@ -41,7 +41,7 @@
// it to actually transform objects (or cameras) in the
// world.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Trackball : public DataNode {
class EXPCL_PANDA Trackball : public MouseInterfaceNode {
PUBLISHED:
Trackball(const string &name);
~Trackball();
@ -88,7 +88,7 @@ PUBLISHED:
void set_invert(bool flag);
bool get_invert() const;
void set_rel_to(const NodePath &_rel_to);
void set_rel_to(const NodePath &rel_to);
const NodePath &get_rel_to() const;
void set_coordinate_system(CoordinateSystem cs);
@ -118,10 +118,6 @@ private:
NodePath _rel_to;
CoordinateSystem _cs;
// Remember which mouse buttons are being held down.
ModifierButtons _mods;
protected:
// Inherited from DataNode
virtual void do_transmit_data(const DataNodeTransmit &input,
@ -130,7 +126,6 @@ protected:
private:
// inputs
int _pixel_xy_input;
int _button_events_input;
// outputs
int _transform_output;
@ -142,9 +137,9 @@ public:
return _type_handle;
}
static void init_type() {
DataNode::init_type();
MouseInterfaceNode::init_type();
register_type(_type_handle, "Trackball",
DataNode::get_class_type());
MouseInterfaceNode::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();