Skip to content

Commit

Permalink
[needs-docs] Merge pull request qgis#30227 from boundlessgeo/master_l…
Browse files Browse the repository at this point in the history
…egend-horiz-scroll
  • Loading branch information
dakcarto authored Jun 26, 2019
2 parents c224a01 + 6e6b289 commit f434825
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 16 deletions.
22 changes: 22 additions & 0 deletions python/gui/auto_generated/layertree/qgslayertreeview.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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 );
Expand All @@ -221,6 +242,7 @@ Emitted when a current layer is changed

protected:


};


Expand Down
6 changes: 6 additions & 0 deletions src/gui/layertree/qgslayertreeembeddedwidgetsimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "qgslayertreeembeddedwidgetsimpl.h"

#include <QFontMetrics>
#include <QHBoxLayout>
#include <QLabel>
#include <QSlider>
Expand All @@ -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
Expand Down
43 changes: 42 additions & 1 deletion src/gui/layertree/qgslayertreeview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <QMenu>
#include <QContextMenuEvent>
#include <QHeaderView>

#include "qgslayertreeviewindicator.h"
#include "qgslayertreeviewitemdelegate.h"
Expand All @@ -43,13 +44,22 @@ 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 );

// we need a custom item delegate in order to draw indicators
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 );
}
Expand Down Expand Up @@ -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 );
}
}
}
Expand Down Expand Up @@ -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 );
}
19 changes: 19 additions & 0 deletions src/gui/layertree/qgslayertreeview.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -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 );
Expand All @@ -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 );
Expand All @@ -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;
};
Expand Down
49 changes: 35 additions & 14 deletions src/gui/layertree/qgslayertreeviewitemdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
#include "qgslayertreeview.h"
#include "qgslayertreeviewindicator.h"

#include <QBrush>
#include <QHelpEvent>
#include <QMenu>
#include <QPen>
#include <QToolTip>

/// @cond PRIVATE
Expand All @@ -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 ) )
{
Expand All @@ -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() );
}
}
}
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand All @@ -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 );
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/gui/layertree/qgslayertreeviewitemdelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down

0 comments on commit f434825

Please sign in to comment.