[FEATURE] New standard widget for symbol buttons

Button widgets for configuring symbol properties were reimplemented
multiple times throughout the codebase. This commit creates a new
standard QgsSymbolButton widget which should be used whenever
a button for configuring symbol properties is required.

Features include:
- automatic use of inline panels whenever possible
- dropdown menu with shortcuts to color settings, copy/pasting colors
- accepts drag and dropped colors to set symbol color
This commit is contained in:
Nyall Dawson 2017-07-23 13:17:24 +10:00
parent 9a12249b02
commit 22c4740f63
7 changed files with 904 additions and 0 deletions

View File

@ -188,6 +188,7 @@
%Include qgsstatusbar.sip %Include qgsstatusbar.sip
%Include qgssublayersdialog.sip %Include qgssublayersdialog.sip
%Include qgssubstitutionlistwidget.sip %Include qgssubstitutionlistwidget.sip
%Include qgssymbolbutton.sip
%Include qgstablewidgetbase.sip %Include qgstablewidgetbase.sip
%Include qgstabwidget.sip %Include qgstabwidget.sip
%Include qgstaskmanagerwidget.sip %Include qgstaskmanagerwidget.sip

View File

@ -0,0 +1,159 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgssymbolbutton.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsSymbolButton : QToolButton
{
%Docstring
A button for creating and modifying QgsSymbol settings.
The button shows a preview icon for the current symbol, and will open a detailed symbol editor dialog (or
panel widget) when clicked.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgssymbolbutton.h"
%End
public:
QgsSymbolButton( QWidget *parent /TransferThis/ = 0, const QString &dialogTitle = QString() );
%Docstring
Construct a new symbol button.
Use ``dialogTitle`` string to define the title to show in the symbol settings dialog.
%End
virtual QSize minimumSizeHint() const;
void setDialogTitle( const QString &title );
%Docstring
Sets the ``title`` for the symbol settings dialog window.
.. seealso:: dialogTitle()
%End
QString dialogTitle() const;
%Docstring
Returns the title for the symbol settings dialog window.
.. seealso:: setDialogTitle()
:rtype: str
%End
QgsSymbol *symbol();
%Docstring
Returns the current symbol defined by the button.
.. seealso:: setSymbol()
.. seealso:: changed()
:rtype: QgsSymbol
%End
QgsMapCanvas *mapCanvas() const;
%Docstring
Returns the map canvas associated with the widget.
.. seealso:: setMapCanvas()
:rtype: QgsMapCanvas
%End
void setMapCanvas( QgsMapCanvas *canvas );
%Docstring
Sets a map ``canvas`` to associate with the widget. This allows the
widget to fetch current settings from the map canvas, such as current scale.
.. seealso:: mapCanvas()
%End
QgsVectorLayer *layer() const;
%Docstring
Returns the layer associated with the widget.
.. seealso:: setLayer()
:rtype: QgsVectorLayer
%End
void setLayer( QgsVectorLayer *layer );
%Docstring
Sets a ``layer`` to associate with the widget. This allows the
widget to setup layer related settings within the symbol settings dialog,
such as correctly populating data defined override buttons.
.. seealso:: layer()
%End
void registerExpressionContextGenerator( QgsExpressionContextGenerator *generator );
%Docstring
Register an expression context generator class that will be used to retrieve
an expression context for the button when required.
%End
public slots:
void setSymbol( QgsSymbol *symbol /Transfer/ );
%Docstring
Sets the ``symbol`` for the button. Ownership of ``symbol`` is transferred to the
button.
.. seealso:: symbol()
.. seealso:: changed()
%End
void setColor( const QColor &color );
%Docstring
Sets the current ``color`` for the symbol. Will emit a changed() signal if the color is different
to the previous symbol color.
%End
void copyColor();
%Docstring
Copies the current symbol color to the clipboard.
.. seealso:: pasteColor()
%End
void pasteColor();
%Docstring
Pastes a color from the clipboard to the symbol. If clipboard does not contain a valid
color or string representation of a color, then no change is applied.
.. seealso:: copyColor()
%End
signals:
void changed();
%Docstring
Emitted when the symbol's settings are changed.
.. seealso:: symbol()
.. seealso:: setSymbol()
%End
protected:
virtual void changeEvent( QEvent *e );
virtual void showEvent( QShowEvent *e );
virtual void resizeEvent( QResizeEvent *event );
virtual void mousePressEvent( QMouseEvent *e );
virtual void mouseMoveEvent( QMouseEvent *e );
virtual void dragEnterEvent( QDragEnterEvent *e );
virtual void dragLeaveEvent( QDragLeaveEvent *e );
virtual void dropEvent( QDropEvent *e );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgssymbolbutton.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -336,6 +336,7 @@ SET(QGIS_GUI_SRCS
qgssubstitutionlistwidget.cpp qgssubstitutionlistwidget.cpp
qgssqlcomposerdialog.cpp qgssqlcomposerdialog.cpp
qgsstatusbar.cpp qgsstatusbar.cpp
qgssymbolbutton.cpp
qgstablewidgetbase.cpp qgstablewidgetbase.cpp
qgstabwidget.cpp qgstabwidget.cpp
qgstablewidgetitem.cpp qgstablewidgetitem.cpp
@ -492,6 +493,7 @@ SET(QGIS_GUI_MOC_HDRS
qgsstatusbar.h qgsstatusbar.h
qgssublayersdialog.h qgssublayersdialog.h
qgssubstitutionlistwidget.h qgssubstitutionlistwidget.h
qgssymbolbutton.h
qgstablewidgetbase.h qgstablewidgetbase.h
qgstabwidget.h qgstabwidget.h
qgstaskmanagerwidget.h qgstaskmanagerwidget.h

446
src/gui/qgssymbolbutton.cpp Normal file
View File

@ -0,0 +1,446 @@
/***************************************************************************
qgssymbolbutton.h
-----------------
Date : July 2017
Copyright : (C) 2017 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 "qgssymbolbutton.h"
#include "qgspanelwidget.h"
#include "qgsexpressioncontext.h"
#include "qgsexpressioncontextgenerator.h"
#include "qgsvectorlayer.h"
#include "qgssymbolselectordialog.h"
#include "qgsstyle.h"
#include "qgscolorwidgets.h"
#include "qgscolorschemeregistry.h"
#include "qgscolorswatchgrid.h"
#include "qgssymbollayerutils.h"
#include <QMenu>
#include <QClipboard>
#include <QDrag>
QgsSymbolButton::QgsSymbolButton( QWidget *parent, const QString &dialogTitle )
: QToolButton( parent )
, mDialogTitle( dialogTitle.isEmpty() ? tr( "Symbol Settings" ) : dialogTitle )
{
mSymbol.reset( QgsFillSymbol::createSimple( QgsStringMap() ) );
setAcceptDrops( true );
connect( this, &QAbstractButton::clicked, this, &QgsSymbolButton::showSettingsDialog );
//setup dropdown menu
mMenu = new QMenu( this );
connect( mMenu, &QMenu::aboutToShow, this, &QgsSymbolButton::prepareMenu );
setMenu( mMenu );
setPopupMode( QToolButton::MenuButtonPopup );
}
QSize QgsSymbolButton::minimumSizeHint() const
{
//make sure height of button looks good under different platforms
QSize size = QToolButton::minimumSizeHint();
int fontHeight = fontMetrics().height() * 1.4;
return QSize( size.width(), qMax( size.height(), fontHeight ) );
}
void QgsSymbolButton::showSettingsDialog()
{
QgsExpressionContext context;
if ( mExpressionContextGenerator )
context = mExpressionContextGenerator->createExpressionContext();
else
{
context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer.data() ) );
}
QgsSymbol *newSymbol = mSymbol->clone();
QgsSymbolWidgetContext symbolContext;
symbolContext.setExpressionContext( &context );
symbolContext.setMapCanvas( mMapCanvas );
QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
if ( panel && panel->dockMode() )
{
QgsSymbolSelectorWidget *d = new QgsSymbolSelectorWidget( newSymbol, QgsStyle::defaultStyle(), mLayer, nullptr );
d->setContext( symbolContext );
connect( d, &QgsPanelWidget::widgetChanged, this, &QgsSymbolButton::updateSymbolFromWidget );
connect( d, &QgsPanelWidget::panelAccepted, this, &QgsSymbolButton::cleanUpSymbolSelector );
panel->openPanel( d );
}
else
{
QgsSymbolSelectorDialog dialog( newSymbol, QgsStyle::defaultStyle(), mLayer, nullptr );
dialog.setWindowTitle( mDialogTitle );
dialog.setContext( symbolContext );
if ( dialog.exec() )
{
setSymbol( newSymbol );
}
else
{
delete newSymbol;
}
// reactivate button's window
activateWindow();
}
}
void QgsSymbolButton::updateSymbolFromWidget()
{
if ( QgsSymbolSelectorWidget *w = qobject_cast<QgsSymbolSelectorWidget *>( sender() ) )
setSymbol( w->symbol()->clone() );
}
void QgsSymbolButton::cleanUpSymbolSelector( QgsPanelWidget *container )
{
QgsSymbolSelectorWidget *w = qobject_cast<QgsSymbolSelectorWidget *>( container );
if ( !w )
return;
delete w->symbol();
}
QgsMapCanvas *QgsSymbolButton::mapCanvas() const
{
return mMapCanvas;
}
void QgsSymbolButton::setMapCanvas( QgsMapCanvas *mapCanvas )
{
mMapCanvas = mapCanvas;
}
QgsVectorLayer *QgsSymbolButton::layer() const
{
return mLayer;
}
void QgsSymbolButton::setLayer( QgsVectorLayer *layer )
{
mLayer = layer;
}
void QgsSymbolButton::registerExpressionContextGenerator( QgsExpressionContextGenerator *generator )
{
mExpressionContextGenerator = generator;
}
void QgsSymbolButton::setSymbol( QgsSymbol *symbol )
{
mSymbol.reset( symbol );
updatePreview();
emit changed();
}
void QgsSymbolButton::setColor( const QColor &color )
{
QColor opaque = color;
opaque.setAlphaF( 1.0 );
if ( opaque == mSymbol->color() )
return;
mSymbol->setColor( opaque );
updatePreview();
emit changed();
}
void QgsSymbolButton::copyColor()
{
QApplication::clipboard()->setMimeData( QgsSymbolLayerUtils::colorToMimeData( mSymbol->color() ) );
}
void QgsSymbolButton::pasteColor()
{
QColor clipColor;
bool hasAlpha = false;
if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
{
//paste color
setColor( clipColor );
QgsRecentColorScheme::addRecentColor( clipColor );
}
}
void QgsSymbolButton::mousePressEvent( QMouseEvent *e )
{
if ( e->button() == Qt::RightButton )
{
QToolButton::showMenu();
return;
}
else if ( e->button() == Qt::LeftButton )
{
mDragStartPosition = e->pos();
}
QToolButton::mousePressEvent( e );
}
void QgsSymbolButton::mouseMoveEvent( QMouseEvent *e )
{
//handle dragging colors/symbols from button
if ( !( e->buttons() & Qt::LeftButton ) )
{
//left button not depressed, so not a drag
QToolButton::mouseMoveEvent( e );
return;
}
if ( ( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
{
//mouse not moved, so not a drag
QToolButton::mouseMoveEvent( e );
return;
}
//user is dragging
QDrag *drag = new QDrag( this );
drag->setMimeData( QgsSymbolLayerUtils::colorToMimeData( mSymbol->color() ) );
drag->setPixmap( QgsColorWidget::createDragIcon( mSymbol->color() ) );
drag->exec( Qt::CopyAction );
setDown( false );
}
void QgsSymbolButton::dragEnterEvent( QDragEnterEvent *e )
{
//is dragged data valid color data?
QColor mimeColor;
bool hasAlpha = false;
if ( colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
{
//if so, we accept the drag, and temporarily change the button's color
//to match the dragged color. This gives immediate feedback to the user
//that colors can be dropped here
e->acceptProposedAction();
updatePreview( mimeColor );
}
}
void QgsSymbolButton::dragLeaveEvent( QDragLeaveEvent *e )
{
Q_UNUSED( e );
//reset button color
updatePreview();
}
void QgsSymbolButton::dropEvent( QDropEvent *e )
{
//is dropped data valid format data?
QColor mimeColor;
bool hasAlpha = false;
if ( colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
{
//accept drop and set new color
e->acceptProposedAction();
if ( hasAlpha )
{
mSymbol->setOpacity( mimeColor.alphaF() );
}
mimeColor.setAlphaF( 1.0 );
mSymbol->setColor( mimeColor );
QgsRecentColorScheme::addRecentColor( mimeColor );
updatePreview();
emit changed();
}
updatePreview();
}
void QgsSymbolButton::prepareMenu()
{
//we need to tear down and rebuild this menu every time it is shown. Otherwise the space allocated to any
//QgsColorSwatchGridAction is not recalculated by Qt and the swatch grid may not be the correct size
//for the number of colors shown in the grid. Note that we MUST refresh color swatch grids every time this
//menu is opened, otherwise color schemes like the recent color scheme grid are meaningless
mMenu->clear();
QAction *configureAction = new QAction( tr( "Configure symbol..." ), this );
mMenu->addAction( configureAction );
connect( configureAction, &QAction::triggered, this, &QgsSymbolButton::showSettingsDialog );
mMenu->addSeparator();
QgsColorWheel *colorWheel = new QgsColorWheel( mMenu );
colorWheel->setColor( mSymbol->color() );
QgsColorWidgetAction *colorAction = new QgsColorWidgetAction( colorWheel, mMenu, mMenu );
colorAction->setDismissOnColorSelection( false );
connect( colorAction, &QgsColorWidgetAction::colorChanged, this, &QgsSymbolButton::setColor );
mMenu->addAction( colorAction );
//get schemes with ShowInColorButtonMenu flag set
QList< QgsColorScheme * > schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorButtonMenu );
QList< QgsColorScheme * >::iterator it = schemeList.begin();
for ( ; it != schemeList.end(); ++it )
{
QgsColorSwatchGridAction *colorAction = new QgsColorSwatchGridAction( *it, mMenu, QStringLiteral( "symbology" ), this );
colorAction->setBaseColor( mSymbol->color() );
mMenu->addAction( colorAction );
connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsSymbolButton::setColor );
connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsSymbolButton::addRecentColor );
}
mMenu->addSeparator();
QAction *copyColorAction = new QAction( tr( "Copy color" ), this );
mMenu->addAction( copyColorAction );
connect( copyColorAction, &QAction::triggered, this, &QgsSymbolButton::copyColor );
QAction *pasteColorAction = new QAction( tr( "Paste color" ), this );
//enable or disable paste action based on current clipboard contents. We always show the paste
//action, even if it's disabled, to give hint to the user that pasting colors is possible
QColor clipColor;
bool hasAlpha = false;
if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
{
pasteColorAction->setIcon( createColorIcon( clipColor ) );
}
else
{
pasteColorAction->setEnabled( false );
}
mMenu->addAction( pasteColorAction );
connect( pasteColorAction, &QAction::triggered, this, &QgsSymbolButton::pasteColor );
}
void QgsSymbolButton::addRecentColor( const QColor &color )
{
QgsRecentColorScheme::addRecentColor( color );
}
void QgsSymbolButton::changeEvent( QEvent *e )
{
if ( e->type() == QEvent::EnabledChange )
{
updatePreview();
}
QToolButton::changeEvent( e );
}
void QgsSymbolButton::showEvent( QShowEvent *e )
{
updatePreview();
QToolButton::showEvent( e );
}
void QgsSymbolButton::resizeEvent( QResizeEvent *event )
{
QToolButton::resizeEvent( event );
//recalculate icon size and redraw icon
mIconSize = QSize();
updatePreview();
}
void QgsSymbolButton::updatePreview( const QColor &color, QgsSymbol *tempSymbol )
{
std::unique_ptr< QgsSymbol > previewSymbol;
if ( tempSymbol )
previewSymbol.reset( tempSymbol->clone() );
else
previewSymbol.reset( mSymbol->clone() );
if ( color.isValid() )
previewSymbol->setColor( color );
QSize currentIconSize;
//icon size is button size with a small margin
if ( menu() )
{
if ( !mIconSize.isValid() )
{
//calculate size of push button part of widget (ie, without the menu dropdown button part)
QStyleOptionToolButton opt;
initStyleOption( &opt );
QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
this );
//make sure height of icon looks good under different platforms
#ifdef Q_OS_WIN
mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
#else
mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
#endif
}
currentIconSize = mIconSize;
}
else
{
//no menu
#ifdef Q_OS_WIN
currentIconSize = QSize( width() - 10, height() - 6 );
#else
currentIconSize = QSize( width() - 10, height() - 12 );
#endif
}
if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
{
return;
}
//create an icon pixmap
QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( previewSymbol.get(), currentIconSize );
setIconSize( currentIconSize );
setIcon( icon );
}
bool QgsSymbolButton::colorFromMimeData( const QMimeData *mimeData, QColor &resultColor, bool &hasAlpha )
{
hasAlpha = false;
QColor mimeColor = QgsSymbolLayerUtils::colorFromMimeData( mimeData, hasAlpha );
if ( mimeColor.isValid() )
{
resultColor = mimeColor;
return true;
}
//could not get color from mime data
return false;
}
QPixmap QgsSymbolButton::createColorIcon( const QColor &color ) const
{
//create an icon pixmap
QPixmap pixmap( 16, 16 );
pixmap.fill( Qt::transparent );
QPainter p;
p.begin( &pixmap );
//draw color over pattern
p.setBrush( QBrush( color ) );
//draw border
p.setPen( QColor( 197, 197, 197 ) );
p.drawRect( 0, 0, 15, 15 );
p.end();
return pixmap;
}
void QgsSymbolButton::setDialogTitle( const QString &title )
{
mDialogTitle = title;
}
QString QgsSymbolButton::dialogTitle() const
{
return mDialogTitle;
}
QgsSymbol *QgsSymbolButton::symbol()
{
return mSymbol.get();
}

218
src/gui/qgssymbolbutton.h Normal file
View File

@ -0,0 +1,218 @@
/***************************************************************************
qgssymbolbutton.h
-----------------
Date : July 2017
Copyright : (C) 2017 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 QGSSYMBOLBUTTON_H
#define QGSSYMBOLBUTTON_H
#include "qgis_gui.h"
#include "qgis.h"
#include "qgssymbol.h"
#include <QToolButton>
#include <QPointer>
#include <memory>
class QgsMapCanvas;
class QgsVectorLayer;
class QgsExpressionContextGenerator;
class QgsPanelWidget;
/**
* \ingroup gui
* \class QgsSymbolButton
* A button for creating and modifying QgsSymbol settings.
*
* The button shows a preview icon for the current symbol, and will open a detailed symbol editor dialog (or
* panel widget) when clicked.
*
* \since QGIS 3.0
*/
class GUI_EXPORT QgsSymbolButton : public QToolButton
{
Q_OBJECT
Q_PROPERTY( QString dialogTitle READ dialogTitle WRITE setDialogTitle )
public:
/**
* Construct a new symbol button.
* Use \a dialogTitle string to define the title to show in the symbol settings dialog.
*/
QgsSymbolButton( QWidget *parent SIP_TRANSFERTHIS = nullptr, const QString &dialogTitle = QString() );
virtual QSize minimumSizeHint() const override;
/**
* Sets the \a title for the symbol settings dialog window.
* \see dialogTitle()
*/
void setDialogTitle( const QString &title );
/**
* Returns the title for the symbol settings dialog window.
* \see setDialogTitle()
*/
QString dialogTitle() const;
/**
* Returns the current symbol defined by the button.
* \see setSymbol()
* \see changed()
*/
QgsSymbol *symbol();
/**
* Returns the map canvas associated with the widget.
* \see setMapCanvas()
*/
QgsMapCanvas *mapCanvas() const;
/**
* Sets a map \a canvas to associate with the widget. This allows the
* widget to fetch current settings from the map canvas, such as current scale.
* \see mapCanvas()
*/
void setMapCanvas( QgsMapCanvas *canvas );
/**
* Returns the layer associated with the widget.
* \see setLayer()
*/
QgsVectorLayer *layer() const;
/**
* Sets a \a layer to associate with the widget. This allows the
* widget to setup layer related settings within the symbol settings dialog,
* such as correctly populating data defined override buttons.
* \see layer()
*/
void setLayer( QgsVectorLayer *layer );
/**
* Register an expression context generator class that will be used to retrieve
* an expression context for the button when required.
*/
void registerExpressionContextGenerator( QgsExpressionContextGenerator *generator );
public slots:
/**
* Sets the \a symbol for the button. Ownership of \a symbol is transferred to the
* button.
* \see symbol()
* \see changed()
*/
void setSymbol( QgsSymbol *symbol SIP_TRANSFER );
/**
* Sets the current \a color for the symbol. Will emit a changed() signal if the color is different
* to the previous symbol color.
*/
void setColor( const QColor &color );
/**
* Copies the current symbol color to the clipboard.
* \see pasteColor()
*/
void copyColor();
/**
* Pastes a color from the clipboard to the symbol. If clipboard does not contain a valid
* color or string representation of a color, then no change is applied.
* \see copyColor()
*/
void pasteColor();
signals:
/**
* Emitted when the symbol's settings are changed.
* \see symbol()
* \see setSymbol()
*/
void changed();
protected:
void changeEvent( QEvent *e ) override;
void showEvent( QShowEvent *e ) override;
void resizeEvent( QResizeEvent *event ) override;
// Reimplemented to detect right mouse button clicks on the color button and allow dragging colors
void mousePressEvent( QMouseEvent *e ) override;
// Reimplemented to allow dragging colors/symbols from button
void mouseMoveEvent( QMouseEvent *e ) override;
// Reimplemented to accept dragged colors
void dragEnterEvent( QDragEnterEvent *e ) override;
// Reimplemented to reset button appearance after drag leave
void dragLeaveEvent( QDragLeaveEvent *e ) override;
// Reimplemented to accept dropped colors
void dropEvent( QDropEvent *e ) override;
private slots:
void showSettingsDialog();
void updateSymbolFromWidget();
void cleanUpSymbolSelector( QgsPanelWidget *container );
/** Creates the drop-down menu entries
*/
void prepareMenu();
void addRecentColor( const QColor &color );
private:
QString mDialogTitle;
QgsMapCanvas *mMapCanvas = nullptr;
QPoint mDragStartPosition;
QMenu *mMenu = nullptr;
QPointer< QgsVectorLayer > mLayer;
QSize mIconSize;
std::unique_ptr< QgsSymbol > mSymbol;
QgsExpressionContextGenerator *mExpressionContextGenerator = nullptr;
/**
* Regenerates the text preview. If \a color is specified, a temporary color preview
* is shown instead.
*/
void updatePreview( const QColor &color = QColor(), QgsSymbol *tempSymbol = nullptr );
/** Attempts to parse mimeData as a color, either via the mime data's color data or by
* parsing a textual representation of a color.
* \returns true if mime data could be intrepreted as a color
* \param mimeData mime data
* \param resultColor QColor to store evaluated color
* \param hasAlpha will be set to true if mime data also included an alpha component
* \see formatFromMimeData
*/
bool colorFromMimeData( const QMimeData *mimeData, QColor &resultColor, bool &hasAlpha );
/**
* Create a \a color icon for display in the drop-down menu.
*/
QPixmap createColorIcon( const QColor &color ) const;
};
#endif // QGSSYMBOLBUTTON_H

View File

@ -126,6 +126,7 @@ ADD_PYTHON_TEST(PyQgsRenderer test_qgsrenderer.py)
ADD_PYTHON_TEST(PyQgsRulebasedRenderer test_qgsrulebasedrenderer.py) ADD_PYTHON_TEST(PyQgsRulebasedRenderer test_qgsrulebasedrenderer.py)
ADD_PYTHON_TEST(PyQgsSingleSymbolRenderer test_qgssinglesymbolrenderer.py) ADD_PYTHON_TEST(PyQgsSingleSymbolRenderer test_qgssinglesymbolrenderer.py)
ADD_PYTHON_TEST(PyQgsShapefileProvider test_provider_shapefile.py) ADD_PYTHON_TEST(PyQgsShapefileProvider test_provider_shapefile.py)
ADD_PYTHON_TEST(PyQgsSymbolButton test_qgssymbolbutton.py)
ADD_PYTHON_TEST(PyQgsTabfileProvider test_provider_tabfile.py) ADD_PYTHON_TEST(PyQgsTabfileProvider test_provider_tabfile.py)
ADD_PYTHON_TEST(PyQgsTabWidget test_qgstabwidget.py) ADD_PYTHON_TEST(PyQgsTabWidget test_qgstabwidget.py)
ADD_PYTHON_TEST(PyQgsTextRenderer test_qgstextrenderer.py) ADD_PYTHON_TEST(PyQgsTextRenderer test_qgstextrenderer.py)

View File

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsSymbolButton.
.. note:: 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.
"""
__author__ = 'Nyall Dawson'
__date__ = '23/07/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # NOQA
from qgis.core import QgsFillSymbol, QgsMarkerSymbol
from qgis.gui import QgsSymbolButton, QgsMapCanvas
from qgis.testing import start_app, unittest
from qgis.PyQt.QtGui import QColor, QFont
from qgis.PyQt.QtTest import QSignalSpy
from utilities import getTestFont
start_app()
class TestQgsSymbolButton(unittest.TestCase):
def testGettersSetters(self):
button = QgsSymbolButton()
canvas = QgsMapCanvas()
button.setDialogTitle('test title')
self.assertEqual(button.dialogTitle(), 'test title')
button.setMapCanvas(canvas)
self.assertEqual(button.mapCanvas(), canvas)
def testSetGetSymbol(self):
button = QgsSymbolButton()
symbol = QgsMarkerSymbol.createSimple({})
symbol.setColor(QColor(255, 0, 0))
signal_spy = QSignalSpy(button.changed)
button.setSymbol(symbol)
self.assertEqual(len(signal_spy), 1)
r = button.symbol()
self.assertEqual(r.color(), QColor(255, 0, 0))
def testSetColor(self):
button = QgsSymbolButton()
symbol = QgsMarkerSymbol.createSimple({})
symbol.setColor(QColor(255, 255, 0))
button.setSymbol(symbol)
signal_spy = QSignalSpy(button.changed)
button.setColor(QColor(0, 255, 0))
self.assertEqual(len(signal_spy), 1)
r = button.symbol()
self.assertEqual(r.color().name(), QColor(0, 255, 0).name())
# set same color, should not emit signal
button.setColor(QColor(0, 255, 0))
self.assertEqual(len(signal_spy), 1)
# color with transparency - should be stripped
button.setColor(QColor(0, 255, 0, 100))
r = button.symbol()
self.assertEqual(r.color(), QColor(0, 255, 0))
if __name__ == '__main__':
unittest.main()