Panda3D

winStatsPianoRoll.cxx

00001 // Filename: winStatsPianoRoll.cxx
00002 // Created by:  drose (03Dec03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "winStatsPianoRoll.h"
00016 #include "winStatsMonitor.h"
00017 #include "numeric_types.h"
00018 
00019 static const int default_piano_roll_width = 400;
00020 static const int default_piano_roll_height = 200;
00021 
00022 bool WinStatsPianoRoll::_window_class_registered = false;
00023 const char * const WinStatsPianoRoll::_window_class_name = "piano";
00024 
00025 ////////////////////////////////////////////////////////////////////
00026 //     Function: WinStatsPianoRoll::Constructor
00027 //       Access: Public
00028 //  Description:
00029 ////////////////////////////////////////////////////////////////////
00030 WinStatsPianoRoll::
00031 WinStatsPianoRoll(WinStatsMonitor *monitor, int thread_index) :
00032   PStatPianoRoll(monitor, thread_index, 
00033                  default_piano_roll_width,
00034                  default_piano_roll_height),
00035   WinStatsGraph(monitor)
00036 {
00037   _left_margin = 128;
00038   _right_margin = 8;
00039   _top_margin = 16;
00040   _bottom_margin = 8;
00041 
00042   // Let's show the units on the guide bar labels.  There's room.
00043   set_guide_bar_units(get_guide_bar_units() | GBU_show_units);
00044 
00045   create_window();
00046   clear_region();
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: WinStatsPianoRoll::Destructor
00051 //       Access: Public, Virtual
00052 //  Description:
00053 ////////////////////////////////////////////////////////////////////
00054 WinStatsPianoRoll::
00055 ~WinStatsPianoRoll() {
00056 }
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: WinStatsPianoRoll::idle
00060 //       Access: Public, Virtual
00061 //  Description: Called as each frame's data is made available.  There
00062 //               is no gurantee the frames will arrive in order, or
00063 //               that all of them will arrive at all.  The monitor
00064 //               should be prepared to accept frames received
00065 //               out-of-order or missing.
00066 ////////////////////////////////////////////////////////////////////
00067 void WinStatsPianoRoll::
00068 new_data(int thread_index, int frame_number) {
00069   if (!_pause) {
00070     update();
00071   }
00072 }
00073 
00074 ////////////////////////////////////////////////////////////////////
00075 //     Function: WinStatsPianoRoll::force_redraw
00076 //       Access: Public, Virtual
00077 //  Description: Called when it is necessary to redraw the entire graph.
00078 ////////////////////////////////////////////////////////////////////
00079 void WinStatsPianoRoll::
00080 force_redraw() {
00081   PStatPianoRoll::force_redraw();
00082 }
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: WinStatsPianoRoll::changed_graph_size
00086 //       Access: Public, Virtual
00087 //  Description: Called when the user has resized the window, forcing
00088 //               a resize of the graph.
00089 ////////////////////////////////////////////////////////////////////
00090 void WinStatsPianoRoll::
00091 changed_graph_size(int graph_xsize, int graph_ysize) {
00092   PStatPianoRoll::changed_size(graph_xsize, graph_ysize);
00093 }
00094 
00095 ////////////////////////////////////////////////////////////////////
00096 //     Function: WinStatsPianoRoll::set_time_units
00097 //       Access: Public, Virtual
00098 //  Description: Called when the user selects a new time units from
00099 //               the monitor pulldown menu, this should adjust the
00100 //               units for the graph to the indicated mask if it is a
00101 //               time-based graph.
00102 ////////////////////////////////////////////////////////////////////
00103 void WinStatsPianoRoll::
00104 set_time_units(int unit_mask) {
00105   int old_unit_mask = get_guide_bar_units();
00106   if ((old_unit_mask & (GBU_hz | GBU_ms)) != 0) {
00107     unit_mask = unit_mask & (GBU_hz | GBU_ms);
00108     unit_mask |= (old_unit_mask & GBU_show_units);
00109     set_guide_bar_units(unit_mask);
00110 
00111     RECT rect;
00112     GetClientRect(_window, &rect);
00113     rect.left = _right_margin;
00114     InvalidateRect(_window, &rect, TRUE);
00115   }
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //     Function: WinStatsPianoRoll::clicked_label
00120 //       Access: Public, Virtual
00121 //  Description: Called when the user single-clicks on a label.
00122 ////////////////////////////////////////////////////////////////////
00123 void WinStatsPianoRoll::
00124 clicked_label(int collector_index) {
00125   if (collector_index >= 0) {
00126     WinStatsGraph::_monitor->open_strip_chart(_thread_index, collector_index, false);
00127   }
00128 }
00129 
00130 ////////////////////////////////////////////////////////////////////
00131 //     Function: WinStatsPianoRoll::set_horizontal_scale
00132 //       Access: Public
00133 //  Description: Changes the amount of time the width of the
00134 //               horizontal axis represents.  This may force a redraw.
00135 ////////////////////////////////////////////////////////////////////
00136 void WinStatsPianoRoll::
00137 set_horizontal_scale(double time_width) {
00138   PStatPianoRoll::set_horizontal_scale(time_width);
00139 
00140   RECT rect;
00141   GetClientRect(_window, &rect);
00142   rect.bottom = _top_margin;
00143   InvalidateRect(_window, &rect, TRUE);
00144 }
00145 
00146 ////////////////////////////////////////////////////////////////////
00147 //     Function: WinStatsPianoRoll::clear_region
00148 //       Access: Protected
00149 //  Description: Erases the chart area.
00150 ////////////////////////////////////////////////////////////////////
00151 void WinStatsPianoRoll::
00152 clear_region() {
00153   RECT rect = { 0, 0, get_xsize(), get_ysize() };
00154   FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
00155 }
00156 
00157 ////////////////////////////////////////////////////////////////////
00158 //     Function: WinStatsPianoRoll::begin_draw
00159 //       Access: Protected, Virtual
00160 //  Description: Erases the chart area in preparation for drawing a
00161 //               bunch of bars.
00162 ////////////////////////////////////////////////////////////////////
00163 void WinStatsPianoRoll::
00164 begin_draw() {
00165   clear_region();
00166 
00167   // Draw in the guide bars.
00168   int num_guide_bars = get_num_guide_bars();
00169   for (int i = 0; i < num_guide_bars; i++) {
00170     draw_guide_bar(_bitmap_dc, get_guide_bar(i));
00171   }
00172 }
00173 
00174 ////////////////////////////////////////////////////////////////////
00175 //     Function: WinStatsPianoRoll::draw_bar
00176 //       Access: Protected, Virtual
00177 //  Description: Draws a single bar on the chart.
00178 ////////////////////////////////////////////////////////////////////
00179 void WinStatsPianoRoll::
00180 draw_bar(int row, int from_x, int to_x) {
00181   if (row >= 0 && row < _label_stack.get_num_labels()) {
00182     int y = _label_stack.get_label_y(row) - _graph_top;
00183     int height = _label_stack.get_label_height(row);
00184 
00185     RECT rect = { 
00186       from_x, y - height + 2,
00187       to_x, y - 2,
00188     };
00189     int collector_index = get_label_collector(row);
00190     HBRUSH brush = get_collector_brush(collector_index);
00191     FillRect(_bitmap_dc, &rect, brush);
00192   }
00193 }
00194 
00195 ////////////////////////////////////////////////////////////////////
00196 //     Function: WinStatsPianoRoll::end_draw
00197 //       Access: Protected, Virtual
00198 //  Description: Called after all the bars have been drawn, this
00199 //               triggers a refresh event to draw it to the window.
00200 ////////////////////////////////////////////////////////////////////
00201 void WinStatsPianoRoll::
00202 end_draw() {
00203   InvalidateRect(_graph_window, NULL, FALSE);
00204 }
00205 
00206 ////////////////////////////////////////////////////////////////////
00207 //     Function: WinStatsPianoRoll::idle
00208 //       Access: Protected, Virtual
00209 //  Description: Called at the end of the draw cycle.
00210 ////////////////////////////////////////////////////////////////////
00211 void WinStatsPianoRoll::
00212 idle() {
00213   if (_labels_changed) {
00214     update_labels();
00215   }
00216 }
00217 
00218 ////////////////////////////////////////////////////////////////////
00219 //     Function: WinStatsPianoRoll::window_proc
00220 //       Access: Protected
00221 //  Description: 
00222 ////////////////////////////////////////////////////////////////////
00223 LONG WinStatsPianoRoll::
00224 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
00225   switch (msg) {
00226   case WM_LBUTTONDOWN:
00227     if (_potential_drag_mode == DM_new_guide_bar) {
00228       set_drag_mode(DM_new_guide_bar);
00229       SetCapture(_graph_window);
00230       return 0;
00231     }
00232     break;
00233 
00234   default:
00235     break;
00236   }
00237 
00238   return WinStatsGraph::window_proc(hwnd, msg, wparam, lparam);
00239 }
00240 
00241 ////////////////////////////////////////////////////////////////////
00242 //     Function: WinStatsPianoRoll::graph_window_proc
00243 //       Access: Protected
00244 //  Description: 
00245 ////////////////////////////////////////////////////////////////////
00246 LONG WinStatsPianoRoll::
00247 graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
00248   switch (msg) {
00249   case WM_LBUTTONDOWN:
00250     if (_potential_drag_mode == DM_none) {
00251       set_drag_mode(DM_scale);
00252       PN_int16 x = LOWORD(lparam);
00253       _drag_scale_start = pixel_to_height(x);
00254       SetCapture(_graph_window);
00255       return 0;
00256 
00257     } else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) {
00258       set_drag_mode(DM_guide_bar);
00259       PN_int16 x = LOWORD(lparam);
00260       _drag_start_x = x;
00261       SetCapture(_graph_window);
00262       return 0;
00263     }
00264     break;
00265 
00266   case WM_MOUSEMOVE: 
00267     if (_drag_mode == DM_none && _potential_drag_mode == DM_none) {
00268       // When the mouse is over a color bar, highlight it.
00269       PN_int16 x = LOWORD(lparam);
00270       PN_int16 y = HIWORD(lparam);
00271       _label_stack.highlight_label(get_collector_under_pixel(x, y));
00272 
00273       // Now we want to get a WM_MOUSELEAVE when the mouse leaves the
00274       // graph window.
00275       TRACKMOUSEEVENT tme = {
00276         sizeof(TRACKMOUSEEVENT),
00277         TME_LEAVE,
00278         _graph_window,
00279         0
00280       };
00281       TrackMouseEvent(&tme);
00282 
00283     } else {
00284       // If the mouse is in some drag mode, stop highlighting.
00285       _label_stack.highlight_label(-1);
00286     }
00287 
00288     if (_drag_mode == DM_scale) {
00289       PN_int16 x = LOWORD(lparam);
00290       double ratio = (double)x / (double)get_xsize();
00291       if (ratio > 0.0f) {
00292         set_horizontal_scale(_drag_scale_start / ratio);
00293       }
00294       return 0;
00295 
00296     } else if (_drag_mode == DM_new_guide_bar) {
00297       // We haven't created the new guide bar yet; we won't until the
00298       // mouse comes within the graph's region.
00299       PN_int16 x = LOWORD(lparam);
00300       if (x >= 0 && x < get_xsize()) {
00301         set_drag_mode(DM_guide_bar);
00302         _drag_guide_bar = add_user_guide_bar(pixel_to_height(x));
00303         return 0;
00304       }
00305 
00306     } else if (_drag_mode == DM_guide_bar) {
00307       PN_int16 x = LOWORD(lparam);
00308       move_user_guide_bar(_drag_guide_bar, pixel_to_height(x));
00309       return 0;
00310     }
00311     break;
00312 
00313   case WM_MOUSELEAVE:
00314     // When the mouse leaves the graph, stop highlighting.
00315     _label_stack.highlight_label(-1);
00316     break;
00317 
00318   case WM_LBUTTONUP:
00319     if (_drag_mode == DM_scale) {
00320       set_drag_mode(DM_none);
00321       ReleaseCapture();
00322       return 0;
00323 
00324     } else if (_drag_mode == DM_guide_bar) {
00325       PN_int16 x = LOWORD(lparam);
00326       if (x < 0 || x >= get_xsize()) {
00327         remove_user_guide_bar(_drag_guide_bar);
00328       } else {
00329         move_user_guide_bar(_drag_guide_bar, pixel_to_height(x));
00330       }
00331       set_drag_mode(DM_none);
00332       ReleaseCapture();
00333       return 0;
00334     }
00335     break;
00336 
00337   case WM_LBUTTONDBLCLK:
00338     {
00339       // Double-clicking on a color bar in the graph is the same as
00340       // double-clicking on the corresponding label.
00341       PN_int16 x = LOWORD(lparam);
00342       PN_int16 y = HIWORD(lparam);
00343       clicked_label(get_collector_under_pixel(x, y));
00344       return 0;
00345     }
00346     break;
00347 
00348   default:
00349     break;
00350   }
00351 
00352   return WinStatsGraph::graph_window_proc(hwnd, msg, wparam, lparam);
00353 }
00354 
00355 ////////////////////////////////////////////////////////////////////
00356 //     Function: WinStatsPianoRoll::additional_window_paint
00357 //       Access: Protected, Virtual
00358 //  Description: This is called during the servicing of WM_PAINT; it
00359 //               gives a derived class opportunity to do some further
00360 //               painting into the window (the outer window, not the
00361 //               graph window).
00362 ////////////////////////////////////////////////////////////////////
00363 void WinStatsPianoRoll::
00364 additional_window_paint(HDC hdc) {
00365   // Draw in the labels for the guide bars.
00366   HFONT hfnt = (HFONT)GetStockObject(ANSI_VAR_FONT); 
00367   SelectObject(hdc, hfnt);
00368   SetTextAlign(hdc, TA_LEFT | TA_BOTTOM);
00369   SetBkMode(hdc, TRANSPARENT);
00370 
00371   int y = _top_margin;
00372 
00373   int i;
00374   int num_guide_bars = get_num_guide_bars();
00375   for (i = 0; i < num_guide_bars; i++) {
00376     draw_guide_label(hdc, y, get_guide_bar(i));
00377   }
00378 
00379   int num_user_guide_bars = get_num_user_guide_bars();
00380   for (i = 0; i < num_user_guide_bars; i++) {
00381     draw_guide_label(hdc, y, get_user_guide_bar(i));
00382   }
00383 }
00384 
00385 ////////////////////////////////////////////////////////////////////
00386 //     Function: WinStatsPianoRoll::additional_graph_window_paint
00387 //       Access: Protected, Virtual
00388 //  Description: This is called during the servicing of WM_PAINT; it
00389 //               gives a derived class opportunity to do some further
00390 //               painting into the window (the outer window, not the
00391 //               graph window).
00392 ////////////////////////////////////////////////////////////////////
00393 void WinStatsPianoRoll::
00394 additional_graph_window_paint(HDC hdc) {
00395   int num_user_guide_bars = get_num_user_guide_bars();
00396   for (int i = 0; i < num_user_guide_bars; i++) {
00397     draw_guide_bar(hdc, get_user_guide_bar(i));
00398   }
00399 }
00400 
00401 ////////////////////////////////////////////////////////////////////
00402 //     Function: WinStatsPianoRoll::consider_drag_start
00403 //       Access: Protected, Virtual
00404 //  Description: Based on the mouse position within the window's
00405 //               client area, look for draggable things the mouse
00406 //               might be hovering over and return the apprioprate
00407 //               DragMode enum or DM_none if nothing is indicated.
00408 ////////////////////////////////////////////////////////////////////
00409 WinStatsGraph::DragMode WinStatsPianoRoll::
00410 consider_drag_start(int mouse_x, int mouse_y, int width, int height) {
00411   if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) {
00412     if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) {
00413       // See if the mouse is over a user-defined guide bar.
00414       int x = mouse_x - _graph_left;
00415       double from_height = pixel_to_height(x - 2);
00416       double to_height = pixel_to_height(x + 2);
00417       _drag_guide_bar = find_user_guide_bar(from_height, to_height);
00418       if (_drag_guide_bar >= 0) {
00419         return DM_guide_bar;
00420       }
00421 
00422     } else if (mouse_x < _left_margin - 2 ||
00423                mouse_x > width - _right_margin + 2) {
00424       // The mouse is left or right of the graph; maybe create a new
00425       // guide bar.
00426       return DM_new_guide_bar;
00427     }
00428   }
00429 
00430   return WinStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height);
00431 }
00432 
00433 ////////////////////////////////////////////////////////////////////
00434 //     Function: WinStatsPianoRoll::get_collector_under_pixel
00435 //       Access: Private
00436 //  Description: Returns the collector index associated with the
00437 //               indicated vertical row, or -1.
00438 ////////////////////////////////////////////////////////////////////
00439 int WinStatsPianoRoll::
00440 get_collector_under_pixel(int xpoint, int ypoint) {
00441   if (_label_stack.get_num_labels() == 0) {
00442     return -1;
00443   }
00444 
00445   // Assume all of the labels are the same height.
00446   int height = _label_stack.get_label_height(0);
00447   int row = (get_ysize() - ypoint) / height;
00448   if (row >= 0 && row < _label_stack.get_num_labels()) {
00449     return _label_stack.get_label_collector_index(row);
00450   } else {
00451     return -1;
00452   }
00453 }
00454 
00455 ////////////////////////////////////////////////////////////////////
00456 //     Function: WinStatsPianoRoll::update_labels
00457 //       Access: Private
00458 //  Description: Resets the list of labels.
00459 ////////////////////////////////////////////////////////////////////
00460 void WinStatsPianoRoll::
00461 update_labels() {
00462   _label_stack.clear_labels();
00463   for (int i = 0; i < get_num_labels(); i++) {
00464     int label_index = 
00465       _label_stack.add_label(WinStatsGraph::_monitor, this,
00466                              _thread_index,
00467                              get_label_collector(i), true);
00468   }
00469   _labels_changed = false;
00470 }
00471 
00472 ////////////////////////////////////////////////////////////////////
00473 //     Function: WinStatsPianoRoll::draw_guide_bar
00474 //       Access: Private
00475 //  Description: Draws the line for the indicated guide bar on the
00476 //               graph.
00477 ////////////////////////////////////////////////////////////////////
00478 void WinStatsPianoRoll::
00479 draw_guide_bar(HDC hdc, const PStatGraph::GuideBar &bar) {
00480   int x = height_to_pixel(bar._height);
00481 
00482   if (x > 0 && x < get_xsize() - 1) {
00483     // Only draw it if it's not too close to either edge.
00484     switch (bar._style) {
00485     case GBS_target:
00486       SelectObject(hdc, _light_pen);
00487       break;
00488 
00489     case GBS_user:
00490       SelectObject(hdc, _user_guide_bar_pen);
00491       break;
00492       
00493     case GBS_normal:
00494       SelectObject(hdc, _dark_pen);
00495       break;
00496     }
00497     MoveToEx(hdc, x, 0, NULL);
00498     LineTo(hdc, x, get_ysize());
00499   }
00500 }
00501 
00502 ////////////////////////////////////////////////////////////////////
00503 //     Function: WinStatsPianoRoll::draw_guide_label
00504 //       Access: Private
00505 //  Description: Draws the text for the indicated guide bar label at
00506 //               the top of the graph.
00507 ////////////////////////////////////////////////////////////////////
00508 void WinStatsPianoRoll::
00509 draw_guide_label(HDC hdc, int y, const PStatGraph::GuideBar &bar) {
00510   switch (bar._style) {
00511   case GBS_target:
00512     SetTextColor(hdc, _light_color);
00513     break;
00514     
00515   case GBS_user:
00516     SetTextColor(hdc, _user_guide_bar_color);
00517     break;
00518     
00519   case GBS_normal:
00520     SetTextColor(hdc, _dark_color);
00521     break;
00522   }
00523 
00524   int x = height_to_pixel(bar._height);
00525   const string &label = bar._label;
00526   SIZE size;
00527   GetTextExtentPoint32(hdc, label.data(), label.length(), &size);
00528 
00529   if (bar._style != GBS_user) {
00530     double from_height = pixel_to_height(x - size.cx);
00531     double to_height = pixel_to_height(x + size.cx);
00532     if (find_user_guide_bar(from_height, to_height) >= 0) {
00533       // Omit the label: there's a user-defined guide bar in the same space.
00534       return;
00535     }
00536   }
00537 
00538   int this_x = _graph_left + x - size.cx / 2;
00539   if (x >= 0 && x < get_xsize()) {
00540     TextOut(hdc, this_x, y,
00541             label.data(), label.length()); 
00542   }
00543 }
00544 
00545 ////////////////////////////////////////////////////////////////////
00546 //     Function: WinStatsPianoRoll::create_window
00547 //       Access: Private
00548 //  Description: Creates the window for this strip chart.
00549 ////////////////////////////////////////////////////////////////////
00550 void WinStatsPianoRoll::
00551 create_window() {
00552   if (_window) {
00553     return;
00554   }
00555 
00556   HINSTANCE application = GetModuleHandle(NULL);
00557   register_window_class(application);
00558 
00559   const PStatClientData *client_data = 
00560     WinStatsGraph::_monitor->get_client_data();
00561   string thread_name = client_data->get_thread_name(_thread_index);
00562   string window_title = thread_name + " thread piano roll";
00563 
00564 
00565   RECT win_rect = { 
00566     0, 0,
00567     _left_margin + get_xsize() + _right_margin, 
00568     _top_margin + get_ysize() + _bottom_margin
00569   };  
00570   
00571   // compute window size based on desired client area size
00572   AdjustWindowRect(&win_rect, graph_window_style, FALSE);
00573 
00574   _window = 
00575     CreateWindow(_window_class_name, window_title.c_str(), graph_window_style,
00576                  CW_USEDEFAULT, CW_USEDEFAULT,
00577                  win_rect.right - win_rect.left,
00578                  win_rect.bottom - win_rect.top,
00579                  WinStatsGraph::_monitor->get_window(), NULL, application, 0);
00580   if (!_window) {
00581     nout << "Could not create PianoRoll window!\n";
00582     exit(1);
00583   }
00584 
00585   SetWindowLongPtr(_window, 0, (LONG_PTR)this);
00586   setup_label_stack();
00587 
00588   // Ensure that the window is on top of the stack.
00589   SetWindowPos(_window, HWND_TOP, 0, 0, 0, 0, 
00590                SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
00591 }
00592 
00593 ////////////////////////////////////////////////////////////////////
00594 //     Function: WinStatsPianoRoll::register_window_class
00595 //       Access: Private, Static
00596 //  Description: Registers the window class for the pianoRoll window, if
00597 //               it has not already been registered.
00598 ////////////////////////////////////////////////////////////////////
00599 void WinStatsPianoRoll::
00600 register_window_class(HINSTANCE application) {
00601   if (_window_class_registered) {
00602     return;
00603   }
00604 
00605   WNDCLASS wc;
00606 
00607   ZeroMemory(&wc, sizeof(WNDCLASS));
00608   wc.style = 0;
00609   wc.lpfnWndProc = (WNDPROC)static_window_proc;
00610   wc.hInstance = application;
00611   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
00612   wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
00613   wc.lpszMenuName = NULL;
00614   wc.lpszClassName = _window_class_name;
00615 
00616   // Reserve space to associate the this pointer with the window.
00617   wc.cbWndExtra = sizeof(WinStatsPianoRoll *);
00618   
00619   if (!RegisterClass(&wc)) {
00620     nout << "Could not register PianoRoll window class!\n";
00621     exit(1);
00622   }
00623 
00624   _window_class_registered = true;
00625 }
00626 
00627 ////////////////////////////////////////////////////////////////////
00628 //     Function: WinStatsPianoRoll::static_window_proc
00629 //       Access: Private, Static
00630 //  Description: 
00631 ////////////////////////////////////////////////////////////////////
00632 LONG WINAPI WinStatsPianoRoll::
00633 static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
00634   WinStatsPianoRoll *self = (WinStatsPianoRoll *)GetWindowLongPtr(hwnd, 0);
00635   if (self != (WinStatsPianoRoll *)NULL && self->_window == hwnd) {
00636     return self->window_proc(hwnd, msg, wparam, lparam);
00637   } else {
00638     return DefWindowProc(hwnd, msg, wparam, lparam);
00639   }
00640 }
 All Classes Functions Variables Enumerations