QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsfontbutton.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfontbutton.h
3  ---------------
4  Date : May 2017
5  Copyright : (C) 2017 by Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsfontbutton.h"
17 #include "qgstextformatwidget.h"
18 #include "qgssymbollayerutils.h"
19 #include "qgscolorscheme.h"
20 #include "qgsmapcanvas.h"
21 #include "qgscolorwidgets.h"
22 #include "qgscolorschemeregistry.h"
23 #include "qgscolorswatchgrid.h"
24 #include "qgsdoublespinbox.h"
25 #include "qgsunittypes.h"
26 #include "qgsmenuheader.h"
27 #include "qgsfontutils.h"
28 #include <QMenu>
29 #include <QClipboard>
30 #include <QDrag>
31 #include <QDesktopWidget>
32 #include <QToolTip>
33 
34 QgsFontButton::QgsFontButton( QWidget *parent, const QString &dialogTitle )
35  : QToolButton( parent )
36  , mDialogTitle( dialogTitle.isEmpty() ? tr( "Text Format" ) : dialogTitle )
37 
38 {
39  setText( tr( "Font" ) );
40 
41  setAcceptDrops( true );
42  connect( this, &QAbstractButton::clicked, this, &QgsFontButton::showSettingsDialog );
43 
44  //setup dropdown menu
45  mMenu = new QMenu( this );
46  connect( mMenu, &QMenu::aboutToShow, this, &QgsFontButton::prepareMenu );
47  setMenu( mMenu );
48  setPopupMode( QToolButton::MenuButtonPopup );
49 
50  //make sure height of button looks good under different platforms
51  QSize size = QToolButton::minimumSizeHint();
52  int fontHeight = Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 1.4;
53  int minWidth = Qgis::UI_SCALE_FACTOR * fontMetrics().width( 'X' ) * 20;
54  mSizeHint = QSize( std::max( minWidth, size.width() ), std::max( size.height(), fontHeight ) );
55 }
56 
58 {
59  return mSizeHint;
60 }
61 
63 {
64  return mSizeHint;
65 }
66 
67 void QgsFontButton::showSettingsDialog()
68 {
69  switch ( mMode )
70  {
71  case ModeTextRenderer:
72  {
74  if ( panel && panel->dockMode() )
75  {
76  QgsTextFormatPanelWidget *formatWidget = new QgsTextFormatPanelWidget( mFormat, mMapCanvas, this );
77  formatWidget->setPanelTitle( mDialogTitle );
78 
79  connect( formatWidget, &QgsTextFormatPanelWidget::widgetChanged, this, [ this, formatWidget ] { this->setTextFormat( formatWidget->format() ); } );
80  panel->openPanel( formatWidget );
81  return;
82  }
83 
84  QgsTextFormatDialog dialog( mFormat, mMapCanvas, this );
85  dialog.setWindowTitle( mDialogTitle );
86  if ( dialog.exec() )
87  {
88  setTextFormat( dialog.format() );
89  QgsFontUtils::addRecentFontFamily( mFormat.font().family() );
90  }
91  break;
92  }
93 
94  case ModeQFont:
95  {
96  bool ok;
97  QFont newFont = QgsGuiUtils::getFont( ok, mFont, mDialogTitle );
98  if ( ok )
99  {
100  QgsFontUtils::addRecentFontFamily( newFont.family() );
101  setCurrentFont( newFont );
102  }
103  break;
104  }
105  }
106 
107  // reactivate button's window
108  activateWindow();
109  raise();
110 }
111 
113 {
114  return mMapCanvas;
115 }
116 
118 {
119  mMapCanvas = mapCanvas;
120 }
121 
123 {
124  mFormat = format;
125  updatePreview();
126  emit changed();
127 }
128 
129 void QgsFontButton::setColor( const QColor &color )
130 {
131  QColor opaque = color;
132  opaque.setAlphaF( 1.0 );
133 
134  if ( mFormat.color() != opaque )
135  {
136  mFormat.setColor( opaque );
137  updatePreview();
138  emit changed();
139  }
140 }
141 
143 {
144  switch ( mMode )
145  {
146  case ModeTextRenderer:
147  QApplication::clipboard()->setMimeData( mFormat.toMimeData() );
148  break;
149 
150  case ModeQFont:
151  QApplication::clipboard()->setMimeData( QgsFontUtils::toMimeData( mFont ) );
152  break;
153  }
154 }
155 
157 {
158  QgsTextFormat tempFormat;
159  QFont font;
160  if ( mMode == ModeTextRenderer && formatFromMimeData( QApplication::clipboard()->mimeData(), tempFormat ) )
161  {
162  setTextFormat( tempFormat );
163  QgsFontUtils::addRecentFontFamily( mFormat.font().family() );
164  }
165  else if ( mMode == ModeQFont && fontFromMimeData( QApplication::clipboard()->mimeData(), font ) )
166  {
167  QgsFontUtils::addRecentFontFamily( font.family() );
168  setCurrentFont( font );
169  }
170 }
171 
172 bool QgsFontButton::event( QEvent *e )
173 {
174  if ( e->type() == QEvent::ToolTip )
175  {
176  QHelpEvent *helpEvent = static_cast< QHelpEvent *>( e );
177  QString toolTip;
178  double fontSize = 0.0;
179  switch ( mMode )
180  {
181  case ModeTextRenderer:
182  fontSize = mFormat.size();
183  break;
184 
185  case ModeQFont:
186  fontSize = mFont.pointSizeF();
187  break;
188  }
189  toolTip = QStringLiteral( "<b>%1</b><br>%2<br>Size: %3" ).arg( text(), mFormat.font().family() ).arg( fontSize );
190  QToolTip::showText( helpEvent->globalPos(), toolTip );
191  }
192  return QToolButton::event( e );
193 }
194 
195 void QgsFontButton::mousePressEvent( QMouseEvent *e )
196 {
197  if ( e->button() == Qt::RightButton )
198  {
199  QToolButton::showMenu();
200  return;
201  }
202  else if ( e->button() == Qt::LeftButton )
203  {
204  mDragStartPosition = e->pos();
205  }
206  QToolButton::mousePressEvent( e );
207 }
208 
209 void QgsFontButton::mouseMoveEvent( QMouseEvent *e )
210 {
211  //handle dragging fonts from button
212 
213  if ( !( e->buttons() & Qt::LeftButton ) )
214  {
215  //left button not depressed, so not a drag
216  QToolButton::mouseMoveEvent( e );
217  return;
218  }
219 
220  if ( ( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
221  {
222  //mouse not moved, so not a drag
223  QToolButton::mouseMoveEvent( e );
224  return;
225  }
226 
227  //user is dragging font
228  QDrag *drag = new QDrag( this );
229  switch ( mMode )
230  {
231  case ModeTextRenderer:
232  drag->setMimeData( mFormat.toMimeData() );
233  break;
234 
235  case ModeQFont:
236  drag->setMimeData( QgsFontUtils::toMimeData( mFont ) );
237  break;
238  }
239  drag->setPixmap( createDragIcon() );
240  drag->exec( Qt::CopyAction );
241  setDown( false );
242 }
243 
244 bool QgsFontButton::colorFromMimeData( const QMimeData *mimeData, QColor &resultColor, bool &hasAlpha )
245 {
246  hasAlpha = false;
247  QColor mimeColor = QgsSymbolLayerUtils::colorFromMimeData( mimeData, hasAlpha );
248 
249  if ( mimeColor.isValid() )
250  {
251  resultColor = mimeColor;
252  return true;
253  }
254 
255  //could not get color from mime data
256  return false;
257 }
258 
259 void QgsFontButton::dragEnterEvent( QDragEnterEvent *e )
260 {
261  //is dragged data valid font data?
262  QColor mimeColor;
263  QgsTextFormat format;
264  QFont font;
265  bool hasAlpha = false;
266 
267  if ( mMode == ModeTextRenderer && formatFromMimeData( e->mimeData(), format ) )
268  {
269  e->acceptProposedAction();
270  updatePreview( QColor(), &format );
271  }
272  else if ( mMode == ModeQFont && fontFromMimeData( e->mimeData(), font ) )
273  {
274  e->acceptProposedAction();
275  updatePreview( QColor(), nullptr, &font );
276  }
277  else if ( mMode == ModeTextRenderer && colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
278  {
279  //if so, we accept the drag, and temporarily change the button's color
280  //to match the dragged color. This gives immediate feedback to the user
281  //that colors can be dropped here
282  e->acceptProposedAction();
283  updatePreview( mimeColor );
284  }
285 }
286 
287 void QgsFontButton::dragLeaveEvent( QDragLeaveEvent *e )
288 {
289  Q_UNUSED( e );
290  //reset button color
291  updatePreview();
292 }
293 
294 void QgsFontButton::dropEvent( QDropEvent *e )
295 {
296  //is dropped data valid format data?
297  QColor mimeColor;
298  QgsTextFormat format;
299  QFont font;
300  bool hasAlpha = false;
301  if ( mMode == ModeTextRenderer && formatFromMimeData( e->mimeData(), format ) )
302  {
303  setTextFormat( format );
304  QgsFontUtils::addRecentFontFamily( mFormat.font().family() );
305  return;
306  }
307  else if ( mMode == ModeQFont && fontFromMimeData( e->mimeData(), font ) )
308  {
309  QgsFontUtils::addRecentFontFamily( font.family() );
310  setCurrentFont( font );
311  return;
312  }
313  else if ( mMode == ModeTextRenderer && colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
314  {
315  //accept drop and set new color
316  e->acceptProposedAction();
317 
318  if ( hasAlpha )
319  {
320  mFormat.setOpacity( mimeColor.alphaF() );
321  }
322  mimeColor.setAlphaF( 1.0 );
323  mFormat.setColor( mimeColor );
325  updatePreview();
326  emit changed();
327  }
328  updatePreview();
329 }
330 
331 void QgsFontButton::wheelEvent( QWheelEvent *event )
332 {
333  double size = 0;
334  switch ( mMode )
335  {
336  case ModeTextRenderer:
337  size = mFormat.size();
338  break;
339 
340  case ModeQFont:
341  size = mFont.pointSizeF();
342  break;
343  }
344 
345  double increment = event->modifiers() & Qt::ControlModifier ? 0.1 : 1;
346  if ( event->delta() > 0 )
347  {
348  size += increment;
349  }
350  else
351  {
352  size -= increment;
353  }
354  size = std::max( size, 1.0 );
355 
356  switch ( mMode )
357  {
358  case ModeTextRenderer:
359  {
360  QgsTextFormat newFormat = mFormat;
361  newFormat.setSize( size );
362  setTextFormat( newFormat );
363  break;
364  }
365 
366  case ModeQFont:
367  {
368  QFont newFont = mFont;
369  newFont.setPointSizeF( size );
370  setCurrentFont( newFont );
371  break;
372  }
373  }
374 
375  event->accept();
376 }
377 
378 QPixmap QgsFontButton::createColorIcon( const QColor &color ) const
379 {
380  //create an icon pixmap
381  QPixmap pixmap( 16, 16 );
382  pixmap.fill( Qt::transparent );
383 
384  QPainter p;
385  p.begin( &pixmap );
386 
387  //draw color over pattern
388  p.setBrush( QBrush( color ) );
389 
390  //draw border
391  p.setPen( QColor( 197, 197, 197 ) );
392  p.drawRect( 0, 0, 15, 15 );
393  p.end();
394  return pixmap;
395 }
396 
397 QPixmap QgsFontButton::createDragIcon( QSize size, const QgsTextFormat *tempFormat, const QFont *tempFont ) const
398 {
399  if ( !tempFormat )
400  tempFormat = &mFormat;
401  if ( !tempFont )
402  tempFont = &mFont;
403 
404  //create an icon pixmap
405  QPixmap pixmap( size.width(), size.height() );
406  pixmap.fill( Qt::transparent );
407  QPainter p;
408  p.begin( &pixmap );
409  p.setRenderHint( QPainter::Antialiasing );
410  QRect rect( 0, 0, size.width(), size.height() );
411 
412  if ( mMode == ModeQFont || tempFormat->color().lightnessF() < 0.7 )
413  {
414  p.setBrush( QBrush( QColor( 255, 255, 255 ) ) );
415  p.setPen( QPen( QColor( 150, 150, 150 ), 0 ) );
416  }
417  else
418  {
419  p.setBrush( QBrush( QColor( 0, 0, 0 ) ) );
420  p.setPen( QPen( QColor( 100, 100, 100 ), 0 ) );
421  }
422  p.drawRect( rect );
423  p.setBrush( Qt::NoBrush );
424  p.setPen( Qt::NoPen );
425 
426  switch ( mMode )
427  {
428  case ModeTextRenderer:
429  {
430  QgsRenderContext context;
431  QgsMapToPixel newCoordXForm;
432  newCoordXForm.setParameters( 1, 0, 0, 0, 0, 0 );
433  context.setMapToPixel( newCoordXForm );
434 
435  context.setScaleFactor( QgsApplication::desktop()->logicalDpiX() / 25.4 );
436  context.setUseAdvancedEffects( true );
437  context.setPainter( &p );
438 
439  // slightly inset text to account for buffer/background
440  double xtrans = 0;
441  if ( tempFormat->buffer().enabled() )
442  xtrans = context.convertToPainterUnits( tempFormat->buffer().size(), tempFormat->buffer().sizeUnit(), tempFormat->buffer().sizeMapUnitScale() );
443  if ( tempFormat->background().enabled() && tempFormat->background().sizeType() != QgsTextBackgroundSettings::SizeFixed )
444  xtrans = std::max( xtrans, context.convertToPainterUnits( tempFormat->background().size().width(), tempFormat->background().sizeUnit(), tempFormat->background().sizeMapUnitScale() ) );
445 
446  double ytrans = 0.0;
447  if ( tempFormat->buffer().enabled() )
448  ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat->buffer().size(), tempFormat->buffer().sizeUnit(), tempFormat->buffer().sizeMapUnitScale() ) );
449  if ( tempFormat->background().enabled() )
450  ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat->background().size().height(), tempFormat->background().sizeUnit(), tempFormat->background().sizeMapUnitScale() ) );
451 
452  QRectF textRect = rect;
453  textRect.setLeft( xtrans );
454  textRect.setWidth( textRect.width() - xtrans );
455  textRect.setTop( ytrans );
456  if ( textRect.height() > 300 )
457  textRect.setHeight( 300 );
458  if ( textRect.width() > 2000 )
459  textRect.setWidth( 2000 );
460 
461  QgsTextRenderer::drawText( textRect, 0, QgsTextRenderer::AlignCenter, QStringList() << tr( "Aa" ),
462  context, *tempFormat );
463  break;
464  }
465  case ModeQFont:
466  {
467  p.setBrush( Qt::NoBrush );
468  p.setPen( QColor( 0, 0, 0 ) );
469  p.setFont( *tempFont );
470  QRectF textRect = rect;
471  textRect.setLeft( 2 );
472  p.drawText( textRect, Qt::AlignVCenter, tr( "Aa" ) );
473  break;
474  }
475  }
476 
477  p.end();
478  return pixmap;
479 }
480 
481 void QgsFontButton::prepareMenu()
482 {
483  //we need to tear down and rebuild this menu every time it is shown. Otherwise the space allocated to any
484  //QgsColorSwatchGridAction is not recalculated by Qt and the swatch grid may not be the correct size
485  //for the number of colors shown in the grid. Note that we MUST refresh color swatch grids every time this
486  //menu is opened, otherwise color schemes like the recent color scheme grid are meaningless
487  mMenu->clear();
488 
489 
490  QWidgetAction *sizeAction = new QWidgetAction( mMenu );
491  QWidget *sizeWidget = new QWidget();
492  QVBoxLayout *sizeLayout = new QVBoxLayout();
493  sizeLayout->setMargin( 0 );
494  sizeLayout->setContentsMargins( 0, 0, 0, 3 );
495  sizeLayout->setSpacing( 2 );
496 
497  QString fontHeaderLabel;
498  switch ( mMode )
499  {
500  case ModeTextRenderer:
501  fontHeaderLabel = tr( "Font size (%1)" ).arg( QgsUnitTypes::toString( mFormat.sizeUnit() ) );
502  break;
503 
504  case ModeQFont:
505  fontHeaderLabel = tr( "Font size (pt)" );
506  break;
507  }
508 
509  QgsMenuHeader *sizeLabel = new QgsMenuHeader( fontHeaderLabel );
510  sizeLayout->addWidget( sizeLabel );
511 
512  QgsDoubleSpinBox *sizeSpin = new QgsDoubleSpinBox( nullptr );
513  sizeSpin->setDecimals( 4 );
514  sizeSpin->setMaximum( 1e+9 );
515  sizeSpin->setShowClearButton( false );
516  sizeSpin->setValue( mMode == ModeTextRenderer ? mFormat.size() : mFont.pointSizeF() );
517  connect( sizeSpin, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ),
518  this, [ = ]( double value )
519  {
520  switch ( mMode )
521  {
522  case ModeTextRenderer:
523  mFormat.setSize( value );
524  break;
525  case ModeQFont:
526  mFont.setPointSizeF( value );
527  break;
528  }
529  updatePreview();
530  emit changed();
531  } );
532  QHBoxLayout *spinLayout = new QHBoxLayout();
533  spinLayout->setMargin( 0 );
534  spinLayout->setContentsMargins( 4, 0, 4, 0 );
535  spinLayout->addWidget( sizeSpin );
536  sizeLayout->addLayout( spinLayout );
537  sizeWidget->setLayout( sizeLayout );
538  sizeAction->setDefaultWidget( sizeWidget );
539  sizeWidget->setFocusProxy( sizeSpin );
540  sizeWidget->setFocusPolicy( Qt::StrongFocus );
541  mMenu->addAction( sizeAction );
542 
543  QMenu *recentFontMenu = new QMenu( tr( "Recent Fonts" ), mMenu );
544  Q_FOREACH ( const QString &family, QgsFontUtils::recentFontFamilies() )
545  {
546  QAction *fontAction = new QAction( family, recentFontMenu );
547  QFont f = fontAction->font();
548  f.setFamily( family );
549  fontAction->setFont( f );
550  fontAction->setToolTip( family );
551  recentFontMenu->addAction( fontAction );
552  if ( ( mMode == ModeTextRenderer && family == mFormat.font().family() )
553  || ( mMode == ModeQFont && family == mFont.family() ) )
554  {
555  fontAction->setCheckable( true );
556  fontAction->setChecked( true );
557  }
558  auto setFont = [this, family]
559  {
560  switch ( mMode )
561  {
562  case ModeTextRenderer:
563  {
564  QgsTextFormat newFormat = mFormat;
565  QFont f = newFormat.font();
566  f.setFamily( family );
567  newFormat.setFont( f );
568  setTextFormat( newFormat );
569  QgsFontUtils::addRecentFontFamily( mFormat.font().family() );
570  break;
571  }
572  case ModeQFont:
573  {
574  QFont font = mFont;
575  font.setFamily( family );
576  setCurrentFont( font );
578  break;
579  }
580  }
581  };
582  connect( fontAction, &QAction::triggered, this, setFont );
583  }
584  mMenu->addMenu( recentFontMenu );
585 
586  QAction *configureAction = new QAction( tr( "Configure Format…" ), this );
587  mMenu->addAction( configureAction );
588  connect( configureAction, &QAction::triggered, this, &QgsFontButton::showSettingsDialog );
589 
590  QAction *copyFormatAction = new QAction( tr( "Copy Format" ), this );
591  mMenu->addAction( copyFormatAction );
592  connect( copyFormatAction, &QAction::triggered, this, &QgsFontButton::copyFormat );
593  QAction *pasteFormatAction = new QAction( tr( "Paste Format" ), this );
594  //enable or disable paste action based on current clipboard contents. We always show the paste
595  //action, even if it's disabled, to give hint to the user that pasting colors is possible
596  QgsTextFormat tempFormat;
597  QFont tempFont;
598  if ( mMode == ModeTextRenderer && formatFromMimeData( QApplication::clipboard()->mimeData(), tempFormat ) )
599  {
601  tempFormat.setSize( 14 );
602  pasteFormatAction->setIcon( createDragIcon( QSize( 16, 16 ), &tempFormat ) );
603  }
604  else if ( mMode == ModeQFont && fontFromMimeData( QApplication::clipboard()->mimeData(), tempFont ) )
605  {
606  tempFont.setPointSize( 8 );
607  pasteFormatAction->setIcon( createDragIcon( QSize( 16, 16 ), nullptr, &tempFont ) );
608  }
609  else
610  {
611  pasteFormatAction->setEnabled( false );
612  }
613  mMenu->addAction( pasteFormatAction );
614  connect( pasteFormatAction, &QAction::triggered, this, &QgsFontButton::pasteFormat );
615 
616  if ( mMode == ModeTextRenderer )
617  {
618  mMenu->addSeparator();
619 
620  QgsColorWheel *colorWheel = new QgsColorWheel( mMenu );
621  colorWheel->setColor( mFormat.color() );
622  QgsColorWidgetAction *colorAction = new QgsColorWidgetAction( colorWheel, mMenu, mMenu );
623  colorAction->setDismissOnColorSelection( false );
624  connect( colorAction, &QgsColorWidgetAction::colorChanged, this, &QgsFontButton::setColor );
625  mMenu->addAction( colorAction );
626 
628  QColor alphaColor = mFormat.color();
629  alphaColor.setAlphaF( mFormat.opacity() );
630  alphaRamp->setColor( alphaColor );
631  QgsColorWidgetAction *alphaAction = new QgsColorWidgetAction( alphaRamp, mMenu, mMenu );
632  alphaAction->setDismissOnColorSelection( false );
633  connect( alphaAction, &QgsColorWidgetAction::colorChanged, this, [ = ]( const QColor & color )
634  {
635  double opacity = color.alphaF();
636  mFormat.setOpacity( opacity );
637  updatePreview();
638  emit changed();
639  } );
640  connect( colorAction, &QgsColorWidgetAction::colorChanged, alphaRamp, [alphaRamp]( const QColor & color ) { alphaRamp->setColor( color, false ); }
641  );
642  mMenu->addAction( alphaAction );
643 
644  //get schemes with ShowInColorButtonMenu flag set
645  QList< QgsColorScheme * > schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorButtonMenu );
646  QList< QgsColorScheme * >::iterator it = schemeList.begin();
647  for ( ; it != schemeList.end(); ++it )
648  {
649  QgsColorSwatchGridAction *colorAction = new QgsColorSwatchGridAction( *it, mMenu, QStringLiteral( "labeling" ), this );
650  colorAction->setBaseColor( mFormat.color() );
651  mMenu->addAction( colorAction );
652  connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsFontButton::setColor );
653  connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsFontButton::addRecentColor );
654  }
655 
656  mMenu->addSeparator();
657 
658  QAction *copyColorAction = new QAction( tr( "Copy Color" ), this );
659  mMenu->addAction( copyColorAction );
660  connect( copyColorAction, &QAction::triggered, this, &QgsFontButton::copyColor );
661 
662  QAction *pasteColorAction = new QAction( tr( "Paste Color" ), this );
663  //enable or disable paste action based on current clipboard contents. We always show the paste
664  //action, even if it's disabled, to give hint to the user that pasting colors is possible
665  QColor clipColor;
666  bool hasAlpha = false;
667  if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
668  {
669  pasteColorAction->setIcon( createColorIcon( clipColor ) );
670  }
671  else
672  {
673  pasteColorAction->setEnabled( false );
674  }
675  mMenu->addAction( pasteColorAction );
676  connect( pasteColorAction, &QAction::triggered, this, &QgsFontButton::pasteColor );
677  }
678 }
679 
680 void QgsFontButton::addRecentColor( const QColor &color )
681 {
683 }
684 
685 QFont QgsFontButton::currentFont() const
686 {
687  return mFont;
688 }
689 
690 void QgsFontButton::setCurrentFont( const QFont &font )
691 {
692  mFont = font;
693  updatePreview();
694  emit changed();
695 }
696 
698 {
699  return mMode;
700 }
701 
703 {
704  mMode = mode;
705  updatePreview();
706 }
707 
708 bool QgsFontButton::formatFromMimeData( const QMimeData *mimeData, QgsTextFormat &resultFormat ) const
709 {
710  bool ok = false;
711  resultFormat = QgsTextFormat::fromMimeData( mimeData, &ok );
712  return ok;
713 }
714 
715 bool QgsFontButton::fontFromMimeData( const QMimeData *mimeData, QFont &resultFont ) const
716 {
717  bool ok = false;
718  resultFont = QgsFontUtils::fromMimeData( mimeData, &ok );
719  return ok;
720 }
721 
722 void QgsFontButton::changeEvent( QEvent *e )
723 {
724  if ( e->type() == QEvent::EnabledChange )
725  {
726  updatePreview();
727  }
728  QToolButton::changeEvent( e );
729 }
730 
731 void QgsFontButton::showEvent( QShowEvent *e )
732 {
733  updatePreview();
734  QToolButton::showEvent( e );
735 }
736 
737 void QgsFontButton::resizeEvent( QResizeEvent *event )
738 {
739  QToolButton::resizeEvent( event );
740  //recalculate icon size and redraw icon
741  mIconSize = QSize();
742  updatePreview();
743 }
744 
745 void QgsFontButton::updatePreview( const QColor &color, QgsTextFormat *format, QFont *font )
746 {
747  QgsTextFormat tempFormat;
748  QFont tempFont;
749 
750  if ( format )
751  tempFormat = *format;
752  else
753  tempFormat = mFormat;
754  if ( font )
755  tempFont = *font;
756  else
757  tempFont = mFont;
758 
759  if ( color.isValid() )
760  tempFormat.setColor( color );
761 
762  QSize currentIconSize;
763  //icon size is button size with a small margin
764  if ( menu() )
765  {
766  if ( !mIconSize.isValid() )
767  {
768  //calculate size of push button part of widget (ie, without the menu dropdown button part)
769  QStyleOptionToolButton opt;
770  initStyleOption( &opt );
771  QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
772  this );
773  //make sure height of icon looks good under different platforms
774 #ifdef Q_OS_WIN
775  mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
776 #else
777  mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
778 #endif
779  }
780  currentIconSize = mIconSize;
781  }
782  else
783  {
784  //no menu
785 #ifdef Q_OS_WIN
786  currentIconSize = QSize( width() - 10, height() - 6 );
787 #else
788  currentIconSize = QSize( width() - 10, height() - 12 );
789 #endif
790  }
791 
792  if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
793  {
794  return;
795  }
796 
797  //create an icon pixmap
798  QPixmap pixmap( currentIconSize );
799  pixmap.fill( Qt::transparent );
800  QPainter p;
801  p.begin( &pixmap );
802  p.setRenderHint( QPainter::Antialiasing );
803  QRect rect( 0, 0, currentIconSize.width(), currentIconSize.height() );
804 
805  switch ( mMode )
806  {
807  case ModeTextRenderer:
808  {
809  QgsRenderContext context;
810  QgsMapToPixel newCoordXForm;
811  newCoordXForm.setParameters( 1, 0, 0, 0, 0, 0 );
812  context.setMapToPixel( newCoordXForm );
813 
814  context.setScaleFactor( QgsApplication::desktop()->logicalDpiX() / 25.4 );
815  context.setUseAdvancedEffects( true );
816  context.setPainter( &p );
817 
818  // slightly inset text to account for buffer/background
819  double xtrans = 0;
820  if ( tempFormat.buffer().enabled() )
821  xtrans = context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() );
822  if ( tempFormat.background().enabled() && tempFormat.background().sizeType() != QgsTextBackgroundSettings::SizeFixed )
823  xtrans = std::max( xtrans, context.convertToPainterUnits( tempFormat.background().size().width(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
824 
825  double ytrans = 0.0;
826  if ( tempFormat.buffer().enabled() )
827  ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() ) );
828  if ( tempFormat.background().enabled() )
829  ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat.background().size().height(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
830 
831  QRectF textRect = rect;
832  textRect.setLeft( xtrans );
833  textRect.setWidth( textRect.width() - xtrans );
834  textRect.setTop( ytrans );
835  if ( textRect.height() > 300 )
836  textRect.setHeight( 300 );
837  if ( textRect.width() > 2000 )
838  textRect.setWidth( 2000 );
839 
840  QgsTextRenderer::drawText( textRect, 0, QgsTextRenderer::AlignLeft, QStringList() << text(),
841  context, tempFormat );
842  break;
843  }
844  case ModeQFont:
845  {
846  p.setBrush( Qt::NoBrush );
847  p.setPen( QColor( 0, 0, 0 ) );
848  p.setFont( tempFont );
849  QRectF textRect = rect;
850  textRect.setLeft( 2 );
851  p.drawText( textRect, Qt::AlignVCenter, text() );
852  break;
853  }
854 
855  }
856  p.end();
857  setIconSize( currentIconSize );
858  setIcon( pixmap );
859 }
860 
862 {
863  //copy color
864  QApplication::clipboard()->setMimeData( QgsSymbolLayerUtils::colorToMimeData( mFormat.color() ) );
865 }
866 
868 {
869  QColor clipColor;
870  bool hasAlpha = false;
871  if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
872  {
873  //paste color
874  setColor( clipColor );
876  }
877 }
878 
879 void QgsFontButton::setDialogTitle( const QString &title )
880 {
881  mDialogTitle = title;
882 }
883 
884 QString QgsFontButton::dialogTitle() const
885 {
886  return mDialogTitle;
887 }
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value...
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
QSize minimumSizeHint() const override
A color swatch grid which can be embedded into a menu.
static QFont fromMimeData(const QMimeData *data, bool *ok=nullptr)
Attempts to parse the provided mime data as a QFont.
void dragEnterEvent(QDragEnterEvent *e) override
void setOpacity(double opacity)
Sets the text&#39;s opacity.
QSizeF size() const
Returns the size of the background shape.
double opacity() const
Returns the text&#39;s opacity.
bool dockMode()
Returns the dock mode state.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
void setCurrentFont(const QFont &font)
Sets the current text font to show in the widget.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:151
QgsFontButton(QWidget *parent=nullptr, const QString &dialogTitle=QString())
Construct a new font button.
virtual void setColor(const QColor &color, bool emitSignals=false)
Sets the color for the widget.
Mode
Available button modes.
Definition: qgsfontbutton.h:54
void copyFormat()
Copies the current text format to the clipboard.
void setShowClearButton(bool showClearButton)
Sets whether the widget will show a clear button.
void copyColor()
Copies the current text color to the clipboard.
void setFont(const QFont &font)
Sets the font used for rendering text.
void resizeEvent(QResizeEvent *event) override
QColor color() const
Returns the color that text will be rendered in.
void colorChanged(const QColor &color)
Emitted when a color has been selected from the widget.
QgsTextFormat format() const
Returns the current formatting settings defined by the widget.
QgsFontButton::Mode mode() const
Returns the current button mode.
Base class for any widget that can be shown as a inline panel.
void mousePressEvent(QMouseEvent *e) override
Show scheme in color button drop-down menu.
void pasteFormat()
Pastes a format from the clipboard.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the buffer size.
static QgsTextFormat fromMimeData(const QMimeData *data, bool *ok=nullptr)
Attempts to parse the provided mime data as a QgsTextFormat.
Custom widget for displaying subheaders within a QMenu in a standard style.
Definition: qgsmenuheader.h:32
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
QList< QgsColorScheme * > schemes() const
Returns all color schemes in the registry.
void mouseMoveEvent(QMouseEvent *e) override
void setUseAdvancedEffects(bool enabled)
Used to enable or disable advanced effects such as blend modes.
static QStringList recentFontFamilies()
Returns a list of recently used font families.
void setSize(double size)
Sets the size for rendered text.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
A color wheel widget.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget...
Alpha component (opacity) of color.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas to associate with the widget.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setTextFormat(const QgsTextFormat &format)
Sets the current text format to show in the widget.
A color ramp widget.
bool event(QEvent *e) override
QSize sizeHint() const override
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
QString dialogTitle() const
Returns the title for the text settings dialog window.
QgsTextBackgroundSettings & background()
Returns a reference to the text background settings.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
void changed()
Emitted when the widget&#39;s text format settings are changed.
void setColor(const QColor &color, bool emitSignals=false) override
Configure font settings for use with QgsTextRenderer.
Definition: qgsfontbutton.h:56
QMimeData * toMimeData() const
Returns new mime data representing the text format settings.
static void addRecentColor(const QColor &color)
Adds a color to the list of recent colors.
void widgetChanged()
Emitted when the widget state changes.
static void drawText(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true)
Draws text within a rectangle using the specified settings.
void setParameters(double mapUnitsPerPixel, double centerX, double centerY, int widthPixels, int heightPixels, double rotation)
Set parameters for use in transforming coordinates.
static void addRecentFontFamily(const QString &family)
Adds a font family to the list of recently used font families.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application&#39;s color scheme registry, used for managing color schemes. ...
QgsTextFormat format() const
Returns the current formatting settings defined by the widget.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the buffer size.
double size() const
Returns the size of the buffer.
An action containing a color widget, which can be embedded into a menu.
static QMimeData * colorToMimeData(const QColor &color)
Creates mime data from a color.
void setMode(Mode mode)
Sets the current button mode.
double size() const
Returns the size for rendered text.
bool enabled() const
Returns whether the background is enabled.
void setMapToPixel(const QgsMapToPixel &mtp)
A panel widget for customizing text formatting settings.
SizeType sizeType() const
Returns the method used to determine the size of the background shape (e.g., fixed size or buffer aro...
bool enabled() const
Returns whether the buffer is enabled.
Configure font settings for use with QFont objects.
Definition: qgsfontbutton.h:57
QFont currentFont() const
Returns the current QFont set by the widget.
void dragLeaveEvent(QDragLeaveEvent *e) override
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the shape size.
static QMimeData * toMimeData(const QFont &font)
Returns new mime data representing the specified font settings.
void wheelEvent(QWheelEvent *event) override
Container for all settings relating to text rendering.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the size of rendered text.
void setDialogTitle(const QString &title)
Sets the title for the text settings dialog window.
A simple dialog for customizing text formatting settings.
void setDismissOnColorSelection(bool dismiss)
Sets whether the parent menu should be dismissed and closed when a color is selected from the action&#39;...
void dropEvent(QDropEvent *e) override
void showEvent(QShowEvent *e) override
void changeEvent(QEvent *e) override
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
QFont font() const
Returns the font used for rendering text.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units used for the shape&#39;s size.
QFont getFont(bool &ok, const QFont &initial, const QString &title)
Show font selection dialog.
void setColor(const QColor &color)
Sets the current color for the text.
static QColor colorFromMimeData(const QMimeData *data, bool &hasAlpha)
Attempts to parse mime data as a color.
void colorChanged(const QColor &color)
Emitted when a color has been selected from the widget.
void setBaseColor(const QColor &baseColor)
Sets the base color for the color grid.
void pasteColor()
Pastes a color from the clipboard to the text format.