Browse Source

pgui enhancements

David Rose 24 years ago
parent
commit
3bc425127e

+ 3 - 3
panda/src/pgui/Sources.pp

@@ -12,7 +12,7 @@
   #define SOURCES  \
     config_pgui.h \
     pgButton.I pgButton.h \
-    pgButtonEvent.I pgButtonEvent.h \
+    pgMouseWatcherParameter.I pgMouseWatcherParameter.h \
     pgFrameStyle.I pgFrameStyle.h \
     pgItem.I pgItem.h \
     pgMouseWatcherRegion.I pgMouseWatcherRegion.h \
@@ -22,7 +22,7 @@
   #define SOURCES $[SOURCES] \
     config_pgui.cxx \
     pgButton.cxx \
-    pgButtonEvent.cxx \
+    pgMouseWatcherParameter.cxx \
     pgFrameStyle.cxx \
     pgItem.cxx \
     pgMouseWatcherRegion.cxx \
@@ -30,7 +30,7 @@
 
   #define INSTALL_HEADERS \
     pgButton.I pgButton.h \
-    pgButtonEvent.I pgButtonEvent.h \
+    pgMouseWatcherParameter.I pgMouseWatcherParameter.h \
     pgFrameStyle.I pgFrameStyle.h \
     pgItem.I pgItem.h \
     pgMouseWatcherRegion.I pgMouseWatcherRegion.h \

+ 2 - 2
panda/src/pgui/config_pgui.cxx

@@ -18,7 +18,7 @@
 
 #include "config_pgui.h"
 #include "pgButton.h"
-#include "pgButtonEvent.h"
+#include "pgMouseWatcherParameter.h"
 #include "pgItem.h"
 #include "pgMouseWatcherRegion.h"
 #include "pgTop.h"
@@ -30,7 +30,7 @@ NotifyCategoryDef(pgui, "");
 
 ConfigureFn(config_pgui) {
   PGButton::init_type();
-  PGButtonEvent::init_type();
+  PGMouseWatcherParameter::init_type();
   PGItem::init_type();
   PGMouseWatcherRegion::init_type();
   PGTop::init_type();

+ 2 - 2
panda/src/pgui/pgButton.I

@@ -73,6 +73,6 @@ set_active(bool active) {
 //               button is clicked normally.
 ////////////////////////////////////////////////////////////////////
 INLINE string PGButton::
-get_click_event() const {
-  return "click-" + get_id();
+get_click_event(const ButtonHandle &button) const {
+  return "click-" + button.get_name() + "-" + get_id();
 }

+ 65 - 24
panda/src/pgui/pgButton.cxx

@@ -17,11 +17,14 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "pgButton.h"
+#include "pgMouseWatcherParameter.h"
+
 #include "throw_event.h"
 #include "renderRelation.h"
 #include "colorTransition.h"
 #include "transformTransition.h"
 #include "mouseButton.h"
+#include "mouseWatcherParameter.h"
 
 TypeHandle PGButton::_type_handle;
 
@@ -34,6 +37,7 @@ PGButton::
 PGButton(const string &name) : PGItem(name)
 {
   _button_down = false;
+  _click_buttons.insert(MouseButton::one());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -87,11 +91,11 @@ make_copy() const {
 //               mouse enters the region.
 ////////////////////////////////////////////////////////////////////
 void PGButton::
-enter() {
+enter(const MouseWatcherParameter &param) {
   if (get_active()) {
     set_state(_button_down ? S_depressed : S_rollover);
   }
-  PGItem::enter();
+  PGItem::enter(param);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -101,70 +105,68 @@ enter() {
 //               mouse exits the region.
 ////////////////////////////////////////////////////////////////////
 void PGButton::
-exit() {
+exit(const MouseWatcherParameter &param) {
   if (get_active()) {
     set_state(S_ready);
   }
-  PGItem::exit();
+  PGItem::exit(param);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGButton::button_down
+//     Function: PGButton::press
 //       Access: Public, Virtual
 //  Description: This is a callback hook function, called whenever a
 //               mouse or keyboard button is depressed while the mouse
 //               is within the region.
 ////////////////////////////////////////////////////////////////////
 void PGButton::
-button_down(ButtonHandle button, float x, float y) {
-  if (button == MouseButton::one() ||
-      button == MouseButton::two() ||
-      button == MouseButton::three()) {
+press(const MouseWatcherParameter &param) {
+  if (has_click_button(param.get_button())) {
     if (get_active()) {
       _button_down = true;
       set_state(S_depressed);
     }
   }
-  PGItem::button_down(button, x, y);
+  PGItem::press(param);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGButton::button_up
+//     Function: PGButton::release
 //       Access: Public, Virtual
 //  Description: This is a callback hook function, called whenever a
 //               mouse or keyboard button previously depressed with
-//               button_down() is release.  The bool is_within flag is
+//               press() is release.  The bool is_within flag is
 //               true if the button was released while the mouse was
 //               still within the region, or false if it was released
 //               outside the region.
 ////////////////////////////////////////////////////////////////////
 void PGButton::
-button_up(ButtonHandle button, float x, float y, bool is_within) {
-  if (button == MouseButton::one() ||
-      button == MouseButton::two() ||
-      button == MouseButton::three()) {
+release(const MouseWatcherParameter &param) {
+  if (has_click_button(param.get_button())) {
     _button_down = false;
     if (get_active()) {
-      if (is_within) {
-        set_state(S_rollover);
-        click();
-      } else {
+      if (param.is_outside()) {
         set_state(S_ready);
+      } else {
+        set_state(S_rollover);
+        click(param);
       }
     }
   }
-  PGItem::button_up(button, x, y, is_within);
+  PGItem::release(param);
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: PGButton::click
 //       Access: Public, Virtual
 //  Description: This is a callback hook function, called whenever the
-//               button is clicked normally.
+//               button is clicked down-and-up by the user normally.
 ////////////////////////////////////////////////////////////////////
 void PGButton::
-click() {
-  throw_event(get_click_event());
+click(const MouseWatcherParameter &param) {
+  PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
+  throw_event(get_click_event(param.get_button()), 
+              EventParameter(ep));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -237,3 +239,42 @@ setup(const ArcChain &ready, const ArcChain &depressed,
   instance_to_state_def(S_rollover, rollover);
   instance_to_state_def(S_inactive, inactive);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::add_click_button
+//       Access: Published
+//  Description: Adds the indicated button to the set of buttons that
+//               can effectively "click" the PGButton.  Normally, this
+//               is just MouseButton::one().  Returns true if the
+//               button was added, or false if it was already there.
+////////////////////////////////////////////////////////////////////
+bool PGButton::
+add_click_button(const ButtonHandle &button) {
+  return _click_buttons.insert(button).second;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::remove_click_button
+//       Access: Published
+//  Description: Removes the indicated button from the set of buttons
+//               that can effectively "click" the PGButton.  Normally,
+//               this is just MouseButton::one().  Returns true if the
+//               button was removed, or false if it was not in the
+//               set.
+////////////////////////////////////////////////////////////////////
+bool PGButton::
+remove_click_button(const ButtonHandle &button) {
+  return (_click_buttons.erase(button) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::has_click_button
+//       Access: Published
+//  Description: Returns true if the indicated button is on the set of
+//               buttons that can effectively "click" the PGButton.
+//               Normally, this is just MouseButton::one().
+////////////////////////////////////////////////////////////////////
+bool PGButton::
+has_click_button(const ButtonHandle &button) {
+  return (_click_buttons.count(button) != 0);
+}

+ 14 - 6
panda/src/pgui/pgButton.h

@@ -23,6 +23,7 @@
 
 #include "pgItem.h"
 #include "arcChain.h"
+#include "pset.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : PGButton
@@ -42,12 +43,12 @@ public:
 
   virtual Node *make_copy() const;
 
-  virtual void enter();
-  virtual void exit();
-  virtual void button_down(ButtonHandle button, float x, float y);
-  virtual void button_up(ButtonHandle button, float x, float y, bool is_within);
+  virtual void enter(const MouseWatcherParameter &param);
+  virtual void exit(const MouseWatcherParameter &param);
+  virtual void press(const MouseWatcherParameter &param);
+  virtual void release(const MouseWatcherParameter &param);
 
-  virtual void click();
+  virtual void click(const MouseWatcherParameter &param);
 
 PUBLISHED:
   enum State {
@@ -67,9 +68,16 @@ PUBLISHED:
 
   INLINE void set_active(bool active);
 
-  INLINE string get_click_event() const;
+  bool add_click_button(const ButtonHandle &button);
+  bool remove_click_button(const ButtonHandle &button);
+  bool has_click_button(const ButtonHandle &button);
+
+  INLINE string get_click_event(const ButtonHandle &button) const;
 
 private:
+  typedef pset<ButtonHandle> Buttons;
+  Buttons _click_buttons;
+
   bool _button_down;
 
 public:

+ 0 - 94
panda/src/pgui/pgButtonEvent.I

@@ -1,94 +0,0 @@
-// Filename: pgButtonEvent.I
-// Created by:  drose (05Jul01)
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: PGButtonEvent::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE PGButtonEvent::
-PGButtonEvent() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PGButtonEvent::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE PGButtonEvent::
-PGButtonEvent(ButtonHandle button, float mouse_x, float mouse_y) :
-  _button(button),
-  _mouse_x(mouse_x),
-  _mouse_y(mouse_y)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PGButtonEvent::get_button
-//       Access: Published
-//  Description: Returns the ButtonHandle of the button involved with
-//               this event.
-////////////////////////////////////////////////////////////////////
-INLINE ButtonHandle PGButtonEvent::
-get_button() const {
-  return _button;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PGButtonEvent::get_button_name
-//       Access: Published
-//  Description: Returns the name of the button involved with this
-//               event.  This is just a shorthand way to get to the
-//               name, since get_button().get_name() will return the
-//               same thing.
-////////////////////////////////////////////////////////////////////
-INLINE string PGButtonEvent::
-get_button_name() const {
-  return _button.get_name();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PGButtonEvent::get_mouse_x
-//       Access: Published
-//  Description: Returns the X position of the mouse within the window
-//               at the time the button event occurred.  This is in
-//               the normalized range [-1 .. 1].
-////////////////////////////////////////////////////////////////////
-INLINE float PGButtonEvent::
-get_mouse_x() const {
-  return _mouse_x;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PGButtonEvent::get_mouse_y
-//       Access: Published
-//  Description: Returns the Y position of the mouse within the window
-//               at the time the button event occurred.  This is in
-//               the normalized range [-1 .. 1].
-////////////////////////////////////////////////////////////////////
-INLINE float PGButtonEvent::
-get_mouse_y() const {
-  return _mouse_y;
-}
-
-INLINE ostream &
-operator << (ostream &out, const PGButtonEvent &event) {
-  event.output(out);
-  return out;
-}

+ 11 - 21
panda/src/pgui/pgItem.I

@@ -186,39 +186,29 @@ get_exit_event() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGItem::get_button_down_event
+//     Function: PGItem::get_press_event
 //       Access: Published
 //  Description: Returns the event name that will be thrown when the
-//               item is active and a mouse or keyboard button is
-//               depressed while the mouse is within the frame.
-//
-//               This event will be thrown with one parameter, which
-//               will be the PGButtonEvent for the button that
-//               generated the event.
+//               item is active and the indicated mouse or keyboard
+//               button is depressed while the mouse is within the
+//               frame.
 ////////////////////////////////////////////////////////////////////
 INLINE string PGItem::
-get_button_down_event() const {
-  return "bdown-" + get_id();
+get_press_event(const ButtonHandle &button) const {
+  return "press-" + button.get_name() + "-" + get_id();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGItem::get_button_up_event
+//     Function: PGItem::get_release_event
 //       Access: Published
 //  Description: Returns the event name that will be thrown when the
-//               item is active and a mouse or keyboard button,
-//               formerly clicked down is within the frame, is
-//               released.
-//
-//               This event will be thrown with two parameters, the
-//               first of which will be the PGButtonEvent for the
-//               button that generated the event, and the second of
-//               which will be a boolean flag indicating true if the
-//               mouse was within the frame while the button was
+//               item is active and the indicated mouse or keyboard
+//               button, formerly clicked down is within the frame, is
 //               released.
 ////////////////////////////////////////////////////////////////////
 INLINE string PGItem::
-get_button_up_event() const {
-  return "bup-" + get_id();
+get_release_event(const ButtonHandle &button) const {
+  return "release-" + button.get_name() + "-" + get_id();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 20 - 20
panda/src/pgui/pgItem.cxx

@@ -17,7 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "pgItem.h"
-#include "pgButtonEvent.h"
+#include "pgMouseWatcherParameter.h"
 
 #include "namedNode.h"
 #include "throw_event.h"
@@ -174,8 +174,10 @@ activate_region(const LMatrix4f &transform, int sort) {
 //               mouse enters the region.
 ////////////////////////////////////////////////////////////////////
 void PGItem::
-enter() {
-  throw_event(get_enter_event());
+enter(const MouseWatcherParameter &param) {
+  PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
+  throw_event(get_enter_event(),
+              EventParameter(ep));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -185,40 +187,38 @@ enter() {
 //               mouse exits the region.
 ////////////////////////////////////////////////////////////////////
 void PGItem::
-exit() {
-  throw_event(get_exit_event());
+exit(const MouseWatcherParameter &param) {
+  PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
+  throw_event(get_exit_event(),
+              EventParameter(ep));
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGItem::button_down
+//     Function: PGItem::press
 //       Access: Public, Virtual
 //  Description: This is a callback hook function, called whenever a
 //               mouse or keyboard button is depressed while the mouse
 //               is within the region.
 ////////////////////////////////////////////////////////////////////
 void PGItem::
-button_down(ButtonHandle button, float x, float y) {
-  PGButtonEvent *be = new PGButtonEvent(button, x, y);
-  throw_event(get_button_down_event(), 
-              EventParameter(be));
+press(const MouseWatcherParameter &param) {
+  PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
+  throw_event(get_press_event(param.get_button()), 
+              EventParameter(ep));
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGItem::button_up
+//     Function: PGItem::release
 //       Access: Public, Virtual
 //  Description: This is a callback hook function, called whenever a
 //               mouse or keyboard button previously depressed with
-//               button_down() is release.  The bool is_within flag is
-//               true if the button was released while the mouse was
-//               still within the region, or false if it was released
-//               outside the region.
+//               press() is released
 ////////////////////////////////////////////////////////////////////
 void PGItem::
-button_up(ButtonHandle button, float x, float y, bool is_within) {
-  PGButtonEvent *be = new PGButtonEvent(button, x, y);
-  throw_event(get_button_up_event(), 
-              EventParameter(be),
-              EventParameter(is_within));
+release(const MouseWatcherParameter &param) {
+  PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
+  throw_event(get_release_event(param.get_button()), 
+              EventParameter(ep));
 }
 
 ////////////////////////////////////////////////////////////////////

+ 7 - 6
panda/src/pgui/pgItem.h

@@ -33,6 +33,7 @@
 #include "textNode.h"
 
 class ArcChain;
+class MouseWatcherParameter;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : PGItem
@@ -63,10 +64,10 @@ public:
   void activate_region(const LMatrix4f &transform, int sort);
   INLINE PGMouseWatcherRegion *get_region() const;
 
-  virtual void enter();
-  virtual void exit();
-  virtual void button_down(ButtonHandle button, float x, float y);
-  virtual void button_up(ButtonHandle button, float x, float y, bool is_within);
+  virtual void enter(const MouseWatcherParameter &param);
+  virtual void exit(const MouseWatcherParameter &param);
+  virtual void press(const MouseWatcherParameter &param);
+  virtual void release(const MouseWatcherParameter &param);
 
 PUBLISHED:
   INLINE void set_frame(float left, float right, float bottom, float top);
@@ -93,8 +94,8 @@ PUBLISHED:
   INLINE const string &get_id() const;
   INLINE string get_enter_event() const;
   INLINE string get_exit_event() const;
-  INLINE string get_button_down_event() const;
-  INLINE string get_button_up_event() const;
+  INLINE string get_press_event(const ButtonHandle &button) const;
+  INLINE string get_release_event(const ButtonHandle &button) const;
 
   static TextNode *get_text_node();
   INLINE static void set_text_node(TextNode *node);

+ 48 - 0
panda/src/pgui/pgMouseWatcherParameter.I

@@ -0,0 +1,48 @@
+// Filename: pgMouseWatcherParameter.I
+// Created by:  drose (05Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherParameter::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PGMouseWatcherParameter::
+PGMouseWatcherParameter() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherParameter::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PGMouseWatcherParameter::
+PGMouseWatcherParameter(const MouseWatcherParameter &copy) :
+  MouseWatcherParameter(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherParameter::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void PGMouseWatcherParameter::
+operator = (const MouseWatcherParameter &copy) {
+  MouseWatcherParameter::operator = (copy);
+}

+ 9 - 9
panda/src/pgui/pgButtonEvent.cxx → panda/src/pgui/pgMouseWatcherParameter.cxx

@@ -1,4 +1,4 @@
-// Filename: pgButtonEvent.cxx
+// Filename: pgMouseWatcherParameter.cxx
 // Created by:  drose (05Jul01)
 //
 ////////////////////////////////////////////////////////////////////
@@ -16,25 +16,25 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include "pgButtonEvent.h"
+#include "pgMouseWatcherParameter.h"
 
-TypeHandle PGButtonEvent::_type_handle;
+TypeHandle PGMouseWatcherParameter::_type_handle;
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGButtonEvent::Destructor
+//     Function: PGMouseWatcherParameter::Destructor
 //       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
-PGButtonEvent::
-~PGButtonEvent() {
+PGMouseWatcherParameter::
+~PGMouseWatcherParameter() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGButtonEvent::output
+//     Function: PGMouseWatcherParameter::output
 //       Access: Published
 //  Description: 
 ////////////////////////////////////////////////////////////////////
-void PGButtonEvent::
+void PGMouseWatcherParameter::
 output(ostream &out) const {
-  out << _button << " at (" << _mouse_x << ", " << _mouse_y << ")";
+  MouseWatcherParameter::output(out);
 }

+ 17 - 28
panda/src/pgui/pgButtonEvent.h → panda/src/pgui/pgMouseWatcherParameter.h

@@ -1,4 +1,4 @@
-// Filename: pgButtonEvent.h
+// Filename: pgMouseWatcherParameter.h
 // Created by:  drose (05Jul01)
 //
 ////////////////////////////////////////////////////////////////////
@@ -16,48 +16,39 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#ifndef PGBUTTONEVENT_H
-#define PGBUTTONEVENT_H
+#ifndef PGMOUSEWATCHERPARAMETER_H
+#define PGMOUSEWATCHERPARAMETER_H
 
 #include "pandabase.h"
 
+#include "mouseWatcherParameter.h"
 #include "typedReferenceCount.h"
-#include "buttonHandle.h"
 
 ////////////////////////////////////////////////////////////////////
-//       Class : PGButtonEvent
-// Description : This is sent along as a parameter to a button_down or
-//               button_up event for an item to indicate which button
-//               was involved, and what the current mouse position
-//               was.
+//       Class : PGMouseWatcherParameter
+// Description : This specialization on MouseWatcherParameter allows
+//               us to tag on additional elements to events for the
+//               gui system, and also inherits from
+//               TypedReferenceCount so we can attach this thing to an
+//               event.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA PGButtonEvent : public TypedReferenceCount {
+class EXPCL_PANDA PGMouseWatcherParameter : public MouseWatcherParameter, public TypedReferenceCount {
 public:
-  INLINE PGButtonEvent();
-  INLINE PGButtonEvent(ButtonHandle button, float mouse_x, float mouse_y);
-  virtual ~PGButtonEvent();
+  INLINE PGMouseWatcherParameter();
+  INLINE PGMouseWatcherParameter(const MouseWatcherParameter &copy);
+  INLINE void operator = (const MouseWatcherParameter &copy);
+  virtual ~PGMouseWatcherParameter();
 
 PUBLISHED:
-  INLINE ButtonHandle get_button() const;
-  INLINE string get_button_name() const;
-
-  INLINE float get_mouse_x() const;
-  INLINE float get_mouse_y() const;
-
   void output(ostream &out) const;
 
-public:
-  ButtonHandle _button;
-  float _mouse_x;
-  float _mouse_y;
-
 public:
   static TypeHandle get_class_type() {
     return _type_handle;
   }
   static void init_type() {
     TypedReferenceCount::init_type();
-    register_type(_type_handle, "PGButtonEvent",
+    register_type(_type_handle, "PGMouseWatcherParameter",
                   TypedReferenceCount::get_class_type());
   }
   virtual TypeHandle get_type() const {
@@ -69,8 +60,6 @@ private:
   static TypeHandle _type_handle;
 };
 
-INLINE ostream &operator << (ostream &out, const PGButtonEvent &event);
-
-#include "pgButtonEvent.I"
+#include "pgMouseWatcherParameter.I"
 
 #endif

+ 11 - 14
panda/src/pgui/pgMouseWatcherRegion.cxx

@@ -55,9 +55,9 @@ PGMouseWatcherRegion::
 //               mouse enters the region.
 ////////////////////////////////////////////////////////////////////
 void PGMouseWatcherRegion::
-enter() {
+enter(const MouseWatcherParameter &param) {
   if (_item != (PGItem *)NULL) {
-    _item->enter();
+    _item->enter(param);
   }
 }
 
@@ -68,39 +68,36 @@ enter() {
 //               mouse exits the region.
 ////////////////////////////////////////////////////////////////////
 void PGMouseWatcherRegion::
-exit() {
+exit(const MouseWatcherParameter &param) {
   if (_item != (PGItem *)NULL) {
-    _item->exit();
+    _item->exit(param);
   }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGMouseWatcherRegion::button_down
+//     Function: PGMouseWatcherRegion::press
 //       Access: Public, Virtual
 //  Description: This is a callback hook function, called whenever a
 //               mouse or keyboard button is depressed while the mouse
 //               is within the region.
 ////////////////////////////////////////////////////////////////////
 void PGMouseWatcherRegion::
-button_down(ButtonHandle button, float x, float y) {
+press(const MouseWatcherParameter &param) {
   if (_item != (PGItem *)NULL) {
-    _item->button_down(button, x, y);
+    _item->press(param);
   }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGMouseWatcherRegion::button_up
+//     Function: PGMouseWatcherRegion::release
 //       Access: Public, Virtual
 //  Description: This is a callback hook function, called whenever a
 //               mouse or keyboard button previously depressed with
-//               button_down() is release.  The bool is_within flag is
-//               true if the button was released while the mouse was
-//               still within the region, or false if it was released
-//               outside the region.
+//               press() is released.
 ////////////////////////////////////////////////////////////////////
 void PGMouseWatcherRegion::
-button_up(ButtonHandle button, float x, float y, bool is_within) {
+release(const MouseWatcherParameter &param) {
   if (_item != (PGItem *)NULL) {
-    _item->button_up(button, x, y, is_within);
+    _item->release(param);
   }
 }

+ 4 - 4
panda/src/pgui/pgMouseWatcherRegion.h

@@ -37,10 +37,10 @@ public:
   PGMouseWatcherRegion(PGItem *item);
   virtual ~PGMouseWatcherRegion();
 
-  virtual void enter();
-  virtual void exit();
-  virtual void button_down(ButtonHandle button, float x, float y);
-  virtual void button_up(ButtonHandle button, float x, float y, bool is_within);
+  virtual void enter(const MouseWatcherParameter &param);
+  virtual void exit(const MouseWatcherParameter &param);
+  virtual void press(const MouseWatcherParameter &param);
+  virtual void release(const MouseWatcherParameter &param);
 
 private:
   PGItem *_item;

+ 10 - 10
panda/src/putil/modifierButtons.I

@@ -19,7 +19,7 @@
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::Copy Assignment Operator
-//       Access: Public
+//       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE void ModifierButtons::
@@ -30,7 +30,7 @@ operator = (const ModifierButtons &copy) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::Equality Operator
-//       Access: Public
+//       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE bool ModifierButtons::
@@ -41,7 +41,7 @@ operator == (const ModifierButtons &other) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::Inequality Operator
-//       Access: Public
+//       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE bool ModifierButtons::
@@ -51,7 +51,7 @@ operator != (const ModifierButtons &other) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::Ordering Operator
-//       Access: Public
+//       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE bool ModifierButtons::
@@ -64,7 +64,7 @@ operator < (const ModifierButtons &other) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::get_num_buttons
-//       Access: Public
+//       Access: Published
 //  Description: Returns the number of buttons that the
 //               ModifierButtons object is monitoring (e.g. the number
 //               of buttons passed to add_button()).
@@ -76,7 +76,7 @@ get_num_buttons() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::get_button
-//       Access: Public
+//       Access: Published
 //  Description: Returns the nth button that the ModifierButtons
 //               object is monitoring (the nth button passed to
 //               add_button()).  This must be in the range 0 <= index
@@ -90,7 +90,7 @@ get_button(int index) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::add_event
-//       Access: Public
+//       Access: Published
 //  Description: Calls button_down() or button_up(), as appropriate,
 //               according to the indicated ButtonEvent.
 ////////////////////////////////////////////////////////////////////
@@ -105,7 +105,7 @@ add_event(const ButtonEvent &event) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::all_buttons_up
-//       Access: Public
+//       Access: Published
 //  Description: Marks all monitored buttons as being in the "up"
 //               state.
 ////////////////////////////////////////////////////////////////////
@@ -116,7 +116,7 @@ all_buttons_up() {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::is_down
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the indicated button is known to be
 //               down, or false if it is known to be up.
 ////////////////////////////////////////////////////////////////////
@@ -128,7 +128,7 @@ is_down(int index) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::is_any_down
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if any of the tracked button are known
 //               to be down, or false if all of them are up.
 ////////////////////////////////////////////////////////////////////

+ 31 - 11
panda/src/putil/modifierButtons.cxx

@@ -22,7 +22,7 @@
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ModifierButtons::
@@ -34,7 +34,7 @@ ModifierButtons() :
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::Copy Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ModifierButtons::
@@ -46,7 +46,7 @@ ModifierButtons(const ModifierButtons &copy) :
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::Destructor
-//       Access: Public
+//       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ModifierButtons::
@@ -55,7 +55,7 @@ ModifierButtons::
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::add_button
-//       Access: Public
+//       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
@@ -86,7 +86,7 @@ add_button(ButtonHandle button) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::has_button
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the indicated button is in the set of
 //               buttons being monitored, false otherwise.
 ////////////////////////////////////////////////////////////////////
@@ -104,7 +104,7 @@ has_button(ButtonHandle button) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::remove_button
-//       Access: Public
+//       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
@@ -137,7 +137,7 @@ remove_button(ButtonHandle button) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::button_down
-//       Access: Public
+//       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
@@ -159,7 +159,7 @@ button_down(ButtonHandle button) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::button_up
-//       Access: Public
+//       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
@@ -181,7 +181,7 @@ button_up(ButtonHandle button) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::is_down
-//       Access: Public
+//       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.
@@ -197,9 +197,29 @@ is_down(ButtonHandle button) const {
   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: Public
+//       Access: Published
 //  Description: Writes a one-line summary of the buttons known to be
 //               down.
 ////////////////////////////////////////////////////////////////////
@@ -216,7 +236,7 @@ output(ostream &out) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ModifierButtons::write
-//       Access: Public
+//       Access: Published
 //  Description: Writes a multi-line summary including all of the
 //               buttons being monitored and which ones are known to
 //               be down.

+ 2 - 0
panda/src/putil/modifierButtons.h

@@ -58,6 +58,8 @@ PUBLISHED:
   INLINE bool is_down(int index) const;
   INLINE bool is_any_down() const;
 
+  string get_prefix() const;
+
   void output(ostream &out) const;
   void write(ostream &out) const;
 

+ 5 - 3
panda/src/tform/Sources.pp

@@ -13,20 +13,22 @@
     buttonThrower.h config_tform.h dataValve.I dataValve.h  \
     driveInterface.I driveInterface.h mouseWatcher.I  \
     mouseWatcher.h mouseWatcherGroup.h \
+    mouseWatcherParameter.I mouseWatcherParameter.h  \
     mouseWatcherRegion.I mouseWatcherRegion.h  \
     planarSlider.h trackball.h transform2sg.h  
      
   #define INCLUDED_SOURCES  \
     buttonThrower.cxx config_tform.cxx dataValve.cxx  \
     driveInterface.cxx mouseWatcher.cxx mouseWatcherGroup.cxx \
-    mouseWatcherRegion.cxx  \
+    mouseWatcherParameter.cxx mouseWatcherRegion.cxx  \
     planarSlider.cxx trackball.cxx transform2sg.cxx 
 
   #define INSTALL_HEADERS \
     buttonThrower.h dataValve.I dataValve.h \
     driveInterface.I driveInterface.h mouseWatcher.I mouseWatcher.h \
-    mouseWatcherRegion.I mouseWatcherRegion.h planarSlider.h \
-    trackball.h transform2sg.h
+    mouseWatcherParameter.I mouseWatcherParameter.h \
+    mouseWatcherRegion.I mouseWatcherRegion.h \
+    planarSlider.h trackball.h transform2sg.h
 
   #define IGATESCAN all
 

+ 1 - 9
panda/src/tform/buttonThrower.cxx

@@ -132,15 +132,7 @@ transmit_data(NodeAttributes &data) {
         if (!_mods.button_down(be._button)) {
           // We only prepend modifier names on the button-down events,
           // and only for buttons which are not themselves modifiers.
-          string prepend;
-
-          for (int i = 0; i < _mods.get_num_buttons(); i++) {
-            ButtonHandle modifier = _mods.get_button(i);
-            if (_mods.is_down(modifier)) {
-              prepend += modifier.get_name() + "-";
-            }
-          }
-          event_name = prepend + event_name;
+          event_name = _mods.get_prefix() + event_name;
         }
 
       } else {

+ 23 - 0
panda/src/tform/mouseWatcher.I

@@ -300,3 +300,26 @@ INLINE EventHandler *MouseWatcher::
 get_extra_handler(void) const {
   return _eh;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcher::set_modifier_buttons
+//       Access: Public
+//  Description: Sets the buttons that should be monitored as modifier
+//               buttons for generating events to the
+//               MouseWatcherRegions.
+////////////////////////////////////////////////////////////////////
+INLINE void MouseWatcher::
+set_modifier_buttons(const ModifierButtons &mods) {
+  _mods = mods;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcher::get_modifier_buttons
+//       Access: Published
+//  Description: Returns the set of buttons that are being monitored
+//               as modifier buttons, as well as their current state.
+////////////////////////////////////////////////////////////////////
+INLINE const ModifierButtons &MouseWatcher::
+get_modifier_buttons() const {
+  return _mods;
+}

+ 45 - 23
panda/src/tform/mouseWatcher.cxx

@@ -18,17 +18,18 @@
 
 #include "mouseWatcher.h"
 #include "config_tform.h"
-
-#include <mouse.h>
-#include <mouseData.h>
-#include <buttonEventDataTransition.h>
-#include <buttonEventDataAttribute.h>
-#include <keyboardButton.h>
-#include <mouseButton.h>
-#include <throw_event.h>
-#include <eventParameter.h>
-#include <pruneTransition.h>
-#include <transformTransition.h>
+#include "mouseWatcherParameter.h"
+
+#include "mouse.h"
+#include "mouseData.h"
+#include "buttonEventDataTransition.h"
+#include "buttonEventDataAttribute.h"
+#include "keyboardButton.h"
+#include "mouseButton.h"
+#include "throw_event.h"
+#include "eventParameter.h"
+#include "pruneTransition.h"
+#include "transformTransition.h"
 
 TypeHandle MouseWatcher::_type_handle;
 
@@ -227,14 +228,18 @@ set_current_region(MouseWatcherRegion *region) {
   }
 #endif
   if (region != _current_region) {
+    MouseWatcherParameter param;
+    param.set_modifier_buttons(_mods);
+    param.set_mouse(_mouse);
+
     if (_current_region != (MouseWatcherRegion *)NULL) {
-      _current_region->exit();
-      throw_event_pattern(_leave_pattern, _current_region);
+      _current_region->exit(param);
+      throw_event_pattern(_leave_pattern, _current_region, ButtonHandle::none());
     }
     _current_region = region;
     if (_current_region != (MouseWatcherRegion *)NULL) {
-      _current_region->enter();
-      throw_event_pattern(_enter_pattern, _current_region);
+      _current_region->enter(param);
+      throw_event_pattern(_enter_pattern, _current_region, ButtonHandle::none());
     }
   }
 }
@@ -247,7 +252,7 @@ set_current_region(MouseWatcherRegion *region) {
 ////////////////////////////////////////////////////////////////////
 void MouseWatcher::
 throw_event_pattern(const string &pattern, const MouseWatcherRegion *region,
-                    const string &button_name) {
+                    const ButtonHandle &button) {
   if (pattern.empty()) {
     return;
   }
@@ -257,6 +262,16 @@ throw_event_pattern(const string &pattern, const MouseWatcherRegion *region,
   }
 #endif
 
+  string button_name;
+  if (button != ButtonHandle::none()) {
+    if (!_mods.has_button(button)) {
+      // We only prepend modifier names for buttons which are not
+      // themselves modifiers.
+      button_name = _mods.get_prefix();
+    }
+    button_name += button.get_name();
+  }
+
   string event;
   for (size_t p = 0; p < pattern.size(); ++p) {
     if (pattern[p] == '%') {
@@ -264,11 +279,11 @@ throw_event_pattern(const string &pattern, const MouseWatcherRegion *region,
       p++;
       if (cmd == "r") {
         if (region != (MouseWatcherRegion *)NULL) {
-          event += region->get_name();
+          event += button_name;
         }
 
       } else if (cmd == "b") {
-        event += button_name;
+        event += button.get_name();
 
       } else {
         tform_cat.error()
@@ -349,6 +364,12 @@ transmit_data(NodeAttributes &data) {
     ButtonEventDataAttribute::const_iterator bi;
     for (bi = b->begin(); bi != b->end(); ++bi) {
       const ButtonEvent &be = (*bi);
+      _mods.add_event(be);
+
+      MouseWatcherParameter param;
+      param.set_button(be._button);
+      param.set_modifier_buttons(_mods);
+      param.set_mouse(_mouse);
 
       if (!be._down) {
         // Button up.  Send the up event associated with the region we
@@ -358,10 +379,11 @@ transmit_data(NodeAttributes &data) {
         // more than one button goes down together, we won't detect
         // both of the button-up events properly.
         if (_button_down_region != (MouseWatcherRegion *)NULL) {
-          bool is_within = (_current_region == _button_down_region);
-          _button_down_region->button_up(be._button, get_mouse_x(), get_mouse_y(), is_within);
+          param.set_outside(_current_region != _button_down_region);
+
+          _button_down_region->release(param);
           throw_event_pattern(_button_up_pattern, _button_down_region,
-                              be._button.get_name());
+                              be._button);
         }
         _button_down = false;
 
@@ -373,9 +395,9 @@ transmit_data(NodeAttributes &data) {
         }
         _button_down = true;
         if (_button_down_region != (MouseWatcherRegion *)NULL) {
-          _button_down_region->button_down(be._button, get_mouse_x(), get_mouse_y());
+          _button_down_region->press(param);
           throw_event_pattern(_button_down_pattern, _button_down_region,
-                              be._button.get_name());
+                              be._button);
         }
       }
     }

+ 16 - 9
panda/src/tform/mouseWatcher.h

@@ -24,14 +24,16 @@
 #include "mouseWatcherRegion.h"
 #include "mouseWatcherGroup.h"
 
-#include <dataNode.h>
-#include <vec3DataTransition.h>
-#include <vec3DataAttribute.h>
-#include <luse.h>
-#include <nodeRelation.h>
-#include <pointerTo.h>
-#include <eventHandler.h>
-#include <pt_NodeRelation.h>
+#include "dataNode.h"
+#include "vec3DataTransition.h"
+#include "vec3DataAttribute.h"
+#include "luse.h"
+#include "nodeRelation.h"
+#include "pointerTo.h"
+#include "eventHandler.h"
+#include "pt_NodeRelation.h"
+#include "modifierButtons.h"
+#include "buttonHandle.h"
 
 #include "pset.h"
 
@@ -93,6 +95,9 @@ PUBLISHED:
   INLINE void set_extra_handler(EventHandler *eh);
   INLINE EventHandler *get_extra_handler(void) const;
 
+  INLINE void set_modifier_buttons(const ModifierButtons &mods);
+  INLINE const ModifierButtons &get_modifier_buttons() const;
+
 public:
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level = 0) const;
@@ -104,7 +109,7 @@ private:
   void set_current_region(MouseWatcherRegion *region);
   void throw_event_pattern(const string &pattern,
                            const MouseWatcherRegion *region,
-                           const string &button_name = string());
+                           const ButtonHandle &button);
 
   typedef pset< PT(MouseWatcherGroup) > Groups;
   Groups _groups;
@@ -125,6 +130,8 @@ private:
 
   EventHandler* _eh;
 
+  ModifierButtons _mods;
+
 ////////////////////////////////////////////////////////////////////
 // From parent class DataNode
 ////////////////////////////////////////////////////////////////////

+ 7 - 10
panda/src/tform/mouseWatcherRegion.cxx

@@ -50,7 +50,7 @@ write(ostream &out, int indent_level) const {
 //               mouse enters the region.
 ////////////////////////////////////////////////////////////////////
 void MouseWatcherRegion::
-enter() {
+enter(const MouseWatcherParameter &) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -60,30 +60,27 @@ enter() {
 //               mouse exits the region.
 ////////////////////////////////////////////////////////////////////
 void MouseWatcherRegion::
-exit() {
+exit(const MouseWatcherParameter &) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: MouseWatcherRegion::button_down
+//     Function: MouseWatcherRegion::press
 //       Access: Public, Virtual
 //  Description: This is a callback hook function, called whenever a
 //               mouse or keyboard button is depressed while the mouse
 //               is within the region.
 ////////////////////////////////////////////////////////////////////
 void MouseWatcherRegion::
-button_down(ButtonHandle, float, float) {
+press(const MouseWatcherParameter &) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: MouseWatcherRegion::button_up
+//     Function: MouseWatcherRegion::release
 //       Access: Public, Virtual
 //  Description: This is a callback hook function, called whenever a
 //               mouse or keyboard button previously depressed with
-//               button_down() is release.  The bool is_within flag is
-//               true if the button was released while the mouse was
-//               still within the region, or false if it was released
-//               outside the region.
+//               press() is released.
 ////////////////////////////////////////////////////////////////////
 void MouseWatcherRegion::
-button_up(ButtonHandle, float, float, bool) {
+release(const MouseWatcherParameter &) {
 }

+ 14 - 9
panda/src/tform/mouseWatcherRegion.h

@@ -19,12 +19,15 @@
 #ifndef MOUSEWATCHERREGION_H
 #define MOUSEWATCHERREGION_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
-#include <namable.h>
-#include <typedReferenceCount.h>
-#include <luse.h>
-#include <buttonHandle.h>
+#include "namable.h"
+#include "typedReferenceCount.h"
+#include "luse.h"
+#include "buttonHandle.h"
+#include "modifierButtons.h"
+
+class MouseWatcherParameter;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : MouseWatcherRegion
@@ -57,10 +60,10 @@ PUBLISHED:
 public:
   INLINE bool operator < (const MouseWatcherRegion &other) const;
 
-  virtual void enter();
-  virtual void exit();
-  virtual void button_down(ButtonHandle button, float x, float y);
-  virtual void button_up(ButtonHandle button, float x, float y, bool is_within);
+  virtual void enter(const MouseWatcherParameter &param);
+  virtual void exit(const MouseWatcherParameter &param);
+  virtual void press(const MouseWatcherParameter &param);
+  virtual void release(const MouseWatcherParameter &param);
 
 private:
   LVecBase4f _frame;
@@ -70,6 +73,8 @@ private:
   bool _active;
   bool _suppress_below;
 
+  ModifierButtons _mods;
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 1 - 0
panda/src/tform/tform_composite2.cxx

@@ -1,6 +1,7 @@
 
 #include "mouseWatcher.cxx"
 #include "mouseWatcherGroup.cxx"
+#include "mouseWatcherParameter.cxx"
 #include "mouseWatcherRegion.cxx"
 #include "trackball.cxx"
 #include "transform2sg.cxx"