QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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
24#include "qgsapplication.h"
26#include "qgsexpressionfinder.h"
27#include "qgsfillsymbol.h"
28#include "qgsimagecache.h"
29#include "qgslinesymbol.h"
30#include "qgsmapcanvas.h"
31#include "qgsmarkersymbol.h"
34#include "qgsstyle.h"
35#include "qgssvgcache.h"
37#include "qgstextformatwidget.h"
38
39#include <QString>
40
41#include "moc_qgsannotationitemwidget_impl.cpp"
42
43using namespace Qt::StringLiterals;
44
46
47QgsAnnotationPolygonItemWidget::QgsAnnotationPolygonItemWidget( QWidget *parent )
49{
50 setupUi( this );
51
52 mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
53 mSelector->setDockMode( dockMode() );
54 connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [this] {
55 if ( !mBlockChangedSignal )
56 {
57 emit itemChanged();
58 QgsApplication::recentStyleHandler()->pushRecentSymbol( u"polygon_annotation_item"_s, qgis::down_cast<QgsFillSymbol *>( mSelector->symbol()->clone() ) );
59 }
60 } );
61 connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
62
63 QVBoxLayout *layout = new QVBoxLayout();
64 layout->setContentsMargins( 0, 0, 0, 0 );
65 layout->addWidget( mSelector );
66 mSymbolSelectorFrame->setLayout( layout );
67
68 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
69 if ( !mBlockChangedSignal )
70 emit itemChanged();
71 } );
72}
73
74QgsAnnotationItem *QgsAnnotationPolygonItemWidget::createItem()
75{
76 QgsAnnotationPolygonItem *newItem = mItem->clone();
77 newItem->setSymbol( mSymbol->clone() );
78 mPropertiesWidget->updateItem( newItem );
79 return newItem;
80}
81
82void QgsAnnotationPolygonItemWidget::updateItem( QgsAnnotationItem *item )
83{
84 if ( QgsAnnotationPolygonItem *polygonItem = dynamic_cast<QgsAnnotationPolygonItem *>( item ) )
85 {
86 polygonItem->setSymbol( mSymbol->clone() );
87 mPropertiesWidget->updateItem( polygonItem );
88 }
89}
90
91void QgsAnnotationPolygonItemWidget::setDockMode( bool dockMode )
92{
94 if ( mSelector )
95 mSelector->setDockMode( dockMode );
96}
97
98void QgsAnnotationPolygonItemWidget::setContext( const QgsSymbolWidgetContext &context )
99{
101 if ( mSelector )
102 mSelector->setContext( context );
103 mPropertiesWidget->setContext( context );
104}
105
106QgsAnnotationPolygonItemWidget::~QgsAnnotationPolygonItemWidget() = default;
107
108bool QgsAnnotationPolygonItemWidget::setNewItem( QgsAnnotationItem *item )
109{
110 QgsAnnotationPolygonItem *polygonItem = dynamic_cast<QgsAnnotationPolygonItem *>( item );
111 if ( !polygonItem )
112 return false;
113
114 mItem.reset( polygonItem->clone() );
115 if ( mItem->symbol() )
116 {
117 mSymbol.reset( mItem->symbol()->clone() );
118 }
119 else
120 {
121 mSymbol = QgsFillSymbol::createSimple( {} );
122 }
123 mBlockChangedSignal = true;
124 mSelector->loadSymbol( mSymbol.get() );
125 mSelector->updatePreview();
126 mPropertiesWidget->setItem( mItem.get() );
127 mBlockChangedSignal = false;
128
129 return true;
130}
131
132
133//
134// QgsAnnotationLineItemWidget
135//
136
137QgsAnnotationLineItemWidget::QgsAnnotationLineItemWidget( QWidget *parent )
139{
140 setupUi( this );
141
142 mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
143 mSelector->setDockMode( dockMode() );
144 connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [this] {
145 if ( !mBlockChangedSignal )
146 {
147 emit itemChanged();
148 QgsApplication::recentStyleHandler()->pushRecentSymbol( u"line_annotation_item"_s, qgis::down_cast<QgsLineSymbol *>( mSelector->symbol()->clone() ) );
149 }
150 } );
151 connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
152
153 QVBoxLayout *layout = new QVBoxLayout();
154 layout->setContentsMargins( 0, 0, 0, 0 );
155 layout->addWidget( mSelector );
156 mSymbolSelectorFrame->setLayout( layout );
157
158 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
159 if ( !mBlockChangedSignal )
160 emit itemChanged();
161 } );
162}
163
164QgsAnnotationItem *QgsAnnotationLineItemWidget::createItem()
165{
166 QgsAnnotationLineItem *newItem = mItem->clone();
167 newItem->setSymbol( mSymbol->clone() );
168 mPropertiesWidget->updateItem( newItem );
169 return newItem;
170}
171
172void QgsAnnotationLineItemWidget::updateItem( QgsAnnotationItem *item )
173{
174 if ( QgsAnnotationLineItem *lineItem = dynamic_cast<QgsAnnotationLineItem *>( item ) )
175 {
176 lineItem->setSymbol( mSymbol->clone() );
177 mPropertiesWidget->updateItem( lineItem );
178 }
179}
180
181void QgsAnnotationLineItemWidget::setDockMode( bool dockMode )
182{
184 if ( mSelector )
185 mSelector->setDockMode( dockMode );
186}
187
188void QgsAnnotationLineItemWidget::setContext( const QgsSymbolWidgetContext &context )
189{
191 if ( mSelector )
192 mSelector->setContext( context );
193 mPropertiesWidget->setContext( context );
194}
195
196QgsAnnotationLineItemWidget::~QgsAnnotationLineItemWidget() = default;
197
198bool QgsAnnotationLineItemWidget::setNewItem( QgsAnnotationItem *item )
199{
200 QgsAnnotationLineItem *lineItem = dynamic_cast<QgsAnnotationLineItem *>( item );
201 if ( !lineItem )
202 return false;
203
204 mItem.reset( lineItem->clone() );
205 if ( mItem->symbol() )
206 {
207 mSymbol.reset( mItem->symbol()->clone() );
208 }
209 else
210 {
211 mSymbol = QgsLineSymbol::createSimple( {} );
212 }
213 mBlockChangedSignal = true;
214 mSelector->loadSymbol( mSymbol.get() );
215 mSelector->updatePreview();
216 mPropertiesWidget->setItem( mItem.get() );
217 mBlockChangedSignal = false;
218
219 return true;
220}
221
222
223//
224// QgsAnnotationMarkerItemWidget
225//
226
227QgsAnnotationMarkerItemWidget::QgsAnnotationMarkerItemWidget( QWidget *parent )
229{
230 setupUi( this );
231
232 mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
233 mSelector->setDockMode( dockMode() );
234 connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [this] {
235 if ( !mBlockChangedSignal )
236 {
237 emit itemChanged();
238 QgsApplication::recentStyleHandler()->pushRecentSymbol( u"marker_annotation_item"_s, qgis::down_cast<QgsMarkerSymbol *>( mSelector->symbol()->clone() ) );
239 }
240 } );
241 connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
242
243 QVBoxLayout *layout = new QVBoxLayout();
244 layout->setContentsMargins( 0, 0, 0, 0 );
245 layout->addWidget( mSelector );
246 mSymbolSelectorFrame->setLayout( layout );
247
248 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
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 = 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// QgsAnnotationPointTextItemWidget
315//
316
317QgsAnnotationPointTextItemWidget::QgsAnnotationPointTextItemWidget( QWidget *parent )
319{
320 setupUi( this );
321
322 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
323
324 mTextFormatButton->setMode( QgsFontButton::ModeTextRenderer );
325
326 mSpinTextAngle->setClearValue( 0 );
327
328 mRotationModeCombo->addItem( tr( "Ignore Map Rotation" ), QVariant::fromValue( Qgis::SymbolRotationMode::IgnoreMapRotation ) );
329 mRotationModeCombo->addItem( tr( "Rotate With Map" ), QVariant::fromValue( Qgis::SymbolRotationMode::RespectMapRotation ) );
330
331 mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
332
333 connect( mTextFormatButton, &QgsFontButton::changed, this, [this] {
334 mTextEdit->setMode( mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
335
336 if ( !mBlockChangedSignal )
337 emit itemChanged();
338 } );
339 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, [this] {
340 if ( !mBlockChangedSignal )
341 emit itemChanged();
342 } );
343 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked );
344 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
345 if ( !mBlockChangedSignal )
346 emit itemChanged();
347 } );
348
349 connect( mSpinTextAngle, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this] {
350 if ( !mBlockChangedSignal )
351 emit itemChanged();
352 } );
353
354 connect( mRotationModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this] {
355 if ( !mBlockChangedSignal )
356 emit itemChanged();
357 } );
358
359 connect( mAlignmentComboBox, &QgsAlignmentComboBox::changed, this, [this] {
360 if ( !mBlockChangedSignal )
361 emit itemChanged();
362 } );
363}
364
365QgsAnnotationItem *QgsAnnotationPointTextItemWidget::createItem()
366{
367 QgsAnnotationPointTextItem *newItem = mItem->clone();
368 updateItem( newItem );
369 return newItem;
370}
371
372void QgsAnnotationPointTextItemWidget::updateItem( QgsAnnotationItem *item )
373{
374 if ( QgsAnnotationPointTextItem *pointTextItem = dynamic_cast<QgsAnnotationPointTextItem *>( item ) )
375 {
376 mBlockChangedSignal = true;
377 pointTextItem->setFormat( mTextFormatButton->textFormat() );
378 pointTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
379 pointTextItem->setAngle( mSpinTextAngle->value() );
380 pointTextItem->setRotationMode( mRotationModeCombo->currentData().value<Qgis::SymbolRotationMode>() );
381 pointTextItem->setAlignment( mAlignmentComboBox->currentAlignment() );
382 mBlockChangedSignal = false;
383 mPropertiesWidget->updateItem( pointTextItem );
384 }
385}
386
387void QgsAnnotationPointTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
388{
390 if ( mTextFormatButton )
391 {
392 mTextFormatButton->setMapCanvas( context.mapCanvas() );
393 mTextFormatButton->setMessageBar( context.messageBar() );
394 }
395 mPropertiesWidget->setContext( context );
396}
397
398void QgsAnnotationPointTextItemWidget::focusDefaultWidget()
399{
400 mTextEdit->textEdit()->selectAll();
401 mTextEdit->setFocus();
402}
403
404QgsAnnotationPointTextItemWidget::~QgsAnnotationPointTextItemWidget() = default;
405
406bool QgsAnnotationPointTextItemWidget::setNewItem( QgsAnnotationItem *item )
407{
408 QgsAnnotationPointTextItem *textItem = dynamic_cast<QgsAnnotationPointTextItem *>( item );
409 if ( !textItem )
410 return false;
411
412 mItem.reset( textItem->clone() );
413
414 mBlockChangedSignal = true;
415 mTextFormatButton->setTextFormat( mItem->format() );
416 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
417 mTextEdit->setText( mItem->text() );
418 mSpinTextAngle->setValue( mItem->angle() );
419 mRotationModeCombo->setCurrentIndex( mRotationModeCombo->findData( QVariant::fromValue( mItem->rotationMode() ) ) );
420 mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask );
421 mPropertiesWidget->setItem( mItem.get() );
422 mBlockChangedSignal = false;
423
424 return true;
425}
426
427void QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked()
428{
429 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
430
431 QgsExpressionContext expressionContext;
432 if ( context().expressionContext() )
433 expressionContext = *( context().expressionContext() );
434 else
435 expressionContext = QgsProject::instance()->createExpressionContext();
436
437 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, u"generic"_s, expressionContext );
438
439 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
440 if ( exprDlg.exec() == QDialog::Accepted )
441 {
442 expression = exprDlg.expressionText().trimmed();
443 if ( !expression.isEmpty() )
444 {
445 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
446 }
447 }
448}
449
450
451//
452// QgsAnnotationLineTextItemWidget
453//
454
455QgsAnnotationLineTextItemWidget::QgsAnnotationLineTextItemWidget( QWidget *parent )
457{
458 setupUi( this );
459
460 mTextFormatButton->setMode( QgsFontButton::ModeTextRenderer );
461
462 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
463
464 connect( mTextFormatButton, &QgsFontButton::changed, this, [this] {
465 mTextEdit->setMode( mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
466
467 if ( !mBlockChangedSignal )
468 emit itemChanged();
469 } );
470 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, [this] {
471 if ( !mBlockChangedSignal )
472 emit itemChanged();
473 } );
474 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked );
475 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
476 if ( !mBlockChangedSignal )
477 emit itemChanged();
478 } );
479
480 mOffsetUnitWidget->setUnits(
482 );
483 mSpinOffset->setClearValue( 0.0 );
484 connect( mSpinOffset, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, [this] {
485 if ( !mBlockChangedSignal )
486 emit itemChanged();
487 } );
488
489 connect( mOffsetUnitWidget, &QgsUnitSelectionWidget::changed, this, [this] {
490 if ( !mBlockChangedSignal )
491 emit itemChanged();
492 } );
493}
494
495QgsAnnotationLineTextItemWidget::~QgsAnnotationLineTextItemWidget() = default;
496
497QgsAnnotationItem *QgsAnnotationLineTextItemWidget::createItem()
498{
499 QgsAnnotationLineTextItem *newItem = mItem->clone();
500 updateItem( newItem );
501 return newItem;
502}
503
504void QgsAnnotationLineTextItemWidget::updateItem( QgsAnnotationItem *item )
505{
506 if ( QgsAnnotationLineTextItem *lineTextItem = dynamic_cast<QgsAnnotationLineTextItem *>( item ) )
507 {
508 mBlockChangedSignal = true;
509 lineTextItem->setFormat( mTextFormatButton->textFormat() );
510 lineTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
511
512 lineTextItem->setOffsetFromLine( mSpinOffset->value() );
513 lineTextItem->setOffsetFromLineUnit( mOffsetUnitWidget->unit() );
514 lineTextItem->setOffsetFromLineMapUnitScale( mOffsetUnitWidget->getMapUnitScale() );
515
516 mBlockChangedSignal = false;
517 mPropertiesWidget->updateItem( lineTextItem );
518 }
519}
520
521void QgsAnnotationLineTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
522{
524 if ( mTextFormatButton )
525 {
526 mTextFormatButton->setMapCanvas( context.mapCanvas() );
527 mTextFormatButton->setMessageBar( context.messageBar() );
528 }
529 mPropertiesWidget->setContext( context );
530}
531
532void QgsAnnotationLineTextItemWidget::focusDefaultWidget()
533{
534 mTextEdit->textEdit()->selectAll();
535 mTextEdit->setFocus();
536}
537
538bool QgsAnnotationLineTextItemWidget::setNewItem( QgsAnnotationItem *item )
539{
540 QgsAnnotationLineTextItem *textItem = dynamic_cast<QgsAnnotationLineTextItem *>( item );
541 if ( !textItem )
542 return false;
543
544 mItem.reset( textItem->clone() );
545
546 mBlockChangedSignal = true;
547 mTextFormatButton->setTextFormat( mItem->format() );
548 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
549 mTextEdit->setText( mItem->text() );
550 mPropertiesWidget->setItem( mItem.get() );
551
552 mSpinOffset->setValue( mItem->offsetFromLine() );
553 mOffsetUnitWidget->setUnit( mItem->offsetFromLineUnit() );
554 mOffsetUnitWidget->setMapUnitScale( mItem->offsetFromLineMapUnitScale() );
555
556 mBlockChangedSignal = false;
557
558 return true;
559}
560
561void QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked()
562{
563 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
564
565 QgsExpressionContext expressionContext;
566 if ( context().expressionContext() )
567 expressionContext = *( context().expressionContext() );
568 else
569 expressionContext = QgsProject::instance()->createExpressionContext();
570
571 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, u"generic"_s, expressionContext );
572
573 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
574 if ( exprDlg.exec() == QDialog::Accepted )
575 {
576 expression = exprDlg.expressionText().trimmed();
577 if ( !expression.isEmpty() )
578 {
579 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
580 }
581 }
582}
583
584
585//
586// QgsAnnotationRectangleTextItemWidget
587//
588
589QgsAnnotationRectangleTextItemWidget::QgsAnnotationRectangleTextItemWidget( QWidget *parent )
591{
592 setupUi( this );
593
594 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
595 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
596 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
597
598 mSizeUnitWidget->setUnits(
600 );
601
602 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
603 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
604 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
605 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
606 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
607 mFrameSymbolButton->registerExpressionContextGenerator( this );
608
609 mSpinBottomMargin->setClearValue( 0 );
610 mSpinTopMargin->setClearValue( 0 );
611 mSpinRightMargin->setClearValue( 0 );
612 mSpinLeftMargin->setClearValue( 0 );
613 mMarginUnitWidget->setUnits(
615 );
616
617 mTextFormatButton->setMode( QgsFontButton::ModeTextRenderer );
618
619 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
620
621 mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight | Qt::AlignJustify );
622 mVerticalAlignmentComboBox->setAvailableAlignments( Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom );
623
624 connect( mTextFormatButton, &QgsFontButton::changed, this, [this] {
625 mTextEdit->setMode( mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
626
627 onWidgetChanged();
628 } );
629 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
630 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked );
631 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
632 connect( mAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
633 connect( mVerticalAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
634 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
635 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
636 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
637 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
638 connect( mSpinTopMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
639 connect( mSpinRightMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
640 connect( mSpinLeftMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
641 connect( mSpinBottomMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
642 connect( mMarginUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
643
644 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
645
646 connect( mWidthSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setWidth );
647 connect( mHeightSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setHeight );
648
649 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationRectangleTextItemWidget::sizeModeChanged );
650 mWidgetFixedSize->hide();
651 sizeModeChanged();
652}
653
654QgsAnnotationItem *QgsAnnotationRectangleTextItemWidget::createItem()
655{
656 QgsAnnotationRectangleTextItem *newItem = mItem->clone();
657 updateItem( newItem );
658 return newItem;
659}
660
661void QgsAnnotationRectangleTextItemWidget::updateItem( QgsAnnotationItem *item )
662{
663 if ( QgsAnnotationRectangleTextItem *rectTextItem = dynamic_cast<QgsAnnotationRectangleTextItem *>( item ) )
664 {
665 mBlockChangedSignal = true;
666 rectTextItem->setFormat( mTextFormatButton->textFormat() );
667 rectTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
668 rectTextItem->setAlignment( mAlignmentComboBox->currentAlignment() | mVerticalAlignmentComboBox->currentAlignment() );
669
670 rectTextItem->setPlacementMode( mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>() );
671
672 rectTextItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
673 rectTextItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
674
675 rectTextItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
676 rectTextItem->setFrameEnabled( mFrameCheckbox->isChecked() );
677 rectTextItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol<QgsFillSymbol>() );
678 rectTextItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol<QgsFillSymbol>() );
679
680 rectTextItem->setMargins( QgsMargins( mSpinLeftMargin->value(), mSpinTopMargin->value(), mSpinRightMargin->value(), mSpinBottomMargin->value() ) );
681 rectTextItem->setMarginsUnit( mMarginUnitWidget->unit() );
682
683 if ( mUpdateItemPosition )
684 {
685 rectTextItem->setBounds( mItem->bounds() );
686 mUpdateItemPosition = false;
687 }
688
689 mBlockChangedSignal = false;
690
691 mPropertiesWidget->updateItem( rectTextItem );
692 }
693}
694
695void QgsAnnotationRectangleTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
696{
698 if ( mTextFormatButton )
699 {
700 mTextFormatButton->setMapCanvas( context.mapCanvas() );
701 mTextFormatButton->setMessageBar( context.messageBar() );
702 }
703 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
704 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
705 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
706 mFrameSymbolButton->setMessageBar( context.messageBar() );
707 mPropertiesWidget->setContext( context );
708}
709
710QgsExpressionContext QgsAnnotationRectangleTextItemWidget::createExpressionContext() const
711{
712 QgsExpressionContext expressionContext;
713 if ( context().expressionContext() )
714 expressionContext = *( context().expressionContext() );
715 else
716 expressionContext = QgsProject::instance()->createExpressionContext();
717 return expressionContext;
718}
719
720void QgsAnnotationRectangleTextItemWidget::focusDefaultWidget()
721{
722 mTextEdit->textEdit()->selectAll();
723 mTextEdit->setFocus();
724}
725
726QgsAnnotationRectangleTextItemWidget::~QgsAnnotationRectangleTextItemWidget() = default;
727
728bool QgsAnnotationRectangleTextItemWidget::setNewItem( QgsAnnotationItem *item )
729{
730 QgsAnnotationRectangleTextItem *textItem = dynamic_cast<QgsAnnotationRectangleTextItem *>( item );
731 if ( !textItem )
732 return false;
733
734 mItem.reset( textItem->clone() );
735
736 mBlockChangedSignal = true;
737 mTextFormatButton->setTextFormat( mItem->format() );
738 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
739 mTextEdit->setText( mItem->text() );
740 mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask );
741 mVerticalAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignVertical_Mask );
742 mPropertiesWidget->setItem( mItem.get() );
743
744 mBackgroundCheckbox->setChecked( textItem->backgroundEnabled() );
745 if ( const QgsSymbol *symbol = textItem->backgroundSymbol() )
746 mBackgroundSymbolButton->setSymbol( symbol->clone() );
747
748 mFrameCheckbox->setChecked( textItem->frameEnabled() );
749 if ( const QgsSymbol *symbol = textItem->frameSymbol() )
750 mFrameSymbolButton->setSymbol( symbol->clone() );
751
752 mMarginUnitWidget->setUnit( textItem->marginsUnit() );
753 mSpinLeftMargin->setValue( textItem->margins().left() );
754 mSpinTopMargin->setValue( textItem->margins().top() );
755 mSpinRightMargin->setValue( textItem->margins().right() );
756 mSpinBottomMargin->setValue( textItem->margins().bottom() );
757
758 mWidthSpinBox->setValue( textItem->fixedSize().width() );
759 mHeightSpinBox->setValue( textItem->fixedSize().height() );
760 mSizeUnitWidget->setUnit( textItem->fixedSizeUnit() );
761 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( textItem->placementMode() ) ) );
762
763 mBlockChangedSignal = false;
764
765 return true;
766}
767
768void QgsAnnotationRectangleTextItemWidget::onWidgetChanged()
769{
770 if ( !mBlockChangedSignal )
771 emit itemChanged();
772}
773
774void QgsAnnotationRectangleTextItemWidget::sizeModeChanged()
775{
776 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>();
777 switch ( mode )
778 {
780 mWidgetFixedSize->hide();
781 break;
782
784 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
785 {
786 const QgsRectangle itemBoundsMapUnits = details->boundingBox();
787 if ( QgsMapCanvas *canvas = context().mapCanvas() )
788 {
789 const QgsPointXY topLeftPixels = canvas->mapSettings().mapToPixel().transform( itemBoundsMapUnits.xMinimum(), itemBoundsMapUnits.yMinimum() );
790 const QgsPointXY bottomRightPixels = canvas->mapSettings().mapToPixel().transform( itemBoundsMapUnits.xMaximum(), itemBoundsMapUnits.yMaximum() );
791 const double widthPixels = std::abs( bottomRightPixels.x() - topLeftPixels.x() );
792 const double heightPixels = std::abs( bottomRightPixels.y() - topLeftPixels.y() );
793
794 // convert width/height in pixels to mm
795 const double pixelsPerMm = canvas->mapSettings().outputDpi() / 25.4;
796 mItem->setFixedSizeUnit( Qgis::RenderUnit::Millimeters );
797 mItem->setFixedSize( QSizeF( widthPixels / pixelsPerMm, heightPixels / pixelsPerMm ) );
798
799 // and update widget UI accordingly
800 whileBlocking( mWidthSpinBox )->setValue( mItem->fixedSize().width() );
801 whileBlocking( mHeightSpinBox )->setValue( mItem->fixedSize().height() );
802 whileBlocking( mSizeUnitWidget )->setUnit( mItem->fixedSizeUnit() );
803
804 mUpdateItemPosition = true;
805 }
806 }
807
808 mWidgetFixedSize->show();
809 break;
810
812 {
813 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
814 {
815 // convert item bounds to relative position
816 const QgsRectangle itemBounds = details->boundingBox();
817 if ( QgsMapCanvas *canvas = context().mapCanvas() )
818 {
819 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
820 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
821 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
822 mUpdateItemPosition = true;
823 }
824 }
825
826 mWidgetFixedSize->hide();
827 break;
828 }
829 }
830
831 onWidgetChanged();
832}
833
834void QgsAnnotationRectangleTextItemWidget::setWidth()
835{
836 onWidgetChanged();
837}
838
839void QgsAnnotationRectangleTextItemWidget::setHeight()
840{
841 onWidgetChanged();
842}
843
844void QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked()
845{
846 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
847
848 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, u"generic"_s, createExpressionContext() );
849
850 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
851 if ( exprDlg.exec() == QDialog::Accepted )
852 {
853 expression = exprDlg.expressionText().trimmed();
854 if ( !expression.isEmpty() )
855 {
856 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
857 }
858 }
859}
860
861
862//
863// QgsAnnotationPictureItemWidget
864//
865
866QgsAnnotationPictureItemWidget::QgsAnnotationPictureItemWidget( QWidget *parent )
868{
869 setupUi( this );
870
871 mSizeStackedWidget->setSizeMode( QgsStackedWidget::SizeMode::CurrentPageOnly );
872
873 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
874 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
875 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
876
877 mSizeUnitWidget->setUnits(
879 );
880
881 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
882 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
883 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
884 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
885 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
886 mFrameSymbolButton->registerExpressionContextGenerator( this );
887
888 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
889 if ( !mBlockChangedSignal )
890 emit itemChanged();
891 } );
892
893 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationPictureItemWidget::sizeModeChanged );
894
895 connect( mRadioSVG, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
896 connect( mRadioRaster, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
897 connect( mSourceLineEdit, &QgsPictureSourceLineEditBase::sourceChanged, this, [this]( const QString &source ) {
898 if ( !mRadioSVG->isChecked() && QFileInfo( source ).suffix().compare( "svg"_L1, Qt::CaseInsensitive ) == 0 )
899 {
900 mRadioSVG->setChecked( true );
901 }
902
903 onWidgetChanged();
904 } );
905
906 connect( mLockAspectRatioCheck, &QCheckBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
907 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
908 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
909 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
910 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
911 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
912
913 connect( mWidthSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setWidth );
914 connect( mHeightSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setHeight );
915 connect( mLockAspectRatio, &QgsRatioLockButton::lockChanged, this, &QgsAnnotationPictureItemWidget::setLockAspectRatio );
916}
917
918QgsAnnotationPictureItemWidget::~QgsAnnotationPictureItemWidget() = default;
919
920QgsAnnotationItem *QgsAnnotationPictureItemWidget::createItem()
921{
922 QgsAnnotationPictureItem *newItem = mItem->clone();
923 updateItem( newItem );
924 return newItem;
925}
926
927void QgsAnnotationPictureItemWidget::updateItem( QgsAnnotationItem *item )
928{
929 if ( QgsAnnotationPictureItem *pictureItem = dynamic_cast<QgsAnnotationPictureItem *>( item ) )
930 {
931 const bool svg = mRadioSVG->isChecked();
933 const QString path = mSourceLineEdit->source();
934 pictureItem->setPath( newFormat, path );
935
936 pictureItem->setPlacementMode( mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>() );
937 switch ( pictureItem->placementMode() )
938 {
940 pictureItem->setLockAspectRatio( mLockAspectRatioCheck->isChecked() );
941 break;
944 pictureItem->setLockAspectRatio( mLockAspectRatio->isChecked() );
945 break;
946 }
947
948 pictureItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
949 pictureItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
950
951 pictureItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
952 pictureItem->setFrameEnabled( mFrameCheckbox->isChecked() );
953 pictureItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol<QgsFillSymbol>() );
954 pictureItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol<QgsFillSymbol>() );
955
956 if ( mUpdateItemPosition )
957 {
958 pictureItem->setBounds( mItem->bounds() );
959 mUpdateItemPosition = false;
960 }
961
962 mPropertiesWidget->updateItem( pictureItem );
963 }
964}
965
966void QgsAnnotationPictureItemWidget::setDockMode( bool dockMode )
967{
969}
970
971void QgsAnnotationPictureItemWidget::setContext( const QgsSymbolWidgetContext &context )
972{
974 mPropertiesWidget->setContext( context );
975 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
976 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
977 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
978 mFrameSymbolButton->setMessageBar( context.messageBar() );
979}
980
981QgsExpressionContext QgsAnnotationPictureItemWidget::createExpressionContext() const
982{
983 QgsExpressionContext expressionContext;
984 if ( context().expressionContext() )
985 expressionContext = *( context().expressionContext() );
986 else
987 expressionContext = QgsProject::instance()->createExpressionContext();
988 return expressionContext;
989}
990
991void QgsAnnotationPictureItemWidget::focusDefaultWidget()
992{
993 mSourceLineEdit->setFocus();
994}
995
996bool QgsAnnotationPictureItemWidget::setNewItem( QgsAnnotationItem *item )
997{
998 QgsAnnotationPictureItem *pictureItem = dynamic_cast<QgsAnnotationPictureItem *>( item );
999 if ( !pictureItem )
1000 return false;
1001
1002 mItem.reset( pictureItem->clone() );
1003
1004 mBlockChangedSignal = true;
1005 mPropertiesWidget->setItem( mItem.get() );
1006
1007 mLockAspectRatioCheck->setChecked( mItem->lockAspectRatio() );
1008 mLockAspectRatio->setLocked( mItem->lockAspectRatio() );
1009 switch ( pictureItem->format() )
1010 {
1012 mRadioSVG->setChecked( true );
1013 break;
1015 mRadioRaster->setChecked( true );
1016 break;
1018 break;
1019 }
1020
1021 mSourceLineEdit->setSource( pictureItem->path() );
1022
1023 mBackgroundCheckbox->setChecked( pictureItem->backgroundEnabled() );
1024 if ( const QgsSymbol *symbol = pictureItem->backgroundSymbol() )
1025 mBackgroundSymbolButton->setSymbol( symbol->clone() );
1026
1027 mFrameCheckbox->setChecked( pictureItem->frameEnabled() );
1028 if ( const QgsSymbol *symbol = pictureItem->frameSymbol() )
1029 mFrameSymbolButton->setSymbol( symbol->clone() );
1030
1031 mWidthSpinBox->setValue( pictureItem->fixedSize().width() );
1032 mHeightSpinBox->setValue( pictureItem->fixedSize().height() );
1033 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( pictureItem->placementMode() ) ) );
1034 sizeModeChanged();
1035
1036 mBlockChangedSignal = false;
1037
1038 return true;
1039}
1040
1041void QgsAnnotationPictureItemWidget::onWidgetChanged()
1042{
1043 if ( !mBlockChangedSignal )
1044 emit itemChanged();
1045}
1046
1047void QgsAnnotationPictureItemWidget::modeChanged( bool checked )
1048{
1049 if ( !checked )
1050 return;
1051
1052 const bool svg = mRadioSVG->isChecked();
1053
1054 if ( svg )
1055 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Svg );
1056 else
1057 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Image );
1058
1059 onWidgetChanged();
1060}
1061
1062void QgsAnnotationPictureItemWidget::sizeModeChanged()
1063{
1064 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>();
1065 switch ( mode )
1066 {
1068 mSizeStackedWidget->setCurrentWidget( mPageSpatialBounds );
1069 break;
1070
1072 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1073 break;
1074
1076 {
1077 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
1078 {
1079 // convert item bounds to relative position
1080 const QgsRectangle itemBounds = details->boundingBox();
1081 if ( QgsMapCanvas *canvas = context().mapCanvas() )
1082 {
1083 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
1084 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
1085 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
1086 mUpdateItemPosition = true;
1087 }
1088 }
1089
1090 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1091 break;
1092 }
1093 }
1094
1095 onWidgetChanged();
1096}
1097
1098void QgsAnnotationPictureItemWidget::setWidth()
1099{
1100 if ( mLockAspectRatio->locked() )
1101 {
1102 const double ratio = pictureAspectRatio();
1103 if ( ratio > 0 )
1104 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1105 }
1106
1107 onWidgetChanged();
1108}
1109
1110void QgsAnnotationPictureItemWidget::setHeight()
1111{
1112 if ( mLockAspectRatio->locked() )
1113 {
1114 const double ratio = pictureAspectRatio();
1115 if ( ratio > 0 )
1116 whileBlocking( mWidthSpinBox )->setValue( mHeightSpinBox->value() / ratio );
1117 }
1118
1119 onWidgetChanged();
1120}
1121
1122void QgsAnnotationPictureItemWidget::setLockAspectRatio( bool locked )
1123{
1124 if ( locked && !mBlockChangedSignal )
1125 {
1126 const double ratio = pictureAspectRatio();
1127 if ( ratio > 0 )
1128 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1129 }
1130
1131 onWidgetChanged();
1132}
1133
1134double QgsAnnotationPictureItemWidget::pictureAspectRatio() const
1135{
1136 const bool svg = mRadioSVG->isChecked();
1137 const QString path = mSourceLineEdit->source();
1138 QSizeF size;
1139 if ( svg )
1140 {
1141 size = QgsApplication::svgCache()->svgViewboxSize( path, 100, QColor(), QColor(), 1, 1 );
1142 }
1143 else
1144 {
1145 size = QgsApplication::imageCache()->originalSize( path );
1146 }
1147 if ( size.isValid() && size.width() > 0 )
1148 return size.height() / size.width();
1149
1150 return 0;
1151}
1152
SymbolRotationMode
Modes for handling how symbol and text entity rotation is handled when maps are rotated.
Definition qgis.h:812
@ RespectMapRotation
Entity is rotated along with the map.
Definition qgis.h:813
@ IgnoreMapRotation
Entity ignores map rotation.
Definition qgis.h:814
PictureFormat
Picture formats.
Definition qgis.h:5434
@ Raster
Raster image.
Definition qgis.h:5436
@ Unknown
Invalid or unknown image type.
Definition qgis.h:5437
@ SVG
SVG image.
Definition qgis.h:5435
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size).
Definition qgis.h:5344
@ Millimeters
Millimeters.
Definition qgis.h:5341
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5345
@ MapUnits
Map units.
Definition qgis.h:5342
@ Pixels
Pixels.
Definition qgis.h:5343
@ Inches
Inches.
Definition qgis.h:5346
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5348
@ Fill
Fill symbol.
Definition qgis.h:639
AnnotationPlacementMode
Annotation item placement modes.
Definition qgis.h:2569
@ SpatialBounds
Item is rendered inside fixed spatial bounds, and size will depend on map scale.
Definition qgis.h:2570
@ FixedSize
Item is rendered at a fixed size, regardless of map scale. Item's location is georeferenced to a spat...
Definition qgis.h:2571
@ RelativeToMapFrame
Items size and placement is relative to the map's frame, and the item will always be rendered in the ...
Definition qgis.h:2572
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 setText(const QString &text)
Sets the text rendered by the item.
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.
An annotation item which renders a text string at a point location.
void setText(const QString &text)
Sets the text rendered by the item.
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.
Qgis::RenderUnit fixedSizeUnit() const
Returns the units to use for fixed item sizes, when the placementMode() is Qgis::AnnotationPlacementM...
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.
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.
void setText(const QString &text)
Sets the text rendered by the item.
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 std::unique_ptr< QgsFillSymbol > createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
@ ModeTextRenderer
Configure font settings for use with QgsTextRenderer.
void changed()
Emitted when the widget's text format settings are changed.
QSize originalSize(const QString &path, bool blocking=false) const
Returns the original size (in pixels) of the image at the specified path.
static std::unique_ptr< 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.
Defines the four margins of a rectangle.
Definition qgsmargins.h:40
double top() const
Returns the top margin.
Definition qgsmargins.h:76
double right() const
Returns the right margin.
Definition qgsmargins.h:82
double bottom() const
Returns the bottom margin.
Definition qgsmargins.h:88
double left() const
Returns the left margin.
Definition qgsmargins.h:70
static std::unique_ptr< 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.
Represents a 2D point.
Definition qgspointxy.h:62
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
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 xMinimum
double yMinimum
double xMaximum
double yMaximum
static QgsRectangle fromCenterAndSize(const QgsPointXY &center, double width, double height)
Creates a new rectangle, given the specified center point and width and height.
QgsPointXY center
Contains information about a rendered annotation item.
@ 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:148
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:227
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:6880