QGIS API Documentation 3.39.0-Master (d85f3c2a281)
Loading...
Searching...
No Matches
qgsannotationitemwidget_impl.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsannotationitemwidget_impl.cpp
3 ------------------------
4 Date : September 2021
5 Copyright : (C) 2021 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 ***************************************************************************/
16
18#include "qgsstyle.h"
19#include "qgsfillsymbol.h"
20#include "qgslinesymbol.h"
21#include "qgsmarkersymbol.h"
30#include "qgstextformatwidget.h"
31#include "qgsapplication.h"
33#include "qgsexpressionfinder.h"
34#include "qgsimagecache.h"
35#include "qgssvgcache.h"
37#include "qgsmapcanvas.h"
38
40
41QgsAnnotationPolygonItemWidget::QgsAnnotationPolygonItemWidget( QWidget *parent )
43{
44 setupUi( this );
45
46 mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
47 mSelector->setDockMode( dockMode() );
48 connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [ = ]
49 {
50 if ( !mBlockChangedSignal )
51 {
52 emit itemChanged();
53 QgsApplication::recentStyleHandler()->pushRecentSymbol( QStringLiteral( "polygon_annotation_item" ), qgis::down_cast< QgsFillSymbol * >( mSelector->symbol()->clone() ) );
54 }
55 } );
56 connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
57
58 QVBoxLayout *layout = new QVBoxLayout();
59 layout->setContentsMargins( 0, 0, 0, 0 );
60 layout->addWidget( mSelector );
61 mSymbolSelectorFrame->setLayout( layout );
62
63 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
64 {
65 if ( !mBlockChangedSignal )
66 emit itemChanged();
67 } );
68}
69
70QgsAnnotationItem *QgsAnnotationPolygonItemWidget::createItem()
71{
72 QgsAnnotationPolygonItem *newItem = mItem->clone();
73 newItem->setSymbol( mSymbol->clone() );
74 mPropertiesWidget->updateItem( newItem );
75 return newItem;
76}
77
78void QgsAnnotationPolygonItemWidget::updateItem( QgsAnnotationItem *item )
79{
80 if ( QgsAnnotationPolygonItem *polygonItem = dynamic_cast< QgsAnnotationPolygonItem * >( item ) )
81 {
82 polygonItem->setSymbol( mSymbol->clone() );
83 mPropertiesWidget->updateItem( polygonItem );
84 }
85}
86
87void QgsAnnotationPolygonItemWidget::setDockMode( bool dockMode )
88{
90 if ( mSelector )
91 mSelector->setDockMode( dockMode );
92}
93
94void QgsAnnotationPolygonItemWidget::setContext( const QgsSymbolWidgetContext &context )
95{
97 if ( mSelector )
98 mSelector->setContext( context );
99 mPropertiesWidget->setContext( context );
100}
101
102QgsAnnotationPolygonItemWidget::~QgsAnnotationPolygonItemWidget() = default;
103
104bool QgsAnnotationPolygonItemWidget::setNewItem( QgsAnnotationItem *item )
105{
106 QgsAnnotationPolygonItem *polygonItem = dynamic_cast< QgsAnnotationPolygonItem * >( item );
107 if ( !polygonItem )
108 return false;
109
110 mItem.reset( polygonItem->clone() );
111 if ( mItem->symbol() )
112 {
113 mSymbol.reset( mItem->symbol()->clone() );
114 }
115 else
116 {
117 mSymbol.reset( QgsFillSymbol::createSimple( {} ) );
118 }
119 mBlockChangedSignal = true;
120 mSelector->loadSymbol( mSymbol.get() );
121 mSelector->updatePreview();
122 mPropertiesWidget->setItem( mItem.get() );
123 mBlockChangedSignal = false;
124
125 return true;
126}
127
128
129//
130// QgsAnnotationLineItemWidget
131//
132
133QgsAnnotationLineItemWidget::QgsAnnotationLineItemWidget( QWidget *parent )
135{
136 setupUi( this );
137
138 mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
139 mSelector->setDockMode( dockMode() );
140 connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [ = ]
141 {
142 if ( !mBlockChangedSignal )
143 {
144 emit itemChanged();
145 QgsApplication::recentStyleHandler()->pushRecentSymbol( QStringLiteral( "line_annotation_item" ), qgis::down_cast< QgsLineSymbol * >( mSelector->symbol()->clone() ) );
146 }
147 } );
148 connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
149
150 QVBoxLayout *layout = new QVBoxLayout();
151 layout->setContentsMargins( 0, 0, 0, 0 );
152 layout->addWidget( mSelector );
153 mSymbolSelectorFrame->setLayout( layout );
154
155 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
156 {
157 if ( !mBlockChangedSignal )
158 emit itemChanged();
159 } );
160}
161
162QgsAnnotationItem *QgsAnnotationLineItemWidget::createItem()
163{
164 QgsAnnotationLineItem *newItem = mItem->clone();
165 newItem->setSymbol( mSymbol->clone() );
166 mPropertiesWidget->updateItem( newItem );
167 return newItem;
168}
169
170void QgsAnnotationLineItemWidget::updateItem( QgsAnnotationItem *item )
171{
172 if ( QgsAnnotationLineItem *lineItem = dynamic_cast< QgsAnnotationLineItem * >( item ) )
173 {
174 lineItem->setSymbol( mSymbol->clone() );
175 mPropertiesWidget->updateItem( lineItem );
176 }
177}
178
179void QgsAnnotationLineItemWidget::setDockMode( bool dockMode )
180{
182 if ( mSelector )
183 mSelector->setDockMode( dockMode );
184}
185
186void QgsAnnotationLineItemWidget::setContext( const QgsSymbolWidgetContext &context )
187{
189 if ( mSelector )
190 mSelector->setContext( context );
191 mPropertiesWidget->setContext( context );
192}
193
194QgsAnnotationLineItemWidget::~QgsAnnotationLineItemWidget() = default;
195
196bool QgsAnnotationLineItemWidget::setNewItem( QgsAnnotationItem *item )
197{
198 QgsAnnotationLineItem *lineItem = dynamic_cast< QgsAnnotationLineItem * >( item );
199 if ( !lineItem )
200 return false;
201
202 mItem.reset( lineItem->clone() );
203 if ( mItem->symbol() )
204 {
205 mSymbol.reset( mItem->symbol()->clone() );
206 }
207 else
208 {
209 mSymbol.reset( QgsLineSymbol::createSimple( {} ) );
210 }
211 mBlockChangedSignal = true;
212 mSelector->loadSymbol( mSymbol.get() );
213 mSelector->updatePreview();
214 mPropertiesWidget->setItem( mItem.get() );
215 mBlockChangedSignal = false;
216
217 return true;
218}
219
220
221//
222// QgsAnnotationMarkerItemWidget
223//
224
225QgsAnnotationMarkerItemWidget::QgsAnnotationMarkerItemWidget( QWidget *parent )
227{
228 setupUi( this );
229
230 mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
231 mSelector->setDockMode( dockMode() );
232 connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [ = ]
233 {
234 if ( !mBlockChangedSignal )
235 {
236 emit itemChanged();
237 QgsApplication::recentStyleHandler()->pushRecentSymbol( QStringLiteral( "marker_annotation_item" ), qgis::down_cast< QgsMarkerSymbol * >( mSelector->symbol()->clone() ) );
238 }
239 } );
240 connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
241
242 QVBoxLayout *layout = new QVBoxLayout();
243 layout->setContentsMargins( 0, 0, 0, 0 );
244 layout->addWidget( mSelector );
245 mSymbolSelectorFrame->setLayout( layout );
246
247 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
248 {
249 if ( !mBlockChangedSignal )
250 emit itemChanged();
251 } );
252}
253
254QgsAnnotationItem *QgsAnnotationMarkerItemWidget::createItem()
255{
256 QgsAnnotationMarkerItem *newItem = mItem->clone();
257 newItem->setSymbol( mSymbol->clone() );
258 mPropertiesWidget->updateItem( newItem );
259 return newItem;
260}
261
262void QgsAnnotationMarkerItemWidget::updateItem( QgsAnnotationItem *item )
263{
264 if ( QgsAnnotationMarkerItem *markerItem = dynamic_cast< QgsAnnotationMarkerItem * >( item ) )
265 {
266 markerItem->setSymbol( mSymbol->clone() );
267 mPropertiesWidget->updateItem( markerItem );
268 }
269}
270
271void QgsAnnotationMarkerItemWidget::setDockMode( bool dockMode )
272{
274 if ( mSelector )
275 mSelector->setDockMode( dockMode );
276}
277
278void QgsAnnotationMarkerItemWidget::setContext( const QgsSymbolWidgetContext &context )
279{
281 if ( mSelector )
282 mSelector->setContext( context );
283 mPropertiesWidget->setContext( context );
284}
285
286QgsAnnotationMarkerItemWidget::~QgsAnnotationMarkerItemWidget() = default;
287
288bool QgsAnnotationMarkerItemWidget::setNewItem( QgsAnnotationItem *item )
289{
290 QgsAnnotationMarkerItem *markerItem = dynamic_cast< QgsAnnotationMarkerItem * >( item );
291 if ( !markerItem )
292 return false;
293
294 mItem.reset( markerItem->clone() );
295 if ( mItem->symbol() )
296 {
297 mSymbol.reset( mItem->symbol()->clone() );
298 }
299 else
300 {
301 mSymbol.reset( QgsMarkerSymbol::createSimple( {} ) );
302 }
303 mBlockChangedSignal = true;
304 mSelector->loadSymbol( mSymbol.get() );
305 mSelector->updatePreview();
306 mPropertiesWidget->setItem( mItem.get() );
307 mBlockChangedSignal = false;
308
309 return true;
310}
311
312
313
314//
315// QgsAnnotationPointTextItemWidget
316//
317
318QgsAnnotationPointTextItemWidget::QgsAnnotationPointTextItemWidget( QWidget *parent )
320{
321 setupUi( this );
322
323 mTextFormatWidget = new QgsTextFormatWidget();
324 QVBoxLayout *vLayout = new QVBoxLayout();
325 vLayout->setContentsMargins( 0, 0, 0, 0 );
326 vLayout->addWidget( mTextFormatWidget );
327 mTextFormatWidgetContainer->setLayout( vLayout );
328
329 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
330 mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 );
331
332 mSpinTextAngle->setClearValue( 0 );
333
334 mRotationModeCombo->addItem( tr( "Ignore Map Rotation" ), QVariant::fromValue( Qgis::SymbolRotationMode::IgnoreMapRotation ) );
335 mRotationModeCombo->addItem( tr( "Rotate With Map" ), QVariant::fromValue( Qgis::SymbolRotationMode::RespectMapRotation ) );
336
337 mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
338
339 mTextFormatWidget->setDockMode( dockMode() );
340 connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [ = ]
341 {
342 mTextEdit->setMode(
343 mTextFormatWidget->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText
344 );
345
346 if ( !mBlockChangedSignal )
347 emit itemChanged();
348 } );
349 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, [ = ]
350 {
351 if ( !mBlockChangedSignal )
352 emit itemChanged();
353 } );
354 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked );
355 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
356 {
357 if ( !mBlockChangedSignal )
358 emit itemChanged();
359 } );
360
361 connect( mSpinTextAngle, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, [ = ]
362 {
363 if ( !mBlockChangedSignal )
364 emit itemChanged();
365 } );
366
367 connect( mRotationModeCombo, qOverload< int >( &QComboBox::currentIndexChanged ), this, [ = ]
368 {
369 if ( !mBlockChangedSignal )
370 emit itemChanged();
371 } );
372
373 connect( mAlignmentComboBox, &QgsAlignmentComboBox::changed, this, [ = ]
374 {
375 if ( !mBlockChangedSignal )
376 emit itemChanged();
377 } );
378}
379
380QgsAnnotationItem *QgsAnnotationPointTextItemWidget::createItem()
381{
382 QgsAnnotationPointTextItem *newItem = mItem->clone();
383 updateItem( newItem );
384 return newItem;
385}
386
387void QgsAnnotationPointTextItemWidget::updateItem( QgsAnnotationItem *item )
388{
389 if ( QgsAnnotationPointTextItem *pointTextItem = dynamic_cast< QgsAnnotationPointTextItem * >( item ) )
390 {
391 mBlockChangedSignal = true;
392 pointTextItem->setFormat( mTextFormatWidget->format() );
393 pointTextItem->setText( mTextFormatWidget->format().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
394 pointTextItem->setAngle( mSpinTextAngle->value() );
395 pointTextItem->setRotationMode( mRotationModeCombo->currentData().value< Qgis::SymbolRotationMode >() );
396 pointTextItem->setAlignment( mAlignmentComboBox->currentAlignment() );
397 mBlockChangedSignal = false;
398 mPropertiesWidget->updateItem( pointTextItem );
399 }
400}
401
402void QgsAnnotationPointTextItemWidget::setDockMode( bool dockMode )
403{
405 if ( mTextFormatWidget )
406 mTextFormatWidget->setDockMode( dockMode );
407}
408
409void QgsAnnotationPointTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
410{
412 if ( mTextFormatWidget )
413 mTextFormatWidget->setContext( context );
414 mPropertiesWidget->setContext( context );
415}
416
417void QgsAnnotationPointTextItemWidget::focusDefaultWidget()
418{
419 mTextEdit->textEdit()->selectAll();
420 mTextEdit->setFocus();
421}
422
423QgsAnnotationPointTextItemWidget::~QgsAnnotationPointTextItemWidget() = default;
424
425bool QgsAnnotationPointTextItemWidget::setNewItem( QgsAnnotationItem *item )
426{
427 QgsAnnotationPointTextItem *textItem = dynamic_cast< QgsAnnotationPointTextItem * >( item );
428 if ( !textItem )
429 return false;
430
431 mItem.reset( textItem->clone() );
432
433 mBlockChangedSignal = true;
434 mTextFormatWidget->setFormat( mItem->format() );
435 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
436 mTextEdit->setText( mItem->text() );
437 mSpinTextAngle->setValue( mItem->angle() );
438 mRotationModeCombo->setCurrentIndex( mRotationModeCombo->findData( QVariant::fromValue( mItem->rotationMode() ) ) );
439 mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask );
440 mPropertiesWidget->setItem( mItem.get() );
441 mBlockChangedSignal = false;
442
443 return true;
444}
445
446void QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked()
447{
448 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
449
450 QgsExpressionContext expressionContext;
451 if ( context().expressionContext() )
452 expressionContext = *( context().expressionContext() );
453 else
454 expressionContext = QgsProject::instance()->createExpressionContext();
455
456 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, QStringLiteral( "generic" ), expressionContext );
457
458 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
459 if ( exprDlg.exec() == QDialog::Accepted )
460 {
461 expression = exprDlg.expressionText().trimmed();
462 if ( !expression.isEmpty() )
463 {
464 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
465 }
466 }
467}
468
469
470//
471// QgsAnnotationLineTextItemWidget
472//
473
474QgsAnnotationLineTextItemWidget::QgsAnnotationLineTextItemWidget( QWidget *parent )
476{
477 setupUi( this );
478
479 mTextFormatWidget = new QgsTextFormatWidget();
480 QVBoxLayout *vLayout = new QVBoxLayout();
481 vLayout->setContentsMargins( 0, 0, 0, 0 );
482 vLayout->addWidget( mTextFormatWidget );
483 mTextFormatWidgetContainer->setLayout( vLayout );
484
485 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
486 mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 );
487
488 mTextFormatWidget->setDockMode( dockMode() );
489 connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [ = ]
490 {
491 mTextEdit->setMode(
492 mTextFormatWidget->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText
493 );
494
495 if ( !mBlockChangedSignal )
496 emit itemChanged();
497 } );
498 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, [ = ]
499 {
500 if ( !mBlockChangedSignal )
501 emit itemChanged();
502 } );
503 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked );
504 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
505 {
506 if ( !mBlockChangedSignal )
507 emit itemChanged();
508 } );
509
512 mSpinOffset->setClearValue( 0.0 );
513 connect( mSpinOffset, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, [ = ]
514 {
515 if ( !mBlockChangedSignal )
516 emit itemChanged();
517 } );
518
519 connect( mOffsetUnitWidget, &QgsUnitSelectionWidget::changed, this, [ = ]
520 {
521 if ( !mBlockChangedSignal )
522 emit itemChanged();
523 } );
524}
525
526QgsAnnotationLineTextItemWidget::~QgsAnnotationLineTextItemWidget() = default;
527
528QgsAnnotationItem *QgsAnnotationLineTextItemWidget::createItem()
529{
530 QgsAnnotationLineTextItem *newItem = mItem->clone();
531 updateItem( newItem );
532 return newItem;
533}
534
535void QgsAnnotationLineTextItemWidget::updateItem( QgsAnnotationItem *item )
536{
537 if ( QgsAnnotationLineTextItem *lineTextItem = dynamic_cast< QgsAnnotationLineTextItem * >( item ) )
538 {
539 mBlockChangedSignal = true;
540 lineTextItem->setFormat( mTextFormatWidget->format() );
541 lineTextItem->setText( mTextFormatWidget->format().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
542
543 lineTextItem->setOffsetFromLine( mSpinOffset->value() );
544 lineTextItem->setOffsetFromLineUnit( mOffsetUnitWidget->unit() );
545 lineTextItem->setOffsetFromLineMapUnitScale( mOffsetUnitWidget->getMapUnitScale() );
546
547 mBlockChangedSignal = false;
548 mPropertiesWidget->updateItem( lineTextItem );
549 }
550}
551
552void QgsAnnotationLineTextItemWidget::setDockMode( bool dockMode )
553{
555 if ( mTextFormatWidget )
556 mTextFormatWidget->setDockMode( dockMode );
557}
558
559void QgsAnnotationLineTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
560{
562 if ( mTextFormatWidget )
563 mTextFormatWidget->setContext( context );
564 mPropertiesWidget->setContext( context );
565}
566
567void QgsAnnotationLineTextItemWidget::focusDefaultWidget()
568{
569 mTextEdit->textEdit()->selectAll();
570 mTextEdit->setFocus();
571}
572
573bool QgsAnnotationLineTextItemWidget::setNewItem( QgsAnnotationItem *item )
574{
575 QgsAnnotationLineTextItem *textItem = dynamic_cast< QgsAnnotationLineTextItem * >( item );
576 if ( !textItem )
577 return false;
578
579 mItem.reset( textItem->clone() );
580
581 mBlockChangedSignal = true;
582 mTextFormatWidget->setFormat( mItem->format() );
583 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
584 mTextEdit->setText( mItem->text() );
585 mPropertiesWidget->setItem( mItem.get() );
586
587 mSpinOffset->setValue( mItem->offsetFromLine() );
588 mOffsetUnitWidget->setUnit( mItem->offsetFromLineUnit() );
589 mOffsetUnitWidget->setMapUnitScale( mItem->offsetFromLineMapUnitScale() );
590
591 mBlockChangedSignal = false;
592
593 return true;
594}
595
596void QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked()
597{
598 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
599
600 QgsExpressionContext expressionContext;
601 if ( context().expressionContext() )
602 expressionContext = *( context().expressionContext() );
603 else
604 expressionContext = QgsProject::instance()->createExpressionContext();
605
606 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, QStringLiteral( "generic" ), expressionContext );
607
608 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
609 if ( exprDlg.exec() == QDialog::Accepted )
610 {
611 expression = exprDlg.expressionText().trimmed();
612 if ( !expression.isEmpty() )
613 {
614 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
615 }
616 }
617}
618
619
620
621//
622// QgsAnnotationRectangleTextItemWidget
623//
624
625QgsAnnotationRectangleTextItemWidget::QgsAnnotationRectangleTextItemWidget( QWidget *parent )
627{
628 setupUi( this );
629
630 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
631 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
632 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
633
636
637
638 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
639 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
640 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
641 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
642 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
643 mFrameSymbolButton->registerExpressionContextGenerator( this );
644
645 mSpinBottomMargin->setClearValue( 0 );
646 mSpinTopMargin->setClearValue( 0 );
647 mSpinRightMargin->setClearValue( 0 );
648 mSpinLeftMargin->setClearValue( 0 );
651
652 mTextFormatWidget = new QgsTextFormatWidget();
653 QVBoxLayout *vLayout = new QVBoxLayout();
654 vLayout->setContentsMargins( 0, 0, 0, 0 );
655 vLayout->addWidget( mTextFormatWidget );
656 mTextFormatWidgetContainer->setLayout( vLayout );
657
658 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
659 mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 );
660
661 mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight | Qt::AlignJustify );
662 mVerticalAlignmentComboBox->setAvailableAlignments( Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom );
663
664 mTextFormatWidget->setDockMode( dockMode() );
665 connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [this]
666 {
667 mTextEdit->setMode(
668 mTextFormatWidget->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText
669 );
670
671 onWidgetChanged();
672 } );
673 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
674 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked );
675 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
676 connect( mAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
677 connect( mVerticalAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
678 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
679 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
680 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
681 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
682 connect( mSpinTopMargin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
683 connect( mSpinRightMargin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
684 connect( mSpinLeftMargin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
685 connect( mSpinBottomMargin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
686 connect( mMarginUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
687
688 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
689
690 connect( mWidthSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setWidth );
691 connect( mHeightSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setHeight );
692
693 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationRectangleTextItemWidget::sizeModeChanged );
694 mWidgetFixedSize->hide();
695 sizeModeChanged();
696}
697
698QgsAnnotationItem *QgsAnnotationRectangleTextItemWidget::createItem()
699{
700 QgsAnnotationRectangleTextItem *newItem = mItem->clone();
701 updateItem( newItem );
702 return newItem;
703}
704
705void QgsAnnotationRectangleTextItemWidget::updateItem( QgsAnnotationItem *item )
706{
707 if ( QgsAnnotationRectangleTextItem *rectTextItem = dynamic_cast< QgsAnnotationRectangleTextItem * >( item ) )
708 {
709 mBlockChangedSignal = true;
710 rectTextItem->setFormat( mTextFormatWidget->format() );
711 rectTextItem->setText( mTextFormatWidget->format().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
712 rectTextItem->setAlignment( mAlignmentComboBox->currentAlignment() | mVerticalAlignmentComboBox->currentAlignment() );
713
714 rectTextItem->setPlacementMode( mSizeModeCombo->currentData().value< Qgis::AnnotationPlacementMode >() );
715
716 rectTextItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
717 rectTextItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
718
719 rectTextItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
720 rectTextItem->setFrameEnabled( mFrameCheckbox->isChecked() );
721 rectTextItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol< QgsFillSymbol >() );
722 rectTextItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol< QgsFillSymbol >() );
723
724 rectTextItem->setMargins( QgsMargins( mSpinLeftMargin->value(),
725 mSpinTopMargin->value(),
726 mSpinRightMargin->value(),
727 mSpinBottomMargin->value() ) );
728 rectTextItem->setMarginsUnit( mMarginUnitWidget->unit() );
729
730 if ( mUpdateItemPosition )
731 {
732 rectTextItem->setBounds( mItem->bounds() );
733 mUpdateItemPosition = false;
734 }
735
736 mBlockChangedSignal = false;
737
738 mPropertiesWidget->updateItem( rectTextItem );
739 }
740}
741
742void QgsAnnotationRectangleTextItemWidget::setDockMode( bool dockMode )
743{
745 if ( mTextFormatWidget )
746 mTextFormatWidget->setDockMode( dockMode );
747}
748
749void QgsAnnotationRectangleTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
750{
752 if ( mTextFormatWidget )
753 mTextFormatWidget->setContext( context );
754 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
755 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
756 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
757 mFrameSymbolButton->setMessageBar( context.messageBar() );
758 mPropertiesWidget->setContext( context );
759}
760
761QgsExpressionContext QgsAnnotationRectangleTextItemWidget::createExpressionContext() const
762{
763 QgsExpressionContext expressionContext;
764 if ( context().expressionContext() )
765 expressionContext = *( context().expressionContext() );
766 else
767 expressionContext = QgsProject::instance()->createExpressionContext();
768 return expressionContext;
769}
770
771void QgsAnnotationRectangleTextItemWidget::focusDefaultWidget()
772{
773 mTextEdit->textEdit()->selectAll();
774 mTextEdit->setFocus();
775}
776
777QgsAnnotationRectangleTextItemWidget::~QgsAnnotationRectangleTextItemWidget() = default;
778
779bool QgsAnnotationRectangleTextItemWidget::setNewItem( QgsAnnotationItem *item )
780{
781 QgsAnnotationRectangleTextItem *textItem = dynamic_cast< QgsAnnotationRectangleTextItem * >( item );
782 if ( !textItem )
783 return false;
784
785 mItem.reset( textItem->clone() );
786
787 mBlockChangedSignal = true;
788 mTextFormatWidget->setFormat( mItem->format() );
789 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
790 mTextEdit->setText( mItem->text() );
791 mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask );
792 mVerticalAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignVertical_Mask );
793 mPropertiesWidget->setItem( mItem.get() );
794
795 mBackgroundCheckbox->setChecked( textItem->backgroundEnabled() );
796 if ( const QgsSymbol *symbol = textItem->backgroundSymbol() )
797 mBackgroundSymbolButton->setSymbol( symbol->clone() );
798
799 mFrameCheckbox->setChecked( textItem->frameEnabled() );
800 if ( const QgsSymbol *symbol = textItem->frameSymbol() )
801 mFrameSymbolButton->setSymbol( symbol->clone() );
802
803 mMarginUnitWidget->setUnit( textItem->marginsUnit() );
804 mSpinLeftMargin->setValue( textItem->margins().left() );
805 mSpinTopMargin->setValue( textItem->margins().top() );
806 mSpinRightMargin->setValue( textItem->margins().right() );
807 mSpinBottomMargin->setValue( textItem->margins().bottom() );
808
809 mWidthSpinBox->setValue( textItem->fixedSize().width() );
810 mHeightSpinBox->setValue( textItem->fixedSize().height() );
811 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( textItem->placementMode() ) ) );
812
813 mBlockChangedSignal = false;
814
815 return true;
816}
817
818void QgsAnnotationRectangleTextItemWidget::onWidgetChanged()
819{
820 if ( !mBlockChangedSignal )
821 emit itemChanged();
822}
823
824void QgsAnnotationRectangleTextItemWidget::sizeModeChanged()
825{
826 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value< Qgis::AnnotationPlacementMode >();
827 switch ( mode )
828 {
830 mWidgetFixedSize->hide();
831 break;
832
834 mWidgetFixedSize->show();
835 break;
836
838 {
839 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
840 {
841 // convert item bounds to relative position
842 const QgsRectangle itemBounds = details->boundingBox();
843 if ( QgsMapCanvas *canvas = context().mapCanvas() )
844 {
845 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
846 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
847 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
848 mUpdateItemPosition = true;
849 }
850 }
851
852 mWidgetFixedSize->hide();
853 break;
854 }
855 }
856
857 onWidgetChanged();
858}
859
860void QgsAnnotationRectangleTextItemWidget::setWidth()
861{
862 onWidgetChanged();
863}
864
865void QgsAnnotationRectangleTextItemWidget::setHeight()
866{
867 onWidgetChanged();
868}
869
870void QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked()
871{
872 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
873
874 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, QStringLiteral( "generic" ), createExpressionContext() );
875
876 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
877 if ( exprDlg.exec() == QDialog::Accepted )
878 {
879 expression = exprDlg.expressionText().trimmed();
880 if ( !expression.isEmpty() )
881 {
882 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
883 }
884 }
885}
886
887
888//
889// QgsAnnotationPictureItemWidget
890//
891
892QgsAnnotationPictureItemWidget::QgsAnnotationPictureItemWidget( QWidget *parent )
894{
895 setupUi( this );
896
897 mSizeStackedWidget->setSizeMode( QgsStackedWidget::SizeMode::CurrentPageOnly );
898
899 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
900 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
901 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
902
905
906 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
907 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
908 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
909 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
910 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
911 mFrameSymbolButton->registerExpressionContextGenerator( this );
912
913 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
914 {
915 if ( !mBlockChangedSignal )
916 emit itemChanged();
917 } );
918
919 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationPictureItemWidget::sizeModeChanged );
920
921 connect( mRadioSVG, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
922 connect( mRadioRaster, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
923 connect( mSourceLineEdit, &QgsPictureSourceLineEditBase::sourceChanged, this, [ = ]( const QString & source )
924 {
925 if ( !mRadioSVG->isChecked() && QFileInfo( source ).suffix().compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
926 {
927 mRadioSVG->setChecked( true );
928 }
929
930 onWidgetChanged();
931 } );
932
933 connect( mLockAspectRatioCheck, &QCheckBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
934 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
935 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
936 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
937 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
938 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
939
940 connect( mWidthSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setWidth );
941 connect( mHeightSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setHeight );
942 connect( mLockAspectRatio, &QgsRatioLockButton::lockChanged, this, &QgsAnnotationPictureItemWidget::setLockAspectRatio );
943}
944
945QgsAnnotationPictureItemWidget::~QgsAnnotationPictureItemWidget() = default;
946
947QgsAnnotationItem *QgsAnnotationPictureItemWidget::createItem()
948{
949 QgsAnnotationPictureItem *newItem = mItem->clone();
950 updateItem( newItem );
951 return newItem;
952}
953
954void QgsAnnotationPictureItemWidget::updateItem( QgsAnnotationItem *item )
955{
956 if ( QgsAnnotationPictureItem *pictureItem = dynamic_cast< QgsAnnotationPictureItem * >( item ) )
957 {
958 const bool svg = mRadioSVG->isChecked();
960 const QString path = mSourceLineEdit->source();
961 pictureItem->setPath( newFormat, path );
962
963 pictureItem->setPlacementMode( mSizeModeCombo->currentData().value< Qgis::AnnotationPlacementMode >() );
964 switch ( pictureItem->placementMode() )
965 {
967 pictureItem->setLockAspectRatio( mLockAspectRatioCheck->isChecked() );
968 break;
971 pictureItem->setLockAspectRatio( mLockAspectRatio->isChecked() );
972 break;
973 }
974
975 pictureItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
976 pictureItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
977
978 pictureItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
979 pictureItem->setFrameEnabled( mFrameCheckbox->isChecked() );
980 pictureItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol< QgsFillSymbol >() );
981 pictureItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol< QgsFillSymbol >() );
982
983 if ( mUpdateItemPosition )
984 {
985 pictureItem->setBounds( mItem->bounds() );
986 mUpdateItemPosition = false;
987 }
988
989 mPropertiesWidget->updateItem( pictureItem );
990 }
991}
992
993void QgsAnnotationPictureItemWidget::setDockMode( bool dockMode )
994{
996}
997
998void QgsAnnotationPictureItemWidget::setContext( const QgsSymbolWidgetContext &context )
999{
1001 mPropertiesWidget->setContext( context );
1002 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
1003 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
1004 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
1005 mFrameSymbolButton->setMessageBar( context.messageBar() );
1006}
1007
1008QgsExpressionContext QgsAnnotationPictureItemWidget::createExpressionContext() const
1009{
1010 QgsExpressionContext expressionContext;
1011 if ( context().expressionContext() )
1012 expressionContext = *( context().expressionContext() );
1013 else
1014 expressionContext = QgsProject::instance()->createExpressionContext();
1015 return expressionContext;
1016}
1017
1018void QgsAnnotationPictureItemWidget::focusDefaultWidget()
1019{
1020 mSourceLineEdit->setFocus();
1021}
1022
1023bool QgsAnnotationPictureItemWidget::setNewItem( QgsAnnotationItem *item )
1024{
1025 QgsAnnotationPictureItem *pictureItem = dynamic_cast< QgsAnnotationPictureItem * >( item );
1026 if ( !pictureItem )
1027 return false;
1028
1029 mItem.reset( pictureItem->clone() );
1030
1031 mBlockChangedSignal = true;
1032 mPropertiesWidget->setItem( mItem.get() );
1033
1034 mLockAspectRatioCheck->setChecked( mItem->lockAspectRatio() );
1035 mLockAspectRatio->setLocked( mItem->lockAspectRatio() );
1036 switch ( pictureItem->format() )
1037 {
1039 mRadioSVG->setChecked( true );
1040 break;
1042 mRadioRaster->setChecked( true );
1043 break;
1045 break;
1046 }
1047
1048 mSourceLineEdit->setSource( pictureItem->path() );
1049
1050 mBackgroundCheckbox->setChecked( pictureItem->backgroundEnabled() );
1051 if ( const QgsSymbol *symbol = pictureItem->backgroundSymbol() )
1052 mBackgroundSymbolButton->setSymbol( symbol->clone() );
1053
1054 mFrameCheckbox->setChecked( pictureItem->frameEnabled() );
1055 if ( const QgsSymbol *symbol = pictureItem->frameSymbol() )
1056 mFrameSymbolButton->setSymbol( symbol->clone() );
1057
1058 mWidthSpinBox->setValue( pictureItem->fixedSize().width() );
1059 mHeightSpinBox->setValue( pictureItem->fixedSize().height() );
1060 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( pictureItem->placementMode() ) ) );
1061 sizeModeChanged();
1062
1063 mBlockChangedSignal = false;
1064
1065 return true;
1066}
1067
1068void QgsAnnotationPictureItemWidget::onWidgetChanged()
1069{
1070 if ( !mBlockChangedSignal )
1071 emit itemChanged();
1072}
1073
1074void QgsAnnotationPictureItemWidget::modeChanged( bool checked )
1075{
1076 if ( !checked )
1077 return;
1078
1079 const bool svg = mRadioSVG->isChecked();
1080
1081 if ( svg )
1082 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Svg );
1083 else
1084 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Image );
1085
1086 onWidgetChanged();
1087}
1088
1089void QgsAnnotationPictureItemWidget::sizeModeChanged()
1090{
1091 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value< Qgis::AnnotationPlacementMode >();
1092 switch ( mode )
1093 {
1095 mSizeStackedWidget->setCurrentWidget( mPageSpatialBounds );
1096 break;
1097
1099 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1100 break;
1101
1103 {
1104 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
1105 {
1106 // convert item bounds to relative position
1107 const QgsRectangle itemBounds = details->boundingBox();
1108 if ( QgsMapCanvas *canvas = context().mapCanvas() )
1109 {
1110 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
1111 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
1112 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
1113 mUpdateItemPosition = true;
1114 }
1115 }
1116
1117 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1118 break;
1119 }
1120 }
1121
1122 onWidgetChanged();
1123}
1124
1125void QgsAnnotationPictureItemWidget::setWidth()
1126{
1127 if ( mLockAspectRatio->locked() )
1128 {
1129 const double ratio = pictureAspectRatio();
1130 if ( ratio > 0 )
1131 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1132 }
1133
1134 onWidgetChanged();
1135}
1136
1137void QgsAnnotationPictureItemWidget::setHeight()
1138{
1139 if ( mLockAspectRatio->locked() )
1140 {
1141 const double ratio = pictureAspectRatio();
1142 if ( ratio > 0 )
1143 whileBlocking( mWidthSpinBox )->setValue( mHeightSpinBox->value() / ratio );
1144 }
1145
1146 onWidgetChanged();
1147}
1148
1149void QgsAnnotationPictureItemWidget::setLockAspectRatio( bool locked )
1150{
1151 if ( locked && !mBlockChangedSignal )
1152 {
1153 const double ratio = pictureAspectRatio();
1154 if ( ratio > 0 )
1155 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1156 }
1157
1158 onWidgetChanged();
1159}
1160
1161double QgsAnnotationPictureItemWidget::pictureAspectRatio() const
1162{
1163 const bool svg = mRadioSVG->isChecked();
1164 const QString path = mSourceLineEdit->source();
1165 QSizeF size;
1166 if ( svg )
1167 {
1168 size = QgsApplication::svgCache()->svgViewboxSize( path, 100, QColor(), QColor(), 1, 1 );
1169 }
1170 else
1171 {
1172 size = QgsApplication::imageCache()->originalSize( path );
1173 }
1174 if ( size.isValid() && size.width() > 0 )
1175 return size.height() / size.width();
1176
1177 return 0;
1178}
1179
1181
SymbolRotationMode
Modes for handling how symbol and text entity rotation is handled when maps are rotated.
Definition qgis.h:750
@ RespectMapRotation
Entity is rotated along with the map.
@ IgnoreMapRotation
Entity ignores map rotation.
PictureFormat
Picture formats.
Definition qgis.h:4849
@ Raster
Raster image.
@ Unknown
Invalid or unknown image type.
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size)
@ Millimeters
Millimeters.
@ Points
Points (e.g., for font sizes)
@ MapUnits
Map units.
@ MetersInMapUnits
Meters value as Map units.
@ Fill
Fill symbol.
AnnotationPlacementMode
Annotation item placement modes.
Definition qgis.h:2312
@ SpatialBounds
Item is rendered inside fixed spatial bounds, and size will depend on map scale.
@ FixedSize
Item is rendered at a fixed size, regardless of map scale. Item's location is georeferenced to a spat...
@ RelativeToMapFrame
Items size and placement is relative to the map's frame, and the item will always be rendered in the ...
void sourceChanged(const QString &source)
Emitted whenever the file source is changed in the widget.
void changed()
Emitted when the alignment is changed.
A base class for property widgets for annotation items.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
void itemChanged()
Emitted when the annotation item definition in the widget is changed by the user.
Abstract base class for annotation items which are drawn with QgsAnnotationLayers.
An annotation item which renders a line symbol along a line geometry.
void setSymbol(QgsLineSymbol *symbol)
Sets the symbol used to render the marker item.
QgsAnnotationLineItem * clone() const override
Returns a clone of the item.
An annotation item which renders text along a line geometry.
QgsAnnotationLineTextItem * clone() const override
Returns a clone of the item.
void setFormat(const QgsTextFormat &format)
Sets the text format used to render the text.
An annotation item which renders a marker symbol at a point location.
void setSymbol(QgsMarkerSymbol *symbol)
Sets the symbol used to render the marker item.
QgsAnnotationMarkerItem * clone() const override
Returns a clone of the item.
An annotation item which renders a picture.
Qgis::PictureFormat format() const
Returns the picture format.
QString path() const
Returns the path of the image used to render the item.
QgsAnnotationPictureItem * clone() const override
Returns a clone of the item.
void setPath(Qgis::PictureFormat format, const QString &path)
Sets the format and path of the image used to render the item.
An annotation item which renders a text string at a point location.
void setFormat(const QgsTextFormat &format)
Sets the text format used to render the text.
QgsAnnotationPointTextItem * clone() const override
Returns a clone of the item.
An annotation item which renders a fill symbol for a polygon geometry.
void setSymbol(QgsFillSymbol *symbol)
Sets the symbol used to render the polygon item.
QgsAnnotationPolygonItem * clone() const override
Returns a clone of the item.
QSizeF fixedSize() const
Returns the fixed size to use for the item, when the placementMode() is Qgis::AnnotationPlacementMode...
bool frameEnabled() const
Returns true if the item's frame should be rendered.
const QgsFillSymbol * frameSymbol() const
Returns the symbol used to render the item's frame.
Qgis::AnnotationPlacementMode placementMode() const
Returns the placement mode for the item.
bool backgroundEnabled() const
Returns true if the item's background should be rendered.
const QgsFillSymbol * backgroundSymbol() const
Returns the symbol used to render the item's background.
An annotation item which renders paragraphs of text within a rectangle.
void setFormat(const QgsTextFormat &format)
Sets the text format used to render the text.
QgsAnnotationRectangleTextItem * clone() const override
Returns a clone of the item.
const QgsMargins & margins() const
Returns the margins between the outside of the item's frame and the interior text.
Qgis::RenderUnit marginsUnit() const
Returns the units for the margins between the item's frame and the interior text.
static QgsRecentStyleHandler * recentStyleHandler()
Returns the handler for recently used style items.
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
A generic dialog for building expression strings.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static QString findAndSelectActiveExpression(QgsCodeEditor *editor, const QString &pattern=QString())
Find the expression under the cursor in the given editor and select it.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
QSize originalSize(const QString &path, bool blocking=false) const
Returns the original size (in pixels) of the image at the specified path.
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
Map canvas is a class for displaying all GIS data types on a canvas.
The QgsMargins class defines the four margins of a rectangle.
Definition qgsmargins.h:37
double top() const
Returns the top margin.
Definition qgsmargins.h:77
double right() const
Returns the right margin.
Definition qgsmargins.h:83
double bottom() const
Returns the bottom margin.
Definition qgsmargins.h:89
double left() const
Returns the left margin.
Definition qgsmargins.h:71
static QgsMarkerSymbol * createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
A class to represent a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void lockChanged(bool locked)
Emitted whenever the lock state changes.
void pushRecentSymbol(const QString &identifier, QgsSymbol *symbol)
Pushes a recently used symbol with the specified identifier.
A rectangle specified with double values.
double width() const
Returns the width of the rectangle.
QgsPointXY center() const
Returns the center point of the rectangle.
static QgsRectangle fromCenterAndSize(const QgsPointXY &center, double width, double height)
Creates a new rectangle, given the specified center point and width and height.
Contains information about a rendered annotation item.
A widget for editing rich text documents, with support for user controlled formatting of text and ins...
@ PlainText
Plain text mode.
@ QgsTextRenderer
QGIS text renderer mode, exposes the HTML/CSS subset supported by the QgsTextRenderer class.
void textChanged()
Emitted when the text contents are changed.
@ CurrentPageOnly
Only the size of the current page is considered when calculating the stacked widget size.
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:145
QSizeF svgViewboxSize(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > &parameters=QMap< QString, QString >())
Calculates the viewbox size of a (possibly cached) SVG file.
void changed()
Emitted when the symbol's settings are changed.
Symbol selector widget that can be used to select and build a symbol.
void symbolModified()
Emitted when a symbol is modified in the widget.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
A widget for customizing text formatting settings.
void widgetChanged()
Emitted when the text format defined by the widget changes.
void changed()
Emitted when the selected unit is changed, or the definition of the map unit scale is changed.
QList< Qgis::RenderUnit > RenderUnitList
List of render units.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:5761