Forráskód Böngészése

crude initial start of gtk-2.0 port of pstats server

David Rose 20 éve
szülő
commit
d1f039f707
44 módosított fájl, 2720 hozzáadás és 3050 törlés
  1. 24 18
      pandatool/src/gtk-stats/Sources.pp
  2. 69 51
      pandatool/src/gtk-stats/gtkStats.cxx
  3. 4 20
      pandatool/src/gtk-stats/gtkStats.h
  4. 0 73
      pandatool/src/gtk-stats/gtkStatsBadVersionWindow.cxx
  5. 0 45
      pandatool/src/gtk-stats/gtkStatsBadVersionWindow.h
  6. 209 0
      pandatool/src/gtk-stats/gtkStatsChartMenu.cxx
  7. 23 22
      pandatool/src/gtk-stats/gtkStatsChartMenu.h
  8. 395 0
      pandatool/src/gtk-stats/gtkStatsGraph.cxx
  9. 142 0
      pandatool/src/gtk-stats/gtkStatsGraph.h
  10. 0 88
      pandatool/src/gtk-stats/gtkStatsGuide.cxx
  11. 0 47
      pandatool/src/gtk-stats/gtkStatsGuide.h
  12. 96 76
      pandatool/src/gtk-stats/gtkStatsLabel.cxx
  13. 33 26
      pandatool/src/gtk-stats/gtkStatsLabel.h
  14. 147 0
      pandatool/src/gtk-stats/gtkStatsLabelStack.cxx
  15. 62 0
      pandatool/src/gtk-stats/gtkStatsLabelStack.h
  16. 0 141
      pandatool/src/gtk-stats/gtkStatsMainWindow.cxx
  17. 0 51
      pandatool/src/gtk-stats/gtkStatsMainWindow.h
  18. 22 22
      pandatool/src/gtk-stats/gtkStatsMenuId.h
  19. 47 0
      pandatool/src/gtk-stats/gtkStatsMonitor.I
  20. 466 83
      pandatool/src/gtk-stats/gtkStatsMonitor.cxx
  21. 68 16
      pandatool/src/gtk-stats/gtkStatsMonitor.h
  22. 0 17
      pandatool/src/gtk-stats/gtkStatsPianoRoll.I
  23. 507 190
      pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx
  24. 34 45
      pandatool/src/gtk-stats/gtkStatsPianoRoll.h
  25. 0 164
      pandatool/src/gtk-stats/gtkStatsPianoWindow.cxx
  26. 1 2
      pandatool/src/gtk-stats/gtkStatsServer.cxx
  27. 4 4
      pandatool/src/gtk-stats/gtkStatsServer.h
  28. 0 17
      pandatool/src/gtk-stats/gtkStatsStripChart.I
  29. 326 282
      pandatool/src/gtk-stats/gtkStatsStripChart.cxx
  30. 32 48
      pandatool/src/gtk-stats/gtkStatsStripChart.h
  31. 0 459
      pandatool/src/gtk-stats/gtkStatsStripWindow.cxx
  32. 0 78
      pandatool/src/gtk-stats/gtkStatsStripWindow.h
  33. 0 210
      pandatool/src/gtk-stats/gtkStatsWindow.cxx
  34. 0 69
      pandatool/src/gtk-stats/gtkStatsWindow.h
  35. 9 0
      pandatool/src/gtk-stats/gtkstats_composite1.cxx
  36. 0 201
      pandatool/src/gtk-stats/scribble.cc
  37. 0 18
      pandatool/src/gtkbase/Sources.pp
  38. 0 69
      pandatool/src/gtkbase/basicGtkDialog.cxx
  39. 0 48
      pandatool/src/gtkbase/basicGtkDialog.h
  40. 0 140
      pandatool/src/gtkbase/basicGtkWindow.cxx
  41. 0 60
      pandatool/src/gtkbase/basicGtkWindow.h
  42. 0 76
      pandatool/src/gtkbase/gtkBase.cxx
  43. 0 46
      pandatool/src/gtkbase/request_initial_size.cxx
  44. 0 28
      pandatool/src/gtkbase/request_initial_size.h

+ 24 - 18
pandatool/src/gtk-stats/Sources.pp

@@ -1,27 +1,33 @@
-#define BUILD_DIRECTORY $[and $[HAVE_GTKMM],$[HAVE_NET]]
-#define USE_PACKAGES net gtkmm
+#define BUILD_DIRECTORY $[and $[HAVE_GTK],$[HAVE_NET]]
+#define USE_PACKAGES net gtk
 
 #begin bin_target
-  #define TARGET gtk-stats
+  // We rename TARGET to gtk-pstats on Windows, so it won't compete
+  // with Windows-native pstats.
+  #define TARGET $[if $[WINDOWS_PLATFORM],gtk-pstats,pstats]
   #define LOCAL_LIBS \
-    gtkbase progbase pstatserver
+    progbase pstatserver
   #define OTHER_LIBS \
-    pstatclient:c linmath:c putil:c net:c express:c panda:m \
-    interrogatedb:c dtoolutil:c dtoolbase:c prc:c dconfig:c dtoolconfig:m dtool:m
-  #define UNIX_SYS_LIBS \
-    m
+    pstatclient:c linmath:c putil:c net:c express:c pandaexpress:m panda:m \
+    dtoolutil:c dtoolbase:c prc:c dconfig:c dtoolconfig:m dtool:m \
+    pystub
 
   #define SOURCES \
-    gtkStats.cxx gtkStats.h \
-    gtkStatsBadVersionWindow.cxx gtkStatsBadVersionWindow.h \
-    gtkStatsGuide.cxx gtkStatsGuide.h \
-    gtkStatsLabel.cxx gtkStatsLabel.h gtkStatsMainWindow.cxx \
-    gtkStatsMainWindow.h gtkStatsMonitor.cxx gtkStatsMonitor.h \
-    gtkStatsPianoRoll.I gtkStatsPianoRoll.cxx gtkStatsPianoRoll.h \
-    gtkStatsPianoWindow.cxx gtkStatsPianoWindow.h gtkStatsServer.cxx \
-    gtkStatsServer.h gtkStatsStripChart.I gtkStatsStripChart.cxx \
-    gtkStatsStripChart.h gtkStatsStripWindow.cxx gtkStatsStripWindow.h \
-    gtkStatsWindow.cxx gtkStatsWindow.h
+    gtkStats.cxx \
+    gtkStatsGraph.cxx gtkStatsGraph.h \
+    gtkStatsLabel.cxx gtkStatsLabel.h \
+    gtkStatsLabelStack.cxx gtkStatsLabelStack.h \
+    gtkStatsMenuId.h \
+    gtkStatsMonitor.cxx gtkStatsMonitor.h gtkStatsMonitor.I \
+    gtkStatsServer.cxx gtkStatsServer.h \
+    gtkStatsStripChart.cxx gtkStatsStripChart.h
+
+//     gtkStatsChartMenu.cxx gtkStatsChartMenu.h \
+//     gtkStatsPianoRoll.cxx gtkStatsPianoRoll.h \
+
+  #if $[DEVELOP_GTKSTATS]
+    #define EXTRA_CDEFS $[EXTRA_CDEFS] DEVELOP_GTKSTATS
+  #endif
 
 #end bin_target
 

+ 69 - 51
pandatool/src/gtk-stats/gtkStats.cxx

@@ -1,5 +1,5 @@
 // Filename: gtkStats.cxx
-// Created by:  drose (14Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -16,67 +16,85 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#include "pandatoolbase.h"
 #include "gtkStats.h"
-#include "gtkStatsMainWindow.h"
-
-#include "pStatServer.h"
+#include "gtkStatsServer.h"
 #include "config_pstats.h"
 
-#include <signal.h>
+GtkWidget *main_window;
+static GtkStatsServer *server = NULL;
 
-GtkStatsMainWindow *GtkStats::_main_window = NULL;
+static gboolean
+delete_event(GtkWidget *widget,
+	     GdkEvent *event, gpointer data) {
+  // Returning FALSE to indicate we should destroy the main window
+  // when the user selects "close".
+  return FALSE;
+}
 
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStats::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkStats::
-GtkStats() {
-  set_program_description
-    ("This is a fancy GUI PStats server that listens on a TCP port for a "
-     "connection from a PStatClient in a Panda player.  It will then "
-     "draw strip charts illustrating the performance stats as reported "
-     "by the player.");
-
-  add_option
-    ("p", "port", 0,
-     "Specify the TCP port to listen for connections on.  By default, this "
-     "is taken from the pstats-host Config variable.",
-     &GtkStats::dispatch_int, NULL, &_port);
-
-  _port = pstats_port;
+static void
+destroy(GtkWidget *widget, gpointer data) {
+  gtk_main_quit();
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStats::run
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStats::
-run() {
-  new GtkStatsMainWindow(_port);
+static gboolean
+timer(gpointer data) {
+  server->poll();
 
-  main_loop();
+  return TRUE;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStats::quit
-//       Access: Public, Static
-//  Description: Call this to cleanly shut down the program.
-////////////////////////////////////////////////////////////////////
-void GtkStats::
-quit() {
-  if (_main_window != (GtkStatsMainWindow *)NULL) {
-    _main_window->destruct();
+int
+main(int argc, char *argv[]) {
+  gtk_init(&argc, &argv);
+
+  main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+  gtk_window_set_title(GTK_WINDOW(main_window), "PStats");
+
+  // Connect the delete and destroy events, so the user can exit the
+  // application by closing the main window.
+  g_signal_connect(G_OBJECT(main_window), "delete_event",
+		   G_CALLBACK(delete_event), NULL);
+  
+  g_signal_connect(G_OBJECT(main_window), "destroy",
+		   G_CALLBACK(destroy), NULL);
+
+  ostringstream stream;
+  stream << "Listening on port " << pstats_port;
+  string str = stream.str();
+  GtkWidget *label = gtk_label_new(str.c_str());
+  gtk_container_add(GTK_CONTAINER(main_window), label);
+  gtk_widget_show(label);
+
+  // Create the server object.
+  server = new GtkStatsServer;
+  if (!server->listen()) {
+    ostringstream stream;
+    stream 
+      << "Unable to open port " << pstats_port
+      << ".  Try specifying a different\n"
+      << "port number using pstats-port in your Config file.";
+    string str = stream.str();
+
+    GtkWidget *dialog = 
+      gtk_message_dialog_new(GTK_WINDOW(main_window),
+			     GTK_DIALOG_DESTROY_WITH_PARENT,
+			     GTK_MESSAGE_ERROR,
+			     GTK_BUTTONS_CLOSE,
+			     str.c_str());
+    gtk_dialog_run(GTK_DIALOG(dialog));
+    gtk_widget_destroy(dialog);
+    exit(1);
   }
-  Gtk::Main::quit();
-}
 
+  gtk_widget_show(main_window);
+
+  // Set up a timer to poll the pstats every so often.
+  g_timeout_add(200, timer, NULL);
+
+  // Now get lost in the message loop.
+  gtk_main();
 
-int main(int argc, char *argv[]) {
-  GtkStats prog;
-  prog.parse_command_line(argc, argv);
-  prog.run();
-  return 0;
+  return (0);
 }

+ 4 - 20
pandatool/src/gtk-stats/gtkStats.h

@@ -1,5 +1,5 @@
 // Filename: gtkStats.h
-// Created by:  drose (14Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -19,27 +19,11 @@
 #ifndef GTKSTATS_H
 #define GTKSTATS_H
 
-#include "pandatoolbase.h"
+#include "pStatServer.h"
 
-#include "gtkBase.h"
+#include <gtk/gtk.h>
 
-class GtkStatsMainWindow;
-
-////////////////////////////////////////////////////////////////////
-//       Class : GtkStats
-// Description : A fancy graphical pstats server written using gtk+
-//               (actually, Gtk--, the C++ layer over gtk+).
-////////////////////////////////////////////////////////////////////
-class GtkStats : public GtkBase {
-public:
-  GtkStats();
-
-  void run();
-  static void quit();
-
-  int _port;
-  static GtkStatsMainWindow *_main_window;
-};
+extern GtkWidget *main_window;
 
 #endif
 

+ 0 - 73
pandatool/src/gtk-stats/gtkStatsBadVersionWindow.cxx

@@ -1,73 +0,0 @@
-// Filename: gtkStatsBadVersionWindow.cxx
-// Created by:  drose (18May01)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "gtkStatsBadVersionWindow.h"
-#include "gtkStatsMonitor.h"
-
-#include "string_utils.h"
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsBadVersionWindow::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkStatsBadVersionWindow::
-GtkStatsBadVersionWindow(GtkStatsMonitor *monitor,
-                         int client_major, int client_minor,
-                         int server_major, int server_minor) {
-  set_title("Bad client");
-
-  Gtk::VBox *box1 = new Gtk::VBox;
-  box1->show();
-  box1->set_border_width(8);
-  add(*manage(box1));
-
-  string message =
-    "Rejected connection by " +
-    monitor->get_client_progname() + " from " +
-    monitor->get_client_hostname() + ".\nClient uses PStats version " +
-    format_string(client_major) + "." + format_string(client_minor) +
-    ",\nwhile server expects PStats version " +
-    format_string(server_major) + "." + format_string(server_minor) + ".";
-
-  Gtk::Label *label = new Gtk::Label(message);
-  label->show();
-  box1->pack_start(*manage(label), true, false, 8);
-
-  Gtk::HBox *box2 = new Gtk::HBox;
-  box2->show();
-  box1->pack_start(*manage(box2), false, false, 0);
-
-  Gtk::Button *close = new Gtk::Button("Close");
-  close->set_usize(80, 30);
-  close->show();
-  box2->pack_start(*manage(close), true, false, 0);
-  close->clicked.connect(slot(this, &GtkStatsBadVersionWindow::close_clicked));
-
-  setup();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsBadVersionWindow::close_clicked
-//       Access: Private
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsBadVersionWindow::
-close_clicked() {
-  destruct();
-}

+ 0 - 45
pandatool/src/gtk-stats/gtkStatsBadVersionWindow.h

@@ -1,45 +0,0 @@
-// Filename: gtkStatsBadVersionWindow.h
-// Created by:  drose (18May01)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef GTKSTATSBADVERSIONWINDOW_H
-#define GTKSTATSBADVERSIONWINDOW_H
-
-#include "pandatoolbase.h"
-
-#include "basicGtkWindow.h"
-
-class GtkStatsMonitor;
-
-////////////////////////////////////////////////////////////////////
-//       Class : GtkStatsBadVersionWindow
-// Description : This window is popped up to indicated an attempted
-//               connection from an invalid client.
-////////////////////////////////////////////////////////////////////
-class GtkStatsBadVersionWindow : public BasicGtkWindow {
-public:
-  GtkStatsBadVersionWindow(GtkStatsMonitor *monitor,
-                           int client_major, int client_minor,
-                           int server_major, int server_minor);
-
-private:
-  void close_clicked();
-};
-
-
-#endif
-

+ 209 - 0
pandatool/src/gtk-stats/gtkStatsChartMenu.cxx

@@ -0,0 +1,209 @@
+// Filename: gtkStatsChartMenu.cxx
+// Created by:  drose (16Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "gtkStatsChartMenu.h"
+#include "gtkStatsMonitor.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsChartMenu::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsChartMenu::
+GtkStatsChartMenu(GtkStatsMonitor *monitor, int thread_index) :
+  _monitor(monitor),
+  _thread_index(thread_index)
+{
+  _menu = CreatePopupMenu();
+  do_update();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsChartMenu::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsChartMenu::
+~GtkStatsChartMenu() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsChartMenu::get_menu_handle
+//       Access: Public
+//  Description: Returns the Windows menu handle for this particular
+//               menu.
+////////////////////////////////////////////////////////////////////
+HMENU GtkStatsChartMenu::
+get_menu_handle() {
+  return _menu;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsChartMenu::add_to_menu_bar
+//       Access: Public
+//  Description: Adds the menu to the end of the indicated menu bar.
+////////////////////////////////////////////////////////////////////
+void GtkStatsChartMenu::
+add_to_menu_bar(HMENU menu_bar, int before_menu_id) {
+  const PStatClientData *client_data = _monitor->get_client_data();
+  string thread_name;
+  if (_thread_index == 0) {
+    // A special case for the main thread.
+    thread_name = "Graphs";
+  } else {
+    thread_name = client_data->get_thread_name(_thread_index);
+  }
+
+  MENUITEMINFO mii;
+  memset(&mii, 0, sizeof(mii));
+  mii.cbSize = sizeof(mii);
+
+  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU; 
+  mii.fType = MFT_STRING; 
+  mii.hSubMenu = _menu; 
+  mii.dwTypeData = (char *)thread_name.c_str(); 
+  InsertMenuItem(menu_bar, before_menu_id, FALSE, &mii);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsChartMenu::check_update
+//       Access: Public
+//  Description: Checks to see if the menu needs to be updated
+//               (e.g. because of new data from the client), and
+//               updates it if necessary.
+////////////////////////////////////////////////////////////////////
+void GtkStatsChartMenu::
+check_update() {
+  PStatView &view = _monitor->get_view(_thread_index);
+  if (view.get_level_index() != _last_level_index) {
+    do_update();
+  }
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsChartMenu::do_update
+//       Access: Public
+//  Description: Unconditionally updates the menu with the latest data
+//               from the client.
+////////////////////////////////////////////////////////////////////
+void GtkStatsChartMenu::
+do_update() {
+  PStatView &view = _monitor->get_view(_thread_index);
+  _last_level_index = view.get_level_index();
+
+  // First, remove all of the old entries from the menu.
+  int num_items = GetMenuItemCount(_menu);
+  for (int i = num_items - 1; i >= 0; i--) {
+    DeleteMenu(_menu, i, MF_BYPOSITION);
+  }
+
+  // Now rebuild the menu with the new set of entries.
+
+  // The menu item(s) for the thread's frame time goes first.
+  add_view(_menu, view.get_top_level(), false);
+
+  bool needs_separator = true;
+  MENUITEMINFO mii;
+  memset(&mii, 0, sizeof(mii));
+  mii.cbSize = sizeof(mii);
+
+  // And then the menu item(s) for each of the level values.
+  const PStatClientData *client_data = _monitor->get_client_data();
+  int num_toplevel_collectors = client_data->get_num_toplevel_collectors();
+  for (int tc = 0; tc < num_toplevel_collectors; tc++) {
+    int collector = client_data->get_toplevel_collector(tc);
+    if (client_data->has_collector(collector) && 
+        client_data->get_collector_has_level(collector)) {
+
+      // We put a separator between the above frame collector and the
+      // first level collector.
+      if (needs_separator) {
+        mii.fMask = MIIM_FTYPE; 
+        mii.fType = MFT_SEPARATOR; 
+        InsertMenuItem(_menu, GetMenuItemCount(_menu), TRUE, &mii);
+
+        needs_separator = false;
+      }
+
+      PStatView &level_view = _monitor->get_level_view(collector, _thread_index);
+      add_view(_menu, level_view.get_top_level(), true);
+    }
+  }
+
+  // Also a menu item for a piano roll (following a separator).
+  mii.fMask = MIIM_FTYPE; 
+  mii.fType = MFT_SEPARATOR; 
+  InsertMenuItem(_menu, GetMenuItemCount(_menu), TRUE, &mii);
+
+  GtkStatsMonitor::MenuDef menu_def(_thread_index, -1, false);
+  int menu_id = _monitor->get_menu_id(menu_def);
+
+  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID; 
+  mii.fType = MFT_STRING; 
+  mii.wID = menu_id;
+  mii.dwTypeData = "Piano Roll";
+  InsertMenuItem(_menu, GetMenuItemCount(_menu), TRUE, &mii);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsChartMenu::add_view
+//       Access: Private
+//  Description: Adds a new entry or entries to the menu for the
+//               indicated view and its children.
+////////////////////////////////////////////////////////////////////
+void GtkStatsChartMenu::
+add_view(HMENU parent_menu, const PStatViewLevel *view_level, bool show_level) {
+  int collector = view_level->get_collector();
+
+  const PStatClientData *client_data = _monitor->get_client_data();
+  string collector_name = client_data->get_collector_name(collector);
+
+  GtkStatsMonitor::MenuDef menu_def(_thread_index, collector, show_level);
+  int menu_id = _monitor->get_menu_id(menu_def);
+
+  MENUITEMINFO mii;
+  memset(&mii, 0, sizeof(mii));
+  mii.cbSize = sizeof(mii);
+
+  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID; 
+  mii.fType = MFT_STRING; 
+  mii.wID = menu_id;
+  mii.dwTypeData = (char *)collector_name.c_str(); 
+  InsertMenuItem(parent_menu, GetMenuItemCount(parent_menu), TRUE, &mii);
+
+  int num_children = view_level->get_num_children();
+  if (num_children > 1) {
+    // If the collector has more than one child, add a menu entry to go
+    // directly to each of its children.
+    HMENU submenu = CreatePopupMenu();
+    string submenu_name = collector_name + " components";
+
+    mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU;
+    mii.fType = MFT_STRING; 
+    mii.hSubMenu = submenu;
+    mii.dwTypeData = (char *)submenu_name.c_str(); 
+    InsertMenuItem(parent_menu, GetMenuItemCount(parent_menu), TRUE, &mii);
+
+    // Reverse the order since the menus are listed from the top down;
+    // we want to be visually consistent with the graphs, which list
+    // these labels from the bottom up.
+    for (int c = num_children - 1; c >= 0; c--) {
+      add_view(submenu, view_level->get_child(c), show_level);
+    }
+  }
+}

+ 23 - 22
pandatool/src/gtk-stats/gtkStatsPianoWindow.h → pandatool/src/gtk-stats/gtkStatsChartMenu.h

@@ -1,5 +1,5 @@
-// Filename: gtkStatsPianoWindow.h
-// Created by:  drose (18Jul00)
+// Filename: gtkStatsChartMenu.h
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -16,42 +16,43 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#ifndef GTKSTATSPIANOWINDOW_H
-#define GTKSTATSPIANOWINDOW_H
+#ifndef GTKSTATSCHARTMENU_H
+#define GTKSTATSCHARTMENU_H
 
 #include "pandatoolbase.h"
 
-#include "gtkStatsMonitor.h"
-#include "gtkStatsWindow.h"
+#include <windows.h>
 
-class GtkStatsPianoRoll;
+class GtkStatsMonitor;
+class PStatView;
+class PStatViewLevel;
 
 ////////////////////////////////////////////////////////////////////
-//       Class : GtkStatsPianoWindow
-// Description : A window that contains a GtkStatsPianoRoll.
+//       Class : GtkStatsChartMenu
+// Description : A pulldown menu of charts available for a particular
+//               thread.
 ////////////////////////////////////////////////////////////////////
-class GtkStatsPianoWindow : public GtkStatsWindow {
+class GtkStatsChartMenu {
 public:
-  GtkStatsPianoWindow(GtkStatsMonitor *monitor, int thread_index,
-                      int chart_xsize, int chart_ysize);
+  GtkStatsChartMenu(GtkStatsMonitor *monitor, int thread_index);
+  ~GtkStatsChartMenu();
 
-  virtual void mark_dead();
-  virtual void idle();
+  HMENU get_menu_handle();
+  void add_to_menu_bar(HMENU menu_bar, int before_menu_id);
 
-protected:
-  virtual void setup_menu();
-  virtual void menu_new_window();
-  void menu_hscale(float hz);
+  void check_update();
+  void do_update();
 
 private:
-  void layout_window(int chart_xsize, int chart_ysize);
+  void add_view(HMENU parent_menu, const PStatViewLevel *view_level,
+                bool show_level);
 
-private:
+  GtkStatsMonitor *_monitor;
   int _thread_index;
 
-  GtkStatsPianoRoll *_chart;
+  int _last_level_index;
+  HMENU _menu;
 };
 
-
 #endif
 

+ 395 - 0
pandatool/src/gtk-stats/gtkStatsGraph.cxx

@@ -0,0 +1,395 @@
+// Filename: gtkStatsGraph.cxx
+// Created by:  drose (16Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "gtkStatsGraph.h"
+#include "gtkStatsMonitor.h"
+#include "gtkStatsLabelStack.h"
+
+const GdkColor GtkStatsGraph::rgb_white = {
+  0, 0xffff, 0xffff, 0xffff
+};
+const GdkColor GtkStatsGraph::rgb_light_gray = {
+  0, 0x9a9a, 0x9a9a, 0x9a9a,
+};
+const GdkColor GtkStatsGraph::rgb_dark_gray = {
+  0, 0x3333, 0x3333, 0x3333,
+};
+const GdkColor GtkStatsGraph::rgb_black = {
+  0, 0x0000, 0x0000, 0x0000
+};
+const GdkColor GtkStatsGraph::rgb_user_guide_bar = {
+  0, 0x8282, 0x9696, 0xffff
+};
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsGraph::
+GtkStatsGraph(GtkStatsMonitor *monitor, int thread_index) :
+  _monitor(monitor),
+  _thread_index(thread_index)
+{
+  _parent_window = NULL;
+  _window = NULL;
+  _graph_window = NULL;
+  //  _sizewe_cursor = LoadCursor(NULL, IDC_SIZEWE);
+  //  _hand_cursor = LoadCursor(NULL, IDC_HAND);
+  _pixmap = 0;
+  _pixmap_gc = 0;
+
+  _graph_left = 0;
+  _graph_top = 0;
+  _pixmap_xsize = 0;
+  _pixmap_ysize = 0;
+
+  _window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+  GtkWidget *parent_window = monitor->get_window();
+
+  gtk_window_set_transient_for(GTK_WINDOW(_window), GTK_WINDOW(parent_window));
+  gtk_window_set_destroy_with_parent(GTK_WINDOW(_window), TRUE);
+  g_signal_connect(G_OBJECT(_window), "delete_event",
+		   G_CALLBACK(window_delete_event), this);
+  g_signal_connect(G_OBJECT(_window), "destroy",
+		   G_CALLBACK(window_destroy), this);
+
+  _graph_window = gtk_drawing_area_new();
+  g_signal_connect(G_OBJECT(_graph_window), "expose_event",  
+		   G_CALLBACK(expose_event_callback), this);
+  g_signal_connect(G_OBJECT(_graph_window), "configure_event",  
+		   G_CALLBACK(configure_event_callback), this);
+
+  gtk_widget_set_size_request(_graph_window, 400, 100);
+
+  _drag_mode = DM_none;
+  _potential_drag_mode = DM_none;
+  _drag_scale_start = 0.0f;
+
+  _pause = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsGraph::
+~GtkStatsGraph() {
+  _monitor = (GtkStatsMonitor *)NULL;
+  release_pixmap();
+
+  /*
+  DeleteObject(_dark_pen);
+  DeleteObject(_light_pen);
+  DeleteObject(_user_guide_bar_pen);
+  */
+  
+  Brushes::iterator bi;
+  for (bi = _brushes.begin(); bi != _brushes.end(); ++bi) {
+    GdkGC *gc = (*bi).second;
+    g_object_unref(gc);
+  }
+
+  if (_graph_window != NULL) {
+    gtk_widget_destroy(_graph_window);
+    _graph_window = NULL;
+  }
+
+  if (_window != NULL) {
+    gtk_widget_destroy(_window);
+    _window = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::get_thread_index
+//       Access: Public
+//  Description: Returns the thread index associated with this
+//               particular graph.
+////////////////////////////////////////////////////////////////////
+int GtkStatsGraph::
+get_thread_index() const {
+  return _thread_index;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::new_collector
+//       Access: Public, Virtual
+//  Description: Called whenever a new Collector definition is
+//               received from the client.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+new_collector(int new_collector) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::new_data
+//       Access: Public, Virtual
+//  Description: Called whenever new data arrives.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+new_data(int thread_index, int frame_number) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::force_redraw
+//       Access: Public, Virtual
+//  Description: Called when it is necessary to redraw the entire graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+force_redraw() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::changed_graph_size
+//       Access: Public, Virtual
+//  Description: Called when the user has resized the window, forcing
+//               a resize of the graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+changed_graph_size(int graph_xsize, int graph_ysize) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::set_time_units
+//       Access: Public, Virtual
+//  Description: Called when the user selects a new time units from
+//               the monitor pulldown menu, this should adjust the
+//               units for the graph to the indicated mask if it is a
+//               time-based graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+set_time_units(int unit_mask) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::set_scroll_speed
+//       Access: Public
+//  Description: Called when the user selects a new scroll speed from
+//               the monitor pulldown menu, this should adjust the
+//               speed for the graph to the indicated value.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+set_scroll_speed(float scroll_speed) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::set_pause
+//       Access: Public
+//  Description: Changes the pause flag for the graph.  When this flag
+//               is true, the graph does not update in response to new
+//               data.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+set_pause(bool pause) {
+  _pause = pause;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::user_guide_bars_changed
+//       Access: Public
+//  Description: Called when the user guide bars have been changed.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+user_guide_bars_changed() {
+  /*
+  InvalidateRect(_window, NULL, TRUE);
+  InvalidateRect(_graph_window, NULL, TRUE);
+  */
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::clicked_label
+//       Access: Public, Virtual
+//  Description: Called when the user single-clicks on a label.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+clicked_label(int collector_index) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::close
+//       Access: Protected
+//  Description: Should be called when the user closes the associated
+//               window.  This tells the monitor to remove the graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+close() {
+  GtkStatsMonitor *monitor = _monitor;
+  _monitor = (GtkStatsMonitor *)NULL;
+  if (monitor != (GtkStatsMonitor *)NULL) {
+    monitor->remove_graph(this);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::get_collector_gc
+//       Access: Protected
+//  Description: Returns a GC suitable for drawing in the indicated
+//               collector's color.
+////////////////////////////////////////////////////////////////////
+GdkGC *GtkStatsGraph::
+get_collector_gc(int collector_index) {
+  Brushes::iterator bi;
+  bi = _brushes.find(collector_index);
+  if (bi != _brushes.end()) {
+    return (*bi).second;
+  }
+
+  // Ask the monitor what color this guy should be.
+  RGBColorf rgb = _monitor->get_collector_color(collector_index);
+
+  GdkColor c;
+  c.red = (int)(rgb[0] * 65535.0f);
+  c.green = (int)(rgb[1] * 65535.0f);
+  c.blue = (int)(rgb[2] * 65535.0f);
+  GdkGC *gc = gdk_gc_new(_pixmap);
+  g_object_ref(gc);
+  gdk_gc_set_rgb_fg_color(gc, &c);
+
+  _brushes[collector_index] = gc;
+  return gc;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::consider_drag_start
+//       Access: Protected, Virtual
+//  Description: Based on the mouse position within the window's
+//               client area, look for draggable things the mouse
+//               might be hovering over and return the apprioprate
+//               DragMode enum or DM_none if nothing is indicated.
+////////////////////////////////////////////////////////////////////
+GtkStatsGraph::DragMode GtkStatsGraph::
+consider_drag_start(int mouse_x, int mouse_y, int width, int height) {
+  if (mouse_x >= _left_margin - 2 && mouse_x <= _left_margin + 2) {
+    return DM_left_margin;
+  } else if (mouse_x >= width - _right_margin - 2 && mouse_x <= width - _right_margin + 2) {
+    return DM_right_margin;
+  }
+
+  return DM_none;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::set_drag_mode
+//       Access: Protected, Virtual
+//  Description: This should be called whenever the drag mode needs to
+//               change state.  It provides hooks for a derived class
+//               to do something special.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+set_drag_mode(GtkStatsGraph::DragMode drag_mode) {
+  _drag_mode = drag_mode;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::setup_pixmap
+//       Access: Private
+//  Description: Sets up a backing-store bitmap of the indicated size.
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+setup_pixmap(int xsize, int ysize) {
+  release_pixmap();
+
+  _pixmap_xsize = max(xsize, 0);
+  _pixmap_ysize = max(ysize, 0);
+
+  _pixmap = gdk_pixmap_new(_graph_window->window, _pixmap_xsize, _pixmap_ysize, -1);
+  g_object_ref(_pixmap);
+  _pixmap_gc = gdk_gc_new(_pixmap);
+  g_object_ref(_pixmap_gc);
+
+  gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
+  gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, 0, 0, 
+		     _pixmap_xsize, _pixmap_ysize);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::release_pixmap
+//       Access: Private
+//  Description: Frees the backing-store bitmap created by
+//               setup_pixmap().
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+release_pixmap() {
+  if (_pixmap != NULL) {
+    g_object_unref(_pixmap);
+    g_object_unref(_pixmap_gc);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::window_delete_event
+//       Access: Private, Static
+//  Description: Callback when the window is closed by the user.
+////////////////////////////////////////////////////////////////////
+gboolean GtkStatsGraph::
+window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
+  // Returning FALSE to indicate we should destroy the window
+  // when the user selects "close".
+  return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::window_delete_event
+//       Access: Private, Static
+//  Description: Callback when the window is destroyed by the system
+//               (or by delete_event).
+////////////////////////////////////////////////////////////////////
+void GtkStatsGraph::
+window_destroy(GtkWidget *widget, gpointer data) {
+  GtkStatsGraph *self = (GtkStatsGraph *)data;
+  self->close();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::expose_event_callback
+//       Access: Private, Static
+//  Description: Fills in the graph window.
+////////////////////////////////////////////////////////////////////
+gboolean GtkStatsGraph::
+expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
+  GtkStatsGraph *self = (GtkStatsGraph *)data;
+
+  if (self->_pixmap != NULL) {
+    gdk_draw_drawable(self->_graph_window->window, 
+		      self->_graph_window->style->fg_gc[0],
+		      self->_pixmap, 0, 0, 0, 0,
+		      self->_pixmap_xsize, self->_pixmap_ysize);
+  }
+    
+  return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsGraph::configure_event_callback
+//       Access: Private, Static
+//  Description: Changes the size of the graph window
+////////////////////////////////////////////////////////////////////
+gboolean GtkStatsGraph::
+configure_event_callback(GtkWidget *widget, GdkEventConfigure *event, 
+			 gpointer data) {
+  GtkStatsGraph *self = (GtkStatsGraph *)data;
+
+  self->changed_graph_size(event->width, event->height);
+  self->setup_pixmap(event->width, event->height);
+  self->force_redraw();
+    
+  return TRUE;
+}

+ 142 - 0
pandatool/src/gtk-stats/gtkStatsGraph.h

@@ -0,0 +1,142 @@
+// Filename: gtkStatsGraph.h
+// Created by:  drose (16Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GTKSTATSGRAPH_H
+#define GTKSTATSGRAPH_H
+
+#include "pandatoolbase.h"
+#include "gtkStatsLabelStack.h"
+#include "pmap.h"
+
+#include <gtk/gtk.h>
+
+class GtkStatsMonitor;
+
+////////////////////////////////////////////////////////////////////
+//       Class : GtkStatsGraph
+// Description : This is just an abstract base class to provide a
+//               common pointer type for the various kinds of graphs
+//               that may be created for a GtkStatsMonitor.
+////////////////////////////////////////////////////////////////////
+class GtkStatsGraph {
+public:
+  // What is the user adjusting by dragging the mouse in a window?
+  enum DragMode {
+    DM_none,
+    DM_scale,
+    DM_left_margin,
+    DM_right_margin,
+    DM_guide_bar,
+    DM_new_guide_bar,
+    DM_sizing,
+  };
+
+public:
+  GtkStatsGraph(GtkStatsMonitor *monitor, int thread_index);
+  virtual ~GtkStatsGraph();
+
+  int get_thread_index() const;
+
+  virtual void new_collector(int collector_index);
+  virtual void new_data(int thread_index, int frame_number);
+  virtual void force_redraw();
+  virtual void changed_graph_size(int graph_xsize, int graph_ysize);
+
+  virtual void set_time_units(int unit_mask);
+  virtual void set_scroll_speed(float scroll_speed);
+  void set_pause(bool pause);
+
+  void user_guide_bars_changed();
+  virtual void clicked_label(int collector_index);
+
+protected:
+  void close();
+  GdkGC *get_collector_gc(int collector_index);
+
+  /*
+  virtual void additional_window_paint(HDC hdc);
+  virtual void additional_graph_window_paint(HDC hdc);
+  */
+  virtual DragMode consider_drag_start(int mouse_x, int mouse_y, 
+                                       int width, int height);
+  virtual void set_drag_mode(DragMode drag_mode);
+
+protected:
+  // Table of GC's for our various collectors.
+  typedef pmap<int, GdkGC *> Brushes;
+  Brushes _brushes;
+
+  GtkStatsMonitor *_monitor;
+  int _thread_index;
+  GtkWidget *_parent_window;
+  GtkWidget *_window;
+  GtkWidget *_graph_window;
+  GtkStatsLabelStack _label_stack;
+
+  /*
+  HCURSOR _sizewe_cursor;
+  HCURSOR _hand_cursor;
+  */
+
+  GdkPixmap *_pixmap;
+  GdkGC *_pixmap_gc;
+
+  int _graph_left, _graph_top;
+  int _pixmap_xsize, _pixmap_ysize;
+  int _left_margin, _right_margin;
+  int _top_margin, _bottom_margin;
+
+  /*
+  COLORREF _dark_color;
+  COLORREF _light_color;
+  COLORREF _user_guide_bar_color;
+  HPEN _dark_pen;
+  HPEN _light_pen;
+  HPEN _user_guide_bar_pen;
+  */
+
+  DragMode _drag_mode;
+  DragMode _potential_drag_mode;
+  int _drag_start_x, _drag_start_y;
+  float _drag_scale_start;
+  int _drag_guide_bar;
+
+  bool _pause;
+
+  static const GdkColor rgb_white;
+  static const GdkColor rgb_light_gray;
+  static const GdkColor rgb_dark_gray;
+  static const GdkColor rgb_black;
+  static const GdkColor rgb_user_guide_bar;
+
+private:
+  void setup_pixmap(int xsize, int ysize);
+  void release_pixmap();
+  void create_graph_window();
+
+  static gboolean window_delete_event(GtkWidget *widget, GdkEvent *event, 
+				      gpointer data);
+  static void window_destroy(GtkWidget *widget, gpointer data);
+  static gboolean expose_event_callback(GtkWidget *widget, 
+					GdkEventExpose *event, gpointer data);
+  static gboolean configure_event_callback(GtkWidget *widget, 
+					   GdkEventConfigure *event, gpointer data);
+};
+
+#endif
+

+ 0 - 88
pandatool/src/gtk-stats/gtkStatsGuide.cxx

@@ -1,88 +0,0 @@
-// Filename: gtkStatsGuide.cxx
-// Created by:  drose (16Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "gtkStatsGuide.h"
-
-#include "pStatStripChart.h"
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsGuide::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkStatsGuide::
-GtkStatsGuide(PStatStripChart *chart) :
-  _chart(chart)
-{
-  set_events(GDK_EXPOSURE_MASK);
-
-  // Choose a suitable minimum width.  This requires knowing what the
-  // font will be.
-  Gdk_Font font = get_style()->gtkobj()->font;
-  int text_width = font.string_width("0000");
-  set_usize(text_width, 0);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsGuide::configure_event_impl
-//       Access: Private, Virtual
-//  Description: Creates a new backing pixmap of the appropriate size.
-////////////////////////////////////////////////////////////////////
-gint GtkStatsGuide::
-configure_event_impl(GdkEventConfigure *) {
-  Gdk_Window window = get_window();
-
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsGuide::expose_event_impl
-//       Access: Private, Virtual
-//  Description: Redraw the text.  We don't bother with clipping
-//               regions here, but just draw the whole thing every
-//               time.
-////////////////////////////////////////////////////////////////////
-gint GtkStatsGuide::
-expose_event_impl(GdkEventExpose *event) {
-  Gdk_GC fg_gc =
-    get_style()->gtkobj()->fg_gc[GTK_WIDGET_STATE (GTK_WIDGET(gtkobj()))];
-  Gdk_GC bg_gc =
-    get_style()->gtkobj()->bg_gc[GTK_WIDGET_STATE (GTK_WIDGET(gtkobj()))];
-
-  if (fg_gc && bg_gc) {
-    Gdk_Window window = get_window();
-    window.draw_rectangle(bg_gc, true, 0, 0, width(), height());
-    
-    Gdk_Font font = fg_gc.get_font();
-    int text_ascent = font.ascent();
-    
-    int num_guide_bars = _chart->get_num_guide_bars();
-    for (int i = 0; i < num_guide_bars; i++) {
-      const PStatStripChart::GuideBar &bar = _chart->get_guide_bar(i);
-      int y = _chart->height_to_pixel(bar._height);
-      
-      if (y >= 5) {
-        // Only draw it if it's not too close to the top.
-        window.draw_string(font, fg_gc, 0, y + text_ascent / 2,
-                           bar._label);
-      }
-    }
-  }
-
-  return false;
-}

+ 0 - 47
pandatool/src/gtk-stats/gtkStatsGuide.h

@@ -1,47 +0,0 @@
-// Filename: gtkStatsGuide.h
-// Created by:  drose (16Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef GTKSTATSGUIDE_H
-#define GTKSTATSGUIDE_H
-
-#include "pandatoolbase.h"
-
-#include <gtk--.h>
-
-class PStatStripChart;
-
-////////////////////////////////////////////////////////////////////
-//       Class : GtkStatsGuide
-// Description : A widget designed to be drawn next to a
-//               GtkStatsStripChart that shows the labels associated
-//               with the strip chart's guide bars.
-////////////////////////////////////////////////////////////////////
-class GtkStatsGuide : public Gtk::DrawingArea {
-public:
-  GtkStatsGuide(PStatStripChart *chart);
-
-private:
-  virtual gint configure_event_impl(GdkEventConfigure *event);
-  virtual gint expose_event_impl(GdkEventExpose *event);
-
-private:
-  PStatStripChart *_chart;
-};
-
-#endif
-

+ 96 - 76
pandatool/src/gtk-stats/gtkStatsLabel.cxx

@@ -1,5 +1,5 @@
 // Filename: gtkStatsLabel.cxx
-// Created by:  drose (15Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -18,27 +18,40 @@
 
 #include "gtkStatsLabel.h"
 #include "gtkStatsMonitor.h"
+#include "gtkStatsGraph.h"
 
-#include "pStatClientData.h"
-#include "pStatMonitor.h"
+int GtkStatsLabel::_left_margin = 2;
+int GtkStatsLabel::_right_margin = 2;
+int GtkStatsLabel::_top_margin = 2;
+int GtkStatsLabel::_bottom_margin = 2;
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GtkStatsLabel::Constructor
 //       Access: Public
-//  Description: This constructor automatically figures out the
-//               appropriate name and color for the label.
+//  Description:
 ////////////////////////////////////////////////////////////////////
 GtkStatsLabel::
-GtkStatsLabel(PStatMonitor *monitor, int collector_index,
-              Gdk_Font font) :
-  _collector_index(collector_index),
-  _font(font)
+GtkStatsLabel(GtkStatsMonitor *monitor, GtkStatsGraph *graph,
+              int thread_index, int collector_index, bool use_fullname) :
+  _monitor(monitor),
+  _graph(graph),
+  _thread_index(thread_index),
+  _collector_index(collector_index)
 {
-  set_events(GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
+  _widget = NULL;
+  if (use_fullname) {
+    _text = _monitor->get_client_data()->get_collector_fullname(_collector_index);
+  } else {
+    _text = _monitor->get_client_data()->get_collector_name(_collector_index);
+  }
 
-  _text = monitor->get_client_data()->get_collector_name(_collector_index);
-  RGBColorf rgb = monitor->get_collector_color(_collector_index);
-  _bg_color.set_rgb_p(rgb[0], rgb[1], rgb[2]);
+  /*
+  RGBColorf rgb = _monitor->get_collector_color(_collector_index);
+  int r = (int)(rgb[0] * 255.0f);
+  int g = (int)(rgb[1] * 255.0f);
+  int b = (int)(rgb[2] * 255.0f);
+  _bg_color = RGB(r, g, b);
+  _bg_brush = CreateSolidBrush(RGB(r, g, b));
 
   // Should our foreground be black or white?
   float bright =
@@ -47,96 +60,103 @@ GtkStatsLabel(PStatMonitor *monitor, int collector_index,
     rgb[2] * 0.114;
 
   if (bright >= 0.5) {
-    _fg_color.set_rgb_p(0, 0, 0);
+    _fg_color = RGB(0, 0, 0);
+    _highlight_brush = (HBRUSH)GetStockObject(BLACK_BRUSH);
   } else {
-    _fg_color.set_rgb_p(1, 1, 1);
+    _fg_color = RGB(255, 255, 255);
+    _highlight_brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
   }
+  */
 
-  Gdk_Colormap::get_system().alloc(_fg_color);
-  Gdk_Colormap::get_system().alloc(_bg_color);
-
-  int text_width = _font.string_width(_text);
-  int text_height = _font.height();
+  _highlight = false;
+  _mouse_within = false;
+}
 
-  _height = text_height + 4;
-  _width = text_width + 4;
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabel::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsLabel::
+~GtkStatsLabel() {
+  //  DeleteObject(_bg_brush);
+}
 
-  set_usize(_width, _height);
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabel::setup
+//       Access: Public
+//  Description: Creates the actual widget.
+////////////////////////////////////////////////////////////////////
+GtkWidget *GtkStatsLabel::
+setup() {
+  _widget = gtk_event_box_new();
+  GtkWidget *label = gtk_label_new(_text.c_str());
+  gtk_container_add(GTK_CONTAINER(_widget), label);
+  gtk_widget_show(label);
+  gtk_widget_show(_widget);
+
+  return _widget;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsLabel::get_width
+//     Function: GtkStatsLabel::get_widget
 //       Access: Public
-//  Description: Returns the width of the widget as we requested it.
+//  Description: Returns the widget for this label.
 ////////////////////////////////////////////////////////////////////
-int GtkStatsLabel::
-get_width() const {
-  return _width;
+GtkWidget *GtkStatsLabel::
+get_widget() const {
+  return _widget;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsLabel::get_height
+//     Function: GtkStatsLabel::get_collector_index
 //       Access: Public
-//  Description: Returns the height of the widget as we requested it.
+//  Description: Returns the collector this label represents.
 ////////////////////////////////////////////////////////////////////
 int GtkStatsLabel::
-get_height() const {
-  return _height;
+get_collector_index() const {
+  return _collector_index;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsLabel::configure_event_impl
-//       Access: Private, Virtual
-//  Description: Creates a new backing pixmap of the appropriate size.
+//     Function: GtkStatsLabel::set_highlight
+//       Access: Public
+//  Description: Enables or disables the visual highlight for this
+//               label.
 ////////////////////////////////////////////////////////////////////
-gint GtkStatsLabel::
-configure_event_impl(GdkEventConfigure *) {
-  Gdk_Window window = get_window();
-
-  _gc = Gdk_GC(window);
-  _gc.set_foreground(_fg_color);
-  _gc.set_background(_bg_color);
-  _gc.set_font(_font);
-
-  _reverse_gc = Gdk_GC(window);
-  _reverse_gc.set_foreground(_bg_color);
-  _reverse_gc.set_background(_fg_color);
-  _reverse_gc.set_font(_font);
-
-  return true;
+void GtkStatsLabel::
+set_highlight(bool highlight) {
+  if (_highlight != highlight) {
+    _highlight = highlight;
+    /*
+    InvalidateRect(_widget, NULL, TRUE);
+    */
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsLabel::expose_event_impl
-//       Access: Private, Virtual
-//  Description: Redraw the text.  We don't bother with clipping
-//               regions here, but just draw the whole text every
-//               time.
+//     Function: GtkStatsLabel::get_highlight
+//       Access: Public
+//  Description: Returns true if the visual highlight for this
+//               label is enabled.
 ////////////////////////////////////////////////////////////////////
-gint GtkStatsLabel::
-expose_event_impl(GdkEventExpose *event) {
-  int text_width = _font.string_width(_text);
-  int text_height = _font.height();
-
-  Gdk_Window window = get_window();
-
-  window.draw_rectangle(_reverse_gc, true, 0, 0, width(), height());
-  window.draw_string(_font, _gc, width() - text_width - 2,
-                      height() - (height() - text_height) / 2 - _font.descent(),
-                      _text);
-  return false;
+bool GtkStatsLabel::
+get_highlight() const {
+  return _highlight;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsLabel::button_press_event_impl
-//       Access: Private, Virtual
-//  Description:
+//     Function: GtkStatsLabel::set_mouse_within
+//       Access: Private
+//  Description: Used internally to indicate whether the mouse is
+//               within the label's widget.
 ////////////////////////////////////////////////////////////////////
-gint GtkStatsLabel::
-button_press_event_impl(GdkEventButton *button) {
-  if (button->type == GDK_2BUTTON_PRESS && button->button == 1) {
-    collector_picked(_collector_index);
-    return true;
+void GtkStatsLabel::
+set_mouse_within(bool mouse_within) {
+  if (_mouse_within != mouse_within) {
+    _mouse_within = mouse_within;
+    /*
+    InvalidateRect(_widget, NULL, TRUE);
+    */
   }
-  return false;
 }

+ 33 - 26
pandatool/src/gtk-stats/gtkStatsLabel.h

@@ -1,5 +1,5 @@
 // Filename: gtkStatsLabel.h
-// Created by:  drose (15Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -21,47 +21,54 @@
 
 #include "pandatoolbase.h"
 
-#include <gtk--.h>
+#include <gtk/gtk.h>
 
-class PStatMonitor;
+class GtkStatsMonitor;
+class GtkStatsGraph;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GtkStatsLabel
 // Description : A text label that will draw in color appropriate for
-//               a particular collector, instead of referring to some
-//               dumb Gtk::Style.  It also throws a signal when the
-//               user double-clicks on it, passing in the collector
-//               index.  This is handy for putting colored labels on
-//               strip charts.
+//               a particular collector.  It also responds when the
+//               user double-clicks on it.  This is handy for putting
+//               colored labels on strip charts.
 ////////////////////////////////////////////////////////////////////
-class GtkStatsLabel : public Gtk::DrawingArea {
+class GtkStatsLabel {
 public:
-  GtkStatsLabel(PStatMonitor *monitor, int collector_index,
-                Gdk_Font font);
+  GtkStatsLabel(GtkStatsMonitor *monitor, GtkStatsGraph *graph,
+                int thread_index, int collector_index, bool use_fullname);
+  ~GtkStatsLabel();
 
-  int get_width() const;
-  int get_height() const;
+  GtkWidget *setup();
+  GtkWidget *get_widget() const;
 
-  SigC::Signal1<void, int> collector_picked;
+  int get_collector_index() const;
 
-private:
-  virtual gint configure_event_impl (GdkEventConfigure *event);
-  virtual gint expose_event_impl (GdkEventExpose *event);
-  virtual gint button_press_event_impl(GdkEventButton *button);
+  void set_highlight(bool highlight);
+  bool get_highlight() const;
 
 private:
-  int _collector_index;
+  void set_mouse_within(bool mouse_within);
 
+  GtkStatsMonitor *_monitor;
+  GtkStatsGraph *_graph;
+  int _thread_index;
+  int _collector_index;
   string _text;
-  Gdk_Font _font;
-  Gdk_Color _fg_color;
-  Gdk_Color _bg_color;
+  GtkWidget *_widget;
+
+  /*
+  COLORREF _bg_color;
+  COLORREF _fg_color;
+  HBRUSH _bg_brush;
+  HBRUSH _highlight_brush;
+  */
 
-  int _width;
-  int _height;
+  bool _highlight;
+  bool _mouse_within;
 
-  Gdk_GC _gc;
-  Gdk_GC _reverse_gc;
+  static int _left_margin, _right_margin;
+  static int _top_margin, _bottom_margin;
 };
 
 #endif

+ 147 - 0
pandatool/src/gtk-stats/gtkStatsLabelStack.cxx

@@ -0,0 +1,147 @@
+// Filename: gtkStatsLabelStack.cxx
+// Created by:  drose (16Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "gtkStatsLabelStack.h"
+#include "gtkStatsLabel.h"
+#include "notify.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabelStack::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsLabelStack::
+GtkStatsLabelStack() {
+  _widget = NULL;
+
+  _highlight_label = -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabelStack::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsLabelStack::
+~GtkStatsLabelStack() {
+  clear_labels();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabelStack::setup
+//       Access: Public
+//  Description: Creates the actual widget object.
+////////////////////////////////////////////////////////////////////
+GtkWidget *GtkStatsLabelStack::
+setup() {
+  if (_widget == NULL) {
+    _widget = gtk_vbox_new(FALSE, 0);
+  }
+ 
+  return _widget;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabelStack::is_setup
+//       Access: Public
+//  Description: Returns true if the label stack has been set up,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool GtkStatsLabelStack::
+is_setup() const {
+  return (_widget != NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabelStack::get_label_collector_index
+//       Access: Public
+//  Description: Returns the collector index associated with the
+//               indicated label.
+////////////////////////////////////////////////////////////////////
+int GtkStatsLabelStack::
+get_label_collector_index(int label_index) const {
+  nassertr(label_index >= 0 && label_index < (int)_labels.size(), -1);
+  return _labels[label_index]->get_collector_index();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabelStack::clear_labels
+//       Access: Public
+//  Description: Removes the set of labels and starts a new set.
+////////////////////////////////////////////////////////////////////
+void GtkStatsLabelStack::
+clear_labels() {
+  Labels::iterator li;
+  for (li = _labels.begin(); li != _labels.end(); ++li) {
+    GtkStatsLabel *label = (*li);
+    gtk_container_remove(GTK_CONTAINER(_widget), label->get_widget());
+    delete (*li);
+  }
+  _labels.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabelStack::add_label
+//       Access: Public
+//  Description: Adds a new label to the top of the stack; returns the
+//               new label index.
+////////////////////////////////////////////////////////////////////
+int GtkStatsLabelStack::
+add_label(GtkStatsMonitor *monitor, GtkStatsGraph *graph,
+          int thread_index, int collector_index, bool use_fullname) {
+  GtkStatsLabel *label = 
+    new GtkStatsLabel(monitor, graph, thread_index, collector_index, use_fullname);
+
+  gtk_box_pack_start(GTK_BOX(_widget), label->setup(),
+		     FALSE, FALSE, 0);
+
+  int label_index = (int)_labels.size();
+  _labels.push_back(label);
+
+  return label_index;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabelStack::get_num_labels
+//       Access: Public
+//  Description: Returns the number of labels in the stack.
+////////////////////////////////////////////////////////////////////
+int GtkStatsLabelStack::
+get_num_labels() const {
+  return _labels.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsLabelStack::highlight_label
+//       Access: Public
+//  Description: Draws a highlight around the label representing the
+//               indicated collector, and removes the highlight from
+//               any other label.  Specify -1 to remove the highlight
+//               from all labels.
+////////////////////////////////////////////////////////////////////
+void GtkStatsLabelStack::
+highlight_label(int collector_index) {
+  if (_highlight_label != collector_index) {
+    _highlight_label = collector_index;
+    Labels::iterator li;
+    for (li = _labels.begin(); li != _labels.end(); ++li) {
+      GtkStatsLabel *label = (*li);
+      label->set_highlight(label->get_collector_index() == _highlight_label);
+    }
+  }
+}

+ 62 - 0
pandatool/src/gtk-stats/gtkStatsLabelStack.h

@@ -0,0 +1,62 @@
+// Filename: gtkStatsLabelStack.h
+// Created by:  drose (16Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GTKSTATSLABELSTACK_H
+#define GTKSTATSLABELSTACK_H
+
+#include "pandatoolbase.h"
+#include "pvector.h"
+
+#include <gtk/gtk.h>
+
+class GtkStatsLabel;
+class GtkStatsMonitor;
+class GtkStatsGraph;
+
+////////////////////////////////////////////////////////////////////
+//       Class : GtkStatsLabelStack
+// Description : A widget that contains a stack of labels from bottom
+//               to top.
+////////////////////////////////////////////////////////////////////
+class GtkStatsLabelStack {
+public:
+  GtkStatsLabelStack();
+  ~GtkStatsLabelStack();
+
+  GtkWidget *setup();
+  bool is_setup() const;
+
+  int get_label_collector_index(int label_index) const;
+
+  void clear_labels();
+  int add_label(GtkStatsMonitor *monitor, GtkStatsGraph *graph,
+                int thread_index, int collector_index, bool use_fullname);
+  int get_num_labels() const;
+
+  void highlight_label(int collector_index);
+
+private:
+  GtkWidget *_widget;
+  int _highlight_label;
+
+  typedef pvector<GtkStatsLabel *> Labels;
+  Labels _labels;
+};
+
+#endif
+

+ 0 - 141
pandatool/src/gtk-stats/gtkStatsMainWindow.cxx

@@ -1,141 +0,0 @@
-// Filename: gtkStatsMainWindow.cxx
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "gtkStatsMainWindow.h"
-#include "gtkStats.h"
-#include "gtkStatsServer.h"
-
-#include "string_utils.h"
-
-#include <signal.h>
-
-static bool user_interrupted = false;
-
-// This simple signal handler lets us know when the user has pressed
-// control-C, so we can clean up nicely.
-static void signal_handler(int) {
-  user_interrupted = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMainWindow::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkStatsMainWindow::
-GtkStatsMainWindow(int port) : _port(port) {
-  nassertv(GtkStats::_main_window == (GtkStatsMainWindow *)NULL);
-  GtkStats::_main_window = this;
-
-  // Set up a global signal handler to catch Interrupt (Control-C) so
-  // we can clean up nicely if the user stops us.
-  signal(SIGINT, &signal_handler);
-
-  _server = new GtkStatsServer;
-  if (!_server->listen(_port)) {
-    nout << "Unable to open port.\n";
-    exit(1);
-  }
-
-  layout_window();
-  setup();
-
-  Gtk::Main::timeout.
-    connect(slot(this, &GtkStatsMainWindow::idle_callback), 200);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMainWindow::Destructor
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkStatsMainWindow::
-~GtkStatsMainWindow() {
-  nassertv(GtkStats::_main_window == this);
-  GtkStats::_main_window = NULL;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMainWindow::destruct
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-bool GtkStatsMainWindow::
-destruct() {
-  if (BasicGtkWindow::destruct()) {
-    nassertr(_server != (GtkStatsServer *)NULL, false);
-    delete _server;
-    GtkStats::quit();
-  }
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMainWindow::layout_window
-//       Access: Private
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsMainWindow::
-layout_window() {
-  set_title("Gtk Stats");
-
-  Gtk::VBox *box1 = new Gtk::VBox;
-  box1->show();
-  box1->set_border_width(8);
-  add(*manage(box1));
-
-  Gtk::Label *listening =
-    new Gtk::Label("Listening on port " + format_string(_port));
-  listening->show();
-  box1->pack_start(*manage(listening), true, false, 8);
-
-  Gtk::HBox *box2 = new Gtk::HBox;
-  box2->show();
-  box1->pack_start(*manage(box2), false, false, 0);
-
-  Gtk::Button *close = new Gtk::Button("Close");
-  close->set_usize(80, 30);
-  close->show();
-  box2->pack_start(*manage(close), true, false, 0);
-  close->clicked.connect(slot(this, &GtkStatsMainWindow::close_clicked));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMainWindow::close_clicked
-//       Access: Private
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsMainWindow::
-close_clicked() {
-  destruct();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMainWindow::idle_callback
-//       Access: Private
-//  Description:
-////////////////////////////////////////////////////////////////////
-gint GtkStatsMainWindow::
-idle_callback() {
-  if (user_interrupted) {
-    destruct();
-    return false;
-  }
-  _server->poll();
-  return true;
-}

+ 0 - 51
pandatool/src/gtk-stats/gtkStatsMainWindow.h

@@ -1,51 +0,0 @@
-// Filename: gtkStatsMainWindow.h
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef GTKSTATSMAINWINDOW_H
-#define GTKSTATSMAINWINDOW_H
-
-#include "pandatoolbase.h"
-
-#include "basicGtkWindow.h"
-
-class GtkStatsServer;
-
-////////////////////////////////////////////////////////////////////
-//       Class : GtkStatsMainWindow
-// Description : This is the main window that's opened up and stays up
-//               all the time when you run gtk-stats.  It just shows
-//               that it's running.
-////////////////////////////////////////////////////////////////////
-class GtkStatsMainWindow : public BasicGtkWindow {
-public:
-  GtkStatsMainWindow(int port);
-  virtual ~GtkStatsMainWindow();
-  virtual bool destruct();
-
-private:
-  void layout_window();
-  void close_clicked();
-  gint idle_callback();
-
-  int _port;
-  GtkStatsServer *_server;
-};
-
-
-#endif
-

+ 22 - 22
pandatool/src/gtkbase/gtkBase.h → pandatool/src/gtk-stats/gtkStatsMenuId.h

@@ -1,5 +1,5 @@
-// Filename: gtkBase.h
-// Created by:  drose (14Jul00)
+// Filename: gtkStatsMenuId.h
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -16,32 +16,32 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#ifndef GTKBASE_H
-#define GTKBASE_H
+#ifndef GTKSTATSMENUID_H
+#define GTKSTATSMENUID_H
 
 #include "pandatoolbase.h"
 
-#include "programBase.h"
-
-#include <gtk--.h>
-
 ////////////////////////////////////////////////////////////////////
-//       Class : GtkBase
-// Description : This is a specialization of ProgramBase for programs
-//               that use the Gtk-- GUI toolkit.
+//        Enum : GtkStatsMenuId
+// Description : The enumerated values here are used for menu ID's for
+//               the various pulldown menus in the application.
 ////////////////////////////////////////////////////////////////////
-class GtkBase : public ProgramBase {
-public:
-  GtkBase();
-  ~GtkBase();
-
-  virtual void parse_command_line(int argc, char *argv[]);
-  void main_loop();
-
-public:
-  static Gtk::Main *_gtk;
+enum GtkStatsMenuId {
+  MI_none,
+  MI_time_ms,
+  MI_time_hz,
+  MI_frame_rate_label,
+  MI_speed_1,
+  MI_speed_2,
+  MI_speed_3,
+  MI_speed_6,
+  MI_speed_12,
+  MI_pause,
+
+  // This one is last and represents the beginning of the range for
+  // the various "new chart" menu options.
+  MI_new_chart
 };
 
 #endif
 
-

+ 47 - 0
pandatool/src/gtk-stats/gtkStatsMonitor.I

@@ -0,0 +1,47 @@
+// Filename: gtkStatsMonitor.I
+// Created by:  drose (16Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::MenuDef::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsMonitor::MenuDef::
+MenuDef(int thread_index, int collector_index, bool show_level) :
+  _thread_index(thread_index),
+  _collector_index(collector_index),
+  _show_level(show_level)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::MenuDef::operator <
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+bool GtkStatsMonitor::MenuDef::
+operator < (const MenuDef &other) const {
+  if (_thread_index != other._thread_index) {
+    return _thread_index < other._thread_index;
+  }
+  if (_collector_index != other._collector_index) {
+    return _collector_index < other._collector_index;
+  }
+  return (int)_show_level < (int)other._show_level;
+}

+ 466 - 83
pandatool/src/gtk-stats/gtkStatsMonitor.cxx

@@ -1,5 +1,5 @@
 // Filename: gtkStatsMonitor.cxx
-// Created by:  drose (14Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -17,15 +17,36 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "gtkStatsMonitor.h"
-#include "gtkStatsWindow.h"
-#include "gtkStatsStripWindow.h"
-#include "gtkStatsBadVersionWindow.h"
+#include "gtkStats.h"
 #include "gtkStatsServer.h"
-
-#include "luse.h"
+#include "gtkStatsStripChart.h"
+/*
+#include "gtkStatsPianoRoll.h"
+#include "gtkStatsChartMenu.h"
+*/
+#include "gtkStatsMenuId.h"
+#include "pStatGraph.h"
 #include "pStatCollectorDef.h"
+#include "indent.h"
+
+typedef void vc();
+
+GtkItemFactoryEntry GtkStatsMonitor::menu_entries[] = {
+  { "/Options", NULL, NULL, 0, "<Branch>" },
+  { "/Options/Units", NULL, NULL, 0, "<Branch>" },
+  { "/Options/Units/ms", NULL, (vc *)&handle_menu_command, MI_time_ms, "<RadioItem>" },
+  { "/Options/Units/Hz", NULL, (vc *)&handle_menu_command, MI_time_hz, "/Options/Units/ms" },
+  { "/Speed", NULL, NULL, 0, "<Branch>" },
+  { "/Speed/1", NULL, (vc *)&handle_menu_command, MI_speed_1, "<RadioItem>" },
+  { "/Speed/2", NULL, (vc *)&handle_menu_command, MI_speed_2, "/Speed/1" },
+  { "/Speed/3", NULL, (vc *)&handle_menu_command, MI_speed_3, "/Speed/1" },
+  { "/Speed/6", NULL, (vc *)&handle_menu_command, MI_speed_6, "/Speed/1" },
+  { "/Speed/12", NULL, (vc *)&handle_menu_command, MI_speed_12, "/Speed/1" },
+  { "/Speed/sep", NULL, NULL, 0, "<Separator>" },
+  { "/Speed/pause", NULL, (vc *)&handle_menu_command, MI_pause, "<CheckItem>" },
+};
+int GtkStatsMonitor::num_menu_entries = sizeof(menu_entries) / sizeof(GtkItemFactoryEntry);
 
-#include <gdk--.h>
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GtkStatsMonitor::Constructor
@@ -34,44 +55,45 @@
 ////////////////////////////////////////////////////////////////////
 GtkStatsMonitor::
 GtkStatsMonitor(GtkStatsServer *server) : PStatMonitor(server) {
-  _destructing = false;
-  _new_collector = false;
+  _window = NULL;
+  _item_factory = NULL;
+
+  // These will be filled in later when the menu is created.
+  _time_units = 0;
+  _scroll_speed = 0.0;
+  _pause = false;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GtkStatsMonitor::Destructor
-//       Access: Public
+//       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
 GtkStatsMonitor::
 ~GtkStatsMonitor() {
-  _destructing = true;
+  Graphs::iterator gi;
+  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
+    delete (*gi);
+  }
+  _graphs.clear();
 
-  Windows::iterator wi;
-  for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
-    GtkStatsWindow *window = (*wi);
-    window->destruct();
+  /*
+  ChartMenus::iterator mi;
+  for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
+    delete (*mi);
   }
-}
+  _chart_menus.clear();
+  */
 
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMonitor::close_all_windows
-//       Access: Public
-//  Description: Closes all the windows associated with this client.
-//               This returns a PointerTo itself, just to guarantee
-//               that the monitor won't destruct until the function
-//               returns (as it might, if there were no other pointers
-//               to it).
-////////////////////////////////////////////////////////////////////
-PT(PStatMonitor) GtkStatsMonitor::
-close_all_windows() {
-  PT(PStatMonitor) temp = this;
-  Windows::iterator wi;
-  for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
-    GtkStatsWindow *window = (*wi);
-    window->destruct();
+  if (_window != NULL) {
+    gtk_widget_destroy(_window);
+    _window = NULL;
   }
-  return temp;
+
+#ifdef DEVELOP_GTKSTATS
+  // For Gtkstats developers, exit when the first monitor closes.
+  gtk_main_quit(0);
+#endif
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -82,7 +104,7 @@ close_all_windows() {
 ////////////////////////////////////////////////////////////////////
 string GtkStatsMonitor::
 get_monitor_name() {
-  return "Gtk Stats";
+  return "GtkStats";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -98,8 +120,6 @@ get_monitor_name() {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsMonitor::
 initialized() {
-  // Create a default window: a strip chart for the main thread.
-  new GtkStatsStripWindow(this, 0, 0, false, 400, 100);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -111,10 +131,8 @@ initialized() {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsMonitor::
 got_hello() {
-  Windows::iterator wi;
-  for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
-    (*wi)->update_title();
-  }
+  create_window();
+  open_strip_chart(0, 0, false);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -131,9 +149,29 @@ got_hello() {
 void GtkStatsMonitor::
 got_bad_version(int client_major, int client_minor,
                 int server_major, int server_minor) {
-  new GtkStatsBadVersionWindow(this, client_major, client_minor,
-                               server_major, server_minor);
-  close_all_windows();
+  ostringstream str;
+  str << "Unable to honor connection attempt from " 
+      << get_client_progname() << " on " << get_client_hostname() 
+      << ": unsupported PStats version " 
+      << client_major << "." << client_minor;
+
+  if (server_minor == 0) {
+    str << " (server understands version " << server_major
+        << "." << server_minor << " only).";
+  } else {
+    str << " (server understands versions " << server_major
+        << ".0 through " << server_major << "." << server_minor << ").";
+  }
+    
+  string message = str.str();
+  GtkWidget *dialog = 
+    gtk_message_dialog_new(GTK_WINDOW(main_window),
+			   GTK_DIALOG_DESTROY_WITH_PARENT,
+			   GTK_MESSAGE_ERROR,
+			   GTK_BUTTONS_CLOSE,
+			   message.c_str());
+  gtk_dialog_run(GTK_DIALOG(dialog));
+  gtk_widget_destroy(dialog);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -148,8 +186,41 @@ got_bad_version(int client_major, int client_minor,
 //               definitions midstream.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsMonitor::
-new_collector(int) {
-  _new_collector = true;
+new_collector(int collector_index) {
+  Graphs::iterator gi;
+  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
+    GtkStatsGraph *graph = (*gi);
+    graph->new_collector(collector_index);
+  }
+
+  /*
+  // We might need to update our menus.
+  ChartMenus::iterator mi;
+  for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
+    (*mi)->do_update();
+  }
+  */
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::new_thread
+//       Access: Public, Virtual
+//  Description: Called whenever a new Thread definition is
+//               received from the client.  Generally, the client will
+//               send all of its threads over shortly after
+//               connecting, but there's no guarantee that they will
+//               all be received before the first frames are received.
+//               The monitor should be prepared to accept new Thread
+//               definitions midstream.
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+new_thread(int thread_index) {
+  /*
+  GtkStatsChartMenu *chart_menu = new GtkStatsChartMenu(this, thread_index);
+  chart_menu->add_to_menu_bar(_menu_bar, MI_frame_rate_label);
+  _chart_menus.push_back(chart_menu);
+  DrawMenuBar(_window);
+  */
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -163,6 +234,11 @@ new_collector(int) {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsMonitor::
 new_data(int thread_index, int frame_number) {
+  Graphs::iterator gi;
+  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
+    GtkStatsGraph *graph = (*gi);
+    graph->new_data(thread_index, frame_number);
+  }
 }
 
 
@@ -176,9 +252,11 @@ new_data(int thread_index, int frame_number) {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsMonitor::
 lost_connection() {
-  Windows::iterator wi;
-  for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
-    (*wi)->mark_dead();
+  nout << "Lost connection to " << get_client_hostname() << "\n";
+
+  if (_window != NULL) {
+    gtk_widget_destroy(_window);
+    _window = NULL;
   }
 }
 
@@ -191,11 +269,29 @@ lost_connection() {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsMonitor::
 idle() {
-  Windows::iterator wi;
-  for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
-    (*wi)->idle();
+  /*
+  // Check if any of our chart menus need updating.
+  ChartMenus::iterator mi;
+  for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
+    (*mi)->check_update();
+  }
+
+  // Update the frame rate label from the main thread (thread 0).
+  const PStatThreadData *thread_data = get_client_data()->get_thread_data(0);
+  float frame_rate = thread_data->get_frame_rate();
+  if (frame_rate != 0.0f) {
+    char buffer[128];
+    sprintf(buffer, "%0.1f ms / %0.1f Hz", 1000.0f / frame_rate, frame_rate);
+  
+    MENUITEMINFO mii;
+    memset(&mii, 0, sizeof(mii));
+    mii.cbSize = sizeof(mii);
+    mii.fMask = MIIM_STRING;
+    mii.dwTypeData = buffer;
+    SetMenuItemInfo(_menu_bar, MI_frame_rate_label, FALSE, &mii);
+    DrawMenuBar(_window);
   }
-  _new_collector = false;
+  */
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -210,52 +306,339 @@ has_idle() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMonitor::is_thread_safe
+//     Function: GtkStatsMonitor::user_guide_bars_changed
 //       Access: Public, Virtual
-//  Description: Should be redefined to return true if this monitor
-//               class can handle running in a sub-thread.
-//
-//               This is not related to the question of whether it can
-//               handle multiple different PStatThreadDatas; this is
-//               strictly a question of whether or not the monitor
-//               itself wants to run in a sub-thread.
+//  Description: Called when the user guide bars have been changed.
 ////////////////////////////////////////////////////////////////////
-bool GtkStatsMonitor::
-is_thread_safe() {
-  return true;
+void GtkStatsMonitor::
+user_guide_bars_changed() {
+  Graphs::iterator gi;
+  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
+    GtkStatsGraph *graph = (*gi);
+    graph->user_guide_bars_changed();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMonitor::add_window
+//     Function: GtkStatsMonitor::get_window
 //       Access: Public
-//  Description: Called only from the GtkStatsWindow constructor, this
-//               indicates a new window that we should track.
+//  Description: Returns the window handle to the monitor's window.
+////////////////////////////////////////////////////////////////////
+GtkWidget *GtkStatsMonitor::
+get_window() const {
+  return _window;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::open_strip_chart
+//       Access: Public
+//  Description: Opens a new strip chart showing the indicated data.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsMonitor::
-add_window(GtkStatsWindow *window) {
-  nassertv(!_destructing);
-  bool inserted = _windows.insert(window).second;
-  nassertv(inserted);
+open_strip_chart(int thread_index, int collector_index, bool show_level) {
+  GtkStatsStripChart *graph = 
+    new GtkStatsStripChart(this, thread_index, collector_index, show_level);
+  add_graph(graph);
+
+  graph->set_time_units(_time_units);
+  graph->set_scroll_speed(_scroll_speed);
+  graph->set_pause(_pause);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsMonitor::remove_window
+//     Function: GtkStatsMonitor::open_piano_roll
 //       Access: Public
-//  Description: Called only from the GtkStatsWindow destructor, this
-//               indicates the end of a window that we should now no
-//               longer track.
-//
-//               When the last window is deleted, this automatically
-//               closes the connection.
+//  Description: Opens a new piano roll showing the indicated data.
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+open_piano_roll(int thread_index) {
+  /*
+  GtkStatsPianoRoll *graph = new GtkStatsPianoRoll(this, thread_index);
+  add_graph(graph);
+
+  graph->set_time_units(_time_units);
+  graph->set_scroll_speed(_scroll_speed);
+  graph->set_pause(_pause);
+  */
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::lookup_menu
+//       Access: Public
+//  Description: Returns the MenuDef properties associated with the
+//               indicated menu ID.  This specifies what we expect to
+//               do when the given menu has been selected.
+////////////////////////////////////////////////////////////////////
+const GtkStatsMonitor::MenuDef &GtkStatsMonitor::
+lookup_menu(int menu_id) const {
+  static MenuDef invalid(0, 0, false);
+  int menu_index = menu_id - MI_new_chart;
+  nassertr(menu_index >= 0 && menu_index < (int)_menu_by_id.size(), invalid);
+  return _menu_by_id[menu_index];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::get_menu_id
+//       Access: Public
+//  Description: Returns the menu ID that is reserved for the
+//               indicated MenuDef properties.  If this is the first
+//               time these particular properties have been requested,
+//               a new menu ID is returned; otherwise, the existing
+//               menu ID is returned.
+////////////////////////////////////////////////////////////////////
+int GtkStatsMonitor::
+get_menu_id(const MenuDef &menu_def) {
+  MenuByDef::iterator mi;
+  mi = _menu_by_def.find(menu_def);
+  if (mi != _menu_by_def.end()) {
+    return (*mi).second;
+  }
+
+  // Slot a new id.
+  int menu_id = (int)_menu_by_id.size() + MI_new_chart;
+  _menu_by_id.push_back(menu_def);
+  _menu_by_def[menu_def] = menu_id;
+
+  return menu_id;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::set_time_units
+//       Access: Public
+//  Description: Called when the user selects a new time units from
+//               the monitor pulldown menu, this should adjust the
+//               units for all graphs to the indicated mask if it is a
+//               time-based graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+set_time_units(int unit_mask) {
+  _time_units = unit_mask;
+
+  // First, change all of the open graphs appropriately.
+  Graphs::iterator gi;
+  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
+    GtkStatsGraph *graph = (*gi);
+    graph->set_time_units(_time_units);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::set_scroll_speed
+//       Access: Public
+//  Description: Called when the user selects a new scroll speed from
+//               the monitor pulldown menu, this should adjust the
+//               speeds for all graphs to the indicated value.
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+set_scroll_speed(float scroll_speed) {
+  _scroll_speed = scroll_speed;
+
+  // First, change all of the open graphs appropriately.
+  Graphs::iterator gi;
+  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
+    GtkStatsGraph *graph = (*gi);
+    graph->set_scroll_speed(_scroll_speed);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::set_pause
+//       Access: Public
+//  Description: Called when the user selects a pause on or pause off
+//               option from the menu.
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+set_pause(bool pause) {
+  _pause = pause;
+
+  // First, change all of the open graphs appropriately.
+  Graphs::iterator gi;
+  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
+    GtkStatsGraph *graph = (*gi);
+    graph->set_pause(_pause);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::add_graph
+//       Access: Private
+//  Description: Adds the newly-created graph to the list of managed
+//               graphs.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsMonitor::
-remove_window(GtkStatsWindow *window) {
-  if (!_destructing) {
-    bool removed = (_windows.erase(window) != 0);
-    nassertv(removed);
+add_graph(GtkStatsGraph *graph) {
+  _graphs.insert(graph);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::remove_graph
+//       Access: Private
+//  Description: Deletes the indicated graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+remove_graph(GtkStatsGraph *graph) {
+  Graphs::iterator gi = _graphs.find(graph);
+  if (gi != _graphs.end()) {
+    _graphs.erase(gi);
+    delete graph;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::create_window
+//       Access: Private
+//  Description: Creates the window for this monitor.
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+create_window() {
+  if (_window != NULL) {
+    return;
+  }
+
+  _window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+  g_signal_connect(G_OBJECT(_window), "delete_event",
+		   G_CALLBACK(window_delete_event), this);
+  g_signal_connect(G_OBJECT(_window), "destroy",
+		   G_CALLBACK(window_destroy), this);
+
+  _window_title = get_client_progname() + " on " + get_client_hostname();
+  gtk_window_set_title(GTK_WINDOW(_window), _window_title.c_str());
+
+  gtk_window_set_default_size(GTK_WINDOW(_window), 500, 360);
+
+  // Set up the menu.
+  GtkAccelGroup *accel_group = gtk_accel_group_new();
+  _item_factory = 
+    gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<PStats>", accel_group);
+  gtk_item_factory_create_items(_item_factory, num_menu_entries, menu_entries,
+				this);
+  gtk_window_add_accel_group(GTK_WINDOW(_window), accel_group);
+  GtkWidget *menubar = gtk_item_factory_get_widget(_item_factory, "<PStats>");
+
+    /*
+  ChartMenus::iterator mi;
+  for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
+    (*mi)->add_to_menu_bar(_menu_bar, MI_frame_rate_label);
+  }
+  */
+
+  // Pack the menu into the window.
+  GtkWidget *main_vbox = gtk_vbox_new(FALSE, 1);
+  //  gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
+  gtk_container_add(GTK_CONTAINER(_window), main_vbox);
+  gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
+
+  gtk_widget_show_all(_window);  
+  gtk_widget_show(_window);
+
+  set_time_units(PStatGraph::GBU_ms);
+  set_scroll_speed(3);
+  set_pause(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::window_delete_event
+//       Access: Private, Static
+//  Description: Callback when the window is closed by the user.
+////////////////////////////////////////////////////////////////////
+gboolean GtkStatsMonitor::
+window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
+  // Returning FALSE to indicate we should destroy the window
+  // when the user selects "close".
+  return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::window_delete_event
+//       Access: Private, Static
+//  Description: Callback when the window is destroyed by the system
+//               (or by delete_event).
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+window_destroy(GtkWidget *widget, gpointer data) {
+  GtkStatsMonitor *self = (GtkStatsMonitor *)data;
+  self->close();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::setup_frame_rate_label
+//       Access: Private
+//  Description: Creates the frame rate label on the right end of the
+//               menu bar.  This is used as a text label to display
+//               the main thread's frame rate to the user, although it
+//               is implemented as a right-justified toplevel menu
+//               item that doesn't open to anything.
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+setup_frame_rate_label() {
+  /*
+  MENUITEMINFO mii;
+  memset(&mii, 0, sizeof(mii));
+  mii.cbSize = sizeof(mii);
+
+  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
+  mii.fType = MFT_STRING | MFT_RIGHTJUSTIFY; 
+  mii.wID = MI_frame_rate_label;
+  mii.dwTypeData = ""; 
+  InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
+  */
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsMonitor::handle_menu_command
+//       Access: Private, Static
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void GtkStatsMonitor::
+handle_menu_command(gpointer callback_data, guint menu_id, GtkWidget *widget) {
+  GtkStatsMonitor *self = (GtkStatsMonitor *)callback_data;
+  switch (menu_id) {
+  case MI_none:
+    break;
+
+  case MI_time_ms:
+    self->set_time_units(PStatGraph::GBU_ms);
+    break;
+
+  case MI_time_hz:
+    self->set_time_units(PStatGraph::GBU_hz);
+    break;
+
+  case MI_speed_1:
+    self->set_scroll_speed(1);
+    break;
+
+  case MI_speed_2:
+    self->set_scroll_speed(2);
+    break;
+
+  case MI_speed_3:
+    self->set_scroll_speed(3);
+    break;
+
+  case MI_speed_6:
+    self->set_scroll_speed(6);
+    break;
+
+  case MI_speed_12:
+    self->set_scroll_speed(12);
+    break;
+
+  case MI_pause:
+    self->set_pause(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
+    break;
 
-    if (_windows.empty()) {
-      close();
+  default:
+    if (menu_id >= MI_new_chart) {
+      const MenuDef &menu_def = self->lookup_menu(menu_id);
+      if (menu_def._collector_index < 0) {
+        self->open_piano_roll(menu_def._thread_index);
+      } else {
+        self->open_strip_chart(menu_def._thread_index, 
+			       menu_def._collector_index,
+			       menu_def._show_level);
+      }
     }
   }
 }

+ 68 - 16
pandatool/src/gtk-stats/gtkStatsMonitor.h

@@ -1,5 +1,5 @@
 // Filename: gtkStatsMonitor.h
-// Created by:  drose (14Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -21,25 +21,37 @@
 
 #include "pandatoolbase.h"
 
+#include "gtkStatsGraph.h"
 #include "pStatMonitor.h"
 #include "pointerTo.h"
-
 #include "pset.h"
+#include "pvector.h"
+#include "pmap.h"
+
+#include <gtk/gtk.h>
 
 class GtkStatsServer;
-class GtkStatsWindow;
-class Gdk_Color;
+class GtkStatsChartMenu;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GtkStatsMonitor
-// Description :
+// Description : This class represents a connection to a PStatsClient
+//               and manages the data exchange with the client.
 ////////////////////////////////////////////////////////////////////
 class GtkStatsMonitor : public PStatMonitor {
 public:
-  GtkStatsMonitor(GtkStatsServer *server);
-  ~GtkStatsMonitor();
+  class MenuDef {
+  public:
+    INLINE MenuDef(int thread_index, int collector_index, bool show_level);
+    INLINE bool operator < (const MenuDef &other) const;
+
+    int _thread_index;
+    int _collector_index;
+    bool _show_level;
+  };
 
-  PT(PStatMonitor) close_all_windows();
+  GtkStatsMonitor(GtkStatsServer *server);
+  virtual ~GtkStatsMonitor();
 
   virtual string get_monitor_name();
 
@@ -48,21 +60,61 @@ public:
   virtual void got_bad_version(int client_major, int client_minor,
                                int server_major, int server_minor);
   virtual void new_collector(int collector_index);
+  virtual void new_thread(int thread_index);
   virtual void new_data(int thread_index, int frame_number);
   virtual void lost_connection();
   virtual void idle();
   virtual bool has_idle();
-  virtual bool is_thread_safe();
 
-public:
-  void add_window(GtkStatsWindow *window);
-  void remove_window(GtkStatsWindow *window);
+  virtual void user_guide_bars_changed();
+
+  GtkWidget *get_window() const;
+  void open_strip_chart(int thread_index, int collector_index, bool show_level);
+  void open_piano_roll(int thread_index);
+
+  const MenuDef &lookup_menu(int menu_id) const;
+  int get_menu_id(const MenuDef &menu_def);
 
-  typedef pset<GtkStatsWindow *> Windows;
-  Windows _windows;
+  void set_time_units(int unit_mask);
+  void set_scroll_speed(float scroll_speed);
+  void set_pause(bool pause);
+  
+private:
+  void add_graph(GtkStatsGraph *graph);
+  void remove_graph(GtkStatsGraph *graph);
 
-  bool _destructing;
-  bool _new_collector;
+  void create_window();
+  static gboolean window_delete_event(GtkWidget *widget, GdkEvent *event, 
+				      gpointer data);
+  static void window_destroy(GtkWidget *widget, gpointer data);
+  void setup_frame_rate_label();
+
+  static void handle_menu_command(gpointer callback_data, guint menu_id, GtkWidget *widget);
+
+  typedef pset<GtkStatsGraph *> Graphs;
+  Graphs _graphs;
+
+  typedef pvector<GtkStatsChartMenu *> ChartMenus;
+  ChartMenus _chart_menus;
+
+  typedef pvector<MenuDef> MenuById;
+  typedef pmap<MenuDef, int> MenuByDef;
+  MenuById _menu_by_id;
+  MenuByDef _menu_by_def;
+
+  GtkWidget *_window;
+  GtkItemFactory *_item_factory;
+  string _window_title;
+  int _time_units;
+  float _scroll_speed;
+  bool _pause;
+
+  static GtkItemFactoryEntry menu_entries[];
+  static int num_menu_entries;
+
+  friend class GtkStatsGraph;
 };
 
+#include "gtkStatsMonitor.I"
+
 #endif

+ 0 - 17
pandatool/src/gtk-stats/gtkStatsPianoRoll.I

@@ -1,17 +0,0 @@
-// Filename: gtkStatsPianoRoll.I
-// Created by:  drose (18Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////

+ 507 - 190
pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx

@@ -1,5 +1,5 @@
 // Filename: gtkStatsPianoRoll.cxx
-// Created by:  drose (18Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -17,16 +17,14 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "gtkStatsPianoRoll.h"
-#include "gtkStatsLabel.h"
-#include "gtkStatsGuide.h"
+#include "gtkStatsMonitor.h"
+#include "numeric_types.h"
 
-#include "request_initial_size.h"
-#include "pStatThreadData.h"
-#include "pStatFrameData.h"
-#include "pStatView.h"
-
-#include <algorithm>
+static const int default_piano_roll_width = 400;
+static const int default_piano_roll_height = 200;
 
+bool GtkStatsPianoRoll::_window_class_registered = false;
+const char * const GtkStatsPianoRoll::_window_class_name = "piano";
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GtkStatsPianoRoll::Constructor
@@ -34,115 +32,147 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 GtkStatsPianoRoll::
-GtkStatsPianoRoll(GtkStatsMonitor *monitor, int thread_index,
-                  int xsize, int ysize) :
-  PStatPianoRoll(monitor, thread_index, xsize, ysize)
+GtkStatsPianoRoll(GtkStatsMonitor *monitor, int thread_index) :
+  PStatPianoRoll(monitor, thread_index, 
+                 default_piano_roll_width,
+                 default_piano_roll_height),
+  GtkStatsGraph(monitor, thread_index)
 {
-  _is_dead = false;
-  set_events(GDK_EXPOSURE_MASK);
+  _left_margin = 128;
+  _right_margin = 8;
+  _top_margin = 16;
+  _bottom_margin = 8;
 
-  _label_align = manage(new Gtk::Alignment(1.0, 1.0));
-  _label_align->show();
+  // Let's show the units on the guide bar labels.  There's room.
+  set_guide_bar_units(get_guide_bar_units() | GBU_show_units);
 
-  _label_box = NULL;
-  pack_labels();
+  create_window();
+  clear_region();
+}
 
-  request_initial_size(*this, get_xsize(), get_ysize());
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsPianoRoll::
+~GtkStatsPianoRoll() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoRoll::mark_dead
-//       Access: Public
-//  Description: Called when the client's connection has been lost,
-//               this should update the window in some obvious way to
-//               indicate that the window is no longer live.
+//     Function: GtkStatsPianoRoll::idle
+//       Access: Public, Virtual
+//  Description: Called as each frame's data is made available.  There
+//               is no gurantee the frames will arrive in order, or
+//               that all of them will arrive at all.  The monitor
+//               should be prepared to accept frames received
+//               out-of-order or missing.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsPianoRoll::
-mark_dead() {
-  _is_dead = true;
-
-  setup_white_gc();
-  force_redraw();
+new_data(int thread_index, int frame_number) {
+  if (!_pause) {
+    update();
+  }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::force_redraw
+//       Access: Public, Virtual
+//  Description: Called when it is necessary to redraw the entire graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+force_redraw() {
+  PStatPianoRoll::force_redraw();
+}
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoRoll::get_labels
-//       Access: Public
-//  Description: Returns an alignment widget that contains all of the
-//               labels appropriate to this chart, already formatted
-//               and stacked up bottom-to-top.  The window should pack
-//               this widget suitably near the strip chart.
-////////////////////////////////////////////////////////////////////
-Gtk::Alignment *GtkStatsPianoRoll::
-get_labels() {
-  return _label_align;
+//     Function: GtkStatsPianoRoll::changed_graph_size
+//       Access: Public, Virtual
+//  Description: Called when the user has resized the window, forcing
+//               a resize of the graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+changed_graph_size(int graph_xsize, int graph_ysize) {
+  PStatPianoRoll::changed_size(graph_xsize, graph_ysize);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoRoll::get_collector_gc
-//       Access: Public
-//  Description: Returns a graphics context suitable for drawing in
-//               the indicated collector's color.
-////////////////////////////////////////////////////////////////////
-Gdk_GC GtkStatsPianoRoll::
-get_collector_gc(int collector_index) {
-  GCs::iterator gi;
-  gi = _gcs.find(collector_index);
-  if (gi != _gcs.end()) {
-    return (*gi).second;
+//     Function: GtkStatsPianoRoll::set_time_units
+//       Access: Public, Virtual
+//  Description: Called when the user selects a new time units from
+//               the monitor pulldown menu, this should adjust the
+//               units for the graph to the indicated mask if it is a
+//               time-based graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+set_time_units(int unit_mask) {
+  int old_unit_mask = get_guide_bar_units();
+  if ((old_unit_mask & (GBU_hz | GBU_ms)) != 0) {
+    unit_mask = unit_mask & (GBU_hz | GBU_ms);
+    unit_mask |= (old_unit_mask & GBU_show_units);
+    set_guide_bar_units(unit_mask);
+
+    RECT rect;
+    GetClientRect(_window, &rect);
+    rect.left = _right_margin;
+    InvalidateRect(_window, &rect, TRUE);
   }
+}
 
-  // Ask the monitor what color this guy should be.
-  RGBColorf rgb = get_monitor()->get_collector_color(collector_index);
-  Gdk_Color color;
-  color.set_rgb_p(rgb[0], rgb[1], rgb[2]);
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::clicked_label
+//       Access: Public, Virtual
+//  Description: Called when the user single-clicks on a label.
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+clicked_label(int collector_index) {
+  if (collector_index >= 0) {
+    GtkStatsGraph::_monitor->open_strip_chart(GtkStatsGraph::_thread_index, collector_index, false);
+  }
+}
 
-  // Now allocate the color from the system colormap.
-  Gdk_Colormap::get_system().alloc(color);
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::set_horizontal_scale
+//       Access: Public
+//  Description: Changes the amount of time the width of the
+//               horizontal axis represents.  This may force a redraw.
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+set_horizontal_scale(float time_width) {
+  PStatPianoRoll::set_horizontal_scale(time_width);
 
-  // Allocate a new graphics context.
-  Gdk_GC gc(_pixmap);
-  gc.set_foreground(color);
+  RECT rect;
+  GetClientRect(_window, &rect);
+  rect.bottom = _top_margin;
+  InvalidateRect(_window, &rect, TRUE);
+}
 
-  _gcs[collector_index] = gc;
-  return gc;
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::clear_region
+//       Access: Protected
+//  Description: Erases the chart area.
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+clear_region() {
+  RECT rect = { 0, 0, get_xsize(), get_ysize() };
+  FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GtkStatsPianoRoll::begin_draw
 //       Access: Protected, Virtual
-//  Description: Erases the chart area in preparation for drawing it
-//               full of bars.
+//  Description: Erases the chart area in preparation for drawing a
+//               bunch of bars.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsPianoRoll::
 begin_draw() {
-  _pixmap.draw_rectangle(_white_gc, true, 0, 0, get_xsize(), get_ysize());
-
-  Gdk_Font font = get_style()->gtkobj()->font;
-  int text_height = font.height();
+  clear_region();
 
   // Draw in the guide bars.
   int num_guide_bars = get_num_guide_bars();
   for (int i = 0; i < num_guide_bars; i++) {
-    const GuideBar &bar = get_guide_bar(i);
-    int x = (int)((float)get_xsize() * bar._height / get_horizontal_scale());
-
-    if (x >= 5 && x <= get_xsize() - 5) {
-      // Only draw it if it's not too close to either edge.
-      switch (bar._style) {
-      case GBS_target:
-        _pixmap.draw_line(_light_gc, x, text_height + 4, x, get_ysize());
-        break;
-
-      case GBS_normal:
-      default:
-        _pixmap.draw_line(_dark_gc, x, text_height + 4, x, get_ysize());
-        break;
-      }
-    }
+    draw_guide_bar(_bitmap_dc, get_guide_bar(i));
   }
-
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -152,10 +182,17 @@ begin_draw() {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsPianoRoll::
 draw_bar(int row, int from_x, int to_x) {
-  if (row >= 0 && row < (int)_y_positions.size()) {
-    int y = height() - _y_positions[row];
-    _pixmap.draw_rectangle(get_collector_gc(get_label_collector(row)),
-                           true, from_x, y - 6, to_x - from_x, 12);
+  if (row >= 0 && row < _label_stack.get_num_labels()) {
+    int y = _label_stack.get_label_y(row) - _graph_top;
+    int height = _label_stack.get_label_height(row);
+
+    RECT rect = { 
+      from_x, y - height + 2,
+      to_x, y - 2,
+    };
+    int collector_index = get_label_collector(row);
+    HBRUSH brush = get_collector_brush(collector_index);
+    FillRect(_bitmap_dc, &rect, brush);
   }
 }
 
@@ -167,31 +204,7 @@ draw_bar(int row, int from_x, int to_x) {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsPianoRoll::
 end_draw() {
-  // Draw in the labels for the guide bars.  We do this in end_draw()
-  // instead of in begin_draw() so the labels will appear on top of
-  // any of the color bars.
-  Gdk_Font font = get_style()->gtkobj()->font;
-  int text_ascent = font.ascent();
-
-  int num_guide_bars = get_num_guide_bars();
-  for (int i = 0; i < num_guide_bars; i++) {
-    const GuideBar &bar = get_guide_bar(i);
-    int x = (int)((float)get_xsize() * bar._height / get_horizontal_scale());
-
-    if (x >= 5 && x <= get_xsize() - 5) {
-      // Only draw it if it's not too close to either edge.
-      int width = font.string_measure(bar._label);
-      _pixmap.draw_string(font, _black_gc, x - width / 2, text_ascent + 2,
-                          bar._label);
-    }
-  }
-
-  GdkRectangle update_rect;
-  update_rect.x = 0;
-  update_rect.y = 0;
-  update_rect.width = get_xsize();
-  update_rect.height = get_ysize();
-  draw(&update_rect);
+  InvalidateRect(_graph_window, NULL, FALSE);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -202,126 +215,430 @@ end_draw() {
 void GtkStatsPianoRoll::
 idle() {
   if (_labels_changed) {
-    pack_labels();
+    update_labels();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::window_proc
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+LONG GtkStatsPianoRoll::
+window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+  switch (msg) {
+  case WM_LBUTTONDOWN:
+    if (_potential_drag_mode == DM_new_guide_bar) {
+      set_drag_mode(DM_new_guide_bar);
+      SetCapture(_graph_window);
+      return 0;
+    }
+    break;
+
+  default:
+    break;
   }
+
+  return GtkStatsGraph::window_proc(hwnd, msg, wparam, lparam);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoRoll::configure_event_impl
-//       Access: Private, Virtual
-//  Description: Creates a new backing pixmap of the appropriate size.
+//     Function: GtkStatsPianoRoll::graph_window_proc
+//       Access: Protected
+//  Description: 
 ////////////////////////////////////////////////////////////////////
-gint GtkStatsPianoRoll::
-configure_event_impl(GdkEventConfigure *) {
-  if (width() != get_xsize() || height() != get_ysize() ||
-      _pixmap.gdkobj() == (GdkDrawable *)NULL) {
-    if (_pixmap) {
-      _pixmap.release();
+LONG GtkStatsPianoRoll::
+graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+  switch (msg) {
+  case WM_LBUTTONDOWN:
+    if (_potential_drag_mode == DM_none) {
+      set_drag_mode(DM_scale);
+      PN_int16 x = LOWORD(lparam);
+      _drag_scale_start = pixel_to_height(x);
+      SetCapture(_graph_window);
+      return 0;
+
+    } else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) {
+      set_drag_mode(DM_guide_bar);
+      PN_int16 x = LOWORD(lparam);
+      _drag_start_x = x;
+      SetCapture(_graph_window);
+      return 0;
+    }
+    break;
+
+  case WM_MOUSEMOVE: 
+    if (_drag_mode == DM_none && _potential_drag_mode == DM_none) {
+      // When the mouse is over a color bar, highlight it.
+      PN_int16 x = LOWORD(lparam);
+      PN_int16 y = HIWORD(lparam);
+      _label_stack.highlight_label(get_collector_under_pixel(x, y));
+
+      // Now we want to get a WM_MOUSELEAVE when the mouse leaves the
+      // graph window.
+      TRACKMOUSEEVENT tme = {
+        sizeof(TRACKMOUSEEVENT),
+        TME_LEAVE,
+        _graph_window,
+        0
+      };
+      TrackMouseEvent(&tme);
+
+    } else {
+      // If the mouse is in some drag mode, stop highlighting.
+      _label_stack.highlight_label(-1);
+    }
+
+    if (_drag_mode == DM_scale) {
+      PN_int16 x = LOWORD(lparam);
+      float ratio = (float)x / (float)get_xsize();
+      if (ratio > 0.0f) {
+        set_horizontal_scale(_drag_scale_start / ratio);
+      }
+      return 0;
+
+    } else if (_drag_mode == DM_new_guide_bar) {
+      // We haven't created the new guide bar yet; we won't until the
+      // mouse comes within the graph's region.
+      PN_int16 x = LOWORD(lparam);
+      if (x >= 0 && x < get_xsize()) {
+        set_drag_mode(DM_guide_bar);
+        _drag_guide_bar = add_user_guide_bar(pixel_to_height(x));
+        return 0;
+      }
+
+    } else if (_drag_mode == DM_guide_bar) {
+      PN_int16 x = LOWORD(lparam);
+      move_user_guide_bar(_drag_guide_bar, pixel_to_height(x));
+      return 0;
+    }
+    break;
+
+  case WM_MOUSELEAVE:
+    // When the mouse leaves the graph, stop highlighting.
+    _label_stack.highlight_label(-1);
+    break;
+
+  case WM_LBUTTONUP:
+    if (_drag_mode == DM_scale) {
+      set_drag_mode(DM_none);
+      ReleaseCapture();
+      return 0;
+
+    } else if (_drag_mode == DM_guide_bar) {
+      PN_int16 x = LOWORD(lparam);
+      if (x < 0 || x >= get_xsize()) {
+        remove_user_guide_bar(_drag_guide_bar);
+      } else {
+        move_user_guide_bar(_drag_guide_bar, pixel_to_height(x));
+      }
+      set_drag_mode(DM_none);
+      ReleaseCapture();
+      return 0;
+    }
+    break;
+
+  case WM_LBUTTONDBLCLK:
+    {
+      // Double-clicking on a color bar in the graph is the same as
+      // double-clicking on the corresponding label.
+      PN_int16 x = LOWORD(lparam);
+      PN_int16 y = HIWORD(lparam);
+      clicked_label(get_collector_under_pixel(x, y));
+      return 0;
     }
+    break;
 
-    _pixmap.create(get_window(), width(), height());
+  default:
+    break;
+  }
 
-    Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
+  return GtkStatsGraph::graph_window_proc(hwnd, msg, wparam, lparam);
+}
 
-    _white_gc = Gdk_GC(_pixmap);
-    setup_white_gc();
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::additional_window_paint
+//       Access: Protected, Virtual
+//  Description: This is called during the servicing of WM_PAINT; it
+//               gives a derived class opportunity to do some further
+//               painting into the window (the outer window, not the
+//               graph window).
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+additional_window_paint(HDC hdc) {
+  // Draw in the labels for the guide bars.
+  HFONT hfnt = (HFONT)GetStockObject(ANSI_VAR_FONT); 
+  SelectObject(hdc, hfnt);
+  SetTextAlign(hdc, TA_LEFT | TA_BOTTOM);
+  SetBkMode(hdc, TRANSPARENT);
 
-    _black_gc = Gdk_GC(_pixmap);
-    _black_gc.set_foreground(system_colormap.black());
+  int y = _top_margin;
 
-    _dark_gc = Gdk_GC(_pixmap);
-    Gdk_Color dark;
-    dark.set_grey_p(0.2);
-    system_colormap.alloc(dark);
-    _dark_gc.set_foreground(dark);
+  int i;
+  int num_guide_bars = get_num_guide_bars();
+  for (i = 0; i < num_guide_bars; i++) {
+    draw_guide_label(hdc, y, get_guide_bar(i));
+  }
 
-    _light_gc = Gdk_GC(_pixmap);
-    Gdk_Color light;
-    light.set_grey_p(0.6);
-    system_colormap.alloc(light);
-    _light_gc.set_foreground(light);
+  int num_user_guide_bars = get_num_user_guide_bars();
+  for (i = 0; i < num_user_guide_bars; i++) {
+    draw_guide_label(hdc, y, get_user_guide_bar(i));
+  }
+}
 
-    _pixmap.draw_rectangle(_white_gc, true, 0, 0, width(), height());
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::additional_graph_window_paint
+//       Access: Protected, Virtual
+//  Description: This is called during the servicing of WM_PAINT; it
+//               gives a derived class opportunity to do some further
+//               painting into the window (the outer window, not the
+//               graph window).
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+additional_graph_window_paint(HDC hdc) {
+  int num_user_guide_bars = get_num_user_guide_bars();
+  for (int i = 0; i < num_user_guide_bars; i++) {
+    draw_guide_bar(hdc, get_user_guide_bar(i));
+  }
+}
 
-    changed_size(width(), height());
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::consider_drag_start
+//       Access: Protected, Virtual
+//  Description: Based on the mouse position within the window's
+//               client area, look for draggable things the mouse
+//               might be hovering over and return the apprioprate
+//               DragMode enum or DM_none if nothing is indicated.
+////////////////////////////////////////////////////////////////////
+GtkStatsGraph::DragMode GtkStatsPianoRoll::
+consider_drag_start(int mouse_x, int mouse_y, int width, int height) {
+  if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) {
+    if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) {
+      // See if the mouse is over a user-defined guide bar.
+      int x = mouse_x - _graph_left;
+      float from_height = pixel_to_height(x - 2);
+      float to_height = pixel_to_height(x + 2);
+      _drag_guide_bar = find_user_guide_bar(from_height, to_height);
+      if (_drag_guide_bar >= 0) {
+        return DM_guide_bar;
+      }
+
+    } else if (mouse_x < _left_margin - 2 ||
+               mouse_x > width - _right_margin + 2) {
+      // The mouse is left or right of the graph; maybe create a new
+      // guide bar.
+      return DM_new_guide_bar;
+    }
   }
-  return true;
+
+  return GtkStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoRoll::expose_event_impl
-//       Access: Private, Virtual
-//  Description: Redraw the screen from the backing pixmap.
+//     Function: GtkStatsPianoRoll::get_collector_under_pixel
+//       Access: Private
+//  Description: Returns the collector index associated with the
+//               indicated vertical row, or -1.
 ////////////////////////////////////////////////////////////////////
-gint GtkStatsPianoRoll::
-expose_event_impl(GdkEventExpose *event) {
-  get_window().draw_pixmap(_white_gc, _pixmap,
-                           event->area.x, event->area.y,
-                           event->area.x, event->area.y,
-                           event->area.width, event->area.height);
+int GtkStatsPianoRoll::
+get_collector_under_pixel(int xpoint, int ypoint) {
+  if (_label_stack.get_num_labels() == 0) {
+    return -1;
+  }
 
-  return false;
+  // Assume all of the labels are the same height.
+  int height = _label_stack.get_label_height(0);
+  int row = (get_ysize() - ypoint) / height;
+  if (row >= 0 && row < _label_stack.get_num_labels()) {
+    return _label_stack.get_label_collector_index(row);
+  } else {
+    return -1;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoRoll::pack_labels
+//     Function: GtkStatsPianoRoll::update_labels
 //       Access: Private
-//  Description:
+//  Description: Resets the list of labels.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsPianoRoll::
-pack_labels() {
-  // First, remove the old labels.
-  _label_align->remove();
+update_labels() {
+  _label_stack.clear_labels();
+  for (int i = 0; i < get_num_labels(); i++) {
+    int label_index = 
+      _label_stack.add_label(GtkStatsGraph::_monitor, this,
+                             GtkStatsGraph::_thread_index,
+                             get_label_collector(i), true);
+  }
+  _labels_changed = false;
+}
 
-  // Now add the new labels back in.
-  _label_box = manage(new Gtk::VBox);
-  _label_box->show();
-  _label_align->add(*_label_box);
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::draw_guide_bar
+//       Access: Private
+//  Description: Draws the line for the indicated guide bar on the
+//               graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+draw_guide_bar(HDC hdc, const PStatGraph::GuideBar &bar) {
+  int x = height_to_pixel(bar._height);
+
+  if (x > 0 && x < get_xsize() - 1) {
+    // Only draw it if it's not too close to either edge.
+    switch (bar._style) {
+    case GBS_target:
+      SelectObject(hdc, _light_pen);
+      break;
+
+    case GBS_user:
+      SelectObject(hdc, _user_guide_bar_pen);
+      break;
+      
+    case GBS_normal:
+      SelectObject(hdc, _dark_pen);
+      break;
+    }
+    MoveToEx(hdc, x, 0, NULL);
+    LineTo(hdc, x, get_ysize());
+  }
+}
 
-  Gdk_Font font = get_style()->gtkobj()->font;
-  int num_labels = get_num_labels();
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::draw_guide_label
+//       Access: Private
+//  Description: Draws the text for the indicated guide bar label at
+//               the top of the graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+draw_guide_label(HDC hdc, int y, const PStatGraph::GuideBar &bar) {
+  switch (bar._style) {
+  case GBS_target:
+    SetTextColor(hdc, _light_color);
+    break;
+    
+  case GBS_user:
+    SetTextColor(hdc, _user_guide_bar_color);
+    break;
+    
+  case GBS_normal:
+    SetTextColor(hdc, _dark_color);
+    break;
+  }
 
-  while ((int)_y_positions.size() < num_labels) {
-    _y_positions.push_back(0);
+  int x = height_to_pixel(bar._height);
+  const string &label = bar._label;
+  SIZE size;
+  GetTextExtentPoint32(hdc, label.data(), label.length(), &size);
+
+  if (bar._style != GBS_user) {
+    float from_height = pixel_to_height(x - size.cx);
+    float to_height = pixel_to_height(x + size.cx);
+    if (find_user_guide_bar(from_height, to_height) >= 0) {
+      // Omit the label: there's a user-defined guide bar in the same space.
+      return;
+    }
   }
 
-  int y = 0;
-  for (int i = 0; i < num_labels; i++) {
-    int collector_index = get_label_collector(i);
-    GtkStatsLabel *label =
-      new GtkStatsLabel(get_monitor(), collector_index, font);
-    label->show();
+  int this_x = _graph_left + x - size.cx / 2;
+  if (x >= 0 && x < get_xsize()) {
+    TextOut(hdc, this_x, y,
+            label.data(), label.length()); 
+  }
+}
 
-    _label_box->pack_end(*manage(label), false, false);
-    _y_positions[i] = y + label->get_height() / 2;
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::create_window
+//       Access: Private
+//  Description: Creates the window for this strip chart.
+////////////////////////////////////////////////////////////////////
+void GtkStatsPianoRoll::
+create_window() {
+  if (_window) {
+    return;
+  }
 
-    y += label->get_height();
+  HINSTANCE application = GetModuleHandle(NULL);
+  register_window_class(application);
+
+  const PStatClientData *client_data = 
+    GtkStatsGraph::_monitor->get_client_data();
+  string thread_name = client_data->get_thread_name(GtkStatsGraph::_thread_index);
+  string window_title = thread_name + " thread piano roll";
+
+
+  RECT win_rect = { 
+    0, 0,
+    _left_margin + get_xsize() + _right_margin, 
+    _top_margin + get_ysize() + _bottom_margin
+  };  
+  
+  // compute window size based on desired client area size
+  AdjustWindowRect(&win_rect, graph_window_style, FALSE);
+
+  _window = 
+    CreateWindow(_window_class_name, window_title.c_str(), graph_window_style,
+                 CW_USEDEFAULT, CW_USEDEFAULT,
+                 win_rect.right - win_rect.left,
+                 win_rect.bottom - win_rect.top,
+                 GtkStatsGraph::_monitor->get_window(), NULL, application, 0);
+  if (!_window) {
+    nout << "Could not create PianoRoll window!\n";
+    exit(1);
   }
 
-  _labels_changed = false;
+  SetWindowLongPtr(_window, 0, (LONG_PTR)this);
+  setup_label_stack();
+
+  // Ensure that the window is on top of the stack.
+  SetWindowPos(_window, HWND_TOP, 0, 0, 0, 0, 
+               SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoRoll::setup_white_gc
-//       Access: Private
-//  Description: Sets the color on _white_gc to be either actually
-//               white (if the chart is still alive) or a light gray
-//               (if the chart is dead).
+//     Function: GtkStatsPianoRoll::register_window_class
+//       Access: Private, Static
+//  Description: Registers the window class for the pianoRoll window, if
+//               it has not already been registered.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsPianoRoll::
-setup_white_gc() {
-  Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
+register_window_class(HINSTANCE application) {
+  if (_window_class_registered) {
+    return;
+  }
 
-  if (_is_dead) {
-    Gdk_Color death;
-    death.set_grey_p(0.8);
-    system_colormap.alloc(death);
+  WNDCLASS wc;
+
+  ZeroMemory(&wc, sizeof(WNDCLASS));
+  wc.style = 0;
+  wc.lpfnWndProc = (WNDPROC)static_window_proc;
+  wc.hInstance = application;
+  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+  wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
+  wc.lpszMenuName = NULL;
+  wc.lpszClassName = _window_class_name;
+
+  // Reserve space to associate the this pointer with the window.
+  wc.cbWndExtra = sizeof(GtkStatsPianoRoll *);
+  
+  if (!RegisterClass(&wc)) {
+    nout << "Could not register PianoRoll window class!\n";
+    exit(1);
+  }
 
-    _white_gc.set_foreground(death);
+  _window_class_registered = true;
+}
 
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsPianoRoll::static_window_proc
+//       Access: Private, Static
+//  Description: 
+////////////////////////////////////////////////////////////////////
+LONG WINAPI GtkStatsPianoRoll::
+static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+  GtkStatsPianoRoll *self = (GtkStatsPianoRoll *)GetWindowLongPtr(hwnd, 0);
+  if (self != (GtkStatsPianoRoll *)NULL && self->_window == hwnd) {
+    return self->window_proc(hwnd, msg, wparam, lparam);
   } else {
-    _white_gc.set_foreground(system_colormap.white());
+    return DefWindowProc(hwnd, msg, wparam, lparam);
   }
-
 }
-

+ 34 - 45
pandatool/src/gtk-stats/gtkStatsPianoRoll.h

@@ -1,5 +1,5 @@
 // Filename: gtkStatsPianoRoll.h
-// Created by:  drose (18Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -21,72 +21,61 @@
 
 #include "pandatoolbase.h"
 
-#include "gtkStatsMonitor.h"
-
+#include "gtkStatsGraph.h"
 #include "pStatPianoRoll.h"
 #include "pointerTo.h"
 
-#include <gtk--.h>
-#include "pmap.h"
+#include <windows.h>
 
-class PStatView;
-class GtkStatsGuide;
+class GtkStatsMonitor;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GtkStatsPianoRoll
-// Description : A special widget that draws a piano-roll style chart,
+// Description : A window that draws a piano-roll style chart,
 //               which shows the collectors explicitly stopping and
 //               starting, one frame at a time.
 ////////////////////////////////////////////////////////////////////
-class GtkStatsPianoRoll : public Gtk::DrawingArea, public PStatPianoRoll {
+class GtkStatsPianoRoll : public PStatPianoRoll, public GtkStatsGraph {
 public:
-  GtkStatsPianoRoll(GtkStatsMonitor *monitor, int thread_index,
-                    int xsize, int ysize);
-
-  void mark_dead();
+  GtkStatsPianoRoll(GtkStatsMonitor *monitor, int thread_index);
+  virtual ~GtkStatsPianoRoll();
 
-  Gtk::Alignment *get_labels();
+  virtual void new_data(int thread_index, int frame_number);
+  virtual void force_redraw();
+  virtual void changed_graph_size(int graph_xsize, int graph_ysize);
 
-  Gdk_GC get_collector_gc(int collector_index);
+  virtual void set_time_units(int unit_mask);
+  virtual void clicked_label(int collector_index);
+  void set_horizontal_scale(float time_width);
 
-private:
+protected:
+  void clear_region();
   virtual void begin_draw();
   virtual void draw_bar(int row, int from_x, int to_x);
   virtual void end_draw();
   virtual void idle();
 
-  virtual gint configure_event_impl(GdkEventConfigure *event);
-  virtual gint expose_event_impl(GdkEventExpose *event);
-
-  void pack_labels();
-  void setup_white_gc();
+  LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+  virtual LONG graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+  virtual void additional_window_paint(HDC hdc);
+  virtual void additional_graph_window_paint(HDC hdc);
+  virtual DragMode consider_drag_start(int mouse_x, int mouse_y, 
+                                       int width, int height);
 
 private:
-  // Backing pixmap for drawing area.
-  Gdk_Pixmap _pixmap;
-
-  // Graphics contexts for fg/bg.  We don't use the contexts defined
-  // in the style, because that would probably interfere with the
-  // visibility of the chart.
-  Gdk_GC _white_gc;
-  Gdk_GC _black_gc;
-  Gdk_GC _dark_gc;
-  Gdk_GC _light_gc;
-
-  // Table of graphics contexts for our various collectors.
-  typedef pmap<int, Gdk_GC> GCs;
-  GCs _gcs;
-
-  // Table of Y-positions for each of our rows, measured from the
-  // bottom.
-  vector_int _y_positions;
-
-  Gtk::Alignment *_label_align;
-  Gtk::VBox *_label_box;
-  bool _is_dead;
-};
+  int get_collector_under_pixel(int xpoint, int ypoint);
+  void update_labels();
+  void draw_guide_bar(HDC hdc, const GuideBar &bar);
+  void draw_guide_label(HDC hdc, int y, const PStatGraph::GuideBar &bar);
+
+  void create_window();
+  static void register_window_class(HINSTANCE application);
 
-#include "gtkStatsPianoRoll.I"
+  static LONG GTKAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+
+  static bool _window_class_registered;
+  static const char * const _window_class_name;
+};
 
 #endif
 

+ 0 - 164
pandatool/src/gtk-stats/gtkStatsPianoWindow.cxx

@@ -1,164 +0,0 @@
-// Filename: gtkStatsPianoWindow.cxx
-// Created by:  drose (18Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "gtkStatsPianoWindow.h"
-#include "gtkStatsPianoRoll.h"
-
-using Gtk::Menu_Helpers::MenuElem;
-using Gtk::Menu_Helpers::SeparatorElem;
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoWindow::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkStatsPianoWindow::
-GtkStatsPianoWindow(GtkStatsMonitor *monitor, int thread_index,
-                    int chart_xsize, int chart_ysize) :
-  GtkStatsWindow(monitor),
-  _thread_index(thread_index)
-{
-  setup_menu();
-  layout_window(chart_xsize, chart_ysize);
-  show();
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoWindow::mark_dead
-//       Access: Public, Virtual
-//  Description: Called when the client's connection has been lost,
-//               this should update the window in some obvious way to
-//               indicate that the window is no longer live.
-////////////////////////////////////////////////////////////////////
-void GtkStatsPianoWindow::
-mark_dead() {
-  GtkStatsWindow::mark_dead();
-  _chart->mark_dead();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoWindow::idle
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsPianoWindow::
-idle() {
-  GtkStatsWindow::idle();
-  _chart->update();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoWindow::setup_menu
-//       Access: Protected, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsPianoWindow::
-setup_menu() {
-  GtkStatsWindow::setup_menu();
-
-  Gtk::Menu *scale_menu = new Gtk::Menu;
-
-  scale_menu->items().push_back
-    (MenuElem("0.1 Hz",
-              bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 0.1f)));
-  scale_menu->items().push_back
-    (MenuElem("1 Hz",
-              bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 1.0f)));
-  scale_menu->items().push_back
-    (MenuElem("5 Hz",
-              bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 5.0f)));
-  scale_menu->items().push_back
-    (MenuElem("10 Hz",
-              bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 10.0f)));
-  scale_menu->items().push_back
-    (MenuElem("20 Hz",
-              bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 20.0f)));
-  scale_menu->items().push_back
-    (MenuElem("30 Hz",
-              bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 30.0f)));
-  scale_menu->items().push_back
-    (MenuElem("60 Hz",
-              bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 60.0f)));
-  scale_menu->items().push_back
-    (MenuElem("120 Hz",
-              bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 120.0f)));
-
-  _menu->items().push_back(MenuElem("Scale", *manage(scale_menu)));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoWindow::menu_new_window
-//       Access: Protected, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsPianoWindow::
-menu_new_window() {
-  new GtkStatsPianoWindow(_monitor, _thread_index,
-                          _chart->get_xsize(), _chart->get_ysize());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoWindow::menu_hscale
-//       Access: Protected
-//  Description: Selects a new horizontal scale for the piano roll.
-//               This is done from the menu called "Scale".
-//
-//               The units is in Hz.
-////////////////////////////////////////////////////////////////////
-void GtkStatsPianoWindow::
-menu_hscale(float hz) {
-  _chart->set_horizontal_scale(1.0 / hz);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsPianoWindow::layout_window
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsPianoWindow::
-layout_window(int chart_xsize, int chart_ysize) {
-  Gtk::HBox *hbox = new Gtk::HBox;
-  hbox = new Gtk::HBox;
-  hbox->show();
-  _main_box->pack_start(*manage(hbox), true, true, 8);
-
-  Gtk::Table *chart_table = new Gtk::Table(1, 2);
-  chart_table->show();
-  hbox->pack_start(*manage(chart_table), true, true, 8);
-
-  Gtk::Frame *frame = new Gtk::Frame;
-  frame->set_shadow_type(GTK_SHADOW_ETCHED_OUT);
-  frame->show();
-  chart_table->attach(*manage(frame), 1, 2, 0, 1);
-
-  _chart = new GtkStatsPianoRoll(_monitor, _thread_index,
-                                  chart_xsize, chart_ysize);
-  frame->add(*manage(_chart));
-
-  // We put the labels in a frame, too, so they'll line up vertically.
-  Gtk::Frame *label_frame = new Gtk::Frame;
-  label_frame->set_shadow_type(GTK_SHADOW_NONE);
-  label_frame->show();
-  label_frame->add(*manage(_chart->get_labels()));
-
-  chart_table->attach(*manage(label_frame), 0, 1, 0, 1,
-                      0, (GTK_FILL|GTK_EXPAND), 4, 0);
-
-  _chart->show();
-}

+ 1 - 2
pandatool/src/gtk-stats/gtkStatsServer.cxx

@@ -1,5 +1,5 @@
 // Filename: gtkStatsServer.cxx
-// Created by:  drose (14Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -19,7 +19,6 @@
 #include "gtkStatsServer.h"
 #include "gtkStatsMonitor.h"
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GtkStatsServer::make_monitor
 //       Access: Public

+ 4 - 4
pandatool/src/gtk-stats/gtkStatsServer.h

@@ -1,5 +1,5 @@
 // Filename: gtkStatsServer.h
-// Created by:  drose (14Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -20,13 +20,12 @@
 #define GTKSTATSSERVER_H
 
 #include "pandatoolbase.h"
-
 #include "pStatServer.h"
 
-
 ////////////////////////////////////////////////////////////////////
 //       Class : GtkStatsServer
-// Description :
+// Description : The class that owns the main loop, waiting for client
+//               connections.
 ////////////////////////////////////////////////////////////////////
 class GtkStatsServer : public PStatServer {
 public:
@@ -34,3 +33,4 @@ public:
 };
 
 #endif
+

+ 0 - 17
pandatool/src/gtk-stats/gtkStatsStripChart.I

@@ -1,17 +0,0 @@
-// Filename: gtkStatsStripChart.I
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////

+ 326 - 282
pandatool/src/gtk-stats/gtkStatsStripChart.cxx

@@ -1,5 +1,5 @@
 // Filename: gtkStatsStripChart.cxx
-// Created by:  drose (14Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -17,16 +17,12 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "gtkStatsStripChart.h"
-#include "gtkStatsLabel.h"
-#include "gtkStatsGuide.h"
-
-#include "request_initial_size.h"
-#include "pStatThreadData.h"
-#include "pStatFrameData.h"
-#include "pStatView.h"
-
-#include <algorithm>
+#include "gtkStatsMonitor.h"
+#include "pStatCollectorDef.h"
+#include "numeric_types.h"
 
+static const int default_strip_chart_width = 400;
+static const int default_strip_chart_height = 100;
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GtkStatsStripChart::Constructor
@@ -34,99 +30,234 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 GtkStatsStripChart::
-GtkStatsStripChart(GtkStatsMonitor *monitor, PStatView &view,
-                   int collector_index, int xsize, int ysize) :
-  PStatStripChart(monitor, view, collector_index, xsize, ysize)
+GtkStatsStripChart(GtkStatsMonitor *monitor, int thread_index,
+                   int collector_index, bool show_level) :
+  PStatStripChart(monitor, 
+                  show_level ? monitor->get_level_view(collector_index, thread_index) : monitor->get_view(thread_index), 
+                  collector_index, 
+                  default_strip_chart_width,
+                  default_strip_chart_height),
+  GtkStatsGraph(monitor, thread_index)
 {
-  _is_dead = false;
-  set_events(GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
+  _brush_origin = 0;
+
+  _left_margin = 96;
+  _right_margin = 32;
+  _top_margin = 16;
+  _bottom_margin = 8;
+
+  if (show_level) {
+    // If it's a level-type graph, show the appropriate units.
+    if (_unit_name.empty()) {
+      set_guide_bar_units(GBU_named);
+    } else {
+      set_guide_bar_units(GBU_named | GBU_show_units);
+    }
+
+  } else {
+    // If it's a time-type graph, show the ms/Hz units.
+    set_guide_bar_units(get_guide_bar_units() | GBU_show_units);
+  }
+
+  _smooth_check_box = 0;
 
-  _label_align = manage(new Gtk::Alignment(1.0, 1.0));
-  _label_align->show();
+  GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(hbox), _label_stack.setup(),
+		     FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(hbox), _graph_window,
+		     FALSE, FALSE, 0);
 
-  _label_box = NULL;
-  pack_labels();
+  gtk_container_add(GTK_CONTAINER(_window), hbox);
 
-  _guide = manage(new GtkStatsGuide(this));
-  _guide->show();
+  gtk_widget_show_all(_window);  
+  gtk_widget_show(_window);
 
-  request_initial_size(*this, get_xsize(), get_ysize());
+  clear_region();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::mark_dead
-//       Access: Public
-//  Description: Called when the client's connection has been lost,
-//               this should update the window in some obvious way to
-//               indicate that the window is no longer live.
+//     Function: GtkStatsStripChart::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+GtkStatsStripChart::
+~GtkStatsStripChart() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsStripChart::new_collector
+//       Access: Public, Virtual
+//  Description: Called whenever a new Collector definition is
+//               received from the client.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsStripChart::
-mark_dead() {
-  _is_dead = true;
+new_collector(int collector_index) {
+  GtkStatsGraph::new_collector(collector_index);
+}
 
-  setup_white_gc();
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsStripChart::new_data
+//       Access: Public, Virtual
+//  Description: Called as each frame's data is made available.  There
+//               is no gurantee the frames will arrive in order, or
+//               that all of them will arrive at all.  The monitor
+//               should be prepared to accept frames received
+//               out-of-order or missing.
+////////////////////////////////////////////////////////////////////
+void GtkStatsStripChart::
+new_data(int thread_index, int frame_number) {
+  if (is_title_unknown()) {
+    string window_title = get_title_text();
+    if (!is_title_unknown()) {
+      gtk_window_set_title(GTK_WINDOW(_window), window_title.c_str());
+    }
+  }
 
-  if (!first_data()) {
-    force_redraw();
-  } else {
-    clear_region();
+  if (!_pause) {
+    update();
+
+    /*
+    string text = format_number(get_average_net_value(), get_guide_bar_units(), get_guide_bar_unit_name());
+    if (_net_value_text != text) {
+      _net_value_text = text;
+      RECT rect;
+      GetClientRect(_window, &rect);
+      rect.bottom = _top_margin;
+      InvalidateRect(_window, &rect, TRUE);
+    }
+    */
   }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::get_labels
-//       Access: Public
-//  Description: Returns an alignment widget that contains all of the
-//               labels appropriate to this chart, already formatted
-//               and stacked up bottom-to-top.  The window should pack
-//               this widget suitably near the strip chart.
-////////////////////////////////////////////////////////////////////
-Gtk::Alignment *GtkStatsStripChart::
-get_labels() {
-  return _label_align;
+//     Function: GtkStatsStripChart::force_redraw
+//       Access: Public, Virtual
+//  Description: Called when it is necessary to redraw the entire graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsStripChart::
+force_redraw() {
+  PStatStripChart::force_redraw();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::get_guide
-//       Access: Public
-//  Description: Returns a widget that contains the numeric labels for
-//               the guide bars.  The window should pack this widget
-//               suitably near the strip chart.
+//     Function: GtkStatsStripChart::changed_graph_size
+//       Access: Public, Virtual
+//  Description: Called when the user has resized the window, forcing
+//               a resize of the graph.
 ////////////////////////////////////////////////////////////////////
-GtkStatsGuide *GtkStatsStripChart::
-get_guide() {
-  return _guide;
+void GtkStatsStripChart::
+changed_graph_size(int graph_xsize, int graph_ysize) {
+  PStatStripChart::changed_size(graph_xsize, graph_ysize);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsStripChart::set_time_units
+//       Access: Public, Virtual
+//  Description: Called when the user selects a new time units from
+//               the monitor pulldown menu, this should adjust the
+//               units for the graph to the indicated mask if it is a
+//               time-based graph.
+////////////////////////////////////////////////////////////////////
+void GtkStatsStripChart::
+set_time_units(int unit_mask) {
+  int old_unit_mask = get_guide_bar_units();
+  if ((old_unit_mask & (GBU_hz | GBU_ms)) != 0) {
+    unit_mask = unit_mask & (GBU_hz | GBU_ms);
+    unit_mask |= (old_unit_mask & GBU_show_units);
+    set_guide_bar_units(unit_mask);
+
+    /*
+    RECT rect;
+    GetClientRect(_window, &rect);
+    rect.left = _right_margin;
+    InvalidateRect(_window, &rect, TRUE);
+
+    GetClientRect(_window, &rect);
+    rect.bottom = _top_margin;
+    InvalidateRect(_window, &rect, TRUE);
+    */
+  }
+}
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::get_collector_gc
+//     Function: GtkStatsStripChart::set_scroll_speed
 //       Access: Public
-//  Description: Returns a graphics context suitable for drawing in
-//               the indicated collector's color.
-////////////////////////////////////////////////////////////////////
-Gdk_GC GtkStatsStripChart::
-get_collector_gc(int collector_index) {
-  GCs::iterator gi;
-  gi = _gcs.find(collector_index);
-  if (gi != _gcs.end()) {
-    return (*gi).second;
+//  Description: Called when the user selects a new scroll speed from
+//               the monitor pulldown menu, this should adjust the
+//               speed for the graph to the indicated value.
+////////////////////////////////////////////////////////////////////
+void GtkStatsStripChart::
+set_scroll_speed(float scroll_speed) {
+  // The speed factor indicates chart widths per minute.
+  if (scroll_speed != 0.0f) {
+    set_horizontal_scale(60.0f / scroll_speed);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsStripChart::clicked_label
+//       Access: Public, Virtual
+//  Description: Called when the user single-clicks on a label.
+////////////////////////////////////////////////////////////////////
+void GtkStatsStripChart::
+clicked_label(int collector_index) {
+  if (collector_index < 0) {
+    // Clicking on whitespace in the graph is the same as clicking on
+    // the top label.
+    collector_index = get_collector_index();
   }
 
-  // Ask the monitor what color this guy should be.
-  RGBColorf rgb = get_monitor()->get_collector_color(collector_index);
-  Gdk_Color color;
-  color.set_rgb_p(rgb[0], rgb[1], rgb[2]);
+  if (collector_index == get_collector_index() && collector_index != 0) {
+    // Clicking on the top label means to go up to the parent level.
+    const PStatClientData *client_data = 
+      GtkStatsGraph::_monitor->get_client_data();
+    if (client_data->has_collector(collector_index)) {
+      const PStatCollectorDef &def =
+        client_data->get_collector_def(collector_index);
+      if (def._parent_index == 0 && get_view().get_show_level()) {
+        // Unless the parent is "Frame", and we're not a time collector.
+      } else {
+        set_collector_index(def._parent_index);
+      }
+    }
+
+  } else {
+    // Clicking on any other label means to focus on that.
+    set_collector_index(collector_index);
+  }
+}
 
-  // Now allocate the color from the system colormap.
-  Gdk_Colormap::get_system().alloc(color);
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsStripChart::set_vertical_scale
+//       Access: Public
+//  Description: Changes the value the height of the vertical axis
+//               represents.  This may force a redraw.
+////////////////////////////////////////////////////////////////////
+void GtkStatsStripChart::
+set_vertical_scale(float value_height) {
+  PStatStripChart::set_vertical_scale(value_height);
+
+  GdkRectangle rect = {
+    0, 0, get_xsize(), get_ysize() 
+  };
+  gdk_window_invalidate_rect(_graph_window->window, &rect, FALSE);
+}
 
-  // Allocate a new graphics context.
-  Gdk_GC gc(_pixmap);
-  gc.set_foreground(color);
+////////////////////////////////////////////////////////////////////
+//     Function: GtkStatsStripChart::update_labels
+//       Access: Protected, Virtual
+//  Description: Resets the list of labels.
+////////////////////////////////////////////////////////////////////
+void GtkStatsStripChart::
+update_labels() {
+  PStatStripChart::update_labels();
 
-  _gcs[collector_index] = gc;
-  return gc;
+  _label_stack.clear_labels();
+  for (int i = 0; i < get_num_labels(); i++) {
+    _label_stack.add_label(GtkStatsGraph::_monitor, this, _thread_index,
+                           get_label_collector(i), false);
+  }
+  _labels_changed = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -136,8 +267,9 @@ get_collector_gc(int collector_index) {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsStripChart::
 clear_region() {
-  _pixmap.draw_rectangle(_white_gc, true, 0, 0, get_xsize(), get_ysize());
-  end_draw(0, get_xsize());
+  gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
+  gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, 0, 0, 
+		     get_xsize(), get_ysize());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -149,28 +281,19 @@ clear_region() {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsStripChart::
 copy_region(int start_x, int end_x, int dest_x) {
-  _pixmap.copy_area(_white_gc, 0, 0,
-                    _pixmap, start_x, 0,
-                    end_x - start_x + 1, get_ysize());
-
-  // We could make a window-to-window copy to implement scrolling in
-  // the window.  But this leads to trouble if the scrolling window
-  // isn't on top.  Instead, we'll just do the scroll in the pixmap,
-  // and then blt the pixmap back out--in principle, this ought to be
-  // just as fast.
-  /*
-  Gdk_Window window = get_window();
-  window.copy_area(_white_gc, 0, 0,
-                   window, start_x, 0,
-                   end_x - start_x + 1, get_ysize());
-  */
-
-  GdkRectangle update_rect;
-  update_rect.x = dest_x;
-  update_rect.y = 0;
-  update_rect.width = end_x - start_x + 1;
-  update_rect.height = get_ysize();
-  draw(&update_rect);
+  gdk_draw_drawable(_pixmap, _pixmap_gc, _pixmap,
+		    start_x, 0, dest_x, 0,
+		    end_x - start_x, get_ysize());
+  
+  // Also shift the brush origin over, so we still get proper
+  // dithering.
+  _brush_origin += (dest_x - start_x);
+  //  SetBrushOrgEx(_bitmap_dc, _brush_origin, 0, NULL);
+
+  GdkRectangle rect = {
+    dest_x, 0, end_x - start_x, get_ysize() 
+  };
+  gdk_window_invalidate_rect(_graph_window->window, &rect, FALSE);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -182,32 +305,32 @@ copy_region(int start_x, int end_x, int dest_x) {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsStripChart::
 draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) {
-  while (w > 0) {
-    // Start by clearing the band first.
-    _pixmap.draw_line(_white_gc, x, 0, x, get_ysize());
-
-    float overall_time = 0.0;
-    int y = get_ysize();
-
-    FrameData::const_iterator fi;
-    for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
-      const ColorData &cd = (*fi);
-      overall_time += cd._net_value;
-
-      if (overall_time > get_vertical_scale()) {
-        // Off the top.  Go ahead and clamp it by hand, in case it's so
-        // far off the top we'd overflow the 16-bit pixel value.
-        _pixmap.draw_line(get_collector_gc(cd._collector_index), x, y, x, 0);
-        // And we can consider ourselves done now.
-        break;
-      }
-
-      int top_y = height_to_pixel(overall_time);
-      _pixmap.draw_line(get_collector_gc(cd._collector_index), x, y, x, top_y);
-      y = top_y;
+  // Start by clearing the band first.
+  gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
+  gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, x, 0, 
+		     w + 1, get_ysize());
+
+  float overall_time = 0.0;
+  int y = get_ysize();
+
+  FrameData::const_iterator fi;
+  for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
+    const ColorData &cd = (*fi);
+    overall_time += cd._net_value;
+    GdkGC *gc = get_collector_gc(cd._collector_index);
+
+    if (overall_time > get_vertical_scale()) {
+      // Off the top.  Go ahead and clamp it by hand, in case it's so
+      // far off the top we'd overflow the 16-bit pixel value.
+      gdk_draw_rectangle(_pixmap, gc, TRUE, x, 0, w + 1, y);
+
+      // And we can consider ourselves done now.
+      return;
     }
-    x++;
-    w--;
+
+    int top_y = height_to_pixel(overall_time);
+    gdk_draw_rectangle(_pixmap, gc, TRUE, x, top_y, w + 1, y);
+    y = top_y;
   }
 }
 
@@ -218,11 +341,9 @@ draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsStripChart::
 draw_empty(int x, int w) {
-  while (w > 0) {
-    _pixmap.draw_line(_white_gc, x, 0, x, get_ysize());
-    x++;
-    w--;
-  }
+  gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
+  gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, x, 0, 
+		     w + 1, get_ysize());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -232,7 +353,8 @@ draw_empty(int x, int w) {
 ////////////////////////////////////////////////////////////////////
 void GtkStatsStripChart::
 draw_cursor(int x) {
-  _pixmap.draw_line(_black_gc, x, 0, x, get_ysize());
+  gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_black);
+  gdk_draw_line(_pixmap, _pixmap_gc, x, 0, x, get_ysize());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -248,181 +370,103 @@ end_draw(int from_x, int to_x) {
   // Draw in the guide bars.
   int num_guide_bars = get_num_guide_bars();
   for (int i = 0; i < num_guide_bars; i++) {
-    const GuideBar &bar = get_guide_bar(i);
-    int y = height_to_pixel(bar._height);
-
-    if (y >= 5) {
-      // Only draw it if it's not too close to the top.
-      switch (bar._style) {
-      case GBS_target:
-        _pixmap.draw_line(_light_gc, from_x, y, to_x, y);
-        break;
-
-      case GBS_normal:
-      default:
-        _pixmap.draw_line(_dark_gc, from_x, y, to_x, y);
-        break;
-      }
-    }
+    draw_guide_bar(from_x, to_x, get_guide_bar(i));
   }
 
-  GdkRectangle update_rect;
-  update_rect.x = from_x;
-  update_rect.y = 0;
-  update_rect.width = to_x - from_x + 1;
-  update_rect.height = get_ysize();
-  draw(&update_rect);
+  GdkRectangle rect = {
+    from_x, 0, to_x - from_x + 1, get_ysize() 
+  };
+  gdk_window_invalidate_rect(_graph_window->window, &rect, FALSE);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::idle
+//     Function: GtkStatsStripChart::consider_drag_start
 //       Access: Protected, Virtual
-//  Description: Called at the end of the draw cycle.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripChart::
-idle() {
-  if (_labels_changed) {
-    pack_labels();
-  }
-  if (_guide_bars_changed) {
-    GdkRectangle update_rect;
-    update_rect.x = 0;
-    update_rect.y = 0;
-    update_rect.width = _guide->width();
-    update_rect.height = _guide->height();
-    _guide->draw(&update_rect);
-    _guide_bars_changed = false;
-  }
-}
+//  Description: Based on the mouse position within the window's
+//               client area, look for draggable things the mouse
+//               might be hovering over and return the apprioprate
+//               DragMode enum or DM_none if nothing is indicated.
+////////////////////////////////////////////////////////////////////
+GtkStatsGraph::DragMode GtkStatsStripChart::
+consider_drag_start(int mouse_x, int mouse_y, int width, int height) {
+  if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) {
+    if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) {
+      // See if the mouse is over a user-defined guide bar.
+      int y = mouse_y - _graph_top;
+      float from_height = pixel_to_height(y + 2);
+      float to_height = pixel_to_height(y - 2);
+      _drag_guide_bar = find_user_guide_bar(from_height, to_height);
+      if (_drag_guide_bar >= 0) {
+        return DM_guide_bar;
+      }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::configure_event_impl
-//       Access: Private, Virtual
-//  Description: Creates a new backing pixmap of the appropriate size.
-////////////////////////////////////////////////////////////////////
-gint GtkStatsStripChart::
-configure_event_impl(GdkEventConfigure *) {
-  if (width() != get_xsize() || height() != get_ysize() ||
-      _pixmap.gdkobj() == (GdkDrawable *)NULL) {
-    bool is_initial = true;
-    if (_pixmap) {
-      is_initial = false;
-      _pixmap.release();
+    } else {
+      // The mouse is above or below the graph; maybe create a new
+      // guide bar.
+      return DM_new_guide_bar;
     }
-
-    _pixmap.create(get_window(), width(), height());
-
-    Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
-
-    _white_gc = Gdk_GC(_pixmap);
-    setup_white_gc();
-
-    _black_gc = Gdk_GC(_pixmap);
-    _black_gc.set_foreground(system_colormap.black());
-
-    _dark_gc = Gdk_GC(_pixmap);
-    Gdk_Color dark;
-    dark.set_grey_p(0.2);
-    system_colormap.alloc(dark);
-    _dark_gc.set_foreground(dark);
-
-    _light_gc = Gdk_GC(_pixmap);
-    Gdk_Color light;
-    light.set_grey_p(0.6);
-    system_colormap.alloc(light);
-    _light_gc.set_foreground(light);
-
-    _pixmap.draw_rectangle(_white_gc, true, 0, 0, width(), height());
-
-    changed_size(width(), height());
   }
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::expose_event_impl
-//       Access: Private, Virtual
-//  Description: Redraw the screen from the backing pixmap.
-////////////////////////////////////////////////////////////////////
-gint GtkStatsStripChart::
-expose_event_impl(GdkEventExpose *event) {
-  get_window().draw_pixmap(_white_gc, _pixmap,
-                           event->area.x, event->area.y,
-                           event->area.x, event->area.y,
-                           event->area.width, event->area.height);
 
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::button_press_event_impl
-//       Access: Private, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-gint GtkStatsStripChart::
-button_press_event_impl(GdkEventButton *button) {
-  if (button->type == GDK_2BUTTON_PRESS && button->button == 1) {
-    int collector_index = get_collector_under_pixel((int)button->x, (int)button->y);
-    collector_picked(collector_index);
-    return true;
-  }
-  return false;
+  return GtkStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height);
 }
 
-
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::pack_labels
-//       Access: Private
-//  Description:
+//     Function: GtkStatsStripChart::set_drag_mode
+//       Access: Protected, Virtual
+//  Description: This should be called whenever the drag mode needs to
+//               change state.  It provides hooks for a derived class
+//               to do something special.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsStripChart::
-pack_labels() {
-  // First, remove the old labels.
-  _label_align->remove();
-
-  // Now add the new labels back in.
-  _label_box = manage(new Gtk::VBox);
-  _label_box->show();
-  _label_align->add(*_label_box);
-
-  Gdk_Font font = get_style()->gtkobj()->font;
-
-  int num_labels = get_num_labels();
-  for (int i = 0; i < num_labels; i++) {
-    int collector_index = get_label_collector(i);
-    GtkStatsLabel *label =
-      new GtkStatsLabel(get_monitor(), collector_index, font);
-    label->show();
-    
-    label->collector_picked.connect(collector_picked.slot());
-    
-    _label_box->pack_end(*manage(label), false, false);
+set_drag_mode(GtkStatsGraph::DragMode drag_mode) {
+  GtkStatsGraph::set_drag_mode(drag_mode);
+
+  switch (_drag_mode) {
+  case DM_scale:
+  case DM_left_margin:
+  case DM_right_margin:
+  case DM_sizing:
+    // Disable smoothing for these expensive operations.
+    set_average_mode(false);
+    break;
+
+  default:
+    // Restore smoothing according to the current setting of the check
+    // box.
+    /*
+    int result = SendMessage(_smooth_check_box, BM_GETCHECK, 0, 0);
+    set_average_mode(result == BST_CHECKED);
+    */
+    break;
   }
-  
-  _labels_changed = false;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripChart::setup_white_gc
+//     Function: GtkStatsStripChart::draw_guide_bar
 //       Access: Private
-//  Description: Sets the color on _white_gc to be either actually
-//               white (if the chart is still alive) or a light gray
-//               (if the chart is dead).
+//  Description: Draws the line for the indicated guide bar on the
+//               graph.
 ////////////////////////////////////////////////////////////////////
 void GtkStatsStripChart::
-setup_white_gc() {
-  Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
-
-  if (_is_dead) {
-    Gdk_Color death;
-    death.set_grey_p(0.8);
-    system_colormap.alloc(death);
-
-    _white_gc.set_foreground(death);
-
-  } else {
-    _white_gc.set_foreground(system_colormap.white());
+draw_guide_bar(int from_x, int to_x, 
+               const PStatGraph::GuideBar &bar) {
+  int y = height_to_pixel(bar._height);
+
+  if (y > 0) {
+    // Only draw it if it's not too close to the top.
+    switch (bar._style) {
+    case GBS_target:
+      gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_light_gray);
+      break;
+
+    case GBS_user:
+      gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_user_guide_bar);
+      break;
+      
+    case GBS_normal:
+      gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_dark_gray);
+      break;
+    }
+    gdk_draw_line(_pixmap, _pixmap_gc, from_x, y, to_x, y);
   }
-
 }
-

+ 32 - 48
pandatool/src/gtk-stats/gtkStatsStripChart.h

@@ -1,5 +1,5 @@
 // Filename: gtkStatsStripChart.h
-// Created by:  drose (14Jul00)
+// Created by:  drose (16Jan06)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -21,40 +21,37 @@
 
 #include "pandatoolbase.h"
 
-#include "gtkStatsMonitor.h"
-
+#include "gtkStatsGraph.h"
 #include "pStatStripChart.h"
 #include "pointerTo.h"
 
-#include <gtk--.h>
-#include "pmap.h"
+#include <gtk/gtk.h>
 
-class PStatView;
-class GtkStatsGuide;
+class GtkStatsMonitor;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GtkStatsStripChart
-// Description : A special widget that draws a strip chart, given a
-//               view.
+// Description : A window that draws a strip chart, given a view.
 ////////////////////////////////////////////////////////////////////
-class GtkStatsStripChart : public Gtk::DrawingArea, public PStatStripChart {
+class GtkStatsStripChart : public PStatStripChart, public GtkStatsGraph {
 public:
   GtkStatsStripChart(GtkStatsMonitor *monitor,
-                     PStatView &view, int collector_index,
-                     int xsize, int ysize);
-
-  void mark_dead();
+                     int thread_index, int collector_index, bool show_level);
+  virtual ~GtkStatsStripChart();
 
-  Gtk::Alignment *get_labels();
-  GtkStatsGuide *get_guide();
+  virtual void new_collector(int collector_index);
+  virtual void new_data(int thread_index, int frame_number);
+  virtual void force_redraw();
+  virtual void changed_graph_size(int graph_xsize, int graph_ysize);
 
-  Gdk_GC get_collector_gc(int collector_index);
+  virtual void set_time_units(int unit_mask);
+  virtual void set_scroll_speed(float scroll_speed);
+  virtual void clicked_label(int collector_index);
+  void set_vertical_scale(float value_height);
 
-  // This signal is thrown when the user float-clicks on a label or
-  // on a band of color.
-  SigC::Signal1<void, int> collector_picked;
+protected:
+  virtual void update_labels();
 
-private:
   virtual void clear_region();
   virtual void copy_region(int start_x, int end_x, int dest_x);
   virtual void draw_slice(int x, int w, 
@@ -62,38 +59,25 @@ private:
   virtual void draw_empty(int x, int w);
   virtual void draw_cursor(int x);
   virtual void end_draw(int from_x, int to_x);
-  virtual void idle();
 
-  virtual gint configure_event_impl(GdkEventConfigure *event);
-  virtual gint expose_event_impl(GdkEventExpose *event);
-  virtual gint button_press_event_impl(GdkEventButton *button);
+  virtual DragMode consider_drag_start(int mouse_x, int mouse_y, 
+                                       int width, int height);
+  virtual void set_drag_mode(DragMode drag_mode);
 
-  void pack_labels();
-  void setup_white_gc();
+private:
+  void draw_guide_bar(int from_x, int to_x, 
+		      const PStatGraph::GuideBar &bar);
 
 private:
-  // Backing pixmap for drawing area.
-  Gdk_Pixmap _pixmap;
-
-  // Graphics contexts for fg/bg.  We don't use the contexts defined
-  // in the style, because that would probably interfere with the
-  // visibility of the strip chart.
-  Gdk_GC _white_gc;
-  Gdk_GC _black_gc;
-  Gdk_GC _dark_gc;
-  Gdk_GC _light_gc;
-
-  // Table of graphics contexts for our various collectors.
-  typedef pmap<int, Gdk_GC> GCs;
-  GCs _gcs;
-
-  Gtk::Alignment *_label_align;
-  Gtk::VBox *_label_box;
-  GtkStatsGuide *_guide;
-  bool _is_dead;
-};
 
-#include "gtkStatsStripChart.I"
+  int _brush_origin;
+  string _net_value_text;
+
+  GtkWidget *_smooth_check_box;
+
+  static bool _window_class_registered;
+  static const char * const _window_class_name;
+};
 
 #endif
 

+ 0 - 459
pandatool/src/gtk-stats/gtkStatsStripWindow.cxx

@@ -1,459 +0,0 @@
-// Filename: gtkStatsStripWindow.cxx
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "gtkStatsStripWindow.h"
-#include "gtkStatsStripChart.h"
-#include "gtkStatsGuide.h"
-
-#include "pStatCollectorDef.h"
-#include "string_utils.h"
-
-#include <stdio.h>  // for sprintf
-
-
-using Gtk::Menu_Helpers::MenuElem;
-using Gtk::Menu_Helpers::CheckMenuElem;
-using Gtk::Menu_Helpers::SeparatorElem;
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkStatsStripWindow::
-GtkStatsStripWindow(GtkStatsMonitor *monitor, int thread_index,
-                    int collector_index, bool show_level,
-                    int chart_xsize, int chart_ysize) :
-  GtkStatsWindow(monitor),
-  _thread_index(thread_index),
-  _collector_index(collector_index),
-  _show_level(show_level)
-{
-  _title_unknown = false;
-  _setup_scale_menu = false;
-  _smooth = false;
-
-  setup_menu();
-  layout_window(chart_xsize, chart_ysize);
-
-  new_collector();  // To set up the menus in case we can.
-  show();
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::mark_dead
-//       Access: Public, Virtual
-//  Description: Called when the client's connection has been lost,
-//               this should update the window in some obvious way to
-//               indicate that the window is no longer live.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-mark_dead() {
-  GtkStatsWindow::mark_dead();
-  _chart->mark_dead();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::new_collector
-//       Access: Public, Virtual
-//  Description: Called when a new collector has become known.
-//
-//               For the GtkStatsStripWindow, this forces a rebuild of
-//               the menu that selects the collectors available for
-//               picking levels.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-new_collector() {
-  const PStatClientData *client_data = _monitor->get_client_data();
-
-  // Determine the set of collectors that display level data.  We'll
-  // want to put these on the "Levels" pull-down menu.
-
-  pset<int> levels;
-
-  int num_collectors = client_data->get_num_collectors();
-  for (int i = 0; i < num_collectors; i++) {
-    if (client_data->has_collector(i) &&
-        client_data->get_collector_has_level(i)) {
-      // We only put top-level entries on the menu.  Thus, walk up
-      // from this collector to its top level (the one below Frame).
-      int collector_index = i;
-      const PStatCollectorDef &def =
-        client_data->get_collector_def(collector_index);
-      int parent_index = def._parent_index;
-
-      while (parent_index != 0) {
-        collector_index = parent_index;
-        const PStatCollectorDef &def =
-          client_data->get_collector_def(collector_index);
-        parent_index = def._parent_index;
-      }
-
-      levels.insert(collector_index);
-    }
-  }
-
-  // Now put the collectors we found on the menu.
-  _levels_menu->items().clear();
-  pset<int>::const_iterator li;
-  for (li = levels.begin(); li != levels.end(); ++li) {
-    int collector_index = (*li);
-    _levels_menu->items().push_back
-      (MenuElem(client_data->get_collector_name(collector_index),
-                bind(slot(this, &GtkStatsStripWindow::menu_show_levels), collector_index)));
-  }
-
-  // Also re-set-up the scale menu, in case the properties have changed.
-  setup_scale_menu();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::idle
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-idle() {
-  GtkStatsWindow::idle();
-  _chart->update();
-
-  const PStatThreadData *thread_data = _chart->get_view().get_thread_data();
-  if (!thread_data->is_empty()) {
-    float frame_rate = thread_data->get_frame_rate();
-    char buffer[128];
-    sprintf(buffer, "Frame rate: %0.1f Hz", frame_rate);
-    _frame_rate_label->set_text(buffer);
-  }
-
-  if (_title_unknown) {
-    _title_label->set_text(get_title_text());
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::setup_menu
-//       Access: Protected, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-setup_menu() {
-  GtkStatsWindow::setup_menu();
-
-  Gtk::Menu *speed_menu = new Gtk::Menu;
-
-  speed_menu->items().push_back
-    (MenuElem("1",  // 1 chart width scrolls by per minute.
-              bind(slot(this, &GtkStatsStripWindow::menu_hscale), 1.0f)));
-  speed_menu->items().push_back
-    (MenuElem("2",  // 2 chart widths scroll by per minute.
-              bind(slot(this, &GtkStatsStripWindow::menu_hscale), 2.0f)));
-  speed_menu->items().push_back
-    (MenuElem("3",
-              bind(slot(this, &GtkStatsStripWindow::menu_hscale), 3.0f)));
-  speed_menu->items().push_back
-    (MenuElem("6",
-              bind(slot(this, &GtkStatsStripWindow::menu_hscale), 6.0f)));
-  speed_menu->items().push_back
-    (MenuElem("12",
-              bind(slot(this, &GtkStatsStripWindow::menu_hscale), 12.0f)));
-
-  _menu->items().push_back(MenuElem("Speed", *manage(speed_menu)));
-
-  _scale_menu = new Gtk::Menu;
-  _scale_menu->items().push_back
-    (CheckMenuElem("Smooth",
-                   slot(this, &GtkStatsStripWindow::menu_smooth)));
-  _scale_menu->items().push_back(SeparatorElem());
-  _scale_menu->items().push_back
-    (MenuElem("Auto scale",
-              slot(this, &GtkStatsStripWindow::menu_auto_vscale)));
-
-  _menu->items().push_back(MenuElem("Scale", *manage(_scale_menu)));
-
-  _levels_menu = new Gtk::Menu;
-  _menu->items().push_back(MenuElem("Levels", *manage(_levels_menu)));
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::setup_scale_menu
-//       Access: Protected
-//  Description: Sets up the options on the scale menu.  We can't do
-//               this until we have initialized the _chart member and
-//               we have gotten our first collector_index.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-setup_scale_menu() {
-  if (_setup_scale_menu) {
-    // Already done it.
-    return;
-  }
-
-  const PStatClientData *client_data = _monitor->get_client_data();
-  if (!client_data->has_collector(_collector_index)) {
-    // Can't set up the scale menu yet.
-    return;
-  }
-
-  const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
-  float base_scale = 1.0;
-  string unit_name = def._level_units;
-
-  if (_show_level) {
-    _chart->set_guide_bar_unit_name(unit_name);
-    _chart->set_guide_bar_units(PStatGraph::GBU_named);
-
-  } else {
-    _chart->set_guide_bar_units(PStatGraph::GBU_ms);
-  }
-
-  if (def._suggested_scale != 0.0) {
-    base_scale = def._suggested_scale;
-  } else if (!_show_level) {
-    base_scale = 1.0 / _chart->get_target_frame_rate();
-  }
-
-  static const float scales[] = {
-    50.0,
-    10.0,
-    5.0,
-    2.0,
-    1.0,
-    0.5,
-    0.2,
-    0.1,
-    0.02,
-  };
-  static const int num_scales = sizeof(scales) / sizeof(float);
-
-  for (int i = 0; i < num_scales; i++) {
-    float scale = base_scale * scales[i];
-    string label;
-
-    if (_show_level) {
-      label = _chart->format_number(scale, PStatGraph::GBU_named | PStatGraph::GBU_show_units, unit_name);
-    } else {
-      label = _chart->format_number(scale, PStatGraph::GBU_ms | PStatGraph::GBU_hz | PStatGraph::GBU_show_units);
-    }
-
-    _scale_menu->items().push_back
-      (MenuElem(label,
-                bind(slot(this, &GtkStatsStripWindow::menu_vscale), scale)));
-  }
-
-  _setup_scale_menu = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::menu_new_window
-//       Access: Protected, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-menu_new_window() {
-  new GtkStatsStripWindow(_monitor, _thread_index, _collector_index,
-                          _show_level,
-                          _chart->get_xsize(), _chart->get_ysize());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::menu_hscale
-//       Access: Protected
-//  Description: Selects a new horizontal scale for the strip chart.
-//               This is done from the menu called "Speed", since
-//               changing the horizontal scale most obviously affects
-//               the scrolling speed.
-//
-//               The units is in chart width per minute.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-menu_hscale(float wpm) {
-  _chart->set_horizontal_scale(60.0 / wpm);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::menu_vscale
-//       Access: Protected
-//  Description: Selects a new vertical scale for the strip chart.
-//               This is done from the menu called "Scale".
-//
-//               The units is in seconds, or whatever the units
-//               of choice are.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-menu_vscale(float max_height) {
-  _chart->set_vertical_scale(max_height);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::menu_smooth
-//       Access: Protected
-//  Description: Toggles the "smooth" state of the check menu.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-menu_smooth() {
-  _smooth = !_smooth;
-
-  _chart->set_average_mode(_smooth);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::menu_auto_vscale
-//       Access: Protected
-//  Description: Selects a suitable vertical scale based on the data
-//               already visible in the chart.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-menu_auto_vscale() {
-  _chart->set_auto_vertical_scale();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::menu_show_levels
-//       Access: Protected
-//  Description: Shows the level values known for the indicated
-//               collector.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-menu_show_levels(int collector_index) {
-  new GtkStatsStripWindow(_monitor, _thread_index, collector_index,
-                          true,
-                          _chart->get_xsize(), _chart->get_ysize());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::open_subchart
-//       Access: Protected
-//  Description: This is called in response to the collector_picked
-//               signal from the strip chart, which is generated when
-//               the user double-clicks on a band of color or a label.
-//
-//               This opens up a new window focusing just on the
-//               indicated collector.
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-open_subchart(int collector_index) {
-  new GtkStatsStripWindow(_monitor, _thread_index, collector_index,
-                          _show_level,
-                          _chart->get_xsize(), _chart->get_ysize());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::layout_window
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsStripWindow::
-layout_window(int chart_xsize, int chart_ysize) {
-  Gtk::HBox *hbox = new Gtk::HBox;
-  hbox = new Gtk::HBox;
-  hbox->show();
-  _main_box->pack_start(*manage(hbox), true, true, 8);
-
-  Gtk::Table *chart_table = new Gtk::Table(3, 2);
-  chart_table->show();
-  hbox->pack_start(*manage(chart_table), true, true, 8);
-
-  Gtk::HBox *title_hbox = new Gtk::HBox;
-  title_hbox->show();
-  chart_table->attach(*manage(title_hbox), 1, 2, 0, 1,
-                      (GTK_FILL|GTK_EXPAND), 0);
-
-  _title_label = new Gtk::Label(get_title_text());
-  if (_collector_index != 0 || _thread_index != 0) {
-    _title_label->show();
-    _title_label->set_alignment(0.0, 0.5);
-    title_hbox->pack_start(*manage(_title_label), true, true);
-  }
-
-  _frame_rate_label = new Gtk::Label;
-  if (_collector_index == 0) {
-    _frame_rate_label->show();
-    _frame_rate_label->set_alignment(1.0, 0.5);
-    title_hbox->pack_start(*manage(_frame_rate_label), true, true);
-  }
-
-  Gtk::Frame *frame = new Gtk::Frame;
-  frame->set_shadow_type(GTK_SHADOW_ETCHED_OUT);
-  frame->show();
-  chart_table->attach(*manage(frame), 1, 2, 1, 2);
-
-  if (_show_level) {
-    _chart = new GtkStatsStripChart(_monitor,
-                                    _monitor->get_level_view(_collector_index, _thread_index),
-                                    _collector_index,
-                                    chart_xsize, chart_ysize);
-  } else {
-    _chart = new GtkStatsStripChart(_monitor,
-                                    _monitor->get_view(_thread_index),
-                                    _collector_index,
-                                    chart_xsize, chart_ysize);
-  }
-
-  _chart->collector_picked.
-    connect(slot(this, &GtkStatsStripWindow::open_subchart));
-  frame->add(*manage(_chart));
-
-  chart_table->attach(*_chart->get_labels(), 0, 1, 1, 2,
-                      0, (GTK_FILL|GTK_EXPAND), 4, 0);
-  chart_table->attach(*_chart->get_guide(), 2, 3, 1, 2,
-                      0, (GTK_FILL|GTK_EXPAND), 4, 0);
-  _chart->show();
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsStripWindow::get_title_text
-//       Access: Private
-//  Description: Returns the text suitable for the title label on the
-//               top line.
-////////////////////////////////////////////////////////////////////
-string GtkStatsStripWindow::
-get_title_text() {
-  string text;
-
-  _title_unknown = false;
-
-  const PStatClientData *client_data = _monitor->get_client_data();
-  if (client_data->has_collector(_collector_index)) {
-    const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
-    if (_show_level) {
-      if (def._level_units.empty()) {
-        text = def._name;
-      } else {
-        text = def._name + " (" + def._level_units + ")";
-      }
-    } else {
-      text = def._name + " time";
-    }
-  } else {
-    _title_unknown = true;
-  }
-
-  if (_thread_index != 0) {
-    if (client_data->has_thread(_thread_index)) {
-      text += "(" + client_data->get_thread_name(_thread_index) + " thread)";
-    } else {
-      _title_unknown = true;
-    }
-  }
-
-  return text;
-}
-

+ 0 - 78
pandatool/src/gtk-stats/gtkStatsStripWindow.h

@@ -1,78 +0,0 @@
-// Filename: gtkStatsStripWindow.h
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef GTKSTATSSTRIPWINDOW_H
-#define GTKSTATSSTRIPWINDOW_H
-
-#include "pandatoolbase.h"
-
-#include "gtkStatsMonitor.h"
-#include "gtkStatsWindow.h"
-
-class GtkStatsStripChart;
-
-////////////////////////////////////////////////////////////////////
-//       Class : GtkStatsStripWindow
-// Description : A window that contains your basic one-thread,
-//               one-level strip chart.
-////////////////////////////////////////////////////////////////////
-class GtkStatsStripWindow : public GtkStatsWindow {
-public:
-  GtkStatsStripWindow(GtkStatsMonitor *monitor, int thread_index,
-                      int collector_index, bool show_level,
-                      int chart_xsize, int chart_ysize);
-
-  virtual void mark_dead();
-  virtual void new_collector();
-  virtual void idle();
-
-protected:
-  virtual void setup_menu();
-  void setup_scale_menu();
-  virtual void menu_new_window();
-  void menu_hscale(float wpm);
-  void menu_vscale(float max_height);
-  void menu_smooth();
-  void menu_auto_vscale();
-  void menu_show_levels(int collector_index);
-  void open_subchart(int collector_index);
-
-private:
-  void layout_window(int chart_xsize, int chart_ysize);
-  string get_title_text();
-
-private:
-  int _thread_index;
-  int _collector_index;
-  bool _show_level;
-  bool _title_unknown;
-  bool _setup_scale_menu;
-
-  Gtk::Label *_title_label;
-  Gtk::Label *_frame_rate_label;
-  GtkStatsStripChart *_chart;
-
-  Gtk::Menu *_scale_menu;
-  Gtk::Menu *_levels_menu;
-
-  bool _smooth;
-};
-
-
-#endif
-

+ 0 - 210
pandatool/src/gtk-stats/gtkStatsWindow.cxx

@@ -1,210 +0,0 @@
-// Filename: gtkStatsWindow.cxx
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "gtkStatsWindow.h"
-#include "gtkStatsMonitor.h"
-#include "gtkStatsStripWindow.h"
-#include "gtkStatsPianoWindow.h"
-
-using Gtk::Menu_Helpers::MenuElem;
-using Gtk::Menu_Helpers::SeparatorElem;
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkStatsWindow::
-GtkStatsWindow(GtkStatsMonitor *monitor) : _monitor(monitor) {
-  _monitor->add_window(this);
-  update_title();
-  setup();
-
-  _main_box = new Gtk::VBox;
-  _main_box->show();
-  add(*manage(_main_box));
-
-  _menu = manage(new Gtk::MenuBar);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::destruct
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-bool GtkStatsWindow::
-destruct() {
-  if (BasicGtkWindow::destruct()) {
-    _monitor->remove_window(this);
-    _monitor.clear();
-    return true;
-  }
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::update_title
-//       Access: Public, Virtual
-//  Description: Sets the title bar appropriately, once the client's
-//               information is known.
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-update_title() {
-  if (_monitor->is_client_known()) {
-    string title =
-      _monitor->get_client_progname() + " from " + _monitor->get_client_hostname();
-    if (!_monitor->is_alive()) {
-      title += " (closed)";
-    }
-    set_title(title);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::mark_dead
-//       Access: Public, Virtual
-//  Description: Called when the client's connection has been lost,
-//               this should update the window in some obvious way to
-//               indicate that the window is no longer live.
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-mark_dead() {
-  update_title();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::new_collector
-//       Access: Public, Virtual
-//  Description: Called when a new collector has become known, in case
-//               the window cares.
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-new_collector() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::idle
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-idle() {
-  if (_monitor->_new_collector) {
-    new_collector();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::setup_menu
-//       Access: Protected, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-setup_menu() {
-  _file_menu = new Gtk::Menu;
-
-  _file_menu->items().push_back
-    (MenuElem("New strip chart",
-              slot(this, &GtkStatsWindow::menu_open_strip_chart)));
-  _file_menu->items().push_back
-    (MenuElem("New piano roll",
-              slot(this, &GtkStatsWindow::menu_open_piano_roll)));
-
-  /*
-  _file_menu->items().push_back
-    (MenuElem("New window",
-              slot(this, &GtkStatsWindow::menu_new_window)));
-  */
-
-  _file_menu->items().push_back(SeparatorElem());
-
-  _file_menu->items().push_back
-    (MenuElem("Disconnect from client",
-              slot(this, &GtkStatsWindow::menu_disconnect)));
-  _file_menu->items().push_back
-    (MenuElem("Close window",
-              slot(this, &GtkStatsWindow::menu_close_window)));
-  _file_menu->items().push_back
-    (MenuElem("Close all windows this client",
-              slot(this, &GtkStatsWindow::menu_close_all_windows)));
-
-  _menu->items().push_back(MenuElem("File", *manage(_file_menu)));
-  _menu->show();
-  _main_box->pack_start(*_menu, false, false);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::menu_open_strip_chart
-//       Access: Protected
-//  Description: Open up a new strip-chart style window for the main
-//               thread.
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-menu_open_strip_chart() {
-  new GtkStatsStripWindow(_monitor, 0, 0, false, 400, 100);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::menu_open_piano_roll
-//       Access: Protected
-//  Description: Open up a new piano-roll style window for the main
-//               thread.
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-menu_open_piano_roll() {
-  new GtkStatsPianoWindow(_monitor, 0, 400, 100);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::menu_new_window
-//       Access: Protected, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-menu_new_window() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::menu_close_window
-//       Access: Protected
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-menu_close_window() {
-  destruct();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::menu_close_all_windows
-//       Access: Protected
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-menu_close_all_windows() {
-  _monitor->close_all_windows();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkStatsWindow::menu_disconnect
-//       Access: Protected
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GtkStatsWindow::
-menu_disconnect() {
-  _monitor->close();
-}

+ 0 - 69
pandatool/src/gtk-stats/gtkStatsWindow.h

@@ -1,69 +0,0 @@
-// Filename: gtkStatsWindow.h
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef GTKSTATSWINDOW_H
-#define GTKSTATSWINDOW_H
-
-#include "pandatoolbase.h"
-
-#include "gtkStatsMonitor.h"
-
-#include "basicGtkWindow.h"
-
-#include "pointerTo.h"
-
-////////////////////////////////////////////////////////////////////
-//       Class : GtkStatsWindow
-// Description : This is the base class for a family of windows that
-//               are associated with one particular stats client.
-//               Each window keeps a pointer back to the
-//               GtkStatsMonitor object, which in turn knows about all
-//               of the windows; when the last window is closed, the
-//               monitor object goes away and ends the session.
-////////////////////////////////////////////////////////////////////
-class GtkStatsWindow : public BasicGtkWindow {
-public:
-  GtkStatsWindow(GtkStatsMonitor *monitor);
-  virtual bool destruct();
-
-  virtual void update_title();
-  virtual void mark_dead();
-  virtual void new_collector();
-  virtual void idle();
-
-protected:
-  virtual void setup_menu();
-
-  void menu_open_strip_chart();
-  void menu_open_piano_roll();
-  virtual void menu_new_window();
-  void menu_close_window();
-  void menu_close_all_windows();
-  void menu_disconnect();
-
-protected:
-  PT(GtkStatsMonitor) _monitor;
-
-  Gtk::VBox *_main_box;
-  Gtk::MenuBar *_menu;
-  Gtk::Menu *_file_menu;
-};
-
-
-#endif
-

+ 9 - 0
pandatool/src/gtk-stats/gtkstats_composite1.cxx

@@ -0,0 +1,9 @@
+#include "gtkStats.cxx"
+#include "gtkStatsChartMenu.cxx"
+#include "gtkStatsGraph.cxx"
+#include "gtkStatsLabel.cxx"
+#include "gtkStatsLabelStack.cxx"
+#include "gtkStatsMonitor.cxx"
+#include "gtkStatsPianoRoll.cxx"
+#include "gtkStatsServer.cxx"
+#include "gtkStatsStripChart.cxx"

+ 0 - 201
pandatool/src/gtk-stats/scribble.cc

@@ -1,201 +0,0 @@
-
-
-
-/* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-/* Modifed for gtk-- by [email protected] */
-/* Modified (slightly) for gdk-- by [email protected] */
-#include <gtk--/main.h>
-#include <gtk--/style.h>
-#include <gtk--/window.h>
-#include <gtk--/button.h>
-#include <gtk--/box.h>
-#include <gtk--/drawingarea.h>
-#include <iostream>
-
-
-class ScribbleDrawingArea  : public Gtk::DrawingArea
-{
-  /* Backing pixmap for drawing area */
-
-  Gdk_Pixmap pixmap;
-  Gdk_GC gc;
-  Gdk_Window win;
-  Gdk_Visual visual;
-
-  virtual gint configure_event_impl (GdkEventConfigure *event);
-  virtual gint expose_event_impl (GdkEventExpose *event);
-  virtual gint button_press_event_impl (GdkEventButton *event);
-  virtual gint motion_notify_event_impl (GdkEventMotion *event);
-  void draw_brush (gdouble x, gdouble y);
-
-public:
-  ScribbleDrawingArea ();
-
-};
-
-ScribbleDrawingArea::ScribbleDrawingArea()
-    : Gtk::DrawingArea(), pixmap (0)
-  {
-    set_events (GDK_EXPOSURE_MASK
-                | GDK_LEAVE_NOTIFY_MASK
-                | GDK_BUTTON_PRESS_MASK
-                | GDK_POINTER_MOTION_MASK
-                | GDK_POINTER_MOTION_HINT_MASK);
-  }
-
-
-/* Create a new backing pixmap of the appropriate size */
-int ScribbleDrawingArea::configure_event_impl (GdkEventConfigure * /* event */)
-  {
-    win = get_window();
-    visual = win.get_visual();
-
-    if (pixmap)
-      pixmap.release();
-      gc = get_style()->gtkobj()->white_gc;
-      // Gtk::Style has no access to its data members, so use gtk objekt.
-      // Some access functions would be nice like GtkStyle::get_white_gc() etc.
-    pixmap.create(get_window(),  width(), height());
-
-    pixmap.draw_rectangle (gc,
-                        TRUE,
-                        0, 0,
-                        width(),
-                        height());
-
-    return TRUE;
-  }
-
-/* Redraw the screen from the backing pixmap */
-int ScribbleDrawingArea::expose_event_impl (GdkEventExpose *event)
-  {
-    
-    gc = get_style()->gtkobj()->fg_gc[GTK_WIDGET_STATE (GTK_WIDGET(gtkobj()))];
-    // Same like above, + Gtk::Widget has set_state function but no get_state 
-    // function. 
-    win.draw_pixmap(gc ,
-                    pixmap,
-                    event->area.x, event->area.y,
-                    event->area.x, event->area.y,
-                    event->area.width, event->area.height);
-
-    return FALSE;
-  }
-
-/* Draw a rectangle on the screen */
-void ScribbleDrawingArea::draw_brush (gdouble x, gdouble y)
-  {
-    GdkRectangle update_rect;
-    update_rect.x = (int)x - 5;
-    update_rect.y = (int)y - 5;
-    update_rect.width = 10;
-    update_rect.height = 10;
-    gc = get_style()->gtkobj()->black_gc;
-    pixmap.draw_rectangle(
-                        gc,
-                        TRUE,
-                        update_rect.x, update_rect.y,
-                        update_rect.width, update_rect.height);
-    draw(&update_rect);
-    //draw (&update_rect);
-  }
-
-gint ScribbleDrawingArea::button_press_event_impl (GdkEventButton *event)
-  {
-    if (event->button == 1 && pixmap)
-      draw_brush (event->x, event->y);
-
-    return TRUE;
-  }
-
-gint ScribbleDrawingArea::motion_notify_event_impl (GdkEventMotion *event)
-  {
-    int x, y;
-    GdkModifierType state;
-    if (event->is_hint)
-      gdk_window_get_pointer (event->window, &x, &y, &state);
-    else
-      {
-        x = (int)event->x;
-        y = (int)event->y;
-        state = (GdkModifierType) event->state;
-      }
-    
-    if (state & GDK_BUTTON1_MASK && pixmap)
-      draw_brush (x, y);
-  
-    return TRUE;
-  }
-
-
-class ScribbleWindow : public Gtk::Window
-{
-
-  Gtk::VBox vbox;
-  ScribbleDrawingArea drawing_area;
-  Gtk::Button button;
-  void quit ();
-public:  
-  ScribbleWindow ();
-}; 
-
-void ScribbleWindow::quit ()
-  {
-    Gtk::Main::quit();
-  }
-
-ScribbleWindow::ScribbleWindow ()
-    :  Gtk::Window(GTK_WINDOW_TOPLEVEL),
-       vbox (FALSE, 0),
-       button ("quit")
-  {
-    add (vbox);
-
-    /* Create the drawing area */
-    drawing_area.size (400, 400);
-    vbox.pack_start (drawing_area, TRUE, TRUE, 0);
-
-
-    /* Add the button */
-    vbox.pack_start (button, FALSE, FALSE, 0);
-
-    button.clicked.connect(slot(*this, &ScribbleWindow::quit));
-    destroy.connect(slot(*this, &ScribbleWindow::quit));
-
-    drawing_area.show();
-    button.show();
-    vbox.show();
-  }
-
-int
-main (int argc, char *argv[])
-{
-  ScribbleWindow *window;
-  Gtk::Main myapp(argc, argv);
-
-  window = new ScribbleWindow;
-  window->show();
-
-  myapp.run();
-
-  return 0;
-}

+ 0 - 18
pandatool/src/gtkbase/Sources.pp

@@ -1,18 +0,0 @@
-#define BUILD_DIRECTORY $[HAVE_GTKMM]
-#define USE_PACKAGES gtkmm
-
-#begin ss_lib_target
-  #define TARGET gtkbase
-  #define LOCAL_LIBS \
-    progbase
-
-  #define SOURCES \
-    basicGtkDialog.cxx basicGtkDialog.h basicGtkWindow.cxx \
-    basicGtkWindow.h gtkBase.cxx gtkBase.h request_initial_size.cxx \
-    request_initial_size.h
-
-  #define INSTALL_HEADERS \
-    basicGtkDialog.h basicGtkWindow.h gtkBase.h request_initial_size.h
-
-#end ss_lib_target
-

+ 0 - 69
pandatool/src/gtkbase/basicGtkDialog.cxx

@@ -1,69 +0,0 @@
-// Filename: basicGtkDialog.cxx
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "basicGtkDialog.h"
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkDialog::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-BasicGtkDialog::
-BasicGtkDialog(bool free_store) : BasicGtkWindow(free_store) {
-  _vbox = manage(new Gtk::VBox);
-  _action_area = manage(new Gtk::HBox);
-
-  Gtk::VBox *box0 = manage(new Gtk::VBox);
-  Gtk::HSeparator *hsep = manage(new Gtk::HSeparator);
-
-  add(*box0);
-  box0->show();
-  box0->pack_start(*_vbox);
-  _vbox->show();
-
-  box0->pack_start(*hsep);
-  hsep->show();
-
-  _action_area->set_border_width(10);
-  box0->pack_start(*_action_area, false);
-  _action_area->show();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkDialog::get_vbox
-//       Access: Public
-//  Description: Returns a pointer to the main part of the dialog
-//               window.
-////////////////////////////////////////////////////////////////////
-Gtk::VBox *BasicGtkDialog::
-get_vbox() const {
-  return _vbox;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkDialog::get_action_area
-//       Access: Public
-//  Description: Returns a pointer to part of the dialog reserved for
-//               action buttons.
-////////////////////////////////////////////////////////////////////
-Gtk::HBox *BasicGtkDialog::
-get_action_area() const {
-  return _action_area;
-}
-

+ 0 - 48
pandatool/src/gtkbase/basicGtkDialog.h

@@ -1,48 +0,0 @@
-// Filename: basicGtkDialog.h
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef BASICGTKDIALOG_H
-#define BASICGTKDIALOG_H
-
-#include "basicGtkWindow.h"
-
-#include <gtk--.h>
-
-
-////////////////////////////////////////////////////////////////////
-//       Class : BasicGtkDialog
-// Description : This looks like a wrapper around Gtk::Dialog.
-//               Actually, it doesn't inherit from Gtk::Dialog at all,
-//               but instead (indirectly) from Gtk::Window; it just
-//               duplicates the default functionality of Gtk::Dialog
-//               by defining get_vbox() and a get_action_area().
-////////////////////////////////////////////////////////////////////
-class BasicGtkDialog : public BasicGtkWindow {
-public:
-  BasicGtkDialog(bool free_store = true);
-
-  Gtk::VBox *get_vbox() const;
-  Gtk::HBox *get_action_area() const;
-
-private:
-  Gtk::VBox *_vbox;
-  Gtk::HBox *_action_area;
-};
-
-
-#endif

+ 0 - 140
pandatool/src/gtkbase/basicGtkWindow.cxx

@@ -1,140 +0,0 @@
-// Filename: basicGtkWindow.cxx
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "basicGtkWindow.h"
-#include "gtkBase.h"
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkWindow::Constructor
-//       Access: Public
-//  Description: The free_store parameter should be true if the window
-//               object has been allocated from the free store (using
-//               new) and can be safely deleted using delete when the
-//               window is destroyed by the user, or false if this is
-//               not the case.
-////////////////////////////////////////////////////////////////////
-BasicGtkWindow::
-BasicGtkWindow(bool free_store) : _free_store(free_store) {
-  _destroyed = false;
-  _state = S_virgin;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkWindow::Destructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-BasicGtkWindow::
-~BasicGtkWindow() {
-  destruct();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkWindow::setup
-//       Access: Public
-//  Description: Call this after initializing the window.
-////////////////////////////////////////////////////////////////////
-void BasicGtkWindow::
-setup() {
-  _state = S_setup;
-  _destroy_connection =
-    destroy.connect(slot(this, &BasicGtkWindow::window_destroyed));
-  show();
-
-  // Calling show() sets in motion some X events that must flow
-  // completely through the queue before we can safely hide() the
-  // thing again.  To measure when this has happened, we'll drop our
-  // own event into the queue.  When this event makes it through the
-  // queue, we'll assume all relevant X events have also, and it will
-  // be safe to hide the window.
-  Gtk::Main::idle.connect(slot(this, &BasicGtkWindow::idle_event));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkWindow::destruct
-//       Access: Public, Virtual
-//  Description: Call this to remove the window, etc.  It's not tied
-//               directly to the real destructor because that seems to
-//               just lead to trouble.  This returns true if it
-//               actually destructed, or false if it had already
-//               destructed previously and did nothing this time.
-////////////////////////////////////////////////////////////////////
-bool BasicGtkWindow::
-destruct() {
-  if (_state != S_gone) {
-    // We must hide the window before we destruct, or it won't disappear
-    // from the screen.  Strange.  But we also don't want to try to hide
-    // the window if we're destructing because of a window_destroyed
-    // event, so we check our little flag.
-    if (!_destroyed && _state != S_virgin) {
-      // Now, in case the window was never completely shown, we must
-      // wait for that to happen before we can hide it.
-      while (!_destroyed && _state == S_setup) {
-        GtkBase::_gtk->iteration();
-      }
-
-      if (!_destroyed) {
-        hide();
-      }
-    }
-    _state = S_gone;
-    return true;
-  }
-
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkWindow::delete_self
-//       Access: Protected
-//  Description:
-////////////////////////////////////////////////////////////////////
-void BasicGtkWindow::
-delete_self() {
-  destruct();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkWindow::window_destroyed
-//       Access: Private
-//  Description:
-////////////////////////////////////////////////////////////////////
-void BasicGtkWindow::
-window_destroyed() {
-  _destroyed = true;
-  destruct();
-
-  // We should probably also delete the pointer here.  But maybe not.
-  // Gtk-- is very mysterious about this, so we'll just let it maybe
-  // leak.
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BasicGtkWindow::idle_event
-//       Access: Private
-//  Description:
-////////////////////////////////////////////////////////////////////
-gint BasicGtkWindow::
-idle_event() {
-  // Now, we're finally a bona fide window with all rights thereunto
-  // appertaining.
-  _state = S_ready;
-  return false;
-}
-

+ 0 - 60
pandatool/src/gtkbase/basicGtkWindow.h

@@ -1,60 +0,0 @@
-// Filename: basicGtkWindow.h
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef BASICGTKWINDOW_H
-#define BASICGTKWINDOW_H
-
-#include <gtk--.h>
-
-
-////////////////////////////////////////////////////////////////////
-//       Class : BasicGtkWindow
-// Description : This is just a handy wrapper around Gtk::Window that
-//               provides some convenient setup functions.
-////////////////////////////////////////////////////////////////////
-class BasicGtkWindow : public Gtk::Window {
-public:
-  BasicGtkWindow(bool free_store = true);
-  virtual ~BasicGtkWindow();
-  void setup();
-  virtual bool destruct();
-
-protected:
-  void delete_self();
-  static gint static_delete(BasicGtkWindow *window);
-
-private:
-  void window_destroyed();
-  gint idle_event();
-
-  enum State {
-    S_virgin,
-    S_setup,
-    S_ready,
-    S_gone,
-  };
-
-  bool _destroyed;
-  bool _free_store;
-  State _state;
-  SigC::Connection _destroy_connection;
-};
-
-
-#endif
-

+ 0 - 76
pandatool/src/gtkbase/gtkBase.cxx

@@ -1,76 +0,0 @@
-// Filename: gtkBase.cxx
-// Created by:  drose (14Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "gtkBase.h"
-
-#include "notify.h"
-
-Gtk::Main *GtkBase::_gtk = NULL;
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkBase::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkBase::
-GtkBase() {
-  if (_gtk != (Gtk::Main *)NULL) {
-    nout << "Invalid attempt to create multiple instances of GtkBase!\n";
-    abort();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkBase::Destructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-GtkBase::
-~GtkBase() {
-  nassertv(_gtk != (Gtk::Main *)NULL);
-  delete _gtk;
-  _gtk = NULL;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkBase::parse_command_line
-//       Access: Public, Virtual
-//  Description: This is overridden for GtkBase to give Gtk a chance
-//               to pull out its X-related parameters.
-////////////////////////////////////////////////////////////////////
-void GtkBase::
-parse_command_line(int argc, char *argv[]) {
-  nassertv(_gtk == (Gtk::Main *)NULL);
-  _gtk = new Gtk::Main(argc, argv);
-  ProgramBase::parse_command_line(argc, argv);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GtkBase::main_loop
-//       Access: Public
-//  Description: Call this after all is set up to yield control of the
-//               main loop to Gtk.  This normally doesn't return.
-////////////////////////////////////////////////////////////////////
-void GtkBase::
-main_loop() {
-  nassertv(_gtk != NULL);
-
-  _gtk->run();
-}
-

+ 0 - 46
pandatool/src/gtkbase/request_initial_size.cxx

@@ -1,46 +0,0 @@
-// Filename: request_initial_size.cxx
-// Created by:  drose (15Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "request_initial_size.h"
-
-static int
-restore_usize(Gtk::Widget *widget) {
-  widget->set_usize(0, 0);
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: request_initial_size
-//  Description: Gtk-- hack to request an initial size for a widget,
-//               while still allowing the user to resize it smaller.
-////////////////////////////////////////////////////////////////////
-void
-request_initial_size(Gtk::Widget &widget, int xsize, int ysize) {
-  if (xsize != 0 || ysize != 0) {
-    // I can't find a way to request an initial size for a general
-    // widget.  The best I can do is specify its minimum size.
-    widget.set_usize(xsize, ysize);
-
-    // However, I don't want the minimum size to be enforced forever;
-    // the user should be able to resize the window smaller if he wants
-    // to.  Thus, this ugly hack: at the first idle signal, we return
-    // the usize to 0.
-    Gtk::Main::idle.connect(bind(slot(&restore_usize), &widget));
-  }
-}
-

+ 0 - 28
pandatool/src/gtkbase/request_initial_size.h

@@ -1,28 +0,0 @@
-// Filename: request_initial_size.h
-// Created by:  drose (15Jul00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef REQUEST_INITIAL_SIZE_H
-#define REQUEST_INITIAL_SIZE_H
-
-#include "pandatoolbase.h"
-
-#include <gtk--.h>
-
-void request_initial_size(Gtk::Widget &widget, int xsize, int ysize);
-
-#endif