QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
qgslayertreeviewitemdelegate.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayertreeviewitemdelegate.cpp
3 --------------------------------------
4 Date : January 2018
5 Copyright : (C) 2018 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "moc_qgslayertreeviewitemdelegate.cpp"
18
19#include "qgslayertreemodel.h"
20#include "qgslayertreeview.h"
22
23#include <QBrush>
24#include <QHelpEvent>
25#include <QMenu>
26#include <QPen>
27#include <QToolTip>
28
30
31QgsLayerTreeViewProxyStyle::QgsLayerTreeViewProxyStyle( QgsLayerTreeView *treeView )
32 : QgsProxyStyle( treeView )
33 , mLayerTreeView( treeView )
34{
35}
36
37
38QRect QgsLayerTreeViewProxyStyle::subElementRect( QStyle::SubElement element, const QStyleOption *option, const QWidget *widget ) const
39{
40 if ( element == SE_LayerTreeItemIndicator )
41 {
42 if ( const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>( option ) )
43 {
44 if ( QgsLayerTreeNode *node = mLayerTreeView->index2node( vopt->index ) )
45 {
46 const int count = mLayerTreeView->indicators( node ).count();
47 if ( count )
48 {
49 const QRect vpr = mLayerTreeView->viewport()->rect();
50 const QRect r = QProxyStyle::subElementRect( SE_ItemViewItemText, option, widget );
51 const int indiWidth = r.height() * count;
52 const int spacing = r.height() / 10;
53 const int vpIndiWidth = vpr.width() - indiWidth - spacing - mLayerTreeView->layerMarkWidth();
54 return QRect( vpIndiWidth, r.top(), indiWidth, r.height() );
55 }
56 }
57 }
58 }
59 return QProxyStyle::subElementRect( element, option, widget );
60}
61
62
63// -----
64
65
66QgsLayerTreeViewItemDelegate::QgsLayerTreeViewItemDelegate( QgsLayerTreeView *parent )
67 : QStyledItemDelegate( parent )
68 , mLayerTreeView( parent )
69{
70 connect( mLayerTreeView, &QgsLayerTreeView::clicked, this, &QgsLayerTreeViewItemDelegate::onClicked );
71}
72
73
74void QgsLayerTreeViewItemDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
75{
76 QStyledItemDelegate::paint( painter, option, index );
77
78 QgsLayerTreeNode *node = mLayerTreeView->index2node( index );
79 if ( !node )
80 return;
81
82 QStyleOptionViewItem opt = option;
83 initStyleOption( &opt, index );
84
85 const QColor baseColor = opt.palette.base().color();
86 const QRect tRect = mLayerTreeView->style()->subElementRect( QStyle::SE_ItemViewItemText, &opt, mLayerTreeView );
87
88 const bool shouldShowLayerMark = tRect.left() < 0; // Layer/group node icon not visible anymore?
89 if ( shouldShowLayerMark )
90 {
91 const int tPadding = tRect.height() / 10;
92 const QRect mRect( mLayerTreeView->viewport()->rect().right() - mLayerTreeView->layerMarkWidth(), tRect.top() + tPadding, mLayerTreeView->layerMarkWidth(), tRect.height() - tPadding * 2 );
93 const QBrush pb = painter->brush();
94 const QPen pp = painter->pen();
95 painter->setPen( QPen( Qt::NoPen ) );
96 QBrush b = QBrush( opt.palette.mid() );
97 QColor bc = b.color();
98 // mix mid color with base color for a less dominant, yet still opaque, version of the color
99 bc.setRed( static_cast< int >( bc.red() * 0.3 + baseColor.red() * 0.7 ) );
100 bc.setGreen( static_cast< int >( bc.green() * 0.3 + baseColor.green() * 0.7 ) );
101 bc.setBlue( static_cast< int >( bc.blue() * 0.3 + baseColor.blue() * 0.7 ) );
102 b.setColor( bc );
103 painter->setBrush( b );
104 painter->drawRect( mRect );
105 painter->setBrush( pb );
106 painter->setPen( pp );
107 }
108
109 const QList<QgsLayerTreeViewIndicator *> indicators = mLayerTreeView->indicators( node );
110 if ( indicators.isEmpty() )
111 return;
112
113 const QRect indRect = mLayerTreeView->style()->subElementRect( static_cast<QStyle::SubElement>( QgsLayerTreeViewProxyStyle::SE_LayerTreeItemIndicator ), &opt, mLayerTreeView );
114 const int spacing = indRect.height() / 10;
115 const int h = indRect.height();
116 int x = indRect.left();
117
118 for ( QgsLayerTreeViewIndicator *indicator : indicators )
119 {
120 const QRect rect( x + spacing, indRect.top() + spacing, h - spacing * 2, h - spacing * 2 );
121 // Add a little more padding so the icon does not look misaligned to background
122 const QRect iconRect( x + spacing * 2, indRect.top() + spacing * 2, h - spacing * 4, h - spacing * 4 );
123 x += h;
124
125 QIcon::Mode mode = QIcon::Normal;
126 if ( !( opt.state & QStyle::State_Enabled ) )
127 mode = QIcon::Disabled;
128 else if ( opt.state & QStyle::State_Selected )
129 mode = QIcon::Selected;
130
131 // Draw indicator background, for when floating over text content
132 const qreal bradius = spacing;
133 const QBrush pb = painter->brush();
134 const QPen pp = painter->pen();
135 QBrush b = QBrush( opt.palette.midlight() );
136 QColor bc = b.color();
137 bc.setRed( static_cast< int >( bc.red() * 0.3 + baseColor.red() * 0.7 ) );
138 bc.setGreen( static_cast< int >( bc.green() * 0.3 + baseColor.green() * 0.7 ) );
139 bc.setBlue( static_cast< int >( bc.blue() * 0.3 + baseColor.blue() * 0.7 ) );
140 b.setColor( bc );
141 painter->setBrush( b );
142 painter->setPen( QPen( QBrush( opt.palette.mid() ), 0.25 ) );
143 painter->drawRoundedRect( rect, bradius, bradius );
144 painter->setBrush( pb );
145 painter->setPen( pp );
146
147 indicator->icon().paint( painter, iconRect, Qt::AlignCenter, mode );
148 }
149}
150
151static void _fixStyleOption( QStyleOptionViewItem &opt )
152{
153 // This makes sure our delegate behaves correctly across different styles. Unfortunately there is inconsistency
154 // in how QStyleOptionViewItem::showDecorationSelected is prepared for paint() vs what is returned from view's viewOptions():
155 // - viewOptions() returns it based on style's SH_ItemView_ShowDecorationSelected hint
156 // - for paint() there is extra call to QTreeViewPrivate::adjustViewOptionsForIndex() which makes it
157 // always true if view's selection behavior is SelectRows (which is the default and our case with layer tree view)
158 // So for consistency between different calls we override it to what we get in paint() method ... phew!
159 opt.showDecorationSelected = true;
160}
161
162bool QgsLayerTreeViewItemDelegate::helpEvent( QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index )
163{
164 if ( event && event->type() == QEvent::ToolTip )
165 {
166 QgsLayerTreeNode *node = mLayerTreeView->index2node( index );
167 if ( node )
168 {
169 const QList<QgsLayerTreeViewIndicator *> indicators = mLayerTreeView->indicators( node );
170 if ( !indicators.isEmpty() )
171 {
172 QStyleOptionViewItem opt = option;
173 initStyleOption( &opt, index );
174 _fixStyleOption( opt );
175
176 const QRect indRect = mLayerTreeView->style()->subElementRect( static_cast<QStyle::SubElement>( QgsLayerTreeViewProxyStyle::SE_LayerTreeItemIndicator ), &opt, mLayerTreeView );
177
178 if ( indRect.contains( event->pos() ) )
179 {
180 const int indicatorIndex = ( event->pos().x() - indRect.left() ) / indRect.height();
181 if ( indicatorIndex >= 0 && indicatorIndex < indicators.count() )
182 {
183 const QString tooltip = indicators[indicatorIndex]->toolTip();
184 if ( !tooltip.isEmpty() )
185 {
186 QToolTip::showText( event->globalPos(), tooltip, view );
187 return true;
188 }
189 }
190 }
191 }
192 }
193 }
194 return QStyledItemDelegate::helpEvent( event, view, option, index );
195}
196
197
198void QgsLayerTreeViewItemDelegate::onClicked( const QModelIndex &index )
199{
200 QgsLayerTreeNode *node = mLayerTreeView->index2node( index );
201 if ( !node )
202 return;
203
204 const QList<QgsLayerTreeViewIndicator *> indicators = mLayerTreeView->indicators( node );
205 if ( indicators.isEmpty() )
206 return;
207
208#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
209 QStyleOptionViewItem opt( mLayerTreeView->viewOptions() );
210#else
211 QStyleOptionViewItem opt;
212 mLayerTreeView->initViewItemOption( &opt );
213#endif
214 opt.rect = mLayerTreeView->visualRect( index );
215 initStyleOption( &opt, index );
216 _fixStyleOption( opt );
217
218 const QRect indRect = mLayerTreeView->style()->subElementRect( static_cast<QStyle::SubElement>( QgsLayerTreeViewProxyStyle::SE_LayerTreeItemIndicator ), &opt, mLayerTreeView );
219
220 const QPoint pos = mLayerTreeView->mLastReleaseMousePos;
221 if ( indRect.contains( pos ) )
222 {
223 const int indicatorIndex = ( pos.x() - indRect.left() ) / indRect.height();
224 if ( indicatorIndex >= 0 && indicatorIndex < indicators.count() )
225 emit indicators[indicatorIndex]->clicked( index );
226 }
227}
228
This class is a base class for nodes in a layer tree.
Indicator that can be used in a layer tree view to display icons next to items of the layer tree.
The QgsLayerTreeView class extends QTreeView and provides some additional functionality when working ...
A QProxyStyle subclass which correctly sets the base style to match the QGIS application style,...