Source code for silx.gui.widgets.OverlayMixIn
from silx.gui import qt
from silx.gui.qt import inspect as qt_inspect
from silx.gui.plot import PlotWidget
[docs]
class OverlayMixIn:
"""
MixIn class for overlay widget.
For usage examples refer to :class:`WaitingOverlay`, :class:`LabelOverlay` and :class:`ButtonOverlay`
.. warning:: Any class inheriting from this mixin must also inherit from a QWidget.
"""
def __init__(
self,
parent: qt.QWidget | None = None,
):
self._alignment: qt.Qt.AlignmentFlag = qt.Qt.AlignCenter
self._alignmentOffsets: tuple[int, int] = (0, 0)
self._registerParent(parent=parent)
def getAlignment(self) -> qt.Qt.AlignmentFlag:
return self._alignment
def setAlignment(self, alignment: qt.Qt.AlignmentFlag):
self._alignment = alignment
self._resize()
self.update()
def getAlignmentOffsets(self) -> tuple[int, int]:
return self._alignmentOffsets
def setAlignmentOffsets(self, offsets: tuple[int, int]):
self._alignmentOffsets = offsets
self._resize()
self.update()
def _listenedWidget(self, parent: qt.QWidget) -> qt.QWidget:
"""Returns widget to register event filter to according to parent"""
if isinstance(parent, PlotWidget):
return parent.getWidgetHandle()
return parent
def _backendChanged(self):
self._listenedWidget(self.parent()).installEventFilter(self)
self._resizeLater()
def _registerParent(self, parent: qt.QWidget | None):
if parent is None:
return
self._listenedWidget(parent).installEventFilter(self)
if isinstance(parent, PlotWidget):
parent.sigBackendChanged.connect(self._backendChanged)
self._resize()
def _unregisterParent(self, parent: qt.QWidget | None):
if parent is None:
return
if isinstance(parent, PlotWidget):
parent.sigBackendChanged.disconnect(self._backendChanged)
self._listenedWidget(parent).removeEventFilter(self)
def setParent(self, parent: qt.QWidget):
self._unregisterParent(self.parent())
super().setParent(parent)
self._registerParent(parent)
def _getGeometry(self) -> qt.QRect | None:
parent = self.parent()
if parent is None:
return None
overlaySize = self.sizeHint()
if isinstance(parent, PlotWidget):
offset = parent.getWidgetHandle().mapTo(parent, qt.QPoint(0, 0))
canvasLeft, canvasTop, canvasWidth, canvasHeight = (
parent.getPlotBoundsInPixels()
)
canvasLeft += offset.x()
canvasTop += offset.y()
else:
canvasWidth = parent.size().width()
canvasHeight = parent.size().height()
canvasLeft = 0
canvasTop = 0
# calculate left position
if self._alignment & qt.Qt.AlignTop:
top = canvasTop
elif self._alignment & qt.Qt.AlignBottom:
top = canvasTop + canvasHeight - overlaySize.height()
else:
top = canvasTop + (canvasHeight - overlaySize.height()) / 2
# calculate top position
if self._alignment & qt.Qt.AlignLeft:
left = canvasLeft
elif self._alignment & qt.Qt.AlignRight:
left = canvasLeft + canvasWidth - overlaySize.width()
else:
left = canvasLeft + (canvasWidth - overlaySize.width()) / 2
topLeft = qt.QPoint(
int(left + self._alignmentOffsets[0]),
int(top + self._alignmentOffsets[1]),
)
return qt.QRect(
topLeft,
overlaySize,
)
def _resize(self):
if not qt_inspect.isValid(self):
return # For _resizeLater in case the widget has been deleted
rect = self._getGeometry()
if rect is None:
return
self.setGeometry(rect)
self.raise_()
def _resizeLater(self):
qt.QTimer.singleShot(0, self._resize)
def eventFilter(self, watched: qt.QWidget, event: qt.QEvent):
if event.type() == qt.QEvent.Resize:
self._resize()
self._resizeLater() # Defer resize for the receiver to have handled it
return super().eventFilter(watched, event)