Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add UI action for creating text along line annotation items
And a properties panel
  • Loading branch information
nyalldawson committed Apr 4, 2023
1 parent 8ee5ba8 commit 9fa59d2
Show file tree
Hide file tree
Showing 9 changed files with 398 additions and 2 deletions.
1 change: 1 addition & 0 deletions images/images.qrc
Expand Up @@ -983,6 +983,7 @@
<file>themes/default/algorithms/mAlgorithmRectanglesOvalsDiamonds.svg</file>
<file>themes/default/algorithms/mAlgorithmOffsetLines.svg</file>
<file>composer/refreshing_item.svg</file>
<file>themes/default/mActionTextAlongLine.svg</file>
</qresource>
<qresource prefix="/images/tips">
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>
Expand Down
1 change: 1 addition & 0 deletions images/themes/default/mActionTextAlongLine.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/core/annotations/qgsannotationlinetextitem.cpp
Expand Up @@ -234,7 +234,7 @@ QgsRectangle QgsAnnotationLineTextItem::boundingBox( QgsRenderContext &context )
{
const QString displayText = QgsExpression::replaceExpressionText( mText, &context.expressionContext(), &context.distanceArea() );

const double lineOffsetInMapUnits = context.convertToMapUnits( mOffsetFromLineDistance, mOffsetFromLineUnit, mOffsetFromLineScale );
const double lineOffsetInMapUnits = std::fabs( context.convertToMapUnits( mOffsetFromLineDistance, mOffsetFromLineUnit, mOffsetFromLineScale ) );

const double heightInPixels = QgsTextRenderer::textHeight( context, mTextFormat, { displayText} );

Expand Down
14 changes: 14 additions & 0 deletions src/gui/annotations/qgsannotationitemguiregistry.cpp
Expand Up @@ -233,4 +233,18 @@ void QgsAnnotationItemGuiRegistry::addDefaultItems()
{
return new QgsCreatePointTextItemMapTool( canvas, cadDockWidget );
} ) );

addAnnotationItemGuiMetadata( new QgsAnnotationItemGuiMetadata( QStringLiteral( "linetext" ),
QObject::tr( "Text Annotation along Line" ),
QgsApplication::getThemeIcon( QStringLiteral( "/mActionTextAlongLine.svg" ) ),
[ = ]( QgsAnnotationItem * item )->QgsAnnotationItemBaseWidget *
{
QgsAnnotationLineTextItemWidget *widget = new QgsAnnotationLineTextItemWidget( nullptr );
widget->setItem( item );
return widget;
}, QString(), Qgis::AnnotationItemGuiFlags(), nullptr,
[ = ]( QgsMapCanvas * canvas, QgsAdvancedDigitizingDockWidget * cadDockWidget )->QgsCreateAnnotationItemMapToolInterface *
{
return new QgsCreateLineTextItemMapTool( canvas, cadDockWidget );
} ) );
}
157 changes: 157 additions & 0 deletions src/gui/annotations/qgsannotationitemwidget_impl.cpp
Expand Up @@ -23,6 +23,7 @@
#include "qgsannotationlineitem.h"
#include "qgsannotationmarkeritem.h"
#include "qgsannotationpointtextitem.h"
#include "qgsannotationlinetextitem.h"
#include "qgsexpressionbuilderdialog.h"
#include "qgstextformatwidget.h"
#include "qgsapplication.h"
Expand Down Expand Up @@ -428,5 +429,161 @@ void QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked()
}
}


//
// QgsAnnotationLineTextItemWidget
//

QgsAnnotationLineTextItemWidget::QgsAnnotationLineTextItemWidget( QWidget *parent )
: QgsAnnotationItemBaseWidget( parent )
{
setupUi( this );

mTextFormatWidget = new QgsTextFormatWidget();
QVBoxLayout *vLayout = new QVBoxLayout();
vLayout->setContentsMargins( 0, 0, 0, 0 );
vLayout->addWidget( mTextFormatWidget );
mTextFormatWidgetContainer->setLayout( vLayout );

mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 );

mTextFormatWidget->setDockMode( dockMode() );
connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [ = ]
{
if ( !mBlockChangedSignal )
emit itemChanged();
} );
connect( mTextEdit, &QPlainTextEdit::textChanged, this, [ = ]
{
if ( !mBlockChangedSignal )
emit itemChanged();
} );
connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked );
connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
{
if ( !mBlockChangedSignal )
emit itemChanged();
} );

mOffsetUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << Qgis::RenderUnit::Millimeters << Qgis::RenderUnit::MetersInMapUnits << Qgis::RenderUnit::MapUnits << Qgis::RenderUnit::Pixels
<< Qgis::RenderUnit::Points << Qgis::RenderUnit::Inches );
mSpinOffset->setClearValue( 0.0 );
connect( mSpinOffset, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, [ = ]
{
if ( !mBlockChangedSignal )
emit itemChanged();
} );

connect( mOffsetUnitWidget, &QgsUnitSelectionWidget::changed, this, [ = ]
{
if ( !mBlockChangedSignal )
emit itemChanged();
} );
}

QgsAnnotationItem *QgsAnnotationLineTextItemWidget::createItem()
{
QgsAnnotationLineTextItem *newItem = mItem->clone();
newItem->setFormat( mTextFormatWidget->format() );
newItem->setText( mTextEdit->toPlainText() );

newItem->setOffsetFromLine( mSpinOffset->value() );
newItem->setOffsetFromLineUnit( mOffsetUnitWidget->unit() );
newItem->setOffsetFromLineMapUnitScale( mOffsetUnitWidget->getMapUnitScale() );

mPropertiesWidget->updateItem( newItem );
return newItem;
}

void QgsAnnotationLineTextItemWidget::updateItem( QgsAnnotationItem *item )
{
if ( QgsAnnotationLineTextItem *lineTextItem = dynamic_cast< QgsAnnotationLineTextItem * >( item ) )
{
lineTextItem->setFormat( mTextFormatWidget->format() );
lineTextItem->setText( mTextEdit->toPlainText() );

lineTextItem->setOffsetFromLine( mSpinOffset->value() );
lineTextItem->setOffsetFromLineUnit( mOffsetUnitWidget->unit() );
lineTextItem->setOffsetFromLineMapUnitScale( mOffsetUnitWidget->getMapUnitScale() );

mPropertiesWidget->updateItem( lineTextItem );
}
}

void QgsAnnotationLineTextItemWidget::setDockMode( bool dockMode )
{
QgsAnnotationItemBaseWidget::setDockMode( dockMode );
if ( mTextFormatWidget )
mTextFormatWidget->setDockMode( dockMode );
}

void QgsAnnotationLineTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
{
QgsAnnotationItemBaseWidget::setContext( context );
if ( mTextFormatWidget )
mTextFormatWidget->setContext( context );
mPropertiesWidget->setContext( context );
}

void QgsAnnotationLineTextItemWidget::focusDefaultWidget()
{
mTextEdit->selectAll();
mTextEdit->setFocus();
}

QgsAnnotationLineTextItemWidget::~QgsAnnotationLineTextItemWidget() = default;

bool QgsAnnotationLineTextItemWidget::setNewItem( QgsAnnotationItem *item )
{
QgsAnnotationLineTextItem *textItem = dynamic_cast< QgsAnnotationLineTextItem * >( item );
if ( !textItem )
return false;

mItem.reset( textItem->clone() );

mBlockChangedSignal = true;
mTextFormatWidget->setFormat( mItem->format() );
mTextEdit->setPlainText( mItem->text() );
mPropertiesWidget->setItem( mItem.get() );

mSpinOffset->setValue( mItem->offsetFromLine() );
mOffsetUnitWidget->setUnit( mItem->offsetFromLineUnit() );
mOffsetUnitWidget->setMapUnitScale( mItem->offsetFromLineMapUnitScale() );

mBlockChangedSignal = false;

return true;
}

void QgsAnnotationLineTextItemWidget::mInsertExpressionButton_clicked()
{
QString selText = mTextEdit->textCursor().selectedText();

// html editor replaces newlines with Paragraph Separator characters - see https://github.com/qgis/QGIS/issues/27568
selText = selText.replace( QChar( 0x2029 ), QChar( '\n' ) );

// edit the selected expression if there's one
if ( selText.startsWith( QLatin1String( "[%" ) ) && selText.endsWith( QLatin1String( "%]" ) ) )
selText = selText.mid( 2, selText.size() - 4 );

QgsExpressionContext expressionContext;
if ( context().expressionContext() )
expressionContext = *( context().expressionContext() );
else
expressionContext = QgsProject::instance()->createExpressionContext();

QgsExpressionBuilderDialog exprDlg( nullptr, selText, this, QStringLiteral( "generic" ), expressionContext );

exprDlg.setWindowTitle( tr( "Insert Expression" ) );
if ( exprDlg.exec() == QDialog::Accepted )
{
QString expression = exprDlg.expressionText();
if ( !expression.isEmpty() )
{
mTextEdit->insertPlainText( "[%" + expression + "%]" );
}
}
}

///@endcond PRIVATE

31 changes: 31 additions & 0 deletions src/gui/annotations/qgsannotationitemwidget_impl.h
Expand Up @@ -23,6 +23,7 @@

#include "ui_qgsannotationpointtextwidgetbase.h"
#include "ui_qgsannotationsymbolwidgetbase.h"
#include "ui_qgsannotationlinetextwidgetbase.h"

class QgsSymbolSelectorWidget;
class QgsFillSymbol;
Expand All @@ -32,6 +33,7 @@ class QgsAnnotationPolygonItem;
class QgsAnnotationLineItem;
class QgsAnnotationMarkerItem;
class QgsAnnotationPointTextItem;
class QgsAnnotationLineTextItem;
class QgsTextFormatWidget;

#define SIP_NO_FILE
Expand Down Expand Up @@ -135,6 +137,35 @@ class QgsAnnotationPointTextItemWidget : public QgsAnnotationItemBaseWidget, pri
std::unique_ptr< QgsAnnotationPointTextItem> mItem;
};


class QgsAnnotationLineTextItemWidget : public QgsAnnotationItemBaseWidget, private Ui_QgsAnnotationLineTextWidgetBase
{
Q_OBJECT

public:
QgsAnnotationLineTextItemWidget( QWidget *parent );
~QgsAnnotationLineTextItemWidget() override;
QgsAnnotationItem *createItem() override;
void updateItem( QgsAnnotationItem *item ) override;
void setDockMode( bool dockMode ) override;
void setContext( const QgsSymbolWidgetContext &context ) override;

public slots:

void focusDefaultWidget() override;

protected:
bool setNewItem( QgsAnnotationItem *item ) override;

private:
void mInsertExpressionButton_clicked();

QgsTextFormatWidget *mTextFormatWidget = nullptr;
bool mBlockChangedSignal = false;
std::unique_ptr< QgsAnnotationLineTextItem> mItem;
};


///@endcond

#endif // QGSANNOTATIONITEMWIDGETIMPL_H
33 changes: 32 additions & 1 deletion src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp
Expand Up @@ -19,6 +19,7 @@
#include "qgsannotationmarkeritem.h"
#include "qgsannotationlineitem.h"
#include "qgsannotationpolygonitem.h"
#include "qgsannotationlinetextitem.h"
#include "qgsannotationlayer.h"
#include "qgsstyle.h"
#include "qgsmapcanvas.h"
Expand Down Expand Up @@ -213,5 +214,35 @@ void QgsCreatePolygonItemMapTool::polygonCaptured( const QgsCurvePolygon *polygo
}
}

///@endcond PRIVATE
//
// QgsCreateLineTextItemMapTool
//

QgsCreateLineTextItemMapTool::QgsCreateLineTextItemMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget )
: QgsMapToolCaptureAnnotationItem( canvas, cadDockWidget, CaptureLine )
{
mHandler = new QgsCreateAnnotationItemMapToolHandler( canvas, cadDockWidget, this );
}

void QgsCreateLineTextItemMapTool::lineCaptured( const QgsCurve *line )
{
// do it!
std::unique_ptr< QgsAbstractGeometry > geometry( line->simplifiedTypeRef()->clone() );
if ( qgsgeometry_cast< QgsCurve * >( geometry.get() ) )
{
std::unique_ptr< QgsAnnotationLineTextItem > createdItem = std::make_unique< QgsAnnotationLineTextItem >( tr( "Text" ), qgsgeometry_cast< QgsCurve * >( geometry.release() ) );

std::unique_ptr< QgsLineSymbol > lineSymbol = QgsApplication::recentStyleHandler()->recentSymbol< QgsLineSymbol >( QStringLiteral( "line_annotation_item" ) );
if ( !lineSymbol )
lineSymbol.reset( qgis::down_cast< QgsLineSymbol * >( QgsSymbol::defaultSymbol( Qgis::GeometryType::Line ) ) );

createdItem->setFormat( QgsStyle::defaultTextFormatForProject( QgsProject::instance(), QgsStyle::TextFormatContext::Labeling ) );

// newly created point text items default to using symbology reference scale at the current map scale
createdItem->setUseSymbologyReferenceScale( true );
createdItem->setSymbologyReferenceScale( canvas()->scale() );
mHandler->pushCreatedItem( createdItem.release() );
}
}

///@endcond PRIVATE
13 changes: 13 additions & 0 deletions src/gui/annotations/qgscreateannotationitemmaptool_impl.h
Expand Up @@ -97,6 +97,19 @@ class QgsCreatePolygonItemMapTool: public QgsMapToolCaptureAnnotationItem
void polygonCaptured( const QgsCurvePolygon *polygon ) override;
};


class QgsCreateLineTextItemMapTool: public QgsMapToolCaptureAnnotationItem
{
Q_OBJECT

public:

QgsCreateLineTextItemMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget );

private slots:
void lineCaptured( const QgsCurve *line ) override;
};

///@endcond PRIVATE

#endif // QGSCREATEANNOTATIONITEMMAPTOOLIMPL_H

0 comments on commit 9fa59d2

Please sign in to comment.