diff --git a/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx b/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx index 536f36fef9..cf195b0ea0 100644 --- a/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx +++ b/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx @@ -130,10 +130,15 @@ begin_draw() { if (x >= 5 && x <= get_xsize() - 5) { // Only draw it if it's not too close to either edge. - if (bar._is_target) { + switch (bar._style) { + case GBS_target: _pixmap.draw_line(_light_gc, x, text_height + 4, x, get_ysize()); - } else { + break; + + case GBS_normal: + default: _pixmap.draw_line(_dark_gc, x, text_height + 4, x, get_ysize()); + break; } } } diff --git a/pandatool/src/gtk-stats/gtkStatsStripChart.cxx b/pandatool/src/gtk-stats/gtkStatsStripChart.cxx index 963bb765a3..1b0efe0f9e 100644 --- a/pandatool/src/gtk-stats/gtkStatsStripChart.cxx +++ b/pandatool/src/gtk-stats/gtkStatsStripChart.cxx @@ -255,10 +255,15 @@ end_draw(int from_x, int to_x) { if (y >= 5) { // Only draw it if it's not too close to the top. - if (bar._is_target) { + switch (bar._style) { + case GBS_target: _pixmap.draw_line(_light_gc, from_x, y, to_x, y); - } else { + break; + + case GBS_normal: + default: _pixmap.draw_line(_dark_gc, from_x, y, to_x, y); + break; } } } diff --git a/pandatool/src/pstatserver/pStatGraph.I b/pandatool/src/pstatserver/pStatGraph.I index 8774a43a7e..28c61caa01 100644 --- a/pandatool/src/pstatserver/pStatGraph.I +++ b/pandatool/src/pstatserver/pStatGraph.I @@ -130,6 +130,7 @@ set_guide_bar_units(int guide_bar_units) { if (_guide_bar_units != guide_bar_units) { _guide_bar_units = guide_bar_units; normal_guide_bars(); + user_guide_bar_labels(); } } diff --git a/pandatool/src/pstatserver/pStatGraph.cxx b/pandatool/src/pstatserver/pStatGraph.cxx index c944d9fd29..c7900cfce4 100644 --- a/pandatool/src/pstatserver/pStatGraph.cxx +++ b/pandatool/src/pstatserver/pStatGraph.cxx @@ -31,10 +31,10 @@ // Description: //////////////////////////////////////////////////////////////////// PStatGraph::GuideBar:: -GuideBar(float height, const string &label, bool is_target) : +GuideBar(float height, const string &label, PStatGraph::GuideBarStyle style) : _height(height), _label(label), - _is_target(is_target) + _style(style) { } @@ -47,7 +47,7 @@ PStatGraph::GuideBar:: GuideBar(const PStatGraph::GuideBar ©) : _height(copy._height), _label(copy._label), - _is_target(copy._is_target) + _style(copy._style) { } @@ -104,12 +104,101 @@ get_num_guide_bars() const { const PStatGraph::GuideBar &PStatGraph:: get_guide_bar(int n) const { #ifndef NDEBUG - static GuideBar bogus_bar(0.0, "bogus", false); + static GuideBar bogus_bar(0.0, "bogus", GBS_normal); nassertr(n >= 0 && n < (int)_guide_bars.size(), bogus_bar); #endif return _guide_bars[n]; } +//////////////////////////////////////////////////////////////////// +// Function: PStatGraph::get_num_user_guide_bars +// Access: Public +// Description: Returns the current number of user-defined guide +// bars. Not all of these may be visible. +//////////////////////////////////////////////////////////////////// +int PStatGraph:: +get_num_user_guide_bars() const { + return _user_guide_bars.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatGraph::get_user_guide_bar +// Access: Public +// Description: Returns the nth user-defined guide bar. +//////////////////////////////////////////////////////////////////// +const PStatGraph::GuideBar &PStatGraph:: +get_user_guide_bar(int n) const { +#ifndef NDEBUG + static GuideBar bogus_bar(0.0, "bogus", GBS_user); + nassertr(n >= 0 && n < (int)_user_guide_bars.size(), bogus_bar); +#endif + return _user_guide_bars[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatGraph::move_user_guide_bar +// Access: Public +// Description: Adjusts the height of the nth user-defined guide bar. +//////////////////////////////////////////////////////////////////// +void PStatGraph:: +move_user_guide_bar(int n, float height) { + nassertv(n >= 0 && n < (int)_user_guide_bars.size()); + string label = format_number(height, _guide_bar_units, _unit_name); + _user_guide_bars[n]._height = height; + _user_guide_bars[n]._label = label; +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatGraph::add_user_guide_bar +// Access: Public +// Description: Creates a new user guide bar and returns its index +// number. +//////////////////////////////////////////////////////////////////// +int PStatGraph:: +add_user_guide_bar(float height) { + int n = (int)_user_guide_bars.size(); + GuideBar bar = make_guide_bar(height); + bar._style = GBS_user; + _user_guide_bars.push_back(bar); + + return n; +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatGraph::remove_user_guide_bar +// Access: Public +// Description: Removes the user guide bar with the indicated index +// number. All subsequent index numbers are adjusted +// down one. +//////////////////////////////////////////////////////////////////// +void PStatGraph:: +remove_user_guide_bar(int n) { + nassertv(n >= 0 && n < (int)_user_guide_bars.size()); + _user_guide_bars.erase(_user_guide_bars.begin() + n); +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatGraph::find_user_guide_bar +// Access: Public +// Description: Returns the index number of the first user guide bar +// found whose height is within the indicated range, or +// -1 if no user guide bars fall within the range. +//////////////////////////////////////////////////////////////////// +int PStatGraph:: +find_user_guide_bar(float from_height, float to_height) const { + GuideBars::const_iterator gbi; + for (gbi = _user_guide_bars.begin(); + gbi != _user_guide_bars.end(); + ++gbi) { + const GuideBar &bar = (*gbi); + if (bar._height >= from_height && bar._height <= to_height) { + return (int)(gbi - _user_guide_bars.begin()); + } + } + + return -1; +} + //////////////////////////////////////////////////////////////////// // Function: PStatGraph::format_number @@ -222,6 +311,22 @@ update_guide_bars(int num_bars, float scale) { _guide_bars_changed = true; } +//////////////////////////////////////////////////////////////////// +// Function: PStatGraph::user_guide_bar_labels +// Access: Protected +// Description: Rederives the labels for the user-defined guide bars. +//////////////////////////////////////////////////////////////////// +void PStatGraph:: +user_guide_bar_labels() { + GuideBars::iterator gbi; + for (gbi = _user_guide_bars.begin(); + gbi != _user_guide_bars.end(); + ++gbi) { + GuideBar &bar = (*gbi); + bar._label = format_number(bar._height, _guide_bar_units, _unit_name); + } +} + //////////////////////////////////////////////////////////////////// // Function: PStatGraph::make_guide_bar // Access: Protected @@ -232,14 +337,16 @@ PStatGraph::GuideBar PStatGraph:: make_guide_bar(float value) const { string label = format_number(value, _guide_bar_units, _unit_name); - bool is_target = false; + GuideBarStyle style = GBS_normal; if ((_guide_bar_units & GBU_named) == 0) { // If it's a time unit, check to see if it matches our target // frame rate. float hz = 1.0 / value; - is_target = IS_NEARLY_EQUAL(hz, _target_frame_rate); + if (IS_THRESHOLD_EQUAL(hz, _target_frame_rate, 0.001)) { + style = GBS_target; + } } - return GuideBar(value, label, is_target); + return GuideBar(value, label, style); } diff --git a/pandatool/src/pstatserver/pStatGraph.h b/pandatool/src/pstatserver/pStatGraph.h index f176d145fe..ac02e64c9f 100644 --- a/pandatool/src/pstatserver/pStatGraph.h +++ b/pandatool/src/pstatserver/pStatGraph.h @@ -55,14 +55,20 @@ public: INLINE int get_xsize() const; INLINE int get_ysize() const; + enum GuideBarStyle { + GBS_normal, + GBS_target, + GBS_user, + }; + class GuideBar { public: - GuideBar(float height, const string &label, bool is_target); + GuideBar(float height, const string &label, GuideBarStyle style); GuideBar(const GuideBar ©); float _height; string _label; - bool _is_target; + GuideBarStyle _style; }; enum GuideBarUnits { @@ -75,6 +81,13 @@ public: int get_num_guide_bars() const; const GuideBar &get_guide_bar(int n) const; + int get_num_user_guide_bars() const; + const GuideBar &get_user_guide_bar(int n) const; + void move_user_guide_bar(int n, float height); + int add_user_guide_bar(float height); + void remove_user_guide_bar(int n); + int find_user_guide_bar(float from_height, float to_height) const; + INLINE void set_guide_bar_units(int unit_mask); INLINE int get_guide_bar_units() const; INLINE void set_guide_bar_unit_name(const string &unit_name); @@ -87,6 +100,7 @@ public: protected: virtual void normal_guide_bars()=0; void update_guide_bars(int num_bars, float scale); + void user_guide_bar_labels(); GuideBar make_guide_bar(float value) const; bool _labels_changed; @@ -106,6 +120,7 @@ protected: typedef pvector GuideBars; GuideBars _guide_bars; + GuideBars _user_guide_bars; int _guide_bar_units; string _unit_name; }; diff --git a/pandatool/src/win-stats/winStatsGraph.cxx b/pandatool/src/win-stats/winStatsGraph.cxx index 81c0f4d1d6..f491f734f5 100644 --- a/pandatool/src/win-stats/winStatsGraph.cxx +++ b/pandatool/src/win-stats/winStatsGraph.cxx @@ -39,6 +39,7 @@ WinStatsGraph(WinStatsMonitor *monitor, int thread_index) : _window = 0; _graph_window = 0; _sizewe_cursor = LoadCursor(NULL, IDC_SIZEWE); + _hand_cursor = LoadCursor(NULL, IDC_HAND); _bitmap = 0; _bitmap_dc = 0; @@ -47,8 +48,12 @@ WinStatsGraph(WinStatsMonitor *monitor, int thread_index) : _bitmap_xsize = 0; _bitmap_ysize = 0; - _dark_pen = CreatePen(PS_SOLID, 1, RGB(51, 51, 51)); - _light_pen = CreatePen(PS_SOLID, 1, RGB(154, 154, 154)); + _dark_color = RGB(51, 51, 51); + _light_color = RGB(154, 154, 154); + _user_guide_bar_color = RGB(130, 150, 255); + _dark_pen = CreatePen(PS_SOLID, 1, _dark_color); + _light_pen = CreatePen(PS_SOLID, 1, _light_color); + _user_guide_bar_pen = CreatePen(PS_DASH, 1, _user_guide_bar_color); _drag_mode = DM_none; _potential_drag_mode = DM_none; @@ -67,6 +72,7 @@ WinStatsGraph:: DeleteObject(_dark_pen); DeleteObject(_light_pen); + DeleteObject(_user_guide_bar_pen); Brushes::iterator bi; for (bi = _brushes.begin(); bi != _brushes.end(); ++bi) { @@ -85,6 +91,17 @@ WinStatsGraph:: } } +//////////////////////////////////////////////////////////////////// +// Function: WinStatsGraph::get_thread_index +// Access: Public +// Description: Returns the thread index associated with this +// particular graph. +//////////////////////////////////////////////////////////////////// +int WinStatsGraph:: +get_thread_index() const { + return _thread_index; +} + //////////////////////////////////////////////////////////////////// // Function: WinStatsGraph::new_collector // Access: Public, Virtual @@ -135,6 +152,37 @@ void WinStatsGraph:: set_time_units(int unit_mask) { } +//////////////////////////////////////////////////////////////////// +// Function: WinStatsGraph::move_user_guide_bar +// Access: Public, Virtual +// Description: Adjusts the height of the nth user-defined guide bar. +//////////////////////////////////////////////////////////////////// +void WinStatsGraph:: +move_user_guide_bar(int n, float height) { +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsGraph::add_user_guide_bar +// Access: Public, Virtual +// Description: Creates a new user guide bar and returns its index +// number. +//////////////////////////////////////////////////////////////////// +int WinStatsGraph:: +add_user_guide_bar(float height) { + return -1; +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsGraph::remove_user_guide_bar +// Access: Public, Virtual +// Description: Removes the user guide bar with the indicated index +// number. All subsequent index numbers are adjusted +// down one. +//////////////////////////////////////////////////////////////////// +void WinStatsGraph:: +remove_user_guide_bar(int n) { +} + //////////////////////////////////////////////////////////////////// // Function: WinStatsGraph::close // Access: Protected @@ -229,27 +277,34 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { case WM_SETCURSOR: { - // Why is it so hard to ask what the cursor position within the - // window's client area is? + // Why is it so hard to ask for the cursor position within the + // window's client area? POINT point; GetCursorPos(&point); WINDOWINFO winfo; GetWindowInfo(hwnd, &winfo); const RECT &rect = winfo.rcClient; + int x = point.x - rect.left; + int y = point.y - rect.top; + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; - // 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 = consider_drag_start(x, y, width, height); - _potential_drag_mode = DM_none; + switch (_potential_drag_mode) { + case DM_left_margin: + case DM_right_margin: + SetCursor(_sizewe_cursor); + return TRUE; + + case DM_guide_bar: + SetCursor(_hand_cursor); + return TRUE; + + default: + case DM_none: + break; + } } break; @@ -340,6 +395,21 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { force_redraw(); break; + case WM_LBUTTONDOWN: + // Vector any uncaught WM_LBUTTONDOWN into the main window, so we + // can drag margins, etc. + if (_potential_drag_mode != DM_none) { + PN_int16 x = LOWORD(lparam) + _graph_left; + PN_int16 y = HIWORD(lparam) + _graph_top; + return window_proc(_window, msg, wparam, MAKELPARAM(x, y)); + } + break; + + case WM_LBUTTONUP: + _drag_mode = DM_none; + ReleaseCapture(); + break; + case WM_PAINT: { // Repaint the graph by copying the backing pixmap in. @@ -351,6 +421,8 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { _bitmap_dc, 0, 0, SRCCOPY); + additional_graph_window_paint(hdc); + EndPaint(hwnd, &ps); return 0; } @@ -374,6 +446,36 @@ void WinStatsGraph:: additional_window_paint(HDC hdc) { } +//////////////////////////////////////////////////////////////////// +// Function: WinStatsGraph::additional_graph_window_paint +// Access: Protected, Virtual +// Description: This is called during the servicing of WM_PAINT; it +// gives a derived class opportunity to do some further +// painting into the graph window. +//////////////////////////////////////////////////////////////////// +void WinStatsGraph:: +additional_graph_window_paint(HDC hdc) { +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsGraph::consider_drag_start +// Access: Protected, Virtual +// Description: Based on the mouse position within the window's +// client area, look for draggable things the mouse +// might be hovering over and return the apprioprate +// DragMode enum or DM_none if nothing is indicated. +//////////////////////////////////////////////////////////////////// +WinStatsGraph::DragMode WinStatsGraph:: +consider_drag_start(int mouse_x, int mouse_y, int width, int height) { + if (mouse_x >= _left_margin - 2 && mouse_x <= _left_margin + 2) { + return DM_left_margin; + } else if (mouse_x >= width - _right_margin - 2 && mouse_x <= width - _right_margin + 2) { + return DM_right_margin; + } + + return DM_none; +} + //////////////////////////////////////////////////////////////////// // Function: WinStatsGraph::setup_bitmap // Access: Private diff --git a/pandatool/src/win-stats/winStatsGraph.h b/pandatool/src/win-stats/winStatsGraph.h index 5793ea76a6..9293ac9878 100644 --- a/pandatool/src/win-stats/winStatsGraph.h +++ b/pandatool/src/win-stats/winStatsGraph.h @@ -34,10 +34,23 @@ class WinStatsMonitor; // that may be created for a WinStatsMonitor. //////////////////////////////////////////////////////////////////// class WinStatsGraph { +public: + // What is the user adjusting by dragging the mouse in a window? + enum DragMode { + DM_none, + DM_scale, + DM_left_margin, + DM_right_margin, + DM_guide_bar, + DM_new_guide_bar, + }; + public: WinStatsGraph(WinStatsMonitor *monitor, int thread_index); virtual ~WinStatsGraph(); + int get_thread_index() const; + virtual void new_collector(int collector_index); virtual void new_data(int thread_index, int frame_number); virtual void force_redraw(); @@ -45,6 +58,10 @@ public: virtual void set_time_units(int unit_mask); + virtual void move_user_guide_bar(int n, float height); + virtual int add_user_guide_bar(float height); + virtual void remove_user_guide_bar(int n); + protected: void close(); @@ -57,7 +74,9 @@ protected: virtual LONG graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); virtual void additional_window_paint(HDC hdc); - + virtual void additional_graph_window_paint(HDC hdc); + virtual DragMode consider_drag_start(int mouse_x, int mouse_y, + int width, int height); protected: // Table of brushes for our various collectors. @@ -71,6 +90,7 @@ protected: WinStatsLabelStack _label_stack; HCURSOR _sizewe_cursor; + HCURSOR _hand_cursor; HBITMAP _bitmap; HDC _bitmap_dc; @@ -80,20 +100,18 @@ protected: int _left_margin, _right_margin; int _top_margin, _bottom_margin; + COLORREF _dark_color; + COLORREF _light_color; + COLORREF _user_guide_bar_color; HPEN _dark_pen; HPEN _light_pen; + HPEN _user_guide_bar_pen; - // What is the user adjusting by dragging the mouse in a window? - enum DragMode { - DM_none, - DM_scale, - DM_left_margin, - DM_right_margin, - }; DragMode _drag_mode; DragMode _potential_drag_mode; int _drag_start_x, _drag_start_y; float _drag_scale_start; + int _drag_guide_bar; private: void setup_bitmap(int xsize, int ysize); diff --git a/pandatool/src/win-stats/winStatsMonitor.cxx b/pandatool/src/win-stats/winStatsMonitor.cxx index 09d78ba903..d2d9680874 100644 --- a/pandatool/src/win-stats/winStatsMonitor.cxx +++ b/pandatool/src/win-stats/winStatsMonitor.cxx @@ -365,6 +365,63 @@ set_time_units(int unit_mask) { SetMenuItemInfo(_options_menu, MI_time_hz, FALSE, &mii); } +//////////////////////////////////////////////////////////////////// +// Function: WinStatsMonitor::move_user_guide_bar +// Access: Public +// Description: Adjusts the height of the nth user-defined guide bar +// for all graphs that share the indicated thread. +//////////////////////////////////////////////////////////////////// +void WinStatsMonitor:: +move_user_guide_bar(int thread_index, int n, float height) { + Graphs::iterator gi; + for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { + WinStatsGraph *graph = (*gi); + if (graph->get_thread_index() == thread_index) { + graph->move_user_guide_bar(n, height); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsMonitor::add_user_guide_bar +// Access: Public +// Description: Creates a new user guide bar and returns its index +// number for all graphs that share the indicated +// thread. +//////////////////////////////////////////////////////////////////// +int WinStatsMonitor:: +add_user_guide_bar(int thread_index, float height) { + int result = -1; + + Graphs::iterator gi; + for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { + WinStatsGraph *graph = (*gi); + if (graph->get_thread_index() == thread_index) { + result = graph->add_user_guide_bar(height); + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsMonitor::remove_user_guide_bar +// Access: Public +// Description: Removes the user guide bar with the indicated index +// number, for all graphs that share the indicated +// thread. +//////////////////////////////////////////////////////////////////// +void WinStatsMonitor:: +remove_user_guide_bar(int thread_index, int n) { + Graphs::iterator gi; + for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { + WinStatsGraph *graph = (*gi); + if (graph->get_thread_index() == thread_index) { + graph->remove_user_guide_bar(n); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: WinStatsMonitor::add_graph // Access: Private diff --git a/pandatool/src/win-stats/winStatsMonitor.h b/pandatool/src/win-stats/winStatsMonitor.h index 95e391d254..bec3345ce6 100644 --- a/pandatool/src/win-stats/winStatsMonitor.h +++ b/pandatool/src/win-stats/winStatsMonitor.h @@ -72,6 +72,10 @@ public: int get_menu_id(const MenuDef &menu_def); void set_time_units(int unit_mask); + + void move_user_guide_bar(int thread_index, int n, float height); + int add_user_guide_bar(int thread_index, float height); + void remove_user_guide_bar(int thread_index, int n); private: void add_graph(WinStatsGraph *graph); diff --git a/pandatool/src/win-stats/winStatsPianoRoll.cxx b/pandatool/src/win-stats/winStatsPianoRoll.cxx index 46a61aebd3..e573786e01 100755 --- a/pandatool/src/win-stats/winStatsPianoRoll.cxx +++ b/pandatool/src/win-stats/winStatsPianoRoll.cxx @@ -133,6 +133,56 @@ set_horizontal_scale(float time_width) { InvalidateRect(_window, &rect, TRUE); } +//////////////////////////////////////////////////////////////////// +// Function: WinStatsPianoRoll::move_user_guide_bar +// Access: Public, Virtual +// Description: Adjusts the height of the nth user-defined guide bar. +//////////////////////////////////////////////////////////////////// +void WinStatsPianoRoll:: +move_user_guide_bar(int n, float height) { + RECT rect; + GetClientRect(_window, &rect); + rect.bottom = _top_margin; + InvalidateRect(_window, &rect, TRUE); + + InvalidateRect(_graph_window, NULL, TRUE); + + PStatPianoRoll::move_user_guide_bar(n, height); +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsPianoRoll::add_user_guide_bar +// Access: Public, Virtual +// Description: Creates a new user guide bar and returns its index +// number. +//////////////////////////////////////////////////////////////////// +int WinStatsPianoRoll:: +add_user_guide_bar(float height) { + RECT rect; + GetClientRect(_window, &rect); + rect.bottom = _top_margin; + InvalidateRect(_window, &rect, TRUE); + + return PStatPianoRoll::add_user_guide_bar(height); +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsPianoRoll::remove_user_guide_bar +// Access: Public, Virtual +// Description: Removes the user guide bar with the indicated index +// number. All subsequent index numbers are adjusted +// down one. +//////////////////////////////////////////////////////////////////// +void WinStatsPianoRoll:: +remove_user_guide_bar(int n) { + RECT rect; + GetClientRect(_window, &rect); + rect.bottom = _top_margin; + InvalidateRect(_window, &rect, TRUE); + + return PStatPianoRoll::remove_user_guide_bar(n); +} + //////////////////////////////////////////////////////////////////// // Function: WinStatsPianoRoll::clear_region // Access: Protected @@ -157,19 +207,7 @@ begin_draw() { // Draw in the guide bars. int num_guide_bars = get_num_guide_bars(); for (int i = 0; i < num_guide_bars; i++) { - const GuideBar &bar = get_guide_bar(i); - int x = height_to_pixel(bar._height); - - if (x > 0 && x < get_xsize() - 1) { - // Only draw it if it's not too close to either edge. - if (bar._is_target) { - SelectObject(_bitmap_dc, _light_pen); - } else { - SelectObject(_bitmap_dc, _dark_pen); - } - MoveToEx(_bitmap_dc, x, 0, NULL); - LineTo(_bitmap_dc, x, get_ysize()); - } + draw_guide_bar(_bitmap_dc, get_guide_bar(i)); } } @@ -224,12 +262,18 @@ idle() { //////////////////////////////////////////////////////////////////// LONG WinStatsPianoRoll:: window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - /* switch (msg) { + case WM_LBUTTONDOWN: + if (_potential_drag_mode == DM_new_guide_bar) { + _drag_mode = DM_new_guide_bar; + SetCapture(_graph_window); + return 0; + } + break; + default: break; } - */ return WinStatsGraph::window_proc(hwnd, msg, wparam, lparam); } @@ -243,13 +287,21 @@ LONG WinStatsPianoRoll:: graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { case WM_LBUTTONDOWN: - { + if (_potential_drag_mode == DM_none) { _drag_mode = DM_scale; PN_int16 x = LOWORD(lparam); _drag_scale_start = pixel_to_height(x); SetCapture(_graph_window); + return 0; + + } else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) { + _drag_mode = DM_guide_bar; + PN_int16 x = LOWORD(lparam); + _drag_start_x = x; + SetCapture(_graph_window); + return 0; } - return 0; + break; case WM_MOUSEMOVE: if (_drag_mode == DM_scale) { @@ -259,6 +311,22 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { set_horizontal_scale(_drag_scale_start / ratio); } return 0; + + } else if (_drag_mode == DM_new_guide_bar) { + // We haven't created the new guide bar yet; we won't until the + // mouse comes within the graph's region. + PN_int16 x = LOWORD(lparam); + if (x >= 0 && x < get_xsize()) { + _drag_mode = DM_guide_bar; + _drag_guide_bar = + WinStatsGraph::_monitor->add_user_guide_bar(WinStatsGraph::_thread_index, pixel_to_height(x)); + return 0; + } + + } else if (_drag_mode == DM_guide_bar) { + PN_int16 x = LOWORD(lparam); + WinStatsGraph::_monitor->move_user_guide_bar(WinStatsGraph::_thread_index, _drag_guide_bar, pixel_to_height(x)); + return 0; } break; @@ -267,6 +335,17 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { _drag_mode = DM_none; ReleaseCapture(); return 0; + + } else if (_drag_mode == DM_guide_bar) { + PN_int16 x = LOWORD(lparam); + if (x < 0 || x >= get_xsize()) { + WinStatsGraph::_monitor->remove_user_guide_bar(WinStatsGraph::_thread_index, _drag_guide_bar); + } else { + WinStatsGraph::_monitor->move_user_guide_bar(WinStatsGraph::_thread_index, _drag_guide_bar, pixel_to_height(x)); + } + _drag_mode = DM_none; + ReleaseCapture(); + return 0; } break; @@ -292,21 +371,66 @@ additional_window_paint(HDC hdc) { SelectObject(hdc, hfnt); SetTextAlign(hdc, TA_LEFT | TA_BOTTOM); SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, RGB(0, 0, 0)); + int y = _top_margin; + + int i; int num_guide_bars = get_num_guide_bars(); - for (int i = 0; i < num_guide_bars; i++) { - const GuideBar &bar = get_guide_bar(i); - int x = height_to_pixel(bar._height); - - const string &label = bar._label; - SIZE size; - GetTextExtentPoint32(hdc, label.data(), label.length(), &size); - x -= size.cx / 2; - - TextOut(hdc, x + _graph_left, _top_margin, - label.data(), label.length()); + for (i = 0; i < num_guide_bars; i++) { + draw_guide_label(hdc, y, get_guide_bar(i)); } + + int num_user_guide_bars = get_num_user_guide_bars(); + for (i = 0; i < num_user_guide_bars; i++) { + draw_guide_label(hdc, y, get_user_guide_bar(i)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsPianoRoll::additional_graph_window_paint +// Access: Protected, Virtual +// Description: This is called during the servicing of WM_PAINT; it +// gives a derived class opportunity to do some further +// painting into the window (the outer window, not the +// graph window). +//////////////////////////////////////////////////////////////////// +void WinStatsPianoRoll:: +additional_graph_window_paint(HDC hdc) { + int num_user_guide_bars = get_num_user_guide_bars(); + for (int i = 0; i < num_user_guide_bars; i++) { + draw_guide_bar(hdc, get_user_guide_bar(i)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsPianoRoll::consider_drag_start +// Access: Protected, Virtual +// Description: Based on the mouse position within the window's +// client area, look for draggable things the mouse +// might be hovering over and return the apprioprate +// DragMode enum or DM_none if nothing is indicated. +//////////////////////////////////////////////////////////////////// +WinStatsGraph::DragMode WinStatsPianoRoll:: +consider_drag_start(int mouse_x, int mouse_y, int width, int height) { + if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) { + if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) { + // See if the mouse is over a user-defined guide bar. + int x = mouse_x - _graph_left; + float from_height = pixel_to_height(x - 2); + float to_height = pixel_to_height(x + 2); + _drag_guide_bar = find_user_guide_bar(from_height, to_height); + if (_drag_guide_bar >= 0) { + return DM_guide_bar; + } + + } else { + // The mouse is above or below the graph; maybe create a new + // guide bar. + return DM_new_guide_bar; + } + } + + return WinStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height); } //////////////////////////////////////////////////////////////////// @@ -326,6 +450,79 @@ update_labels() { _labels_changed = false; } +//////////////////////////////////////////////////////////////////// +// Function: WinStatsPianoRoll::draw_guide_bar +// Access: Private +// Description: Draws the line for the indicated guide bar on the +// graph. +//////////////////////////////////////////////////////////////////// +void WinStatsPianoRoll:: +draw_guide_bar(HDC hdc, const PStatGraph::GuideBar &bar) { + int x = height_to_pixel(bar._height); + + if (x > 0 && x < get_xsize() - 1) { + // Only draw it if it's not too close to either edge. + switch (bar._style) { + case GBS_target: + SelectObject(hdc, _light_pen); + break; + + case GBS_user: + SelectObject(hdc, _user_guide_bar_pen); + break; + + case GBS_normal: + SelectObject(hdc, _dark_pen); + break; + } + MoveToEx(hdc, x, 0, NULL); + LineTo(hdc, x, get_ysize()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsPianoRoll::draw_guide_label +// Access: Private +// Description: Draws the text for the indicated guide bar label at +// the top of the graph. +//////////////////////////////////////////////////////////////////// +void WinStatsPianoRoll:: +draw_guide_label(HDC hdc, int y, const PStatGraph::GuideBar &bar) { + switch (bar._style) { + case GBS_target: + SetTextColor(hdc, _light_color); + break; + + case GBS_user: + SetTextColor(hdc, _user_guide_bar_color); + break; + + case GBS_normal: + SetTextColor(hdc, _dark_color); + break; + } + + int x = height_to_pixel(bar._height); + const string &label = bar._label; + SIZE size; + GetTextExtentPoint32(hdc, label.data(), label.length(), &size); + + if (bar._style != GBS_user) { + float from_height = pixel_to_height(x - size.cx / 2 - 1); + float to_height = pixel_to_height(x + size.cx / 2 + 1); + if (find_user_guide_bar(from_height, to_height) >= 0) { + // Omit the label: there's a user-defined guide bar in the same space. + return; + } + } + + int this_x = _graph_left + x - size.cx / 2; + if (x >= 0 && x < get_xsize()) { + TextOut(hdc, this_x, y, + label.data(), label.length()); + } +} + //////////////////////////////////////////////////////////////////// // Function: WinStatsPianoRoll::create_window // Access: Private diff --git a/pandatool/src/win-stats/winStatsPianoRoll.h b/pandatool/src/win-stats/winStatsPianoRoll.h index 53ecf69ab7..a73c6c65d4 100755 --- a/pandatool/src/win-stats/winStatsPianoRoll.h +++ b/pandatool/src/win-stats/winStatsPianoRoll.h @@ -47,6 +47,10 @@ public: virtual void set_time_units(int unit_mask); void set_horizontal_scale(float time_width); + virtual void move_user_guide_bar(int n, float height); + virtual int add_user_guide_bar(float height); + virtual void remove_user_guide_bar(int n); + protected: void clear_region(); virtual void begin_draw(); @@ -57,9 +61,15 @@ protected: LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); virtual LONG graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); virtual void additional_window_paint(HDC hdc); + virtual void additional_graph_window_paint(HDC hdc); + virtual DragMode consider_drag_start(int mouse_x, int mouse_y, + int width, int height); private: void update_labels(); + void draw_guide_bar(HDC hdc, const GuideBar &bar); + void draw_guide_label(HDC hdc, int y, const PStatGraph::GuideBar &bar); + void create_window(); static void register_window_class(HINSTANCE application); diff --git a/pandatool/src/win-stats/winStatsStripChart.cxx b/pandatool/src/win-stats/winStatsStripChart.cxx index e2b8b160e2..a675caea68 100644 --- a/pandatool/src/win-stats/winStatsStripChart.cxx +++ b/pandatool/src/win-stats/winStatsStripChart.cxx @@ -154,6 +154,56 @@ set_vertical_scale(float value_height) { InvalidateRect(_window, &rect, TRUE); } +//////////////////////////////////////////////////////////////////// +// Function: WinStatsStripChart::move_user_guide_bar +// Access: Public, Virtual +// Description: Adjusts the height of the nth user-defined guide bar. +//////////////////////////////////////////////////////////////////// +void WinStatsStripChart:: +move_user_guide_bar(int n, float height) { + RECT rect; + GetClientRect(_window, &rect); + rect.left = _right_margin; + InvalidateRect(_window, &rect, TRUE); + + InvalidateRect(_graph_window, NULL, TRUE); + + PStatStripChart::move_user_guide_bar(n, height); +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsStripChart::add_user_guide_bar +// Access: Public, Virtual +// Description: Creates a new user guide bar and returns its index +// number. +//////////////////////////////////////////////////////////////////// +int WinStatsStripChart:: +add_user_guide_bar(float height) { + RECT rect; + GetClientRect(_window, &rect); + rect.left = _right_margin; + InvalidateRect(_window, &rect, TRUE); + + return PStatStripChart::add_user_guide_bar(height); +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsStripChart::remove_user_guide_bar +// Access: Public, Virtual +// Description: Removes the user guide bar with the indicated index +// number. All subsequent index numbers are adjusted +// down one. +//////////////////////////////////////////////////////////////////// +void WinStatsStripChart:: +remove_user_guide_bar(int n) { + RECT rect; + GetClientRect(_window, &rect); + rect.left = _right_margin; + InvalidateRect(_window, &rect, TRUE); + + return PStatStripChart::remove_user_guide_bar(n); +} + //////////////////////////////////////////////////////////////////// // Function: WinStatsStripChart::update_labels // Access: Protected, Virtual @@ -284,19 +334,7 @@ end_draw(int from_x, int to_x) { // Draw in the guide bars. int num_guide_bars = get_num_guide_bars(); for (int i = 0; i < num_guide_bars; i++) { - const GuideBar &bar = get_guide_bar(i); - int y = height_to_pixel(bar._height); - - if (y > 0) { - // Only draw it if it's not too close to the top. - if (bar._is_target) { - SelectObject(_bitmap_dc, _light_pen); - } else { - SelectObject(_bitmap_dc, _dark_pen); - } - MoveToEx(_bitmap_dc, from_x, y, NULL); - LineTo(_bitmap_dc, to_x + 1, y); - } + draw_guide_bar(_bitmap_dc, from_x, to_x, get_guide_bar(i)); } RECT rect = { @@ -312,12 +350,18 @@ end_draw(int from_x, int to_x) { //////////////////////////////////////////////////////////////////// LONG WinStatsStripChart:: window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - /* switch (msg) { + case WM_LBUTTONDOWN: + if (_potential_drag_mode == DM_new_guide_bar) { + _drag_mode = DM_new_guide_bar; + SetCapture(_graph_window); + return 0; + } + break; + default: break; } - */ return WinStatsGraph::window_proc(hwnd, msg, wparam, lparam); } @@ -331,13 +375,21 @@ LONG WinStatsStripChart:: graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { case WM_LBUTTONDOWN: - { + if (_potential_drag_mode == DM_none) { _drag_mode = DM_scale; PN_int16 y = HIWORD(lparam); _drag_scale_start = pixel_to_height(y); SetCapture(_graph_window); + return 0; + + } else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) { + _drag_mode = DM_guide_bar; + PN_int16 y = HIWORD(lparam); + _drag_start_y = y; + SetCapture(_graph_window); + return 0; } - return 0; + break; case WM_MOUSEMOVE: if (_drag_mode == DM_scale) { @@ -347,6 +399,22 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { set_vertical_scale(_drag_scale_start / ratio); } return 0; + + } else if (_drag_mode == DM_new_guide_bar) { + // We haven't created the new guide bar yet; we won't until the + // mouse comes within the graph's region. + PN_int16 y = HIWORD(lparam); + if (y >= 0 && y < get_ysize()) { + _drag_mode = DM_guide_bar; + _drag_guide_bar = + WinStatsGraph::_monitor->add_user_guide_bar(_thread_index, pixel_to_height(y)); + return 0; + } + + } else if (_drag_mode == DM_guide_bar) { + PN_int16 y = HIWORD(lparam); + WinStatsGraph::_monitor->move_user_guide_bar(_thread_index, _drag_guide_bar, pixel_to_height(y)); + return 0; } break; @@ -355,6 +423,17 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { _drag_mode = DM_none; ReleaseCapture(); return 0; + + } else if (_drag_mode == DM_guide_bar) { + PN_int16 y = HIWORD(lparam); + if (y < 0 || y >= get_ysize()) { + WinStatsGraph::_monitor->remove_user_guide_bar(_thread_index, _drag_guide_bar); + } else { + WinStatsGraph::_monitor->move_user_guide_bar(_thread_index, _drag_guide_bar, pixel_to_height(y)); + } + _drag_mode = DM_none; + ReleaseCapture(); + return 0; } break; @@ -375,24 +454,109 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { //////////////////////////////////////////////////////////////////// void WinStatsStripChart:: additional_window_paint(HDC hdc) { + // Draw in the labels for the guide bars. HFONT hfnt = (HFONT)GetStockObject(ANSI_VAR_FONT); SelectObject(hdc, hfnt); SetTextAlign(hdc, TA_LEFT | TA_TOP); SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, RGB(0, 0, 0)); RECT rect; GetClientRect(_window, &rect); int x = rect.right - _right_margin + 2; int last_y = -100; + int i; int num_guide_bars = get_num_guide_bars(); - for (int i = 0; i < num_guide_bars; i++) { - const GuideBar &bar = get_guide_bar(i); - last_y = draw_guide_label(hdc, x, bar._height, last_y); + for (i = 0; i < num_guide_bars; i++) { + last_y = draw_guide_label(hdc, x, get_guide_bar(i), last_y); } - draw_guide_label(hdc, x, get_vertical_scale(), last_y); + last_y = -100; + int num_user_guide_bars = get_num_user_guide_bars(); + for (i = 0; i < num_user_guide_bars; i++) { + last_y = draw_guide_label(hdc, x, get_user_guide_bar(i), last_y); + } + + GuideBar top_value = make_guide_bar(get_vertical_scale()); + draw_guide_label(hdc, x, top_value, last_y); +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsStripChart::additional_graph_window_paint +// Access: Protected, Virtual +// Description: This is called during the servicing of WM_PAINT; it +// gives a derived class opportunity to do some further +// painting into the window (the outer window, not the +// graph window). +//////////////////////////////////////////////////////////////////// +void WinStatsStripChart:: +additional_graph_window_paint(HDC hdc) { + int num_user_guide_bars = get_num_user_guide_bars(); + for (int i = 0; i < num_user_guide_bars; i++) { + draw_guide_bar(hdc, 0, get_xsize(), get_user_guide_bar(i)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsStripChart::consider_drag_start +// Access: Protected, Virtual +// Description: Based on the mouse position within the window's +// client area, look for draggable things the mouse +// might be hovering over and return the apprioprate +// DragMode enum or DM_none if nothing is indicated. +//////////////////////////////////////////////////////////////////// +WinStatsGraph::DragMode WinStatsStripChart:: +consider_drag_start(int mouse_x, int mouse_y, int width, int height) { + if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) { + if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) { + // See if the mouse is over a user-defined guide bar. + int y = mouse_y - _graph_top; + float from_height = pixel_to_height(y + 2); + float to_height = pixel_to_height(y - 2); + _drag_guide_bar = find_user_guide_bar(from_height, to_height); + if (_drag_guide_bar >= 0) { + return DM_guide_bar; + } + + } else { + // The mouse is above or below the graph; maybe create a new + // guide bar. + return DM_new_guide_bar; + } + } + + return WinStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height); +} + +//////////////////////////////////////////////////////////////////// +// Function: WinStatsStripChart::draw_guide_bar +// Access: Private +// Description: Draws the line for the indicated guide bar on the +// graph. +//////////////////////////////////////////////////////////////////// +void WinStatsStripChart:: +draw_guide_bar(HDC hdc, int from_x, int to_x, + const PStatGraph::GuideBar &bar) { + int y = height_to_pixel(bar._height); + + if (y > 0) { + // Only draw it if it's not too close to the top. + switch (bar._style) { + case GBS_target: + SelectObject(hdc, _light_pen); + break; + + case GBS_user: + SelectObject(hdc, _user_guide_bar_pen); + break; + + case GBS_normal: + SelectObject(hdc, _dark_pen); + break; + } + MoveToEx(hdc, from_x, y, NULL); + LineTo(hdc, to_x + 1, y); + } } //////////////////////////////////////////////////////////////////// @@ -404,15 +568,38 @@ additional_window_paint(HDC hdc) { // given. Returns the top pixel value of the new label. //////////////////////////////////////////////////////////////////// int WinStatsStripChart:: -draw_guide_label(HDC hdc, int x, float value, int last_y) { - int y = height_to_pixel(value); - string label = format_number(value, get_guide_bar_units(), - get_guide_bar_unit_name()); +draw_guide_label(HDC hdc, int x, const PStatGraph::GuideBar &bar, int last_y) { + switch (bar._style) { + case GBS_target: + SetTextColor(hdc, _light_color); + break; + + case GBS_user: + SetTextColor(hdc, _user_guide_bar_color); + break; + + case GBS_normal: + SetTextColor(hdc, _dark_color); + break; + } + + int y = height_to_pixel(bar._height); + const string &label = bar._label; SIZE size; GetTextExtentPoint32(hdc, label.data(), label.length(), &size); + if (bar._style != GBS_user) { + float from_height = pixel_to_height(y + size.cy / 2 + 1); + float to_height = pixel_to_height(y - size.cy / 2 - 1); + if (find_user_guide_bar(from_height, to_height) >= 0) { + // Omit the label: there's a user-defined guide bar in the same space. + return last_y; + } + } + int this_y = _graph_top + y - size.cy / 2; - if (last_y < this_y || last_y > this_y + size.cy) { + if (y >= 0 && y < get_ysize() && + (last_y < this_y || last_y > this_y + size.cy)) { TextOut(hdc, x, this_y, label.data(), label.length()); last_y = this_y; diff --git a/pandatool/src/win-stats/winStatsStripChart.h b/pandatool/src/win-stats/winStatsStripChart.h index 9e45d16fd8..d6c1f6d18b 100644 --- a/pandatool/src/win-stats/winStatsStripChart.h +++ b/pandatool/src/win-stats/winStatsStripChart.h @@ -47,6 +47,10 @@ public: virtual void set_time_units(int unit_mask); void set_vertical_scale(float value_height); + virtual void move_user_guide_bar(int n, float height); + virtual int add_user_guide_bar(float height); + virtual void remove_user_guide_bar(int n); + protected: virtual void update_labels(); @@ -60,9 +64,13 @@ protected: LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); virtual LONG graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); virtual void additional_window_paint(HDC hdc); + virtual void additional_graph_window_paint(HDC hdc); + virtual DragMode consider_drag_start(int mouse_x, int mouse_y, + int width, int height); private: - int draw_guide_label(HDC hdc, int x, float value, int last_y); + void draw_guide_bar(HDC hdc, int from_x, int to_x, const GuideBar &bar); + int draw_guide_label(HDC hdc, int x, const GuideBar &bar, int last_y); void create_window(); static void register_window_class(HINSTANCE application);