Browse Source

initial pgui stuff

David Rose 24 years ago
parent
commit
68e199f696
38 changed files with 2732 additions and 276 deletions
  1. 1 1
      panda/metalibs/panda/Sources.pp
  2. 3 3
      panda/src/graph/Sources.pp
  3. 62 7
      panda/src/graph/arcChain.I
  4. 89 0
      panda/src/graph/arcChain.cxx
  5. 16 1
      panda/src/graph/arcChain.h
  6. 40 0
      panda/src/pgui/Sources.pp
  7. 35 0
      panda/src/pgui/config_pgui.cxx
  8. 27 0
      panda/src/pgui/config_pgui.h
  9. 78 0
      panda/src/pgui/pgButton.I
  10. 212 0
      panda/src/pgui/pgButton.cxx
  11. 95 0
      panda/src/pgui/pgButton.h
  12. 150 0
      panda/src/pgui/pgFrameStyle.I
  13. 133 0
      panda/src/pgui/pgFrameStyle.cxx
  14. 79 0
      panda/src/pgui/pgFrameStyle.h
  15. 233 0
      panda/src/pgui/pgItem.I
  16. 396 0
      panda/src/pgui/pgItem.cxx
  17. 145 0
      panda/src/pgui/pgItem.h
  18. 18 0
      panda/src/pgui/pgMouseWatcherRegion.I
  19. 106 0
      panda/src/pgui/pgMouseWatcherRegion.cxx
  20. 71 0
      panda/src/pgui/pgMouseWatcherRegion.h
  21. 56 0
      panda/src/pgui/pgTop.I
  22. 256 0
      panda/src/pgui/pgTop.cxx
  23. 99 0
      panda/src/pgui/pgTop.h
  24. 25 83
      panda/src/sgmanip/nodePath.I
  25. 0 99
      panda/src/sgmanip/nodePath.cxx
  26. 2 11
      panda/src/sgmanip/nodePath.h
  27. 1 1
      panda/src/sgraphutil/frustumCullTraverser.I
  28. 9 7
      panda/src/tform/Sources.pp
  29. 2 0
      panda/src/tform/config_tform.cxx
  30. 1 1
      panda/src/tform/mouseWatcher.I
  31. 83 52
      panda/src/tform/mouseWatcher.cxx
  32. 10 9
      panda/src/tform/mouseWatcher.h
  33. 87 0
      panda/src/tform/mouseWatcherGroup.cxx
  34. 60 0
      panda/src/tform/mouseWatcherGroup.h
  35. 44 0
      panda/src/tform/mouseWatcherRegion.cxx
  36. 6 0
      panda/src/tform/mouseWatcherRegion.h
  37. 1 0
      panda/src/tform/tform_composite1.cxx
  38. 1 1
      panda/src/tform/tform_composite2.cxx

+ 1 - 1
panda/metalibs/panda/Sources.pp

@@ -16,7 +16,7 @@
     parametrics pnm \
     parametrics pnm \
     pnmimagetypes pnmimage sgattrib sgmanip sgraph sgraphutil \
     pnmimagetypes pnmimage sgattrib sgmanip sgraph sgraphutil \
     switchnode text tform tiff lerp loader putil effects \
     switchnode text tform tiff lerp loader putil effects \
-    audio gui pandabase 
+    audio gui pgui pandabase 
 
 
 
 
 
 

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

@@ -48,8 +48,8 @@
 
 
    #define INCLUDED_SOURCES \
    #define INCLUDED_SOURCES \
      allAttributesWrapper.cxx allTransitionsWrapper.cxx \
      allAttributesWrapper.cxx allTransitionsWrapper.cxx \
-     arcChain.cxxbitMask32Transition.cxx   \
-     boundedObject.cxxconfig_graph.cxx graphReducer.cxx   \
+     arcChain.cxx bitMask32Transition.cxx   \
+     boundedObject.cxx config_graph.cxx graphReducer.cxx   \
      immediateAttribute.cxx immediateTransition.cxx   \
      immediateAttribute.cxx immediateTransition.cxx   \
      lmatrix4fTransition.cxx multiNodeAttribute.cxx   \
      lmatrix4fTransition.cxx multiNodeAttribute.cxx   \
      multiNodeTransition.cxx namedNode.cxx node.cxx   \
      multiNodeTransition.cxx namedNode.cxx node.cxx   \
@@ -58,7 +58,7 @@
      nodeTransition.cxx nodeTransitionCache.cxx   \
      nodeTransition.cxx nodeTransitionCache.cxx   \
      nodeTransitionCacheEntry.cxx nodeTransitionWrapper.cxx   \
      nodeTransitionCacheEntry.cxx nodeTransitionWrapper.cxx   \
      nodeTransitions.cxx   \
      nodeTransitions.cxx   \
-     nullAttributeWrapper.cxxnullLevelState.cxx   \
+     nullAttributeWrapper.cxx nullLevelState.cxx   \
      nullTransitionWrapper.cxx onAttribute.cxx onOffAttribute.cxx   \
      nullTransitionWrapper.cxx onAttribute.cxx onOffAttribute.cxx   \
      onOffTransition.cxx onTransition.cxx pt_NamedNode.cxx   \
      onOffTransition.cxx onTransition.cxx pt_NamedNode.cxx   \
      pt_Node.cxx pt_NodeRelation.cxx vector_PT_Node.cxx   \
      pt_Node.cxx pt_NodeRelation.cxx vector_PT_Node.cxx   \

+ 62 - 7
panda/src/graph/arcChain.I

@@ -301,27 +301,82 @@ operator = (const ArcChain &copy) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: ArcChain::has_node
+//     Function: ArcChain::is_empty
 //       Access: Public
 //       Access: Public
-//  Description: Returns true if there is at least a top node in the
-//               chain, or false otherwise.
+//  Description: Returns true if the ArcChain contains no nodes and no
+//               arcs.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE_GRAPH bool ArcChain::
 INLINE_GRAPH bool ArcChain::
-has_node() const {
-  return (_head != (ArcComponent *)NULL);
+is_empty() const {
+  return (_head == (ArcComponent *)NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ArcChain::is_singleton
+//       Access: Public
+//  Description: Returns true if the ArcChain contains exactly one
+//               node, and no arcs.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH bool ArcChain::
+is_singleton() const {
+  return (_head != (ArcComponent *)NULL && _head->is_top_node());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ArcChain::has_arcs
 //     Function: ArcChain::has_arcs
 //       Access: Public
 //       Access: Public
-//  Description: Returns true if there are any arcs in the chain, or
-//               false otherwise.
+//  Description: Returns true if the ArcChain contains at least one
+//               arc, and therefore at least two nodes.  This is the
+//               same thing as asking get_num_arcs() > 0, but is
+//               easier to compute.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE_GRAPH bool ArcChain::
 INLINE_GRAPH bool ArcChain::
 has_arcs() const {
 has_arcs() const {
   return (_head != (ArcComponent *)NULL && !_head->is_top_node());
   return (_head != (ArcComponent *)NULL && !_head->is_top_node());
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: ArcChain::get_num_arcs
+//       Access: Public
+//  Description: Returns the number of arcs in the path.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH int ArcChain::
+get_num_arcs() const {
+  if (!has_arcs()) {
+    return 0;
+  }
+  return get_num_nodes() - 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ArcChain::node
+//       Access: Public
+//  Description: Returns the bottom node of the path, or NULL if the
+//               path is empty.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH Node *ArcChain::
+node() const {
+  if (is_empty()) {
+    return (Node *)NULL;
+  }
+  return _head->get_node();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ArcChain::arc
+//       Access: Public
+//  Description: Returns the bottom arc of the path, or NULL if the
+//               path is empty or is a singleton.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH NodeRelation *ArcChain::
+arc() const {
+  if (!has_arcs()) {
+    // A singleton or empty list.
+    return (NodeRelation *)NULL;
+  }
+  return _head->get_arc();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ArcChain::begin
 //     Function: ArcChain::begin
 //       Access: Public
 //       Access: Public

+ 89 - 0
panda/src/graph/arcChain.cxx

@@ -60,6 +60,95 @@ operator = (const ArcComponent &copy) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: ArcChain::get_num_nodes
+//       Access: Public
+//  Description: Returns the number of nodes in the path.  This is
+//               always one more than the number of arcs (except for
+//               a completely empty path).
+////////////////////////////////////////////////////////////////////
+int ArcChain::
+get_num_nodes() const {
+  int num = 0;
+  ArcComponent *comp = _head;
+  while (comp != (ArcComponent *)NULL) {
+    num++;
+    comp = comp->get_next();
+  }
+  return num;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ArcChain::get_node
+//       Access: Public
+//  Description: Returns the nth node of the path, where 0 is the
+//               bottom node and get_num_nodes() - 1 is the top node.
+//               This requires iterating through the path.
+////////////////////////////////////////////////////////////////////
+Node *ArcChain::
+get_node(int index) const {
+  nassertr(index >= 0 && index < get_num_nodes(), NULL);
+
+  ArcComponent *comp = _head;
+  while (index > 0) {
+    // If this assertion fails, the index was out of range.
+    nassertr(comp != (ArcComponent *)NULL, NULL);
+    comp = comp->get_next();
+    index--;
+  }
+
+  // If this assertion fails, the index was out of range.
+  nassertr(comp != (ArcComponent *)NULL, NULL);
+  return comp->get_node();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ArcChain::get_arc
+//       Access: Public
+//  Description: Returns the nth arc of the path, where 0 is the arc
+//               above the bottom node node and get_num_arcs() - 1 is
+//               the arc below the top node.  This requires iterating
+//               through the path.
+////////////////////////////////////////////////////////////////////
+NodeRelation *ArcChain::
+get_arc(int index) const {
+  nassertr(index >= 0 && index < get_num_arcs(), NULL);
+
+  ArcComponent *comp = _head;
+  while (index > 0) {
+    // If this assertion fails, the index was out of range.
+    nassertr(comp != (ArcComponent *)NULL, NULL);
+    comp = comp->get_next();
+    index--;
+  }
+
+  // If either assertion fails, the index was out of range.
+  nassertr(comp != (ArcComponent *)NULL, NULL);
+  nassertr(comp->has_arc(), NULL);
+  return comp->get_arc();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ArcChain::get_top_node
+//       Access: Public
+//  Description: Returns the top node of the path, or NULL if the path
+//               is empty.  This requires iterating through the path.
+////////////////////////////////////////////////////////////////////
+Node *ArcChain::
+get_top_node() const {
+  if (is_empty()) {
+    return (Node *)NULL;
+  }
+
+  ArcComponent *comp = _head;
+  while (!comp->is_top_node()) {
+    comp = comp->get_next();
+    nassertr(comp != (ArcComponent *)NULL, NULL);
+  }
+
+  return comp->get_node();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ArcChain::r_output
 //     Function: ArcChain::r_output
 //       Access: Private
 //       Access: Private

+ 16 - 1
panda/src/graph/arcChain.h

@@ -141,8 +141,23 @@ public:
   INLINE_GRAPH ArcChain(const ArcChain &copy);
   INLINE_GRAPH ArcChain(const ArcChain &copy);
   INLINE_GRAPH void operator = (const ArcChain &copy);
   INLINE_GRAPH void operator = (const ArcChain &copy);
 
 
-  INLINE_GRAPH bool has_node() const;
+  // Methods to query an ArcChain's contents.
+PUBLISHED:
+  INLINE_GRAPH bool is_empty() const;
+  INLINE_GRAPH bool is_singleton() const;
   INLINE_GRAPH bool has_arcs() const;
   INLINE_GRAPH bool has_arcs() const;
+  int get_num_nodes() const;
+  Node *get_node(int index) const;
+
+  INLINE_GRAPH int get_num_arcs() const;
+  NodeRelation *get_arc(int index) const;
+
+  Node *get_top_node() const;
+  INLINE_GRAPH Node *node() const;
+  INLINE_GRAPH NodeRelation *arc() const;
+
+public:
+  // Methods to make an ArcChain behave like an STL container.
 
 
   INLINE_GRAPH const_iterator begin() const;
   INLINE_GRAPH const_iterator begin() const;
   INLINE_GRAPH const_iterator end() const;
   INLINE_GRAPH const_iterator end() const;

+ 40 - 0
panda/src/pgui/Sources.pp

@@ -0,0 +1,40 @@
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+                   dtoolutil:c dtoolbase:c dtool:m
+
+#begin lib_target
+  #define TARGET pgui
+  #define LOCAL_LIBS \
+    text tform graph linmath event putil gobj \
+    mathutil sgraph sgraphutil
+
+//  #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx 
+
+  #define SOURCES  \
+    config_pgui.h \
+    pgButton.I pgButton.h \
+    pgFrameStyle.I pgFrameStyle.h \
+    pgItem.I pgItem.h \
+    pgMouseWatcherRegion.I pgMouseWatcherRegion.h \
+    pgTop.I pgTop.h
+     
+//  #define INCLUDED_SOURCES  \
+  #define SOURCES $[SOURCES] \
+    config_pgui.cxx \
+    pgButton.cxx \
+    pgFrameStyle.cxx \
+    pgItem.cxx \
+    pgMouseWatcherRegion.cxx \
+    pgTop.cxx
+
+  #define INSTALL_HEADERS \
+    pgButton.I pgButton.h \
+    pgFrameStyle.I pgFrameStyle.h \
+    pgItem.I pgItem.h \
+    pgMouseWatcherRegion.I pgMouseWatcherRegion.h \
+    pgTop.I pgTop.h
+    
+
+  #define IGATESCAN all
+
+#end lib_target
+

+ 35 - 0
panda/src/pgui/config_pgui.cxx

@@ -0,0 +1,35 @@
+// Filename: config_pgui.cxx
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "config_pgui.h"
+#include "pgButton.h"
+#include "pgItem.h"
+#include "pgMouseWatcherRegion.h"
+#include "pgTop.h"
+
+#include "dconfig.h"
+
+Configure(config_pgui);
+NotifyCategoryDef(pgui, "");
+
+ConfigureFn(config_pgui) {
+  PGButton::init_type();
+  PGItem::init_type();
+  PGMouseWatcherRegion::init_type();
+  PGTop::init_type();
+}

+ 27 - 0
panda/src/pgui/config_pgui.h

@@ -0,0 +1,27 @@
+// Filename: config_pgui.h
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIG_PGUI_H
+#define CONFIG_PGUI_H
+
+#include <pandabase.h>
+#include <notifyCategoryProxy.h>
+
+NotifyCategoryDecl(pgui, EXPCL_PANDA, EXPTP_PANDA);
+
+#endif

+ 78 - 0
panda/src/pgui/pgButton.I

@@ -0,0 +1,78 @@
+// Filename: pgButton.I
+// Created by:  drose (03Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: PGButton::setup
+//       Access: Published
+//  Description: Sets up the button using the indicated NodePath as
+//               arbitrary geometry.
+////////////////////////////////////////////////////////////////////
+INLINE void PGButton::
+setup(const ArcChain &ready) {
+  setup(ready, ready, ready, ready);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::setup
+//       Access: Published
+//  Description: Sets up the button using the indicated NodePath as
+//               arbitrary geometry.
+////////////////////////////////////////////////////////////////////
+INLINE void PGButton::
+setup(const ArcChain &ready, const ArcChain &depressed) {
+  setup(ready, depressed, ready, ready);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::setup
+//       Access: Published
+//  Description: Sets up the button using the indicated NodePath as
+//               arbitrary geometry.
+////////////////////////////////////////////////////////////////////
+INLINE void PGButton::
+setup(const ArcChain &ready, const ArcChain &depressed, 
+      const ArcChain &rollover) {
+  setup(ready, depressed, rollover, ready);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::set_active
+//       Access: Public
+//  Description: Toggles the active/inactive state of the button.  In
+//               the case of a PGButton, this also changes its visual
+//               appearance.
+////////////////////////////////////////////////////////////////////
+INLINE void PGButton:: 
+set_active(bool active) {
+  if (active != get_active()) {
+    set_state(active ? S_ready : S_inactive);
+    PGItem::set_active(active);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::get_click_event
+//       Access: Published
+//  Description: Returns the event name that will be thrown when the
+//               button is clicked normally.
+////////////////////////////////////////////////////////////////////
+INLINE string PGButton::
+get_click_event() const {
+  return "click-" + get_id();
+}

+ 212 - 0
panda/src/pgui/pgButton.cxx

@@ -0,0 +1,212 @@
+// Filename: pgButton.cxx
+// Created by:  drose (03Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pgButton.h"
+#include "throw_event.h"
+#include "renderRelation.h"
+#include "colorTransition.h"
+
+TypeHandle PGButton::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGButton::
+PGButton(const string &name) : PGItem(name)
+{
+  _button_down = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGButton::
+~PGButton() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGButton::
+PGButton(const PGButton &copy) :
+  PGItem(copy)
+{
+  _button_down = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PGButton::
+operator = (const PGButton &copy) {
+  PGItem::operator = (copy);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::make_copy
+//       Access: Public, Virtual
+//  Description: Returns a newly-allocated Node that is a shallow copy
+//               of this one.  It will be a different Node pointer,
+//               but its internal data may or may not be shared with
+//               that of the original Node.
+////////////////////////////////////////////////////////////////////
+Node *PGButton::
+make_copy() const {
+  return new PGButton(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::enter
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever the
+//               mouse enters the region.
+////////////////////////////////////////////////////////////////////
+void PGButton::
+enter() {
+  if (get_active()) {
+    set_state(_button_down ? S_depressed : S_rollover);
+  }
+  PGItem::enter();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::exit
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever the
+//               mouse exits the region.
+////////////////////////////////////////////////////////////////////
+void PGButton::
+exit() {
+  if (get_active()) {
+    set_state(S_ready);
+  }
+  PGItem::exit();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::button_down
+//       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) {
+  if (get_active()) {
+    _button_down = true;
+    set_state(S_depressed);
+  }
+  PGItem::button_down(button);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::button_up
+//       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.
+////////////////////////////////////////////////////////////////////
+void PGButton::
+button_up(ButtonHandle button, bool is_within) {
+  _button_down = false;
+  if (get_active()) {
+    if (is_within) {
+      set_state(S_rollover);
+      click();
+    } else {
+      set_state(S_ready);
+    }
+  }
+  PGItem::button_up(button, is_within);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::click
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever the
+//               button is clicked normally.
+////////////////////////////////////////////////////////////////////
+void PGButton::
+click() {
+  throw_event(get_click_event());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::setup
+//       Access: Published
+//  Description: Sets up the button as a default text button using the
+//               indicated label string.  The TextNode defined by
+//               PGItem::get_text_node() will be used to create the
+//               label geometry.  This automatically sets up the frame
+//               according to the size of the text.
+////////////////////////////////////////////////////////////////////
+void PGButton::
+setup(const string &label) {
+  TextNode *text_node = get_text_node();
+  text_node->set_text(label);
+  PT_Node geom = text_node->generate();
+
+  new RenderRelation(get_state_def(S_ready), geom);
+  NodeRelation *dep = new RenderRelation(get_state_def(S_depressed), geom);
+  new RenderRelation(get_state_def(S_rollover), geom);
+  new RenderRelation(get_state_def(S_inactive), geom);
+
+  PGFrameStyle style;
+  style.set_type(PGFrameStyle::T_flat);
+  style.set_color(1.0, 1.0, 1.0, 1.0);
+  set_frame_style(S_ready, style);
+
+  style.set_color(0.0, 0.0, 0.0, 1.0);
+  set_frame_style(S_depressed, style);
+  ColorTransition *col_trans = new ColorTransition(Colorf(0.0, 1.0, 1.0, 1.0));
+  dep->set_transition(col_trans);
+
+  style.set_color(1.0, 1.0, 0.0, 1.0);
+  set_frame_style(S_rollover, style);
+
+  style.set_color(0.6, 0.6, 0.6, 1.0);
+  set_frame_style(S_inactive, style);
+
+  set_frame(text_node->get_card_actual());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGButton::setup
+//       Access: Published
+//  Description: Sets up the button using the indicated NodePath as
+//               arbitrary geometry.
+////////////////////////////////////////////////////////////////////
+void PGButton::
+setup(const ArcChain &ready, const ArcChain &depressed, 
+      const ArcChain &rollover, const ArcChain &inactive) {
+  instance_to_state_def(S_ready, ready);
+  instance_to_state_def(S_depressed, depressed);
+  instance_to_state_def(S_rollover, rollover);
+  instance_to_state_def(S_inactive, inactive);
+}

+ 95 - 0
panda/src/pgui/pgButton.h

@@ -0,0 +1,95 @@
+// Filename: pgButton.h
+// Created by:  drose (03Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PGBUTTON_H
+#define PGBUTTON_H
+
+#include "pandabase.h"
+
+#include "pgItem.h"
+#include "arcChain.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : PGButton
+// Description : This is a particular kind of PGItem that is
+//               specialized to behave like a normal button object.
+//               It keeps track of its own state, and handles mouse
+//               events sensibly.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA PGButton : public PGItem {
+PUBLISHED:
+  PGButton(const string &name = "");
+  virtual ~PGButton();
+
+public:
+  PGButton(const PGButton &copy);
+  void operator = (const PGButton &copy);
+
+  virtual Node *make_copy() const;
+
+  virtual void enter();
+  virtual void exit();
+  virtual void button_down(ButtonHandle button);
+  virtual void button_up(ButtonHandle button, bool is_within);
+
+  virtual void click();
+
+PUBLISHED:
+  enum State {
+    S_ready = 0,
+    S_depressed,
+    S_rollover,
+    S_inactive
+  };
+
+  void setup(const string &label);
+  INLINE void setup(const ArcChain &ready);
+  INLINE void setup(const ArcChain &ready, const ArcChain &depressed);
+  INLINE void setup(const ArcChain &ready, const ArcChain &depressed, 
+                    const ArcChain &rollover);
+  void setup(const ArcChain &ready, const ArcChain &depressed,
+             const ArcChain &rollover, const ArcChain &inactive);
+
+  INLINE void set_active(bool active);
+
+  INLINE string get_click_event() const;
+
+private:
+  bool _button_down;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    PGItem::init_type();
+    register_type(_type_handle, "PGButton",
+                  PGItem::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 "pgButton.I"
+
+#endif

+ 150 - 0
panda/src/pgui/pgFrameStyle.I

@@ -0,0 +1,150 @@
+// Filename: pgFrameStyle.I
+// Created by:  drose (03Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: PGFrameStyle::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PGFrameStyle::
+PGFrameStyle() {
+  _type = T_none;
+  _color.set(1.0, 1.0, 1.0, 1.0);
+  _width = 0.01;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PGFrameStyle::
+PGFrameStyle(const PGFrameStyle &copy) :
+  _type(copy._type),
+  _color(copy._color),
+  _width(copy._width)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::Copy Assignment Operator
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void PGFrameStyle::
+operator = (const PGFrameStyle &copy) {
+  _type = copy._type;
+  _color = copy._color;
+  _width = copy._width;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::Destructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PGFrameStyle::
+~PGFrameStyle() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::set_type
+//       Access: Published
+//  Description: Sets the basic type of frame.
+////////////////////////////////////////////////////////////////////
+INLINE void PGFrameStyle::
+set_type(PGFrameStyle::Type type) {
+  _type = type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::get_type
+//       Access: Published
+//  Description: Returns the basic type of frame.
+////////////////////////////////////////////////////////////////////
+INLINE PGFrameStyle::Type PGFrameStyle::
+get_type() const {
+  return _type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::set_color
+//       Access: Published
+//  Description: Sets the dominant color of the frame.
+////////////////////////////////////////////////////////////////////
+INLINE void PGFrameStyle::
+set_color(float r, float g, float b, float a) {
+  set_color(Colorf(r, g, b, a));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::set_color
+//       Access: Published
+//  Description: Sets the dominant color of the frame.
+////////////////////////////////////////////////////////////////////
+INLINE void PGFrameStyle::
+set_color(const Colorf &color) {
+  _color = color;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::set_color
+//       Access: Published
+//  Description: Returns the dominant color of the frame.
+////////////////////////////////////////////////////////////////////
+INLINE const Colorf &PGFrameStyle::
+get_color() const {
+  return _color;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::set_width
+//       Access: Published
+//  Description: Sets the width parameter, which has meaning only for
+//               certain frame types.  For instance, this is the width
+//               of the bevel for T_bevel_in or T_bevel_out.  The
+//               units are in screen units.
+////////////////////////////////////////////////////////////////////
+INLINE void PGFrameStyle::
+set_width(float width) {
+  _width = width;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::get_width
+//       Access: Published
+//  Description: Returns the width parameter, which has meaning only
+//               for certain frame types.  For instance, this is the
+//               width of the bevel for T_bevel_in or T_bevel_out.
+//               The units are in screen units.
+////////////////////////////////////////////////////////////////////
+INLINE float PGFrameStyle::
+get_width() const {
+  return _width;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle ostream output
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE ostream &
+operator << (ostream &out, const PGFrameStyle &pfs) {
+  pfs.output(out);
+  return out;
+}

+ 133 - 0
panda/src/pgui/pgFrameStyle.cxx

@@ -0,0 +1,133 @@
+// Filename: pgFrameStyle.cxx
+// Created by:  drose (03Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pgFrameStyle.h"
+#include "geomTristrip.h"
+#include "geomNode.h"
+#include "transparencyProperty.h"
+#include "transparencyTransition.h"
+#include "renderRelation.h"
+
+ostream &
+operator << (ostream &out, PGFrameStyle::Type type) {
+  switch (type) {
+  case PGFrameStyle::T_none:
+    return out << "none";
+
+  case PGFrameStyle::T_flat:
+    return out << "flat";
+
+  case PGFrameStyle::T_bevel_out:
+    return out << "bevel_out";
+
+  case PGFrameStyle::T_bevel_in:
+    return out << "bevel_in";
+  }
+
+  return out << "**unknown(" << (int)type << ")**";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PGFrameStyle::
+output(ostream &out) const {
+  out << _type << " color = " << _color << " width = " << _width;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::generate_into
+//       Access: Public
+//  Description: Generates geometry representing a frame of the
+//               indicated size, and parents it to the indicated node,
+//               with a scene graph sort order of -1.
+//
+//               The return value is the generated arc, if any, or
+//               NULL if nothing is generated.
+////////////////////////////////////////////////////////////////////
+NodeRelation *PGFrameStyle::
+generate_into(Node *node, const LVecBase4f &frame) {
+  NodeRelation *arc = (NodeRelation *)NULL;
+  PT(Geom) geom;
+
+  switch (_type) {
+  case T_none:
+    return (NodeRelation *)NULL;
+
+  case T_flat:
+    geom = generate_flat_geom(frame);
+    break;
+
+  default:
+    break;
+  }
+
+  if (geom != (Geom *)NULL) {
+    // We've got a basic Geom; create a GeomNode for it.
+    PT(GeomNode) gnode = new GeomNode("frame");
+    gnode->add_geom(geom);
+    arc = new RenderRelation(node, gnode, -1);
+  }
+
+  if (arc != (NodeRelation *)NULL && _color[3] != 1.0) {
+    // We've got some alpha on the color; we need transparency.
+    TransparencyProperty::Mode mode = TransparencyProperty::M_alpha;
+    TransparencyTransition *tt = new TransparencyTransition(mode);
+    arc->set_transition(tt);
+  }
+
+  return arc;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGFrameStyle::generate_flat_geom
+//       Access: Public
+//  Description: Generates the Geom object appropriate to a T_flat
+//               frame.
+////////////////////////////////////////////////////////////////////
+PT(Geom) PGFrameStyle::
+generate_flat_geom(const LVecBase4f &frame) {
+  PT(Geom) geom = new GeomTristrip;
+
+  float left = frame[0];
+  float right = frame[1];
+  float bottom = frame[2];
+  float top = frame[3];
+
+  PTA_int lengths(0);
+  lengths.push_back(4);
+
+  PTA_Vertexf verts;
+  verts.push_back(Vertexf(left, 0.0, top));
+  verts.push_back(Vertexf(left, 0.0, bottom));
+  verts.push_back(Vertexf(right, 0.0, top));
+  verts.push_back(Vertexf(right, 0.0, bottom));
+
+  geom->set_num_prims(1);
+  geom->set_lengths(lengths);
+
+  geom->set_coords(verts, G_PER_VERTEX);
+
+  PTA_Colorf colors;
+  colors.push_back(_color);
+  geom->set_colors(colors, G_OVERALL);
+  
+  return geom;
+}

+ 79 - 0
panda/src/pgui/pgFrameStyle.h

@@ -0,0 +1,79 @@
+// Filename: pgFrameStyle.h
+// Created by:  drose (03Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PGFRAMESTYLE_H
+#define PGFRAMESTYLE_H
+
+#include "pandabase.h"
+
+#include "luse.h"
+#include "geom.h"
+#include "pointerTo.h"
+
+class NodeRelation;
+class Node;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PGFrameStyle
+// Description : 
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA PGFrameStyle {
+PUBLISHED:
+  INLINE PGFrameStyle();
+  INLINE PGFrameStyle(const PGFrameStyle &copy);
+  INLINE void operator = (const PGFrameStyle &copy);
+
+  INLINE ~PGFrameStyle();
+
+  enum Type {
+    T_none,
+    T_flat,
+    T_bevel_out,
+    T_bevel_in
+  };
+
+  INLINE void set_type(Type type);
+  INLINE Type get_type() const;
+
+  INLINE void set_color(float r, float g, float b, float a);
+  INLINE void set_color(const Colorf &color);
+  INLINE const Colorf &get_color() const;
+
+  INLINE void set_width(float width);
+  INLINE float get_width() const;
+
+  void output(ostream &out) const;
+
+public:
+  NodeRelation *generate_into(Node *node, const LVecBase4f &frame);
+
+private:
+  PT(Geom) generate_flat_geom(const LVecBase4f &frame);
+
+private:
+  Type _type;
+  Colorf _color;
+  float _width;
+};
+
+INLINE ostream &operator << (ostream &out, const PGFrameStyle &pfs);
+ostream &operator << (ostream &out, PGFrameStyle::Type type);
+
+#include "pgFrameStyle.I"
+
+#endif

+ 233 - 0
panda/src/pgui/pgItem.I

@@ -0,0 +1,233 @@
+// Filename: pgItem.I
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: PGItem::get_region
+//       Access: Public
+//  Description: Returns the MouseWatcherRegion associated with this
+//               item.  Every PGItem has a MouseWatcherRegion
+//               associated with it, that is created when the PGItem
+//               is created; it does not change during the lifetime of
+//               the PGItem.  Even items that do not have a frame have
+//               an associated MouseWatcherRegion, although it will
+//               not be used in this case.
+////////////////////////////////////////////////////////////////////
+INLINE PGMouseWatcherRegion *PGItem:: 
+get_region() const {
+  return _region;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::set_frame
+//       Access: Published
+//  Description: Sets the bounding rectangle of the item, in local
+//               coordinates.  This is the region on screen within
+//               which the mouse will be considered to be within the
+//               item.  Normally, it should correspond to the bounding
+//               rectangle of the visible geometry of the item.
+////////////////////////////////////////////////////////////////////
+INLINE void PGItem::
+set_frame(float left, float right, float bottom, float top) {
+  set_frame(LVecBase4f(left, right, bottom, top));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::set_frame
+//       Access: Published
+//  Description: Sets the bounding rectangle of the item, in local
+//               coordinates.  This is the region on screen within
+//               which the mouse will be considered to be within the
+//               item.  Normally, it should correspond to the bounding
+//               rectangle of the visible geometry of the item.
+////////////////////////////////////////////////////////////////////
+INLINE void PGItem::
+set_frame(const LVecBase4f &frame) {
+  _has_frame = true;
+  _frame = frame;
+  mark_frames_stale();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_frame
+//       Access: Published
+//  Description: Returns the bounding rectangle of the item.  See
+//               set_frame().  It is an error to call this if
+//               has_frame() returns false.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase4f &PGItem::
+get_frame() const {
+  nassertr(has_frame(), _frame);
+  return _frame;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::has_frame
+//       Access: Published
+//  Description: Returns true if the item has a bounding rectangle;
+//               see set_frame().
+////////////////////////////////////////////////////////////////////
+INLINE bool PGItem::
+has_frame() const {
+  return _has_frame;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::clear_frame
+//       Access: Published
+//  Description: Removes the bounding rectangle from the item.  It
+//               will no longer be possible to position the mouse
+//               within the item; see set_frame().
+////////////////////////////////////////////////////////////////////
+INLINE void PGItem::
+clear_frame() {
+  _has_frame = false;
+  mark_frames_stale();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::set_state
+//       Access: Published
+//  Description: Sets the "state" of this particular PGItem.  
+//
+//               The PGItem node will render as if it were the
+//               subgraph assigned to the corresponding index via
+//               set_state_def().
+////////////////////////////////////////////////////////////////////
+INLINE void PGItem::
+set_state(int state) {
+  _state = state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_state
+//       Access: Published
+//  Description: Returns the "state" of this particular PGItem.  See
+//               set_state().
+////////////////////////////////////////////////////////////////////
+INLINE int PGItem::
+get_state() const {
+  return _state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::set_active
+//       Access: Published
+//  Description: Sets whether the PGItem is active for mouse watching.
+//               This is not necessarily related to the
+//               active/inactive appearance of the item, which is
+//               controlled by set_state(), but it does affect whether
+//               it responds to mouse events.
+////////////////////////////////////////////////////////////////////
+INLINE void PGItem::
+set_active(bool active) {
+  _active = active;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_active
+//       Access: Published
+//  Description: Returns whether the PGItem is currently active for
+//               mouse events.  See set_active().
+////////////////////////////////////////////////////////////////////
+INLINE bool PGItem::
+get_active() const {
+  return _active;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_id
+//       Access: Published
+//  Description: Returns the unique ID assigned to this PGItem.  This
+//               will be assigned to the region created with the
+//               MouseWatcher, and will thus be used to generate event
+//               names.
+////////////////////////////////////////////////////////////////////
+INLINE const string &PGItem::
+get_id() const {
+  return _region->get_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_enter_event
+//       Access: Published
+//  Description: Returns the event name that will be thrown when the
+//               item is active and the mouse enters its frame.
+////////////////////////////////////////////////////////////////////
+INLINE string PGItem::
+get_enter_event() const {
+  return "enter-" + get_id();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_exit_event
+//       Access: Published
+//  Description: Returns the event name that will be thrown when the
+//               item is active and the mouse exits its frame.
+////////////////////////////////////////////////////////////////////
+INLINE string PGItem::
+get_exit_event() const {
+  return "exit-" + get_id();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_button_down_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 name of the button that generated the
+//               event.
+////////////////////////////////////////////////////////////////////
+INLINE string PGItem::
+get_button_down_event() const {
+  return "bdown-" + get_id();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_button_up_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 name of 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 released.
+////////////////////////////////////////////////////////////////////
+INLINE string PGItem::
+get_button_up_event() const {
+  return "bup-" + get_id();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::set_text_node
+//       Access: Published, Static
+//  Description: Changes the TextNode object that will be used by all
+//               PGItems to generate default labels given a string.
+//               This can be loaded with the default font, etc.
+////////////////////////////////////////////////////////////////////
+INLINE void PGItem::
+set_text_node(TextNode *node) {
+  _text_node = node;
+}

+ 396 - 0
panda/src/pgui/pgItem.cxx

@@ -0,0 +1,396 @@
+// Filename: pgItem.cxx
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pgItem.h"
+
+#include "namedNode.h"
+#include "throw_event.h"
+#include "string_utils.h"
+#include "arcChain.h"
+
+TypeHandle PGItem::_type_handle;
+PT(TextNode) PGItem::_text_node;
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGItem::
+PGItem(const string &name) : NamedNode(name)
+{
+  _has_frame = false;
+  _frame.set(0, 0, 0, 0);
+  _region = new PGMouseWatcherRegion(this);
+  _state = 0;
+  _active = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGItem::
+~PGItem() {
+  nassertv(_region->_item == this);
+  _region->_item = (PGItem *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGItem::
+PGItem(const PGItem &copy) :
+  NamedNode(copy),
+  _has_frame(copy._has_frame),
+  _frame(copy._frame),
+  _state(copy._state),
+  _active(copy._active)
+{
+  _region = new PGMouseWatcherRegion(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PGItem::
+operator = (const PGItem &copy) {
+  NamedNode::operator = (copy);
+  _has_frame = copy._has_frame;
+  _frame = copy._frame;
+  _state = copy._state;
+  _active = copy._active;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::make_copy
+//       Access: Public, Virtual
+//  Description: Returns a newly-allocated Node that is a shallow copy
+//               of this one.  It will be a different Node pointer,
+//               but its internal data may or may not be shared with
+//               that of the original Node.
+////////////////////////////////////////////////////////////////////
+Node *PGItem::
+make_copy() const {
+  return new PGItem(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::activate_region
+//       Access: Public, Virtual
+//  Description: Applies the indicated scene graph transform and order
+//               as determined by the traversal from PGTop.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+activate_region(const LMatrix4f &transform, int sort) {
+  LPoint3f ll(_frame[0], 0.0, _frame[2]);
+  LPoint3f ur(_frame[1], 0.0, _frame[3]);
+  ll = ll * transform;
+  ur = ur * transform;
+  _region->set_frame(ll[0], ur[0], ll[2], ur[2]);
+  _region->set_sort(sort);
+  _region->set_active(true);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::enter
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever the
+//               mouse enters the region.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+enter() {
+  throw_event(get_enter_event());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::exit
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever the
+//               mouse exits the region.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+exit() {
+  throw_event(get_exit_event());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::button_down
+//       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) {
+  throw_event(get_button_down_event(), button.get_name());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::button_up
+//       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.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+button_up(ButtonHandle button, bool is_within) {
+  throw_event(get_button_up_event(), 
+              EventParameter(button.get_name()), 
+              EventParameter(is_within));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_num_state_defs
+//       Access: Published
+//  Description: Returns one more than the highest-numbered state def
+//               that was ever assigned to the PGItem.  The complete
+//               set of state defs assigned may then be retrieved by
+//               indexing from 0 to (get_num_state_defs() - 1).
+//
+//               This is only an upper limit on the actual number of
+//               state defs, since there may be holes in the list.
+////////////////////////////////////////////////////////////////////
+int PGItem::
+get_num_state_defs() const {
+  return _state_defs.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::has_state_def
+//       Access: Published
+//  Description: Returns true if get_state_def() has ever been called
+//               for the indicated state (thus defining a render
+//               subgraph for this state index), false otherwise.
+////////////////////////////////////////////////////////////////////
+bool PGItem::
+has_state_def(int state) const {
+  if (state < 0 || state >= (int)_state_defs.size()) {
+    return false;
+  }
+  return (_state_defs[state]._node != (Node *)NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::clear_state_def
+//       Access: Published
+//  Description: Resets the NodePath assigned to the indicated state
+//               to its initial default, with only a frame
+//               representation if appropriate.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+clear_state_def(int state) {
+  if (state < 0 || state >= (int)_state_defs.size()) {
+    return;
+  }
+
+  Node *def = _state_defs[state]._node;
+  if (def != (Node *)NULL) {
+    // Remove all the children from this node.
+    int num_children = def->get_num_children(RenderRelation::get_class_type());
+    while (num_children > 0) {
+      nassertv(num_children == def->get_num_children(RenderRelation::get_class_type()));
+      NodeRelation *arc = 
+        def->get_child(RenderRelation::get_class_type(), num_children - 1);
+      remove_arc(arc);
+      num_children--;
+    }
+  }
+
+  _state_defs[state]._frame_arc = (NodeRelation *)NULL;
+  _state_defs[state]._frame_stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_state_def
+//       Access: Published
+//  Description: Returns the Node that is the root of the subgraph
+//               that will be drawn when the PGItem is in the
+//               indicated state.  The first time this is called for a
+//               particular state index, it may create the Node.
+////////////////////////////////////////////////////////////////////
+Node *PGItem::
+get_state_def(int state) {
+  nassertr(state < 1000, (Node *)NULL);  // Sanity check.
+  slot_state_def(state);
+
+  if (_state_defs[state]._node == (Node *)NULL) {
+    // Create a new node.
+    _state_defs[state]._node = new NamedNode("state_" + format_string(state));
+    _state_defs[state]._frame_stale = true;
+  }
+
+  if (_state_defs[state]._frame_stale) {
+    update_frame(state);
+  }
+
+  return _state_defs[state]._node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::instance_to_state_def
+//       Access: Published
+//  Description: Parents an instance of the bottom node of the
+//               indicated ArcChain (normally a NodePath) to the
+//               indicated state index.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+instance_to_state_def(int state, const ArcChain &chain) {
+  if (chain.empty()) {
+    // If the chain is empty, quietly do nothing.
+    return;
+  }
+
+  NodeRelation *new_arc = 
+    new RenderRelation(get_state_def(state), chain.node());
+
+  if (chain.has_arcs()) {
+    // If the chain has an arc, copy the transitions from it.
+    new_arc->copy_transitions_from(chain.arc());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_frame_style
+//       Access: Published
+//  Description: Returns the kind of frame that will be drawn behind
+//               the item when it is in the indicated state.
+////////////////////////////////////////////////////////////////////
+PGFrameStyle PGItem::
+get_frame_style(int state) {
+  if (state < 0 || state >= (int)_state_defs.size()) {
+    return PGFrameStyle();
+  }
+  return _state_defs[state]._frame_style;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::set_frame_style
+//       Access: Published
+//  Description: Changes the kind of frame that will be drawn behind
+//               the item when it is in the indicated state.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+set_frame_style(int state, const PGFrameStyle &style) {
+  // Get the state def node, mainly to ensure that this state is
+  // slotted and listed as having been defined.
+  Node *def = get_state_def(state);
+  nassertv(def != (Node *)NULL);
+
+  _state_defs[state]._frame_style = style;
+  _state_defs[state]._frame_stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::get_text_node
+//       Access: Published, Static
+//  Description: Returns the TextNode object that will be used by all
+//               PGItems to generate default labels given a string.
+//               This can be loaded with the default font, etc.
+////////////////////////////////////////////////////////////////////
+TextNode *PGItem::
+get_text_node() {
+  if (_text_node == (TextNode *)NULL) {
+    _text_node = new TextNode("pguiText");
+    _text_node->freeze();
+    _text_node->set_text_color(0.0, 0.0, 0.0, 1.0);
+    _text_node->set_align(TM_ALIGN_CENTER);
+  }
+  return _text_node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::slot_state_def
+//       Access: Private
+//  Description: Ensures there is a slot in the array for the given
+//               state definition.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+slot_state_def(int state) {
+  while (state >= (int)_state_defs.size()) {
+    StateDef def;
+    def._frame_stale = true;
+    _state_defs.push_back(def);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::update_frame
+//       Access: Private
+//  Description: Generates a new instance of the frame geometry for
+//               the indicated state.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+update_frame(int state) {
+  // First, remove the old frame geometry, if any.
+  if (state >= 0 && state < (int)_state_defs.size()) {
+    NodeRelation *old_arc = _state_defs[state]._frame_arc;
+    if (old_arc != (NodeRelation *)NULL) {
+      if (old_arc->is_attached()) {
+        remove_arc(old_arc);
+        _state_defs[state]._frame_arc = (NodeRelation *)NULL;
+      }
+    }
+  }
+
+  // We must turn off the stale flag first, before we call
+  // get_state_def(), to prevent get_state_def() from being a
+  // recursive call.
+  _state_defs[state]._frame_stale = false;
+
+  // Now create new frame geometry.
+  if (has_frame()) {
+    Node *node = get_state_def(state);
+    nassertv(node != (Node *)NULL);
+    
+    _state_defs[state]._frame_arc = 
+      _state_defs[state]._frame_style.generate_into(node, _frame);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::mark_frames_stale
+//       Access: Private
+//  Description: Marks all the frames in all states stale, so that
+//               they will be regenerated the next time each state is
+//               requested.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+mark_frames_stale() {
+  StateDefs::iterator di;
+  for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
+    // Remove the old frame, if any.
+    NodeRelation *old_arc = (*di)._frame_arc;
+    if (old_arc != (NodeRelation *)NULL) {
+      if (old_arc->is_attached()) {
+        remove_arc(old_arc);
+        (*di)._frame_arc = (NodeRelation *)NULL;
+      }
+    }
+
+    (*di)._frame_stale = true;
+  }
+}

+ 145 - 0
panda/src/pgui/pgItem.h

@@ -0,0 +1,145 @@
+// Filename: pgItem.h
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PGITEM_H
+#define PGITEM_H
+
+#include "pandabase.h"
+
+#include "pgMouseWatcherRegion.h"
+#include "pgFrameStyle.h"
+
+#include "namedNode.h"
+#include "nodeRelation.h"
+#include "luse.h"
+#include "pointerTo.h"
+#include "pt_Node.h"
+#include "pt_NodeRelation.h"
+#include "textNode.h"
+
+class ArcChain;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PGItem
+// Description : This is the base class for all the various kinds of
+//               gui widget objects.
+//
+//               It is a Node which corresponds to a rectangular
+//               region on the screen, and it may have any number of
+//               "state" subgraphs, one of which is rendered at any
+//               given time according to its current state.
+//
+//               The PGItem node must be parented to the scene graph
+//               somewhere beneath a PGTop node in order for this
+//               behavior to work.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA PGItem : public NamedNode {
+PUBLISHED:
+  PGItem(const string &name = "");
+  virtual ~PGItem();
+
+public:
+  PGItem(const PGItem &copy);
+  void operator = (const PGItem &copy);
+
+  virtual Node *make_copy() const;
+
+  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);
+  virtual void button_up(ButtonHandle button, bool is_within);
+
+PUBLISHED:
+  INLINE void set_frame(float left, float right, float bottom, float top);
+  INLINE void set_frame(const LVecBase4f &frame);
+  INLINE const LVecBase4f &get_frame() const;
+  INLINE bool has_frame() const;
+  INLINE void clear_frame();
+
+  INLINE void set_state(int state);
+  INLINE int get_state() const;
+
+  INLINE void set_active(bool active);
+  INLINE bool get_active() const;
+
+  int get_num_state_defs() const;
+  void clear_state_def(int state);
+  bool has_state_def(int state) const;
+  Node *get_state_def(int state);
+  void instance_to_state_def(int state, const ArcChain &chain);
+
+  PGFrameStyle get_frame_style(int state);
+  void set_frame_style(int state, const PGFrameStyle &style);
+
+  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;
+
+  static TextNode *get_text_node();
+  INLINE static void set_text_node(TextNode *node);
+
+private:
+  void slot_state_def(int state);
+  void update_frame(int state);
+  void mark_frames_stale();
+
+  bool _has_frame;
+  LVecBase4f _frame;
+  int _state;
+  bool _active;
+
+  PT(PGMouseWatcherRegion) _region;
+
+  class StateDef {
+  public:
+    PT_Node _node;
+    PGFrameStyle _frame_style;
+    PT_NodeRelation _frame_arc;
+    bool _frame_stale;
+  };
+  typedef pvector<StateDef> StateDefs;
+  StateDefs _state_defs;
+
+  static PT(TextNode) _text_node;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    NamedNode::init_type();
+    register_type(_type_handle, "PGItem",
+                  NamedNode::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 "pgItem.I"
+
+#endif

+ 18 - 0
panda/src/pgui/pgMouseWatcherRegion.I

@@ -0,0 +1,18 @@
+// Filename: pgMouseWatcherRegion.I
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 106 - 0
panda/src/pgui/pgMouseWatcherRegion.cxx

@@ -0,0 +1,106 @@
+// Filename: pgMouseWatcherRegion.cxx
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pgMouseWatcherRegion.h"
+#include "pgItem.h"
+
+#include "string_utils.h"
+
+TypeHandle PGMouseWatcherRegion::_type_handle;
+int PGMouseWatcherRegion::_next_index = 0;
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherRegion::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGMouseWatcherRegion::
+PGMouseWatcherRegion(PGItem *item) :
+#ifndef CPPPARSER
+  MouseWatcherRegion("pg" + format_string(_next_index++), 0, 0, 0, 0),
+#endif
+  _item(item)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherRegion::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGMouseWatcherRegion::
+~PGMouseWatcherRegion() {
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherRegion::enter
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever the
+//               mouse enters the region.
+////////////////////////////////////////////////////////////////////
+void PGMouseWatcherRegion::
+enter() {
+  if (_item != (PGItem *)NULL) {
+    _item->enter();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherRegion::exit
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever the
+//               mouse exits the region.
+////////////////////////////////////////////////////////////////////
+void PGMouseWatcherRegion::
+exit() {
+  if (_item != (PGItem *)NULL) {
+    _item->exit();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherRegion::button_down
+//       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) {
+  if (_item != (PGItem *)NULL) {
+    _item->button_down(button);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherRegion::button_up
+//       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.
+////////////////////////////////////////////////////////////////////
+void PGMouseWatcherRegion::
+button_up(ButtonHandle button, bool is_within) {
+  if (_item != (PGItem *)NULL) {
+    _item->button_up(button, is_within);
+  }
+}

+ 71 - 0
panda/src/pgui/pgMouseWatcherRegion.h

@@ -0,0 +1,71 @@
+// Filename: pgMouseWatcherRegion.h
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PGMOUSEWATCHERREGION_H
+#define PGMOUSEWATCHERREGION_H
+
+#include "pandabase.h"
+
+#include "mouseWatcherRegion.h"
+
+class PGItem;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PGMouseWatcherRegion
+// Description : This is a specialization on MouseWatcherRegion, to
+//               add a bit more fields that are relevant to the PG
+//               system.  Each PGItem corresponds to exactly one
+//               PGMouseWatcherRegion.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA PGMouseWatcherRegion : public MouseWatcherRegion {
+public:
+  PGMouseWatcherRegion(PGItem *item);
+  virtual ~PGMouseWatcherRegion();
+
+  virtual void enter();
+  virtual void exit();
+  virtual void button_down(ButtonHandle button);
+  virtual void button_up(ButtonHandle button, bool is_within);
+
+private:
+  PGItem *_item;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    MouseWatcherRegion::init_type();
+    register_type(_type_handle, "PGMouseWatcherRegion",
+                  MouseWatcherRegion::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;
+  static int _next_index;
+
+  friend class PGItem;
+};
+
+#include "pgMouseWatcherRegion.I"
+
+#endif

+ 56 - 0
panda/src/pgui/pgTop.I

@@ -0,0 +1,56 @@
+// Filename: pgTop.I
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: PGTop::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PGTop::
+PGTop(const PGTop &copy) :
+  NamedNode(copy),
+  _watcher(copy._watcher)
+{
+  _gsg = (GraphicsStateGuardian *)NULL;
+  _trav = (RenderTraverser *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGTop::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void PGTop::
+operator = (const PGTop &copy) {
+  NamedNode::operator = (copy);
+  _watcher = copy._watcher;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGTop::get_mouse_watcher
+//       Access: Published
+//  Description: Returns the MouseWatcher pointer that the PGTop object
+//               registers its PG items with, or NULL if the
+//               MouseWatcher has not yet been set.
+////////////////////////////////////////////////////////////////////
+INLINE MouseWatcher *PGTop::
+get_mouse_watcher() const {
+  return _watcher;
+}

+ 256 - 0
panda/src/pgui/pgTop.cxx

@@ -0,0 +1,256 @@
+// Filename: pgTop.cxx
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pgTop.h"
+#include "pgItem.h"
+
+#include "arcChain.h"
+#include "graphicsStateGuardian.h"
+#include "config_sgraphutil.h"
+#include "renderRelation.h"
+#include "geomNode.h"
+#include "allTransitionsWrapper.h"
+#include "allAttributesWrapper.h"
+#include "wrt.h"
+#include "switchNode.h"
+#include "transformTransition.h"
+#include "nodeTransitionWrapper.h"
+#include "directRenderTraverser.h"
+#include "omniBoundingVolume.h"
+#include "pruneTransition.h"
+
+TypeHandle PGTop::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGTop::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGTop::
+PGTop(const string &name) : NamedNode(name)
+{
+  _gsg = (GraphicsStateGuardian *)NULL;
+  _trav = (RenderTraverser *)NULL;
+
+  // A PGTop node normally has an infinite bounding volume.  Screw
+  // culling.
+  set_bound(OmniBoundingVolume());
+  set_final(true);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGTop::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PGTop::
+~PGTop() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGTop::make_copy
+//       Access: Public, Virtual
+//  Description: Returns a newly-allocated Node that is a shallow copy
+//               of this one.  It will be a different Node pointer,
+//               but its internal data may or may not be shared with
+//               that of the original Node.
+////////////////////////////////////////////////////////////////////
+Node *PGTop::
+make_copy() const {
+  return new PGTop(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGTop::sub_render
+//       Access: Public, Virtual
+//  Description: Gets called during the draw traversal to render this
+//               node and all nodes below it.  In the case of the
+//               PGTop node, this uses a depth-first left-to-right
+//               traversal to render all of the GeomNodes and PGItems
+//               in the scene graph order.
+////////////////////////////////////////////////////////////////////
+bool PGTop::
+sub_render(const AllAttributesWrapper &attrib, AllTransitionsWrapper &,
+           RenderTraverser *trav) {
+  _attrib = attrib;
+  _gsg = trav->get_gsg();
+  const ArcChain &chain = trav->get_arc_chain();
+
+  // Empty our set of regions in preparation for re-adding whichever
+  // ones we encounter in the traversal that are current.
+  clear_regions();
+  _sort_index = 0;
+
+  // Start the traversal below the current node.
+  const DownRelationPointers &drp = 
+    find_connection(RenderRelation::get_class_type()).get_down();
+  
+  DownRelationPointers::const_iterator drpi;
+  for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
+    NodeRelation *arc = (*drpi);
+    if (!arc->has_transition(PruneTransition::get_class_type())) {
+      ArcChain next_chain(chain);
+      next_chain.push_back(arc);
+      r_traverse(arc->get_child(), next_chain);
+    }
+  }
+
+  // We don't need the normal render traverser to do anything else;
+  // we've done it all.
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGTop::has_sub_render
+//       Access: Public, Virtual
+//  Description: Should be redefined to return true if the function
+//               sub_render(), above, expects to be called during
+//               traversal.
+////////////////////////////////////////////////////////////////////
+bool PGTop::
+has_sub_render() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGTop::set_mouse_watcher
+//       Access: Published
+//  Description: Sets the MouseWatcher pointer that the PGTop object
+//               registers its PG items with.  This must be set before
+//               the PG items are active.
+////////////////////////////////////////////////////////////////////
+void PGTop::
+set_mouse_watcher(MouseWatcher *watcher) {
+  if (_watcher != (MouseWatcher *)NULL) {
+    _watcher->remove_group(this);
+  }
+  _watcher = watcher;
+  if (_watcher != (MouseWatcher *)NULL) {
+    _watcher->add_group(this);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGTop::r_traverse
+//       Access: Private
+//  Description: Handles the main recursive traversal of the scene
+//               graph for nodes below the PGTop node.  This
+//               implements a depth-first traversal.
+////////////////////////////////////////////////////////////////////
+void PGTop::
+r_traverse(Node *node, const ArcChain &chain) {
+  if (implicit_app_traversal) {
+    node->app_traverse();
+  }
+  node->draw_traverse();
+  _gsg->_nodes_pcollector.add_level(1);
+
+
+  if (node->is_of_type(PGItem::get_class_type())) {
+    PGItem *pgi = DCAST(PGItem, node);
+
+    if (pgi->has_frame() && pgi->get_active()) {
+      // The item has a frame, so we want to generate a region for it
+      // and update the MouseWatcher.
+
+      // Get the complete net transform to the PGItem from the top.
+      LMatrix4f mat;
+      
+      NodeTransitionWrapper ntw(TransformTransition::get_class_type());
+      wrt(pgi, chain.begin(), chain.end(), (Node *)NULL, 
+          ntw, RenderRelation::get_class_type());
+      const TransformTransition *tt;
+      if (!get_transition_into(tt, ntw)) {
+        // No relative transform.
+        mat = LMatrix4f::ident_mat();
+        return;
+      }
+      
+      mat = tt->get_matrix();
+      
+      // Now apply this transform to the item's frame.
+      pgi->activate_region(mat, _sort_index);
+      _sort_index++;
+
+      add_region(pgi->get_region());
+    }
+
+    if (pgi->has_state_def(pgi->get_state())) {
+      // This item has a current state definition that we should use
+      // to render the item.
+      Node *def = pgi->get_state_def(pgi->get_state());
+
+      // Get the net transitions to the PGItem.
+      AllTransitionsWrapper complete_trans;
+      wrt(pgi, chain.begin(), chain.end(), this,
+          complete_trans, RenderRelation::get_class_type());
+
+      // We'll use a normal DirectRenderTraverser to do the rendering
+      // of the subgraph.
+      DirectRenderTraverser drt(_gsg, RenderRelation::get_class_type());
+      drt.traverse(def, _attrib, complete_trans);
+    }
+
+  } else if (node->is_of_type(GeomNode::get_class_type())) {
+    _gsg->_geom_nodes_pcollector.add_level(1);
+    GeomNode *geom = DCAST(GeomNode, node);
+
+    // Get the complete state of the GeomNode.
+    AllTransitionsWrapper complete_trans;
+    wrt(geom, chain.begin(), chain.end(), this,
+        complete_trans, RenderRelation::get_class_type());
+    AllAttributesWrapper complete_state;
+    complete_state.apply_from(_attrib, complete_trans);
+    _gsg->set_state(complete_state.get_attributes(), true);
+
+    // Finally, draw the Geom.
+    _gsg->prepare_display_region();
+    geom->draw(_gsg);
+  }
+
+
+  // Continue the traversal.
+  const DownRelationPointers &drp =
+    node->find_connection(RenderRelation::get_class_type()).get_down();
+  
+  if (node->is_of_type(SwitchNode::get_class_type())) {
+    SwitchNode *swnode = DCAST(SwitchNode, node);
+    swnode->compute_switch(_trav);
+    size_t i = 0;
+    for (i = 0; i < drp.size(); i++) {
+      if (swnode->is_child_visible(RenderRelation::get_class_type(), i)) {
+        NodeRelation *arc = drp[i];
+        if (!arc->has_transition(PruneTransition::get_class_type())) {
+          ArcChain next_chain(chain);
+          next_chain.push_back(arc);
+          r_traverse(arc->get_child(), next_chain);
+        }
+      }
+    }
+  } else {
+    DownRelationPointers::const_iterator drpi;
+    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
+      NodeRelation *arc = (*drpi);
+      if (!arc->has_transition(PruneTransition::get_class_type())) {
+        ArcChain next_chain(chain);
+        next_chain.push_back(arc);
+        r_traverse(arc->get_child(), next_chain);
+      }
+    }
+  }
+}

+ 99 - 0
panda/src/pgui/pgTop.h

@@ -0,0 +1,99 @@
+// Filename: pgTop.h
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PGTOP_H
+#define PGTOP_H
+
+#include "pandabase.h"
+
+#include "namedNode.h"
+#include "mouseWatcherGroup.h"
+#include "mouseWatcher.h"
+#include "pointerTo.h"
+#include "allAttributesWrapper.h"
+
+class GraphicsStateGuardian;
+class RenderTraverser;
+class ArcChain;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PGTop
+// Description : The "top" node of the new Panda GUI system.  This
+//               node must be parented to the 2-d scene graph, and all
+//               PG objects should be parented to this node or
+//               somewhere below it.  PG objects not parented within
+//               this hierarchy will not even be visible.
+//
+//               This node begins the special traversal of the PG
+//               objects that registers each node within the
+//               MouseWatcher and forces everything to render in a
+//               depth-first, left-to-right order, appropriate for 2-d
+//               objects.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA PGTop : public NamedNode, public MouseWatcherGroup {
+PUBLISHED:
+  PGTop(const string &name = "");
+  virtual ~PGTop();
+
+public:
+  INLINE PGTop(const PGTop &copy);
+  INLINE void operator = (const PGTop &copy);
+
+  virtual Node *make_copy() const;
+
+  virtual bool sub_render(const AllAttributesWrapper &attrib,
+                          AllTransitionsWrapper &trans,
+                          RenderTraverser *trav);
+  virtual bool has_sub_render() const;
+
+PUBLISHED:
+  void set_mouse_watcher(MouseWatcher *watcher);
+  INLINE MouseWatcher *get_mouse_watcher() const;
+
+private:
+  void r_traverse(Node *node, const ArcChain &chain);
+
+  PT(MouseWatcher) _watcher;
+  GraphicsStateGuardian *_gsg;
+  RenderTraverser *_trav;
+  AllAttributesWrapper _attrib;
+  int _sort_index;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    NamedNode::init_type();
+    MouseWatcherGroup::init_type();
+    register_type(_type_handle, "PGTop",
+                  NamedNode::get_class_type(),
+                  MouseWatcherGroup::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 "pgTop.I"
+
+#endif

+ 25 - 83
panda/src/sgmanip/nodePath.I

@@ -51,6 +51,26 @@ NodePath(Node *top_node, TypeHandle graph_type) :
 {
 {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::Constructor
+//       Access: Public
+//  Description: Creates a NodePath that contains one arc, and the two
+//               Nodes connected to that arc.
+//
+//               If the NodeRelation pointer is NULL, this quietly
+//               creates an empty NodePath.
+////////////////////////////////////////////////////////////////////
+INLINE NodePath::
+NodePath(NodeRelation *arc) :
+  _graph_type(RenderRelation::get_class_type()),
+  _error_type(ET_ok)
+{
+  if (arc != (NodeRelation *)NULL) {
+    _graph_type = arc->get_type();
+    extend_by(arc);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::Constructor
 //     Function: NodePath::Constructor
 //       Access: Public
 //       Access: Public
@@ -183,12 +203,9 @@ compare_to(const NodePath &other) const {
 //       Access: Public
 //       Access: Public
 //  Description: Changes the type of graph that the NodePath will
 //  Description: Changes the type of graph that the NodePath will
 //               search for.  By default, this is RenderRelation.
 //               search for.  By default, this is RenderRelation.
-//               This may only be called when the NodePath contains no
-//               arcs (e.g. is_empty() || is_singleton()).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
 INLINE void NodePath::
 set_graph_type(TypeHandle graph_type) {
 set_graph_type(TypeHandle graph_type) {
-  nassertv(_head == (ArcComponent *)NULL);
   _graph_type = graph_type;
   _graph_type = graph_type;
 }
 }
 
 
@@ -242,17 +259,6 @@ get_max_search_depth() {
   return _max_search_depth;
   return _max_search_depth;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::is_empty
-//       Access: Public
-//  Description: Returns true if the NodePath contains no nodes and no
-//               arcs.
-////////////////////////////////////////////////////////////////////
-INLINE bool NodePath::
-is_empty() const {
-  return !ArcChain::has_node();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::get_error_type
 //     Function: NodePath::get_error_type
 //       Access: Public
 //       Access: Public
@@ -264,74 +270,6 @@ get_error_type() const {
   return _error_type;
   return _error_type;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::is_singleton
-//       Access: Public
-//  Description: Returns true if the NodePath contains exactly one
-//               node, and no arcs.
-////////////////////////////////////////////////////////////////////
-INLINE bool NodePath::
-is_singleton() const {
-  return ArcChain::has_node() && !ArcChain::has_arcs();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::has_arcs
-//       Access: Public
-//  Description: Returns true if the NodePath contains at least one
-//               arc, and therefore at least two nodes.  This is the
-//               same thing as asking get_num_arcs() > 0, but is
-//               easier to compute.
-////////////////////////////////////////////////////////////////////
-INLINE bool NodePath::
-has_arcs() const {
-  return ArcChain::has_arcs();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_num_arcs
-//       Access: Public
-//  Description: Returns the number of arcs in the path.
-////////////////////////////////////////////////////////////////////
-INLINE int NodePath::
-get_num_arcs() const {
-  if (!has_arcs()) {
-    return 0;
-  }
-  return get_num_nodes() - 1;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::node
-//       Access: Public
-//  Description: Returns the bottom node of the path, or NULL if the
-//               path is empty.
-////////////////////////////////////////////////////////////////////
-INLINE Node *NodePath::
-node() const {
-  nassertr(_error_type == ET_ok, (Node *)NULL);
-  if (is_empty()) {
-    return (Node *)NULL;
-  }
-  return _head->get_node();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::arc
-//       Access: Public
-//  Description: Returns the bottom arc of the path, or NULL if the
-//               path is empty or is a singleton.
-////////////////////////////////////////////////////////////////////
-INLINE NodeRelation *NodePath::
-arc() const {
-  nassertr(_error_type == ET_ok, (NodeRelation *)NULL);
-  if (!has_arcs()) {
-    // A singleton or empty list.
-    return (NodeRelation *)NULL;
-  }
-  return _head->get_arc();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::get_num_children
 //     Function: NodePath::get_num_children
 //       Access: Public
 //       Access: Public
@@ -449,7 +387,11 @@ attach_new_node(const string &name, int sort) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
 INLINE void NodePath::
 output(ostream &out) const {
 output(ostream &out) const {
-  out << as_string(0);
+  if (_error_type == ET_ok && is_empty()) {
+    out << "**empty**";
+  } else {
+    out << as_string(0);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 0 - 99
panda/src/sgmanip/nodePath.cxx

@@ -150,16 +150,6 @@ extend_by(NodeRelation *darc) {
     return false;
     return false;
   }
   }
 
 
-  if (darc->get_type() != get_graph_type() &&
-      darc->get_type() != NodeRelation::get_stashed_type()) {
-    if (sgmanip_cat.is_debug()) {
-      sgmanip_cat.debug()
-        << "Cannot extend " << *this << " by arc " << *darc
-        << "; wrong graph type.\n";
-    }
-    return false;
-  }
-
   _head = new ArcComponent(darc, _head);
   _head = new ArcComponent(darc, _head);
 
 
   return true;
   return true;
@@ -418,95 +408,6 @@ find_singular_transform() const {
   return NodePath::not_found();
   return NodePath::not_found();
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_node
-//       Access: Public
-//  Description: Returns the nth node of the path, where 0 is the
-//               bottom node and get_num_nodes() - 1 is the top node.
-//               This requires iterating through the path.
-////////////////////////////////////////////////////////////////////
-Node *NodePath::
-get_node(int index) const {
-  nassertr(index >= 0 && index < get_num_nodes(), NULL);
-
-  ArcComponent *comp = _head;
-  while (index > 0) {
-    // If this assertion fails, the index was out of range.
-    nassertr(comp != (ArcComponent *)NULL, NULL);
-    comp = comp->get_next();
-    index--;
-  }
-
-  // If this assertion fails, the index was out of range.
-  nassertr(comp != (ArcComponent *)NULL, NULL);
-  return comp->get_node();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_num_nodes
-//       Access: Public
-//  Description: Returns the number of nodes in the path.  This is
-//               always one more than the number of arcs (except for
-//               a completely empty path).
-////////////////////////////////////////////////////////////////////
-int NodePath::
-get_num_nodes() const {
-  int num = 0;
-  ArcComponent *comp = _head;
-  while (comp != (ArcComponent *)NULL) {
-    num++;
-    comp = comp->get_next();
-  }
-  return num;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_arc
-//       Access: Public
-//  Description: Returns the nth arc of the path, where 0 is the arc
-//               above the bottom node node and get_num_arcs() - 1 is
-//               the arc below the top node.  This requires iterating
-//               through the path.
-////////////////////////////////////////////////////////////////////
-NodeRelation *NodePath::
-get_arc(int index) const {
-  nassertr(index >= 0 && index < get_num_arcs(), NULL);
-
-  ArcComponent *comp = _head;
-  while (index > 0) {
-    // If this assertion fails, the index was out of range.
-    nassertr(comp != (ArcComponent *)NULL, NULL);
-    comp = comp->get_next();
-    index--;
-  }
-
-  // If either assertion fails, the index was out of range.
-  nassertr(comp != (ArcComponent *)NULL, NULL);
-  nassertr(comp->has_arc(), NULL);
-  return comp->get_arc();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_top_node
-//       Access: Public
-//  Description: Returns the top node of the path, or NULL if the path
-//               is empty.  This requires iterating through the path.
-////////////////////////////////////////////////////////////////////
-Node *NodePath::
-get_top_node() const {
-  if (is_empty()) {
-    return (Node *)NULL;
-  }
-
-  ArcComponent *comp = _head;
-  while (!comp->is_top_node()) {
-    comp = comp->get_next();
-    nassertr(comp != (ArcComponent *)NULL, NULL);
-  }
-
-  return comp->get_node();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::share_with
 //     Function: NodePath::share_with
 //       Access: Public
 //       Access: Public

+ 2 - 11
panda/src/sgmanip/nodePath.h

@@ -148,6 +148,7 @@ PUBLISHED:
 
 
   INLINE NodePath(TypeHandle graph_type = RenderRelation::get_class_type());
   INLINE NodePath(TypeHandle graph_type = RenderRelation::get_class_type());
   INLINE NodePath(Node *top_node, TypeHandle graph_type = RenderRelation::get_class_type());
   INLINE NodePath(Node *top_node, TypeHandle graph_type = RenderRelation::get_class_type());
+  INLINE NodePath(NodeRelation *arc);
   INLINE NodePath(const ArcChain &chain, TypeHandle graph_type);
   INLINE NodePath(const ArcChain &chain, TypeHandle graph_type);
 
 
   INLINE NodePath(const NodePath &copy);
   INLINE NodePath(const NodePath &copy);
@@ -183,19 +184,9 @@ PUBLISHED:
 
 
   // Methods to query a NodePath's contents.
   // Methods to query a NodePath's contents.
 
 
-  INLINE bool is_empty() const;
   INLINE ErrorType get_error_type() const;
   INLINE ErrorType get_error_type() const;
-  INLINE bool is_singleton() const;
-  INLINE bool has_arcs() const;
-  int get_num_nodes() const;
-  Node *get_node(int index) const;
 
 
-  INLINE int get_num_arcs() const;
-  NodeRelation *get_arc(int index) const;
-
-  Node *get_top_node() const;
-  INLINE Node *node() const;
-  INLINE NodeRelation *arc() const;
+  // Most of these methods are inherited from ArcChain.
 
 
 
 
   // Methods to manage the disconnected NodePaths that can result if
   // Methods to manage the disconnected NodePaths that can result if

+ 1 - 1
panda/src/sgraphutil/frustumCullTraverser.I

@@ -74,7 +74,7 @@ FrustumCullTraverser(ArcChain &arc_chain, Node *root,
     }
     }
   }
   }
 
 
-  bool needs_top_node = !_arc_chain.has_node();
+  bool needs_top_node = _arc_chain.is_empty();
   if (needs_top_node) {
   if (needs_top_node) {
     // If the ArcChain supplied in is initially empty, put the root
     // If the ArcChain supplied in is initially empty, put the root
     // node in it.
     // node in it.

+ 9 - 7
panda/src/tform/Sources.pp

@@ -10,15 +10,17 @@
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx 
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx 
 
 
   #define SOURCES  \
   #define SOURCES  \
-     buttonThrower.h config_tform.h dataValve.I dataValve.h  \
-     driveInterface.I driveInterface.h mouseWatcher.I  \
-     mouseWatcher.h mouseWatcherRegion.I mouseWatcherRegion.h  \
-     planarSlider.h trackball.h transform2sg.h  
+    buttonThrower.h config_tform.h dataValve.I dataValve.h  \
+    driveInterface.I driveInterface.h mouseWatcher.I  \
+    mouseWatcher.h mouseWatcherGroup.h \
+    mouseWatcherRegion.I mouseWatcherRegion.h  \
+    planarSlider.h trackball.h transform2sg.h  
      
      
   #define INCLUDED_SOURCES  \
   #define INCLUDED_SOURCES  \
-     buttonThrower.cxx config_tform.cxx dataValve.cxx  \
-     driveInterface.cxx mouseWatcher.cxx mouseWatcherRegion.cxx  \
-     planarSlider.cxx trackball.cxx transform2sg.cxx 
+    buttonThrower.cxx config_tform.cxx dataValve.cxx  \
+    driveInterface.cxx mouseWatcher.cxx mouseWatcherGroup.cxx \
+    mouseWatcherRegion.cxx  \
+    planarSlider.cxx trackball.cxx transform2sg.cxx 
 
 
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
     buttonThrower.h dataValve.I dataValve.h \
     buttonThrower.h dataValve.I dataValve.h \

+ 2 - 0
panda/src/tform/config_tform.cxx

@@ -22,6 +22,7 @@
 #include "driveInterface.h"
 #include "driveInterface.h"
 #include "buttonThrower.h"
 #include "buttonThrower.h"
 #include "mouseWatcher.h"
 #include "mouseWatcher.h"
+#include "mouseWatcherGroup.h"
 #include "mouseWatcherRegion.h"
 #include "mouseWatcherRegion.h"
 #include "planarSlider.h"
 #include "planarSlider.h"
 #include "trackball.h"
 #include "trackball.h"
@@ -49,6 +50,7 @@ ConfigureFn(config_tform) {
   DriveInterface::init_type();
   DriveInterface::init_type();
   ButtonThrower::init_type();
   ButtonThrower::init_type();
   MouseWatcher::init_type();
   MouseWatcher::init_type();
+  MouseWatcherGroup::init_type();
   MouseWatcherRegion::init_type();
   MouseWatcherRegion::init_type();
   PlanarSlider::init_type();
   PlanarSlider::init_type();
   Trackball::init_type();
   Trackball::init_type();

+ 1 - 1
panda/src/tform/mouseWatcher.I

@@ -296,7 +296,7 @@ set_extra_handler(EventHandler *eh) {
 //               can be registered with a mouseWatcher so that events
 //               can be registered with a mouseWatcher so that events
 //               can be dealt with much sooner.
 //               can be dealt with much sooner.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE EventHandler* MouseWatcher::
+INLINE EventHandler *MouseWatcher::
 get_extra_handler(void) const {
 get_extra_handler(void) const {
   return _eh;
   return _eh;
 }
 }

+ 83 - 52
panda/src/tform/mouseWatcher.cxx

@@ -59,34 +59,10 @@ MouseWatcher::
 ~MouseWatcher() {
 ~MouseWatcher() {
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: MouseWatcher::add_region
-//       Access: Published
-//  Description: Adds the indicated region to the set of regions that
-//               are to be watched.  Returns true if it was
-//               successfully added, or false if it was already on the
-//               list.
-////////////////////////////////////////////////////////////////////
-bool MouseWatcher::
-add_region(MouseWatcherRegion *region) {
-  return _regions.insert(region).second;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MouseWatcher::has_region
-//       Access: Published
-//  Description: Returns true if the indicated region has already been
-//               added to the MouseWatcher, false otherwise.
-////////////////////////////////////////////////////////////////////
-bool MouseWatcher::
-has_region(MouseWatcherRegion *region) const {
-  return _regions.count(region) != 0;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MouseWatcher::remove_region
 //     Function: MouseWatcher::remove_region
 //       Access: Published
 //       Access: Published
-//  Description: Removes the indicated region from the Watcher.
+//  Description: Removes the indicated region from the group.
 //               Returns true if it was successfully removed, or false
 //               Returns true if it was successfully removed, or false
 //               if it wasn't there in the first place.
 //               if it wasn't there in the first place.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -98,27 +74,7 @@ remove_region(MouseWatcherRegion *region) {
   if (region == _button_down_region) {
   if (region == _button_down_region) {
     _button_down_region = (MouseWatcherRegion *)NULL;
     _button_down_region = (MouseWatcherRegion *)NULL;
   }
   }
-  return _regions.erase(region) != 0;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MouseWatcher::find_region
-//       Access: Published
-//  Description: Returns a pointer to the first region found with the
-//               indicated name.  If multiple regions share the same
-//               name, the one that is returned is indeterminate.
-////////////////////////////////////////////////////////////////////
-MouseWatcherRegion *MouseWatcher::
-find_region(const string &name) const {
-  Regions::const_iterator ri;
-  for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
-    MouseWatcherRegion *region = (*ri);
-    if (region->get_name() == name) {
-      return region;
-    }
-  }
-
-  return (MouseWatcherRegion *)NULL;
+  return MouseWatcherGroup::remove_region(region);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -151,6 +107,27 @@ get_over_region(const LPoint2f &pos) const {
     }
     }
   }
   }
 
 
+  // Also check all of our sub-groups.
+  Groups::const_iterator gi;
+  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
+    MouseWatcherGroup *group = (*gi);
+    for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
+      MouseWatcherRegion *region = (*ri);
+      const LVecBase4f &frame = region->get_frame();
+      
+      if (region->get_active() &&
+          pos[0] >= frame[0] && pos[0] <= frame[1] &&
+          pos[1] >= frame[2] && pos[1] <= frame[3]) {
+        
+        // We're over this region.  Is it preferred to the other one?
+        if (over_region == (MouseWatcherRegion *)NULL ||
+            *region < *over_region) {
+          over_region = region;
+        }
+      }
+    }
+  }
+
   return over_region;
   return over_region;
 }
 }
 
 
@@ -180,6 +157,59 @@ write(ostream &out, int indent_level) const {
     MouseWatcherRegion *region = (*ri);
     MouseWatcherRegion *region = (*ri);
     region->write(out, indent_level + 2);
     region->write(out, indent_level + 2);
   }
   }
+
+  if (!_groups.empty()) {
+    Groups::const_iterator gi;
+    for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
+      MouseWatcherGroup *group = (*gi);
+      indent(out, indent_level + 2)
+        << "Subgroup:\n";
+      for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
+        MouseWatcherRegion *region = (*ri);
+        region->write(out, indent_level + 4);
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcher::add_group
+//       Access: Public
+//  Description: Adds the indicated group of regions to the set of
+//               regions the MouseWatcher will monitor each frame.
+//
+//               Since the MouseWatcher itself inherits from
+//               MouseWatcherGroup, this operation is normally not
+//               necessary--you can simply add the Regions you care
+//               about one at a time.  Adding a complete group is
+//               useful when you may want to explicitly remove the
+//               regions as a group later.
+//
+//               Returns true if the group was successfully added, or
+//               false if it was already on the list.
+////////////////////////////////////////////////////////////////////
+bool MouseWatcher::
+add_group(MouseWatcherGroup *group) {
+  return _groups.insert(group).second;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcher::remove_group
+//       Access: Public
+//  Description: Removes the indicated group from the set of extra
+//               groups associated with the MouseWatcher.  Returns
+//               true if successful, or false if the group was already
+//               removed or was never added via add_group().
+////////////////////////////////////////////////////////////////////
+bool MouseWatcher::
+remove_group(MouseWatcherGroup *group) {
+  if (group->has_region(_current_region)) {
+    _current_region = (MouseWatcherRegion *)NULL;
+  }
+  if (group->has_region(_button_down_region)) {
+    _button_down_region = (MouseWatcherRegion *)NULL;
+  }
+  return _groups.erase(group) != 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -198,10 +228,12 @@ set_current_region(MouseWatcherRegion *region) {
 #endif
 #endif
   if (region != _current_region) {
   if (region != _current_region) {
     if (_current_region != (MouseWatcherRegion *)NULL) {
     if (_current_region != (MouseWatcherRegion *)NULL) {
+      _current_region->exit();
       throw_event_pattern(_leave_pattern, _current_region);
       throw_event_pattern(_leave_pattern, _current_region);
     }
     }
     _current_region = region;
     _current_region = region;
     if (_current_region != (MouseWatcherRegion *)NULL) {
     if (_current_region != (MouseWatcherRegion *)NULL) {
+      _current_region->enter();
       throw_event_pattern(_enter_pattern, _current_region);
       throw_event_pattern(_enter_pattern, _current_region);
     }
     }
   }
   }
@@ -219,9 +251,11 @@ throw_event_pattern(const string &pattern, const MouseWatcherRegion *region,
   if (pattern.empty()) {
   if (pattern.empty()) {
     return;
     return;
   }
   }
+#ifndef NDEBUG
   if (region != (MouseWatcherRegion *)NULL) {
   if (region != (MouseWatcherRegion *)NULL) {
     region->test_ref_count_integrity();
     region->test_ref_count_integrity();
   }
   }
+#endif
 
 
   string event;
   string event;
   for (size_t p = 0; p < pattern.size(); ++p) {
   for (size_t p = 0; p < pattern.size(); ++p) {
@@ -323,13 +357,9 @@ transmit_data(NodeAttributes &data) {
         // There is some danger of losing button-up events here.  If
         // There is some danger of losing button-up events here.  If
         // more than one button goes down together, we won't detect
         // more than one button goes down together, we won't detect
         // both of the button-up events properly.
         // both of the button-up events properly.
-
-        // We should probably throw a different button_up event based
-        // on whether the _current_region is NULL or not, so the
-        // calling code can differentiate between button_up within the
-        // starting region, and button_up outside the region.
-        // Presently, changing this will break the GUI code.
         if (_button_down_region != (MouseWatcherRegion *)NULL) {
         if (_button_down_region != (MouseWatcherRegion *)NULL) {
+          bool is_within = (_current_region == _button_down_region);
+          _button_down_region->button_up(be._button, is_within);
           throw_event_pattern(_button_up_pattern, _button_down_region,
           throw_event_pattern(_button_up_pattern, _button_down_region,
                               be._button.get_name());
                               be._button.get_name());
         }
         }
@@ -343,6 +373,7 @@ transmit_data(NodeAttributes &data) {
         }
         }
         _button_down = true;
         _button_down = true;
         if (_button_down_region != (MouseWatcherRegion *)NULL) {
         if (_button_down_region != (MouseWatcherRegion *)NULL) {
+          _button_down_region->button_down(be._button);
           throw_event_pattern(_button_down_pattern, _button_down_region,
           throw_event_pattern(_button_down_pattern, _button_down_region,
                               be._button.get_name());
                               be._button.get_name());
         }
         }

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

@@ -22,6 +22,7 @@
 #include <pandabase.h>
 #include <pandabase.h>
 
 
 #include "mouseWatcherRegion.h"
 #include "mouseWatcherRegion.h"
+#include "mouseWatcherGroup.h"
 
 
 #include <dataNode.h>
 #include <dataNode.h>
 #include <vec3DataTransition.h>
 #include <vec3DataTransition.h>
@@ -52,15 +53,12 @@
 //               scene graph.  It will move the geometry around
 //               scene graph.  It will move the geometry around
 //               according to the mouse's known position.
 //               according to the mouse's known position.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA MouseWatcher : public DataNode {
+class EXPCL_PANDA MouseWatcher : public DataNode, public MouseWatcherGroup {
 PUBLISHED:
 PUBLISHED:
   MouseWatcher(const string &name = "");
   MouseWatcher(const string &name = "");
   ~MouseWatcher();
   ~MouseWatcher();
 
 
-  bool add_region(MouseWatcherRegion *region);
-  bool has_region(MouseWatcherRegion *region) const;
   bool remove_region(MouseWatcherRegion *region);
   bool remove_region(MouseWatcherRegion *region);
-  MouseWatcherRegion *find_region(const string &name) const;
 
 
   INLINE bool has_mouse() const;
   INLINE bool has_mouse() const;
   INLINE const LPoint2f &get_mouse() const;
   INLINE const LPoint2f &get_mouse() const;
@@ -93,26 +91,29 @@ PUBLISHED:
   INLINE void clear_geometry();
   INLINE void clear_geometry();
 
 
   INLINE void set_extra_handler(EventHandler *eh);
   INLINE void set_extra_handler(EventHandler *eh);
-  INLINE EventHandler* get_extra_handler(void) const;
+  INLINE EventHandler *get_extra_handler(void) const;
 
 
 public:
 public:
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level = 0) const;
   virtual void write(ostream &out, int indent_level = 0) const;
 
 
+  bool add_group(MouseWatcherGroup *group);
+  bool remove_group(MouseWatcherGroup *group);
+
 private:
 private:
   void set_current_region(MouseWatcherRegion *region);
   void set_current_region(MouseWatcherRegion *region);
   void throw_event_pattern(const string &pattern,
   void throw_event_pattern(const string &pattern,
                            const MouseWatcherRegion *region,
                            const MouseWatcherRegion *region,
                            const string &button_name = string());
                            const string &button_name = string());
 
 
-  typedef pset< PT(MouseWatcherRegion) > Regions;
-  Regions _regions;
+  typedef pset< PT(MouseWatcherGroup) > Groups;
+  Groups _groups;
 
 
   bool _has_mouse;
   bool _has_mouse;
   LPoint2f _mouse;
   LPoint2f _mouse;
 
 
-  MouseWatcherRegion *_current_region;
-  MouseWatcherRegion *_button_down_region;
+  PT(MouseWatcherRegion) _current_region;
+  PT(MouseWatcherRegion) _button_down_region;
   bool _button_down;
   bool _button_down;
 
 
   string _button_down_pattern;
   string _button_down_pattern;

+ 87 - 0
panda/src/tform/mouseWatcherGroup.cxx

@@ -0,0 +1,87 @@
+// Filename: mouseWatcherGroup.cxx
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "mouseWatcherGroup.h"
+
+
+TypeHandle MouseWatcherGroup::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherGroup::add_region
+//       Access: Published
+//  Description: Adds the indicated region to the set of regions in
+//               the group.  Returns true if it was successfully
+//               added, or false if it was already on the list.
+////////////////////////////////////////////////////////////////////
+bool MouseWatcherGroup::
+add_region(MouseWatcherRegion *region) {
+  return _regions.insert(region).second;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherGroup::has_region
+//       Access: Published
+//  Description: Returns true if the indicated region has already been
+//               added to the MouseWatcherGroup, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool MouseWatcherGroup::
+has_region(MouseWatcherRegion *region) const {
+  return _regions.count(region) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherGroup::remove_region
+//       Access: Published
+//  Description: Removes the indicated region from the group.
+//               Returns true if it was successfully removed, or false
+//               if it wasn't there in the first place.
+////////////////////////////////////////////////////////////////////
+bool MouseWatcherGroup::
+remove_region(MouseWatcherRegion *region) {
+  return _regions.erase(region) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherGroup::find_region
+//       Access: Published
+//  Description: Returns a pointer to the first region found with the
+//               indicated name.  If multiple regions share the same
+//               name, the one that is returned is indeterminate.
+////////////////////////////////////////////////////////////////////
+MouseWatcherRegion *MouseWatcherGroup::
+find_region(const string &name) const {
+  Regions::const_iterator ri;
+  for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
+    MouseWatcherRegion *region = (*ri);
+    if (region->get_name() == name) {
+      return region;
+    }
+  }
+
+  return (MouseWatcherRegion *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherGroup::clear_regions
+//       Access: Published
+//  Description: Removes all the regions from the group.
+////////////////////////////////////////////////////////////////////
+void MouseWatcherGroup::
+clear_regions() {
+  _regions.clear();
+}

+ 60 - 0
panda/src/tform/mouseWatcherGroup.h

@@ -0,0 +1,60 @@
+// Filename: mouseWatcherGroup.h
+// Created by:  drose (02Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MOUSEWATCHERGROUP_H
+#define MOUSEWATCHERGROUP_H
+
+#include "pandabase.h"
+#include "mouseWatcherRegion.h"
+
+#include "pointerTo.h"
+#include "referenceCount.h"
+#include "pset.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : MouseWatcherGroup
+// Description : This represents a collection of MouseWatcherRegions
+//               that may be managed as a group.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA MouseWatcherGroup : virtual public ReferenceCount {
+PUBLISHED:
+  bool add_region(MouseWatcherRegion *region);
+  bool has_region(MouseWatcherRegion *region) const;
+  bool remove_region(MouseWatcherRegion *region);
+  MouseWatcherRegion *find_region(const string &name) const;
+  void clear_regions();
+
+protected:
+  typedef pset< PT(MouseWatcherRegion) > Regions;
+  Regions _regions;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    register_type(_type_handle, "MouseWatcherGroup");
+  }
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class MouseWatcher;
+};
+
+#endif

+ 44 - 0
panda/src/tform/mouseWatcherRegion.cxx

@@ -43,3 +43,47 @@ write(ostream &out, int indent_level) const {
   indent(out, indent_level) << get_name() << " lrbt = " << _frame << "\n";
   indent(out, indent_level) << get_name() << " lrbt = " << _frame << "\n";
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherRegion::enter
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever the
+//               mouse enters the region.
+////////////////////////////////////////////////////////////////////
+void MouseWatcherRegion::
+enter() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherRegion::exit
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever the
+//               mouse exits the region.
+////////////////////////////////////////////////////////////////////
+void MouseWatcherRegion::
+exit() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherRegion::button_down
+//       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) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherRegion::button_up
+//       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.
+////////////////////////////////////////////////////////////////////
+void MouseWatcherRegion::
+button_up(ButtonHandle, bool) {
+}

+ 6 - 0
panda/src/tform/mouseWatcherRegion.h

@@ -24,6 +24,7 @@
 #include <namable.h>
 #include <namable.h>
 #include <typedReferenceCount.h>
 #include <typedReferenceCount.h>
 #include <luse.h>
 #include <luse.h>
+#include <buttonHandle.h>
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : MouseWatcherRegion
 //       Class : MouseWatcherRegion
@@ -56,6 +57,11 @@ PUBLISHED:
 public:
 public:
   INLINE bool operator < (const MouseWatcherRegion &other) const;
   INLINE bool operator < (const MouseWatcherRegion &other) const;
 
 
+  virtual void enter();
+  virtual void exit();
+  virtual void button_down(ButtonHandle button);
+  virtual void button_up(ButtonHandle button, bool is_within);
+
 private:
 private:
   LVecBase4f _frame;
   LVecBase4f _frame;
   float _area;
   float _area;

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

@@ -3,4 +3,5 @@
 #include "config_tform.cxx"
 #include "config_tform.cxx"
 #include "dataValve.cxx"
 #include "dataValve.cxx"
 #include "driveInterface.cxx"
 #include "driveInterface.cxx"
+#include "planarSlider.cxx"
 
 

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

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