Repository: silx-kit/silx
Issue: plot3d PositionInfoWidget issue with high-dpi screen

With high-dpi screen, there is an issue with plot3d `PositionInfoWidget`.

The mouse position is converted with `QWidget.mapFromGlobal` (see [doc](https://doc.qt.io/archives/qt-5.13/qwidget.html#mapFromGlobal):

https://github.com/silx-kit/silx/blob/fe8256f30918a4aaa479d1fa8d34f361822556e4/silx/gui/plot3d/tools/PositionInfoWidget.py#L216

Where I would expect to get the position in widget "logical" pixel but actual screen pixel is returned.

Tested on macos10.12 with python3.7 and pyqt5.13.2

That's easy to fix, but it would need more testing: I wonder whether it is an issue with Qt/macos or a general behavior...


Changed files:
src/silx/gui/plot3d/_model/items.py, src/silx/gui/plot3d/Plot3DWidget.py, src/silx/gui/plot3d/actions/mode.py

diff --git a/src/silx/gui/plot3d/Plot3DWidget.py b/src/silx/gui/plot3d/Plot3DWidget.py
index e5a01ac69..2f379055a 100644
--- a/src/silx/gui/plot3d/Plot3DWidget.py
+++ b/src/silx/gui/plot3d/Plot3DWidget.py
@@ -112,7 +112,7 @@ class Plot3DWidget(glu.OpenGLWidget):
     sigSceneClicked = qt.Signal(float, float)
     """Signal emitted when the scene is clicked with the left mouse button.
 
-    It provides the (x, y) clicked mouse position
+    It provides the (x, y) clicked mouse position in logical widget pixel coordinates.
     """
 
     @enum.unique
@@ -168,7 +168,9 @@ class Plot3DWidget(glu.OpenGLWidget):
     def __clickHandler(self, *args):
         """Handle interaction state machine click"""
         x, y = args[0][:2]
-        self.sigSceneClicked.emit(x, y)
+        # Convert from device pixel to logical pixel unit
+        devicePixelRatio = self.getDevicePixelRatio()
+        self.sigSceneClicked.emit(x / devicePixelRatio, y / devicePixelRatio)
 
     def setInteractiveMode(self, mode):
         """Set the interactive mode.
diff --git a/src/silx/gui/plot3d/_model/items.py b/src/silx/gui/plot3d/_model/items.py
index 8a3dcb63c..492f44b2e 100644
--- a/src/silx/gui/plot3d/_model/items.py
+++ b/src/silx/gui/plot3d/_model/items.py
@@ -99,9 +99,9 @@ class ItemProxyRow(ProxyRow):
                                items.Item3DChangedType)):
             events = (events,)
         self.__events = events
-        item.sigItemChanged.connect(self.__itemChanged)
+        item.sigItemChanged.connect(self._itemChanged)
 
-    def __itemChanged(self, event):
+    def _itemChanged(self, event):
         """Handle item changed
 
         :param Union[ItemChangedType,Item3DChangedType] event:
@@ -1384,9 +1384,9 @@ class ComplexIsosurfaceRow(IsosurfaceRow):
         self._colormapRow = ColormapRow(item)
 
         self.__updateRowsForItem(item)
-        item.sigItemChanged.connect(self.__itemChanged)
+        item.sigItemChanged.connect(self._itemChanged)
 
-    def __itemChanged(self, event):
+    def _itemChanged(self, event):
         """Update enabled/disabled rows"""
         if event == items.ItemChangedType.COMPLEX_MODE:
             item = self.sender()
@@ -1560,7 +1560,7 @@ class Scatter2DPropertyMixInRow(object):
         self.__isEnabled = item.isPropertyEnabled(propertyName)
         self.__updateFlags()
 
-        item.sigItemChanged.connect(self.__itemChanged)
+        item.sigItemChanged.connect(self._itemChanged)
 
     def data(self, column, role):
         if column == 1 and not self.__isEnabled:
@@ -1577,7 +1577,7 @@ class Scatter2DPropertyMixInRow(object):
         else:
             self.setFlags(qt.Qt.NoItemFlags)
 
-    def __itemChanged(self, event):
+    def _itemChanged(self, event):
         """Set flags to enable/disable the row"""
         if event == items.ItemChangedType.VISUALIZATION_MODE:
             item = self.sender()
diff --git a/src/silx/gui/plot3d/actions/mode.py b/src/silx/gui/plot3d/actions/mode.py
index ce09b4c9d..b9cd7c83f 100644
--- a/src/silx/gui/plot3d/actions/mode.py
+++ b/src/silx/gui/plot3d/actions/mode.py
@@ -1,7 +1,7 @@
 # coding: utf-8
 # /*##########################################################################
 #
-# Copyright (c) 2017-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -143,7 +143,7 @@ class PickingModeAction(Plot3DAction):
 
     This signal is only emitted when the action is checked.
 
-    It provides the (x, y) clicked mouse position
+    It provides the (x, y) clicked mouse position in logical widget pixel coordinates
     """
 
     def __init__(self, parent, plot3d=None):