menu stuff

This commit is contained in:
David Rose 2004-01-09 01:23:25 +00:00
parent 1643f77bc7
commit 5d8bb3dfab
12 changed files with 1091 additions and 6 deletions

View File

@ -156,12 +156,31 @@ get_collector_fullname(int index) const {
// Description: Indicates whether the given collector has level data
// (and consequently, whether it should appear on the
// Levels menu).
//
// The return value is true if anything changed, false
// otherwise.
////////////////////////////////////////////////////////////////////
void PStatClientData::
bool PStatClientData::
set_collector_has_level(int index, bool flag) {
bool any_changed = false;
slot_collector(index);
nassertv(index >= 0 && index < (int)_collectors.size());
_collectors[index]._is_level = flag;
nassertr(index >= 0 && index < (int)_collectors.size(), false);
if (_collectors[index]._is_level != flag) {
any_changed = true;
_collectors[index]._is_level = flag;
// Turning this on for a given collector also implicitly turns all
// of its ancestors.
if (flag) {
PStatCollectorDef *def = _collectors[index]._def;
if (def->_parent_index != 0) {
set_collector_has_level(def->_parent_index, flag);
}
}
}
return any_changed;
}
@ -178,6 +197,32 @@ get_collector_has_level(int index) const {
_collectors[index]._is_level);
}
////////////////////////////////////////////////////////////////////
// Function: PStatClientData::get_num_toplevel_collectors
// Access: Public
// Description: Returns the total number of collectors that are
// toplevel collectors. These are the collectors that
// are the children of "Frame", which is collector 0.
////////////////////////////////////////////////////////////////////
int PStatClientData::
get_num_toplevel_collectors() const {
return _toplevel_collectors.size();
}
////////////////////////////////////////////////////////////////////
// Function: PStatClientData::get_toplevel_collector
// Access: Public
// Description: Returns the collector index of the nth toplevel
// collector. Use this function to iterate through the
// n toplevel collectors indicated by
// get_num_toplevel_collectors().
////////////////////////////////////////////////////////////////////
int PStatClientData::
get_toplevel_collector(int n) const {
nassertr(n >= 0 && n < (int)_toplevel_collectors.size(), 0);
return _toplevel_collectors[n];
}
////////////////////////////////////////////////////////////////////
// Function: PStatClientData::get_num_threads
// Access: Public
@ -278,6 +323,7 @@ add_collector(PStatCollectorDef *def) {
}
_collectors[def->_index]._def = def;
update_toplevel_collectors();
}
////////////////////////////////////////////////////////////////////
@ -343,3 +389,21 @@ slot_collector(int collector_index) {
_collectors.push_back(collector);
}
}
////////////////////////////////////////////////////////////////////
// Function: PStatClientData::update_toplevel_collectors
// Access: Private
// Description: Rebuilds the list of toplevel collectors.
////////////////////////////////////////////////////////////////////
void PStatClientData::
update_toplevel_collectors() {
_toplevel_collectors.clear();
Collectors::const_iterator ci;
for (ci = _collectors.begin(); ci != _collectors.end(); ++ci) {
PStatCollectorDef *def = (*ci)._def;
if (def->_parent_index == 0) {
_toplevel_collectors.push_back(def->_index);
}
}
}

View File

@ -50,9 +50,12 @@ public:
const PStatCollectorDef &get_collector_def(int index) const;
string get_collector_name(int index) const;
string get_collector_fullname(int index) const;
void set_collector_has_level(int index, bool flag);
bool set_collector_has_level(int index, bool flag);
bool get_collector_has_level(int index) const;
int get_num_toplevel_collectors() const;
int get_toplevel_collector(int index) const;
int get_num_threads() const;
bool has_thread(int index) const;
string get_thread_name(int index) const;
@ -68,7 +71,7 @@ public:
PStatFrameData *frame_data);
private:
void slot_collector(int collector_index);
void update_toplevel_collectors();
private:
bool _is_alive;
@ -83,6 +86,9 @@ private:
typedef pvector<Collector> Collectors;
Collectors _collectors;
typedef pvector<int> ToplevelCollectors;
ToplevelCollectors _toplevel_collectors;
class Thread {
public:
string _name;

View File

@ -12,6 +12,7 @@
#define SOURCES \
winStats.cxx \
winStatsChartMenu.cxx winStatsChartMenu.h \
winStatsGraph.cxx winStatsGraph.h \
winStatsLabel.cxx winStatsLabel.h \
winStatsLabelStack.cxx winStatsLabelStack.h \

View File

@ -0,0 +1,185 @@
// Filename: winStatsChartMenu.cxx
// Created by: drose (08Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "winStatsChartMenu.h"
#include "pStatMonitor.h"
////////////////////////////////////////////////////////////////////
// Function: WinStatsChartMenu::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WinStatsChartMenu::
WinStatsChartMenu(PStatMonitor *monitor, int thread_index) :
_monitor(monitor),
_thread_index(thread_index)
{
_menu = CreatePopupMenu();
do_update();
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsChartMenu::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WinStatsChartMenu::
~WinStatsChartMenu() {
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsChartMenu::get_menu_handle
// Access: Public
// Description: Returns the Windows menu handle for this particular
// menu.
////////////////////////////////////////////////////////////////////
HMENU WinStatsChartMenu::
get_menu_handle() {
return _menu;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsChartMenu::add_to_menu_bar
// Access: Public
// Description: Adds the menu to the end of the indicated menu bar.
////////////////////////////////////////////////////////////////////
void WinStatsChartMenu::
add_to_menu_bar(HMENU menu_bar) {
const PStatClientData *client_data = _monitor->get_client_data();
string 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, GetMenuItemCount(menu_bar), TRUE, &mii);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsChartMenu::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 WinStatsChartMenu::
check_update() {
PStatView &view = _monitor->get_view(_thread_index);
if (view.get_level_index() != _last_level_index) {
do_update();
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsChartMenu::do_update
// Access: Public
// Description: Unconditionally updates the menu with the latest data
// from the client.
////////////////////////////////////////////////////////////////////
void WinStatsChartMenu::
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());
bool needs_separator = true;
// 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) {
MENUITEMINFO mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
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());
}
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsChartMenu::add_view
// Access: Private
// Description: Adds a new entry or entries to the menu for the
// indicated view and its children.
////////////////////////////////////////////////////////////////////
void WinStatsChartMenu::
add_view(HMENU parent_menu, const PStatViewLevel *view_level) {
int collector = view_level->get_collector();
const PStatClientData *client_data = _monitor->get_client_data();
string collector_name = client_data->get_collector_name(collector);
MENUITEMINFO mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STRING | MIIM_FTYPE;
mii.fType = MFT_STRING;
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 != 0) {
// If the collector has any children, 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));
}
}
}

View File

@ -0,0 +1,57 @@
// Filename: winStatsChartMenu.h
// Created by: drose (08Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef WINSTATSCHARTMENU_H
#define WINSTATSCHARTMENU_H
#include "pandatoolbase.h"
#include <windows.h>
class PStatMonitor;
class PStatView;
class PStatViewLevel;
////////////////////////////////////////////////////////////////////
// Class : WinStatsChartMenu
// Description : A pulldown menu of charts available for a particular
// thread.
////////////////////////////////////////////////////////////////////
class WinStatsChartMenu {
public:
WinStatsChartMenu(PStatMonitor *monitor, int thread_index);
~WinStatsChartMenu();
HMENU get_menu_handle();
void add_to_menu_bar(HMENU menu_bar);
void check_update();
void do_update();
private:
void add_view(HMENU parent_menu, const PStatViewLevel *view_level);
PStatMonitor *_monitor;
int _thread_index;
int _last_level_index;
HMENU _menu;
};
#endif

View File

@ -0,0 +1,284 @@
// Filename: winStatsLabel.cxx
// Created by: drose (07Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "winStatsLabel.h"
#include "winStatsMonitor.h"
int WinStatsLabel::_left_margin = 2;
int WinStatsLabel::_right_margin = 2;
int WinStatsLabel::_top_margin = 2;
int WinStatsLabel::_bottom_margin = 2;
bool WinStatsLabel::_window_class_registered = false;
const char * const WinStatsLabel::_window_class_name = "label";
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WinStatsLabel::
WinStatsLabel(WinStatsMonitor *monitor, int collector_index) :
_collector_index(collector_index)
{
_window = 0;
_text = monitor->get_client_data()->get_collector_name(_collector_index);
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 =
rgb[0] * 0.299 +
rgb[1] * 0.587 +
rgb[2] * 0.114;
if (bright >= 0.5) {
_fg_color = RGB(0, 0, 0);
} else {
_fg_color = RGB(255, 255, 255);
}
_x = 0;
_y = 0;
_width = 0;
_height = 0;
_ideal_width = 0;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WinStatsLabel::
~WinStatsLabel() {
if (_window) {
DestroyWindow(_window);
_window = 0;
}
DeleteObject(_bg_brush);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::setup
// Access: Public
// Description: Creates the actual window.
////////////////////////////////////////////////////////////////////
void WinStatsLabel::
setup(HWND parent_window) {
if (_window) {
DestroyWindow(_window);
_window = 0;
}
create_window(parent_window);
HDC hdc = GetDC(_window);
HGDIOBJ hfnt = GetStockObject(ANSI_VAR_FONT);
SelectObject(hdc, hfnt);
SIZE size;
GetTextExtentPoint32(hdc, _text.data(), _text.length(), &size);
_height = size.cy + _top_margin + _bottom_margin;
_ideal_width = size.cx + _left_margin + _right_margin;
ReleaseDC(_window, hdc);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::set_pos
// Access: Public
// Description: Sets the position of the label on its parent. The
// position describes the lower-left corner of the
// rectangle, not the upper-left.
////////////////////////////////////////////////////////////////////
void WinStatsLabel::
set_pos(int x, int y, int width) {
_x = x;
_y = y;
_width = width;
SetWindowPos(_window, 0, x, y - _height, _width, _height,
SWP_NOZORDER | SWP_SHOWWINDOW);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::get_x
// Access: Public
// Description: Returns the x position of the label on its parent.
////////////////////////////////////////////////////////////////////
int WinStatsLabel::
get_x() const {
return _x;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::get_y
// Access: Public
// Description: Returns the y position of the label on its parent.
////////////////////////////////////////////////////////////////////
int WinStatsLabel::
get_y() const {
return _y;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::get_width
// Access: Public
// Description: Returns the width of the label as we requested it.
////////////////////////////////////////////////////////////////////
int WinStatsLabel::
get_width() const {
return _width;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::get_height
// Access: Public
// Description: Returns the height of the label as we requested it.
////////////////////////////////////////////////////////////////////
int WinStatsLabel::
get_height() const {
return _height;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::get_ideal_width
// Access: Public
// Description: Returns the width the label would really prefer to be.
////////////////////////////////////////////////////////////////////
int WinStatsLabel::
get_ideal_width() const {
return _ideal_width;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::create_window
// Access: Private
// Description: Creates the window for this label.
////////////////////////////////////////////////////////////////////
void WinStatsLabel::
create_window(HWND parent_window) {
if (_window) {
return;
}
HINSTANCE application = GetModuleHandle(NULL);
register_window_class(application);
_window =
CreateWindow(_window_class_name, _text.c_str(), WS_CHILD,
0, 0, 0, 0,
parent_window, NULL, application, 0);
if (!_window) {
nout << "Could not create Label window!\n";
exit(1);
}
SetWindowLongPtr(_window, 0, (LONG_PTR)this);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::register_window_class
// Access: Private, Static
// Description: Registers the window class for the label window, if
// it has not already been registered.
////////////////////////////////////////////////////////////////////
void WinStatsLabel::
register_window_class(HINSTANCE application) {
if (_window_class_registered) {
return;
}
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 = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = _window_class_name;
// Reserve space to associate the this pointer with the window.
wc.cbWndExtra = sizeof(WinStatsLabel *);
if (!RegisterClass(&wc)) {
nout << "Could not register Label window class!\n";
exit(1);
}
_window_class_registered = true;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::static_window_proc
// Access: Private, Static
// Description:
////////////////////////////////////////////////////////////////////
LONG WINAPI WinStatsLabel::
static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
WinStatsLabel *self = (WinStatsLabel *)GetWindowLongPtr(hwnd, 0);
if (self != (WinStatsLabel *)NULL && self->_window == hwnd) {
return self->window_proc(hwnd, msg, wparam, lparam);
} else {
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabel::window_proc
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
LONG WinStatsLabel::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rect = { 0, 0, _width, _height };
FillRect(hdc, &rect, _bg_brush);
HGDIOBJ hfnt = GetStockObject(ANSI_VAR_FONT);
SelectObject(hdc, hfnt);
SetTextAlign(hdc, TA_RIGHT | TA_TOP);
SetBkColor(hdc, _bg_color);
SetBkMode(hdc, OPAQUE);
SetTextColor(hdc, _fg_color);
TextOut(hdc, _width - _right_margin, _top_margin,
_text.data(), _text.length());
EndPaint(hwnd, &ps);
return 0;
}
default:
break;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}

View File

@ -0,0 +1,77 @@
// Filename: winStatsLabel.h
// Created by: drose (07Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef WINSTATSLABEL_H
#define WINSTATSLABEL_H
#include "pandatoolbase.h"
#include <windows.h>
class WinStatsMonitor;
////////////////////////////////////////////////////////////////////
// Class : WinStatsLabel
// Description : A text label that will draw in color appropriate for
// a particular collector. It also responds when the
// user double-clicks on it. This is handy for putting
// colored labels on strip charts.
////////////////////////////////////////////////////////////////////
class WinStatsLabel {
public:
WinStatsLabel(WinStatsMonitor *monitor, int collector_index);
~WinStatsLabel();
void setup(HWND parent_window);
void set_pos(int x, int y, int width);
int get_x() const;
int get_y() const;
int get_width() const;
int get_height() const;
int get_ideal_width() const;
private:
void create_window(HWND parent_window);
static void register_window_class(HINSTANCE application);
static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
int _collector_index;
string _text;
HWND _window;
COLORREF _bg_color;
COLORREF _fg_color;
HBRUSH _bg_brush;
int _x;
int _y;
int _width;
int _height;
int _ideal_width;
static int _left_margin, _right_margin;
static int _top_margin, _bottom_margin;
static bool _window_class_registered;
static const char * const _window_class_name;
};
#endif

View File

@ -0,0 +1,282 @@
// Filename: winStatsLabelStack.cxx
// Created by: drose (07Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "winStatsLabelStack.h"
#include "winStatsLabel.h"
bool WinStatsLabelStack::_window_class_registered = false;
const char * const WinStatsLabelStack::_window_class_name = "stack";
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WinStatsLabelStack::
WinStatsLabelStack() {
_window = 0;
_x = 0;
_y = 0;
_width = 0;
_height = 0;
_ideal_width = 0;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WinStatsLabelStack::
~WinStatsLabelStack() {
clear_labels();
if (_window) {
DestroyWindow(_window);
_window = 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::setup
// Access: Public
// Description: Creates the actual window object.
////////////////////////////////////////////////////////////////////
void WinStatsLabelStack::
setup(HWND parent_window) {
if (_window) {
DestroyWindow(_window);
_window = 0;
}
create_window(parent_window);
_ideal_width = 0;
Labels::iterator li;
for (li = _labels.begin(); li != _labels.end(); ++li) {
WinStatsLabel *label = (*li);
label->setup(_window);
_ideal_width = max(_ideal_width, label->get_ideal_width());
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::is_setup
// Access: Public
// Description: Returns true if the label stack has been set up,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool WinStatsLabelStack::
is_setup() const {
return (_window != 0);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::set_pos
// Access: Public
// Description: Sets the position and size of the label stack on its parent.
////////////////////////////////////////////////////////////////////
void WinStatsLabelStack::
set_pos(int x, int y, int width, int height) {
_x = x;
_y = y;
_width = width;
_height = height;
SetWindowPos(_window, 0, x, y, _width, _height,
SWP_NOZORDER | SWP_SHOWWINDOW);
Labels::iterator li;
int yp = height;
for (li = _labels.begin(); li != _labels.end(); ++li) {
WinStatsLabel *label = (*li);
label->set_pos(0, yp, _width);
yp -= label->get_height();
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::get_x
// Access: Public
// Description: Returns the x position of the stack on its parent.
////////////////////////////////////////////////////////////////////
int WinStatsLabelStack::
get_x() const {
return _x;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::get_y
// Access: Public
// Description: Returns the y position of the stack on its parent.
////////////////////////////////////////////////////////////////////
int WinStatsLabelStack::
get_y() const {
return _y;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::get_width
// Access: Public
// Description: Returns the width of the stack as we requested it.
////////////////////////////////////////////////////////////////////
int WinStatsLabelStack::
get_width() const {
return _width;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::get_height
// Access: Public
// Description: Returns the height of the stack as we requested it.
////////////////////////////////////////////////////////////////////
int WinStatsLabelStack::
get_height() const {
return _height;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::get_ideal_width
// Access: Public
// Description: Returns the width the stack would really prefer to be.
////////////////////////////////////////////////////////////////////
int WinStatsLabelStack::
get_ideal_width() const {
return _ideal_width;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::clear_labels
// Access: Public
// Description: Removes the set of labels and starts a new set.
////////////////////////////////////////////////////////////////////
void WinStatsLabelStack::
clear_labels() {
Labels::iterator li;
for (li = _labels.begin(); li != _labels.end(); ++li) {
delete (*li);
}
_labels.clear();
_ideal_width = 0;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::add_label
// Access: Public
// Description: Adds a new label to the top of the stack.
////////////////////////////////////////////////////////////////////
void WinStatsLabelStack::
add_label(WinStatsMonitor *monitor, int collector_index) {
int yp = _height;
if (!_labels.empty()) {
WinStatsLabel *top_label = _labels.back();
yp = top_label->get_y() - top_label->get_height();
}
WinStatsLabel *label = new WinStatsLabel(monitor, collector_index);
if (_window) {
label->setup(_window);
label->set_pos(0, yp, _width);
}
_ideal_width = max(_ideal_width, label->get_ideal_width());
_labels.push_back(label);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::create_window
// Access: Private
// Description: Creates the window for this stack.
////////////////////////////////////////////////////////////////////
void WinStatsLabelStack::
create_window(HWND parent_window) {
if (_window) {
return;
}
HINSTANCE application = GetModuleHandle(NULL);
register_window_class(application);
_window =
CreateWindow(_window_class_name, "label stack", WS_CHILD | WS_CLIPCHILDREN,
0, 0, 0, 0,
parent_window, NULL, application, 0);
if (!_window) {
nout << "Could not create Label Stack window!\n";
exit(1);
}
SetWindowLongPtr(_window, 0, (LONG_PTR)this);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::register_window_class
// Access: Private, Static
// Description: Registers the window class for the label window, if
// it has not already been registered.
////////////////////////////////////////////////////////////////////
void WinStatsLabelStack::
register_window_class(HINSTANCE application) {
if (_window_class_registered) {
return;
}
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(WinStatsLabelStack *);
if (!RegisterClass(&wc)) {
nout << "Could not register Label Stack window class!\n";
exit(1);
}
_window_class_registered = true;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::static_window_proc
// Access: Private, Static
// Description:
////////////////////////////////////////////////////////////////////
LONG WINAPI WinStatsLabelStack::
static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
WinStatsLabelStack *self = (WinStatsLabelStack *)GetWindowLongPtr(hwnd, 0);
if (self != (WinStatsLabelStack *)NULL && self->_window == hwnd) {
return self->window_proc(hwnd, msg, wparam, lparam);
} else {
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsLabelStack::window_proc
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
LONG WinStatsLabelStack::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
return DefWindowProc(hwnd, msg, wparam, lparam);
}

View File

@ -0,0 +1,75 @@
// Filename: winStatsLabelStack.h
// Created by: drose (07Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef WINSTATSLABELSTACK_H
#define WINSTATSLABELSTACK_H
#include "pandatoolbase.h"
#include "pvector.h"
#include <windows.h>
class WinStatsLabel;
class WinStatsMonitor;
////////////////////////////////////////////////////////////////////
// Class : WinStatsLabelStack
// Description : A window that contains a stack of labels from bottom
// to top.
////////////////////////////////////////////////////////////////////
class WinStatsLabelStack {
public:
WinStatsLabelStack();
~WinStatsLabelStack();
void setup(HWND parent_window);
bool is_setup() const;
void set_pos(int x, int y, int width, int height);
int get_x() const;
int get_y() const;
int get_width() const;
int get_height() const;
int get_ideal_width() const;
void clear_labels();
void add_label(WinStatsMonitor *monitor, int collector_index);
private:
void create_window(HWND parent_window);
static void register_window_class(HINSTANCE application);
static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
HWND _window;
int _x;
int _y;
int _width;
int _height;
int _ideal_width;
typedef pvector<WinStatsLabel *> Labels;
Labels _labels;
static bool _window_class_registered;
static const char * const _window_class_name;
};
#endif

View File

@ -18,8 +18,10 @@
#include "winStatsMonitor.h"
#include "winStatsStripChart.h"
#include "winStatsChartMenu.h"
#include "pStatCollectorDef.h"
#include "indent.h"
bool WinStatsMonitor::_window_class_registered = false;
const char * const WinStatsMonitor::_window_class_name = "monitor";
@ -32,6 +34,7 @@ const char * const WinStatsMonitor::_window_class_name = "monitor";
WinStatsMonitor::
WinStatsMonitor() {
_window = 0;
_menu_bar = 0;
}
////////////////////////////////////////////////////////////////////
@ -48,6 +51,12 @@ WinStatsMonitor::
}
_graphs.clear();
ChartMenus::iterator mi;
for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
delete (*mi);
}
_chart_menus.clear();
if (_window) {
DestroyWindow(_window);
_window = 0;
@ -135,6 +144,30 @@ new_collector(int collector_index) {
WinStatsGraph *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: WinStatsMonitor::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 WinStatsMonitor::
new_thread(int thread_index) {
WinStatsChartMenu *chart_menu = new WinStatsChartMenu(this, thread_index);
chart_menu->add_to_menu_bar(_menu_bar);
_chart_menus.push_back(chart_menu);
}
////////////////////////////////////////////////////////////////////
@ -184,6 +217,11 @@ lost_connection() {
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
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();
}
}
////////////////////////////////////////////////////////////////////
@ -246,6 +284,13 @@ create_window() {
HINSTANCE application = GetModuleHandle(NULL);
register_window_class(application);
_menu_bar = CreateMenu();
ChartMenus::iterator mi;
for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
(*mi)->add_to_menu_bar(_menu_bar);
}
_window_title = get_client_progname() + " on " + get_client_hostname();
DWORD window_style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
WS_CLIPSIBLINGS | WS_VISIBLE;
@ -253,7 +298,7 @@ create_window() {
_window =
CreateWindow(_window_class_name, _window_title.c_str(), window_style,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, application, 0);
NULL, _menu_bar, application, 0);
if (!_window) {
nout << "Could not create monitor window!\n";
exit(1);

View File

@ -28,6 +28,8 @@
#include <windows.h>
class WinStatsChartMenu;
////////////////////////////////////////////////////////////////////
// Class : WinStatsMonitor
// Description : This class represents a connection to a PStatsClient
@ -45,6 +47,7 @@ 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();
@ -65,7 +68,11 @@ private:
typedef pset<WinStatsGraph *> Graphs;
Graphs _graphs;
typedef pvector<WinStatsChartMenu *> ChartMenus;
ChartMenus _chart_menus;
HWND _window;
HMENU _menu_bar;
string _window_title;
static bool _window_class_registered;

View File

@ -337,10 +337,12 @@ static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
////////////////////////////////////////////////////////////////////
LONG WinStatsStripChart::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
/*
switch (msg) {
default:
break;
}
*/
return WinStatsGraph::window_proc(hwnd, msg, wparam, lparam);
}