QGIS API Documentation 4.3.0-Master (6e9a7aceb6d)
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 populateRotationModeComboBox( mRotationModeCombo );
329
330 mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
331
332 connect( mTextFormatButton, &QgsFontButton::changed, this, [this] {
333 mTextEdit->setMode( mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
334
335 if ( !mBlockChangedSignal )
336 emit itemChanged();
337 } );
338 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, [this] {
339 if ( !mBlockChangedSignal )
340 emit itemChanged();
341 } );
342 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked );
343 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
344 if ( !mBlockChangedSignal )
345 emit itemChanged();
346 } );
347
348 connect( mSpinTextAngle, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this] {
349 if ( !mBlockChangedSignal )
350 emit itemChanged();
351 } );
352
353 connect( mRotationModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this] {
354 if ( !mBlockChangedSignal )
355 emit itemChanged();
356 } );
357
358 connect( mAlignmentComboBox, &QgsAlignmentComboBox::changed, this, [this] {
359 if ( !mBlockChangedSignal )
360 emit itemChanged();
361 } );
362}
363
364QgsAnnotationItem *QgsAnnotationPointTextItemWidget::createItem()
365{
366 QgsAnnotationPointTextItem *newItem = mItem->clone();
367 updateItem( newItem );
368 return newItem;
369}
370
371void QgsAnnotationPointTextItemWidget::updateItem( QgsAnnotationItem *item )
372{
373 if ( QgsAnnotationPointTextItem *pointTextItem = dynamic_cast<QgsAnnotationPointTextItem *>( item ) )
374 {
375 mBlockChangedSignal = true;
376 pointTextItem->setFormat( mTextFormatButton->textFormat() );
377 pointTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
378 pointTextItem->setAngle( mSpinTextAngle->value() );
379 pointTextItem->setRotationMode( mRotationModeCombo->currentData().value<Qgis::SymbolRotationMode>() );
380 pointTextItem->setAlignment( mAlignmentComboBox->currentAlignment() );
381 mBlockChangedSignal = false;
382 mPropertiesWidget->updateItem( pointTextItem );
383 }
384}
385
386void QgsAnnotationPointTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
387{
389 if ( mTextFormatButton )
390 {
391 mTextFormatButton->setMapCanvas( context.mapCanvas() );
392 mTextFormatButton->setMessageBar( context.messageBar() );
393 }
394 mPropertiesWidget->setContext( context );
395}
396
397void QgsAnnotationPointTextItemWidget::focusDefaultWidget()
398{
399 mTextEdit->textEdit()->selectAll();
400 mTextEdit->setFocus();
401}
402
403QgsAnnotationPointTextItemWidget::~QgsAnnotationPointTextItemWidget() = default;
404
405bool QgsAnnotationPointTextItemWidget::setNewItem( QgsAnnotationItem *item )
406{
407 QgsAnnotationPointTextItem *textItem = dynamic_cast<QgsAnnotationPointTextItem *>( item );
408 if ( !textItem )
409 return false;
410
411 mItem.reset( textItem->clone() );
412
413 mBlockChangedSignal = true;
414 mTextFormatButton->setTextFormat( mItem->format() );
415 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
416 mTextEdit->setText( mItem->text() );
417 mSpinTextAngle->setValue( mItem->angle() );
418 mRotationModeCombo->setCurrentIndex( mRotationModeCombo->findData( QVariant::fromValue( mItem->rotationMode() ) ) );
419 mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask );
420 mPropertiesWidget->setItem( mItem.get() );
421 mBlockChangedSignal = false;
422
423 return true;
424}
425
426void QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked()
427{
428 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
429
430 QgsExpressionContext expressionContext;
431 if ( context().expressionContext() )
432 expressionContext = *( context().expressionContext() );
433 else
434 expressionContext = QgsProject::instance()->createExpressionContext();
435
436 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, u"generic"_s, expressionContext );
437
438 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
439 if ( exprDlg.exec() == QDialog::Accepted )
440 {
441 expression = exprDlg.expressionText().trimmed();
442 if ( !expression.isEmpty() )
443 {
444 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
445 }
446 }
447}
448
449
450//
451// QgsAnnotationLineTextItemWidget
452//
453
454QgsAnnotationLineTextItemWidget::QgsAnnotationLineTextItemWidget( QWidget *parent )
456{
457 setupUi( this );
458
459 mTextFormatButton->setMode( QgsFontButton::ModeTextRenderer );
460
461 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
462
463 mAlignmentCombo->addItem( tr( "Start of Line" ), QVariant::fromValue( Qgis::TextAnchorPoint::StartOfText ) );
464 mAlignmentCombo->addItem( tr( "Center of Line" ), QVariant::fromValue( Qgis::TextAnchorPoint::CenterOfText ) );
465 mAlignmentCombo->addItem( tr( "End of Line" ), QVariant::fromValue( Qgis::TextAnchorPoint::EndOfText ) );
466
467 connect( mTextFormatButton, &QgsFontButton::changed, this, [this] {
468 mTextEdit->setMode( mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
469
470 if ( !mBlockChangedSignal )
471 emit itemChanged();
472 } );
473 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, [this] {
474 if ( !mBlockChangedSignal )
475 emit itemChanged();
476 } );
477 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked );
478 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
479 if ( !mBlockChangedSignal )
480 emit itemChanged();
481 } );
482
483 mOffsetUnitWidget->setUnits(
485 );
486 mSpinOffset->setClearValue( 0.0 );
487 connect( mSpinOffset, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, [this] {
488 if ( !mBlockChangedSignal )
489 emit itemChanged();
490 } );
491
492 connect( mOffsetUnitWidget, &QgsUnitSelectionWidget::changed, this, [this] {
493 if ( !mBlockChangedSignal )
494 emit itemChanged();
495 } );
496
497 connect( mAlignmentCombo, qOverload< int >( &QComboBox::currentIndexChanged ), this, [this] {
498 if ( !mBlockChangedSignal )
499 emit itemChanged();
500 } );
501}
502
503QgsAnnotationLineTextItemWidget::~QgsAnnotationLineTextItemWidget() = default;
504
505QgsAnnotationItem *QgsAnnotationLineTextItemWidget::createItem()
506{
507 QgsAnnotationLineTextItem *newItem = mItem->clone();
508 updateItem( newItem );
509 return newItem;
510}
511
512void QgsAnnotationLineTextItemWidget::updateItem( QgsAnnotationItem *item )
513{
514 if ( QgsAnnotationLineTextItem *lineTextItem = dynamic_cast<QgsAnnotationLineTextItem *>( item ) )
515 {
516 mBlockChangedSignal = true;
517 lineTextItem->setFormat( mTextFormatButton->textFormat() );
518 lineTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
519
520 lineTextItem->setOffsetFromLine( mSpinOffset->value() );
521 lineTextItem->setOffsetFromLineUnit( mOffsetUnitWidget->unit() );
522 lineTextItem->setOffsetFromLineMapUnitScale( mOffsetUnitWidget->getMapUnitScale() );
523
524 lineTextItem->setTextAnchor( mAlignmentCombo->currentData().value< Qgis::TextAnchorPoint >() );
525
526 mBlockChangedSignal = false;
527 mPropertiesWidget->updateItem( lineTextItem );
528 }
529}
530
531void QgsAnnotationLineTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
532{
534 if ( mTextFormatButton )
535 {
536 mTextFormatButton->setMapCanvas( context.mapCanvas() );
537 mTextFormatButton->setMessageBar( context.messageBar() );
538 }
539 mPropertiesWidget->setContext( context );
540}
541
542void QgsAnnotationLineTextItemWidget::focusDefaultWidget()
543{
544 mTextEdit->textEdit()->selectAll();
545 mTextEdit->setFocus();
546}
547
548bool QgsAnnotationLineTextItemWidget::setNewItem( QgsAnnotationItem *item )
549{
550 QgsAnnotationLineTextItem *textItem = dynamic_cast<QgsAnnotationLineTextItem *>( item );
551 if ( !textItem )
552 return false;
553
554 mItem.reset( textItem->clone() );
555
556 mBlockChangedSignal = true;
557 mTextFormatButton->setTextFormat( mItem->format() );
558 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
559 mTextEdit->setText( mItem->text() );
560 mPropertiesWidget->setItem( mItem.get() );
561
562 mSpinOffset->setValue( mItem->offsetFromLine() );
563 mOffsetUnitWidget->setUnit( mItem->offsetFromLineUnit() );
564 mOffsetUnitWidget->setMapUnitScale( mItem->offsetFromLineMapUnitScale() );
565
566 mAlignmentCombo->setCurrentIndex( mAlignmentCombo->findData( QVariant::fromValue( mItem->textAnchor() ) ) );
567
568 mBlockChangedSignal = false;
569
570 return true;
571}
572
573void QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked()
574{
575 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
576
577 QgsExpressionContext expressionContext;
578 if ( context().expressionContext() )
579 expressionContext = *( context().expressionContext() );
580 else
581 expressionContext = QgsProject::instance()->createExpressionContext();
582
583 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, u"generic"_s, expressionContext );
584
585 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
586 if ( exprDlg.exec() == QDialog::Accepted )
587 {
588 expression = exprDlg.expressionText().trimmed();
589 if ( !expression.isEmpty() )
590 {
591 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
592 }
593 }
594}
595
596
597//
598// QgsAnnotationRectangleTextItemWidget
599//
600
601QgsAnnotationRectangleTextItemWidget::QgsAnnotationRectangleTextItemWidget( QWidget *parent )
603{
604 setupUi( this );
605
606 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
607 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
608 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
609
610 populateRotationModeComboBox( mRotationModeCombo );
611
612 mSizeUnitWidget->setUnits(
614 );
615
616 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
617 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
618 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
619 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
620 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
621 mFrameSymbolButton->registerExpressionContextGenerator( this );
622
623 mSpinBottomMargin->setClearValue( 0 );
624 mSpinTopMargin->setClearValue( 0 );
625 mSpinRightMargin->setClearValue( 0 );
626 mSpinLeftMargin->setClearValue( 0 );
627 mMarginUnitWidget->setUnits(
629 );
630
631 mTextFormatButton->setMode( QgsFontButton::ModeTextRenderer );
632
633 mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer );
634
635 mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight | Qt::AlignJustify );
636 mVerticalAlignmentComboBox->setAvailableAlignments( Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom );
637
638 connect( mTextFormatButton, &QgsFontButton::changed, this, [this] {
639 mTextEdit->setMode( mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
640
641 onWidgetChanged();
642 } );
643 connect( mTextEdit, &QgsRichTextEditor::textChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
644 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked );
645 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
646 connect( mAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
647 connect( mVerticalAlignmentComboBox, &QgsAlignmentComboBox::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
648 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
649 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
650 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
651 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
652 connect( mSpinTopMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
653 connect( mSpinRightMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
654 connect( mSpinLeftMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
655 connect( mSpinBottomMargin, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
656 connect( mMarginUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
657
658 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
659
660 connect( mWidthSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setWidth );
661 connect( mHeightSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::setHeight );
662
663 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationRectangleTextItemWidget::sizeModeChanged );
664 connect( mRotationModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
665 mSpinAngle->setClearValue( 0 );
666 connect( mSpinAngle, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsAnnotationRectangleTextItemWidget::onWidgetChanged );
667 mWidgetFixedSize->hide();
668 sizeModeChanged();
669}
670
671QgsAnnotationItem *QgsAnnotationRectangleTextItemWidget::createItem()
672{
673 QgsAnnotationRectangleTextItem *newItem = mItem->clone();
674 updateItem( newItem );
675 return newItem;
676}
677
678void QgsAnnotationRectangleTextItemWidget::updateItem( QgsAnnotationItem *item )
679{
680 if ( QgsAnnotationRectangleTextItem *rectTextItem = dynamic_cast<QgsAnnotationRectangleTextItem *>( item ) )
681 {
682 mBlockChangedSignal = true;
683 rectTextItem->setFormat( mTextFormatButton->textFormat() );
684 rectTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() );
685 rectTextItem->setAlignment( mAlignmentComboBox->currentAlignment() | mVerticalAlignmentComboBox->currentAlignment() );
686
687 rectTextItem->setPlacementMode( mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>() );
688
689 rectTextItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
690 rectTextItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
691
692 rectTextItem->setRotation( mSpinAngle->value() );
693 rectTextItem->setRotationMode( mRotationModeCombo->currentData().value<Qgis::SymbolRotationMode>() );
694
695 rectTextItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
696 rectTextItem->setFrameEnabled( mFrameCheckbox->isChecked() );
697 rectTextItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol<QgsFillSymbol>() );
698 rectTextItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol<QgsFillSymbol>() );
699
700 rectTextItem->setMargins( QgsMargins( mSpinLeftMargin->value(), mSpinTopMargin->value(), mSpinRightMargin->value(), mSpinBottomMargin->value() ) );
701 rectTextItem->setMarginsUnit( mMarginUnitWidget->unit() );
702
703 if ( mUpdateItemPosition )
704 {
705 rectTextItem->setBounds( mItem->bounds() );
706 mUpdateItemPosition = false;
707 }
708
709 mBlockChangedSignal = false;
710
711 mPropertiesWidget->updateItem( rectTextItem );
712 }
713}
714
715void QgsAnnotationRectangleTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
716{
718 if ( mTextFormatButton )
719 {
720 mTextFormatButton->setMapCanvas( context.mapCanvas() );
721 mTextFormatButton->setMessageBar( context.messageBar() );
722 }
723 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
724 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
725 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
726 mFrameSymbolButton->setMessageBar( context.messageBar() );
727 mPropertiesWidget->setContext( context );
728}
729
730QgsExpressionContext QgsAnnotationRectangleTextItemWidget::createExpressionContext() const
731{
732 QgsExpressionContext expressionContext;
733 if ( context().expressionContext() )
734 expressionContext = *( context().expressionContext() );
735 else
736 expressionContext = QgsProject::instance()->createExpressionContext();
737 return expressionContext;
738}
739
740void QgsAnnotationRectangleTextItemWidget::focusDefaultWidget()
741{
742 mTextEdit->textEdit()->selectAll();
743 mTextEdit->setFocus();
744}
745
746QgsAnnotationRectangleTextItemWidget::~QgsAnnotationRectangleTextItemWidget() = default;
747
748bool QgsAnnotationRectangleTextItemWidget::setNewItem( QgsAnnotationItem *item )
749{
750 QgsAnnotationRectangleTextItem *textItem = dynamic_cast<QgsAnnotationRectangleTextItem *>( item );
751 if ( !textItem )
752 return false;
753
754 mItem.reset( textItem->clone() );
755
756 mBlockChangedSignal = true;
757 mTextFormatButton->setTextFormat( mItem->format() );
758 mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText );
759 mTextEdit->setText( mItem->text() );
760 mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask );
761 mVerticalAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignVertical_Mask );
762 mPropertiesWidget->setItem( mItem.get() );
763
764 mBackgroundCheckbox->setChecked( textItem->backgroundEnabled() );
765 if ( const QgsSymbol *symbol = textItem->backgroundSymbol() )
766 mBackgroundSymbolButton->setSymbol( symbol->clone() );
767
768 mFrameCheckbox->setChecked( textItem->frameEnabled() );
769 if ( const QgsSymbol *symbol = textItem->frameSymbol() )
770 mFrameSymbolButton->setSymbol( symbol->clone() );
771
772 mMarginUnitWidget->setUnit( textItem->marginsUnit() );
773 mSpinLeftMargin->setValue( textItem->margins().left() );
774 mSpinTopMargin->setValue( textItem->margins().top() );
775 mSpinRightMargin->setValue( textItem->margins().right() );
776 mSpinBottomMargin->setValue( textItem->margins().bottom() );
777
778 mWidthSpinBox->setValue( textItem->fixedSize().width() );
779 mHeightSpinBox->setValue( textItem->fixedSize().height() );
780 mSizeUnitWidget->setUnit( textItem->fixedSizeUnit() );
781 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( textItem->placementMode() ) ) );
782 mRotationModeCombo->setCurrentIndex( mRotationModeCombo->findData( QVariant::fromValue( textItem->rotationMode() ) ) );
783 mSpinAngle->setValue( textItem->rotation() );
784
785 mBlockChangedSignal = false;
786
787 return true;
788}
789
790void QgsAnnotationRectangleTextItemWidget::onWidgetChanged()
791{
792 if ( !mBlockChangedSignal )
793 emit itemChanged();
794}
795
796void QgsAnnotationRectangleTextItemWidget::sizeModeChanged()
797{
798 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>();
799 switch ( mode )
800 {
802 mWidgetFixedSize->hide();
803 break;
804
806 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
807 {
808 const QgsRectangle itemBoundsMapUnits = details->boundingBox();
809 if ( QgsMapCanvas *canvas = context().mapCanvas() )
810 {
811 const QgsPointXY topLeftPixels = canvas->mapSettings().mapToPixel().transform( itemBoundsMapUnits.xMinimum(), itemBoundsMapUnits.yMinimum() );
812 const QgsPointXY bottomRightPixels = canvas->mapSettings().mapToPixel().transform( itemBoundsMapUnits.xMaximum(), itemBoundsMapUnits.yMaximum() );
813 const double widthPixels = std::abs( bottomRightPixels.x() - topLeftPixels.x() );
814 const double heightPixels = std::abs( bottomRightPixels.y() - topLeftPixels.y() );
815
816 // convert width/height in pixels to mm
817 const double pixelsPerMm = canvas->mapSettings().outputDpi() / 25.4;
818 mItem->setFixedSizeUnit( Qgis::RenderUnit::Millimeters );
819 mItem->setFixedSize( QSizeF( widthPixels / pixelsPerMm, heightPixels / pixelsPerMm ) );
820
821 // and update widget UI accordingly
822 whileBlocking( mWidthSpinBox )->setValue( mItem->fixedSize().width() );
823 whileBlocking( mHeightSpinBox )->setValue( mItem->fixedSize().height() );
824 whileBlocking( mSizeUnitWidget )->setUnit( mItem->fixedSizeUnit() );
825
826 mUpdateItemPosition = true;
827 }
828 }
829
830 mWidgetFixedSize->show();
831 break;
832
834 {
835 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
836 {
837 // convert item bounds to relative position
838 const QgsRectangle itemBounds = details->boundingBox();
839 if ( QgsMapCanvas *canvas = context().mapCanvas() )
840 {
841 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
842 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
843 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
844 mUpdateItemPosition = true;
845 }
846 }
847
848 mWidgetFixedSize->hide();
849 break;
850 }
851 }
852
853 onWidgetChanged();
854}
855
856void QgsAnnotationRectangleTextItemWidget::setWidth()
857{
858 onWidgetChanged();
859}
860
861void QgsAnnotationRectangleTextItemWidget::setHeight()
862{
863 onWidgetChanged();
864}
865
866void QgsAnnotationRectangleTextItemWidget::mInsertExpressionButton_clicked()
867{
868 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mTextEdit->textEdit() );
869
870 QgsExpressionBuilderDialog exprDlg( nullptr, expression, this, u"generic"_s, createExpressionContext() );
871
872 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
873 if ( exprDlg.exec() == QDialog::Accepted )
874 {
875 expression = exprDlg.expressionText().trimmed();
876 if ( !expression.isEmpty() )
877 {
878 mTextEdit->textEdit()->insertPlainText( "[%" + expression + "%]" );
879 }
880 }
881}
882
883
884//
885// QgsAnnotationPictureItemWidget
886//
887
888QgsAnnotationPictureItemWidget::QgsAnnotationPictureItemWidget( QWidget *parent )
890{
891 setupUi( this );
892
893 mSizeStackedWidget->setSizeMode( QgsStackedWidget::SizeMode::CurrentPageOnly );
894
895 mSizeModeCombo->addItem( tr( "Scale Dependent Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::SpatialBounds ) );
896 mSizeModeCombo->addItem( tr( "Fixed Size" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::FixedSize ) );
897 mSizeModeCombo->addItem( tr( "Relative to Map" ), QVariant::fromValue( Qgis::AnnotationPlacementMode::RelativeToMapFrame ) );
898
899 populateRotationModeComboBox( mRotationModeCombo );
900
901 mSizeUnitWidget->setUnits(
903 );
904
905 mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
906 mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) );
907 mBackgroundSymbolButton->registerExpressionContextGenerator( this );
908 mFrameSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
909 mFrameSymbolButton->setDialogTitle( tr( "Frame" ) );
910 mFrameSymbolButton->registerExpressionContextGenerator( this );
911
912 connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [this] {
913 if ( !mBlockChangedSignal )
914 emit itemChanged();
915 } );
916
917 connect( mSizeModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationPictureItemWidget::sizeModeChanged );
918
919 connect( mRotationModeCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
920
921 mSpinAngle->setClearValue( 0 );
922 connect( mSpinAngle, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
923
924 connect( mRadioSVG, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
925 connect( mRadioRaster, &QRadioButton::toggled, this, &QgsAnnotationPictureItemWidget::modeChanged );
926 connect( mSourceLineEdit, &QgsPictureSourceLineEditBase::sourceChanged, this, [this]( const QString &source ) {
927 if ( !mRadioSVG->isChecked() && QFileInfo( source ).suffix().compare( "svg"_L1, Qt::CaseInsensitive ) == 0 )
928 {
929 mRadioSVG->setChecked( true );
930 }
931
932 onWidgetChanged();
933 } );
934
935 connect( mLockAspectRatioCheck, &QCheckBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
936 connect( mFrameCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
937 connect( mBackgroundCheckbox, &QGroupBox::toggled, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
938 connect( mBackgroundSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
939 connect( mFrameSymbolButton, &QgsSymbolButton::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
940 connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsAnnotationPictureItemWidget::onWidgetChanged );
941
942 connect( mWidthSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setWidth );
943 connect( mHeightSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsAnnotationPictureItemWidget::setHeight );
944 connect( mLockAspectRatio, &QgsRatioLockButton::lockChanged, this, &QgsAnnotationPictureItemWidget::setLockAspectRatio );
945}
946
947QgsAnnotationPictureItemWidget::~QgsAnnotationPictureItemWidget() = default;
948
949QgsAnnotationItem *QgsAnnotationPictureItemWidget::createItem()
950{
951 QgsAnnotationPictureItem *newItem = mItem->clone();
952 updateItem( newItem );
953 return newItem;
954}
955
956void QgsAnnotationPictureItemWidget::updateItem( QgsAnnotationItem *item )
957{
958 if ( QgsAnnotationPictureItem *pictureItem = dynamic_cast<QgsAnnotationPictureItem *>( item ) )
959 {
960 const bool svg = mRadioSVG->isChecked();
962 const QString path = mSourceLineEdit->source();
963 pictureItem->setPath( newFormat, path );
964
965 pictureItem->setPlacementMode( mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>() );
966 switch ( pictureItem->placementMode() )
967 {
969 pictureItem->setLockAspectRatio( mLockAspectRatioCheck->isChecked() );
970 break;
973 pictureItem->setLockAspectRatio( mLockAspectRatio->isChecked() );
974 break;
975 }
976
977 pictureItem->setFixedSize( QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() ) );
978 pictureItem->setFixedSizeUnit( mSizeUnitWidget->unit() );
979
980 pictureItem->setRotation( mSpinAngle->value() );
981 pictureItem->setRotationMode( mRotationModeCombo->currentData().value<Qgis::SymbolRotationMode>() );
982
983 pictureItem->setBackgroundEnabled( mBackgroundCheckbox->isChecked() );
984 pictureItem->setFrameEnabled( mFrameCheckbox->isChecked() );
985 pictureItem->setBackgroundSymbol( mBackgroundSymbolButton->clonedSymbol<QgsFillSymbol>() );
986 pictureItem->setFrameSymbol( mFrameSymbolButton->clonedSymbol<QgsFillSymbol>() );
987
988 if ( mUpdateItemPosition )
989 {
990 pictureItem->setBounds( mItem->bounds() );
991 mUpdateItemPosition = false;
992 }
993
994 mPropertiesWidget->updateItem( pictureItem );
995 }
996}
997
998void QgsAnnotationPictureItemWidget::setDockMode( bool dockMode )
999{
1001}
1002
1003void QgsAnnotationPictureItemWidget::setContext( const QgsSymbolWidgetContext &context )
1004{
1006 mPropertiesWidget->setContext( context );
1007 mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() );
1008 mBackgroundSymbolButton->setMessageBar( context.messageBar() );
1009 mFrameSymbolButton->setMapCanvas( context.mapCanvas() );
1010 mFrameSymbolButton->setMessageBar( context.messageBar() );
1011}
1012
1013QgsExpressionContext QgsAnnotationPictureItemWidget::createExpressionContext() const
1014{
1015 QgsExpressionContext expressionContext;
1016 if ( context().expressionContext() )
1017 expressionContext = *( context().expressionContext() );
1018 else
1019 expressionContext = QgsProject::instance()->createExpressionContext();
1020 return expressionContext;
1021}
1022
1023void QgsAnnotationPictureItemWidget::focusDefaultWidget()
1024{
1025 mSourceLineEdit->setFocus();
1026}
1027
1028bool QgsAnnotationPictureItemWidget::setNewItem( QgsAnnotationItem *item )
1029{
1030 QgsAnnotationPictureItem *pictureItem = dynamic_cast<QgsAnnotationPictureItem *>( item );
1031 if ( !pictureItem )
1032 return false;
1033
1034 mItem.reset( pictureItem->clone() );
1035
1036 mBlockChangedSignal = true;
1037 mPropertiesWidget->setItem( mItem.get() );
1038
1039 mLockAspectRatioCheck->setChecked( mItem->lockAspectRatio() );
1040 mLockAspectRatio->setLocked( mItem->lockAspectRatio() );
1041 switch ( pictureItem->format() )
1042 {
1044 mRadioSVG->setChecked( true );
1045 break;
1047 mRadioRaster->setChecked( true );
1048 break;
1050 break;
1051 }
1052
1053 mSourceLineEdit->setSource( pictureItem->path() );
1054
1055 mBackgroundCheckbox->setChecked( pictureItem->backgroundEnabled() );
1056 if ( const QgsSymbol *symbol = pictureItem->backgroundSymbol() )
1057 mBackgroundSymbolButton->setSymbol( symbol->clone() );
1058
1059 mFrameCheckbox->setChecked( pictureItem->frameEnabled() );
1060 if ( const QgsSymbol *symbol = pictureItem->frameSymbol() )
1061 mFrameSymbolButton->setSymbol( symbol->clone() );
1062
1063 mWidthSpinBox->setValue( pictureItem->fixedSize().width() );
1064 mHeightSpinBox->setValue( pictureItem->fixedSize().height() );
1065 mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( pictureItem->placementMode() ) ) );
1066 mSpinAngle->setValue( pictureItem->rotation() );
1067 mRotationModeCombo->setCurrentIndex( mRotationModeCombo->findData( QVariant::fromValue( pictureItem->rotationMode() ) ) );
1068 sizeModeChanged();
1069
1070 mBlockChangedSignal = false;
1071
1072 return true;
1073}
1074
1075void QgsAnnotationPictureItemWidget::onWidgetChanged()
1076{
1077 if ( !mBlockChangedSignal )
1078 emit itemChanged();
1079}
1080
1081void QgsAnnotationPictureItemWidget::modeChanged( bool checked )
1082{
1083 if ( !checked )
1084 return;
1085
1086 const bool svg = mRadioSVG->isChecked();
1087
1088 if ( svg )
1089 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Svg );
1090 else
1091 mSourceLineEdit->setMode( QgsPictureSourceLineEditBase::Image );
1092
1093 onWidgetChanged();
1094}
1095
1096void QgsAnnotationPictureItemWidget::sizeModeChanged()
1097{
1098 const Qgis::AnnotationPlacementMode mode = mSizeModeCombo->currentData().value<Qgis::AnnotationPlacementMode>();
1099 switch ( mode )
1100 {
1102 mSizeStackedWidget->setCurrentWidget( mPageSpatialBounds );
1103 break;
1104
1106 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1107 break;
1108
1110 {
1111 if ( const QgsRenderedAnnotationItemDetails *details = renderedItemDetails() )
1112 {
1113 // convert item bounds to relative position
1114 const QgsRectangle itemBounds = details->boundingBox();
1115 if ( QgsMapCanvas *canvas = context().mapCanvas() )
1116 {
1117 const double centerX = ( itemBounds.center().x() - canvas->extent().xMinimum() ) / canvas->extent().width();
1118 const double centerY = ( canvas->extent().yMaximum() - itemBounds.center().y() ) / canvas->extent().height();
1119 mItem->setBounds( QgsRectangle::fromCenterAndSize( QgsPointXY( centerX, centerY ), 0.5, 0.5 ) );
1120 mUpdateItemPosition = true;
1121 }
1122 }
1123
1124 mSizeStackedWidget->setCurrentWidget( mPageFixedSize );
1125 break;
1126 }
1127 }
1128
1129 onWidgetChanged();
1130}
1131
1132void QgsAnnotationPictureItemWidget::setWidth()
1133{
1134 if ( mLockAspectRatio->locked() )
1135 {
1136 const double ratio = pictureAspectRatio();
1137 if ( ratio > 0 )
1138 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1139 }
1140
1141 onWidgetChanged();
1142}
1143
1144void QgsAnnotationPictureItemWidget::setHeight()
1145{
1146 if ( mLockAspectRatio->locked() )
1147 {
1148 const double ratio = pictureAspectRatio();
1149 if ( ratio > 0 )
1150 whileBlocking( mWidthSpinBox )->setValue( mHeightSpinBox->value() / ratio );
1151 }
1152
1153 onWidgetChanged();
1154}
1155
1156void QgsAnnotationPictureItemWidget::setLockAspectRatio( bool locked )
1157{
1158 if ( locked && !mBlockChangedSignal )
1159 {
1160 const double ratio = pictureAspectRatio();
1161 if ( ratio > 0 )
1162 whileBlocking( mHeightSpinBox )->setValue( mWidthSpinBox->value() * ratio );
1163 }
1164
1165 onWidgetChanged();
1166}
1167
1168double QgsAnnotationPictureItemWidget::pictureAspectRatio() const
1169{
1170 const bool svg = mRadioSVG->isChecked();
1171 const QString path = mSourceLineEdit->source();
1172 QSizeF size;
1173 if ( svg )
1174 {
1175 size = QgsApplication::svgCache()->svgViewboxSize( path, 100, QColor(), QColor(), 1, 1 );
1176 }
1177 else
1178 {
1179 size = QgsApplication::imageCache()->originalSize( path );
1180 }
1181 if ( size.isValid() && size.width() > 0 )
1182 return size.height() / size.width();
1183
1184 return 0;
1185}
1186
SymbolRotationMode
Modes for handling how symbol and text entity rotation is handled when maps are rotated.
Definition qgis.h:848
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.
double rotation() const
Returns the rotation of the item, in degrees clockwise.
Qgis::SymbolRotationMode rotationMode() const
Returns the method used to render the item with respect to the rotation of the map.
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:7382