Files
renderdoc/qrenderdoc/Widgets/Extended/RDHeaderView.cpp
T
baldurk 24e1a8fc42 Add a new 'stretchy size hint' mode for RDHeaderView
* The basic idea here is to have a reasonable middleground between
  ResizeToContents and Stretch. We want to show at *least* enough for
  the contents, but the remaining space should be shared between the
  columns according to some proportions.
* That way you don't end up with one huge column and several tiny ones
  that are just big enough but no more, but all data is still visible.
2017-07-12 19:50:29 +01:00

940 lines
25 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2016-2017 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "RDHeaderView.h"
#include <QLabel>
#include <QMouseEvent>
#include <QPainter>
#include <QPixmap>
/////////////////////////////////////////////////////////////////////////////////
//
// this file contains a few hardcoded assumptions for my use case, especially
// with the 'custom sizing' mode that allows merging sections and pinning sections
// and so on.
//
// * No handling for moving/rearranging/hiding sections with the custom sizing
// mode. Just needs more careful handling and distinguishing between logical
// and visual indices.
// * Probably a few places vertical orientation isn't handled right, but that
// shouldn't be too bad.
//
/////////////////////////////////////////////////////////////////////////////////
RDHeaderView::RDHeaderView(Qt::Orientation orient, QWidget *parent) : QHeaderView(orient, parent)
{
m_sectionPreview = new QLabel(this);
setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
}
RDHeaderView::~RDHeaderView()
{
}
QSize RDHeaderView::sizeHint() const
{
if(!m_customSizing)
return QHeaderView::sizeHint();
return m_sizeHint;
}
void RDHeaderView::setModel(QAbstractItemModel *model)
{
QAbstractItemModel *m = this->model();
if(m)
{
QObject::disconnect(m, &QAbstractItemModel::headerDataChanged, this,
&RDHeaderView::headerDataChanged);
QObject::disconnect(m, &QAbstractItemModel::columnsInserted, this,
&RDHeaderView::columnsInserted);
QObject::disconnect(m, &QAbstractItemModel::rowsInserted, this, &RDHeaderView::rowsChanged);
QObject::disconnect(m, &QAbstractItemModel::rowsRemoved, this, &RDHeaderView::rowsChanged);
}
QHeaderView::setModel(model);
QObject::connect(model, &QAbstractItemModel::headerDataChanged, this,
&RDHeaderView::headerDataChanged);
QObject::connect(model, &QAbstractItemModel::columnsInserted, this, &RDHeaderView::columnsInserted);
QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &RDHeaderView::rowsChanged);
QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &RDHeaderView::rowsChanged);
}
void RDHeaderView::reset()
{
if(m_customSizing)
cacheSections();
}
void RDHeaderView::cacheSections()
{
if(m_suppressSectionCache)
return;
QAbstractItemModel *m = this->model();
int oldCount = m_sections.count();
m_sections.resize(m->columnCount());
// give new sections a default minimum size
for(int col = oldCount; col < m_sections.count(); col++)
m_sections[col].size = 10;
for(int col = 0; col < m_sections.count(); col++)
{
if(m_columnGroupRole > 0)
{
QVariant v = m->data(m->index(0, col), m_columnGroupRole);
if(v.isValid())
m_sections[col].group = v.toInt();
if(col > 0)
{
m_sections[col - 1].groupGap =
(m_sections[col].group != m_sections[col - 1].group) && m_sections[col].group >= 0;
}
}
else
{
m_sections[col].group = col;
m_sections[col].groupGap = true;
}
}
int accum = 0;
for(int col = 0; col < m_sections.count(); col++)
{
if(col == m_pinnedColumns)
m_pinnedWidth = accum;
m_sections[col].offset = accum;
accum += m_sections[col].size;
if(hasGroupGap(col))
accum += groupGapSize();
}
if(m_pinnedColumns >= m_sections.count())
m_pinnedWidth = m_pinnedColumns;
QStyleOptionHeader opt;
initStyleOption(&opt);
QFont f = font();
f.setBold(true);
opt.section = 0;
opt.fontMetrics = QFontMetrics(f);
opt.text = m->headerData(0, orientation(), Qt::DisplayRole).toString();
m_sizeHint = style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), this);
m_sizeHint.setWidth(accum);
viewport()->update(viewport()->rect());
}
int RDHeaderView::sectionSize(int logicalIndex) const
{
if(m_customSizing)
{
if(logicalIndex < 0 || logicalIndex >= m_sections.count())
return 0;
return m_sections[logicalIndex].size;
}
return QHeaderView::sectionSize(logicalIndex);
}
int RDHeaderView::sectionViewportPosition(int logicalIndex) const
{
if(m_customSizing)
{
if(logicalIndex < 0 || logicalIndex >= m_sections.count())
return -1;
int offs = m_sections[logicalIndex].offset;
if(logicalIndex >= m_pinnedColumns)
offs -= offset();
return offs;
}
return QHeaderView::sectionViewportPosition(logicalIndex);
}
int RDHeaderView::visualIndexAt(int position) const
{
if(m_customSizing)
{
if(m_sections.isEmpty())
return -1;
if(position >= m_pinnedWidth)
position += offset();
SectionData search;
search.offset = position;
auto it = std::lower_bound(
m_sections.begin(), m_sections.end(), search,
[this](const SectionData &a, const SectionData &b) { return a.offset <= b.offset; });
if(it != m_sections.begin())
--it;
if(it->offset <= position &&
position < (it->offset + it->size + (it->groupGap ? groupGapSize() : 0)))
return (it - m_sections.begin());
return -1;
}
return QHeaderView::visualIndexAt(position);
}
int RDHeaderView::logicalIndexAt(int position) const
{
return visualIndexAt(position);
}
int RDHeaderView::count() const
{
if(m_customSizing)
return m_sections.count();
return QHeaderView::count();
}
void RDHeaderView::resizeSection(int logicalIndex, int size)
{
if(!m_customSizing)
return QHeaderView::resizeSection(logicalIndex, size);
if(logicalIndex >= 0 && logicalIndex < m_sections.count())
{
int oldSize = m_sections[logicalIndex].size;
m_sections[logicalIndex].size = size;
emit sectionResized(logicalIndex, oldSize, size);
}
cacheSections();
}
void RDHeaderView::resizeSections(QHeaderView::ResizeMode mode)
{
if(!m_sectionStretchHints.isEmpty())
{
resizeSectionsWithHints();
return;
}
if(!m_customSizing)
return resizeSections(mode);
if(mode != ResizeToContents)
return;
QAbstractItemModel *m = this->model();
int rowCount = m->rowCount();
for(int col = 0; col < m_sections.count(); col++)
{
QSize sz;
for(int row = 0; row < rowCount; row++)
{
QVariant v = m->data(m->index(row, col), Qt::SizeHintRole);
if(v.isValid() && v.canConvert<QSize>())
sz = sz.expandedTo(v.value<QSize>());
}
int oldSize = m_sections[col].size;
m_sections[col].size = sz.width();
emit sectionResized(col, oldSize, sz.width());
}
}
void RDHeaderView::resizeSections(const QList<int> &sizes)
{
if(!m_customSizing)
{
for(int i = 0; i < qMin(sizes.count(), QHeaderView::count()); i++)
{
QHeaderView::resizeSection(i, sizes[i]);
}
return;
}
for(int i = 0; i < qMin(sizes.count(), m_sections.count()); i++)
{
int oldSize = m_sections[i].size;
m_sections[i].size = sizes[i];
emit sectionResized(i, oldSize, sizes[i]);
}
cacheSections();
}
bool RDHeaderView::hasGroupGap(int columnIndex) const
{
if(columnIndex >= 0 && columnIndex < m_sections.count())
return m_sections[columnIndex].groupGap;
return false;
}
bool RDHeaderView::hasGroupTitle(int columnIndex) const
{
if(columnIndex == m_sections.count() - 1)
return true;
if(columnIndex >= 0 && columnIndex < m_sections.count())
return m_sections[columnIndex].groupGap || m_sections[columnIndex].group < 0;
return false;
}
void RDHeaderView::cacheSectionMinSizes()
{
m_sectionMinSizes.resize(count());
m_sectionMinSizesTotal = 0;
for(int i = 0; i < m_sectionMinSizes.count(); i++)
{
int sz = 0;
// see if we can fetch the column/row size hint from the item view
QAbstractItemView *view = qobject_cast<QAbstractItemView *>(parent());
if(view)
{
if(orientation() == Qt::Horizontal)
sz = view->sizeHintForColumn(i);
else
sz = view->sizeHintForRow(i);
}
// also include the size for the header as another minimum
if(orientation() == Qt::Horizontal)
sz = qMax(sz, sectionSizeFromContents(i).width());
else
sz = qMax(sz, sectionSizeFromContents(i).height());
// finally respect the minimum section size specified
sz = qMax(sz, minimumSectionSize());
// update the minimum size for this section and count the total which we'll need
m_sectionMinSizes[i] = sz;
m_sectionMinSizesTotal += m_sectionMinSizes[i];
}
}
void RDHeaderView::resizeSectionsWithHints()
{
if(m_sectionMinSizes.count() == 0)
return;
QVector<int> sizes = m_sectionMinSizes;
int available = 0;
if(orientation() == Qt::Horizontal)
available = rect().width();
else
available = rect().height();
// see if we even have any extra space to allocate
if(available > m_sectionMinSizesTotal)
{
// this is how much space we can allocate to stretch sections
available -= m_sectionMinSizesTotal;
// distribute the available space between the sections. Dividing by the total stretch tells us
// how many 'whole' multiples we can allocate:
int wholeMultiples = available / m_sectionStretchHintTotal;
if(wholeMultiples > 0)
{
for(int i = 0; i < sizes.count() && i < m_sectionStretchHints.count(); i++)
{
int hint = m_sectionStretchHints[i];
if(hint > 0)
sizes[i] += wholeMultiples * hint;
}
}
available -= wholeMultiples * m_sectionStretchHintTotal;
// we now have a small amount (less than m_sectionStretchHintTotal) of extra space to allocate.
// we still want to assign this leftover proportional to the hints, otherwise we'd end up with a
// stair-stepping effect.
// To do this we calculate hint/total for each section then loop around adding on fractional
// components to the sizes until one is above 1, then it gets a pixel, and we keep going until
// all the remainder is allocated
QVector<float> fractions, increment;
fractions.resize(sizes.count());
increment.resize(sizes.count());
// set up increments
for(int i = 0; i < sizes.count(); i++)
{
// don't assign any space to sections with negative hints, or sections without hints
if(i >= m_sectionStretchHints.count() || m_sectionStretchHints[i] <= 0)
{
increment[i] = 0.0f;
continue;
}
increment[i] = float(m_sectionStretchHints[i]) / float(m_sectionStretchHintTotal);
}
while(available > 0)
{
// loop along each section incrementing it.
for(int i = 0; i < fractions.count(); i++)
{
fractions[i] += increment[i];
// if we have a whole pixel now, assign it
if(fractions[i] > 1.0f)
{
fractions[i] -= 1.0f;
sizes[i]++;
available--;
// if we've assigned all pixels, stop
if(available == 0)
break;
}
}
}
for(int pix = 0; pix < available; pix++)
{
int minSection = 0;
for(int i = 1; i < sizes.count(); i++)
{
// don't assign any space to sections with negative hints
if(i < m_sectionStretchHints.count() && m_sectionStretchHints[i] <= 0)
continue;
if(sizes[i] < sizes[minSection])
minSection = i;
}
sizes[minSection]++;
}
}
resizeSections(sizes.toList());
}
void RDHeaderView::setColumnStretchHints(const QList<int> &hints)
{
if(hints.count() != count())
qCritical() << "Got" << hints.count() << "hints, but have" << count() << "columns";
m_sectionStretchHints = hints;
m_sectionStretchHintTotal = 0;
for(int h : m_sectionStretchHints)
{
if(h > 0)
m_sectionStretchHintTotal += h;
}
// we take control of the sizing, we don't currently support custom resizing AND stretchy size
// hints.
QHeaderView::setSectionResizeMode(QHeaderView::Fixed);
cacheSectionMinSizes();
resizeSectionsWithHints();
}
void RDHeaderView::headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast)
{
if(m_customSizing)
cacheSections();
}
void RDHeaderView::columnsInserted(const QModelIndex &parent, int first, int last)
{
if(m_customSizing)
cacheSections();
}
void RDHeaderView::rowsChanged(const QModelIndex &parent, int first, int last)
{
if(!m_sectionStretchHints.isEmpty())
{
cacheSectionMinSizes();
resizeSectionsWithHints();
}
}
void RDHeaderView::mousePressEvent(QMouseEvent *event)
{
int mousePos = event->x();
int idx = logicalIndexAt(mousePos);
if(sectionsMovable() && idx >= 0 && event->buttons() == Qt::LeftButton)
{
int secSize = sectionSize(idx);
int secPos = sectionViewportPosition(idx);
int handleWidth = style()->pixelMetric(QStyle::PM_HeaderGripMargin, 0, this);
if(secPos >= 0 && secSize > 0 && mousePos >= secPos + handleWidth &&
mousePos <= secPos + secSize - handleWidth)
{
m_movingSection = idx;
m_sectionPreview->resize(secSize, height());
QPixmap preview(m_sectionPreview->size());
preview.fill(QColor::fromRgba(qRgba(0, 0, 0, 100)));
QPainter painter(&preview);
painter.setOpacity(0.75f);
paintSection(&painter, QRect(QPoint(0, 0), m_sectionPreview->size()), idx);
painter.end();
m_sectionPreview->setPixmap(preview);
m_sectionPreviewOffset = mousePos - secPos;
m_sectionPreview->move(mousePos - m_sectionPreviewOffset, 0);
m_sectionPreview->show();
return;
}
}
if(m_customSizing)
{
m_resizeState = checkResizing(event);
m_cursorPos = QCursor::pos().x();
return QAbstractItemView::mousePressEvent(event);
}
QHeaderView::mousePressEvent(event);
}
void RDHeaderView::mouseMoveEvent(QMouseEvent *event)
{
if(m_movingSection >= 0)
{
m_sectionPreview->move(event->x() - m_sectionPreviewOffset, 0);
return;
}
if(m_customSizing)
{
if(m_resizeState.first == NoResize || m_resizeState.second < 0 ||
m_resizeState.second >= m_sections.count())
{
auto res = checkResizing(event);
bool hasCursor = testAttribute(Qt::WA_SetCursor);
if(res.first != NoResize)
{
if(!hasCursor)
setCursor(Qt::SplitHCursor);
}
else if(hasCursor)
{
unsetCursor();
}
}
else
{
int curX = QCursor::pos().x();
int delta = curX - m_cursorPos;
int idx = m_resizeState.second;
if(m_resizeState.first == LeftResize && idx > 0)
idx--;
// batch the cache update
m_suppressSectionCache = true;
int firstCol = idx;
int lastCol = idx;
// idx is the last in a group, so search backwards to see if there are neighbour sections we
// should share the resize with
while(firstCol > 0 && m_sections[firstCol - 1].group == m_sections[lastCol].group)
firstCol--;
// how much space could we lose on the columns, in total
int freeSpace = 0;
for(int col = firstCol; col <= lastCol; col++)
freeSpace += m_sections[col].size - minimumSectionSize();
int numCols = lastCol - firstCol + 1;
// spread the delta amonst the colummns
int perSectionDelta = delta / numCols;
// call resizeSection to emit the sectionResized signal but we set m_suppressSectionCache so
// we won't cache sections.
for(int col = firstCol; col <= lastCol; col++)
resizeSection(col, qMax(minimumSectionSize(), m_sections[col].size + perSectionDelta));
// if there was an uneven spread, a few pixels will remain
int remainder = delta - perSectionDelta * numCols;
// loop around for the remainder pixels, assigning them one by one to the smallest/largest
// column.
// this is inefficient but remainder is very small - at most 3.
int step = remainder < 0 ? -1 : 1;
for(int i = 0; i < qAbs(remainder); i++)
{
int chosenCol = firstCol;
for(int col = firstCol; col <= lastCol; col++)
{
if(step > 0 && m_sections[col].size < m_sections[chosenCol].size)
chosenCol = col;
else if(step < 0 && m_sections[col].size > m_sections[chosenCol].size)
chosenCol = col;
}
resizeSection(chosenCol, qMax(minimumSectionSize(), m_sections[chosenCol].size + step));
}
// only updating the cursor when the section is moving means that it becomes 'sticky'. If we
// try to size down below the minimum size and keep going then it doesn't start resizing up
// until it passes the divider again.
int appliedDelta = delta;
// if we were resizing down, at best we removed the remaining free space
if(delta < 0)
appliedDelta = qMax(delta, -freeSpace);
m_cursorPos += appliedDelta;
m_suppressSectionCache = false;
cacheSections();
}
return QAbstractItemView::mouseMoveEvent(event);
}
QHeaderView::mouseMoveEvent(event);
}
QPair<RDHeaderView::ResizeType, int> RDHeaderView::checkResizing(QMouseEvent *event)
{
int mousePos = event->x();
int idx = logicalIndexAt(mousePos);
bool hasCursor = testAttribute(Qt::WA_SetCursor);
bool cursorSet = false;
bool leftResize = idx > 0 && (m_sections[idx - 1].group != m_sections[idx].group);
bool rightResize = idx >= 0 && hasGroupTitle(idx);
if(leftResize || rightResize)
{
int secSize = sectionSize(idx);
int secPos = sectionViewportPosition(idx);
int handleWidth = style()->pixelMetric(QStyle::PM_HeaderGripMargin, 0, this);
int gapWidth = 0;
if(hasGroupGap(idx))
gapWidth = groupGapSize();
if(leftResize && secPos >= 0 && secSize > 0 && mousePos < secPos + handleWidth)
{
return qMakePair(LeftResize, idx);
}
if(rightResize && secPos >= 0 && secSize > 0 &&
mousePos > secPos + secSize - handleWidth - gapWidth)
{
return qMakePair(RightResize, idx);
}
}
return qMakePair(NoResize, -1);
}
void RDHeaderView::mouseReleaseEvent(QMouseEvent *event)
{
if(m_movingSection >= 0)
{
int mousePos = event->x();
int idx = logicalIndexAt(mousePos);
if(idx >= 0)
{
int secSize = sectionSize(idx);
int secPos = sectionPosition(idx);
int srcSection = visualIndex(m_movingSection);
int dstSection = visualIndex(idx);
if(srcSection >= 0 && dstSection >= 0 && srcSection != dstSection)
{
// the half-way point of the section decides whether we're dropping to the left
// or the right of it.
if(mousePos < secPos + secSize / 2)
{
// if we're moving from the left, place it to the left of dstSection
if(srcSection < dstSection)
moveSection(srcSection, dstSection - 1);
else
moveSection(srcSection, dstSection);
}
else
{
// if we're moving it from the right, place it to the right of dstSection
if(srcSection > dstSection)
moveSection(srcSection, dstSection + 1);
else
moveSection(srcSection, dstSection);
}
}
}
m_sectionPreview->hide();
}
m_movingSection = -1;
if(m_customSizing)
{
m_resizeState = qMakePair(NoResize, -1);
return QAbstractItemView::mouseReleaseEvent(event);
}
QHeaderView::mouseReleaseEvent(event);
}
void RDHeaderView::paintEvent(QPaintEvent *e)
{
if(!m_customSizing)
return QHeaderView::paintEvent(e);
if(count() == 0)
return;
QPainter painter(viewport());
int start = qMax(visualIndexAt(e->rect().left()), 0);
int end = visualIndexAt(e->rect().right());
if(end == -1)
end = count() - 1;
// make sure we always paint the whole header for any merged headers
while(start > 0 && !hasGroupTitle(start - 1))
start--;
while(end < m_sections.count() && !hasGroupTitle(end))
end++;
QRect accumRect;
for(int i = start; i <= end; ++i)
{
int pos = sectionViewportPosition(i);
int size = sectionSize(i);
if(!hasGroupGap(i) && pos < 0)
{
size += pos;
pos = 0;
}
// either set or accumulate this section's rect
if(accumRect.isEmpty())
accumRect.setRect(pos, 0, size, viewport()->height());
else
accumRect.setWidth(accumRect.width() + size);
if(hasGroupTitle(i))
{
painter.save();
accumRect.setWidth(accumRect.width() - 1);
if(accumRect.left() < m_pinnedWidth && i >= m_pinnedColumns)
accumRect.setLeft(m_pinnedWidth);
paintSection(&painter, accumRect, i);
painter.restore();
// if we have more sections to go, reset so we can accumulate the next group
if(i < end)
accumRect = QRect();
}
}
// clear the remainder of the header if there's a gap
if(accumRect.right() < e->rect().right())
{
QStyleOption opt;
opt.init(this);
opt.state |= QStyle::State_Horizontal;
opt.rect =
QRect(accumRect.right() + 1, 0, e->rect().right() - accumRect.right(), viewport()->height());
style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
}
}
void RDHeaderView::paintSection(QPainter *painter, const QRect &rect, int section) const
{
if(!m_customSizing)
return QHeaderView::paintSection(painter, rect, section);
if(!rect.isValid())
return;
QStyleOptionHeader opt;
initStyleOption(&opt);
QAbstractItemModel *m = this->model();
if(hasFocus())
opt.state |= (QStyle::State_Active | QStyle::State_HasFocus);
else
opt.state &= ~(QStyle::State_Active | QStyle::State_HasFocus);
QVariant textAlignment = m->headerData(section, orientation(), Qt::TextAlignmentRole);
opt.rect = rect;
opt.section = section;
opt.textAlignment = defaultAlignment();
opt.iconAlignment = Qt::AlignVCenter;
QVariant variant;
if(m_columnGroupRole)
{
variant = m->headerData(section, orientation(), m_columnGroupRole);
if(variant.isValid() && variant.canConvert<QString>())
opt.text = variant.toString();
}
if(opt.text.isEmpty())
opt.text = m->headerData(section, orientation(), Qt::DisplayRole).toString();
int margin = 2 * style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this);
if(textElideMode() != Qt::ElideNone)
opt.text = opt.fontMetrics.elidedText(opt.text, textElideMode(), rect.width() - margin);
if(section == 0 && section == m_sections.count() - 1)
opt.position = QStyleOptionHeader::OnlyOneSection;
else if(section == 0)
opt.position = QStyleOptionHeader::Beginning;
else if(section == m_sections.count() - 1)
opt.position = QStyleOptionHeader::End;
else
opt.position = QStyleOptionHeader::Middle;
opt.orientation = orientation();
bool prevSel = section > 0 && selectionModel()->isColumnSelected(section - 1, QModelIndex());
bool nextSel = section + 1 < m_sections.count() &&
selectionModel()->isColumnSelected(section + 1, QModelIndex());
if(prevSel && nextSel)
opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
else if(prevSel)
opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
else if(nextSel)
opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
else
opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
style()->drawControl(QStyle::CE_Header, &opt, painter, this);
}
void RDHeaderView::currentChanged(const QModelIndex &current, const QModelIndex &old)
{
if(!m_customSizing)
return QHeaderView::currentChanged(current, old);
// not optimal at all
if(current != old)
{
QRect r = viewport()->rect();
if(old.isValid())
{
QRect rect = r;
if(orientation() == Qt::Horizontal)
{
rect.setLeft(sectionViewportPosition(old.column()));
rect.setWidth(sectionSize(old.column()));
}
else
{
rect.setTop(sectionViewportPosition(old.column()));
rect.setHeight(sectionSize(old.column()));
}
viewport()->update(rect);
}
if(current.isValid())
{
QRect rect = r;
if(orientation() == Qt::Horizontal)
{
rect.setLeft(sectionViewportPosition(current.column()));
rect.setWidth(sectionSize(current.column()));
}
else
{
rect.setTop(sectionViewportPosition(current.column()));
rect.setHeight(sectionSize(current.column()));
}
viewport()->update(rect);
}
}
}
void RDHeaderView::updateGeometries()
{
if(!m_sectionStretchHints.isEmpty())
resizeSectionsWithHints();
QHeaderView::updateGeometries();
}