QGIS API Documentation 3.41.0-Master (3440c17df1d)
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#include "moc_qgsannotationitemwidget_impl.cpp"
17
19#include "qgsstyle.h"
20#include "qgsfillsymbol.h"
21#include "qgslinesymbol.h"
22#include "qgsmarkersymbol.h"
31#include "qgstextformatwidget.h"
32#include "qgsapplication.h"
34#include "qgsexpressionfinder.h"
35#include "qgsimagecache.h"
36#include "qgssvgcache.h"
38#include "qgsmapcanvas.h"
39
41
42QgsAnnotationPolygonItemWidget::QgsAnnotationPolygonItemWidget( QWidget *parent )
44{
45 setupUi( this );
46
47 mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
48 mSelector->setDockMode( dockMode() );
49 connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [ = ]
50 {
51 if ( !mBlockChangedSignal )
52 {
53 emit itemChanged();
54 QgsApplication::recentStyleHandler()->pushRecentSymbol( QStringLiteral( "polygon_annotation_item" ), qgis::down_cast< QgsFillSymbol * >( mSelector->symbol()->clone() ) );
55 }
56 } );
57 connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
58
59 QVBoxLayout *layout = new QVBoxLayout();
60 layout->setContentsMargins( 0, 0, 0, 0 );
61 layout->addWidget( mSelector );
62 mSymbolSelectorFrame->setLayout( layout );
63
64 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
65 {
66 if ( !mBlockChangedSignal )
67 emit itemChanged();
68 } );
69}
70
71QgsAnnotationItem *QgsAnnotationPolygonItemWidget::createItem()
72{
73 QgsAnnotationPolygonItem *newItem = mItem->clone();
74 newItem->setSymbol( mSymbol->clone() );
75 mPropertiesWidget->updateItem( newItem );
76 return newItem;
77}
78
79void QgsAnnotationPolygonItemWidget::updateItem( QgsAnnotationItem *item )
80{
81 if ( QgsAnnotationPolygonItem *polygonItem = dynamic_cast< QgsAnnotationPolygonItem * >( item ) )
82 {
83 polygonItem->setSymbol( mSymbol->clone() );
84 mPropertiesWidget->updateItem( polygonItem );
85 }
86}
87
88void QgsAnnotationPolygonItemWidget::setDockMode( bool dockMode )
89{
91 if ( mSelector )
92 mSelector->setDockMode( dockMode );
93}
94
95void QgsAnnotationPolygonItemWidget::setContext( const QgsSymbolWidgetContext &context )
96{
98 if ( mSelector )
99 mSelector->setContext( context );
100 mPropertiesWidget->setContext( context );
101}
102
103QgsAnnotationPolygonItemWidget::~QgsAnnotationPolygonItemWidget() = default;
104
105bool QgsAnnotationPolygonItemWidget::setNewItem( QgsAnnotationItem *item )
106{
107 QgsAnnotationPolygonItem *polygonItem = dynamic_cast< QgsAnnotationPolygonItem * >( item );
108 if ( !polygonItem )
109 return false;
110
111 mItem.reset( polygonItem->clone() );
112 if ( mItem->symbol() )
113 {
114 mSymbol.reset( mItem->symbol()->clone() );
115 }
116 else
117 {
118 mSymbol.reset( QgsFillSymbol::createSimple( {} ) );
119 }
120 mBlockChangedSignal = true;
121 mSelector->loadSymbol( mSymbol.get() );
122 mSelector->updatePreview();
123 mPropertiesWidget->setItem( mItem.get() );
124 mBlockChangedSignal = false;
125
126 return true;
127}
128
129
130//
131// QgsAnnotationLineItemWidget
132//
133
134QgsAnnotationLineItemWidget::QgsAnnotationLineItemWidget( QWidget *parent )
136{
137 setupUi( this );
138
139 mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
140 mSelector->setDockMode( dockMode() );
141 connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [ = ]
142 {
143 if ( !mBlockChangedSignal )
144 {
145 emit itemChanged();
146 QgsApplication::recentStyleHandler()->pushRecentSymbol( QStringLiteral( "line_annotation_item" ), qgis::down_cast< QgsLineSymbol * >( mSelector->symbol()->clone() ) );
147 }
148 } );
149 connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
150
151 QVBoxLayout *layout = new QVBoxLayout();
152 layout->setContentsMargins( 0, 0, 0, 0 );
153 layout->addWidget( mSelector );
154 mSymbolSelectorFrame->setLayout( layout );
155
156 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
157 {
158 if ( !mBlockChangedSignal )
159 emit itemChanged();
160 } );
161}
162
163QgsAnnotationItem *QgsAnnotationLineItemWidget::createItem()
164{
165 QgsAnnotationLineItem *newItem = mItem->clone();
166 newItem->setSymbol( mSymbol->clone() );
167 mPropertiesWidget->updateItem( newItem );
168 return newItem;
169}
170
171void QgsAnnotationLineItemWidget::updateItem( QgsAnnotationItem *item )
172{
173 if ( QgsAnnotationLineItem *lineItem = dynamic_cast< QgsAnnotationLineItem * >( item ) )
174 {
175 lineItem->setSymbol( mSymbol->clone() );
176 mPropertiesWidget->updateItem( lineItem );
177 }
178}
179
180void QgsAnnotationLineItemWidget::setDockMode( bool dockMode )
181{
183 if ( mSelector )
184 mSelector->setDockMode( dockMode );
185}
186
187void QgsAnnotationLineItemWidget::setContext( const QgsSymbolWidgetContext &context )
188{
190 if ( mSelector )
191 mSelector->setContext( context );
192 mPropertiesWidget->setContext( context );
193}
194
195QgsAnnotationLineItemWidget::~QgsAnnotationLineItemWidget() = default;
196
197bool QgsAnnotationLineItemWidget::setNewItem( QgsAnnotationItem *item )
198{
199 QgsAnnotationLineItem *lineItem = dynamic_cast< QgsAnnotationLineItem * >( item );
200 if ( !lineItem )
201 return false;
202
203 mItem.reset( lineItem->clone() );
204 if ( mItem->symbol() )
205 {
206 mSymbol.reset( mItem->symbol()->clone() );
207 }
208 else
209 {
210 mSymbol.reset( QgsLineSymbol::createSimple( {} ) );
211 }
212 mBlockChangedSignal = true;
213 mSelector->loadSymbol( mSymbol.get() );
214 mSelector->updatePreview();
215 mPropertiesWidget->setItem( mItem.get() );
216 mBlockChangedSignal = false;
217
218 return true;
219}
220
221
222//
223// QgsAnnotationMarkerItemWidget
224//
225
226QgsAnnotationMarkerItemWidget::QgsAnnotationMarkerItemWidget( QWidget *parent )
228{
229 setupUi( this );
230
231 mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
232 mSelector->setDockMode( dockMode() );
233 connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [ = ]
234 {
235 if ( !mBlockChangedSignal )
236 {
237 emit itemChanged();
238 QgsApplication::recentStyleHandler()->pushRecentSymbol( QStringLiteral( "marker_annotation_item" ), 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, [ = ]
249 {
250 if ( !mBlockChangedSignal )
251 emit itemChanged();
252 } );
253}
254
255QgsAnnotationItem *QgsAnnotationMarkerItemWidget::createItem()
256{
257 QgsAnnotationMarkerItem *newItem = mItem->clone();
258 newItem->setSymbol( mSymbol->clone() );
259 mPropertiesWidget->updateItem( newItem );
260 return newItem;
261}
262
263void QgsAnnotationMarkerItemWidget::updateItem( QgsAnnotationItem *item )
264{
265 if ( QgsAnnotationMarkerItem *markerItem = dynamic_cast< QgsAnnotationMarkerItem * >( item ) )
266 {
267 markerItem->setSymbol( mSymbol->clone() );
268 mPropertiesWidget->updateItem( markerItem );
269 }
270}
271
272void QgsAnnotationMarkerItemWidget::setDockMode( bool dockMode )
273{
275 if ( mSelector )
276 mSelector->setDockMode( dockMode );
277}
278
279void QgsAnnotationMarkerItemWidget::setContext( const QgsSymbolWidgetContext &context )
280{
282 if ( mSelector )
283 mSelector->setContext( context );
284 mPropertiesWidget->setContext( context );
285}
286
287QgsAnnotationMarkerItemWidget::~QgsAnnotationMarkerItemWidget() = default;
288
289bool QgsAnnotationMarkerItemWidget::setNewItem( QgsAnnotationItem *item )
290{
291 QgsAnnotationMarkerItem *markerItem = dynamic_cast< QgsAnnotationMarkerItem * >( item );
292 if ( !markerItem )
293 return false;
294
295 mItem.reset( markerItem->clone() );
296 if ( mItem->symbol() )
297 {
298 mSymbol.reset( mItem->symbol()->clone() );
299 }
300 else
301 {
302 mSymbol.reset( QgsMarkerSymbol::createSimple( {} ) );
303 }
304 mBlockChangedSignal = true;
305 mSelector->loadSymbol( mSymbol.get() );
306 mSelector->updatePreview();
307 mPropertiesWidget->setItem( mItem.get() );
308 mBlockChangedSignal = false;
309
310 return true;
311}
312
313
314
315//
316// QgsAnnotationPointTextItemWidget
317//
318
319QgsAnnotationPointTextItemWidget::QgsAnnotationPointTextItemWidget( QWidget *parent )
321{
322 setupUi( this );
323
324 mTextFormatWidget = new QgsTextFormatWidget();
325 QVBoxLayout *vLayout = new QVBoxLayout();
326 vLayout->setContentsMargins( 0, 0, 0, 0 );
327 vLayout->addWidget( mTextFormatWidget );
328 mTextFormatWidgetContainer->setLayout( vLayout );
329
330 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
331 mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 );
332
333 mSpinTextAngle->setClearValue( 0 );
334
335 mRotationModeCombo->addItem( tr( "Ignore Map Rotation" ), QVariant::fromValue( Qgis::SymbolRotationMode::IgnoreMapRotation ) );
336 mRotationModeCombo->addItem( tr( "Rotate With Map" ), QVariant::fromValue( Qgis::SymbolRotationMode::RespectMapRotation ) );
337
338 mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
339
340 mTextFormatWidget->setDockMode( dockMode() );
341 connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [ = ]
342 {
343 mTextEdit->setMode(
344 mTextFormatWidget->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText
345 );
346
347 if ( !mBlockChangedSignal )
348 emit itemChanged();
349 } );
350 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, [ = ]
351 {
352 if ( !mBlockChangedSignal )
353 emit itemChanged();
354 } );
355 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked );
356 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
357 {
358 if ( !mBlockChangedSignal )
359 emit itemChanged();
360 } );
361
362 connect( mSpinTextAngle, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, [ = ]
363 {
364 if ( !mBlockChangedSignal )
365 emit itemChanged();
366 } );
367
368 connect( mRotationModeCombo, qOverload< int >( &QComboBox::currentIndexChanged ), this, [ = ]
369 {
370 if ( !mBlockChangedSignal )
371 emit itemChanged();
372 } );
373
374 connect( mAlignmentComboBox, &QgsAlignmentComboBox::changed, this, [ = ]
375 {
376 if ( !mBlockChangedSignal )
377 emit itemChanged();
378 } );
379}
380
381QgsAnnotationItem *QgsAnnotationPointTextItemWidget::createItem()
382{
383 QgsAnnotationPointTextItem *newItem = mItem->clone();
384 updateItem( newItem );
385 return newItem;
386}
387
388void QgsAnnotationPointTextItemWidget::updateItem( QgsAnnotationItem *item )
389{
390 if ( QgsAnnotationPointTextItem *pointTextItem = dynamic_cast< QgsAnnotationPointTextItem * >( item ) )
391 {
392 mBlockChangedSignal = true;
393 pointTextItem->setFormat( mTextFormatWidget->format() );
394 pointTextItem->setText( mTextFormatWidget->format().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
395 pointTextItem->setAngle( mSpinTextAngle->value() );
396 pointTextItem->setRotationMode( mRotationModeCombo->currentData().value< Qgis::SymbolRotationMode >() );
397 pointTextItem->setAlignment( mAlignmentComboBox->currentAlignment() );
398 mBlockChangedSignal = false;
399 mPropertiesWidget->updateItem( pointTextItem );
400 }
401}
402
403void QgsAnnotationPointTextItemWidget::setDockMode( bool dockMode )
404{
406 if ( mTextFormatWidget )
407 mTextFormatWidget->setDockMode( dockMode );
408}
409
410void QgsAnnotationPointTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
411{
413 if ( mTextFormatWidget )
414 mTextFormatWidget->setContext( context );
415 mPropertiesWidget->setContext( context );
416}
417
418void QgsAnnotationPointTextItemWidget::focusDefaultWidget()
419{
420 mTextEdit->textEdit()->selectAll();
421 mTextEdit->setFocus();
422}
423
424QgsAnnotationPointTextItemWidget::~QgsAnnotationPointTextItemWidget() = default;
425
426bool QgsAnnotationPointTextItemWidget::setNewItem( QgsAnnotationItem *item )
427{
428 QgsAnnotationPointTextItem *textItem = dynamic_cast< QgsAnnotationPointTextItem * >( item );
429 if ( !textItem )
430 return false;
431
432 mItem.reset( textItem->clone() );
433
434 mBlockChangedSignal = true;
435 mTextFormatWidget->setFormat( mItem->format() );
436 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
437 mTextEdit->setText( mItem->text() );
438 mSpinTextAngle->setValue( mItem->angle() );
439 mRotationModeCombo->setCurrentIndex( mRotationModeCombo->findData( QVariant::fromValue( mItem->rotationMode() ) ) );
440 mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask );
441 mPropertiesWidget->setItem( mItem.get() );
442 mBlockChangedSignal = false;
443
444 return true;
445}
446
447void QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked()
448{
449 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
450
451 QgsExpressionContext expressionContext;
452 if ( context().expressionContext() )
453 expressionContext = *( context().expressionContext() );
454 else
455 expressionContext = QgsProject::instance()->createExpressionContext();
456
457 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, QStringLiteral( "generic" ), expressionContext );
458
459 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
460 if ( exprDlg.exec() == QDialog::Accepted )
461 {
462 expression = exprDlg.expressionText().trimmed();
463 if ( !expression.isEmpty() )
464 {
465 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
466 }
467 }
468}
469
470
471//
472// QgsAnnotationLineTextItemWidget
473//
474
475QgsAnnotationLineTextItemWidget::QgsAnnotationLineTextItemWidget( QWidget *parent )
477{
478 setupUi( this );
479
480 mTextFormatWidget = new QgsTextFormatWidget();
481 QVBoxLayout *vLayout = new QVBoxLayout();
482 vLayout->setContentsMargins( 0, 0, 0, 0 );
483 vLayout->addWidget( mTextFormatWidget );
484 mTextFormatWidgetContainer->setLayout( vLayout );
485
486 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
487 mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 );
488
489 mTextFormatWidget->setDockMode( dockMode() );
490 connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [ = ]
491 {
492 mTextEdit->setMode(
493 mTextFormatWidget->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText
494 );
495
496 if ( !mBlockChangedSignal )
497 emit itemChanged();
498 } );
499 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, [ = ]
500 {
501 if ( !mBlockChangedSignal )
502 emit itemChanged();
503 } );
504 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked );
505 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
506 {
507 if ( !mBlockChangedSignal )
508 emit itemChanged();
509 } );
510
513 mSpinOffset->setClearValue( 0.0 );
514 connect( mSpinOffset, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, [ = ]
515 {
516 if ( !mBlockChangedSignal )
517 emit itemChanged();
518 } );
519
520 connect( mOffsetUnitWidget, &QgsUnitSelectionWidget::changed, this, [ = ]
521 {
522 if ( !mBlockChangedSignal )
523 emit itemChanged();
524 } );
525}
526
527QgsAnnotationLineTextItemWidget::~QgsAnnotationLineTextItemWidget() = default;
528
529QgsAnnotationItem *QgsAnnotationLineTextItemWidget::createItem()
530{
531 QgsAnnotationLineTextItem *newItem = mItem->clone();
532 updateItem( newItem );
533 return newItem;
534}
535
536void QgsAnnotationLineTextItemWidget::updateItem( QgsAnnotationItem *item )
537{
538 if ( QgsAnnotationLineTextItem *lineTextItem = dynamic_cast< QgsAnnotationLineTextItem * >( item ) )
539 {
540 mBlockChangedSignal = true;
541 lineTextItem->setFormat( mTextFormatWidget->format() );
542 lineTextItem->setText( mTextFormatWidget->format().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
543
544 lineTextItem->setOffsetFromLine( mSpinOffset->value() );
545 lineTextItem->setOffsetFromLineUnit( mOffsetUnitWidget->unit() );
546 lineTextItem->setOffsetFromLineMapUnitScale( mOffsetUnitWidget->getMapUnitScale() );
547
548 mBlockChangedSignal = false;
549 mPropertiesWidget->updateItem( lineTextItem );
550 }
551}
552
553void QgsAnnotationLineTextItemWidget::setDockMode( bool dockMode )
554{
556 if ( mTextFormatWidget )
557 mTextFormatWidget->setDockMode( dockMode );
558}
559
560void QgsAnnotationLineTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
561{
563 if ( mTextFormatWidget )
564 mTextFormatWidget->setContext( context );
565 mPropertiesWidget->setContext( context );
566}
567
568void QgsAnnotationLineTextItemWidget::focusDefaultWidget()
569{
570 mTextEdit->textEdit()->selectAll();
571 mTextEdit->setFocus();
572}
573
574bool QgsAnnotationLineTextItemWidget::setNewItem( QgsAnnotationItem *item )
575{
576 QgsAnnotationLineTextItem *textItem = dynamic_cast< QgsAnnotationLineTextItem * >( item );
577 if ( !textItem )
578 return false;
579
580 mItem.reset( textItem->clone() );
581
582 mBlockChangedSignal = true;
583 mTextFormatWidget->setFormat( mItem->format() );
584 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
585 mTextEdit->setText( mItem->text() );
586 mPropertiesWidget->setItem( mItem.get() );
587
588 mSpinOffset->setValue( mItem->offsetFromLine() );
589 mOffsetUnitWidget->setUnit( mItem->offsetFromLineUnit() );
590 mOffsetUnitWidget->setMapUnitScale( mItem->offsetFromLineMapUnitScale() );
591
592 mBlockChangedSignal = false;
593
594 return true;
595}
596
597void QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked()
598{
599 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
600
601 QgsExpressionContext expressionContext;
602 if ( context().expressionContext() )
603 expressionContext = *( context().expressionContext() );
604 else
605 expressionContext = QgsProject::instance()->createExpressionContext();
606
607 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, QStringLiteral( "generic" ), expressionContext );
608
609 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
610 if ( exprDlg.exec() == QDialog::Accepted )
611 {
612 expression = exprDlg.expressionText().trimmed();
613 if ( !expression.isEmpty() )
614 {
615 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
616 }
617 }
618}
619
620
621
622//
623// QgsAnnotationRectangleTextItemWidget
624//
625
626QgsAnnotationRectangleTextItemWidget::QgsAnnotationRectangleTextItemWidget( QWidget *parent )
628{
629 setupUi( this );
630
631 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
632 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
633 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
634
637
638
639 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
640 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
641 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
642 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
643 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
644 mFrameSymbolButton->registerExpressionContextGenerator( this );
645
646 mSpinBottomMargin->setClearValue( 0 );
647 mSpinTopMargin->setClearValue( 0 );
648 mSpinRightMargin->setClearValue( 0 );
649 mSpinLeftMargin->setClearValue( 0 );
652
653 mTextFormatWidget = new QgsTextFormatWidget();
654 QVBoxLayout *vLayout = new QVBoxLayout();
655 vLayout->setContentsMargins( 0, 0, 0, 0 );
656 vLayout->addWidget( mTextFormatWidget );
657 mTextFormatWidgetContainer->setLayout( vLayout );
658
659 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
660 mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 );
661
662 mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight | Qt::AlignJustify );
663 mVerticalAlignmentComboBox->setAvailableAlignments( Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom );
664
665 mTextFormatWidget->setDockMode( dockMode() );
666 connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [this]
667 {
668 mTextEdit->setMode(
669 mTextFormatWidget->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText
670 );
671
672 onWidgetChanged();
673 } );
674 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
675 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked );
676 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
677 connect( mAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
678 connect( mVerticalAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
679 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
680 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
681 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
682 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
683 connect( mSpinTopMargin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
684 connect( mSpinRightMargin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
685 connect( mSpinLeftMargin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
686 connect( mSpinBottomMargin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
687 connect( mMarginUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
688
689 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
690
691 connect( mWidthSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setWidth );
692 connect( mHeightSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setHeight );
693
694 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationRectangleTextItemWidget::sizeModeChanged );
695 mWidgetFixedSize->hide();
696 sizeModeChanged();
697}
698
699QgsAnnotationItem *QgsAnnotationRectangleTextItemWidget::createItem()
700{
701 QgsAnnotationRectangleTextItem *newItem = mItem->clone();
702 updateItem( newItem );
703 return newItem;
704}
705
706void QgsAnnotationRectangleTextItemWidget::updateItem( QgsAnnotationItem *item )
707{
708 if ( QgsAnnotationRectangleTextItem *rectTextItem = dynamic_cast< QgsAnnotationRectangleTextItem * >( item ) )
709 {
710 mBlockChangedSignal = true;
711 rectTextItem->setFormat( mTextFormatWidget->format() );
712 rectTextItem->setText( mTextFormatWidget->format().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
713 rectTextItem->setAlignment( mAlignmentComboBox->currentAlignment() | mVerticalAlignmentComboBox->currentAlignment() );
714
715 rectTextItem->setPlacementMode( mSizeModeCombo->currentData().value< Qgis::AnnotationPlacementMode >() );
716
717 rectTextItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
718 rectTextItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
719
720 rectTextItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
721 rectTextItem->setFrameEnabled( mFrameCheckbox->isChecked() );
722 rectTextItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol< QgsFillSymbol >() );
723 rectTextItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol< QgsFillSymbol >() );
724
725 rectTextItem->setMargins( QgsMargins( mSpinLeftMargin->value(),
726 mSpinTopMargin->value(),
727 mSpinRightMargin->value(),
728 mSpinBottomMargin->value() ) );
729 rectTextItem->setMarginsUnit( mMarginUnitWidget->unit() );
730
731 if ( mUpdateItemPosition )
732 {
733 rectTextItem->setBounds( mItem->bounds() );
734 mUpdateItemPosition = false;
735 }
736
737 mBlockChangedSignal = false;
738
739 mPropertiesWidget->updateItem( rectTextItem );
740 }
741}
742
743void QgsAnnotationRectangleTextItemWidget::setDockMode( bool dockMode )
744{
746 if ( mTextFormatWidget )
747 mTextFormatWidget->setDockMode( dockMode );
748}
749
750void QgsAnnotationRectangleTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
751{
753 if ( mTextFormatWidget )
754 mTextFormatWidget->setContext( context );
755 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
756 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
757 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
758 mFrameSymbolButton->setMessageBar( context.messageBar() );
759 mPropertiesWidget->setContext( context );
760}
761
762QgsExpressionContext QgsAnnotationRectangleTextItemWidget::createExpressionContext() const
763{
764 QgsExpressionContext expressionContext;
765 if ( context().expressionContext() )
766 expressionContext = *( context().expressionContext() );
767 else
768 expressionContext = QgsProject::instance()->createExpressionContext();
769 return expressionContext;
770}
771
772void QgsAnnotationRectangleTextItemWidget::focusDefaultWidget()
773{
774 mTextEdit->textEdit()->selectAll();
775 mTextEdit->setFocus();
776}
777
778QgsAnnotationRectangleTextItemWidget::~QgsAnnotationRectangleTextItemWidget() = default;
779
780bool QgsAnnotationRectangleTextItemWidget::setNewItem( QgsAnnotationItem *item )
781{
782 QgsAnnotationRectangleTextItem *textItem = dynamic_cast< QgsAnnotationRectangleTextItem * >( item );
783 if ( !textItem )
784 return false;
785
786 mItem.reset( textItem->clone() );
787
788 mBlockChangedSignal = true;
789 mTextFormatWidget->setFormat( mItem->format() );
790 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
791 mTextEdit->setText( mItem->text() );
792 mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask );
793 mVerticalAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignVertical_Mask );
794 mPropertiesWidget->setItem( mItem.get() );
795
796 mBackgroundCheckbox->setChecked( textItem->backgroundEnabled() );
797 if ( const QgsSymbol *symbol = textItem->backgroundSymbol() )
798 mBackgroundSymbolButton->setSymbol( symbol->clone() );
799
800 mFrameCheckbox->setChecked( textItem->frameEnabled() );
801 if ( const QgsSymbol *symbol = textItem->frameSymbol() )
802 mFrameSymbolButton->setSymbol( symbol->clone() );
803
804 mMarginUnitWidget->setUnit( textItem->marginsUnit() );
805 mSpinLeftMargin->setValue( textItem->margins().left() );
806 mSpinTopMargin->setValue( textItem->margins().top() );
807 mSpinRightMargin->setValue( textItem->margins().right() );
808 mSpinBottomMargin->setValue( textItem->margins().bottom() );
809
810 mWidthSpinBox->setValue( textItem->fixedSize().width() );
811 mHeightSpinBox->setValue( textItem->fixedSize().height() );
812 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( textItem->placementMode() ) ) );
813
814 mBlockChangedSignal = false;
815
816 return true;
817}
818
819void QgsAnnotationRectangleTextItemWidget::onWidgetChanged()
820{
821 if ( !mBlockChangedSignal )
822 emit itemChanged();
823}
824
825void QgsAnnotationRectangleTextItemWidget::sizeModeChanged()
826{
827 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value< Qgis::AnnotationPlacementMode >();
828 switch ( mode )
829 {
831 mWidgetFixedSize->hide();
832 break;
833
835 mWidgetFixedSize->show();
836 break;
837
839 {
840 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
841 {
842 // convert item bounds to relative position
843 const QgsRectangle itemBounds = details->boundingBox();
844 if ( QgsMapCanvas *canvas = context().mapCanvas() )
845 {
846 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
847 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
848 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
849 mUpdateItemPosition = true;
850 }
851 }
852
853 mWidgetFixedSize->hide();
854 break;
855 }
856 }
857
858 onWidgetChanged();
859}
860
861void QgsAnnotationRectangleTextItemWidget::setWidth()
862{
863 onWidgetChanged();
864}
865
866void QgsAnnotationRectangleTextItemWidget::setHeight()
867{
868 onWidgetChanged();
869}
870
871void QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked()
872{
873 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
874
875 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, QStringLiteral( "generic" ), createExpressionContext() );
876
877 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
878 if ( exprDlg.exec() == QDialog::Accepted )
879 {
880 expression = exprDlg.expressionText().trimmed();
881 if ( !expression.isEmpty() )
882 {
883 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
884 }
885 }
886}
887
888
889//
890// QgsAnnotationPictureItemWidget
891//
892
893QgsAnnotationPictureItemWidget::QgsAnnotationPictureItemWidget( QWidget *parent )
895{
896 setupUi( this );
897
898 mSizeStackedWidget->setSizeMode( QgsStackedWidget::SizeMode::CurrentPageOnly );
899
900 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
901 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
902 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
903
906
907 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
908 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
909 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
910 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
911 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
912 mFrameSymbolButton->registerExpressionContextGenerator( this );
913
914 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
915 {
916 if ( !mBlockChangedSignal )
917 emit itemChanged();
918 } );
919
920 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationPictureItemWidget::sizeModeChanged );
921
922 connect( mRadioSVG, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
923 connect( mRadioRaster, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
924 connect( mSourceLineEdit, &QgsPictureSourceLineEditBase::sourceChanged, this, [ = ]( const QString & source )
925 {
926 if ( !mRadioSVG->isChecked() && QFileInfo( source ).suffix().compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
927 {
928 mRadioSVG->setChecked( true );
929 }
930
931 onWidgetChanged();
932 } );
933
934 connect( mLockAspectRatioCheck, &QCheckBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
935 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
936 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
937 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
938 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
939 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
940
941 connect( mWidthSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setWidth );
942 connect( mHeightSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setHeight );
943 connect( mLockAspectRatio, &QgsRatioLockButton::lockChanged, this, &QgsAnnotationPictureItemWidget::setLockAspectRatio );
944}
945
946QgsAnnotationPictureItemWidget::~QgsAnnotationPictureItemWidget() = default;
947
948QgsAnnotationItem *QgsAnnotationPictureItemWidget::createItem()
949{
950 QgsAnnotationPictureItem *newItem = mItem->clone();
951 updateItem( newItem );
952 return newItem;
953}
954
955void QgsAnnotationPictureItemWidget::updateItem( QgsAnnotationItem *item )
956{
957 if ( QgsAnnotationPictureItem *pictureItem = dynamic_cast< QgsAnnotationPictureItem * >( item ) )
958 {
959 const bool svg = mRadioSVG->isChecked();
961 const QString path = mSourceLineEdit->source();
962 pictureItem->setPath( newFormat, path );
963
964 pictureItem->setPlacementMode( mSizeModeCombo->currentData().value< Qgis::AnnotationPlacementMode >() );
965 switch ( pictureItem->placementMode() )
966 {
968 pictureItem->setLockAspectRatio( mLockAspectRatioCheck->isChecked() );
969 break;
972 pictureItem->setLockAspectRatio( mLockAspectRatio->isChecked() );
973 break;
974 }
975
976 pictureItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
977 pictureItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
978
979 pictureItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
980 pictureItem->setFrameEnabled( mFrameCheckbox->isChecked() );
981 pictureItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol< QgsFillSymbol >() );
982 pictureItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol< QgsFillSymbol >() );
983
984 if ( mUpdateItemPosition )
985 {
986 pictureItem->setBounds( mItem->bounds() );
987 mUpdateItemPosition = false;
988 }
989
990 mPropertiesWidget->updateItem( pictureItem );
991 }
992}
993
994void QgsAnnotationPictureItemWidget::setDockMode( bool dockMode )
995{
997}
998
999void QgsAnnotationPictureItemWidget::setContext( const QgsSymbolWidgetContext &context )
1000{
1002 mPropertiesWidget->setContext( context );
1003 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
1004 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
1005 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
1006 mFrameSymbolButton->setMessageBar( context.messageBar() );
1007}
1008
1009QgsExpressionContext QgsAnnotationPictureItemWidget::createExpressionContext() const
1010{
1011 QgsExpressionContext expressionContext;
1012 if ( context().expressionContext() )
1013 expressionContext = *( context().expressionContext() );
1014 else
1015 expressionContext = QgsProject::instance()->createExpressionContext();
1016 return expressionContext;
1017}
1018
1019void QgsAnnotationPictureItemWidget::focusDefaultWidget()
1020{
1021 mSourceLineEdit->setFocus();
1022}
1023
1024bool QgsAnnotationPictureItemWidget::setNewItem( QgsAnnotationItem *item )
1025{
1026 QgsAnnotationPictureItem *pictureItem = dynamic_cast< QgsAnnotationPictureItem * >( item );
1027 if ( !pictureItem )
1028 return false;
1029
1030 mItem.reset( pictureItem->clone() );
1031
1032 mBlockChangedSignal = true;
1033 mPropertiesWidget->setItem( mItem.get() );
1034
1035 mLockAspectRatioCheck->setChecked( mItem->lockAspectRatio() );
1036 mLockAspectRatio->setLocked( mItem->lockAspectRatio() );
1037 switch ( pictureItem->format() )
1038 {
1040 mRadioSVG->setChecked( true );
1041 break;
1043 mRadioRaster->setChecked( true );
1044 break;
1046 break;
1047 }
1048
1049 mSourceLineEdit->setSource( pictureItem->path() );
1050
1051 mBackgroundCheckbox->setChecked( pictureItem->backgroundEnabled() );
1052 if ( const QgsSymbol *symbol = pictureItem->backgroundSymbol() )
1053 mBackgroundSymbolButton->setSymbol( symbol->clone() );
1054
1055 mFrameCheckbox->setChecked( pictureItem->frameEnabled() );
1056 if ( const QgsSymbol *symbol = pictureItem->frameSymbol() )
1057 mFrameSymbolButton->setSymbol( symbol->clone() );
1058
1059 mWidthSpinBox->setValue( pictureItem->fixedSize().width() );
1060 mHeightSpinBox->setValue( pictureItem->fixedSize().height() );
1061 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( pictureItem->placementMode() ) ) );
1062 sizeModeChanged();
1063
1064 mBlockChangedSignal = false;
1065
1066 return true;
1067}
1068
1069void QgsAnnotationPictureItemWidget::onWidgetChanged()
1070{
1071 if ( !mBlockChangedSignal )
1072 emit itemChanged();
1073}
1074
1075void QgsAnnotationPictureItemWidget::modeChanged( bool checked )
1076{
1077 if ( !checked )
1078 return;
1079
1080 const bool svg = mRadioSVG->isChecked();
1081
1082 if ( svg )
1083 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Svg );
1084 else
1085 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Image );
1086
1087 onWidgetChanged();
1088}
1089
1090void QgsAnnotationPictureItemWidget::sizeModeChanged()
1091{
1092 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value< Qgis::AnnotationPlacementMode >();
1093 switch ( mode )
1094 {
1096 mSizeStackedWidget->setCurrentWidget( mPageSpatialBounds );
1097 break;
1098
1100 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1101 break;
1102
1104 {
1105 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
1106 {
1107 // convert item bounds to relative position
1108 const QgsRectangle itemBounds = details->boundingBox();
1109 if ( QgsMapCanvas *canvas = context().mapCanvas() )
1110 {
1111 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
1112 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
1113 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
1114 mUpdateItemPosition = true;
1115 }
1116 }
1117
1118 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1119 break;
1120 }
1121 }
1122
1123 onWidgetChanged();
1124}
1125
1126void QgsAnnotationPictureItemWidget::setWidth()
1127{
1128 if ( mLockAspectRatio->locked() )
1129 {
1130 const double ratio = pictureAspectRatio();
1131 if ( ratio > 0 )
1132 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1133 }
1134
1135 onWidgetChanged();
1136}
1137
1138void QgsAnnotationPictureItemWidget::setHeight()
1139{
1140 if ( mLockAspectRatio->locked() )
1141 {
1142 const double ratio = pictureAspectRatio();
1143 if ( ratio > 0 )
1144 whileBlocking( mWidthSpinBox )->setValue( mHeightSpinBox->value() / ratio );
1145 }
1146
1147 onWidgetChanged();
1148}
1149
1150void QgsAnnotationPictureItemWidget::setLockAspectRatio( bool locked )
1151{
1152 if ( locked && !mBlockChangedSignal )
1153 {
1154 const double ratio = pictureAspectRatio();
1155 if ( ratio > 0 )
1156 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1157 }
1158
1159 onWidgetChanged();
1160}
1161
1162double QgsAnnotationPictureItemWidget::pictureAspectRatio() const
1163{
1164 const bool svg = mRadioSVG->isChecked();
1165 const QString path = mSourceLineEdit->source();
1166 QSizeF size;
1167 if ( svg )
1168 {
1169 size = QgsApplication::svgCache()->svgViewboxSize( path, 100, QColor(), QColor(), 1, 1 );
1170 }
1171 else
1172 {
1173 size = QgsApplication::imageCache()->originalSize( path );
1174 }
1175 if ( size.isValid() && size.width() > 0 )
1176 return size.height() / size.width();
1177
1178 return 0;
1179}
1180
1182
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:4901
@ 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.
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.
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:146
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:5862