summaryrefslogtreecommitdiff
path: root/src/silx/gui/plot/tools/roi.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/silx/gui/plot/tools/roi.py')
-rw-r--r--src/silx/gui/plot/tools/roi.py380
1 files changed, 239 insertions, 141 deletions
diff --git a/src/silx/gui/plot/tools/roi.py b/src/silx/gui/plot/tools/roi.py
index 1da692c..21b9409 100644
--- a/src/silx/gui/plot/tools/roi.py
+++ b/src/silx/gui/plot/tools/roi.py
@@ -1,6 +1,6 @@
# /*##########################################################################
#
-# Copyright (c) 2018-2022 European Synchrotron Radiation Facility
+# Copyright (c) 2018-2023 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
@@ -34,6 +34,7 @@ import logging
import time
import weakref
import functools
+from typing import Optional
import numpy
@@ -42,6 +43,8 @@ from ...utils import blockSignals
from ...utils import LockReentrant
from .. import PlotWidget
from ..items import roi as roi_items
+from ..items import ItemChangedType
+from ..items.roi import RegionOfInterest
from ...colors import rgba
@@ -87,7 +90,7 @@ class CreateRoiModeAction(qt.QAction):
iconName = "add-shape-unknown"
if name is None:
name = roiClass.__name__
- text = 'Add %s' % name
+ text = "Add %s" % name
self.setIcon(icons.getQIcon(iconName))
self.setText(text)
self.setCheckable(True)
@@ -144,7 +147,9 @@ class CreateRoiModeAction(qt.QAction):
if roiManager is not None:
roiManager.sigInteractiveRoiCreated.disconnect(self.initRoi)
roiManager.sigInteractiveRoiFinalized.disconnect(self.__finalizeRoi)
- roiManager.sigInteractiveModeFinished.disconnect(self.__interactiveModeFinished)
+ roiManager.sigInteractiveModeFinished.disconnect(
+ self.__interactiveModeFinished
+ )
self.setChecked(False)
def initRoi(self, roi):
@@ -391,7 +396,8 @@ class RegionOfInterestManager(qt.QObject):
self._roiClass = None
self._source = None
- self._color = rgba('red')
+ self._lastHoveredMarkerLabel = None
+ self._color = rgba("red")
self._label = "__RegionOfInterestManager__%d" % id(self)
@@ -404,8 +410,7 @@ class RegionOfInterestManager(qt.QObject):
parent.sigPlotSignal.connect(self._plotSignals)
- parent.sigInteractiveModeChanged.connect(
- self._plotInteractiveModeChanged)
+ parent.sigInteractiveModeChanged.connect(self._plotInteractiveModeChanged)
parent.sigItemRemoved.connect(self._itemRemoved)
@@ -432,7 +437,7 @@ class RegionOfInterestManager(qt.QObject):
:raise ValueError: If kind is not supported
"""
if not issubclass(roiClass, roi_items.RegionOfInterest):
- raise ValueError('Unsupported ROI class %s' % roiClass)
+ raise ValueError("Unsupported ROI class %s" % roiClass)
action = self._modeActions.get(roiClass, None)
if action is None: # Lazy-loading
@@ -476,19 +481,21 @@ class RegionOfInterestManager(qt.QObject):
return # Should not happen
kind = roiClass.getFirstInteractionShape()
- if kind == 'point':
- if event['event'] == 'mouseClicked' and event['button'] == 'left':
- points = numpy.array([(event['x'], event['y'])],
- dtype=numpy.float64)
+ if kind == "point":
+ if event["event"] == "mouseClicked" and event["button"] == "left":
+ points = numpy.array([(event["x"], event["y"])], dtype=numpy.float64)
# Not an interactive creation
roi = self._createInteractiveRoi(roiClass, points=points)
roi.creationFinalized()
self.sigInteractiveRoiFinalized.emit(roi)
else: # other shapes
- if (event['event'] in ('drawingProgress', 'drawingFinished') and
- event['parameters']['label'] == self._label):
- points = numpy.array((event['xdata'], event['ydata']),
- dtype=numpy.float64).T
+ if (
+ event["event"] in ("drawingProgress", "drawingFinished")
+ and event["parameters"]["label"] == self._label
+ ):
+ points = numpy.array(
+ (event["xdata"], event["ydata"]), dtype=numpy.float64
+ ).T
if self._drawnROI is None: # Create new ROI
# NOTE: Set something before createRoi, so isDrawing is True
@@ -497,8 +504,8 @@ class RegionOfInterestManager(qt.QObject):
else:
self._drawnROI.setFirstShapePoints(points)
- if event['event'] == 'drawingFinished':
- if kind == 'polygon' and len(points) > 1:
+ if event["event"] == "drawingFinished":
+ if kind == "polygon" and len(points) > 1:
self._drawnROI.setFirstShapePoints(points[:-1])
roi = self._drawnROI
self._drawnROI = None # Stop drawing
@@ -521,7 +528,7 @@ class RegionOfInterestManager(qt.QObject):
return roi
return None
- def setCurrentRoi(self, roi):
+ def setCurrentRoi(self, roi: Optional[RegionOfInterest]):
"""Set the currently selected ROI, and emit a signal.
:param Union[RegionOfInterest,None] roi: The ROI to select
@@ -545,11 +552,8 @@ class RegionOfInterestManager(qt.QObject):
self._currentRoi.setHighlighted(True)
self.sigCurrentRoiChanged.emit(roi)
- def getCurrentRoi(self):
- """Returns the currently selected ROI, else None.
-
- :rtype: Union[RegionOfInterest,None]
- """
+ def getCurrentRoi(self) -> Optional[RegionOfInterest]:
+ """Returns the currently selected ROI, else None."""
return self._currentRoi
def _plotSignals(self, event):
@@ -568,6 +572,8 @@ class RegionOfInterestManager(qt.QObject):
plot = self.parent()
marker = plot._getMarkerAt(event["xpixel"], event["ypixel"])
roi = self.__getRoiFromMarker(marker)
+ elif event["event"] == "hover":
+ self._lastHoveredMarkerLabel = event["label"]
else:
return
@@ -585,7 +591,7 @@ class RegionOfInterestManager(qt.QObject):
else:
self.setCurrentRoi(None)
- def __updateMode(self, roi):
+ def __updateMode(self, roi: RegionOfInterest):
if isinstance(roi, roi_items.InteractionModeMixIn):
available = roi.availableInteractionModes()
mode = roi.getInteractionMode()
@@ -593,46 +599,50 @@ class RegionOfInterestManager(qt.QObject):
mode = available[(imode + 1) % len(available)]
roi.setInteractionMode(mode)
- def _feedContextMenu(self, menu):
+ def _feedContextMenu(self, menu: qt.QMenu):
"""Called when the default plot context menu is about to be displayed"""
roi = self.getCurrentRoi()
if roi is not None:
if roi.isEditable():
- # Filter by data position
- # FIXME: It would be better to use GUI coords for it
- plot = self.parent()
- pos = plot.getWidgetHandle().mapFromGlobal(qt.QCursor.pos())
- data = plot.pixelToData(pos.x(), pos.y())
- if roi.contains(data):
- if isinstance(roi, roi_items.InteractionModeMixIn):
- self._contextMenuForInteractionMode(menu, roi)
-
- removeAction = qt.QAction(menu)
- removeAction.setText("Remove %s" % roi.getName())
- callback = functools.partial(self.removeRoi, roi)
- removeAction.triggered.connect(callback)
- menu.addAction(removeAction)
-
- def _contextMenuForInteractionMode(self, menu, roi):
- availableModes = roi.availableInteractionModes()
- currentMode = roi.getInteractionMode()
- submenu = qt.QMenu(menu)
- modeGroup = qt.QActionGroup(menu)
- modeGroup.setExclusive(True)
- for mode in availableModes:
- action = qt.QAction(menu)
- action.setText(mode.label)
- action.setToolTip(mode.description)
- action.setCheckable(True)
- if mode is currentMode:
- action.setChecked(True)
- else:
- callback = functools.partial(roi.setInteractionMode, mode)
- action.triggered.connect(callback)
- modeGroup.addAction(action)
- submenu.addAction(action)
- submenu.setTitle("%s interaction mode" % roi.getName())
- menu.addMenu(submenu)
+ if self._isMouseHoverRoi(roi):
+ roiMenu = self._createMenuForRoi(menu, roi)
+ menu.addMenu(roiMenu)
+
+ def _isMouseHoverRoi(self, roi: RegionOfInterest) -> bool:
+ """Check that the mouse hovers this roi"""
+ plot = self.parent()
+
+ if self._lastHoveredMarkerLabel is not None:
+ marker = plot._getMarker(self._lastHoveredMarkerLabel)
+ if marker is not None:
+ r = self.__getRoiFromMarker(marker)
+ if roi is r:
+ return True
+
+ # Filter by data position
+ # FIXME: It would be better to use GUI coords for it
+ pos = plot.getWidgetHandle().mapFromGlobal(qt.QCursor.pos())
+ data = plot.pixelToData(pos.x(), pos.y())
+ return roi.contains(data)
+
+ def _createMenuForRoi(self, parent: qt.QWidget, roi: RegionOfInterest) -> qt.QMenu:
+ """Create a QMenu for the given RegionOfInterest"""
+ roiMenu = qt.QMenu(parent)
+ roiMenu.setTitle(roi.getName())
+
+ if isinstance(roi, roi_items.InteractionModeMixIn):
+ interactionMenu = roi.createMenuForInteractionMode(roiMenu)
+ roiMenu.addMenu(interactionMenu)
+
+ removeAction = qt.QAction(roiMenu)
+ removeAction.setText("Remove")
+ callback = functools.partial(self.removeRoi, roi)
+ removeAction.triggered.connect(callback)
+ roiMenu.addAction(removeAction)
+
+ roi.populateContextMenu(roiMenu)
+
+ return roiMenu
# RegionOfInterest API
@@ -654,8 +664,7 @@ class RegionOfInterestManager(qt.QObject):
"""
if self.getRois(): # Something to reset
for roi in self._rois:
- roi.sigRegionChanged.disconnect(
- self._regionOfInterestChanged)
+ roi.sigRegionChanged.disconnect(self._regionOfInterestChanged)
roi.setParent(None)
self._rois = []
self._roisUpdated()
@@ -715,8 +724,7 @@ class RegionOfInterestManager(qt.QObject):
"""
plot = self.parent()
if plot is None:
- raise RuntimeError(
- 'Cannot add ROI: PlotWidget no more available')
+ raise RuntimeError("Cannot add ROI: PlotWidget no more available")
roi.setParent(self)
@@ -739,11 +747,12 @@ class RegionOfInterestManager(qt.QObject):
:param roi_items.RegionOfInterest roi: The ROI to remove
:raise ValueError: When ROI does not belong to this object
"""
- if not (isinstance(roi, roi_items.RegionOfInterest) and
- roi.parent() is self and
- roi in self._rois):
- raise ValueError(
- 'RegionOfInterest does not belong to this instance')
+ if not (
+ isinstance(roi, roi_items.RegionOfInterest)
+ and roi.parent() is self
+ and roi in self._rois
+ ):
+ raise ValueError("RegionOfInterest does not belong to this instance")
roi.sigAboutToBeRemoved.emit()
self.sigRoiAboutToBeRemoved.emit(roi)
@@ -834,7 +843,7 @@ class RegionOfInterestManager(qt.QObject):
self.stop()
if not issubclass(roiClass, roi_items.RegionOfInterest):
- raise ValueError('Unsupported ROI class %s' % roiClass)
+ raise ValueError("Unsupported ROI class %s" % roiClass)
plot = self.parent()
if plot is None:
@@ -859,18 +868,20 @@ class RegionOfInterestManager(qt.QObject):
plot = self.parent()
firstInteractionShapeKind = roiClass.getFirstInteractionShape()
- if firstInteractionShapeKind == 'point':
- plot.setInteractiveMode(mode='select', source=self)
+ if firstInteractionShapeKind == "point":
+ plot.setInteractiveMode(mode="select", source=self)
else:
if roiClass.showFirstInteractionShape():
color = rgba(self.getColor())
else:
color = None
- plot.setInteractiveMode(mode='select-draw',
- source=self,
- shape=firstInteractionShapeKind,
- color=color,
- label=self._label)
+ plot.setInteractiveMode(
+ mode="draw",
+ source=self,
+ shape=firstInteractionShapeKind,
+ color=color,
+ label=self._label,
+ )
def __roiInteractiveModeEnded(self):
"""Handle end of ROI draw interactive mode"""
@@ -964,7 +975,7 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
super(InteractiveRegionOfInterestManager, self).__init__(parent)
self._maxROI = None
self.__timeoutEndTime = None
- self.__message = ''
+ self.__message = ""
self.__validationMode = self.ValidationMode.ENTER
self.__execClass = None
@@ -991,11 +1002,10 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
if max_ is not None:
max_ = int(max_)
if max_ <= 0:
- raise ValueError('Max limit must be strictly positive')
+ raise ValueError("Max limit must be strictly positive")
if len(self.getRois()) > max_:
- raise ValueError(
- 'Cannot set max limit: Already too many ROIs')
+ raise ValueError("Cannot set max limit: Already too many ROIs")
self._maxROI = max_
@@ -1013,19 +1023,19 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
class ValidationMode(enum.Enum):
"""Mode of validation to leave blocking :meth:`exec`"""
- AUTO = 'auto'
+ AUTO = "auto"
"""Automatically ends the interactive mode once
the user terminates the last ROI shape."""
- ENTER = 'enter'
+ ENTER = "enter"
"""Ends the interactive mode when the *Enter* key is pressed."""
- AUTO_ENTER = 'auto_enter'
+ AUTO_ENTER = "auto_enter"
"""Ends the interactive mode when reaching max ROIs or
when the *Enter* key is pressed.
"""
- NONE = 'none'
+ NONE = "none"
"""Do not provide the user a way to end the interactive mode.
The end of :meth:`exec` is done through :meth:`quit` or timeout.
@@ -1051,9 +1061,10 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
self.__validationMode = mode
if self.isExec():
- if (self.isMaxRois() and self.getValidationMode() in
- (self.ValidationMode.AUTO,
- self.ValidationMode.AUTO_ENTER)):
+ if self.isMaxRois() and self.getValidationMode() in (
+ self.ValidationMode.AUTO,
+ self.ValidationMode.AUTO_ENTER,
+ ):
self.quit()
self.__updateMessage()
@@ -1064,17 +1075,20 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
if event.type() == qt.QEvent.KeyPress:
key = event.key()
- if (key in (qt.Qt.Key_Return, qt.Qt.Key_Enter) and
- self.getValidationMode() in (
- self.ValidationMode.ENTER,
- self.ValidationMode.AUTO_ENTER)):
+ if key in (
+ qt.Qt.Key_Return,
+ qt.Qt.Key_Enter,
+ ) and self.getValidationMode() in (
+ self.ValidationMode.ENTER,
+ self.ValidationMode.AUTO_ENTER,
+ ):
# Stop on return key pressed
self.quit()
return True # Stop further handling of this keys
- if (key in (qt.Qt.Key_Delete, qt.Qt.Key_Backspace) or (
- key == qt.Qt.Key_Z and
- event.modifiers() & qt.Qt.ControlModifier)):
+ if key in (qt.Qt.Key_Delete, qt.Qt.Key_Backspace) or (
+ key == qt.Qt.Key_Z and event.modifiers() & qt.Qt.ControlModifier
+ ):
rois = self.getRois()
if rois: # Something to undo
self.removeRoi(rois[-1])
@@ -1096,8 +1110,7 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
return self.__message
else:
remaining = self.__timeoutEndTime - time.time()
- return self.__message + (' - %d seconds remaining' %
- max(1, int(remaining)))
+ return self.__message + (" - %d seconds remaining" % max(1, int(remaining)))
# Listen to ROI updates
@@ -1110,9 +1123,10 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
self.removeRoi(self.getRois()[-2])
self.__updateMessage()
- if (self.isMaxRois() and
- self.getValidationMode() in (self.ValidationMode.AUTO,
- self.ValidationMode.AUTO_ENTER)):
+ if self.isMaxRois() and self.getValidationMode() in (
+ self.ValidationMode.AUTO,
+ self.ValidationMode.AUTO_ENTER,
+ ):
self.quit()
def __aboutToBeRemoved(self, *args, **kwargs):
@@ -1131,10 +1145,10 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
def __updateMessage(self, nbrois=None):
"""Update message"""
if not self.isExec():
- message = 'Done'
+ message = "Done"
elif not self.isStarted():
- message = 'Use %s ROI edition mode' % self.__execClass
+ message = "Use %s ROI edition mode" % self.__execClass
else:
if nbrois is None:
@@ -1144,16 +1158,18 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
max_ = self.getMaxRois()
if max_ is None:
- message = 'Select %ss (%d selected)' % (name, nbrois)
+ message = "Select %ss (%d selected)" % (name, nbrois)
elif max_ <= 1:
- message = 'Select a %s' % name
+ message = "Select a %s" % name
else:
- message = 'Select %d/%d %ss' % (nbrois, max_, name)
+ message = "Select %d/%d %ss" % (nbrois, max_, name)
- if (self.getValidationMode() == self.ValidationMode.ENTER and
- self.isMaxRois()):
- message += ' - Press Enter to confirm'
+ if (
+ self.getValidationMode() == self.ValidationMode.ENTER
+ and self.isMaxRois()
+ ):
+ message += " - Press Enter to confirm"
if message != self.__message:
self.__message = message
@@ -1164,9 +1180,11 @@ class InteractiveRegionOfInterestManager(RegionOfInterestManager):
def __timeoutUpdate(self):
"""Handle update of timeout"""
- if (self.__timeoutEndTime is not None and
- (self.__timeoutEndTime - time.time()) > 0):
- self.sigMessageChanged.emit(self.getMessage())
+ if (
+ self.__timeoutEndTime is not None
+ and (self.__timeoutEndTime - time.time()) > 0
+ ):
+ self.sigMessageChanged.emit(self.getMessage())
else: # Stop interactive mode and message timer
timer = self.sender()
if timer is not None:
@@ -1234,7 +1252,7 @@ class _DeleteRegionOfInterestToolButton(qt.QToolButton):
def __init__(self, parent, roi):
super(_DeleteRegionOfInterestToolButton, self).__init__(parent)
- self.setIcon(icons.getQIcon('remove'))
+ self.setIcon(icons.getQIcon("remove"))
self.setToolTip("Remove this ROI")
self.__roiRef = roi if roi is None else weakref.ref(roi)
self.clicked.connect(self.__clicked)
@@ -1252,11 +1270,20 @@ class _DeleteRegionOfInterestToolButton(qt.QToolButton):
class RegionOfInterestTableWidget(qt.QTableWidget):
"""Widget displaying the ROIs of a :class:`RegionOfInterestManager`"""
+ # Columns indices of the different displayed information
+ (
+ _LABEL_VISIBLE_COL,
+ _EDITABLE_COL,
+ _KIND_COL,
+ _COORDINATES_COL,
+ _DELETE_COL,
+ ) = range(5)
+
def __init__(self, parent=None):
super(RegionOfInterestTableWidget, self).__init__(parent)
self._roiManagerRef = None
- headers = ['Label', 'Edit', 'Kind', 'Coordinates', '']
+ headers = ["Label", "Edit", "Kind", "Coordinates", ""]
self.setColumnCount(len(headers))
self.setHorizontalHeaderLabels(headers)
@@ -1278,21 +1305,17 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
self.itemChanged.connect(self.__itemChanged)
def __itemChanged(self, item):
- """Handle item updates"""
+ """Handle QTableWidget item updates"""
column = item.column()
- index = item.data(qt.Qt.UserRole)
-
- if index is not None:
- manager = self.getRegionOfInterestManager()
- roi = manager.getRois()[index]
- else:
+ roi = item.data(qt.Qt.UserRole)
+ if roi is None:
return
if column == 0:
# First collect information from item, then update ROI
- # Otherwise, this causes issues issues
+ # Otherwise, this causes issues
checked = item.checkState() == qt.Qt.Checked
- text= item.text()
+ text = item.text()
roi.setVisible(checked)
roi.setName(text)
elif column == 1:
@@ -1300,7 +1323,7 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
elif column in (2, 3, 4):
pass # TODO
else:
- logger.error('Unhandled column %d', column)
+ logger.error("Unhandled column %d", column)
def setRegionOfInterestManager(self, manager):
"""Set the :class:`RegionOfInterestManager` object to sync with
@@ -1312,7 +1335,13 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
previousManager = self.getRegionOfInterestManager()
if previousManager is not None:
- previousManager.sigRoiChanged.disconnect(self._sync)
+ previousManager.sigRoiAdded.disconnect(self.__roiAdded)
+ previousManager.sigRoiAboutToBeRemoved.disconnect(
+ self.__roiAboutToBeRemoved
+ )
+ for roi in previousManager.getRois():
+ self.__disconnectRoi(roi)
+
self.setRowCount(0)
self._roiManagerRef = weakref.ref(manager)
@@ -1320,7 +1349,10 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
self._sync()
if manager is not None:
- manager.sigRoiChanged.connect(self._sync)
+ for roi in manager.getRois():
+ self.__connectRoi(roi)
+ manager.sigRoiAdded.connect(self.__roiAdded)
+ manager.sigRoiAboutToBeRemoved.connect(self.__roiAboutToBeRemoved)
def _getReadableRoiDescription(self, roi):
"""Returns modelisation of a ROI as a readable sequence of values.
@@ -1345,6 +1377,75 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
logger.debug("Backtrace", exc_info=True)
return text
+ def __connectRoi(self, roi: RegionOfInterest):
+ """Start listening ROI signals"""
+ roi.sigItemChanged.connect(self.__roiItemChanged)
+ roi.sigRegionChanged.connect(self.__roiRegionChanged)
+
+ def __disconnectRoi(self, roi: RegionOfInterest):
+ """Stop listening ROI signals"""
+ roi.sigItemChanged.disconnect(self.__roiItemChanged)
+ roi.sigRegionChanged.disconnect(self.__roiRegionChanged)
+
+ def __getRoiRow(self, roi: RegionOfInterest) -> int:
+ """Returns row index of given region of interest
+
+ :raises ValueError: If region of interest is not in the list
+ """
+ manager = self.getRegionOfInterestManager()
+ if manager is None:
+ return
+ return manager.getRois().index(roi)
+
+ def __roiAdded(self, roi: RegionOfInterest):
+ """Handle new ROI added to the manager"""
+ self.__connectRoi(roi)
+ self._sync()
+
+ def __roiAboutToBeRemoved(self, roi: RegionOfInterest):
+ """Handle removing a ROI from the manager"""
+ self.__disconnectRoi(roi)
+ self.removeRow(self.__getRoiRow(roi))
+
+ def __roiItemChanged(self, event: ItemChangedType):
+ """Handle ROI sigItemChanged events"""
+ roi = self.sender()
+ if roi is None:
+ return
+
+ try:
+ row = self.__getRoiRow(roi)
+ except ValueError:
+ return
+
+ if event == ItemChangedType.VISIBLE:
+ item = self.item(row, self._LABEL_VISIBLE_COL)
+ item.setCheckState(qt.Qt.Checked if roi.isVisible() else qt.Qt.Unchecked)
+ return
+
+ if event == ItemChangedType.NAME:
+ item = self.item(row, self._LABEL_VISIBLE_COL)
+ item.setText(roi.getName())
+ return
+
+ if event == ItemChangedType.EDITABLE:
+ item = self.item(row, self._EDITABLE_COL)
+ item.setCheckState(qt.Qt.Checked if roi.isEditable() else qt.Qt.Unchecked)
+ return
+
+ def __roiRegionChanged(self):
+ """Handle change of ROI coordinates"""
+ roi = self.sender()
+ if roi is None:
+ return
+
+ item = self.item(self.__getRoiRow(roi), self._COORDINATES_COL)
+ if item is None:
+ return
+
+ text = self._getReadableRoiDescription(roi)
+ item.setText(text)
+
def _sync(self):
"""Update widget content according to ROI manger"""
manager = self.getRegionOfInterestManager()
@@ -1360,21 +1461,19 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
baseFlags = qt.Qt.ItemIsSelectable | qt.Qt.ItemIsEnabled
# Label and visible
- label = roi.getName()
- item = qt.QTableWidgetItem(label)
+ item = qt.QTableWidgetItem()
item.setFlags(baseFlags | qt.Qt.ItemIsEditable | qt.Qt.ItemIsUserCheckable)
- item.setData(qt.Qt.UserRole, index)
- item.setCheckState(
- qt.Qt.Checked if roi.isVisible() else qt.Qt.Unchecked)
- self.setItem(index, 0, item)
+ item.setData(qt.Qt.UserRole, roi)
+ item.setText(roi.getName())
+ item.setCheckState(qt.Qt.Checked if roi.isVisible() else qt.Qt.Unchecked)
+ self.setItem(index, self._LABEL_VISIBLE_COL, item)
# Editable
item = qt.QTableWidgetItem()
item.setFlags(baseFlags | qt.Qt.ItemIsUserCheckable)
- item.setData(qt.Qt.UserRole, index)
- item.setCheckState(
- qt.Qt.Checked if roi.isEditable() else qt.Qt.Unchecked)
- self.setItem(index, 1, item)
+ item.setData(qt.Qt.UserRole, roi)
+ item.setCheckState(qt.Qt.Checked if roi.isEditable() else qt.Qt.Unchecked)
+ self.setItem(index, self._EDITABLE_COL, item)
item.setTextAlignment(qt.Qt.AlignCenter)
item.setText(None)
@@ -1385,19 +1484,18 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
label = roi.__class__.__name__
item = qt.QTableWidgetItem(label.capitalize())
item.setFlags(baseFlags)
- self.setItem(index, 2, item)
+ self.setItem(index, self._KIND_COL, item)
+ # Coordinates
item = qt.QTableWidgetItem()
item.setFlags(baseFlags)
-
- # Coordinates
text = self._getReadableRoiDescription(roi)
item.setText(text)
- self.setItem(index, 3, item)
+ self.setItem(index, self._COORDINATES_COL, item)
# Delete
- delBtn = _DeleteRegionOfInterestToolButton(None, roi)
widget = qt.QWidget(self)
+ delBtn = _DeleteRegionOfInterestToolButton(widget, roi)
layout = qt.QHBoxLayout()
layout.setContentsMargins(2, 2, 2, 2)
layout.setSpacing(0)
@@ -1405,7 +1503,7 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
layout.addStretch(1)
layout.addWidget(delBtn)
layout.addStretch(1)
- self.setCellWidget(index, 4, widget)
+ self.setCellWidget(index, self._DELETE_COL, widget)
def getRegionOfInterestManager(self):
"""Returns the :class:`RegionOfInterestManager` this widget supervise.