Browse Source

pstats: Make label stack scrollable on Windows if it runs off

rdb 3 years ago
parent
commit
b0a6e498e2

+ 16 - 3
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;
     }
 

+ 1 - 0
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;

+ 8 - 0
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.
  */

+ 1 - 0
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;

+ 65 - 8
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;
   }

+ 7 - 1
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<WinStatsLabel *> Labels;
   Labels _labels;

+ 1 - 0
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);