Add widget for Embedded Symbols renderer

Allows users to control the default symbol used for features without
embedded styles
This commit is contained in:
Nyall Dawson 2021-03-02 15:08:53 +10:00
parent 031e2b0c61
commit 5245430461
10 changed files with 344 additions and 0 deletions

View File

@ -79,6 +79,13 @@ Ownership of ``symbol`` is transferred to the renderer.
Creates a new embedded symbol renderer from an XML ``element``, using the supplied read/write ``context``.
The caller takes ownership of the returned renderer.
%End
static QgsEmbeddedSymbolRenderer *convertFromRenderer( const QgsFeatureRenderer *renderer ) /Factory/;
%Docstring
Creates a QgsEmbeddedSymbolRenderer from an existing ``renderer``.
:return: a new renderer if the conversion was possible, otherwise ``None``.
%End
private:

View File

@ -0,0 +1,58 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/symbology/qgsembeddedsymbolrendererwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsEmbeddedSymbolRendererWidget : QgsRendererWidget, QgsExpressionContextGenerator
{
%Docstring
A widget used represent options of a :py:class:`QgsEmbeddedSymbolRenderer`
.. versionadded:: 3.20
%End
%TypeHeaderCode
#include "qgsembeddedsymbolrendererwidget.h"
%End
public:
static QgsRendererWidget *create( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer ) /Factory/;
%Docstring
Static creation method
:param layer: the layer where this renderer is applied
:param style:
:param renderer: the merged feature renderer (will not take ownership)
%End
QgsEmbeddedSymbolRendererWidget( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer );
%Docstring
Constructor
:param layer: the layer where this renderer is applied
:param style:
:param renderer: the merged feature renderer (will not take ownership)
%End
virtual QgsFeatureRenderer *renderer();
virtual void setContext( const QgsSymbolWidgetContext &context );
virtual QgsExpressionContext createExpressionContext() const;
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/symbology/qgsembeddedsymbolrendererwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -390,6 +390,7 @@
%Include auto_generated/symbology/qgsdashspacedialog.sip
%Include auto_generated/symbology/qgsdatadefinedsizelegendwidget.sip
%Include auto_generated/symbology/qgsellipsesymbollayerwidget.sip
%Include auto_generated/symbology/qgsembeddedsymbolrendererwidget.sip
%Include auto_generated/symbology/qgsgraduatedhistogramwidget.sip
%Include auto_generated/symbology/qgsgraduatedsymbolrendererwidget.sip
%Include auto_generated/symbology/qgsheatmaprendererwidget.sip

View File

@ -16,6 +16,7 @@
#include "qgsembeddedsymbolrenderer.h"
#include "qgspainteffectregistry.h"
#include "qgssymbollayerutils.h"
#include "qgssinglesymbolrenderer.h"
QgsEmbeddedSymbolRenderer::QgsEmbeddedSymbolRenderer( QgsSymbol *defaultSymbol )
: QgsFeatureRenderer( QStringLiteral( "embeddedSymbol" ) )
@ -114,6 +115,23 @@ QgsFeatureRenderer *QgsEmbeddedSymbolRenderer::create( QDomElement &element, con
return r;
}
QgsEmbeddedSymbolRenderer *QgsEmbeddedSymbolRenderer::convertFromRenderer( const QgsFeatureRenderer *renderer )
{
if ( renderer->type() == QLatin1String( "embeddedSymbol" ) )
{
return dynamic_cast<QgsEmbeddedSymbolRenderer *>( renderer->clone() );
}
else if ( renderer->type() == QLatin1String( "singleSymbol" ) )
{
std::unique_ptr< QgsEmbeddedSymbolRenderer > symbolRenderer = std::make_unique< QgsEmbeddedSymbolRenderer >( static_cast< const QgsSingleSymbolRenderer * >( renderer )->symbol()->clone() );
return symbolRenderer.release();
}
else
{
return nullptr;
}
}
QDomElement QgsEmbeddedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
{
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );

View File

@ -79,6 +79,12 @@ class CORE_EXPORT QgsEmbeddedSymbolRenderer : public QgsFeatureRenderer
*/
static QgsFeatureRenderer *create( QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;
/**
* Creates a QgsEmbeddedSymbolRenderer from an existing \a renderer.
* \returns a new renderer if the conversion was possible, otherwise NULLPTR.
*/
static QgsEmbeddedSymbolRenderer *convertFromRenderer( const QgsFeatureRenderer *renderer ) SIP_FACTORY;
private:
#ifdef SIP_RUN
QgsEmbeddedSymbolRenderer( const QgsEmbeddedSymbolRenderer & );

View File

@ -38,6 +38,7 @@ set(QGIS_GUI_SRCS
symbology/qgsdashspacedialog.cpp
symbology/qgsdatadefinedsizelegendwidget.cpp
symbology/qgsellipsesymbollayerwidget.cpp
symbology/qgsembeddedsymbolrendererwidget.cpp
symbology/qgsgraduatedhistogramwidget.cpp
symbology/qgsgraduatedsymbolrendererwidget.cpp
symbology/qgsheatmaprendererwidget.cpp
@ -1193,6 +1194,7 @@ set(QGIS_GUI_HDRS
symbology/qgsdashspacedialog.h
symbology/qgsdatadefinedsizelegendwidget.h
symbology/qgsellipsesymbollayerwidget.h
symbology/qgsembeddedsymbolrendererwidget.h
symbology/qgsgraduatedhistogramwidget.h
symbology/qgsgraduatedsymbolrendererwidget.h
symbology/qgsheatmaprendererwidget.h

View File

@ -0,0 +1,112 @@
/***************************************************************************
qgsembeddedsymbolrendererwidget.cpp
---------------------
begin : March 2021
copyright : (C) 2021 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsembeddedsymbolrendererwidget.h"
#include "qgsembeddedsymbolrenderer.h"
#include "qgsrendererregistry.h"
#include "qgssymbol.h"
#include "qgslogger.h"
#include "qgsvectorlayer.h"
#include "qgsapplication.h"
QgsRendererWidget *QgsEmbeddedSymbolRendererWidget::create( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer )
{
return new QgsEmbeddedSymbolRendererWidget( layer, style, renderer );
}
QgsEmbeddedSymbolRendererWidget::QgsEmbeddedSymbolRendererWidget( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer )
: QgsRendererWidget( layer, style )
{
if ( !layer )
{
return;
}
QgsWkbTypes::GeometryType type = QgsWkbTypes::geometryType( layer->wkbType() );
// the renderer only applies to layers with providers supporting embedded symbols
if ( !( layer->dataProvider()->capabilities() & QgsVectorDataProvider::FeatureSymbology ) )
{
//setup blank dialog
mRenderer.reset( nullptr );
QGridLayout *layout = new QGridLayout( this );
QLabel *label = new QLabel( tr( "The embedded symbols renderer can only be used with layers\n"
"containing embedded styling information.\n\n"
"'%1' does not contain embedded styling and cannot be displayed." )
.arg( layer->name() ), this );
this->setLayout( layout );
layout->addWidget( label );
return;
}
setupUi( this );
mDefaultSymbolToolButton->setSymbolType( QgsSymbol::symbolTypeForGeometryType( type ) );
// try to recognize the previous renderer
// (null renderer means "no previous renderer")
if ( renderer )
{
mRenderer.reset( QgsEmbeddedSymbolRenderer::convertFromRenderer( renderer ) );
}
if ( ! mRenderer )
{
// use default embedded renderer
mRenderer.reset( new QgsEmbeddedSymbolRenderer( QgsSymbol::defaultSymbol( type ) ) );
}
mDefaultSymbolToolButton->setSymbol( mRenderer->defaultSymbol()->clone() );
mDefaultSymbolToolButton->setDialogTitle( tr( "Default symbol" ) );
mDefaultSymbolToolButton->setLayer( mLayer );
mDefaultSymbolToolButton->registerExpressionContextGenerator( this );
connect( mDefaultSymbolToolButton, &QgsSymbolButton::changed, this, [ = ]
{
mRenderer->setDefaultSymbol( mDefaultSymbolToolButton->symbol()->clone() );
emit widgetChanged();
} );
}
QgsFeatureRenderer *QgsEmbeddedSymbolRendererWidget::renderer()
{
return mRenderer.get();
}
void QgsEmbeddedSymbolRendererWidget::setContext( const QgsSymbolWidgetContext &context )
{
QgsRendererWidget::setContext( context );
if ( mDefaultSymbolToolButton )
{
mDefaultSymbolToolButton->setMapCanvas( context.mapCanvas() );
mDefaultSymbolToolButton->setMessageBar( context.messageBar() );
}
}
QgsExpressionContext QgsEmbeddedSymbolRendererWidget::createExpressionContext() const
{
QgsExpressionContext context;
if ( QgsExpressionContext *expressionContext = mContext.expressionContext() )
context = *expressionContext;
else
context.appendScopes( mContext.globalProjectAtlasMapLayerScopes( mLayer ) );
const QList< QgsExpressionContextScope > scopes = mContext.additionalExpressionContextScopes();
for ( const QgsExpressionContextScope &s : scopes )
{
context << new QgsExpressionContextScope( s );
}
return context;
}

View File

@ -0,0 +1,65 @@
/***************************************************************************
qgsembeddedsymbolrendererwidget.h
---------------------
begin : March 2021
copyright : (C) 2021 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSEMBEDDEDSYMBOLRENDERERWIDGET_H
#define QGSEMBEDDEDSYMBOLRENDERERWIDGET_H
#include "ui_qgsembeddedsymbolrendererwidgetbase.h"
#include "qgis_sip.h"
#include "qgsembeddedsymbolrenderer.h"
#include "qgsrendererwidget.h"
#include "qgis_gui.h"
class QMenu;
/**
* \ingroup gui
* \brief A widget used represent options of a QgsEmbeddedSymbolRenderer
*
* \since QGIS 3.20
*/
class GUI_EXPORT QgsEmbeddedSymbolRendererWidget : public QgsRendererWidget, public QgsExpressionContextGenerator, private Ui::QgsEmbeddedSymbolRendererWidgetBase
{
Q_OBJECT
public:
/**
* Static creation method
* \param layer the layer where this renderer is applied
* \param style
* \param renderer the merged feature renderer (will not take ownership)
*/
static QgsRendererWidget *create( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer ) SIP_FACTORY;
/**
* Constructor
* \param layer the layer where this renderer is applied
* \param style
* \param renderer the merged feature renderer (will not take ownership)
*/
QgsEmbeddedSymbolRendererWidget( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer );
QgsFeatureRenderer *renderer() override;
void setContext( const QgsSymbolWidgetContext &context ) override;
QgsExpressionContext createExpressionContext() const override;
private:
//! The renderer
std::unique_ptr<QgsEmbeddedSymbolRenderer> mRenderer;
};
#endif // QGSEMBEDDEDSYMBOLRENDERERWIDGET_H

View File

@ -29,6 +29,7 @@
#include "qgsheatmaprendererwidget.h"
#include "qgs25drendererwidget.h"
#include "qgsnullsymbolrendererwidget.h"
#include "qgsembeddedsymbolrendererwidget.h"
#include "qgspanelwidget.h"
#include "qgspainteffect.h"
@ -78,6 +79,7 @@ static void _initRendererWidgetFunctions()
_initRenderer( QStringLiteral( "heatmapRenderer" ), QgsHeatmapRendererWidget::create, QStringLiteral( "rendererHeatmapSymbol.svg" ) );
_initRenderer( QStringLiteral( "25dRenderer" ), Qgs25DRendererWidget::create, QStringLiteral( "renderer25dSymbol.svg" ) );
_initRenderer( QStringLiteral( "nullSymbol" ), QgsNullSymbolRendererWidget::create, QStringLiteral( "rendererNullSymbol.svg" ) );
_initRenderer( QStringLiteral( "embeddedSymbol" ), QgsEmbeddedSymbolRendererWidget::create );
sInitialized = true;
}

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsEmbeddedSymbolRendererWidgetBase</class>
<widget class="QWidget" name="QgsEmbeddedSymbolRendererWidgetBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>316</width>
<height>78</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="1">
<widget class="QgsSymbolButton" name="mDefaultSymbolToolButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Default symbol</string>
</property>
</widget>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsSymbolButton</class>
<extends>QToolButton</extends>
<header>qgssymbolbutton.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>