Panda3D
 All Classes Functions Variables Enumerations
winStatsStripChart.cxx
1 // Filename: winStatsStripChart.cxx
2 // Created by: drose (03Dec03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "winStatsStripChart.h"
16 #include "winStatsMonitor.h"
17 #include "pStatCollectorDef.h"
18 #include "numeric_types.h"
19 
20 static const int default_strip_chart_width = 400;
21 static const int default_strip_chart_height = 100;
22 
23 // Surely we aren't expected to hardcode the size of a normal
24 // checkbox. But Windows seems to require this data to be passed to
25 // CreateWindow(), so what else can I do?
26 size_t WinStatsStripChart::_check_box_height = 13;
27 size_t WinStatsStripChart::_check_box_width = 13;
28 
29 bool WinStatsStripChart::_window_class_registered = false;
30 const char * const WinStatsStripChart::_window_class_name = "strip";
31 
32 ////////////////////////////////////////////////////////////////////
33 // Function: WinStatsStripChart::Constructor
34 // Access: Public
35 // Description:
36 ////////////////////////////////////////////////////////////////////
37 WinStatsStripChart::
38 WinStatsStripChart(WinStatsMonitor *monitor, int thread_index,
39  int collector_index, bool show_level) :
40  PStatStripChart(monitor,
41  show_level ? monitor->get_level_view(collector_index, thread_index) : monitor->get_view(thread_index),
42  thread_index,
43  collector_index,
44  default_strip_chart_width,
45  default_strip_chart_height),
46  WinStatsGraph(monitor)
47 {
48  _brush_origin = 0;
49 
50  _left_margin = 96;
51  _right_margin = 32;
52  _top_margin = 16;
53  _bottom_margin = 8;
54 
55  if (show_level) {
56  // If it's a level-type graph, show the appropriate units.
57  if (_unit_name.empty()) {
58  set_guide_bar_units(GBU_named);
59  } else {
60  set_guide_bar_units(GBU_named | GBU_show_units);
61  }
62 
63  } else {
64  // If it's a time-type graph, show the ms/Hz units.
65  set_guide_bar_units(get_guide_bar_units() | GBU_show_units);
66  }
67 
68  _smooth_check_box = 0;
69 
70  create_window();
71  clear_region();
72 }
73 
74 ////////////////////////////////////////////////////////////////////
75 // Function: WinStatsStripChart::Destructor
76 // Access: Public, Virtual
77 // Description:
78 ////////////////////////////////////////////////////////////////////
79 WinStatsStripChart::
80 ~WinStatsStripChart() {
81 }
82 
83 ////////////////////////////////////////////////////////////////////
84 // Function: WinStatsStripChart::new_collector
85 // Access: Public, Virtual
86 // Description: Called whenever a new Collector definition is
87 // received from the client.
88 ////////////////////////////////////////////////////////////////////
90 new_collector(int collector_index) {
91  WinStatsGraph::new_collector(collector_index);
92 }
93 
94 ////////////////////////////////////////////////////////////////////
95 // Function: WinStatsStripChart::new_data
96 // Access: Public, Virtual
97 // Description: Called as each frame's data is made available. There
98 // is no gurantee the frames will arrive in order, or
99 // that all of them will arrive at all. The monitor
100 // should be prepared to accept frames received
101 // out-of-order or missing.
102 ////////////////////////////////////////////////////////////////////
104 new_data(int thread_index, int frame_number) {
105  if (is_title_unknown()) {
106  string window_title = get_title_text();
107  if (!is_title_unknown()) {
108  SetWindowText(_window, window_title.c_str());
109  }
110  }
111 
112  if (!_pause) {
113  update();
114 
115  string text = format_number(get_average_net_value(), get_guide_bar_units(), get_guide_bar_unit_name());
116  if (_net_value_text != text) {
117  _net_value_text = text;
118  RECT rect;
119  GetClientRect(_window, &rect);
120  rect.bottom = _top_margin;
121  InvalidateRect(_window, &rect, TRUE);
122  }
123  }
124 }
125 
126 ////////////////////////////////////////////////////////////////////
127 // Function: WinStatsStripChart::force_redraw
128 // Access: Public, Virtual
129 // Description: Called when it is necessary to redraw the entire graph.
130 ////////////////////////////////////////////////////////////////////
133  PStatStripChart::force_redraw();
134 }
135 
136 ////////////////////////////////////////////////////////////////////
137 // Function: WinStatsStripChart::changed_graph_size
138 // Access: Public, Virtual
139 // Description: Called when the user has resized the window, forcing
140 // a resize of the graph.
141 ////////////////////////////////////////////////////////////////////
143 changed_graph_size(int graph_xsize, int graph_ysize) {
144  PStatStripChart::changed_size(graph_xsize, graph_ysize);
145 }
146 
147 ////////////////////////////////////////////////////////////////////
148 // Function: WinStatsStripChart::set_time_units
149 // Access: Public, Virtual
150 // Description: Called when the user selects a new time units from
151 // the monitor pulldown menu, this should adjust the
152 // units for the graph to the indicated mask if it is a
153 // time-based graph.
154 ////////////////////////////////////////////////////////////////////
156 set_time_units(int unit_mask) {
157  int old_unit_mask = get_guide_bar_units();
158  if ((old_unit_mask & (GBU_hz | GBU_ms)) != 0) {
159  unit_mask = unit_mask & (GBU_hz | GBU_ms);
160  unit_mask |= (old_unit_mask & GBU_show_units);
161  set_guide_bar_units(unit_mask);
162 
163  RECT rect;
164  GetClientRect(_window, &rect);
165  rect.left = _right_margin;
166  InvalidateRect(_window, &rect, TRUE);
167 
168  GetClientRect(_window, &rect);
169  rect.bottom = _top_margin;
170  InvalidateRect(_window, &rect, TRUE);
171  }
172 }
173 
174 ////////////////////////////////////////////////////////////////////
175 // Function: WinStatsStripChart::set_scroll_speed
176 // Access: Public
177 // Description: Called when the user selects a new scroll speed from
178 // the monitor pulldown menu, this should adjust the
179 // speed for the graph to the indicated value.
180 ////////////////////////////////////////////////////////////////////
182 set_scroll_speed(double scroll_speed) {
183  // The speed factor indicates chart widths per minute.
184  if (scroll_speed != 0.0f) {
185  set_horizontal_scale(60.0f / scroll_speed);
186  }
187 }
188 
189 ////////////////////////////////////////////////////////////////////
190 // Function: WinStatsStripChart::clicked_label
191 // Access: Public, Virtual
192 // Description: Called when the user single-clicks on a label.
193 ////////////////////////////////////////////////////////////////////
195 clicked_label(int collector_index) {
196  if (collector_index < 0) {
197  // Clicking on whitespace in the graph is the same as clicking on
198  // the top label.
199  collector_index = get_collector_index();
200  }
201 
202  if (collector_index == get_collector_index() && collector_index != 0) {
203  // Clicking on the top label means to go up to the parent level.
204  const PStatClientData *client_data =
205  WinStatsGraph::_monitor->get_client_data();
206  if (client_data->has_collector(collector_index)) {
207  const PStatCollectorDef &def =
208  client_data->get_collector_def(collector_index);
209  if (def._parent_index == 0 && get_view().get_show_level()) {
210  // Unless the parent is "Frame", and we're not a time collector.
211  } else {
212  set_collector_index(def._parent_index);
213  }
214  }
215 
216  } else {
217  // Clicking on any other label means to focus on that.
218  set_collector_index(collector_index);
219  }
220 }
221 
222 ////////////////////////////////////////////////////////////////////
223 // Function: WinStatsStripChart::set_vertical_scale
224 // Access: Public
225 // Description: Changes the value the height of the vertical axis
226 // represents. This may force a redraw.
227 ////////////////////////////////////////////////////////////////////
229 set_vertical_scale(double value_height) {
231 
232  RECT rect;
233  GetClientRect(_window, &rect);
234  rect.left = _right_margin;
235  InvalidateRect(_window, &rect, TRUE);
236 }
237 
238 ////////////////////////////////////////////////////////////////////
239 // Function: WinStatsStripChart::update_labels
240 // Access: Protected, Virtual
241 // Description: Resets the list of labels.
242 ////////////////////////////////////////////////////////////////////
243 void WinStatsStripChart::
244 update_labels() {
245  PStatStripChart::update_labels();
246 
247  _label_stack.clear_labels();
248  for (int i = 0; i < get_num_labels(); i++) {
249  _label_stack.add_label(WinStatsGraph::_monitor, this, _thread_index,
250  get_label_collector(i), false);
251  }
252  _labels_changed = false;
253 }
254 
255 ////////////////////////////////////////////////////////////////////
256 // Function: WinStatsStripChart::clear_region
257 // Access: Protected, Virtual
258 // Description: Erases the chart area.
259 ////////////////////////////////////////////////////////////////////
260 void WinStatsStripChart::
261 clear_region() {
262  RECT rect = { 0, 0, get_xsize(), get_ysize() };
263  FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
264 }
265 
266 ////////////////////////////////////////////////////////////////////
267 // Function: WinStatsStripChart::copy_region
268 // Access: Protected, Virtual
269 // Description: Should be overridden by the user class to copy a
270 // region of the chart from one part of the chart to
271 // another. This is used to implement scrolling.
272 ////////////////////////////////////////////////////////////////////
273 void WinStatsStripChart::
274 copy_region(int start_x, int end_x, int dest_x) {
275  BitBlt(_bitmap_dc, dest_x, 0,
276  end_x - start_x, get_ysize(),
277  _bitmap_dc, start_x, 0,
278  SRCCOPY);
279 
280  // Also shift the brush origin over, so we still get proper
281  // dithering.
282  _brush_origin += (dest_x - start_x);
283  SetBrushOrgEx(_bitmap_dc, _brush_origin, 0, NULL);
284 
285  RECT rect = {
286  dest_x, 0, dest_x + end_x - start_x, get_ysize()
287  };
288  InvalidateRect(_graph_window, &rect, FALSE);
289 }
290 
291 ////////////////////////////////////////////////////////////////////
292 // Function: WinStatsStripChart::draw_slice
293 // Access: Protected, Virtual
294 // Description: Draws a single vertical slice of the strip chart, at
295 // the given pixel position, and corresponding to the
296 // indicated level data.
297 ////////////////////////////////////////////////////////////////////
298 void WinStatsStripChart::
299 draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) {
300  // Start by clearing the band first.
301  RECT rect = { x, 0, x + w, get_ysize() };
302  FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
303 
304  double overall_time = 0.0;
305  int y = get_ysize();
306 
307  FrameData::const_iterator fi;
308  for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
309  const ColorData &cd = (*fi);
310  overall_time += cd._net_value;
311  HBRUSH brush = get_collector_brush(cd._collector_index);
312 
313  if (overall_time > get_vertical_scale()) {
314  // Off the top. Go ahead and clamp it by hand, in case it's so
315  // far off the top we'd overflow the 16-bit pixel value.
316  rect.top = 0;
317  rect.bottom = y;
318  FillRect(_bitmap_dc, &rect, brush);
319  // And we can consider ourselves done now.
320  return;
321  }
322 
323  int top_y = height_to_pixel(overall_time);
324  rect.top = top_y;
325  rect.bottom = y;
326  FillRect(_bitmap_dc, &rect, brush);
327  y = top_y;
328  }
329 }
330 
331 ////////////////////////////////////////////////////////////////////
332 // Function: WinStatsStripChart::draw_empty
333 // Access: Protected, Virtual
334 // Description: Draws a single vertical slice of background color.
335 ////////////////////////////////////////////////////////////////////
336 void WinStatsStripChart::
337 draw_empty(int x, int w) {
338  RECT rect = { x, 0, x + w, get_ysize() };
339  FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
340 }
341 
342 ////////////////////////////////////////////////////////////////////
343 // Function: WinStatsStripChart::draw_cursor
344 // Access: Protected, Virtual
345 // Description: Draws a single vertical slice of foreground color.
346 ////////////////////////////////////////////////////////////////////
347 void WinStatsStripChart::
348 draw_cursor(int x) {
349  RECT rect = { x, 0, x + 1, get_ysize() };
350  FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
351 }
352 
353 ////////////////////////////////////////////////////////////////////
354 // Function: WinStatsStripChart::end_draw
355 // Access: Protected, Virtual
356 // Description: Should be overridden by the user class. This hook
357 // will be called after drawing a series of color bars
358 // in the strip chart; it gives the pixel range that
359 // was just redrawn.
360 ////////////////////////////////////////////////////////////////////
361 void WinStatsStripChart::
362 end_draw(int from_x, int to_x) {
363  // Draw in the guide bars.
364  int num_guide_bars = get_num_guide_bars();
365  for (int i = 0; i < num_guide_bars; i++) {
366  draw_guide_bar(_bitmap_dc, from_x, to_x, get_guide_bar(i));
367  }
368 
369  RECT rect = {
370  from_x, 0, to_x + 1, get_ysize()
371  };
372  InvalidateRect(_graph_window, &rect, FALSE);
373 }
374 
375 ////////////////////////////////////////////////////////////////////
376 // Function: WinStatsStripChart::window_proc
377 // Access: Protected
378 // Description:
379 ////////////////////////////////////////////////////////////////////
380 LONG WinStatsStripChart::
381 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
382  switch (msg) {
383  case WM_LBUTTONDOWN:
384  if (_potential_drag_mode == DM_new_guide_bar) {
385  set_drag_mode(DM_new_guide_bar);
386  SetCapture(_graph_window);
387  return 0;
388  }
389  break;
390 
391  case WM_COMMAND:
392  switch (LOWORD(wparam)) {
393  case BN_CLICKED:
394  if ((HWND)lparam == _smooth_check_box) {
395  int result = SendMessage(_smooth_check_box, BM_GETCHECK, 0, 0);
396  set_average_mode(result == BST_CHECKED);
397  return 0;
398  }
399  break;
400  }
401  break;
402 
403  default:
404  break;
405  }
406 
407  return WinStatsGraph::window_proc(hwnd, msg, wparam, lparam);
408 }
409 
410 ////////////////////////////////////////////////////////////////////
411 // Function: WinStatsStripChart::graph_window_proc
412 // Access: Protected
413 // Description:
414 ////////////////////////////////////////////////////////////////////
415 LONG WinStatsStripChart::
416 graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
417  switch (msg) {
418  case WM_LBUTTONDOWN:
419  if (_potential_drag_mode == DM_none) {
420  set_drag_mode(DM_scale);
421  PN_int16 y = HIWORD(lparam);
422  _drag_scale_start = pixel_to_height(y);
423  SetCapture(_graph_window);
424  return 0;
425 
426  } else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) {
427  set_drag_mode(DM_guide_bar);
428  PN_int16 y = HIWORD(lparam);
429  _drag_start_y = y;
430  SetCapture(_graph_window);
431  return 0;
432  }
433  break;
434 
435  case WM_MOUSEMOVE:
436  if (_drag_mode == DM_none && _potential_drag_mode == DM_none) {
437  // When the mouse is over a color bar, highlight it.
438  PN_int16 x = LOWORD(lparam);
439  PN_int16 y = HIWORD(lparam);
440  _label_stack.highlight_label(get_collector_under_pixel(x, y));
441 
442  // Now we want to get a WM_MOUSELEAVE when the mouse leaves the
443  // graph window.
444  TRACKMOUSEEVENT tme = {
445  sizeof(TRACKMOUSEEVENT),
446  TME_LEAVE,
447  _graph_window,
448  0
449  };
450  TrackMouseEvent(&tme);
451 
452  } else {
453  // If the mouse is in some drag mode, stop highlighting.
454  _label_stack.highlight_label(-1);
455  }
456 
457  if (_drag_mode == DM_scale) {
458  PN_int16 y = HIWORD(lparam);
459  double ratio = 1.0f - ((double)y / (double)get_ysize());
460  if (ratio > 0.0f) {
461  set_vertical_scale(_drag_scale_start / ratio);
462  }
463  return 0;
464 
465  } else if (_drag_mode == DM_new_guide_bar) {
466  // We haven't created the new guide bar yet; we won't until the
467  // mouse comes within the graph's region.
468  PN_int16 y = HIWORD(lparam);
469  if (y >= 0 && y < get_ysize()) {
470  set_drag_mode(DM_guide_bar);
471  _drag_guide_bar = add_user_guide_bar(pixel_to_height(y));
472  return 0;
473  }
474 
475  } else if (_drag_mode == DM_guide_bar) {
476  PN_int16 y = HIWORD(lparam);
477  move_user_guide_bar(_drag_guide_bar, pixel_to_height(y));
478  return 0;
479  }
480  break;
481 
482  case WM_MOUSELEAVE:
483  // When the mouse leaves the graph, stop highlighting.
484  _label_stack.highlight_label(-1);
485  break;
486 
487  case WM_LBUTTONUP:
488  if (_drag_mode == DM_scale) {
489  set_drag_mode(DM_none);
490  ReleaseCapture();
491  return 0;
492 
493  } else if (_drag_mode == DM_guide_bar) {
494  PN_int16 y = HIWORD(lparam);
495  if (y < 0 || y >= get_ysize()) {
496  remove_user_guide_bar(_drag_guide_bar);
497  } else {
498  move_user_guide_bar(_drag_guide_bar, pixel_to_height(y));
499  }
500  set_drag_mode(DM_none);
501  ReleaseCapture();
502  return 0;
503  }
504  break;
505 
506  case WM_LBUTTONDBLCLK:
507  {
508  // Double-clicking on a color bar in the graph is the same as
509  // double-clicking on the corresponding label.
510  PN_int16 x = LOWORD(lparam);
511  PN_int16 y = HIWORD(lparam);
513  return 0;
514  }
515  break;
516 
517  default:
518  break;
519  }
520 
521  return WinStatsGraph::graph_window_proc(hwnd, msg, wparam, lparam);
522 }
523 
524 ////////////////////////////////////////////////////////////////////
525 // Function: WinStatsStripChart::additional_window_paint
526 // Access: Protected, Virtual
527 // Description: This is called during the servicing of WM_PAINT; it
528 // gives a derived class opportunity to do some further
529 // painting into the window (the outer window, not the
530 // graph window).
531 ////////////////////////////////////////////////////////////////////
532 void WinStatsStripChart::
533 additional_window_paint(HDC hdc) {
534  // Draw in the labels for the guide bars.
535  HFONT hfnt = (HFONT)GetStockObject(ANSI_VAR_FONT);
536  SelectObject(hdc, hfnt);
537  SetTextAlign(hdc, TA_LEFT | TA_TOP);
538  SetBkMode(hdc, TRANSPARENT);
539 
540  RECT rect;
541  GetClientRect(_window, &rect);
542  int x = rect.right - _right_margin + 2;
543  int last_y = -100;
544 
545  int i;
546  int num_guide_bars = get_num_guide_bars();
547  for (i = 0; i < num_guide_bars; i++) {
548  last_y = draw_guide_label(hdc, x, get_guide_bar(i), last_y);
549  }
550 
551  GuideBar top_value = make_guide_bar(get_vertical_scale());
552  draw_guide_label(hdc, x, top_value, last_y);
553 
554  last_y = -100;
555  int num_user_guide_bars = get_num_user_guide_bars();
556  for (i = 0; i < num_user_guide_bars; i++) {
557  last_y = draw_guide_label(hdc, x, get_user_guide_bar(i), last_y);
558  }
559 
560  // Now draw the "net value" label at the top.
561  SetTextAlign(hdc, TA_RIGHT | TA_BOTTOM);
562  SetTextColor(hdc, RGB(0, 0, 0));
563  TextOut(hdc, rect.right - _right_margin, _top_margin,
564  _net_value_text.data(), _net_value_text.length());
565 
566  // Also draw the "Smooth" label on the check box. This isn't part
567  // of the check box itself, because doing that doesn't use the right
568  // font! Surely this isn't the correct Windows(tm) way to do this
569  // sort of thing, but I don't know any better for now.
570  SetTextAlign(hdc, TA_LEFT | TA_BOTTOM);
571  TextOut(hdc, _left_margin + _check_box_width + 2, _top_margin, "Smooth", 6);
572 }
573 
574 ////////////////////////////////////////////////////////////////////
575 // Function: WinStatsStripChart::additional_graph_window_paint
576 // Access: Protected, Virtual
577 // Description: This is called during the servicing of WM_PAINT; it
578 // gives a derived class opportunity to do some further
579 // painting into the window (the outer window, not the
580 // graph window).
581 ////////////////////////////////////////////////////////////////////
582 void WinStatsStripChart::
583 additional_graph_window_paint(HDC hdc) {
584  int num_user_guide_bars = get_num_user_guide_bars();
585  for (int i = 0; i < num_user_guide_bars; i++) {
586  draw_guide_bar(hdc, 0, get_xsize(), get_user_guide_bar(i));
587  }
588 }
589 
590 ////////////////////////////////////////////////////////////////////
591 // Function: WinStatsStripChart::consider_drag_start
592 // Access: Protected, Virtual
593 // Description: Based on the mouse position within the window's
594 // client area, look for draggable things the mouse
595 // might be hovering over and return the apprioprate
596 // DragMode enum or DM_none if nothing is indicated.
597 ////////////////////////////////////////////////////////////////////
598 WinStatsGraph::DragMode WinStatsStripChart::
599 consider_drag_start(int mouse_x, int mouse_y, int width, int height) {
600  if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) {
601  if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) {
602  // See if the mouse is over a user-defined guide bar.
603  int y = mouse_y - _graph_top;
604  double from_height = pixel_to_height(y + 2);
605  double to_height = pixel_to_height(y - 2);
606  _drag_guide_bar = find_user_guide_bar(from_height, to_height);
607  if (_drag_guide_bar >= 0) {
608  return DM_guide_bar;
609  }
610 
611  } else {
612  // The mouse is above or below the graph; maybe create a new
613  // guide bar.
614  return DM_new_guide_bar;
615  }
616  }
617 
618  return WinStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height);
619 }
620 
621 ////////////////////////////////////////////////////////////////////
622 // Function: WinStatsStripChart::set_drag_mode
623 // Access: Protected, Virtual
624 // Description: This should be called whenever the drag mode needs to
625 // change state. It provides hooks for a derived class
626 // to do something special.
627 ////////////////////////////////////////////////////////////////////
628 void WinStatsStripChart::
629 set_drag_mode(WinStatsGraph::DragMode drag_mode) {
630  WinStatsGraph::set_drag_mode(drag_mode);
631 
632  switch (_drag_mode) {
633  case DM_scale:
634  case DM_left_margin:
635  case DM_right_margin:
636  case DM_sizing:
637  // Disable smoothing for these expensive operations.
638  set_average_mode(false);
639  break;
640 
641  default:
642  // Restore smoothing according to the current setting of the check
643  // box.
644  int result = SendMessage(_smooth_check_box, BM_GETCHECK, 0, 0);
645  set_average_mode(result == BST_CHECKED);
646  }
647 }
648 
649 ////////////////////////////////////////////////////////////////////
650 // Function: WinStatsStripChart::move_graph_window
651 // Access: Protected, Virtual
652 // Description: Repositions the graph child window within the parent
653 // window according to the _margin variables.
654 ////////////////////////////////////////////////////////////////////
655 void WinStatsStripChart::
656 move_graph_window(int graph_left, int graph_top, int graph_xsize, int graph_ysize) {
657  WinStatsGraph::move_graph_window(graph_left, graph_top, graph_xsize, graph_ysize);
658  if (_smooth_check_box != 0) {
659  SetWindowPos(_smooth_check_box, 0,
660  _left_margin, _top_margin - _check_box_height - 1,
661  0, 0,
662  SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
663  InvalidateRect(_smooth_check_box, NULL, TRUE);
664  }
665 }
666 
667 ////////////////////////////////////////////////////////////////////
668 // Function: WinStatsStripChart::draw_guide_bar
669 // Access: Private
670 // Description: Draws the line for the indicated guide bar on the
671 // graph.
672 ////////////////////////////////////////////////////////////////////
673 void WinStatsStripChart::
674 draw_guide_bar(HDC hdc, int from_x, int to_x,
675  const PStatGraph::GuideBar &bar) {
676  int y = height_to_pixel(bar._height);
677 
678  if (y > 0) {
679  // Only draw it if it's not too close to the top.
680  switch (bar._style) {
681  case GBS_target:
682  SelectObject(hdc, _light_pen);
683  break;
684 
685  case GBS_user:
686  SelectObject(hdc, _user_guide_bar_pen);
687  break;
688 
689  case GBS_normal:
690  SelectObject(hdc, _dark_pen);
691  break;
692  }
693  MoveToEx(hdc, from_x, y, NULL);
694  LineTo(hdc, to_x + 1, y);
695  }
696 }
697 
698 ////////////////////////////////////////////////////////////////////
699 // Function: WinStatsStripChart::draw_guide_label
700 // Access: Private
701 // Description: Draws the text for the indicated guide bar label to
702 // the right of the graph, unless it would overlap with
703 // the indicated last label, whose top pixel value is
704 // given. Returns the top pixel value of the new label.
705 ////////////////////////////////////////////////////////////////////
706 int WinStatsStripChart::
707 draw_guide_label(HDC hdc, int x, const PStatGraph::GuideBar &bar, int last_y) {
708  switch (bar._style) {
709  case GBS_target:
710  SetTextColor(hdc, _light_color);
711  break;
712 
713  case GBS_user:
714  SetTextColor(hdc, _user_guide_bar_color);
715  break;
716 
717  case GBS_normal:
718  SetTextColor(hdc, _dark_color);
719  break;
720  }
721 
722  int y = height_to_pixel(bar._height);
723  const string &label = bar._label;
724  SIZE size;
725  GetTextExtentPoint32(hdc, label.data(), label.length(), &size);
726 
727  if (bar._style != GBS_user) {
728  double from_height = pixel_to_height(y + size.cy);
729  double to_height = pixel_to_height(y - size.cy);
730  if (find_user_guide_bar(from_height, to_height) >= 0) {
731  // Omit the label: there's a user-defined guide bar in the same space.
732  return last_y;
733  }
734  }
735 
736  int this_y = _graph_top + y - size.cy / 2;
737  if (y >= 0 && y < get_ysize() &&
738  (last_y < this_y || last_y > this_y + size.cy)) {
739  TextOut(hdc, x, this_y,
740  label.data(), label.length());
741  last_y = this_y;
742  }
743 
744  return last_y;
745 }
746 
747 
748 ////////////////////////////////////////////////////////////////////
749 // Function: WinStatsStripChart::create_window
750 // Access: Private
751 // Description: Creates the window for this strip chart.
752 ////////////////////////////////////////////////////////////////////
753 void WinStatsStripChart::
754 create_window() {
755  if (_window) {
756  return;
757  }
758 
759  HINSTANCE application = GetModuleHandle(NULL);
760  register_window_class(application);
761 
762  string window_title = get_title_text();
763 
764  RECT win_rect = {
765  0, 0,
766  _left_margin + get_xsize() + _right_margin,
767  _top_margin + get_ysize() + _bottom_margin
768  };
769 
770  // compute window size based on desired client area size
771  AdjustWindowRect(&win_rect, graph_window_style, FALSE);
772 
773  _window =
774  CreateWindow(_window_class_name, window_title.c_str(), graph_window_style,
775  CW_USEDEFAULT, CW_USEDEFAULT,
776  win_rect.right - win_rect.left,
777  win_rect.bottom - win_rect.top,
778  WinStatsGraph::_monitor->get_window(), NULL, application, 0);
779  if (!_window) {
780  nout << "Could not create StripChart window!\n";
781  exit(1);
782  }
783 
784  SetWindowLongPtr(_window, 0, (LONG_PTR)this);
785  setup_label_stack();
786 
787  _smooth_check_box =
788  CreateWindow("BUTTON", "",
789  WS_CHILD | BS_AUTOCHECKBOX,
790  0, 0, _check_box_width, _check_box_height,
791  _window, NULL, application, 0);
792 
793  // Ensure that the window is on top of the stack.
794  SetWindowPos(_window, HWND_TOP, 0, 0, 0, 0,
795  SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
796 }
797 
798 ////////////////////////////////////////////////////////////////////
799 // Function: WinStatsStripChart::register_window_class
800 // Access: Private, Static
801 // Description: Registers the window class for the stripChart window, if
802 // it has not already been registered.
803 ////////////////////////////////////////////////////////////////////
804 void WinStatsStripChart::
805 register_window_class(HINSTANCE application) {
806  if (_window_class_registered) {
807  return;
808  }
809 
810  WNDCLASS wc;
811 
812  ZeroMemory(&wc, sizeof(WNDCLASS));
813  wc.style = 0;
814  wc.lpfnWndProc = (WNDPROC)static_window_proc;
815  wc.hInstance = application;
816  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
817  wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
818  wc.lpszMenuName = NULL;
819  wc.lpszClassName = _window_class_name;
820 
821  // Reserve space to associate the this pointer with the window.
822  wc.cbWndExtra = sizeof(WinStatsStripChart *);
823 
824  if (!RegisterClass(&wc)) {
825  nout << "Could not register StripChart window class!\n";
826  exit(1);
827  }
828 
829  _window_class_registered = true;
830 }
831 
832 ////////////////////////////////////////////////////////////////////
833 // Function: WinStatsStripChart::static_window_proc
834 // Access: Private, Static
835 // Description:
836 ////////////////////////////////////////////////////////////////////
837 LONG WINAPI WinStatsStripChart::
838 static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
839  WinStatsStripChart *self = (WinStatsStripChart *)GetWindowLongPtr(hwnd, 0);
840  if (self != (WinStatsStripChart *)NULL && self->_window == hwnd) {
841  return self->window_proc(hwnd, msg, wparam, lparam);
842  } else {
843  return DefWindowProc(hwnd, msg, wparam, lparam);
844  }
845 }
void set_horizontal_scale(double time_width)
Changes the amount of time the width of the horizontal axis represents.
int height_to_pixel(double value) const
Converts a value (i.e.
virtual void new_collector(int collector_index)
Called whenever a new Collector definition is received from the client.
double pixel_to_height(int y) const
Converts a vertical pixel offset to a value (a &quot;height&quot; in the strip chart).
bool is_title_unknown() const
Returns true if get_title_text() has never yet returned an answer, false if it has.
A window that draws a strip chart, given a view.
int get_ysize() const
Returns the height of the chart in pixels.
Definition: pStatGraph.I:113
void set_guide_bar_units(int unit_mask)
Sets the units that are displayed for the guide bar labels.
Definition: pStatGraph.I:125
int get_label_collector(int n) const
Returns the collector index associated with the nth label.
Definition: pStatGraph.I:44
void move_user_guide_bar(int n, double height)
Adjusts the height of the nth user-defined guide bar.
Definition: pStatGraph.cxx:137
virtual void set_scroll_speed(double scroll_speed)
Called when the user selects a new scroll speed from the monitor pulldown menu, this should adjust th...
The data associated with a particular client, but not with any one particular frame or thread: the li...
void set_vertical_scale(double value_height)
Changes the value the height of the vertical axis represents.
This is an abstract class that presents the interface for drawing a basic strip-chart, showing the relative value over an interval of time for several different collectors, differentiated by bands of color.
bool has_collector(int index) const
Returns true if the indicated collector has been defined by the client already, false otherwise...
int get_num_guide_bars() const
Returns the number of horizontal guide bars that should be drawn, based on the indicated target frame...
Definition: pStatGraph.cxx:86
virtual void set_time_units(int unit_mask)
Called when the user selects a new time units from the monitor pulldown menu, this should adjust the ...
int get_collector_under_pixel(int xpoint, int ypoint)
Return the collector index associated with the particular band of color at the indicated pixel locati...
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
void update()
Updates the chart with the latest data.
const PStatCollectorDef & get_collector_def(int index) const
Returns the nth collector definition.
This is just an abstract base class to provide a common pointer type for the various kinds of graphs ...
Definition: winStatsGraph.h:32
const GuideBar & get_guide_bar(int n) const
Returns the nth horizontal guide bar.
Definition: pStatGraph.cxx:101
int get_collector_index() const
Returns the particular collector whose data this strip chart reflects.
string get_title_text()
Returns the text suitable for the title label on the top line.
void set_vertical_scale(double value_height)
Changes the value the height of the vertical axis represents.
virtual void changed_graph_size(int graph_xsize, int graph_ysize)
Called when the user has resized the window, forcing a resize of the graph.
int find_user_guide_bar(double from_height, double to_height) const
Returns the index number of the first user guide bar found whose height is within the indicated range...
Definition: pStatGraph.cxx:172
GuideBar get_user_guide_bar(int n) const
Returns the nth user-defined guide bar.
Definition: pStatGraph.cxx:126
virtual void new_data(int thread_index, int frame_number)
Called as each frame&#39;s data is made available.
int get_num_labels() const
Returns the number of labels to be drawn for this chart.
Definition: pStatGraph.I:33
This class represents a connection to a PStatsClient and manages the data exchange with the client...
virtual void new_collector(int collector_index)
Called whenever a new Collector definition is received from the client.
int get_xsize() const
Returns the width of the chart in pixels.
Definition: pStatGraph.I:103
int get_guide_bar_units() const
Returns the units that are displayed for the guide bar labels.
Definition: pStatGraph.I:140
const PStatClientData * get_client_data() const
Returns the client data associated with this monitor.
Definition: pStatMonitor.I:32
const string & get_guide_bar_unit_name() const
Returns the name of the units to be used for the guide bars if the units type is set to GBU_named | G...
Definition: pStatGraph.I:164
void set_average_mode(bool average_mode)
Changes the average_mode flag.
void set_collector_index(int collector_index)
Changes the collector represented by this strip chart.
double get_vertical_scale() const
Returns total value the height of the vertical axis represents.
virtual void clicked_label(int collector_index)
Called when the user single-clicks on a label.
PStatView & get_view() const
Returns the View this chart represents.
int add_user_guide_bar(double height)
Creates a new user guide bar and returns its index number.
Definition: pStatGraph.cxx:148
Defines the details about the Collectors: the name, the suggested color, etc.
static string format_number(double value)
Returns a string representing the value nicely formatted for its range.
Definition: pStatGraph.cxx:184
HWND get_window() const
Returns the window handle to the monitor&#39;s window.
int get_num_user_guide_bars() const
Returns the current number of user-defined guide bars.
Definition: pStatGraph.cxx:116
virtual void force_redraw()
Called when it is necessary to redraw the entire graph.
void remove_user_guide_bar(int n)
Removes the user guide bar with the indicated index number.
Definition: pStatGraph.cxx:160