Go back to manually drawing PE_PanelItemViewItem in drawBranches()

* There's a messy order-of-operations thing to deal with various
  different themes, as well as a couple of minor problems, but at least
  the highlight and selection bars draw fairly consistently and don't
  leave an ugly gap over the branches.
This commit is contained in:
baldurk
2017-06-02 17:30:41 +01:00
parent d426020321
commit 0c3dec3b67
4 changed files with 87 additions and 38 deletions
+51 -16
View File
@@ -23,21 +23,10 @@
******************************************************************************/
#include "RDTreeView.h"
#include <QMouseEvent>
#include <QPainter>
#include <QProxyStyle>
class RDTreeViewtyleProxy : public QProxyStyle
{
public:
int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0,
QStyleHintReturn *returnData = 0) const
{
if(hint == QStyle::SH_ItemView_ShowDecorationSelected)
return 1;
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
};
RDTreeViewDelegate::RDTreeViewDelegate(RDTreeView *view) : QStyledItemDelegate(view), m_View(view)
{
}
@@ -62,11 +51,24 @@ QSize RDTreeViewDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo
RDTreeView::RDTreeView(QWidget *parent) : QTreeView(NULL)
{
setItemDelegate(new RDTreeViewDelegate(this));
setMouseTracking(true);
// set a proxy style that does nothing but return true for
// QStyle::SH_ItemView_ShowDecorationSelected styleHint.
setStyle(new RDTreeViewtyleProxy);
setItemDelegate(new RDTreeViewDelegate(this));
}
void RDTreeView::mouseMoveEvent(QMouseEvent *e)
{
m_currentHoverIndex = indexAt(e->pos());
}
void RDTreeView::leaveEvent(QEvent *e)
{
m_currentHoverIndex = QModelIndex();
}
void RDTreeView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
m_currentHoverIndex = QModelIndex();
}
void RDTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &options,
@@ -115,8 +117,41 @@ void RDTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &options,
}
}
void RDTreeView::fillBranchesRect(QPainter *painter, const QRect &rect, const QModelIndex &index) const
{
QStyleOptionViewItem opt;
opt.initFrom(this);
if(selectionModel()->isSelected(index))
opt.state |= QStyle::State_Selected;
if(m_currentHoverIndex.row() == index.row() && m_currentHoverIndex.parent() == index.parent())
opt.state |= QStyle::State_MouseOver;
else
opt.state &= ~QStyle::State_MouseOver;
if(hasFocus())
opt.state |= (QStyle::State_Active | QStyle::State_HasFocus);
else
opt.state &= ~(QStyle::State_Active | QStyle::State_HasFocus);
int depth = 1;
QModelIndex idx = index.parent();
while(idx.isValid())
{
depth++;
idx = idx.parent();
}
opt.rect = rect;
opt.rect.setWidth(depth * indentation());
opt.showDecorationSelected = true;
style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, this);
}
void RDTreeView::drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const
{
if(m_fillBranchRect)
fillBranchesRect(painter, rect, index);
if(m_VisibleBranches)
{
QTreeView::drawBranches(painter, rect, index);
+10
View File
@@ -54,15 +54,25 @@ public:
void setItemVerticalMargin(int vertical) { m_VertMargin = vertical; }
int verticalItemMargin() { return m_VertMargin; }
protected:
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
void mouseMoveEvent(QMouseEvent *e) override;
void leaveEvent(QEvent *e) override;
void drawRow(QPainter *painter, const QStyleOptionViewItem &options,
const QModelIndex &index) const override;
void drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const override;
void fillBranchesRect(QPainter *painter, const QRect &rect, const QModelIndex &index) const;
void enableBranchRectFill(bool fill) { m_fillBranchRect = fill; }
QModelIndex m_currentHoverIndex;
private:
bool m_VisibleBranches = true;
bool m_VisibleGridLines = true;
int m_VertMargin = 6;
bool m_fillBranchRect = true;
friend class RDTreeViewDelegate;
};
+26 -20
View File
@@ -176,7 +176,7 @@ public:
{
if(widget->m_hoverColumn == index.column())
{
if(widget->m_currentHoverItem == item)
if(itemForIndex(widget->m_currentHoverIndex) == item)
return widget->m_activeHoverIcon;
else
return widget->m_normalHoverIcon;
@@ -187,12 +187,12 @@ public:
}
else if(role == Qt::BackgroundRole)
{
// item's background color takes priority
if(item->m_back != QBrush())
// item's background color takes priority but only if not selected
if(item->m_back != QBrush() && !widget->selectionModel()->isSelected(index))
return item->m_back;
// otherwise if we're hover-highlighting, use the highlight color at 20% opacity
if(widget->m_currentHoverItem == item)
if(itemForIndex(widget->m_currentHoverIndex) == item && widget->m_hoverColumn >= 0)
{
QColor col = widget->palette().color(QPalette::Highlight);
col.setAlphaF(0.2f);
@@ -410,9 +410,11 @@ void RDTreeWidgetItem::clear()
if(m_widget)
m_widget->m_model->endRemoveChildren();
}
RDTreeWidget::RDTreeWidget(QWidget *parent) : RDTreeView(parent)
{
setMouseTracking(true);
// we'll call this ourselves in drawBranches()
RDTreeView::enableBranchRectFill(false);
m_root = new RDTreeWidgetItem;
m_root->m_widget = this;
@@ -558,31 +560,31 @@ void RDTreeWidget::clear()
void RDTreeWidget::mouseMoveEvent(QMouseEvent *e)
{
QModelIndex idx = indexAt(e->pos());
RDTreeWidgetItem *item = m_model->itemForIndex(idx);
RDTreeWidgetItem *oldHover = m_model->itemForIndex(m_currentHoverIndex);
if(idx.column() == m_hoverColumn && m_hoverHandCursor)
RDTreeView::mouseMoveEvent(e);
RDTreeWidgetItem *newHover = m_model->itemForIndex(m_currentHoverIndex);
if(m_currentHoverIndex.column() == m_hoverColumn && m_hoverHandCursor)
setCursor(QCursor(Qt::PointingHandCursor));
else
unsetCursor();
if(m_currentHoverItem == item || m_hoverColumn < 0)
if(oldHover == newHover)
return;
RDTreeWidgetItem *old = m_currentHoverItem;
m_currentHoverItem = item;
// it's only two items, don't try and make a range but just change them both
QVector<int> roles = {Qt::DecorationRole, Qt::BackgroundRole, Qt::ForegroundRole};
if(old)
m_model->itemChanged(old, roles);
m_model->itemChanged(item, roles);
if(oldHover)
m_model->itemChanged(oldHover, roles);
m_model->itemChanged(newHover, roles);
if(m_instantTooltips)
{
QToolTip::hideText();
if(m_currentHoverItem != NULL && !m_currentHoverItem->m_tooltip.isEmpty())
if(newHover && !newHover->m_tooltip.isEmpty())
{
// the documentation says:
//
@@ -594,7 +596,7 @@ void RDTreeWidget::mouseMoveEvent(QMouseEvent *e)
// immediately show, it will try to reuse the tooltip and end up not moving it at all if the
// text hasn't changed.
QToolTip::showText(QCursor::pos(), lit(" "), this);
QToolTip::showText(QCursor::pos(), m_currentHoverItem->m_tooltip, this);
QToolTip::showText(QCursor::pos(), newHover->m_tooltip, this);
}
}
@@ -619,12 +621,11 @@ void RDTreeWidget::leaveEvent(QEvent *e)
{
unsetCursor();
if(m_currentHoverItem)
if(m_currentHoverIndex.isValid())
{
RDTreeWidgetItem *item = m_currentHoverItem;
RDTreeWidgetItem *item = m_model->itemForIndex(m_currentHoverIndex);
if(!item->m_tooltip.isEmpty() && m_instantTooltips)
QToolTip::hideText();
m_currentHoverItem = NULL;
m_model->itemChanged(item, {Qt::DecorationRole, Qt::BackgroundRole, Qt::ForegroundRole});
}
@@ -729,6 +730,11 @@ void RDTreeWidget::drawBranches(QPainter *painter, const QRect &rect, const QMod
// behind the tree lines.
QRect allLinesRect(rect.left(), rect.top(), (parents.count() + 1) * indentation(), rect.height());
// calling this manually here means it won't be called later in RDTreeView::drawBranches, and
// allows us to overwrite it with our background filling if we want to.
RDTreeWidget::fillBranchesRect(painter, rect, index);
if(!selectionModel()->isSelected(index) && item->m_back != QBrush())
{
painter->fillRect(allLinesRect, item->m_back);
@@ -241,8 +241,6 @@ private:
QPair<int, int> m_highestIndex;
uint64_t m_queuedRoles;
RDTreeWidgetItem *m_currentHoverItem = NULL;
bool m_instantTooltips = false;
bool m_customCopyPaste = false;
int m_hoverColumn = -1;