Skip to content

Commit

Permalink
Map tip position improvements (#52469)
Browse files Browse the repository at this point in the history
  • Loading branch information
YoannQDQ committed Apr 8, 2023
1 parent 53ba34c commit e98e655
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 161 deletions.
5 changes: 0 additions & 5 deletions python/gui/auto_generated/qgsmaptip.sip.in
Expand Up @@ -62,11 +62,6 @@ Clear the current maptip if it exists

:param mpMapCanvas: the canvas from which the tip should be cleared.
:param msDelay: optional time in ms to defer clearing the maptip (since QGIS 3.26)
%End

void applyFontSettings();
%Docstring
Apply font family and size to match user settings
%End

static QString vectorMapTipPreviewText( QgsMapLayer *layer, QgsMapCanvas *mapCanvas, const QString &mapTemplate, const QString &displayExpression );
Expand Down
2 changes: 2 additions & 0 deletions resources/themes/Blend of Gray/palette.txt
Expand Up @@ -6,4 +6,6 @@
10:#373737
12:#f0f0f0
13:#373737
18:#535353
19:#fff
20:#727272
3 changes: 1 addition & 2 deletions resources/themes/Blend of Gray/style.qss
Expand Up @@ -39,8 +39,7 @@ QWebView, QTextBrowser
QToolTip
{
border: 1px solid #222;
background-color: @itemdarkbackground;
color: @itembackground;
background: @itembackground;
}

QMenuBar {
Expand Down
2 changes: 2 additions & 0 deletions resources/themes/Night Mapping/palette.txt
Expand Up @@ -8,4 +8,6 @@
13:#323232
14:#0080ff
15:#0080ff
18:#535353
19:#ddd
20:#535353
2 changes: 0 additions & 2 deletions resources/themes/Night Mapping/style.qss
Expand Up @@ -39,8 +39,6 @@ QWebView, QTextBrowser
QToolTip
{
border: 1px solid #222;
background-color: @itemdarkbackground;
color: @text;
}

QMenuBar {
Expand Down
5 changes: 0 additions & 5 deletions src/app/qgisapp.cpp
Expand Up @@ -3262,11 +3262,6 @@ void QgisApp::setAppStyleSheet( const QString &stylesheet )
{
d->setStyleSheet( stylesheet );
}

if ( mpMaptip )
{
mpMaptip->applyFontSettings();
}
}

void QgisApp::createMenus()
Expand Down
196 changes: 116 additions & 80 deletions src/gui/qgsmaptip.cpp
Expand Up @@ -41,17 +41,44 @@
#endif
#include <QHBoxLayout>


#include "qgsmaptip.h"


const QString QgsMapTip::sMapTipTemplate = "<html>\n"
" <head>\n"
" <style>\n"
" body {\n"
" margin: 0;\n"
" font: %1pt \"%2\";\n"
" color: %3;\n"
" width: %4px;\n"
" }\n"
" #QgsWebViewContainer {\n"
" background-color: %5;\n"
" border: 1px solid %6;\n"
" display: inline-block;\n"
" margin: 0\n"
" }\n"
" #QgsWebViewContainerInner {\n"
" margin: 5px\n"
" }\n"
" </style>\n"
" </head>\n"
" <body>\n"
" <div id='QgsWebViewContainer'>\n"
" <div id='QgsWebViewContainerInner'>\n"
" %7\n"
" </div>\n"
" </div>\n"
" </body>\n"
"</html>\n";


QgsMapTip::QgsMapTip()
{
// Init the visible flag
mMapTipVisible = false;

// Init font-related values
applyFontSettings();

mDelayedClearTimer.setSingleShot( true );
connect( &mDelayedClearTimer, &QTimer::timeout, this, [ = ]() {this->clear();} );
}
Expand All @@ -74,26 +101,26 @@ void QgsMapTip::showMapTip( QgsMapLayer *pLayer,
}

// Do not render a new map tip when the mouse hovers an existing one
if ( mWidget && mWidget->underMouse() )
if ( mWebView && mWebView->underMouse() )
{
return;
}

// Show the maptip on the canvas
QString tipText, lastTipText, tipHtml, backgroundColor, strokeColor;
QString tipText, lastTipText, tipHtml;

if ( ! mWidget )
if ( ! mWebView )
{
mWidget = new QWidget( pMapCanvas );
mWidget->setContentsMargins( MARGIN_VALUE, MARGIN_VALUE, MARGIN_VALUE, MARGIN_VALUE );
mWebView = new QgsWebView( mWidget );
mWebView = new QgsWebView( pMapCanvas );
// Make the webwiew transparent
mWebView->setStyleSheet( QStringLiteral( "background:transparent;" ) );


#if WITH_QTWEBKIT
mWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );//Handle link clicks by yourself
mWebView->setContextMenuPolicy( Qt::NoContextMenu ); //No context menu is allowed if you don't need it
connect( mWebView, &QWebView::linkClicked, this, &QgsMapTip::onLinkClicked );
connect( mWebView, &QWebView::loadFinished, this, [ = ]( bool ) { resizeContent(); } );
connect( mWebView, &QWebView::loadFinished, this, [ = ]( bool ) { resizeAndMoveToolTip(); } );
#endif

mWebView->page()->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
Expand All @@ -104,29 +131,6 @@ void QgsMapTip::showMapTip( QgsMapLayer *pLayer,
mWebView->page()->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
mWebView->page()->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );

QHBoxLayout *layout = new QHBoxLayout;
layout->setContentsMargins( 0, 0, 0, 0 );
layout->addWidget( mWebView );

mWidget->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
mWidget->setLayout( layout );

// Assure the map tip is never larger than half the map canvas
const int MAX_WIDTH = pMapCanvas->geometry().width() / 2;
const int MAX_HEIGHT = pMapCanvas->geometry().height() / 2;
mWidget->setMaximumSize( MAX_WIDTH, MAX_HEIGHT );

// Start with 0 size,
// The content will automatically make it grow up to MaximumSize
mWidget->resize( 0, 0 );

backgroundColor = QgsApplication::palette().base().color().name();
strokeColor = QgsApplication::palette().shadow().color().name();
mWidget->setStyleSheet( QString(
".QWidget{"
"border: 1px solid %1;"
"background-color: %2;}" ).arg(
strokeColor, backgroundColor ) );
}

// Only supported layer types here:
Expand Down Expand Up @@ -154,12 +158,8 @@ void QgsMapTip::showMapTip( QgsMapLayer *pLayer,
return;
}

tipHtml = QgsMapTip::htmlText( tipText );

QgsDebugMsg( tipHtml );

// Compute offset from the cursor position
int cursorOffset = 0;
// attempt to shift the tip away from the cursor.
if ( QgsApplication::instance() )
{
// The following calculations are taken
Expand All @@ -169,26 +169,87 @@ void QgsMapTip::showMapTip( QgsMapLayer *pLayer,
cursorOffset = static_cast< int >( std::ceil( scale * 32 ) );
}

mWidget->move( pixelPosition.x() + cursorOffset, pixelPosition.y() );
// Ensures the map tip is never larger than half the map canvas minus the cursor size + margin (cursorOffset)
const int MAX_WIDTH = pMapCanvas->width() / 2 - cursorOffset;
const int MAX_HEIGHT = pMapCanvas->height() / 2;

mWebView->setMaximumSize( MAX_WIDTH, MAX_HEIGHT );

tipHtml = QgsMapTip::htmlText( tipText, MAX_WIDTH );

QgsDebugMsg( tipHtml );

mPosition = pixelPosition;
mMapCanvas = pMapCanvas;
mWebView->setHtml( tipHtml );
lastTipText = tipText;

mWidget->show();
#if !WITH_QTWEBKIT
resizeAndMoveToolTip();
#endif

}

void QgsMapTip::resizeContent()
void QgsMapTip::resizeAndMoveToolTip()
{
#if WITH_QTWEBKIT
// Get the content size
const QWebElement container = mWebView->page()->mainFrame()->findFirstElement(
QStringLiteral( "#QgsWebViewContainer" ) );
const int width = container.geometry().width() + MARGIN_VALUE * 2;
const int height = container.geometry().height() + MARGIN_VALUE * 2;
mWidget->resize( width, height );
const int width = container.geometry().width();
const int height = container.geometry().height();
mWebView->resize( width, height );
#else
mWebView->adjustSize();
#endif

int cursorOffset = 0;
// attempt to shift the tip away from the cursor.
if ( QgsApplication::instance() )
{
// The following calculations are taken
// from QgsApplication::getThemeCursor, and are used to calculate the correct cursor size
// for both hi-dpi and non-hi-dpi screens.
double scale = Qgis::UI_SCALE_FACTOR * QgsApplication::instance()->fontMetrics().height() / 32.0;
cursorOffset = static_cast< int >( std::ceil( scale * 32 ) );
}

if ( mMapCanvas == nullptr )
{
mWebView->move( mPosition );
mWebView->show();
return;
}

// Check if there is enough space to the right of the cursor
int availableWidthRight = mMapCanvas->width() - mPosition.x() - cursorOffset;
int availableWidthLeft = mPosition.x() - cursorOffset;
int availableHeightBottom = mMapCanvas->height() - mPosition.y();
int availableHeightTop = mPosition.y();
int x, y;
// If there is enough space on the right, or more space on the right than on the left, move the map tip to the right of the cursor
if ( mWebView->width() < availableWidthRight || availableWidthRight > availableWidthLeft )
{
x = mPosition.x() + cursorOffset;
}
// Otherwise, move the map tip to the left of the cursor
else
{
x = mPosition.x() - mWebView->width() - cursorOffset;
}

// If there is enough space on the bottom, or more space on the bottom than on the top, move the map tip to the bottom of the cursor
if ( mWebView->height() < availableHeightBottom || availableHeightBottom > availableHeightTop )
{
y = mPosition.y();
}
// Otherwise, move the map tip to the top of the cursor
else
{
y = mPosition.y() - mWebView->height();
}
mWebView->move( x, y );
mWebView->show();
}

void QgsMapTip::clear( QgsMapCanvas *, int msDelay )
Expand All @@ -199,7 +260,7 @@ void QgsMapTip::clear( QgsMapCanvas *, int msDelay )
}

// Skip clearing the map tip if the user interacts with it or the timer still runs
if ( mDelayedClearTimer.isActive() || mWidget->underMouse() )
if ( mDelayedClearTimer.isActive() || mWebView->underMouse() )
{
return;
}
Expand All @@ -210,7 +271,7 @@ void QgsMapTip::clear( QgsMapCanvas *, int msDelay )
return;
}
mWebView->setHtml( QString() );
mWidget->hide();
mWebView->hide();

// Reset the visible flag
mMapTipVisible = false;
Expand Down Expand Up @@ -357,42 +418,17 @@ QString QgsMapTip::fetchRaster( QgsMapLayer *layer, QgsPointXY &mapPosition, Qgs
return QgsExpression::replaceExpressionText( rlayer->mapTipTemplate(), &context );
}

QString QgsMapTip::htmlText( const QString &text )
QString QgsMapTip::htmlText( const QString &text, int maxWidth )
{

const QgsSettings settings;
const QFont defaultFont = qApp->font();
const int fontSize = settings.value( QStringLiteral( "/qgis/stylesheet/fontPointSize" ), defaultFont.pointSize() ).toInt();
const QString fontFamily = settings.value( QStringLiteral( "/qgis/stylesheet/fontFamily" ), defaultFont.family() ).toString();
QString bodyStyle, containerStyle, backgroundColor, strokeColor, textColor;

backgroundColor = QgsApplication::palette().base().color().name();
strokeColor = QgsApplication::palette().shadow().color().name();
textColor = QgsApplication::palette().windowText().color().name();

bodyStyle = QString(
"background-color: %1;"
"margin: 0;"
"font: %2pt \"%3\";"
"color: %4;" ).arg( backgroundColor ).arg( fontSize ).arg( fontFamily, textColor );

containerStyle = QString(
"display: inline-block;"
"margin: 0px" );

return QString(
"<html>"
"<body style='%1'>"
"<div id='QgsWebViewContainer' style='%2'>%3</div>"
"</body>"
"</html>" ).arg( bodyStyle, containerStyle, text );
}

void QgsMapTip::applyFontSettings()
{
const QgsSettings settings;
const QFont defaultFont = qApp->font();
mFontSize = settings.value( QStringLiteral( "/qgis/stylesheet/fontPointSize" ), defaultFont.pointSize() ).toInt();
mFontFamily = settings.value( QStringLiteral( "/qgis/stylesheet/fontFamily" ), defaultFont.family() ).toString();
const QString backgroundColor = QgsApplication::palette().base().color().name();
const QString strokeColor = QgsApplication::palette().shadow().color().name();
const QString textColor = QgsApplication::palette().toolTipText().color().name();
return sMapTipTemplate.arg( fontSize ).arg( fontFamily ).arg( textColor ).arg( maxWidth == -1 ? "" : QString::number( maxWidth ) ).arg( backgroundColor ).arg( strokeColor ).arg( text );
}

// This slot handles all clicks
Expand Down Expand Up @@ -444,7 +480,7 @@ QString QgsMapTip::vectorMapTipPreviewText( QgsMapLayer *layer, QgsMapCanvas *ma
}

// Insert the map tip text into the html template
return QgsMapTip::htmlText( tipText );
return QgsMapTip::htmlText( tipText, mapCanvas->width() / 2 );

}

Expand All @@ -468,5 +504,5 @@ QString QgsMapTip::rasterMapTipPreviewText( QgsMapLayer *layer, QgsMapCanvas *ma
const QString tipText = QgsExpression::replaceExpressionText( mapTemplate, &context );

// Insert the map tip text into the html template
return QgsMapTip::htmlText( tipText );
return QgsMapTip::htmlText( tipText, mapCanvas->width() / 2 );
}

0 comments on commit e98e655

Please sign in to comment.