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