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