diff --git a/pandatool/src/win-stats/Sources.pp b/pandatool/src/win-stats/Sources.pp index 0494eff19c..ed59572cd5 100644 --- a/pandatool/src/win-stats/Sources.pp +++ b/pandatool/src/win-stats/Sources.pp @@ -21,6 +21,10 @@ winStatsServer.cxx winStatsServer.h \ winStatsStripChart.cxx winStatsStripChart.h + #if $[DEVELOP_WINSTATS] + #define EXTRA_CDEFS $[EXTRA_CDEFS] DEVELOP_WINSTATS + #endif + #define WIN_SYS_LIBS Imm32.lib winmm.lib kernel32.lib oldnames.lib user32.lib gdi32.lib #end bin_target diff --git a/pandatool/src/win-stats/winStats.cxx b/pandatool/src/win-stats/winStats.cxx index cae59a53a3..a1b9999826 100644 --- a/pandatool/src/win-stats/winStats.cxx +++ b/pandatool/src/win-stats/winStats.cxx @@ -62,7 +62,7 @@ create_toplevel_window(HINSTANCE application) { wc.lpfnWndProc = (WNDPROC)toplevel_window_proc; wc.hInstance = application; wc.lpszClassName = toplevel_class_name; - + if (!RegisterClass(&wc)) { nout << "Could not register window class!\n"; exit(1); @@ -70,8 +70,11 @@ create_toplevel_window(HINSTANCE application) { DWORD window_style = WS_POPUP | WS_SYSMENU | WS_ICONIC; + char window_name[128]; + sprintf(window_name, "PStats %d", pstats_port); + HWND toplevel_window = - CreateWindow(toplevel_class_name, "PStats", window_style, + CreateWindow(toplevel_class_name, window_name, window_style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, application, 0); if (!toplevel_window) { @@ -87,7 +90,7 @@ create_toplevel_window(HINSTANCE application) { // but it is sometimes more convenient during development to use // main() instead, which doesn't squelch the stderr output. -#ifdef USE_WINMAIN +#ifndef DEVELOP_WINSTATS int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) #else int main(int argc, char *argv[]) diff --git a/pandatool/src/win-stats/winStatsChartMenu.cxx b/pandatool/src/win-stats/winStatsChartMenu.cxx index 9bd685008c..13b20b8eb2 100755 --- a/pandatool/src/win-stats/winStatsChartMenu.cxx +++ b/pandatool/src/win-stats/winStatsChartMenu.cxx @@ -59,7 +59,7 @@ get_menu_handle() { // Description: Adds the menu to the end of the indicated menu bar. //////////////////////////////////////////////////////////////////// void WinStatsChartMenu:: -add_to_menu_bar(HMENU menu_bar) { +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) { @@ -77,7 +77,7 @@ add_to_menu_bar(HMENU menu_bar) { mii.fType = MFT_STRING; mii.hSubMenu = _menu; mii.dwTypeData = (char *)thread_name.c_str(); - InsertMenuItem(menu_bar, GetMenuItemCount(menu_bar), TRUE, &mii); + InsertMenuItem(menu_bar, before_menu_id, FALSE, &mii); } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/win-stats/winStatsChartMenu.h b/pandatool/src/win-stats/winStatsChartMenu.h index aa9253c890..8ead93549f 100755 --- a/pandatool/src/win-stats/winStatsChartMenu.h +++ b/pandatool/src/win-stats/winStatsChartMenu.h @@ -38,7 +38,7 @@ public: ~WinStatsChartMenu(); HMENU get_menu_handle(); - void add_to_menu_bar(HMENU menu_bar); + void add_to_menu_bar(HMENU menu_bar, int before_menu_id); void check_update(); void do_update(); diff --git a/pandatool/src/win-stats/winStatsGraph.cxx b/pandatool/src/win-stats/winStatsGraph.cxx index 4176df50ef..33e40cfe0c 100644 --- a/pandatool/src/win-stats/winStatsGraph.cxx +++ b/pandatool/src/win-stats/winStatsGraph.cxx @@ -23,6 +23,9 @@ bool WinStatsGraph::_graph_window_class_registered = false; const char * const WinStatsGraph::_graph_window_class_name = "graph"; +DWORD WinStatsGraph::graph_window_style = +WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_VISIBLE; + //////////////////////////////////////////////////////////////////// // Function: WinStatsGraph::Constructor // Access: Public @@ -35,6 +38,7 @@ WinStatsGraph(WinStatsMonitor *monitor, int thread_index) : { _window = 0; _graph_window = 0; + _sizewe_cursor = LoadCursor(NULL, IDC_SIZEWE); _bitmap = 0; _bitmap_dc = 0; @@ -49,6 +53,10 @@ WinStatsGraph(WinStatsMonitor *monitor, int thread_index) : _dark_pen = CreatePen(PS_SOLID, 1, RGB(51, 51, 51)); _light_pen = CreatePen(PS_SOLID, 1, RGB(154, 154, 154)); + + _drag_mode = DM_none; + _potential_drag_mode = DM_none; + _drag_vscale_start = 0.0f; } //////////////////////////////////////////////////////////////////// @@ -156,12 +164,6 @@ void WinStatsGraph:: setup_label_stack() { _label_stack.setup(_window); move_label_stack(); - /* - if (_label_stack()->get_ideal_width() > _label_stack->get_width()) { - _left_margin = _label_stack->get_ideal_width() + 16; - move_label_stack(); - } - */ } //////////////////////////////////////////////////////////////////// @@ -229,6 +231,64 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { InvalidateRect(hwnd, NULL, TRUE); break; + case WM_SETCURSOR: + { + // Why is it so hard to ask what the cursor position within the + // window's client area is? + POINT point; + GetCursorPos(&point); + WINDOWINFO winfo; + GetWindowInfo(hwnd, &winfo); + const RECT &rect = winfo.rcClient; + + // Display a double-headed arrow to drag the left or right margins. + if (point.x >= rect.left + _left_margin - 1 && point.x <= rect.left + _left_margin + 1) { + SetCursor(_sizewe_cursor); + _potential_drag_mode = DM_left_margin; + return TRUE; + } + if (point.x >= rect.right - _right_margin - 2 && point.x <= rect.right - _right_margin) { + SetCursor(_sizewe_cursor); + _potential_drag_mode = DM_right_margin; + return TRUE; + } + + _potential_drag_mode = DM_none; + } + break; + + case WM_LBUTTONDOWN: + if (_potential_drag_mode != DM_none) { + _drag_mode = _potential_drag_mode; + _drag_start_x = (PN_int16)LOWORD(lparam); + _drag_start_y = (PN_int16)HIWORD(lparam); + SetCapture(_window); + } + return 0; + + case WM_MOUSEMOVE: + if (_drag_mode == DM_left_margin) { + PN_int16 x = LOWORD(lparam); + _left_margin += (x - _drag_start_x); + _drag_start_x = x; + InvalidateRect(hwnd, NULL, TRUE); + move_label_stack(); + return 0; + + } else if (_drag_mode == DM_right_margin) { + PN_int16 x = LOWORD(lparam); + _right_margin += (_drag_start_x - x); + _drag_start_x = x; + InvalidateRect(hwnd, NULL, TRUE); + return 0; + } + break; + + case WM_LBUTTONUP: + _drag_mode = DM_none; + ReleaseCapture(); + break; + case WM_PAINT: { PAINTSTRUCT ps; diff --git a/pandatool/src/win-stats/winStatsGraph.h b/pandatool/src/win-stats/winStatsGraph.h index b04b85245f..bff3af04d7 100644 --- a/pandatool/src/win-stats/winStatsGraph.h +++ b/pandatool/src/win-stats/winStatsGraph.h @@ -70,6 +70,8 @@ protected: HWND _graph_window; WinStatsLabelStack _label_stack; + HCURSOR _sizewe_cursor; + HBITMAP _bitmap; HDC _bitmap_dc; @@ -81,6 +83,18 @@ protected: HPEN _dark_pen; HPEN _light_pen; + // What is the user adjusting by dragging the mouse in a window? + enum DragMode { + DM_none, + DM_vscale, + DM_left_margin, + DM_right_margin, + }; + DragMode _drag_mode; + DragMode _potential_drag_mode; + int _drag_start_x, _drag_start_y; + float _drag_vscale_start; + private: void setup_bitmap(int xsize, int ysize); void release_bitmap(); @@ -93,6 +107,9 @@ private: static bool _graph_window_class_registered; static const char * const _graph_window_class_name; + +protected: + static DWORD graph_window_style; }; #endif diff --git a/pandatool/src/win-stats/winStatsLabel.cxx b/pandatool/src/win-stats/winStatsLabel.cxx index 85d344ddcb..8f0043daff 100755 --- a/pandatool/src/win-stats/winStatsLabel.cxx +++ b/pandatool/src/win-stats/winStatsLabel.cxx @@ -214,7 +214,7 @@ register_window_class(HINSTANCE application) { WNDCLASS wc; ZeroMemory(&wc, sizeof(WNDCLASS)); - wc.style = CS_DBLCLKS; + wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)static_window_proc; wc.hInstance = application; wc.hCursor = LoadCursor(NULL, IDC_ARROW); diff --git a/pandatool/src/win-stats/winStatsMenuId.h b/pandatool/src/win-stats/winStatsMenuId.h index 1579a64059..7fdca141a4 100755 --- a/pandatool/src/win-stats/winStatsMenuId.h +++ b/pandatool/src/win-stats/winStatsMenuId.h @@ -30,6 +30,7 @@ enum WinStatsMenuId { MI_none, MI_time_ms, MI_time_hz, + MI_frame_rate_label, // This one is last and represents the beginning of the range for // the various "new chart" menu options. diff --git a/pandatool/src/win-stats/winStatsMonitor.cxx b/pandatool/src/win-stats/winStatsMonitor.cxx index 7ecdd2793b..740b748e32 100644 --- a/pandatool/src/win-stats/winStatsMonitor.cxx +++ b/pandatool/src/win-stats/winStatsMonitor.cxx @@ -47,7 +47,6 @@ WinStatsMonitor() { //////////////////////////////////////////////////////////////////// WinStatsMonitor:: ~WinStatsMonitor() { - cerr << "WinStatsMonitor destructor\n"; Graphs::iterator gi; for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { delete (*gi); @@ -65,8 +64,10 @@ WinStatsMonitor:: _window = 0; } - // For now, exit when the first monitor closes. +#ifdef DEVELOP_WINSTATS + // For Winstats developers, exit when the first monitor closes. exit(0); +#endif } //////////////////////////////////////////////////////////////////// @@ -93,7 +94,6 @@ get_monitor_name() { //////////////////////////////////////////////////////////////////// void WinStatsMonitor:: initialized() { - cerr << "Monitor initialized (refcount = " << get_ref_count() << ")\n"; } //////////////////////////////////////////////////////////////////// @@ -168,7 +168,7 @@ new_collector(int collector_index) { void WinStatsMonitor:: new_thread(int thread_index) { WinStatsChartMenu *chart_menu = new WinStatsChartMenu(this, thread_index); - chart_menu->add_to_menu_bar(_menu_bar); + chart_menu->add_to_menu_bar(_menu_bar, MI_frame_rate_label); _chart_menus.push_back(chart_menu); DrawMenuBar(_window); } @@ -202,8 +202,7 @@ new_data(int thread_index, int frame_number) { //////////////////////////////////////////////////////////////////// void WinStatsMonitor:: lost_connection() { - cerr << "Lost connection to " << get_client_hostname() - << " (refcount = " << get_ref_count() << ")\n"; + nout << "Lost connection to " << get_client_hostname() << "\n"; if (_window) { DestroyWindow(_window); @@ -225,6 +224,22 @@ idle() { 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); + } } //////////////////////////////////////////////////////////////////// @@ -326,7 +341,6 @@ set_time_units(int unit_mask) { memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STATE; - mii.fState = MFS_CHECKED; mii.fState = ((_time_units & PStatGraph::GBU_ms) != 0) ? MFS_CHECKED : MFS_UNCHECKED; @@ -379,10 +393,11 @@ create_window() { _menu_bar = CreateMenu(); setup_options_menu(); + setup_frame_rate_label(); ChartMenus::iterator mi; for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) { - (*mi)->add_to_menu_bar(_menu_bar); + (*mi)->add_to_menu_bar(_menu_bar, MI_frame_rate_label); } _window_title = get_client_progname() + " on " + get_client_hostname(); @@ -439,7 +454,28 @@ setup_options_menu() { mii.wID = MI_time_hz; mii.dwTypeData = "Hz"; InsertMenuItem(_options_menu, GetMenuItemCount(_options_menu), TRUE, &mii); +} +//////////////////////////////////////////////////////////////////// +// Function: WinStatsMonitor::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 WinStatsMonitor:: +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); } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/win-stats/winStatsMonitor.h b/pandatool/src/win-stats/winStatsMonitor.h index d8960a8c32..6239c11faa 100644 --- a/pandatool/src/win-stats/winStatsMonitor.h +++ b/pandatool/src/win-stats/winStatsMonitor.h @@ -78,6 +78,7 @@ private: void create_window(); void setup_options_menu(); + void setup_frame_rate_label(); static void register_window_class(HINSTANCE application); static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); diff --git a/pandatool/src/win-stats/winStatsStripChart.cxx b/pandatool/src/win-stats/winStatsStripChart.cxx index 2c11a0a2cf..550b914826 100644 --- a/pandatool/src/win-stats/winStatsStripChart.cxx +++ b/pandatool/src/win-stats/winStatsStripChart.cxx @@ -40,8 +40,6 @@ WinStatsStripChart(WinStatsMonitor *monitor, int thread_index, WinStatsGraph(monitor, thread_index) { _brush_origin = 0; - _drag_vscale = false; - _drag_vscale_start = 0.0f; // Let's show the units on the guide bar labels. There's room. set_guide_bar_units(get_guide_bar_units() | GBU_show_units); @@ -284,7 +282,7 @@ end_draw(int from_x, int to_x) { const GuideBar &bar = get_guide_bar(i); int y = height_to_pixel(bar._height); - if (y >= 5) { + if (y > 0) { // Only draw it if it's not too close to the top. if (bar._is_target) { SelectObject(_bitmap_dc, _light_pen); @@ -337,7 +335,7 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { case WM_LBUTTONDOWN: { - _drag_vscale = true; + _drag_mode = DM_vscale; PN_int16 y = HIWORD(lparam); _drag_vscale_start = pixel_to_height(y); SetCapture(_graph_window); @@ -345,7 +343,7 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { return 0; case WM_MOUSEMOVE: - if (_drag_vscale) { + if (_drag_mode == DM_vscale) { PN_int16 y = HIWORD(lparam); float ratio = 1.0f - ((float)y / (float)get_ysize()); if (ratio > 0.0f) { @@ -356,19 +354,13 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { break; case WM_LBUTTONUP: - if (_drag_vscale) { - PN_int16 y = HIWORD(lparam); - float ratio = 1.0f - ((float)y / (float)get_ysize()); - if (ratio > 0.0f) { - set_vertical_scale(_drag_vscale_start / ratio); - } - _drag_vscale = false; + if (_drag_mode == DM_vscale) { + _drag_mode = DM_none; ReleaseCapture(); return 0; } break; - default: break; } @@ -448,7 +440,6 @@ create_window() { register_window_class(application); string window_title = get_title_text(); - DWORD window_style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_VISIBLE; RECT win_rect = { 0, 0, @@ -457,10 +448,10 @@ create_window() { }; // compute window size based on desired client area size - AdjustWindowRect(&win_rect, window_style, FALSE); + AdjustWindowRect(&win_rect, graph_window_style, FALSE); _window = - CreateWindow(_window_class_name, window_title.c_str(), window_style, + 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, diff --git a/pandatool/src/win-stats/winStatsStripChart.h b/pandatool/src/win-stats/winStatsStripChart.h index 70eed44c44..cb12ac12ab 100644 --- a/pandatool/src/win-stats/winStatsStripChart.h +++ b/pandatool/src/win-stats/winStatsStripChart.h @@ -69,8 +69,6 @@ private: static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); int _brush_origin; - bool _drag_vscale; - float _drag_vscale_start; static bool _window_class_registered; static const char * const _window_class_name;