Skip to content

Commit

Permalink
Gui: Fix document tree background rendering with overlay (Qt6)
Browse files Browse the repository at this point in the history
This aims to fix rendering of tree view items in Qt6. While I don't
belive that this is a good way to fix this, I am worried that it is the
only way to do ir.

BC BREAK: This change introduces artificial QTreeView widget that can be
targeted using QSS and can be used in the delegate for painting background of
items. `QTreeView::item` would now be used to render background for the
whole row, while each cell can be targeted using `#DocumentTreeItems`
selector.

More details on implementation:
https://stackoverflow.com/questions/78414383/qt6-disable-drawing-of-default-background-for-qtreeview-items/78421604#78421604

Fixes: FreeCAD#13760
  • Loading branch information
kadet1090 committed May 2, 2024
1 parent a02ff7a commit b2fba39
Showing 1 changed file with 73 additions and 29 deletions.
102 changes: 73 additions & 29 deletions src/Gui/Tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@ namespace Gui {
*/
class TreeWidgetItemDelegate: public QStyledItemDelegate {
typedef QStyledItemDelegate inherited;

QTreeView *artificial;

QRect calculateItemRect(const QStyleOptionViewItem &option, const QModelIndex &index) const;

public:
explicit TreeWidgetItemDelegate(QObject* parent=nullptr);

Expand All @@ -389,6 +394,42 @@ class TreeWidgetItemDelegate: public QStyledItemDelegate {
TreeWidgetItemDelegate::TreeWidgetItemDelegate(QObject* parent)
: QStyledItemDelegate(parent)
{
artificial = new QTreeView(qobject_cast<QWidget*>(parent));
artificial->setObjectName("DocumentTreeItems");

Check failure on line 398 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

calling a private constructor of class 'QString'

Check failure on line 398 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

calling a private constructor of class 'QString' [clang-diagnostic-error]
artificial->setFixedSize(0, 0);
}


QRect TreeWidgetItemDelegate::calculateItemRect(const QStyleOptionViewItem &option, const QModelIndex &index) const

Check warning on line 403 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

unused parameter 'index' [-Wunused-parameter]
{
auto tree = static_cast<TreeWidget*>(parent());
auto style = tree->style();

QRect rect = option.rect;

const int margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, tree) + 1;

// 2 margin for text, 2 margin for decoration (icon) = 4 times margin
int width = 4 * margin
+ option.fontMetrics.boundingRect(option.text).width()
+ option.decorationSize.width()
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ TreeParams::getItemBackgroundPadding() // required only for Qt5 build, Qt6 properly calculates layout
#endif
;

if (TreeParams::getCheckBoxesSelection()) {
// another 2 margin for checkbox
width += 2 * margin
+ style->pixelMetric(QStyle::PM_IndicatorWidth)
+ style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
}

if (width < rect.width()) {
rect.setWidth(width);
}

return rect;
}

void TreeWidgetItemDelegate::paint(QPainter *painter,
Expand All @@ -397,59 +438,62 @@ void TreeWidgetItemDelegate::paint(QPainter *painter,
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);

TreeWidget * tree = static_cast<TreeWidget*>(parent());
auto tree = static_cast<TreeWidget*>(parent());
auto style = tree->style();

// If the second column is not shown, we'll trim the color background when
// rendering as transparent overlay.
bool trimBG = TreeParams::getHideColumn();
QRect rect = opt.rect;

if (index.column() == 0) {
if (tree->testAttribute(Qt::WA_NoSystemBackground)
&& (trimBG || (opt.backgroundBrush.style() == Qt::NoBrush
&& _TreeItemBackground.style() != Qt::NoBrush)))
{
const int margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, tree) + 1;
// 2 margin for text, 2 margin for decoration (icon)
int width = 4*margin + opt.fontMetrics.boundingRect(opt.text).width()
+ opt.decorationSize.width() + TreeParams::getItemBackgroundPadding();
if (TreeParams::getCheckBoxesSelection()) {
// another 2 margin for checkbox
width += 2*margin + style->pixelMetric(QStyle::PM_IndicatorWidth)
+ style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
}
if (width < rect.width())
rect.setWidth(width);
if (trimBG) {
rect.setWidth(rect.width() + 5);
opt.rect = rect;
if (opt.backgroundBrush.style() == Qt::NoBrush)
painter->fillRect(rect, _TreeItemBackground);
} else if (!opt.state.testFlag(QStyle::State_Selected))
QRect rect = calculateItemRect(option, index);

if (trimBG && opt.backgroundBrush.style() == Qt::NoBrush) {
painter->fillRect(rect, _TreeItemBackground);
} else if (!opt.state.testFlag(QStyle::State_Selected)) {
painter->fillRect(rect, _TreeItemBackground);
}
}

}

style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, tree);
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, artificial);
}

void TreeWidgetItemDelegate::initStyleOption(QStyleOptionViewItem *option,
const QModelIndex &index) const
{
inherited::initStyleOption(option, index);

TreeWidget * tree = static_cast<TreeWidget*>(parent());
QTreeWidgetItem * item = tree->itemFromIndex(index);
if (!item || item->type() != TreeWidget::ObjectType)
auto tree = static_cast<TreeWidget*>(parent());
auto item = tree->itemFromIndex(index);

if (!item) {
return;
}

QSize size;
size = option->icon.actualSize(QSize(0xffff, 0xffff));
if (size.height())
option->decorationSize = QSize(size.width()*TreeWidget::iconSize()/size.height(),
TreeWidget::iconSize());
if (TreeParams::getHideColumn()) {
option->rect = calculateItemRect(*option, index);
}

auto mousePos = option->widget->mapFromGlobal(QCursor::pos());
auto isHovered = option->rect.contains(mousePos);

if (!isHovered) {
option->state &= ~QStyle::State_MouseOver;
}

QSize size = option->icon.actualSize(QSize(0xffff, 0xffff));

if (size.height() > 0) {
option->decorationSize = QSize(
size.width() * TreeWidget::iconSize() / size.height(),
TreeWidget::iconSize()
);
}
}

QWidget* TreeWidgetItemDelegate::createEditor(
Expand Down

0 comments on commit b2fba39

Please sign in to comment.