From 231504d23abcdccd4dc12b91e33736208ea27d08 Mon Sep 17 00:00:00 2001 From: Konstantin Leontev Date: Tue, 10 Oct 2023 11:09:15 +0100 Subject: [PATCH] [bos #32216][CEA] GUI ergonomic with HDPI screens. Added using of Qt::AA_UseHighDpiPixmaps attribute and device pixel ratio (usually set by QT_SCALE_FACTOR env var). Fixed OCC and Vtk viewers display and selection issues with Qt HDPI scaling. Fixed OCC and Vtk viewers selection and context menu offset. --- src/OCCViewer/OCCViewer_ViewSketcher.cxx | 8 + src/OCCViewer/OCCViewer_ViewWindow.cxx | 23 ++- src/SVTK/SVTK_InteractorStyle.cxx | 37 +++- src/SVTK/SVTK_RenderWindowInteractor.cxx | 21 ++- src/Session/SALOME_Session_Server.cxx | 19 ++ src/ViewerTools/CMakeLists.txt | 7 +- src/ViewerTools/ViewerTools_ScreenScaling.cxx | 167 ++++++++++++++++++ src/ViewerTools/ViewerTools_ScreenScaling.h | 47 +++++ 8 files changed, 311 insertions(+), 18 deletions(-) create mode 100644 src/ViewerTools/ViewerTools_ScreenScaling.cxx create mode 100644 src/ViewerTools/ViewerTools_ScreenScaling.h diff --git a/src/OCCViewer/OCCViewer_ViewSketcher.cxx b/src/OCCViewer/OCCViewer_ViewSketcher.cxx index b46212577..d59345aa7 100644 --- a/src/OCCViewer/OCCViewer_ViewSketcher.cxx +++ b/src/OCCViewer/OCCViewer_ViewSketcher.cxx @@ -20,6 +20,7 @@ #include "OCCViewer_ViewSketcher.h" #include "OCCViewer_ViewWindow.h" #include "OCCViewer_ViewPort3d.h" +#include "ViewerTools_ScreenScaling.h" #include "QtxRubberBand.h" @@ -122,6 +123,13 @@ bool OCCViewer_ViewSketcher::eventFilter( QObject* o, QEvent* e ) { OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort(); + // We need to downscale only non-system events here + if (!e->spontaneous()) + { + // Make a copy event with updated coordinates + e = ViewerTools_ScreenScaling::getDpiAwareEvent(e, false); + } + QMouseEvent* me = (QMouseEvent*)e; SketchState state = EnTrain; bool ignore = false; diff --git a/src/OCCViewer/OCCViewer_ViewWindow.cxx b/src/OCCViewer/OCCViewer_ViewWindow.cxx index 3a5336bee..372b9145a 100644 --- a/src/OCCViewer/OCCViewer_ViewWindow.cxx +++ b/src/OCCViewer/OCCViewer_ViewWindow.cxx @@ -40,6 +40,7 @@ #include "OCCViewer_EnvTextureDlg.h" #include "OCCViewer_LightSourceDlg.h" #include "OCCViewer_Utilities.h" +#include "ViewerTools_ScreenScaling.h" #include #include @@ -373,6 +374,9 @@ OCCViewer_ViewWindow::getButtonState( QMouseEvent* theEvent, int theInteractionS bool OCCViewer_ViewWindow::eventFilter( QObject* watched, QEvent* e ) { if ( watched == myViewPort ) { + // Makes a copy event with updated coordinates if we need so + e = ViewerTools_ScreenScaling::getDpiAwareEvent(e); + int aType = e->type(); switch(aType) { case QEvent::MouseButtonPress: @@ -1080,8 +1084,10 @@ void OCCViewer_ViewWindow::vpMouseReleaseEvent(QMouseEvent* theEvent) emit mouseReleased(this, theEvent); if(theEvent->button() == Qt::RightButton && prevState == -1) { + // We need to pass unscaled coordinates to get a menu painted in a right place. + const double pixelRatio = ViewerTools_ScreenScaling::getPR(); QContextMenuEvent aEvent( QContextMenuEvent::Mouse, - theEvent->pos(), theEvent->globalPos() ); + theEvent->pos() / pixelRatio, theEvent->globalPos() / pixelRatio ); emit contextMenuRequested( &aEvent ); } } @@ -3153,6 +3159,11 @@ void OCCViewer_ViewWindow::onSketchingFinished() { Handle(AIS_InteractiveContext) ic = myModel->getAISContext(); bool append = mypSketcher->isHasShift(); + + // Sketcher uses unscaled coordinates to draw a rubber band, + // then we need to scale them here for proper selection. + const double pixelRatio = ViewerTools_ScreenScaling::getPR(); + switch( mypSketcher->type() ) { case Rect: @@ -3160,10 +3171,10 @@ void OCCViewer_ViewWindow::onSketchingFinished() QRect* aRect = (QRect*)mypSketcher->data(); if ( aRect ) { - int aLeft = aRect->left(); - int aRight = aRect->right(); - int aTop = aRect->top(); - int aBottom = aRect->bottom(); + int aLeft = aRect->left() * pixelRatio; + int aRight = aRect->right() * pixelRatio; + int aTop = aRect->top() * pixelRatio; + int aBottom = aRect->bottom() * pixelRatio; // myRect = aRect; if( append ) @@ -3186,7 +3197,7 @@ void OCCViewer_ViewWindow::onSketchingFinished() for (int index = 1; it != itEnd; ++it, index++) { QPoint aPoint = *it; - anArray.SetValue(index, gp_Pnt2d(aPoint.x(), aPoint.y())); + anArray.SetValue(index, gp_Pnt2d(aPoint.x() * pixelRatio, aPoint.y() * pixelRatio)); } if (append) diff --git a/src/SVTK/SVTK_InteractorStyle.cxx b/src/SVTK/SVTK_InteractorStyle.cxx index 1701d907e..57da3e4fd 100644 --- a/src/SVTK/SVTK_InteractorStyle.cxx +++ b/src/SVTK/SVTK_InteractorStyle.cxx @@ -41,6 +41,7 @@ #include "SUIT_Tools.h" #include "SALOME_Actor.h" +#include "ViewerTools_ScreenScaling.h" #include #include @@ -646,7 +647,12 @@ void SVTK_InteractorStyle::OnLeftButtonUp(int vtkNotUsed(ctrl), { myShiftState = shift; if( myPoligonState == InProcess ) { // add a new point of polygon - myPolygonPoints.append( QPoint( x, y ) ); + // The mouse events were already scaled up with a pixel ratio for a proper selection, + // but rubber band's implemented with QPainter scales them on its own. + // So, we need to pass unscaled coordinates to get a polygon painted in a right place. + const double pixelRatio = ViewerTools_ScreenScaling::getPR(); + + myPolygonPoints.append(QPoint(x / pixelRatio, y / pixelRatio)); this->Interactor->GetEventPosition( mySelectionEvent->myX, mySelectionEvent->myY ); mySelectionEvent->myPolygonPoints.append( QPoint( mySelectionEvent->myX, mySelectionEvent->myY ) ); return; @@ -1672,7 +1678,17 @@ void SVTK_InteractorStyle::drawRect() myRectBand = new QtxRectRubberBand( GetRenderWidget() ); myRectBand->setUpdatesEnabled ( false ); - QRect aRect = SUIT_Tools::makeRect(myPoint.x(), myPoint.y(), myOtherPoint.x(), myOtherPoint.y()); + + // The mouse events were already scaled up with a pixel ratio for a proper selection, + // but rubber band's implemented with QPainter scales them on its own. + // So, we need to pass unscaled coordinates to get a rectangle painted in a right place. + const double pixelRatio = ViewerTools_ScreenScaling::getPR(); + QRect aRect = SUIT_Tools::makeRect( + myPoint.x() / pixelRatio, + myPoint.y() / pixelRatio, + myOtherPoint.x() / pixelRatio, + myOtherPoint.y() / pixelRatio); + myRectBand->initGeometry( aRect ); if ( !myRectBand->isVisible() ) @@ -1771,27 +1787,34 @@ bool isValid( const QPolygon* thePoints, const QPoint& theCurrent ) */ void SVTK_InteractorStyle::drawPolygon() { + // The mouse events were already scaled up with a pixel ratio for a proper selection, + // but rubber band's implemented with QPainter scales them on its own. + // So, we need to pass unscaled coordinates to get a polygon painted in a right place. + const double pixelRatio = ViewerTools_ScreenScaling::getPR(); + const QPoint myPointCopy(myPoint.x() / pixelRatio, myPoint.y() / pixelRatio); + const QPoint myOtherPointCopy(myOtherPoint.x() / pixelRatio, myOtherPoint.y() / pixelRatio); + QSize aToler( 5, 5 ); if ( !myPolygonBand ) { myPolygonBand = new QtxPolyRubberBand( GetRenderWidget() ); QPalette palette; palette.setColor( myPolygonBand->foregroundRole(), Qt::white ); myPolygonBand->setPalette( palette ); - myPolygonPoints.append( QPoint( myPoint.x(), myPoint.y() ) ); + myPolygonPoints.append(myPointCopy); } myPolygonBand->hide(); bool closed = false; - bool valid = GetRenderWidget()->rect().contains( QPoint( myOtherPoint.x(), myOtherPoint.y() ) ); + bool valid = GetRenderWidget()->rect().contains(myOtherPointCopy); if ( !myPolygonPoints.at(0).isNull() ) { QRect aRect( myPolygonPoints.at(0).x() - aToler.width(), myPolygonPoints.at(0).y() - aToler.height(), 2 * aToler.width(), 2 * aToler.height() ); - closed = aRect.contains( QPoint( myOtherPoint.x(), myOtherPoint.y() ) ); + closed = aRect.contains(myOtherPointCopy); } QPolygon* points = new QPolygon( myPolygonPoints ); - valid = valid && isValid( points, QPoint( myOtherPoint.x(), myOtherPoint.y() ) ); + valid = valid && isValid(points, myOtherPointCopy); myPoligonState = valid ? InProcess : NotValid; delete points; if ( closed && !valid ) @@ -1806,7 +1829,7 @@ void SVTK_InteractorStyle::drawPolygon() else GetRenderWidget()->setCursor( Qt::ForbiddenCursor ); - myPolygonPoints.append( QPoint( myOtherPoint.x(), myOtherPoint.y() ) ); + myPolygonPoints.append(myOtherPointCopy); QPolygon aPolygon( myPolygonPoints ); myPolygonBand->initGeometry( aPolygon ); diff --git a/src/SVTK/SVTK_RenderWindowInteractor.cxx b/src/SVTK/SVTK_RenderWindowInteractor.cxx index c24945c22..4ac4dea5f 100644 --- a/src/SVTK/SVTK_RenderWindowInteractor.cxx +++ b/src/SVTK/SVTK_RenderWindowInteractor.cxx @@ -30,6 +30,7 @@ #include "SVTK_Renderer.h" #include "SVTK_Functor.h" #include "SALOME_Actor.h" +#include "ViewerTools_ScreenScaling.h" // QT Includes // Put Qt includes before the X11 includes which #define the symbol None @@ -175,7 +176,8 @@ QVTK_RenderWindowInteractor ::polish() { // Final initialization just before the widget is displayed - GetDevice()->SetSize(width(),height()); + const double pixelRatio = ViewerTools_ScreenScaling::getPR(); + GetDevice()->SetSize(width() * pixelRatio, height() * pixelRatio); if(!GetDevice()->GetInitialized() && GetDevice()->GetRenderWindow()){ GetDevice()->Initialize(); GetDevice()->ConfigureEvent(); @@ -208,13 +210,15 @@ QVTK_RenderWindowInteractor */ void QVTK_RenderWindowInteractor -::resizeEvent( QResizeEvent* /*theEvent*/ ) +::resizeEvent( QResizeEvent* /* theEvent */ ) { + int* aSize = getRenderWindow()->GetSize(); int aWidth = aSize[0]; int aHeight = aSize[1]; - GetDevice()->UpdateSize(width(),height()); + const double pixelRatio = ViewerTools_ScreenScaling::getPR(); + GetDevice()->UpdateSize(width() * pixelRatio, height() * pixelRatio); if(isVisible() && aWidth && aHeight){ if( aWidth != width() || aHeight != height() ) { @@ -695,6 +699,7 @@ void SVTK_RenderWindowInteractor ::mouseMoveEvent( QMouseEvent* event ) { + event = static_cast(ViewerTools_ScreenScaling::getDpiAwareEvent(event)); QVTK_RenderWindowInteractor::mouseMoveEvent(event); if(GENERATE_SUIT_EVENTS) @@ -709,6 +714,7 @@ void SVTK_RenderWindowInteractor ::mousePressEvent( QMouseEvent* event ) { + event = static_cast(ViewerTools_ScreenScaling::getDpiAwareEvent(event)); QVTK_RenderWindowInteractor::mousePressEvent(event); if(GENERATE_SUIT_EVENTS) @@ -733,6 +739,7 @@ SVTK_RenderWindowInteractor isOperation = style->CurrentState() != VTK_INTERACTOR_STYLE_CAMERA_NONE; } + event = static_cast(ViewerTools_ScreenScaling::getDpiAwareEvent(event)); QVTK_RenderWindowInteractor::mouseReleaseEvent(event); if ( style ) { @@ -743,8 +750,10 @@ SVTK_RenderWindowInteractor if ( aRightBtn && !isOperation && !isPolygonalSelection && !( event->modifiers() & Qt::ControlModifier ) && !( event->modifiers() & Qt::ShiftModifier ) ) { + // We need to pass unscaled coordinates to get a menu painted in a right place. + const double pixelRatio = ViewerTools_ScreenScaling::getPR(); QContextMenuEvent aEvent( QContextMenuEvent::Mouse, - event->pos(), event->globalPos() ); + event->pos() / pixelRatio, event->globalPos() / pixelRatio); emit contextMenuRequested( &aEvent ); } if(GENERATE_SUIT_EVENTS) @@ -759,6 +768,8 @@ void SVTK_RenderWindowInteractor ::mouseDoubleClickEvent( QMouseEvent* event ) { + event = static_cast(ViewerTools_ScreenScaling::getDpiAwareEvent(event)); + if( GetInteractorStyle() && event->button() == Qt::LeftButton ) { SVTK_InteractorStyle* style = dynamic_cast( GetInteractorStyle() ); if ( style ) @@ -779,6 +790,8 @@ void SVTK_RenderWindowInteractor ::wheelEvent( QWheelEvent* event ) { + event = static_cast(ViewerTools_ScreenScaling::getDpiAwareEvent(event)); + QVTK_RenderWindowInteractor::wheelEvent(event); if(event->delta() > 0) diff --git a/src/Session/SALOME_Session_Server.cxx b/src/Session/SALOME_Session_Server.cxx index b4bd5c611..b291e1070 100644 --- a/src/Session/SALOME_Session_Server.cxx +++ b/src/Session/SALOME_Session_Server.cxx @@ -477,6 +477,25 @@ int AbstractGUIAppMain(int argc, char **argv) QApplication::setApplicationName("salome"); QApplication::setApplicationVersion(salomeVersion()); + // supports HDPI + MESSAGE("Set QApplication attributes to supports HDPI..."); + + // Make QIcon::pixmap() generate high-dpi pixmaps that can be larger than the requested size. + // Such pixmaps will have devicePixelRatio() set to a value higher than 1. + // After setting this attribute, application code that uses pixmap sizes in layout geometry calculations + // should typically divide by devicePixelRatio() to get device-independent layout geometry. + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + + // The lines below do the same - enables automatic scaling, based on the monitor's pixel density. + // This won't change the size of point-sized fonts, since point is a physical measurement unit. + // Using them can make an impression of large icons among small fonts. + // qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1"); + // QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // Doesn't scale fonts + + // Keep this line as an example of using explicit scale factor. + // Defines a global scale factor for the whole application, including point-sized fonts. + // qputenv("QT_SCALE_FACTOR", "1.5"); // Scales everything + // Install Qt debug messages handler MsgHandler msgHandler; qInstallMessageHandler(QtxMsgHandler); diff --git a/src/ViewerTools/CMakeLists.txt b/src/ViewerTools/CMakeLists.txt index 44792cd11..fa3791cc8 100644 --- a/src/ViewerTools/CMakeLists.txt +++ b/src/ViewerTools/CMakeLists.txt @@ -31,7 +31,10 @@ INCLUDE_DIRECTORIES( ADD_DEFINITIONS(${QT_DEFINITIONS}) # libraries to link to -SET(_link_LIBRARIES ${QT_LIBRARIES} qtx) +SET(_link_LIBRARIES + ${QT_LIBRARIES} + ${KERNEL_SALOMELocalTrace} + qtx) # --- headers --- @@ -40,6 +43,7 @@ SET(_moc_HEADERS ViewerTools_CubeAxesDlgBase.h ViewerTools_DialogBase.h ViewerTools_FontWidgetBase.h + ViewerTools_ScreenScaling.h ) # header files / no moc processing @@ -67,6 +71,7 @@ SET(_other_SOURCES ViewerTools_CubeAxesDlgBase.cxx ViewerTools_DialogBase.cxx ViewerTools_FontWidgetBase.cxx + ViewerTools_ScreenScaling.cxx ) # sources / to compile diff --git a/src/ViewerTools/ViewerTools_ScreenScaling.cxx b/src/ViewerTools/ViewerTools_ScreenScaling.cxx new file mode 100644 index 000000000..e4dd6d9cd --- /dev/null +++ b/src/ViewerTools/ViewerTools_ScreenScaling.cxx @@ -0,0 +1,167 @@ +// Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "ViewerTools_ScreenScaling.h" + +#include +#include +#include +#include +#include + +#include "utilities.h" + +/*! + * Namespace : ViewerTools_ScreenScaling + * Description : Tools for handle UI on screens with different scaling + */ +namespace ViewerTools_ScreenScaling +{ + // Returns pixel ratio for the current screen + double getPR() + { + auto getPixelRatio = []() -> double + { + // Returns the device pixel ratio for the device as a floating point number. + // Common values are 1 for normal-dpi displays and 2 for high-dpi "retina" displays. + // Returns QT_SCALE_FACTOR if QT_SCALE_FACTOR was set. + // Returns 2 on HDPI if QApplication::setAttribute(Qt::AA_EnableHighDpiScaling) was set. + // Returns 2 * QT_SCALE_FACTOR if both of the features above were set. + // NOTE. QT_SCALE_FACTOR breaks UI in a set (-1.0, 0.0) and (0.0, 1.0). + // Negative values don't scale or break UI down, but end up with 1.0 pixel ratio. + const double pixelRatio = QApplication::desktop()->devicePixelRatioF(); + MESSAGE("pixelRatio: " << pixelRatio); + + // Keep commented block here for a test case where we use QT_SCALE_FACTOR value instead. + // QByteArray scaleFactorArr = qgetenv("QT_SCALE_FACTOR"); + // const QString scaleFactorStr = QString::fromLocal8Bit(scaleFactorArr); + + // bool isScale = false; + // const double scaleFactor = scaleFactorStr.toDouble(&isScale); + // if (isScale) + // { + // MESSAGE("scaleFactor: " << scaleFactor); + // return scaleFactor; + // } + + return pixelRatio; + }; + + // TODO: check if we need to get it out of static to handle moving to another screen + static const double pixelRatio = getPixelRatio(); + return pixelRatio; + } + + // Check if we have pixel ratio != 1.0 + bool isScaledPixelRatio() + { + auto isScaledPR = []() -> bool + { + // This an arbitrary value that seems to be meaningful for UI scaling. + // It's not clear if we need smaller values. + const double epsilon = 0.01; + const double pixelRatio = ViewerTools_ScreenScaling::getPR(); + + const bool isScaled = std::abs(pixelRatio - 1.0) > epsilon; + MESSAGE("isScaled: " << isScaled); + + return isScaled; + }; + + static const bool isScaled = isScaledPR(); + return isScaled; + } + + + // Returns a copy of the given event with the local coordinates + // updated with the current pixel ratio. + QEvent* getDpiAwareEvent(QEvent* e, bool toMultiply/* = true */) + { + // Calculate a new position + auto getNewPos = [toMultiply](const QPointF& pos) -> QPointF + { + double pixelRatio = ViewerTools_ScreenScaling::getPR(); + if (!toMultiply) + { + pixelRatio = 1.0 / pixelRatio; + } + + const double x = pos.x() * pixelRatio; + const double y = pos.y() * pixelRatio; + + // Commented because of bloated output for casual debug + // MESSAGE("New pos: " << x << ", " << y); + + return QPointF(x, y); + }; + + // Scales mouse event + auto makeMouseEvent = [&getNewPos](QMouseEvent* e) -> QEvent* + { + const QPointF pos = e->localPos(); + const QPointF newPos = getNewPos(pos); + + const QPointF globalPos = e->globalPos(); + const QPointF globalNewPos = getNewPos(globalPos); + + // Commented because of bloated output for casual debug + // MESSAGE("type: " << e->type() << "; old: " << pos.x() << ", " << pos.y() << "; new: " << newPos.x() << ", " << newPos.y()); + + return new QMouseEvent(e->type(), newPos, globalNewPos, e->button(), e->buttons(), e->modifiers()); + }; + + // Scales wheel event + auto makeWheelEvent = [&getNewPos](QWheelEvent* e) -> QEvent* + { + const QPointF pos = e->posF(); + + // Commented because of bloated output for casual debug + // MESSAGE("Old pos: " << pos.x() << ", " << pos.y()); + + return new QWheelEvent( + getNewPos(pos), e->globalPosF(), e->pixelDelta(), e->angleDelta(), e->buttons(), e->modifiers(), e->phase(), e->inverted(), e->source()); + }; + + // Return on start if we don't have any scaling + if (!isScaledPixelRatio()) + return e; + + // Make a copy of the event with the new position + const int aType = e->type(); + switch(aType) + { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + case QEvent::MouseButtonDblClick: + return makeMouseEvent((QMouseEvent*)e); + + case QEvent::Wheel: + return makeWheelEvent((QWheelEvent*)e); + + default: + break; + } + + return e; + } +}; diff --git a/src/ViewerTools/ViewerTools_ScreenScaling.h b/src/ViewerTools/ViewerTools_ScreenScaling.h new file mode 100644 index 000000000..12e70fb72 --- /dev/null +++ b/src/ViewerTools/ViewerTools_ScreenScaling.h @@ -0,0 +1,47 @@ +// Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef VIEWERTOOLS_SCREENSCALING_H +#define VIEWERTOOLS_SCREENSCALING_H + +#include "ViewerTools.h" + +class QEvent; + +/*! + * Namespace : ViewerTools_ScreenScaling + * Description : Tools for handle UI on screens with different scaling + */ +namespace ViewerTools_ScreenScaling +{ + // Returns pixel ratio for the current screen + VIEWERTOOLS_EXPORT double getPR(); + + // Check if we have pixel ratio != 1.0 + VIEWERTOOLS_EXPORT bool isScaledPixelRatio(); + + // Returns a copy of the given event with the local coordinates + // updated with the current pixel ratio. + VIEWERTOOLS_EXPORT QEvent* getDpiAwareEvent(QEvent* e, bool toMultiply = true); +} + +#endif -- 2.39.2