From 0c3dec3b67736cd9bb0debfe66b116b28e25c3c6 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 2 Jun 2017 17:30:41 +0100 Subject: [PATCH] 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. --- qrenderdoc/Widgets/Extended/RDTreeView.cpp | 67 +++++++++++++++----- qrenderdoc/Widgets/Extended/RDTreeView.h | 10 +++ qrenderdoc/Widgets/Extended/RDTreeWidget.cpp | 46 ++++++++------ qrenderdoc/Widgets/Extended/RDTreeWidget.h | 2 - 4 files changed, 87 insertions(+), 38 deletions(-) diff --git a/qrenderdoc/Widgets/Extended/RDTreeView.cpp b/qrenderdoc/Widgets/Extended/RDTreeView.cpp index 60cfdf3b1..267863a90 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeView.cpp +++ b/qrenderdoc/Widgets/Extended/RDTreeView.cpp @@ -23,21 +23,10 @@ ******************************************************************************/ #include "RDTreeView.h" +#include #include #include -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); diff --git a/qrenderdoc/Widgets/Extended/RDTreeView.h b/qrenderdoc/Widgets/Extended/RDTreeView.h index ef488b43c..3ad48dbc7 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeView.h +++ b/qrenderdoc/Widgets/Extended/RDTreeView.h @@ -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; }; diff --git a/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp b/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp index 27f05cc35..792465183 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp +++ b/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp @@ -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 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); diff --git a/qrenderdoc/Widgets/Extended/RDTreeWidget.h b/qrenderdoc/Widgets/Extended/RDTreeWidget.h index fae13e244..b0942af8d 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeWidget.h +++ b/qrenderdoc/Widgets/Extended/RDTreeWidget.h @@ -241,8 +241,6 @@ private: QPair m_highestIndex; uint64_t m_queuedRoles; - RDTreeWidgetItem *m_currentHoverItem = NULL; - bool m_instantTooltips = false; bool m_customCopyPaste = false; int m_hoverColumn = -1;