[needs-docs] Merge pull request #30227 from boundlessgeo/master_legend-horiz-scroll

This commit is contained in:
Larry Shaffer 2019-06-26 11:42:53 -06:00 committed by GitHub
commit f4348259c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 125 additions and 16 deletions

View File

@ -164,6 +164,15 @@ Returns list of indicators associated with a particular layer tree node.
.. versionadded:: 3.2
%End
int layerMarkWidth() const;
%Docstring
Returns width of contextual menu mark, at right of layer node items.
.. seealso:: :py:func:`setLayerMarkWidth`
.. versionadded:: 3.8
%End
public slots:
@ -184,6 +193,15 @@ Enhancement of QTreeView.expandAll() that also records expanded state in layer t
Enhancement of QTreeView.collapseAll() that also records expanded state in layer tree nodes
.. versionadded:: 2.18
%End
void setLayerMarkWidth( int width );
%Docstring
Set width of contextual menu mark, at right of layer node items.
.. seealso:: :py:func:`layerMarkWidth`
.. versionadded:: 3.8
%End
signals:
@ -208,6 +226,9 @@ Emitted when a current layer is changed
virtual void dropEvent( QDropEvent *event );
virtual void resizeEvent( QResizeEvent *event );
protected slots:
void modelRowsInserted( const QModelIndex &index, int start, int end );
@ -221,6 +242,7 @@ Emitted when a current layer is changed
protected:
};

View File

@ -15,6 +15,7 @@
#include "qgslayertreeembeddedwidgetsimpl.h"
#include <QFontMetrics>
#include <QHBoxLayout>
#include <QLabel>
#include <QSlider>
@ -34,9 +35,14 @@ QgsLayerTreeOpacityWidget::QgsLayerTreeOpacityWidget( QgsMapLayer *layer )
QLabel *l = new QLabel( QStringLiteral( "Opacity" ), this );
mSlider = new QSlider( Qt::Horizontal, this );
mSlider->setRange( 0, 1000 );
int sliderW = static_cast< int >( QFontMetricsF( font() ).width( 'X' ) * 16 * Qgis::UI_SCALE_FACTOR );
mSlider->setMinimumWidth( sliderW / 2 );
mSlider->setMaximumWidth( sliderW );
QHBoxLayout *lay = new QHBoxLayout();
QSpacerItem *spacerItem = new QSpacerItem( 1, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum );
lay->addWidget( l );
lay->addWidget( mSlider );
lay->addItem( spacerItem );
setLayout( lay );
// timer for delayed transparency update - for more responsive GUI

View File

@ -26,6 +26,7 @@
#include <QMenu>
#include <QContextMenuEvent>
#include <QHeaderView>
#include "qgslayertreeviewindicator.h"
#include "qgslayertreeviewitemdelegate.h"
@ -43,6 +44,13 @@ QgsLayerTreeView::QgsLayerTreeView( QWidget *parent )
setEditTriggers( EditKeyPressed );
setExpandsOnDoubleClick( false ); // normally used for other actions
// Ensure legend graphics are scrollable
header()->setStretchLastSection( false );
header()->setSectionResizeMode( QHeaderView::ResizeToContents );
// If vertically scrolling by item, legend graphics can get clipped
setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
setSelectionMode( ExtendedSelection );
setDefaultDropAction( Qt::MoveAction );
@ -50,6 +58,8 @@ QgsLayerTreeView::QgsLayerTreeView( QWidget *parent )
setItemDelegate( new QgsLayerTreeViewItemDelegate( this ) );
setStyle( new QgsLayerTreeViewProxyStyle( this ) );
setLayerMarkWidth( static_cast< int >( QFontMetricsF( font() ).width( 'l' ) * Qgis::UI_SCALE_FACTOR ) );
connect( this, &QTreeView::collapsed, this, &QgsLayerTreeView::updateExpandedStateToNode );
connect( this, &QTreeView::expanded, this, &QgsLayerTreeView::updateExpandedStateToNode );
}
@ -154,7 +164,24 @@ void QgsLayerTreeView::modelRowsInserted( const QModelIndex &index, int start, i
if ( QgsLayerTreeEmbeddedWidgetProvider *provider = QgsGui::layerTreeEmbeddedWidgetRegistry()->provider( providerId ) )
{
QModelIndex index = layerTreeModel()->legendNode2index( legendNodes[i] );
setIndexWidget( index, provider->createWidget( layer, i ) );
QWidget *wdgt = provider->createWidget( layer, i );
// Since column is resized to contents, limit the expanded width of embedded
// widgets, if they are not already limited, e.g. have the default MAX value.
// Else, embedded widget may grow very wide due to large legend graphics.
// NOTE: This approach DOES NOT work right. It causes horizontal scroll
// bar to disappear if the embedded widget is expanded and part
// of the last layer in the panel, even if much wider legend items
// are expanded above it. The correct width-limiting method should
// be setting fixed-width, hidpi-aware embedded widget items in a
// layout and appending an expanding QSpacerItem to end. This ensures
// full width is always created in the column by the embedded widget.
// See QgsLayerTreeOpacityWidget
//if ( wdgt->maximumWidth() == QWIDGETSIZE_MAX )
//{
// wdgt->setMaximumWidth( 250 );
//}
setIndexWidget( index, wdgt );
}
}
}
@ -480,3 +507,17 @@ void QgsLayerTreeView::dropEvent( QDropEvent *event )
}
QTreeView::dropEvent( event );
}
void QgsLayerTreeView::resizeEvent( QResizeEvent *event )
{
// Since last column is resized to content (instead of stretched), the active
// selection rectangle ends at width of widest visible item in tree,
// regardless of which item is selected. This causes layer indicators to
// become 'inactive' (not clickable and no tool tip) unless their rectangle
// enters the view item's selection (active) rectangle.
// Always resetting the minimum section size relative to the viewport ensures
// the view item's selection rectangle extends to the right edge of the
// viewport, which allows indicators to become active again.
header()->setMinimumSectionSize( viewport()->width() );
QTreeView::resizeEvent( event );
}

View File

@ -154,6 +154,13 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
*/
QList<QgsLayerTreeViewIndicator *> indicators( QgsLayerTreeNode *node ) const;
/**
* Returns width of contextual menu mark, at right of layer node items.
* \see setLayerMarkWidth
* \since QGIS 3.8
*/
int layerMarkWidth() const { return mLayerMarkWidth; }
///@cond PRIVATE
/**
@ -184,6 +191,13 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
*/
void collapseAllNodes();
/**
* Set width of contextual menu mark, at right of layer node items.
* \see layerMarkWidth
* \since QGIS 3.8
*/
void setLayerMarkWidth( int width ) { mLayerMarkWidth = width; }
signals:
//! Emitted when a current layer is changed
void currentLayerChanged( QgsMapLayer *layer );
@ -200,6 +214,8 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
void dropEvent( QDropEvent *event ) override;
void resizeEvent( QResizeEvent *event ) override;
protected slots:
void modelRowsInserted( const QModelIndex &index, int start, int end );
@ -226,6 +242,9 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
//! Used by the item delegate for identification of which indicator has been clicked
QPoint mLastReleaseMousePos;
//! Width of contextual menu mark for layer nodes
int mLayerMarkWidth;
// friend so it can access viewOptions() method and mLastReleaseMousePos without making them public
friend class QgsLayerTreeViewItemDelegate;
};

View File

@ -19,7 +19,10 @@
#include "qgslayertreeview.h"
#include "qgslayertreeviewindicator.h"
#include <QBrush>
#include <QHelpEvent>
#include <QMenu>
#include <QPen>
#include <QToolTip>
/// @cond PRIVATE
@ -33,7 +36,7 @@ QgsLayerTreeViewProxyStyle::QgsLayerTreeViewProxyStyle( QgsLayerTreeView *treeVi
QRect QgsLayerTreeViewProxyStyle::subElementRect( QStyle::SubElement element, const QStyleOption *option, const QWidget *widget ) const
{
if ( element == SE_ItemViewItemText || element == SE_LayerTreeItemIndicator )
if ( element == SE_LayerTreeItemIndicator )
{
if ( const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>( option ) )
{
@ -42,17 +45,12 @@ QRect QgsLayerTreeViewProxyStyle::subElementRect( QStyle::SubElement element, co
int count = mLayerTreeView->indicators( node ).count();
if ( count )
{
QRect vpr = mLayerTreeView->viewport()->rect();
QRect r = QProxyStyle::subElementRect( SE_ItemViewItemText, option, widget );
int indiWidth = r.height() * count;
int textWidth = r.width() - indiWidth;
if ( element == SE_LayerTreeItemIndicator )
{
return QRect( r.left() + textWidth, r.top(), indiWidth, r.height() );
}
else if ( element == SE_ItemViewItemText )
{
return QRect( r.left(), r.top(), textWidth, r.height() );
}
int spacing = r.height() / 10;
int vpIndiWidth = vpr.width() - indiWidth - spacing - mLayerTreeView->layerMarkWidth();
return QRect( vpIndiWidth, r.top(), indiWidth, r.height() );
}
}
}
@ -80,13 +78,24 @@ void QgsLayerTreeViewItemDelegate::paint( QPainter *painter, const QStyleOptionV
if ( !node )
return;
QStyleOptionViewItem opt = option;
initStyleOption( &opt, index );
QRect tRect = mLayerTreeView->style()->subElementRect( QStyle::SE_ItemViewItemText, &opt, mLayerTreeView );
int tPadding = tRect.height() / 10;
// Draw layer context menu mark
QRect mRect( mLayerTreeView->viewport()->rect().right() - mLayerTreeView->layerMarkWidth(), tRect.top() + tPadding, mLayerTreeView->layerMarkWidth(), tRect.height() - tPadding * 2 );
QBrush pb = painter->brush();
QPen pp = painter->pen();
painter->setPen( QPen( Qt::NoPen ) );
painter->setBrush( QBrush( opt.palette.mid() ) );
painter->drawRect( mRect );
const QList<QgsLayerTreeViewIndicator *> indicators = mLayerTreeView->indicators( node );
if ( indicators.isEmpty() )
return;
QStyleOptionViewItem opt = option;
initStyleOption( &opt, index );
QRect indRect = mLayerTreeView->style()->subElementRect( static_cast<QStyle::SubElement>( QgsLayerTreeViewProxyStyle::SE_LayerTreeItemIndicator ), &opt, mLayerTreeView );
int spacing = indRect.height() / 10;
int h = indRect.height();
@ -95,6 +104,8 @@ void QgsLayerTreeViewItemDelegate::paint( QPainter *painter, const QStyleOptionV
for ( QgsLayerTreeViewIndicator *indicator : indicators )
{
QRect rect( x + spacing, indRect.top() + spacing, h - spacing * 2, h - spacing * 2 );
// Add a little more padding so the icon does not look misaligned to background
QRect iconRect( x + spacing * 2, indRect.top() + spacing * 2, h - spacing * 4, h - spacing * 4 );
x += h;
QIcon::Mode mode = QIcon::Normal;
@ -103,7 +114,17 @@ void QgsLayerTreeViewItemDelegate::paint( QPainter *painter, const QStyleOptionV
else if ( opt.state & QStyle::State_Selected )
mode = QIcon::Selected;
indicator->icon().paint( painter, rect, Qt::AlignCenter, mode );
// Draw indicator background, for when floating over text content
qreal bradius = spacing;
QBrush pb = painter->brush();
QPen pp = painter->pen();
painter->setBrush( opt.palette.midlight() );
painter->setPen( QPen( QBrush( opt.palette.mid() ), 0.25 ) );
painter->drawRoundedRect( rect, bradius, bradius );
painter->setBrush( pb );
painter->setPen( pp );
indicator->icon().paint( painter, iconRect, Qt::AlignCenter, mode );
}
}

View File

@ -37,7 +37,7 @@ class QgsLayerTreeView;
#include <QStyledItemDelegate>
/**
* Proxy style to make the item text rect shorter so that indicators fit in without colliding with text
* Proxy style for layer items with indicators
*/
class QgsLayerTreeViewProxyStyle : public QgsProxyStyle
{