gtkStatsStripChart.cxx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. // Filename: gtkStatsStripChart.cxx
  2. // Created by: drose (14Jul00)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://www.panda3d.org/license.txt .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. #include "gtkStatsStripChart.h"
  19. #include "gtkStatsLabel.h"
  20. #include "gtkStatsGuide.h"
  21. #include <request_initial_size.h>
  22. #include <pStatThreadData.h>
  23. #include <pStatFrameData.h>
  24. #include <pStatView.h>
  25. #include <algorithm>
  26. ////////////////////////////////////////////////////////////////////
  27. // Function: GtkStatsStripChart::Constructor
  28. // Access: Public
  29. // Description:
  30. ////////////////////////////////////////////////////////////////////
  31. GtkStatsStripChart::
  32. GtkStatsStripChart(GtkStatsMonitor *monitor, PStatView &view,
  33. int collector_index, int xsize, int ysize) :
  34. PStatStripChart(monitor, view, collector_index, xsize, ysize)
  35. {
  36. _is_dead = false;
  37. set_events(GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
  38. _label_align = manage(new Gtk::Alignment(1.0, 1.0));
  39. _label_align->show();
  40. _label_box = NULL;
  41. pack_labels();
  42. _guide = manage(new GtkStatsGuide(this));
  43. _guide->show();
  44. request_initial_size(*this, get_xsize(), get_ysize());
  45. }
  46. ////////////////////////////////////////////////////////////////////
  47. // Function: GtkStatsStripChart::mark_dead
  48. // Access: Public
  49. // Description: Called when the client's connection has been lost,
  50. // this should update the window in some obvious way to
  51. // indicate that the window is no longer live.
  52. ////////////////////////////////////////////////////////////////////
  53. void GtkStatsStripChart::
  54. mark_dead() {
  55. _is_dead = true;
  56. setup_white_gc();
  57. if (!first_data()) {
  58. force_redraw();
  59. } else {
  60. clear_region();
  61. }
  62. }
  63. ////////////////////////////////////////////////////////////////////
  64. // Function: GtkStatsStripChart::get_labels
  65. // Access: Public
  66. // Description: Returns an alignment widget that contains all of the
  67. // labels appropriate to this chart, already formatted
  68. // and stacked up bottom-to-top. The window should pack
  69. // this widget suitably near the strip chart.
  70. ////////////////////////////////////////////////////////////////////
  71. Gtk::Alignment *GtkStatsStripChart::
  72. get_labels() {
  73. return _label_align;
  74. }
  75. ////////////////////////////////////////////////////////////////////
  76. // Function: GtkStatsStripChart::get_guide
  77. // Access: Public
  78. // Description: Returns a widget that contains the numeric labels for
  79. // the guide bars. The window should pack this widget
  80. // suitably near the strip chart.
  81. ////////////////////////////////////////////////////////////////////
  82. GtkStatsGuide *GtkStatsStripChart::
  83. get_guide() {
  84. return _guide;
  85. }
  86. ////////////////////////////////////////////////////////////////////
  87. // Function: GtkStatsStripChart::get_collector_gc
  88. // Access: Public
  89. // Description: Returns a graphics context suitable for drawing in
  90. // the indicated collector's color.
  91. ////////////////////////////////////////////////////////////////////
  92. Gdk_GC GtkStatsStripChart::
  93. get_collector_gc(int collector_index) {
  94. GCs::iterator gi;
  95. gi = _gcs.find(collector_index);
  96. if (gi != _gcs.end()) {
  97. return (*gi).second;
  98. }
  99. // Ask the monitor what color this guy should be.
  100. RGBColorf rgb = get_monitor()->get_collector_color(collector_index);
  101. Gdk_Color color;
  102. color.set_rgb_p(rgb[0], rgb[1], rgb[2]);
  103. // Now allocate the color from the system colormap.
  104. Gdk_Colormap::get_system().alloc(color);
  105. // Allocate a new graphics context.
  106. Gdk_GC gc(_pixmap);
  107. gc.set_foreground(color);
  108. _gcs[collector_index] = gc;
  109. return gc;
  110. }
  111. ////////////////////////////////////////////////////////////////////
  112. // Function: GtkStatsStripChart::clear_region
  113. // Access: Protected, Virtual
  114. // Description: Erases the chart area.
  115. ////////////////////////////////////////////////////////////////////
  116. void GtkStatsStripChart::
  117. clear_region() {
  118. _pixmap.draw_rectangle(_white_gc, true, 0, 0, get_xsize(), get_ysize());
  119. end_draw(0, get_xsize());
  120. }
  121. ////////////////////////////////////////////////////////////////////
  122. // Function: GtkStatsStripChart::copy_region
  123. // Access: Protected, Virtual
  124. // Description: Should be overridden by the user class to copy a
  125. // region of the chart from one part of the chart to
  126. // another. This is used to implement scrolling.
  127. ////////////////////////////////////////////////////////////////////
  128. void GtkStatsStripChart::
  129. copy_region(int start_x, int end_x, int dest_x) {
  130. _pixmap.copy_area(_white_gc, 0, 0,
  131. _pixmap, start_x, 0,
  132. end_x - start_x + 1, get_ysize());
  133. // We could make a window-to-window copy to implement scrolling in
  134. // the window. But this leads to trouble if the scrolling window
  135. // isn't on top. Instead, we'll just do the scroll in the pixmap,
  136. // and then blt the pixmap back out--in principle, this ought to be
  137. // just as fast.
  138. /*
  139. Gdk_Window window = get_window();
  140. window.copy_area(_white_gc, 0, 0,
  141. window, start_x, 0,
  142. end_x - start_x + 1, get_ysize());
  143. */
  144. GdkRectangle update_rect;
  145. update_rect.x = dest_x;
  146. update_rect.y = 0;
  147. update_rect.width = end_x - start_x + 1;
  148. update_rect.height = get_ysize();
  149. draw(&update_rect);
  150. }
  151. ////////////////////////////////////////////////////////////////////
  152. // Function: GtkStatsStripChart::draw_slice
  153. // Access: Protected, Virtual
  154. // Description: Draws a single vertical slice of the strip chart, at
  155. // the given pixel position, and corresponding to the
  156. // indicated level data.
  157. ////////////////////////////////////////////////////////////////////
  158. void GtkStatsStripChart::
  159. draw_slice(int x, int w, int frame_number) {
  160. const FrameData &frame = get_frame_data(frame_number);
  161. while (w > 0) {
  162. // Start by clearing the band first.
  163. _pixmap.draw_line(_white_gc, x, 0, x, get_ysize());
  164. float overall_time = 0.0;
  165. int y = get_ysize();
  166. FrameData::const_iterator fi;
  167. for (fi = frame.begin(); fi != frame.end(); ++fi) {
  168. const ColorData &cd = (*fi);
  169. overall_time += cd._net_value;
  170. if (overall_time > get_vertical_scale()) {
  171. // Off the top. Go ahead and clamp it by hand, in case it's so
  172. // far off the top we'd overflow the 16-bit pixel value.
  173. _pixmap.draw_line(get_collector_gc(cd._collector_index), x, y, x, 0);
  174. // And we can consider ourselves done now.
  175. break;
  176. }
  177. int top_y = height_to_pixel(overall_time);
  178. _pixmap.draw_line(get_collector_gc(cd._collector_index), x, y, x, top_y);
  179. y = top_y;
  180. }
  181. x++;
  182. w--;
  183. }
  184. }
  185. ////////////////////////////////////////////////////////////////////
  186. // Function: GtkStatsStripChart::draw_empty
  187. // Access: Protected, Virtual
  188. // Description: Draws a single vertical slice of background color.
  189. ////////////////////////////////////////////////////////////////////
  190. void GtkStatsStripChart::
  191. draw_empty(int x, int w) {
  192. while (w > 0) {
  193. _pixmap.draw_line(_white_gc, x, 0, x, get_ysize());
  194. x++;
  195. w--;
  196. }
  197. }
  198. ////////////////////////////////////////////////////////////////////
  199. // Function: GtkStatsStripChart::draw_cursor
  200. // Access: Protected, Virtual
  201. // Description: Draws a single vertical slice of foreground color.
  202. ////////////////////////////////////////////////////////////////////
  203. void GtkStatsStripChart::
  204. draw_cursor(int x) {
  205. _pixmap.draw_line(_black_gc, x, 0, x, get_ysize());
  206. }
  207. ////////////////////////////////////////////////////////////////////
  208. // Function: GtkStatsStripChart::end_draw
  209. // Access: Protected, Virtual
  210. // Description: Should be overridden by the user class. This hook
  211. // will be called after drawing a series of color bars
  212. // in the strip chart; it gives the pixel range that
  213. // was just redrawn.
  214. ////////////////////////////////////////////////////////////////////
  215. void GtkStatsStripChart::
  216. end_draw(int from_x, int to_x) {
  217. // Draw in the guide bars.
  218. int num_guide_bars = get_num_guide_bars();
  219. for (int i = 0; i < num_guide_bars; i++) {
  220. const GuideBar &bar = get_guide_bar(i);
  221. int y = height_to_pixel(bar._height);
  222. if (y >= 5) {
  223. // Only draw it if it's not too close to the top.
  224. if (bar._is_target) {
  225. _pixmap.draw_line(_light_gc, from_x, y, to_x, y);
  226. } else {
  227. _pixmap.draw_line(_dark_gc, from_x, y, to_x, y);
  228. }
  229. }
  230. }
  231. GdkRectangle update_rect;
  232. update_rect.x = from_x;
  233. update_rect.y = 0;
  234. update_rect.width = to_x - from_x + 1;
  235. update_rect.height = get_ysize();
  236. draw(&update_rect);
  237. }
  238. ////////////////////////////////////////////////////////////////////
  239. // Function: GtkStatsStripChart::idle
  240. // Access: Protected, Virtual
  241. // Description: Called at the end of the draw cycle.
  242. ////////////////////////////////////////////////////////////////////
  243. void GtkStatsStripChart::
  244. idle() {
  245. if (_labels_changed) {
  246. pack_labels();
  247. }
  248. if (_guide_bars_changed) {
  249. GdkRectangle update_rect;
  250. update_rect.x = 0;
  251. update_rect.y = 0;
  252. update_rect.width = _guide->width();
  253. update_rect.height = _guide->height();
  254. _guide->draw(&update_rect);
  255. _guide_bars_changed = false;
  256. }
  257. }
  258. ////////////////////////////////////////////////////////////////////
  259. // Function: GtkStatsStripChart::configure_event_impl
  260. // Access: Private, Virtual
  261. // Description: Creates a new backing pixmap of the appropriate size.
  262. ////////////////////////////////////////////////////////////////////
  263. gint GtkStatsStripChart::
  264. configure_event_impl(GdkEventConfigure *) {
  265. if (width() != get_xsize() || height() != get_ysize() ||
  266. _pixmap.gdkobj() == (GdkDrawable *)NULL) {
  267. bool is_initial = true;
  268. if (_pixmap) {
  269. is_initial = false;
  270. _pixmap.release();
  271. }
  272. _pixmap.create(get_window(), width(), height());
  273. Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
  274. _white_gc = Gdk_GC(_pixmap);
  275. setup_white_gc();
  276. _black_gc = Gdk_GC(_pixmap);
  277. _black_gc.set_foreground(system_colormap.black());
  278. _dark_gc = Gdk_GC(_pixmap);
  279. Gdk_Color dark;
  280. dark.set_grey_p(0.2);
  281. system_colormap.alloc(dark);
  282. _dark_gc.set_foreground(dark);
  283. _light_gc = Gdk_GC(_pixmap);
  284. Gdk_Color light;
  285. light.set_grey_p(0.6);
  286. system_colormap.alloc(light);
  287. _light_gc.set_foreground(light);
  288. _pixmap.draw_rectangle(_white_gc, true, 0, 0, width(), height());
  289. changed_size(width(), height());
  290. }
  291. return true;
  292. }
  293. ////////////////////////////////////////////////////////////////////
  294. // Function: GtkStatsStripChart::expose_event_impl
  295. // Access: Private, Virtual
  296. // Description: Redraw the screen from the backing pixmap.
  297. ////////////////////////////////////////////////////////////////////
  298. gint GtkStatsStripChart::
  299. expose_event_impl(GdkEventExpose *event) {
  300. get_window().draw_pixmap(_white_gc, _pixmap,
  301. event->area.x, event->area.y,
  302. event->area.x, event->area.y,
  303. event->area.width, event->area.height);
  304. return false;
  305. }
  306. ////////////////////////////////////////////////////////////////////
  307. // Function: GtkStatsStripChart::button_press_event_impl
  308. // Access: Private, Virtual
  309. // Description:
  310. ////////////////////////////////////////////////////////////////////
  311. gint GtkStatsStripChart::
  312. button_press_event_impl(GdkEventButton *button) {
  313. if (button->type == GDK_2BUTTON_PRESS && button->button == 1) {
  314. int collector_index = get_collector_under_pixel(button->x, button->y);
  315. collector_picked(collector_index);
  316. return true;
  317. }
  318. return false;
  319. }
  320. ////////////////////////////////////////////////////////////////////
  321. // Function: GtkStatsStripChart::pack_labels
  322. // Access: Private
  323. // Description:
  324. ////////////////////////////////////////////////////////////////////
  325. void GtkStatsStripChart::
  326. pack_labels() {
  327. // First, remove the old labels.
  328. _label_align->remove();
  329. // Now add the new labels back in.
  330. _label_box = manage(new Gtk::VBox);
  331. _label_box->show();
  332. _label_align->add(*_label_box);
  333. Gdk_Font font = get_style()->gtkobj()->font;
  334. int num_labels = get_num_labels();
  335. for (int i = 0; i < num_labels; i++) {
  336. int collector_index = get_label_collector(i);
  337. GtkStatsLabel *label =
  338. new GtkStatsLabel(get_monitor(), collector_index, font);
  339. label->show();
  340. label->collector_picked.connect(collector_picked.slot());
  341. _label_box->pack_end(*manage(label), false, false);
  342. }
  343. _labels_changed = false;
  344. }
  345. ////////////////////////////////////////////////////////////////////
  346. // Function: GtkStatsStripChart::setup_white_gc
  347. // Access: Private
  348. // Description: Sets the color on _white_gc to be either actually
  349. // white (if the chart is still alive) or a light gray
  350. // (if the chart is dead).
  351. ////////////////////////////////////////////////////////////////////
  352. void GtkStatsStripChart::
  353. setup_white_gc() {
  354. Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
  355. if (_is_dead) {
  356. Gdk_Color death;
  357. death.set_grey_p(0.8);
  358. system_colormap.alloc(death);
  359. _white_gc.set_foreground(death);
  360. } else {
  361. _white_gc.set_foreground(system_colormap.white());
  362. }
  363. }