QGIS API Documentation 4.3.0-Master (621ced71bd7)
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 mAlignmentCombo->addItem( tr( "Start of Line" ), QVariant::fromValue( Qgis::TextAnchorPoint::StartOfText ) );
465 mAlignmentCombo->addItem( tr( "Center of Line" ), QVariant::fromValue( Qgis::TextAnchorPoint::CenterOfText ) );
466 mAlignmentCombo->addItem( tr( "End of Line" ), QVariant::fromValue( Qgis::TextAnchorPoint::EndOfText ) );
467
468 connect( mTextFormatButton, &QgsFontButton::changed, this, [this] {
469 mTextEdit->setMode( mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
470
471 if ( !mBlockChangedSignal )
472 emit itemChanged();
473 } );
474 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, [this] {
475 if ( !mBlockChangedSignal )
476 emit itemChanged();
477 } );
478 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked );
479 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
480 if ( !mBlockChangedSignal )
481 emit itemChanged();
482 } );
483
484 mOffsetUnitWidget->setUnits(
486 );
487 mSpinOffset->setClearValue( 0.0 );
488 connect( mSpinOffset, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, [this] {
489 if ( !mBlockChangedSignal )
490 emit itemChanged();
491 } );
492
493 connect( mOffsetUnitWidget, &QgsUnitSelectionWidget::changed, this, [this] {
494 if ( !mBlockChangedSignal )
495 emit itemChanged();
496 } );
497
498 connect( mAlignmentCombo, qOverload< int >( &QComboBox::currentIndexChanged ), this, [this] {
499 if ( !mBlockChangedSignal )
500 emit itemChanged();
501 } );
502}
503
504QgsAnnotationLineTextItemWidget::~QgsAnnotationLineTextItemWidget() = default;
505
506QgsAnnotationItem *QgsAnnotationLineTextItemWidget::createItem()
507{
508 QgsAnnotationLineTextItem *newItem = mItem->clone();
509 updateItem( newItem );
510 return newItem;
511}
512
513void QgsAnnotationLineTextItemWidget::updateItem( QgsAnnotationItem *item )
514{
515 if ( QgsAnnotationLineTextItem *lineTextItem = dynamic_cast<QgsAnnotationLineTextItem *>( item ) )
516 {
517 mBlockChangedSignal = true;
518 lineTextItem->setFormat( mTextFormatButton->textFormat() );
519 lineTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
520
521 lineTextItem->setOffsetFromLine( mSpinOffset->value() );
522 lineTextItem->setOffsetFromLineUnit( mOffsetUnitWidget->unit() );
523 lineTextItem->setOffsetFromLineMapUnitScale( mOffsetUnitWidget->getMapUnitScale() );
524
525 lineTextItem->setTextAnchor( mAlignmentCombo->currentData().value< Qgis::TextAnchorPoint >() );
526
527 mBlockChangedSignal = false;
528 mPropertiesWidget->updateItem( lineTextItem );
529 }
530}
531
532void QgsAnnotationLineTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
533{
535 if ( mTextFormatButton )
536 {
537 mTextFormatButton->setMapCanvas( context.mapCanvas() );
538 mTextFormatButton->setMessageBar( context.messageBar() );
539 }
540 mPropertiesWidget->setContext( context );
541}
542
543void QgsAnnotationLineTextItemWidget::focusDefaultWidget()
544{
545 mTextEdit->textEdit()->selectAll();
546 mTextEdit->setFocus();
547}
548
549bool QgsAnnotationLineTextItemWidget::setNewItem( QgsAnnotationItem *item )
550{
551 QgsAnnotationLineTextItem *textItem = dynamic_cast<QgsAnnotationLineTextItem *>( item );
552 if ( !textItem )
553 return false;
554
555 mItem.reset( textItem->clone() );
556
557 mBlockChangedSignal = true;
558 mTextFormatButton->setTextFormat( mItem->format() );
559 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
560 mTextEdit->setText( mItem->text() );
561 mPropertiesWidget->setItem( mItem.get() );
562
563 mSpinOffset->setValue( mItem->offsetFromLine() );
564 mOffsetUnitWidget->setUnit( mItem->offsetFromLineUnit() );
565 mOffsetUnitWidget->setMapUnitScale( mItem->offsetFromLineMapUnitScale() );
566
567 mAlignmentCombo->setCurrentIndex( mAlignmentCombo->findData( QVariant::fromValue( mItem->textAnchor() ) ) );
568
569 mBlockChangedSignal = false;
570
571 return true;
572}
573
574void QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked()
575{
576 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
577
578 QgsExpressionContext expressionContext;
579 if ( context().expressionContext() )
580 expressionContext = *( context().expressionContext() );
581 else
582 expressionContext = QgsProject::instance()->createExpressionContext();
583
584 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, u"generic"_s, expressionContext );
585
586 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
587 if ( exprDlg.exec() == QDialog::Accepted )
588 {
589 expression = exprDlg.expressionText().trimmed();
590 if ( !expression.isEmpty() )
591 {
592 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
593 }
594 }
595}
596
597
598//
599// QgsAnnotationRectangleTextItemWidget
600//
601
602QgsAnnotationRectangleTextItemWidget::QgsAnnotationRectangleTextItemWidget( QWidget *parent )
604{
605 setupUi( this );
606
607 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
608 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
609 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
610
611 mSizeUnitWidget->setUnits(
613 );
614
615 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
616 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
617 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
618 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
619 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
620 mFrameSymbolButton->registerExpressionContextGenerator( this );
621
622 mSpinBottomMargin->setClearValue( 0 );
623 mSpinTopMargin->setClearValue( 0 );
624 mSpinRightMargin->setClearValue( 0 );
625 mSpinLeftMargin->setClearValue( 0 );
626 mMarginUnitWidget->setUnits(
628 );
629
630 mTextFormatButton->setMode( QgsFontButton::ModeTextRenderer );
631
632 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
633
634 mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight | Qt::AlignJustify );
635 mVerticalAlignmentComboBox->setAvailableAlignments( Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom );
636
637 connect( mTextFormatButton, &QgsFontButton::changed, this, [this] {
638 mTextEdit->setMode( mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
639
640 onWidgetChanged();
641 } );
642 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
643 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked );
644 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
645 connect( mAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
646 connect( mVerticalAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
647 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
648 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
649 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
650 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
651 connect( mSpinTopMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
652 connect( mSpinRightMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
653 connect( mSpinLeftMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
654 connect( mSpinBottomMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
655 connect( mMarginUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
656
657 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
658
659 connect( mWidthSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setWidth );
660 connect( mHeightSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setHeight );
661
662 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationRectangleTextItemWidget::sizeModeChanged );
663 mWidgetFixedSize->hide();
664 sizeModeChanged();
665}
666
667QgsAnnotationItem *QgsAnnotationRectangleTextItemWidget::createItem()
668{
669 QgsAnnotationRectangleTextItem *newItem = mItem->clone();
670 updateItem( newItem );
671 return newItem;
672}
673
674void QgsAnnotationRectangleTextItemWidget::updateItem( QgsAnnotationItem *item )
675{
676 if ( QgsAnnotationRectangleTextItem *rectTextItem = dynamic_cast<QgsAnnotationRectangleTextItem *>( item ) )
677 {
678 mBlockChangedSignal = true;
679 rectTextItem->setFormat( mTextFormatButton->textFormat() );
680 rectTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
681 rectTextItem->setAlignment( mAlignmentComboBox->currentAlignment() | mVerticalAlignmentComboBox->currentAlignment() );
682
683 rectTextItem->setPlacementMode( mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>() );
684
685 rectTextItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
686 rectTextItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
687
688 rectTextItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
689 rectTextItem->setFrameEnabled( mFrameCheckbox->isChecked() );
690 rectTextItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol<QgsFillSymbol>() );
691 rectTextItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol<QgsFillSymbol>() );
692
693 rectTextItem->setMargins( QgsMargins( mSpinLeftMargin->value(), mSpinTopMargin->value(), mSpinRightMargin->value(), mSpinBottomMargin->value() ) );
694 rectTextItem->setMarginsUnit( mMarginUnitWidget->unit() );
695
696 if ( mUpdateItemPosition )
697 {
698 rectTextItem->setBounds( mItem->bounds() );
699 mUpdateItemPosition = false;
700 }
701
702 mBlockChangedSignal = false;
703
704 mPropertiesWidget->updateItem( rectTextItem );
705 }
706}
707
708void QgsAnnotationRectangleTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
709{
711 if ( mTextFormatButton )
712 {
713 mTextFormatButton->setMapCanvas( context.mapCanvas() );
714 mTextFormatButton->setMessageBar( context.messageBar() );
715 }
716 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
717 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
718 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
719 mFrameSymbolButton->setMessageBar( context.messageBar() );
720 mPropertiesWidget->setContext( context );
721}
722
723QgsExpressionContext QgsAnnotationRectangleTextItemWidget::createExpressionContext() const
724{
725 QgsExpressionContext expressionContext;
726 if ( context().expressionContext() )
727 expressionContext = *( context().expressionContext() );
728 else
729 expressionContext = QgsProject::instance()->createExpressionContext();
730 return expressionContext;
731}
732
733void QgsAnnotationRectangleTextItemWidget::focusDefaultWidget()
734{
735 mTextEdit->textEdit()->selectAll();
736 mTextEdit->setFocus();
737}
738
739QgsAnnotationRectangleTextItemWidget::~QgsAnnotationRectangleTextItemWidget() = default;
740
741bool QgsAnnotationRectangleTextItemWidget::setNewItem( QgsAnnotationItem *item )
742{
743 QgsAnnotationRectangleTextItem *textItem = dynamic_cast<QgsAnnotationRectangleTextItem *>( item );
744 if ( !textItem )
745 return false;
746
747 mItem.reset( textItem->clone() );
748
749 mBlockChangedSignal = true;
750 mTextFormatButton->setTextFormat( mItem->format() );
751 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
752 mTextEdit->setText( mItem->text() );
753 mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask );
754 mVerticalAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignVertical_Mask );
755 mPropertiesWidget->setItem( mItem.get() );
756
757 mBackgroundCheckbox->setChecked( textItem->backgroundEnabled() );
758 if ( const QgsSymbol *symbol = textItem->backgroundSymbol() )
759 mBackgroundSymbolButton->setSymbol( symbol->clone() );
760
761 mFrameCheckbox->setChecked( textItem->frameEnabled() );
762 if ( const QgsSymbol *symbol = textItem->frameSymbol() )
763 mFrameSymbolButton->setSymbol( symbol->clone() );
764
765 mMarginUnitWidget->setUnit( textItem->marginsUnit() );
766 mSpinLeftMargin->setValue( textItem->margins().left() );
767 mSpinTopMargin->setValue( textItem->margins().top() );
768 mSpinRightMargin->setValue( textItem->margins().right() );
769 mSpinBottomMargin->setValue( textItem->margins().bottom() );
770
771 mWidthSpinBox->setValue( textItem->fixedSize().width() );
772 mHeightSpinBox->setValue( textItem->fixedSize().height() );
773 mSizeUnitWidget->setUnit( textItem->fixedSizeUnit() );
774 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( textItem->placementMode() ) ) );
775
776 mBlockChangedSignal = false;
777
778 return true;
779}
780
781void QgsAnnotationRectangleTextItemWidget::onWidgetChanged()
782{
783 if ( !mBlockChangedSignal )
784 emit itemChanged();
785}
786
787void QgsAnnotationRectangleTextItemWidget::sizeModeChanged()
788{
789 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>();
790 switch ( mode )
791 {
793 mWidgetFixedSize->hide();
794 break;
795
797 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
798 {
799 const QgsRectangle itemBoundsMapUnits = details->boundingBox();
800 if ( QgsMapCanvas *canvas = context().mapCanvas() )
801 {
802 const QgsPointXY topLeftPixels = canvas->mapSettings().mapToPixel().transform( itemBoundsMapUnits.xMinimum(), itemBoundsMapUnits.yMinimum() );
803 const QgsPointXY bottomRightPixels = canvas->mapSettings().mapToPixel().transform( itemBoundsMapUnits.xMaximum(), itemBoundsMapUnits.yMaximum() );
804 const double widthPixels = std::abs( bottomRightPixels.x() - topLeftPixels.x() );
805 const double heightPixels = std::abs( bottomRightPixels.y() - topLeftPixels.y() );
806
807 // convert width/height in pixels to mm
808 const double pixelsPerMm = canvas->mapSettings().outputDpi() / 25.4;
809 mItem->setFixedSizeUnit( Qgis::RenderUnit::Millimeters );
810 mItem->setFixedSize( QSizeF( widthPixels / pixelsPerMm, heightPixels / pixelsPerMm ) );
811
812 // and update widget UI accordingly
813 whileBlocking( mWidthSpinBox )->setValue( mItem->fixedSize().width() );
814 whileBlocking( mHeightSpinBox )->setValue( mItem->fixedSize().height() );
815 whileBlocking( mSizeUnitWidget )->setUnit( mItem->fixedSizeUnit() );
816
817 mUpdateItemPosition = true;
818 }
819 }
820
821 mWidgetFixedSize->show();
822 break;
823
825 {
826 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
827 {
828 // convert item bounds to relative position
829 const QgsRectangle itemBounds = details->boundingBox();
830 if ( QgsMapCanvas *canvas = context().mapCanvas() )
831 {
832 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
833 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
834 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
835 mUpdateItemPosition = true;
836 }
837 }
838
839 mWidgetFixedSize->hide();
840 break;
841 }
842 }
843
844 onWidgetChanged();
845}
846
847void QgsAnnotationRectangleTextItemWidget::setWidth()
848{
849 onWidgetChanged();
850}
851
852void QgsAnnotationRectangleTextItemWidget::setHeight()
853{
854 onWidgetChanged();
855}
856
857void QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked()
858{
859 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
860
861 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, u"generic"_s, createExpressionContext() );
862
863 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
864 if ( exprDlg.exec() == QDialog::Accepted )
865 {
866 expression = exprDlg.expressionText().trimmed();
867 if ( !expression.isEmpty() )
868 {
869 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
870 }
871 }
872}
873
874
875//
876// QgsAnnotationPictureItemWidget
877//
878
879QgsAnnotationPictureItemWidget::QgsAnnotationPictureItemWidget( QWidget *parent )
881{
882 setupUi( this );
883
884 mSizeStackedWidget->setSizeMode( QgsStackedWidget::SizeMode::CurrentPageOnly );
885
886 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
887 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
888 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
889
890 mSizeUnitWidget->setUnits(
892 );
893
894 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
895 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
896 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
897 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
898 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
899 mFrameSymbolButton->registerExpressionContextGenerator( this );
900
901 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
902 if ( !mBlockChangedSignal )
903 emit itemChanged();
904 } );
905
906 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationPictureItemWidget::sizeModeChanged );
907
908 connect( mRadioSVG, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
909 connect( mRadioRaster, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
910 connect( mSourceLineEdit, &QgsPictureSourceLineEditBase::sourceChanged, this, [this]( const QString &source ) {
911 if ( !mRadioSVG->isChecked() && QFileInfo( source ).suffix().compare( "svg"_L1, Qt::CaseInsensitive ) == 0 )
912 {
913 mRadioSVG->setChecked( true );
914 }
915
916 onWidgetChanged();
917 } );
918
919 connect( mLockAspectRatioCheck, &QCheckBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
920 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
921 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
922 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
923 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
924 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
925
926 connect( mWidthSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setWidth );
927 connect( mHeightSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setHeight );
928 connect( mLockAspectRatio, &QgsRatioLockButton::lockChanged, this, &QgsAnnotationPictureItemWidget::setLockAspectRatio );
929}
930
931QgsAnnotationPictureItemWidget::~QgsAnnotationPictureItemWidget() = default;
932
933QgsAnnotationItem *QgsAnnotationPictureItemWidget::createItem()
934{
935 QgsAnnotationPictureItem *newItem = mItem->clone();
936 updateItem( newItem );
937 return newItem;
938}
939
940void QgsAnnotationPictureItemWidget::updateItem( QgsAnnotationItem *item )
941{
942 if ( QgsAnnotationPictureItem *pictureItem = dynamic_cast<QgsAnnotationPictureItem *>( item ) )
943 {
944 const bool svg = mRadioSVG->isChecked();
946 const QString path = mSourceLineEdit->source();
947 pictureItem->setPath( newFormat, path );
948
949 pictureItem->setPlacementMode( mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>() );
950 switch ( pictureItem->placementMode() )
951 {
953 pictureItem->setLockAspectRatio( mLockAspectRatioCheck->isChecked() );
954 break;
957 pictureItem->setLockAspectRatio( mLockAspectRatio->isChecked() );
958 break;
959 }
960
961 pictureItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
962 pictureItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
963
964 pictureItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
965 pictureItem->setFrameEnabled( mFrameCheckbox->isChecked() );
966 pictureItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol<QgsFillSymbol>() );
967 pictureItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol<QgsFillSymbol>() );
968
969 if ( mUpdateItemPosition )
970 {
971 pictureItem->setBounds( mItem->bounds() );
972 mUpdateItemPosition = false;
973 }
974
975 mPropertiesWidget->updateItem( pictureItem );
976 }
977}
978
979void QgsAnnotationPictureItemWidget::setDockMode( bool dockMode )
980{
982}
983
984void QgsAnnotationPictureItemWidget::setContext( const QgsSymbolWidgetContext &context )
985{
987 mPropertiesWidget->setContext( context );
988 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
989 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
990 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
991 mFrameSymbolButton->setMessageBar( context.messageBar() );
992}
993
994QgsExpressionContext QgsAnnotationPictureItemWidget::createExpressionContext() const
995{
996 QgsExpressionContext expressionContext;
997 if ( context().expressionContext() )
998 expressionContext = *( context().expressionContext() );
999 else
1000 expressionContext = QgsProject::instance()->createExpressionContext();
1001 return expressionContext;
1002}
1003
1004void QgsAnnotationPictureItemWidget::focusDefaultWidget()
1005{
1006 mSourceLineEdit->setFocus();
1007}
1008
1009bool QgsAnnotationPictureItemWidget::setNewItem( QgsAnnotationItem *item )
1010{
1011 QgsAnnotationPictureItem *pictureItem = dynamic_cast<QgsAnnotationPictureItem *>( item );
1012 if ( !pictureItem )
1013 return false;
1014
1015 mItem.reset( pictureItem->clone() );
1016
1017 mBlockChangedSignal = true;
1018 mPropertiesWidget->setItem( mItem.get() );
1019
1020 mLockAspectRatioCheck->setChecked( mItem->lockAspectRatio() );
1021 mLockAspectRatio->setLocked( mItem->lockAspectRatio() );
1022 switch ( pictureItem->format() )
1023 {
1025 mRadioSVG->setChecked( true );
1026 break;
1028 mRadioRaster->setChecked( true );
1029 break;
1031 break;
1032 }
1033
1034 mSourceLineEdit->setSource( pictureItem->path() );
1035
1036 mBackgroundCheckbox->setChecked( pictureItem->backgroundEnabled() );
1037 if ( const QgsSymbol *symbol = pictureItem->backgroundSymbol() )
1038 mBackgroundSymbolButton->setSymbol( symbol->clone() );
1039
1040 mFrameCheckbox->setChecked( pictureItem->frameEnabled() );
1041 if ( const QgsSymbol *symbol = pictureItem->frameSymbol() )
1042 mFrameSymbolButton->setSymbol( symbol->clone() );
1043
1044 mWidthSpinBox->setValue( pictureItem->fixedSize().width() );
1045 mHeightSpinBox->setValue( pictureItem->fixedSize().height() );
1046 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( pictureItem->placementMode() ) ) );
1047 sizeModeChanged();
1048
1049 mBlockChangedSignal = false;
1050
1051 return true;
1052}
1053
1054void QgsAnnotationPictureItemWidget::onWidgetChanged()
1055{
1056 if ( !mBlockChangedSignal )
1057 emit itemChanged();
1058}
1059
1060void QgsAnnotationPictureItemWidget::modeChanged( bool checked )
1061{
1062 if ( !checked )
1063 return;
1064
1065 const bool svg = mRadioSVG->isChecked();
1066
1067 if ( svg )
1068 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Svg );
1069 else
1070 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Image );
1071
1072 onWidgetChanged();
1073}
1074
1075void QgsAnnotationPictureItemWidget::sizeModeChanged()
1076{
1077 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>();
1078 switch ( mode )
1079 {
1081 mSizeStackedWidget->setCurrentWidget( mPageSpatialBounds );
1082 break;
1083
1085 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1086 break;
1087
1089 {
1090 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
1091 {
1092 // convert item bounds to relative position
1093 const QgsRectangle itemBounds = details->boundingBox();
1094 if ( QgsMapCanvas *canvas = context().mapCanvas() )
1095 {
1096 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
1097 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
1098 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
1099 mUpdateItemPosition = true;
1100 }
1101 }
1102
1103 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1104 break;
1105 }
1106 }
1107
1108 onWidgetChanged();
1109}
1110
1111void QgsAnnotationPictureItemWidget::setWidth()
1112{
1113 if ( mLockAspectRatio->locked() )
1114 {
1115 const double ratio = pictureAspectRatio();
1116 if ( ratio > 0 )
1117 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1118 }
1119
1120 onWidgetChanged();
1121}
1122
1123void QgsAnnotationPictureItemWidget::setHeight()
1124{
1125 if ( mLockAspectRatio->locked() )
1126 {
1127 const double ratio = pictureAspectRatio();
1128 if ( ratio > 0 )
1129 whileBlocking( mWidthSpinBox )->setValue( mHeightSpinBox->value() / ratio );
1130 }
1131
1132 onWidgetChanged();
1133}
1134
1135void QgsAnnotationPictureItemWidget::setLockAspectRatio( bool locked )
1136{
1137 if ( locked && !mBlockChangedSignal )
1138 {
1139 const double ratio = pictureAspectRatio();
1140 if ( ratio > 0 )
1141 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1142 }
1143
1144 onWidgetChanged();
1145}
1146
1147double QgsAnnotationPictureItemWidget::pictureAspectRatio() const
1148{
1149 const bool svg = mRadioSVG->isChecked();
1150 const QString path = mSourceLineEdit->source();
1151 QSizeF size;
1152 if ( svg )
1153 {
1154 size = QgsApplication::svgCache()->svgViewboxSize( path, 100, QColor(), QColor(), 1, 1 );
1155 }
1156 else
1157 {
1158 size = QgsApplication::imageCache()->originalSize( path );
1159 }
1160 if ( size.isValid() && size.width() > 0 )
1161 return size.height() / size.width();
1162
1163 return 0;
1164}
1165
SymbolRotationMode
Modes for handling how symbol and text entity rotation is handled when maps are rotated.
Definition qgis.h:848
@ RespectMapRotation
Entity is rotated along with the map.
Definition qgis.h:849
@ IgnoreMapRotation
Entity ignores map rotation.
Definition qgis.h:850
TextAnchorPoint
Anchor point of label text.
Definition qgis.h:1475
@ EndOfText
Anchor using end of text.
Definition qgis.h:1478
@ StartOfText
Anchor using start of text.
Definition qgis.h:1476
@ CenterOfText
Anchor using center of text.
Definition qgis.h:1477
PictureFormat
Picture formats.
Definition qgis.h:5749
@ Raster
Raster image.
Definition qgis.h:5751
@ Unknown
Invalid or unknown image type.
Definition qgis.h:5752
@ SVG
SVG image.
Definition qgis.h:5750
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size).
Definition qgis.h:5659
@ Millimeters
Millimeters.
Definition qgis.h:5656
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5660
@ MapUnits
Map units.
Definition qgis.h:5657
@ Pixels
Pixels.
Definition qgis.h:5658
@ Inches
Inches.
Definition qgis.h:5661
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5663
@ Fill
Fill symbol.
Definition qgis.h:654
AnnotationPlacementMode
Annotation item placement modes.
Definition qgis.h:2667
@ SpatialBounds
Item is rendered inside fixed spatial bounds, and size will depend on map scale.
Definition qgis.h:2668
@ FixedSize
Item is rendered at a fixed size, regardless of map scale. Item's location is georeferenced to a spat...
Definition qgis.h:2669
@ RelativeToMapFrame
Items size and placement is relative to the map's frame, and the item will always be rendered in the ...
Definition qgis.h:2670
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:164
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:7356