From b0a6e498e2f2ee78b1725ab3b39e6ce5cff56cad Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 29 Nov 2022 23:47:07 +0100 Subject: [PATCH] pstats: Make label stack scrollable on Windows if it runs off --- pandatool/src/win-stats/winStatsGraph.cxx | 19 ++++- pandatool/src/win-stats/winStatsGraph.h | 1 + pandatool/src/win-stats/winStatsLabel.cxx | 8 ++ pandatool/src/win-stats/winStatsLabel.h | 1 + .../src/win-stats/winStatsLabelStack.cxx | 73 +++++++++++++++++-- pandatool/src/win-stats/winStatsLabelStack.h | 8 +- pandatool/src/win-stats/winStatsPianoRoll.cxx | 1 + 7 files changed, 99 insertions(+), 12 deletions(-) diff --git a/pandatool/src/win-stats/winStatsGraph.cxx b/pandatool/src/win-stats/winStatsGraph.cxx index 24808ba9bc..a363a91805 100644 --- a/pandatool/src/win-stats/winStatsGraph.cxx +++ b/pandatool/src/win-stats/winStatsGraph.cxx @@ -47,6 +47,14 @@ WinStatsGraph(WinStatsMonitor *monitor) : _pixel_scale = monitor->get_pixel_scale(); + // Default margins. + int margin = _pixel_scale * 2; + _left_margin = margin; + _right_margin = margin; + _top_margin = margin; + _bottom_margin = margin; + _top_label_stack_margin = margin; + _dark_color = RGB(51, 51, 51); _light_color = RGB(154, 154, 154); _user_guide_bar_color = RGB(130, 150, 255); @@ -253,10 +261,10 @@ move_label_stack() { rect.left += _pixel_scale * 2; rect.right = _left_margin - _pixel_scale * 2; - rect.bottom -= _bottom_margin; _label_stack.set_pos(rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top); + rect.right - rect.left, rect.bottom - rect.top, + _top_label_stack_margin, _bottom_margin); } } @@ -410,12 +418,17 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { WINDOWINFO winfo; GetWindowInfo(hwnd, &winfo); MINMAXINFO &minmax = *(MINMAXINFO *)lparam; + int vminheight = _bottom_margin + _top_margin; + if (_label_stack.get_num_labels() > 0) { + // If we have a label, make sure at least one can be shown. + vminheight = (std::max)(vminheight, _top_label_stack_margin + _label_stack.get_label_height(0) + _bottom_margin); + } minmax.ptMinTrackSize.x = (winfo.rcClient.left - winfo.rcWindow.left) + (winfo.rcWindow.right - winfo.rcClient.right) + (_right_margin + _left_margin); minmax.ptMinTrackSize.y = (winfo.rcClient.top - winfo.rcWindow.top) + (winfo.rcWindow.bottom - winfo.rcClient.bottom) - + (_bottom_margin + _top_margin); + + vminheight; return 0; } diff --git a/pandatool/src/win-stats/winStatsGraph.h b/pandatool/src/win-stats/winStatsGraph.h index 7c1b286cb1..e1a9f21938 100644 --- a/pandatool/src/win-stats/winStatsGraph.h +++ b/pandatool/src/win-stats/winStatsGraph.h @@ -125,6 +125,7 @@ protected: int _bitmap_xsize, _bitmap_ysize; int _left_margin, _right_margin; int _top_margin, _bottom_margin; + int _top_label_stack_margin; int _pixel_scale; COLORREF _dark_color; diff --git a/pandatool/src/win-stats/winStatsLabel.cxx b/pandatool/src/win-stats/winStatsLabel.cxx index 93d81f9531..007f7505d5 100644 --- a/pandatool/src/win-stats/winStatsLabel.cxx +++ b/pandatool/src/win-stats/winStatsLabel.cxx @@ -109,6 +109,14 @@ set_pos(int x, int y, int width) { } } +/** + * Changes the Y attribute without updating the window. + */ +void WinStatsLabel:: +set_y_noupdate(int y) { + _y = y; +} + /** * Enables or disables the visual highlight for this label. */ diff --git a/pandatool/src/win-stats/winStatsLabel.h b/pandatool/src/win-stats/winStatsLabel.h index c4478dc61d..3ad3b39353 100644 --- a/pandatool/src/win-stats/winStatsLabel.h +++ b/pandatool/src/win-stats/winStatsLabel.h @@ -38,6 +38,7 @@ public: void setup(HWND parent_window); void set_pos(int x, int y, int width); + void set_y_noupdate(int y); INLINE int get_x() const; INLINE int get_y() const; diff --git a/pandatool/src/win-stats/winStatsLabelStack.cxx b/pandatool/src/win-stats/winStatsLabelStack.cxx index 8303cb0ec6..be3a5971c4 100644 --- a/pandatool/src/win-stats/winStatsLabelStack.cxx +++ b/pandatool/src/win-stats/winStatsLabelStack.cxx @@ -75,19 +75,17 @@ is_setup() const { * Sets the position and size of the label stack on its parent. */ void WinStatsLabelStack:: -set_pos(int x, int y, int width, int height) { +set_pos(int x, int y, int width, int height, int top_margin, int bottom_margin) { _x = x; _y = y; _width = width; _height = height; + _top_margin = top_margin; + _bottom_margin = bottom_margin; SetWindowPos(_window, 0, x, y, _width, _height, SWP_NOZORDER | SWP_SHOWWINDOW); - int yp = height; - for (WinStatsLabel *label : _labels) { - label->set_pos(0, yp, _width); - yp -= label->get_height(); - } + recalculate_label_positions(); } /** @@ -168,6 +166,7 @@ clear_labels() { } _labels.clear(); _ideal_width = 0; + _scroll = 0; } /** @@ -185,13 +184,15 @@ add_label(WinStatsMonitor *monitor, WinStatsGraph *graph, new WinStatsLabel(monitor, graph, thread_index, collector_index, use_fullname); if (_window) { label->setup(_window); - label->set_pos(0, yp, _width); + label->set_pos(0, yp - _scroll, _width); } _ideal_width = std::max(_ideal_width, label->get_ideal_width()); int label_index = (int)_labels.size(); _labels.push_back(label); + recalculate_label_positions(); + return label_index; } @@ -265,7 +266,7 @@ replace_labels(WinStatsMonitor *monitor, WinStatsGraph *graph, label_map.erase(it); } if (_window) { - label->set_pos(0, yp, _width); + label->set_pos(0, yp - _scroll, _width); } _ideal_width = std::max(_ideal_width, label->get_ideal_width()); yp -= label->get_height(); @@ -277,6 +278,8 @@ replace_labels(WinStatsMonitor *monitor, WinStatsGraph *graph, for (auto it = label_map.begin(); it != label_map.end(); ++it) { delete it->second; } + + recalculate_label_positions(); } /** @@ -315,6 +318,33 @@ update_label_color(int collector_index) { } } +/** + * Called to recalculate the positions of all labels in the stack. + */ +void WinStatsLabelStack:: +recalculate_label_positions() { + int total_height = 0; + for (WinStatsLabel *label : _labels) { + total_height += label->get_height(); + } + total_height += _bottom_margin + _top_margin; + int yp; + if (total_height <= _height) { + // Fits. Align to bottom and reset scroll. + yp = _height - _bottom_margin; + _scroll = 0; + } else { + // Doesn't fit. Align to top. + yp = total_height - _bottom_margin; + _scroll = (std::min)(_scroll, total_height - _height); + _scroll = (std::max)(_scroll, 0); + } + for (WinStatsLabel *label : _labels) { + label->set_pos(0, yp - _scroll, _width); + yp -= label->get_height(); + } +} + /** * Creates the window for this stack. */ @@ -400,6 +430,33 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { return 0; } + case WM_MOUSEWHEEL: + { + int total_height = 0; + for (WinStatsLabel *label : _labels) { + total_height += label->get_height(); + } + total_height += _bottom_margin + _top_margin; + if ((total_height > _height || _scroll != 0) && !_labels.empty()) { + int delta = GET_WHEEL_DELTA_WPARAM(wparam); + delta = (delta * _labels[0]->get_height()) / 120; + int new_scroll = _scroll - delta; + new_scroll = (std::min)(new_scroll, total_height - _height); + new_scroll = (std::max)(new_scroll, 0); + delta = new_scroll - _scroll; + if (delta != 0) { + _scroll = new_scroll; + ScrollWindowEx(_window, 0, -delta, NULL, NULL, NULL, NULL, SW_INVALIDATE | SW_SCROLLCHILDREN); + int yp = yp = total_height - _bottom_margin; + for (WinStatsLabel *label : _labels) { + label->set_y_noupdate(yp - _scroll); + yp -= label->get_height(); + } + } + } + return 0; + } + default: break; } diff --git a/pandatool/src/win-stats/winStatsLabelStack.h b/pandatool/src/win-stats/winStatsLabelStack.h index 748522e401..3223900613 100644 --- a/pandatool/src/win-stats/winStatsLabelStack.h +++ b/pandatool/src/win-stats/winStatsLabelStack.h @@ -37,7 +37,8 @@ public: void setup(HWND parent_window); bool is_setup() const; - void set_pos(int x, int y, int width, int height); + void set_pos(int x, int y, int width, int height, + int top_margin, int bottom_margin); int get_x() const; int get_y() const; @@ -61,6 +62,8 @@ public: void update_label_color(int collector_index); private: + void recalculate_label_positions(); + void create_window(HWND parent_window); static void register_window_class(HINSTANCE application); @@ -74,6 +77,9 @@ private: int _height; int _ideal_width; int _highlight_label; + int _top_margin = 0; + int _bottom_margin = 0; + int _scroll = 0; typedef pvector Labels; Labels _labels; diff --git a/pandatool/src/win-stats/winStatsPianoRoll.cxx b/pandatool/src/win-stats/winStatsPianoRoll.cxx index bb118f3039..97cbbf887c 100644 --- a/pandatool/src/win-stats/winStatsPianoRoll.cxx +++ b/pandatool/src/win-stats/winStatsPianoRoll.cxx @@ -35,6 +35,7 @@ WinStatsPianoRoll(WinStatsMonitor *monitor, int thread_index) : _right_margin = _pixel_scale * 2; _top_margin = _pixel_scale * 5; _bottom_margin = _pixel_scale * 2; + _top_label_stack_margin = _pixel_scale * 5; // Let's show the units on the guide bar labels. There's room. set_guide_bar_units(get_guide_bar_units() | GBU_show_units);