mirror of
https://github.com/qgis/QGIS.git
synced 2025-03-31 00:03:42 -04:00
887 lines
26 KiB
C++
887 lines
26 KiB
C++
/***************************************************************************
|
|
qgsfontbutton.h
|
|
---------------
|
|
Date : May 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 "qgsfontbutton.h"
|
|
#include "qgstextformatwidget.h"
|
|
#include "qgssymbollayerutils.h"
|
|
#include "qgscolorscheme.h"
|
|
#include "qgsmapcanvas.h"
|
|
#include "qgscolorwidgets.h"
|
|
#include "qgscolorschemeregistry.h"
|
|
#include "qgscolorswatchgrid.h"
|
|
#include "qgsdoublespinbox.h"
|
|
#include "qgsunittypes.h"
|
|
#include "qgsmenuheader.h"
|
|
#include "qgsfontutils.h"
|
|
#include <QMenu>
|
|
#include <QClipboard>
|
|
#include <QDrag>
|
|
#include <QDesktopWidget>
|
|
#include <QToolTip>
|
|
|
|
QgsFontButton::QgsFontButton( QWidget *parent, const QString &dialogTitle )
|
|
: QToolButton( parent )
|
|
, mDialogTitle( dialogTitle.isEmpty() ? tr( "Text Format" ) : dialogTitle )
|
|
|
|
{
|
|
setText( tr( "Font" ) );
|
|
|
|
setAcceptDrops( true );
|
|
connect( this, &QAbstractButton::clicked, this, &QgsFontButton::showSettingsDialog );
|
|
|
|
//setup dropdown menu
|
|
mMenu = new QMenu( this );
|
|
connect( mMenu, &QMenu::aboutToShow, this, &QgsFontButton::prepareMenu );
|
|
setMenu( mMenu );
|
|
setPopupMode( QToolButton::MenuButtonPopup );
|
|
|
|
//make sure height of button looks good under different platforms
|
|
QSize size = QToolButton::minimumSizeHint();
|
|
int fontHeight = Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 1.4;
|
|
mSizeHint = QSize( size.width(), std::max( size.height(), fontHeight ) );
|
|
}
|
|
|
|
QSize QgsFontButton::minimumSizeHint() const
|
|
{
|
|
return mSizeHint;
|
|
}
|
|
|
|
QSize QgsFontButton::sizeHint() const
|
|
{
|
|
return mSizeHint;
|
|
}
|
|
|
|
void QgsFontButton::showSettingsDialog()
|
|
{
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
{
|
|
QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
|
|
if ( panel && panel->dockMode() )
|
|
{
|
|
QgsTextFormatPanelWidget *formatWidget = new QgsTextFormatPanelWidget( mFormat, mMapCanvas, this );
|
|
formatWidget->setPanelTitle( mDialogTitle );
|
|
|
|
connect( formatWidget, &QgsTextFormatPanelWidget::widgetChanged, this, [ this, formatWidget ] { this->setTextFormat( formatWidget->format() ); } );
|
|
panel->openPanel( formatWidget );
|
|
return;
|
|
}
|
|
|
|
QgsTextFormatDialog dialog( mFormat, mMapCanvas, this );
|
|
dialog.setWindowTitle( mDialogTitle );
|
|
if ( dialog.exec() )
|
|
{
|
|
setTextFormat( dialog.format() );
|
|
QgsFontUtils::addRecentFontFamily( mFormat.font().family() );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ModeQFont:
|
|
{
|
|
bool ok;
|
|
QFont newFont = QgsGuiUtils::getFont( ok, mFont, mDialogTitle );
|
|
if ( ok )
|
|
{
|
|
QgsFontUtils::addRecentFontFamily( newFont.family() );
|
|
setCurrentFont( newFont );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// reactivate button's window
|
|
activateWindow();
|
|
raise();
|
|
}
|
|
|
|
QgsMapCanvas *QgsFontButton::mapCanvas() const
|
|
{
|
|
return mMapCanvas;
|
|
}
|
|
|
|
void QgsFontButton::setMapCanvas( QgsMapCanvas *mapCanvas )
|
|
{
|
|
mMapCanvas = mapCanvas;
|
|
}
|
|
|
|
void QgsFontButton::setTextFormat( const QgsTextFormat &format )
|
|
{
|
|
mFormat = format;
|
|
updatePreview();
|
|
emit changed();
|
|
}
|
|
|
|
void QgsFontButton::setColor( const QColor &color )
|
|
{
|
|
QColor opaque = color;
|
|
opaque.setAlphaF( 1.0 );
|
|
|
|
if ( mFormat.color() != opaque )
|
|
{
|
|
mFormat.setColor( opaque );
|
|
updatePreview();
|
|
emit changed();
|
|
}
|
|
}
|
|
|
|
void QgsFontButton::copyFormat()
|
|
{
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
QApplication::clipboard()->setMimeData( mFormat.toMimeData() );
|
|
break;
|
|
|
|
case ModeQFont:
|
|
QApplication::clipboard()->setMimeData( QgsFontUtils::toMimeData( mFont ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void QgsFontButton::pasteFormat()
|
|
{
|
|
QgsTextFormat tempFormat;
|
|
QFont font;
|
|
if ( mMode == ModeTextRenderer && formatFromMimeData( QApplication::clipboard()->mimeData(), tempFormat ) )
|
|
{
|
|
setTextFormat( tempFormat );
|
|
QgsFontUtils::addRecentFontFamily( mFormat.font().family() );
|
|
}
|
|
else if ( mMode == ModeQFont && fontFromMimeData( QApplication::clipboard()->mimeData(), font ) )
|
|
{
|
|
QgsFontUtils::addRecentFontFamily( font.family() );
|
|
setCurrentFont( font );
|
|
}
|
|
}
|
|
|
|
bool QgsFontButton::event( QEvent *e )
|
|
{
|
|
if ( e->type() == QEvent::ToolTip )
|
|
{
|
|
QHelpEvent *helpEvent = static_cast< QHelpEvent *>( e );
|
|
QString toolTip;
|
|
double fontSize = 0.0;
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
fontSize = mFormat.size();
|
|
break;
|
|
|
|
case ModeQFont:
|
|
fontSize = mFont.pointSizeF();
|
|
break;
|
|
}
|
|
toolTip = QStringLiteral( "<b>%1</b><br>%2<br>Size: %3" ).arg( text(), mFormat.font().family() ).arg( fontSize );
|
|
QToolTip::showText( helpEvent->globalPos(), toolTip );
|
|
}
|
|
return QToolButton::event( e );
|
|
}
|
|
|
|
void QgsFontButton::mousePressEvent( QMouseEvent *e )
|
|
{
|
|
if ( e->button() == Qt::RightButton )
|
|
{
|
|
QToolButton::showMenu();
|
|
return;
|
|
}
|
|
else if ( e->button() == Qt::LeftButton )
|
|
{
|
|
mDragStartPosition = e->pos();
|
|
}
|
|
QToolButton::mousePressEvent( e );
|
|
}
|
|
|
|
void QgsFontButton::mouseMoveEvent( QMouseEvent *e )
|
|
{
|
|
//handle dragging fonts 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 font
|
|
QDrag *drag = new QDrag( this );
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
drag->setMimeData( mFormat.toMimeData() );
|
|
break;
|
|
|
|
case ModeQFont:
|
|
drag->setMimeData( QgsFontUtils::toMimeData( mFont ) );
|
|
break;
|
|
}
|
|
drag->setPixmap( createDragIcon() );
|
|
drag->exec( Qt::CopyAction );
|
|
setDown( false );
|
|
}
|
|
|
|
bool QgsFontButton::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;
|
|
}
|
|
|
|
void QgsFontButton::dragEnterEvent( QDragEnterEvent *e )
|
|
{
|
|
//is dragged data valid font data?
|
|
QColor mimeColor;
|
|
QgsTextFormat format;
|
|
QFont font;
|
|
bool hasAlpha = false;
|
|
|
|
if ( mMode == ModeTextRenderer && formatFromMimeData( e->mimeData(), format ) )
|
|
{
|
|
e->acceptProposedAction();
|
|
updatePreview( QColor(), &format );
|
|
}
|
|
else if ( mMode == ModeQFont && fontFromMimeData( e->mimeData(), font ) )
|
|
{
|
|
e->acceptProposedAction();
|
|
updatePreview( QColor(), nullptr, &font );
|
|
}
|
|
else if ( mMode == ModeTextRenderer && 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 QgsFontButton::dragLeaveEvent( QDragLeaveEvent *e )
|
|
{
|
|
Q_UNUSED( e );
|
|
//reset button color
|
|
updatePreview();
|
|
}
|
|
|
|
void QgsFontButton::dropEvent( QDropEvent *e )
|
|
{
|
|
//is dropped data valid format data?
|
|
QColor mimeColor;
|
|
QgsTextFormat format;
|
|
QFont font;
|
|
bool hasAlpha = false;
|
|
if ( mMode == ModeTextRenderer && formatFromMimeData( e->mimeData(), format ) )
|
|
{
|
|
setTextFormat( format );
|
|
QgsFontUtils::addRecentFontFamily( mFormat.font().family() );
|
|
return;
|
|
}
|
|
else if ( mMode == ModeQFont && fontFromMimeData( e->mimeData(), font ) )
|
|
{
|
|
QgsFontUtils::addRecentFontFamily( font.family() );
|
|
setCurrentFont( font );
|
|
return;
|
|
}
|
|
else if ( mMode == ModeTextRenderer && colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
|
|
{
|
|
//accept drop and set new color
|
|
e->acceptProposedAction();
|
|
|
|
if ( hasAlpha )
|
|
{
|
|
mFormat.setOpacity( mimeColor.alphaF() );
|
|
}
|
|
mimeColor.setAlphaF( 1.0 );
|
|
mFormat.setColor( mimeColor );
|
|
QgsRecentColorScheme::addRecentColor( mimeColor );
|
|
updatePreview();
|
|
emit changed();
|
|
}
|
|
updatePreview();
|
|
}
|
|
|
|
void QgsFontButton::wheelEvent( QWheelEvent *event )
|
|
{
|
|
double size = 0;
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
size = mFormat.size();
|
|
break;
|
|
|
|
case ModeQFont:
|
|
size = mFont.pointSizeF();
|
|
break;
|
|
}
|
|
|
|
double increment = event->modifiers() & Qt::ControlModifier ? 0.1 : 1;
|
|
if ( event->delta() > 0 )
|
|
{
|
|
size += increment;
|
|
}
|
|
else
|
|
{
|
|
size -= increment;
|
|
}
|
|
size = std::max( size, 1.0 );
|
|
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
{
|
|
QgsTextFormat newFormat = mFormat;
|
|
newFormat.setSize( size );
|
|
setTextFormat( newFormat );
|
|
break;
|
|
}
|
|
|
|
case ModeQFont:
|
|
{
|
|
QFont newFont = mFont;
|
|
newFont.setPointSizeF( size );
|
|
setCurrentFont( newFont );
|
|
break;
|
|
}
|
|
}
|
|
|
|
event->accept();
|
|
}
|
|
|
|
QPixmap QgsFontButton::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;
|
|
}
|
|
|
|
QPixmap QgsFontButton::createDragIcon( QSize size, const QgsTextFormat *tempFormat, const QFont *tempFont ) const
|
|
{
|
|
if ( !tempFormat )
|
|
tempFormat = &mFormat;
|
|
if ( !tempFont )
|
|
tempFont = &mFont;
|
|
|
|
//create an icon pixmap
|
|
QPixmap pixmap( size.width(), size.height() );
|
|
pixmap.fill( Qt::transparent );
|
|
QPainter p;
|
|
p.begin( &pixmap );
|
|
p.setRenderHint( QPainter::Antialiasing );
|
|
QRect rect( 0, 0, size.width(), size.height() );
|
|
|
|
if ( mMode == ModeQFont || tempFormat->color().lightnessF() < 0.7 )
|
|
{
|
|
p.setBrush( QBrush( QColor( 255, 255, 255 ) ) );
|
|
p.setPen( QPen( QColor( 150, 150, 150 ), 0 ) );
|
|
}
|
|
else
|
|
{
|
|
p.setBrush( QBrush( QColor( 0, 0, 0 ) ) );
|
|
p.setPen( QPen( QColor( 100, 100, 100 ), 0 ) );
|
|
}
|
|
p.drawRect( rect );
|
|
p.setBrush( Qt::NoBrush );
|
|
p.setPen( Qt::NoPen );
|
|
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
{
|
|
QgsRenderContext context;
|
|
QgsMapToPixel newCoordXForm;
|
|
newCoordXForm.setParameters( 1, 0, 0, 0, 0, 0 );
|
|
context.setMapToPixel( newCoordXForm );
|
|
|
|
context.setScaleFactor( QgsApplication::desktop()->logicalDpiX() / 25.4 );
|
|
context.setUseAdvancedEffects( true );
|
|
context.setPainter( &p );
|
|
|
|
// slightly inset text to account for buffer/background
|
|
double xtrans = 0;
|
|
if ( tempFormat->buffer().enabled() )
|
|
xtrans = context.convertToPainterUnits( tempFormat->buffer().size(), tempFormat->buffer().sizeUnit(), tempFormat->buffer().sizeMapUnitScale() );
|
|
if ( tempFormat->background().enabled() && tempFormat->background().sizeType() != QgsTextBackgroundSettings::SizeFixed )
|
|
xtrans = std::max( xtrans, context.convertToPainterUnits( tempFormat->background().size().width(), tempFormat->background().sizeUnit(), tempFormat->background().sizeMapUnitScale() ) );
|
|
|
|
double ytrans = 0.0;
|
|
if ( tempFormat->buffer().enabled() )
|
|
ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat->buffer().size(), tempFormat->buffer().sizeUnit(), tempFormat->buffer().sizeMapUnitScale() ) );
|
|
if ( tempFormat->background().enabled() )
|
|
ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat->background().size().height(), tempFormat->background().sizeUnit(), tempFormat->background().sizeMapUnitScale() ) );
|
|
|
|
QRectF textRect = rect;
|
|
textRect.setLeft( xtrans );
|
|
textRect.setWidth( textRect.width() - xtrans );
|
|
textRect.setTop( ytrans );
|
|
if ( textRect.height() > 300 )
|
|
textRect.setHeight( 300 );
|
|
if ( textRect.width() > 2000 )
|
|
textRect.setWidth( 2000 );
|
|
|
|
QgsTextRenderer::drawText( textRect, 0, QgsTextRenderer::AlignCenter, QStringList() << tr( "Aa" ),
|
|
context, *tempFormat );
|
|
break;
|
|
}
|
|
case ModeQFont:
|
|
{
|
|
p.setBrush( Qt::NoBrush );
|
|
p.setPen( QColor( 0, 0, 0 ) );
|
|
p.setFont( *tempFont );
|
|
QRectF textRect = rect;
|
|
textRect.setLeft( 2 );
|
|
p.drawText( textRect, Qt::AlignVCenter, tr( "Aa" ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
p.end();
|
|
return pixmap;
|
|
}
|
|
|
|
void QgsFontButton::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();
|
|
|
|
|
|
QWidgetAction *sizeAction = new QWidgetAction( mMenu );
|
|
QWidget *sizeWidget = new QWidget();
|
|
QVBoxLayout *sizeLayout = new QVBoxLayout();
|
|
sizeLayout->setMargin( 0 );
|
|
sizeLayout->setContentsMargins( 0, 0, 0, 3 );
|
|
sizeLayout->setSpacing( 2 );
|
|
|
|
QString fontHeaderLabel;
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
fontHeaderLabel = tr( "Font size (%1)" ).arg( QgsUnitTypes::toString( mFormat.sizeUnit() ) );
|
|
break;
|
|
|
|
case ModeQFont:
|
|
fontHeaderLabel = tr( "Font size (pt)" );
|
|
break;
|
|
}
|
|
|
|
QgsMenuHeader *sizeLabel = new QgsMenuHeader( fontHeaderLabel );
|
|
sizeLayout->addWidget( sizeLabel );
|
|
|
|
QgsDoubleSpinBox *sizeSpin = new QgsDoubleSpinBox( nullptr );
|
|
sizeSpin->setDecimals( 4 );
|
|
sizeSpin->setMaximum( 1e+9 );
|
|
sizeSpin->setShowClearButton( false );
|
|
sizeSpin->setValue( mMode == ModeTextRenderer ? mFormat.size() : mFont.pointSizeF() );
|
|
connect( sizeSpin, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ),
|
|
this, [ = ]( double value )
|
|
{
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
mFormat.setSize( value );
|
|
break;
|
|
case ModeQFont:
|
|
mFont.setPointSizeF( value );
|
|
break;
|
|
}
|
|
updatePreview();
|
|
emit changed();
|
|
} );
|
|
QHBoxLayout *spinLayout = new QHBoxLayout();
|
|
spinLayout->setMargin( 0 );
|
|
spinLayout->setContentsMargins( 4, 0, 4, 0 );
|
|
spinLayout->addWidget( sizeSpin );
|
|
sizeLayout->addLayout( spinLayout );
|
|
sizeWidget->setLayout( sizeLayout );
|
|
sizeAction->setDefaultWidget( sizeWidget );
|
|
sizeWidget->setFocusProxy( sizeSpin );
|
|
sizeWidget->setFocusPolicy( Qt::StrongFocus );
|
|
mMenu->addAction( sizeAction );
|
|
|
|
QMenu *recentFontMenu = new QMenu( tr( "Recent fonts" ), mMenu );
|
|
Q_FOREACH ( const QString &family, QgsFontUtils::recentFontFamilies() )
|
|
{
|
|
QAction *fontAction = new QAction( family, recentFontMenu );
|
|
QFont f = fontAction->font();
|
|
f.setFamily( family );
|
|
fontAction->setFont( f );
|
|
fontAction->setToolTip( family );
|
|
recentFontMenu->addAction( fontAction );
|
|
if ( ( mMode == ModeTextRenderer && family == mFormat.font().family() )
|
|
|| ( mMode == ModeQFont && family == mFont.family() ) )
|
|
{
|
|
fontAction->setCheckable( true );
|
|
fontAction->setChecked( true );
|
|
}
|
|
auto setFont = [this, family]
|
|
{
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
{
|
|
QgsTextFormat newFormat = mFormat;
|
|
QFont f = newFormat.font();
|
|
f.setFamily( family );
|
|
newFormat.setFont( f );
|
|
setTextFormat( newFormat );
|
|
QgsFontUtils::addRecentFontFamily( mFormat.font().family() );
|
|
break;
|
|
}
|
|
case ModeQFont:
|
|
{
|
|
QFont font = mFont;
|
|
font.setFamily( family );
|
|
setCurrentFont( font );
|
|
QgsFontUtils::addRecentFontFamily( family );
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
connect( fontAction, &QAction::triggered, this, setFont );
|
|
}
|
|
mMenu->addMenu( recentFontMenu );
|
|
|
|
QAction *configureAction = new QAction( tr( "Configure Format…" ), this );
|
|
mMenu->addAction( configureAction );
|
|
connect( configureAction, &QAction::triggered, this, &QgsFontButton::showSettingsDialog );
|
|
|
|
QAction *copyFormatAction = new QAction( tr( "Copy Format" ), this );
|
|
mMenu->addAction( copyFormatAction );
|
|
connect( copyFormatAction, &QAction::triggered, this, &QgsFontButton::copyFormat );
|
|
QAction *pasteFormatAction = new QAction( tr( "Paste Format" ), 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
|
|
QgsTextFormat tempFormat;
|
|
QFont tempFont;
|
|
if ( mMode == ModeTextRenderer && formatFromMimeData( QApplication::clipboard()->mimeData(), tempFormat ) )
|
|
{
|
|
tempFormat.setSizeUnit( QgsUnitTypes::RenderPixels );
|
|
tempFormat.setSize( 14 );
|
|
pasteFormatAction->setIcon( createDragIcon( QSize( 16, 16 ), &tempFormat ) );
|
|
}
|
|
else if ( mMode == ModeQFont && fontFromMimeData( QApplication::clipboard()->mimeData(), tempFont ) )
|
|
{
|
|
tempFont.setPointSize( 8 );
|
|
pasteFormatAction->setIcon( createDragIcon( QSize( 16, 16 ), nullptr, &tempFont ) );
|
|
}
|
|
else
|
|
{
|
|
pasteFormatAction->setEnabled( false );
|
|
}
|
|
mMenu->addAction( pasteFormatAction );
|
|
connect( pasteFormatAction, &QAction::triggered, this, &QgsFontButton::pasteFormat );
|
|
|
|
if ( mMode == ModeTextRenderer )
|
|
{
|
|
mMenu->addSeparator();
|
|
|
|
QgsColorWheel *colorWheel = new QgsColorWheel( mMenu );
|
|
colorWheel->setColor( mFormat.color() );
|
|
QgsColorWidgetAction *colorAction = new QgsColorWidgetAction( colorWheel, mMenu, mMenu );
|
|
colorAction->setDismissOnColorSelection( false );
|
|
connect( colorAction, &QgsColorWidgetAction::colorChanged, this, &QgsFontButton::setColor );
|
|
mMenu->addAction( colorAction );
|
|
|
|
QgsColorRampWidget *alphaRamp = new QgsColorRampWidget( mMenu, QgsColorWidget::Alpha, QgsColorRampWidget::Horizontal );
|
|
QColor alphaColor = mFormat.color();
|
|
alphaColor.setAlphaF( mFormat.opacity() );
|
|
alphaRamp->setColor( alphaColor );
|
|
QgsColorWidgetAction *alphaAction = new QgsColorWidgetAction( alphaRamp, mMenu, mMenu );
|
|
alphaAction->setDismissOnColorSelection( false );
|
|
connect( alphaAction, &QgsColorWidgetAction::colorChanged, this, [ = ]( const QColor & color )
|
|
{
|
|
double opacity = color.alphaF();
|
|
mFormat.setOpacity( opacity );
|
|
updatePreview();
|
|
emit changed();
|
|
} );
|
|
connect( colorAction, &QgsColorWidgetAction::colorChanged, alphaRamp, [alphaRamp]( const QColor & color ) { alphaRamp->setColor( color, false ); }
|
|
);
|
|
mMenu->addAction( alphaAction );
|
|
|
|
//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( "labeling" ), this );
|
|
colorAction->setBaseColor( mFormat.color() );
|
|
mMenu->addAction( colorAction );
|
|
connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsFontButton::setColor );
|
|
connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsFontButton::addRecentColor );
|
|
}
|
|
|
|
mMenu->addSeparator();
|
|
|
|
QAction *copyColorAction = new QAction( tr( "Copy Color" ), this );
|
|
mMenu->addAction( copyColorAction );
|
|
connect( copyColorAction, &QAction::triggered, this, &QgsFontButton::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, &QgsFontButton::pasteColor );
|
|
}
|
|
}
|
|
|
|
void QgsFontButton::addRecentColor( const QColor &color )
|
|
{
|
|
QgsRecentColorScheme::addRecentColor( color );
|
|
}
|
|
|
|
QFont QgsFontButton::currentFont() const
|
|
{
|
|
return mFont;
|
|
}
|
|
|
|
void QgsFontButton::setCurrentFont( const QFont &font )
|
|
{
|
|
mFont = font;
|
|
updatePreview();
|
|
emit changed();
|
|
}
|
|
|
|
QgsFontButton::Mode QgsFontButton::mode() const
|
|
{
|
|
return mMode;
|
|
}
|
|
|
|
void QgsFontButton::setMode( Mode mode )
|
|
{
|
|
mMode = mode;
|
|
updatePreview();
|
|
}
|
|
|
|
bool QgsFontButton::formatFromMimeData( const QMimeData *mimeData, QgsTextFormat &resultFormat ) const
|
|
{
|
|
bool ok = false;
|
|
resultFormat = QgsTextFormat::fromMimeData( mimeData, &ok );
|
|
return ok;
|
|
}
|
|
|
|
bool QgsFontButton::fontFromMimeData( const QMimeData *mimeData, QFont &resultFont ) const
|
|
{
|
|
bool ok = false;
|
|
resultFont = QgsFontUtils::fromMimeData( mimeData, &ok );
|
|
return ok;
|
|
}
|
|
|
|
void QgsFontButton::changeEvent( QEvent *e )
|
|
{
|
|
if ( e->type() == QEvent::EnabledChange )
|
|
{
|
|
updatePreview();
|
|
}
|
|
QToolButton::changeEvent( e );
|
|
}
|
|
|
|
void QgsFontButton::showEvent( QShowEvent *e )
|
|
{
|
|
updatePreview();
|
|
QToolButton::showEvent( e );
|
|
}
|
|
|
|
void QgsFontButton::resizeEvent( QResizeEvent *event )
|
|
{
|
|
QToolButton::resizeEvent( event );
|
|
//recalculate icon size and redraw icon
|
|
mIconSize = QSize();
|
|
updatePreview();
|
|
}
|
|
|
|
void QgsFontButton::updatePreview( const QColor &color, QgsTextFormat *format, QFont *font )
|
|
{
|
|
QgsTextFormat tempFormat;
|
|
QFont tempFont;
|
|
|
|
if ( format )
|
|
tempFormat = *format;
|
|
else
|
|
tempFormat = mFormat;
|
|
if ( font )
|
|
tempFont = *font;
|
|
else
|
|
tempFont = mFont;
|
|
|
|
if ( color.isValid() )
|
|
tempFormat.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
|
|
QPixmap pixmap( currentIconSize );
|
|
pixmap.fill( Qt::transparent );
|
|
QPainter p;
|
|
p.begin( &pixmap );
|
|
p.setRenderHint( QPainter::Antialiasing );
|
|
QRect rect( 0, 0, currentIconSize.width(), currentIconSize.height() );
|
|
|
|
switch ( mMode )
|
|
{
|
|
case ModeTextRenderer:
|
|
{
|
|
QgsRenderContext context;
|
|
QgsMapToPixel newCoordXForm;
|
|
newCoordXForm.setParameters( 1, 0, 0, 0, 0, 0 );
|
|
context.setMapToPixel( newCoordXForm );
|
|
|
|
context.setScaleFactor( QgsApplication::desktop()->logicalDpiX() / 25.4 );
|
|
context.setUseAdvancedEffects( true );
|
|
context.setPainter( &p );
|
|
|
|
// slightly inset text to account for buffer/background
|
|
double xtrans = 0;
|
|
if ( tempFormat.buffer().enabled() )
|
|
xtrans = context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() );
|
|
if ( tempFormat.background().enabled() && tempFormat.background().sizeType() != QgsTextBackgroundSettings::SizeFixed )
|
|
xtrans = std::max( xtrans, context.convertToPainterUnits( tempFormat.background().size().width(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
|
|
|
|
double ytrans = 0.0;
|
|
if ( tempFormat.buffer().enabled() )
|
|
ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() ) );
|
|
if ( tempFormat.background().enabled() )
|
|
ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat.background().size().height(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
|
|
|
|
QRectF textRect = rect;
|
|
textRect.setLeft( xtrans );
|
|
textRect.setWidth( textRect.width() - xtrans );
|
|
textRect.setTop( ytrans );
|
|
if ( textRect.height() > 300 )
|
|
textRect.setHeight( 300 );
|
|
if ( textRect.width() > 2000 )
|
|
textRect.setWidth( 2000 );
|
|
|
|
QgsTextRenderer::drawText( textRect, 0, QgsTextRenderer::AlignLeft, QStringList() << text(),
|
|
context, tempFormat );
|
|
break;
|
|
}
|
|
case ModeQFont:
|
|
{
|
|
p.setBrush( Qt::NoBrush );
|
|
p.setPen( QColor( 0, 0, 0 ) );
|
|
p.setFont( tempFont );
|
|
QRectF textRect = rect;
|
|
textRect.setLeft( 2 );
|
|
p.drawText( textRect, Qt::AlignVCenter, text() );
|
|
break;
|
|
}
|
|
|
|
}
|
|
p.end();
|
|
setIconSize( currentIconSize );
|
|
setIcon( pixmap );
|
|
}
|
|
|
|
void QgsFontButton::copyColor()
|
|
{
|
|
//copy color
|
|
QApplication::clipboard()->setMimeData( QgsSymbolLayerUtils::colorToMimeData( mFormat.color() ) );
|
|
}
|
|
|
|
void QgsFontButton::pasteColor()
|
|
{
|
|
QColor clipColor;
|
|
bool hasAlpha = false;
|
|
if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
|
|
{
|
|
//paste color
|
|
setColor( clipColor );
|
|
QgsRecentColorScheme::addRecentColor( clipColor );
|
|
}
|
|
}
|
|
|
|
void QgsFontButton::setDialogTitle( const QString &title )
|
|
{
|
|
mDialogTitle = title;
|
|
}
|
|
|
|
QString QgsFontButton::dialogTitle() const
|
|
{
|
|
return mDialogTitle;
|
|
}
|