mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-28 00:17:30 -05:00
[needs-docs] Merge pull request #30227 from boundlessgeo/master_legend-horiz-scroll
This commit is contained in:
commit
f4348259c9
@ -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:
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user