winStatsLabel.cxx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file winStatsLabel.cxx
  10. * @author drose
  11. * @date 2004-01-07
  12. */
  13. #include "winStatsLabel.h"
  14. #include "winStatsMonitor.h"
  15. #include "winStatsGraph.h"
  16. int WinStatsLabel::_left_margin = 2;
  17. int WinStatsLabel::_right_margin = 2;
  18. int WinStatsLabel::_top_margin = 2;
  19. int WinStatsLabel::_bottom_margin = 2;
  20. bool WinStatsLabel::_window_class_registered = false;
  21. const char * const WinStatsLabel::_window_class_name = "label";
  22. /**
  23. *
  24. */
  25. WinStatsLabel::
  26. WinStatsLabel(WinStatsMonitor *monitor, WinStatsGraph *graph,
  27. int thread_index, int collector_index, bool use_fullname) :
  28. _monitor(monitor),
  29. _graph(graph),
  30. _thread_index(thread_index),
  31. _collector_index(collector_index)
  32. {
  33. _window = 0;
  34. if (use_fullname) {
  35. _text = _monitor->get_client_data()->get_collector_fullname(_collector_index);
  36. } else {
  37. _text = _monitor->get_client_data()->get_collector_name(_collector_index);
  38. }
  39. LRGBColor rgb = _monitor->get_collector_color(_collector_index);
  40. int r = (int)(rgb[0] * 255.0f);
  41. int g = (int)(rgb[1] * 255.0f);
  42. int b = (int)(rgb[2] * 255.0f);
  43. _bg_color = RGB(r, g, b);
  44. _bg_brush = CreateSolidBrush(RGB(r, g, b));
  45. // Should our foreground be black or white?
  46. double bright =
  47. rgb[0] * 0.299 +
  48. rgb[1] * 0.587 +
  49. rgb[2] * 0.114;
  50. if (bright >= 0.5) {
  51. _fg_color = RGB(0, 0, 0);
  52. _highlight_brush = (HBRUSH)GetStockObject(BLACK_BRUSH);
  53. } else {
  54. _fg_color = RGB(255, 255, 255);
  55. _highlight_brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
  56. }
  57. _x = 0;
  58. _y = 0;
  59. _width = 0;
  60. _height = 0;
  61. _ideal_width = 0;
  62. _highlight = false;
  63. _mouse_within = false;
  64. }
  65. /**
  66. *
  67. */
  68. WinStatsLabel::
  69. ~WinStatsLabel() {
  70. if (_window) {
  71. DestroyWindow(_window);
  72. _window = 0;
  73. }
  74. DeleteObject(_bg_brush);
  75. }
  76. /**
  77. * Creates the actual window.
  78. */
  79. void WinStatsLabel::
  80. setup(HWND parent_window) {
  81. if (_window) {
  82. DestroyWindow(_window);
  83. _window = 0;
  84. }
  85. create_window(parent_window);
  86. HDC hdc = GetDC(_window);
  87. HFONT hfnt = (HFONT)GetStockObject(ANSI_VAR_FONT);
  88. SelectObject(hdc, hfnt);
  89. SIZE size;
  90. GetTextExtentPoint32(hdc, _text.data(), _text.length(), &size);
  91. _height = size.cy + _top_margin + _bottom_margin;
  92. _ideal_width = size.cx + _left_margin + _right_margin;
  93. ReleaseDC(_window, hdc);
  94. }
  95. /**
  96. * Sets the position of the label on its parent. The position describes the
  97. * lower-left corner of the rectangle, not the upper-left.
  98. */
  99. void WinStatsLabel::
  100. set_pos(int x, int y, int width) {
  101. _x = x;
  102. _y = y;
  103. _width = width;
  104. SetWindowPos(_window, 0, x, y - _height, _width, _height,
  105. SWP_NOZORDER | SWP_SHOWWINDOW);
  106. }
  107. /**
  108. * Returns the x position of the label on its parent.
  109. */
  110. int WinStatsLabel::
  111. get_x() const {
  112. return _x;
  113. }
  114. /**
  115. * Returns the y position of the label on its parent.
  116. */
  117. int WinStatsLabel::
  118. get_y() const {
  119. return _y;
  120. }
  121. /**
  122. * Returns the width of the label as we requested it.
  123. */
  124. int WinStatsLabel::
  125. get_width() const {
  126. return _width;
  127. }
  128. /**
  129. * Returns the height of the label as we requested it.
  130. */
  131. int WinStatsLabel::
  132. get_height() const {
  133. return _height;
  134. }
  135. /**
  136. * Returns the width the label would really prefer to be.
  137. */
  138. int WinStatsLabel::
  139. get_ideal_width() const {
  140. return _ideal_width;
  141. }
  142. /**
  143. * Returns the collector this label represents.
  144. */
  145. int WinStatsLabel::
  146. get_collector_index() const {
  147. return _collector_index;
  148. }
  149. /**
  150. * Enables or disables the visual highlight for this label.
  151. */
  152. void WinStatsLabel::
  153. set_highlight(bool highlight) {
  154. if (_highlight != highlight) {
  155. _highlight = highlight;
  156. InvalidateRect(_window, nullptr, TRUE);
  157. }
  158. }
  159. /**
  160. * Returns true if the visual highlight for this label is enabled.
  161. */
  162. bool WinStatsLabel::
  163. get_highlight() const {
  164. return _highlight;
  165. }
  166. /**
  167. * Used internally to indicate whether the mouse is within the label's window.
  168. */
  169. void WinStatsLabel::
  170. set_mouse_within(bool mouse_within) {
  171. if (_mouse_within != mouse_within) {
  172. _mouse_within = mouse_within;
  173. InvalidateRect(_window, nullptr, TRUE);
  174. }
  175. }
  176. /**
  177. * Creates the window for this label.
  178. */
  179. void WinStatsLabel::
  180. create_window(HWND parent_window) {
  181. if (_window) {
  182. return;
  183. }
  184. HINSTANCE application = GetModuleHandle(nullptr);
  185. register_window_class(application);
  186. _window =
  187. CreateWindow(_window_class_name, _text.c_str(), WS_CHILD | WS_CLIPSIBLINGS,
  188. 0, 0, 0, 0,
  189. parent_window, nullptr, application, 0);
  190. if (!_window) {
  191. nout << "Could not create Label window!\n";
  192. exit(1);
  193. }
  194. SetWindowLongPtr(_window, 0, (LONG_PTR)this);
  195. }
  196. /**
  197. * Registers the window class for the label window, if it has not already been
  198. * registered.
  199. */
  200. void WinStatsLabel::
  201. register_window_class(HINSTANCE application) {
  202. if (_window_class_registered) {
  203. return;
  204. }
  205. WNDCLASS wc;
  206. ZeroMemory(&wc, sizeof(WNDCLASS));
  207. wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  208. wc.lpfnWndProc = (WNDPROC)static_window_proc;
  209. wc.hInstance = application;
  210. wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
  211. wc.hbrBackground = nullptr;
  212. wc.lpszMenuName = nullptr;
  213. wc.lpszClassName = _window_class_name;
  214. // Reserve space to associate the this pointer with the window.
  215. wc.cbWndExtra = sizeof(WinStatsLabel *);
  216. if (!RegisterClass(&wc)) {
  217. nout << "Could not register Label window class!\n";
  218. exit(1);
  219. }
  220. _window_class_registered = true;
  221. }
  222. /**
  223. *
  224. */
  225. LONG WINAPI WinStatsLabel::
  226. static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
  227. WinStatsLabel *self = (WinStatsLabel *)GetWindowLongPtr(hwnd, 0);
  228. if (self != nullptr && self->_window == hwnd) {
  229. return self->window_proc(hwnd, msg, wparam, lparam);
  230. } else {
  231. return DefWindowProc(hwnd, msg, wparam, lparam);
  232. }
  233. }
  234. /**
  235. *
  236. */
  237. LONG WinStatsLabel::
  238. window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
  239. switch (msg) {
  240. case WM_LBUTTONDBLCLK:
  241. _graph->clicked_label(_collector_index);
  242. return 0;
  243. case WM_MOUSEMOVE:
  244. {
  245. // When the mouse enters the label area, highlight the label.
  246. set_mouse_within(true);
  247. // Now we want to get a WM_MOUSELEAVE when the mouse leaves the label.
  248. TRACKMOUSEEVENT tme = {
  249. sizeof(TRACKMOUSEEVENT),
  250. TME_LEAVE,
  251. _window,
  252. 0
  253. };
  254. TrackMouseEvent(&tme);
  255. }
  256. break;
  257. case WM_MOUSELEAVE:
  258. set_mouse_within(false);
  259. break;
  260. case WM_PAINT:
  261. {
  262. PAINTSTRUCT ps;
  263. HDC hdc = BeginPaint(hwnd, &ps);
  264. RECT rect = { 0, 0, _width, _height };
  265. FillRect(hdc, &rect, _bg_brush);
  266. if (_highlight || _mouse_within) {
  267. FrameRect(hdc, &rect, _highlight_brush);
  268. }
  269. HFONT hfnt = (HFONT)GetStockObject(ANSI_VAR_FONT);
  270. SelectObject(hdc, hfnt);
  271. SetTextAlign(hdc, TA_RIGHT | TA_TOP);
  272. SetBkColor(hdc, _bg_color);
  273. SetBkMode(hdc, OPAQUE);
  274. SetTextColor(hdc, _fg_color);
  275. TextOut(hdc, _width - _right_margin, _top_margin,
  276. _text.data(), _text.length());
  277. EndPaint(hwnd, &ps);
  278. return 0;
  279. }
  280. default:
  281. break;
  282. }
  283. return DefWindowProc(hwnd, msg, wparam, lparam);
  284. }