ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
cvMultiColumnHeaderView.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 #include <QAbstractItemModel>
11 #include <QHeaderView>
12 #include <QPainter>
13 
14 //-----------------------------------------------------------------------------
16  QWidget* parentObject)
17  : Superclass(orientation, parentObject) {
18  // When a section is resized, for section spanning multiple sections, we
19  // need to ensure that we repaint all sections in the span otherwise the
20  // text doesn't render correctly on adjacent section not being resized.
21  QObject::connect(
22  this, &QHeaderView::sectionResized,
23  [this](int logicalIndex, int, int) {
24  const auto span =
25  this->sectionSpan(this->visualIndex(logicalIndex));
26  if (span.first != span.second) {
27  const auto lspan =
28  QPair<int, int>(this->logicalIndex(span.first),
29  this->logicalIndex(span.second));
30  int start = this->sectionViewportPosition(lspan.first);
31  int end = this->sectionViewportPosition(lspan.second) +
32  this->sectionSize(lspan.second);
33  auto viewport = this->viewport();
34  if (this->orientation() == Qt::Horizontal &&
35  viewport != nullptr) {
36  viewport->update(start, 0, end, viewport->height());
37  } else {
38  viewport->update(0, start, viewport->width(), end);
39  }
40  }
41  });
42 }
43 
44 //-----------------------------------------------------------------------------
46 
47 //-----------------------------------------------------------------------------
48 QString cvMultiColumnHeaderView::sectionDisplayText(int logicalIndex) const {
49  auto amodel = this->model();
50  if (amodel) {
51  return amodel
52  ->headerData(logicalIndex, this->orientation(), Qt::DisplayRole)
53  .toString();
54  }
55  return QString();
56 }
57 
58 //-----------------------------------------------------------------------------
59 QPair<int, int> cvMultiColumnHeaderView::sectionSpan(int visual) const {
60  QPair<int, int> vrange(visual, visual);
61  const int logical = this->logicalIndex(visual);
62  const auto vlabel = this->sectionDisplayText(logical);
63  if (vlabel.isEmpty()) {
64  return vrange;
65  }
66 
67  // Look backwards for sections with the same label
68  for (int cc = vrange.first - 1; cc >= 0; --cc) {
69  const int clogical = this->logicalIndex(cc);
70  if (this->sectionDisplayText(clogical) == vlabel) {
71  vrange.first = cc;
72  } else {
73  break;
74  }
75  }
76 
77  // Look forwards for sections with the same label
78  for (int cc = vrange.second + 1, max = this->count(); cc < max; ++cc) {
79  const int clogical = this->logicalIndex(cc);
80  if (this->sectionDisplayText(clogical) == vlabel) {
81  vrange.second = cc;
82  } else {
83  break;
84  }
85  }
86  return vrange;
87 }
88 
89 //-----------------------------------------------------------------------------
91  const QRect& rect,
92  int logicalIndex) const {
93  if (!rect.isValid()) {
94  return;
95  }
96 
97  const int visual = this->visualIndex(logicalIndex);
98  const auto span = this->sectionSpan(visual);
99  if (span.first == span.second) {
100  // Single section - use default painting
101  this->Superclass::paintSection(painter, rect, logicalIndex);
102  } else {
103  // Multiple sections with same label - paint as merged header
104  if (this->isSortIndicatorShown()) {
105  // If sort indicator is shown and the indicator is being shown on
106  // one of the sections we have grouped together, we have to handle
107  // it specially. In such a case, we still want to paint the sort
108  // indicator for the entire section (we're ignoring that it still
109  // won't be obvious which component is being sorted by, but that's
110  // not a huge UX issue). To do that, we just paint the section with
111  // the sort indicator instead of the one being requested.
112  const int vSortIndicatorShown =
113  this->visualIndex(this->sortIndicatorSection());
114  if (span.first <= vSortIndicatorShown &&
115  span.second >= vSortIndicatorShown) {
116  logicalIndex = this->sortIndicatorSection();
117  }
118  }
119 
120  // Calculate the full rect spanning all sections in the group
121  QRect newrect(rect);
122  for (int cc = span.first; cc < visual; ++cc) {
123  const int cc_size = this->sectionSize(this->logicalIndex(cc));
124  newrect.adjust(-cc_size, 0, 0, 0);
125  }
126 
127  for (int cc = visual + 1; cc <= span.second; ++cc) {
128  const int cc_size = this->sectionSize(this->logicalIndex(cc));
129  newrect.adjust(0, 0, cc_size, 0);
130  }
131 
132  // Paint the merged section
133  this->Superclass::paintSection(painter, newrect, logicalIndex);
134  }
135 }
cvMultiColumnHeaderView(Qt::Orientation orientation, QWidget *parent=nullptr)
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override
~cvMultiColumnHeaderView() override