Repository: silx-kit/silx
Issue: [plot] With Plot2D, data value in bottom bar is not updated when image change

With Plot2D, data value in bottom bar is not updated when image change if the mouse does not move

Changed files:
silx/gui/plot/tools/test/testTools.py, silx/gui/plot/PlotWindow.py, silx/gui/plot/tools/PositionInfo.py

diff --git a/silx/gui/plot/PlotWindow.py b/silx/gui/plot/PlotWindow.py
index ad723230d..ee6172041 100644
--- a/silx/gui/plot/PlotWindow.py
+++ b/silx/gui/plot/PlotWindow.py
@@ -233,6 +233,8 @@ class PlotWindow(PlotWidget):
         centralWidget.setLayout(gridLayout)
         self.setCentralWidget(centralWidget)
 
+        self._positionWidget = None
+
         if control or position:
             hbox = qt.QHBoxLayout()
             hbox.setContentsMargins(0, 0, 0, 0)
@@ -255,11 +257,11 @@ class PlotWindow(PlotWidget):
                     converters = position
                 else:
                     converters = None
-                self.positionWidget = tools.PositionInfo(
+                self._positionWidget = tools.PositionInfo(
                     plot=self, converters=converters)
-                self.positionWidget.autoSnapToActiveCurve = True
+                self._positionWidget.autoSnapToActiveCurve = True
 
-                hbox.addWidget(self.positionWidget)
+                hbox.addWidget(self._positionWidget)
 
             hbox.addStretch(1)
             bottomBar = qt.QWidget()
@@ -300,6 +302,18 @@ class PlotWindow(PlotWidget):
         """
         return self._outputToolBar
 
+    @property
+    @deprecated(replacement="getPositionInfoWidget()", since_version="0.8.0")
+    def positionWidget(self):
+        return self.getPositionInfoWidget()
+
+    def getPositionInfoWidget(self):
+        """Returns the widget displaying current cursor position information
+
+        :rtype: ~silx.gui.plot.tools.PositionInfo
+        """
+        return self._positionWidget
+
     def getSelectionMask(self):
         """Return the current mask handled by :attr:`maskToolsDockWidget`.
 
@@ -838,6 +852,37 @@ class Plot2D(PlotWindow):
             if action is self.getColormapAction():
                 break
 
+        self.sigActiveImageChanged.connect(self.__activeImageChanged)
+
+    def __activeImageChanged(self, previous, legend):
+        """Handle change of active image
+
+        :param Union[str,None] previous: Legend of previous active image
+        :param Union[str,None] legend: Legend of current active image
+        """
+        if previous is not None:
+            item = self.getImage(previous)
+            if item is not None:
+                item.sigItemChanged.disconnect(self.__imageChanged)
+
+        if legend is not None:
+            item = self.getImage(legend)
+            item.sigItemChanged.connect(self.__imageChanged)
+
+        positionInfo = self.getPositionInfoWidget()
+        if positionInfo is not None:
+            positionInfo.updateInfo()
+
+    def __imageChanged(self, event):
+        """Handle update of active image item
+
+        :param event: Type of changed event
+        """
+        if event == items.ItemChangedType.DATA:
+            positionInfo = self.getPositionInfoWidget()
+            if positionInfo is not None:
+                positionInfo.updateInfo()
+
     def _getImageValue(self, x, y):
         """Get status bar value of top most image at position (x, y)
 
diff --git a/silx/gui/plot/tools/PositionInfo.py b/silx/gui/plot/tools/PositionInfo.py
index 5fb105bd8..2175780c5 100644
--- a/silx/gui/plot/tools/PositionInfo.py
+++ b/silx/gui/plot/tools/PositionInfo.py
@@ -155,6 +155,22 @@ class PositionInfo(qt.QWidget):
             xPixel, yPixel = event['xpixel'], event['ypixel']
             self._updateStatusBar(x, y, xPixel, yPixel)
 
+    def updateInfo(self):
+        """Update displayed information"""
+        plot = self.plot
+        if plot is None:
+            _logger.error("Trying to update PositionInfo "
+                          "while PlotWidget no longer exists")
+            return
+
+        widget = plot.getWidgetHandle()
+        position = widget.mapFromGlobal(qt.QCursor.pos())
+        xPixel, yPixel = position.x(), position.y()
+        dataPos = plot.pixelToData(xPixel, yPixel, check=True)
+        if dataPos is not None:  # Inside plot area
+            x, y = dataPos
+            self._updateStatusBar(x, y, xPixel, yPixel)
+
     def _updateStatusBar(self, x, y, xPixel, yPixel):
         """Update information from the status bar using the definitions.
 
diff --git a/silx/gui/plot/tools/test/testTools.py b/silx/gui/plot/tools/test/testTools.py
index 4ff2df40f..810b933dc 100644
--- a/silx/gui/plot/tools/test/testTools.py
+++ b/silx/gui/plot/tools/test/testTools.py
@@ -29,8 +29,9 @@ __license__ = "MIT"
 __date__ = "02/03/2018"
 
 
-import numpy
+import functools
 import unittest
+import numpy
 
 from silx.utils.testutils import TestLogging
 from silx.gui.test.utils import qWaitForWindowExposedAndActivate
@@ -132,6 +133,21 @@ class TestPositionInfo(PlotWidgetTestCase):
             converters=[('Exception', raiseException)])
         self._test(positionWidget, ['Exception'], error=2)
 
+    def testUpdate(self):
+        """Test :meth:`PositionInfo.updateInfo`"""
+        calls = []
+
+        def update(calls, x, y):  # Get number of calls
+            calls.append((x, y))
+            return len(calls)
+
+        positionWidget = tools.PositionInfo(
+            plot=self.plot,
+            converters=[('Call count', functools.partial(update, calls))])
+
+        positionWidget.updateInfo()
+        self.assertEqual(len(calls), 1)
+
 
 class TestPlotToolsToolbars(PlotWidgetTestCase):
     """Tests toolbars from silx.gui.plot.tools"""