Skip to content

Commit

Permalink
Merge pull request #3971 from t20100/fix-plot3d
Browse files Browse the repository at this point in the history
silx.gui.plot3d.ParamTreeView: Fixed Qt6 support
  • Loading branch information
vasole authored Nov 24, 2023
2 parents 9c0463e + 83f7597 commit 7065a3a
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 79 deletions.
109 changes: 48 additions & 61 deletions src/silx/gui/plot3d/ParamTreeView.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,16 @@ class FloatEditor(_FloatEdit):
:param float value: The initial editor value
"""

valueChanged = qt.Signal(float)
"""Signal emitted when the float value has changed"""

def __init__(self, parent=None, value=None):
super(FloatEditor, self).__init__(parent, value)
self.setAlignment(qt.Qt.AlignLeft)
self.editingFinished.connect(self._emit)

def _emit(self):
self.valueChanged.emit(self.value)

value = qt.Property(float,
fget=_FloatEdit.value,
fset=_FloatEdit.setValue,
user=True,
notify=valueChanged)
valueProperty = qt.Property(
float,
fget=_FloatEdit.value,
fset=_FloatEdit.setValue,
user=True,
)
"""Qt user property of the float value this widget edits"""


Expand Down Expand Up @@ -222,14 +216,39 @@ def __init__(self, parent=None):
class BooleanEditor(qt.QCheckBox):
"""Checkbox editor for bool.
This is a QCheckBox with white background.
Wrap a QCheckBox to define a different user property with `clicked` signal.
:param parent: The widget's parent
"""

valueChanged = qt.Signal(bool)
"""Signal emitted when value is changed by the user"""

def __init__(self, parent=None):
super(BooleanEditor, self).__init__(parent)
self.setStyleSheet("background: white;")
self.setBackgroundRole(qt.QPalette.Base)
self.setAutoFillBackground(True)

layout = qt.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
self.__checkbox = qt.QCheckBox(self)
self.__checkbox.clicked.connect(self.valueChanged)
layout.addWidget(self.__checkbox)

def getValue(self) -> bool:
return self.__checkbox.isChecked()

def setValue(self, value: bool):
self.__checkbox.setChecked(value)

value = qt.Property(
bool,
fget=getValue,
fset=setValue,
user=True,
notify=valueChanged,
)
"""Qt user property of the bool value this widget edits"""


class ParameterTreeDelegate(qt.QStyledItemDelegate):
Expand All @@ -255,51 +274,22 @@ def paint(self, painter, option, index):
"""See :meth:`QStyledItemDelegate.paint`"""
data = index.data(qt.Qt.DisplayRole)

if isinstance(data, (qt.QVector3D, qt.QVector4D)):
if isinstance(data, qt.QVector3D):
text = '(x: %g; y: %g; z: %g)' % (data.x(), data.y(), data.z())
elif isinstance(data, qt.QVector4D):
text = '(%g; %g; %g; %g)' % (data.x(), data.y(), data.z(), data.w())
else:
text = ''

painter.save()
painter.setRenderHint(qt.QPainter.Antialiasing, True)

# Select palette color group
colorGroup = qt.QPalette.Inactive
if option.state & qt.QStyle.State_Active:
colorGroup = qt.QPalette.Active
if not option.state & qt.QStyle.State_Enabled:
colorGroup = qt.QPalette.Disabled

# Draw background if selected
if option.state & qt.QStyle.State_Selected:
brush = option.palette.brush(colorGroup,
qt.QPalette.Highlight)
painter.fillRect(option.rect, brush)

# Draw text
if option.state & qt.QStyle.State_Selected:
colorRole = qt.QPalette.HighlightedText
else:
colorRole = qt.QPalette.WindowText
color = option.palette.color(colorGroup, colorRole)
painter.setPen(qt.QPen(color))
painter.drawText(option.rect, qt.Qt.AlignLeft, text)

painter.restore()

# The following commented code does the same as QPainter based code
# but it does not work with PySide
# self.initStyleOption(option, index)
# option.text = text
# widget = option.widget
# style = qt.QApplication.style() if not widget else widget.style()
# style.drawControl(qt.QStyle.CE_ItemViewItem, option, painter, widget)
if not isinstance(data, (qt.QVector3D, qt.QVector4D)):
super(ParameterTreeDelegate, self).paint(painter, option, index)
return

if isinstance(data, qt.QVector3D):
text = '(x: %g; y: %g; z: %g)' % (data.x(), data.y(), data.z())
elif isinstance(data, qt.QVector4D):
text = '(%g; %g; %g; %g)' % (data.x(), data.y(), data.z(), data.w())
else:
super(ParameterTreeDelegate, self).paint(painter, option, index)
text = ''

self.initStyleOption(option, index)
option.text = text
widget = option.widget
style = qt.QApplication.style() if not widget else widget.style()
style.drawControl(qt.QStyle.CE_ItemViewItem, option, painter, widget)

def _commit(self, *args):
"""Commit data to the model from editors"""
Expand Down Expand Up @@ -484,10 +474,7 @@ def _expanded(self, index):

def dataChanged(self, topLeft, bottomRight, roles=()):
"""Handle model dataChanged signal eventually closing editors"""
if roles: # Qt 5
super(ParamTreeView, self).dataChanged(topLeft, bottomRight, roles)
else: # Qt4 compatibility
super(ParamTreeView, self).dataChanged(topLeft, bottomRight)
super(ParamTreeView, self).dataChanged(topLeft, bottomRight, roles)
if not roles or qt.Qt.UserRole in roles: # Check editorHint update
for row in range(topLeft.row(), bottomRight.row() + 1):
for column in range(topLeft.column(), bottomRight.column() + 1):
Expand Down
4 changes: 2 additions & 2 deletions src/silx/gui/plot3d/_model/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def setData(self, column, value, role):
if column == 0 and role == qt.Qt.CheckStateRole:
item = self.item()
if item is not None:
item.setVisible(value == qt.Qt.Checked)
item.setVisible(qt.Qt.CheckState(value) == qt.Qt.Checked)
return True
else:
return False
Expand Down Expand Up @@ -815,7 +815,7 @@ def data(self, column, role):
def setData(self, column, value, role):
if column == 0 and role == qt.Qt.CheckStateRole:
if self._colormap is not None:
bound = self._getBound() if value == qt.Qt.Checked else None
bound = self._getBound() if qt.Qt.CheckState(value) == qt.Qt.Checked else None
self._setBound(bound)
return True
else:
Expand Down
3 changes: 2 additions & 1 deletion src/silx/gui/plot3d/items/clipplane.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ class ClipPlane(Item3D, PlaneMixIn):
def __init__(self, parent=None):
plane = primitives.ClipPlane()
Item3D.__init__(self, parent=parent, primitive=plane)
PlaneMixIn.__init__(self, plane=plane)
PlaneMixIn.__init__(self)
self._setPlane(plane)

def __pickPreProcessing(self, context):
"""Common processing for :meth:`_pickPostProcess` and :meth:`_pickFull`
Expand Down
7 changes: 3 additions & 4 deletions src/silx/gui/plot3d/items/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ class Item3D(qt.QObject):
"""

def __init__(self, parent, primitive=None):
qt.QObject.__init__(self, parent)
qt.QObject.__init__(self)
if parent is not None:
self.setParent(parent)

if primitive is None:
primitive = scene.Group()
Expand All @@ -100,9 +102,6 @@ def __init__(self, parent, primitive=None):
self._label += u' %d' % labelIndex
self._LABEL_INDICES[self.__class__] += 1

if isinstance(parent, Item3D):
parent.sigItemChanged.connect(self.__parentItemChanged)

def setParent(self, parent):
"""Override set parent to handle root item change"""
previousParent = self.parent()
Expand Down
24 changes: 15 additions & 9 deletions src/silx/gui/plot3d/items/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ class InterpolationMixIn(ItemMixInBase):
INTERPOLATION_MODES = NEAREST_INTERPOLATION, LINEAR_INTERPOLATION
"""Supported interpolation modes for :meth:`setInterpolation`"""

def __init__(self, mode=NEAREST_INTERPOLATION, primitive=None):
self.__primitive = primitive
self.__interpolationMode = mode
def __init__(self):
self.__primitive = None
self.__interpolationMode = self.NEAREST_INTERPOLATION
self._syncPrimitiveInterpolation()

def _setPrimitive(self, primitive):
Expand Down Expand Up @@ -185,18 +185,24 @@ def _getSceneSymbol(self):
class PlaneMixIn(ItemMixInBase):
"""Mix-in class for plane items (based on PlaneInGroup primitive)"""

def __init__(self, plane):
def __init__(self):
self.__plane = None
self._setPlane(primitives.PlaneInGroup())

def _setPlane(self, plane: primitives.PlaneInGroup):
"""Set plane primitive"""
if self.__plane is not None:
self.__plane.removeListener(self._planeChanged)
self.__plane.plane.removeListener(self._planePositionChanged)

assert isinstance(plane, primitives.PlaneInGroup)
self.__plane = plane
self.__plane.alpha = 1.
self.__plane.addListener(self._planeChanged)
self.__plane.plane.addListener(self._planePositionChanged)

def _getPlane(self):
"""Returns plane primitive
:rtype: primitives.PlaneInGroup
"""
def _getPlane(self) -> primitives.PlaneInGroup:
"""Returns plane primitive"""
return self.__plane

def _planeChanged(self, source, *args, **kwargs):
Expand Down
6 changes: 4 additions & 2 deletions src/silx/gui/plot3d/items/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,14 @@ class CutPlane(Item3D, ColormapMixIn, InterpolationMixIn, PlaneMixIn):
"""

def __init__(self, parent):
plane = cutplane.CutPlane(normal=(0, 1, 0))

Item3D.__init__(self, parent=None)
ColormapMixIn.__init__(self)
InterpolationMixIn.__init__(self)
PlaneMixIn.__init__(self, plane=plane)
PlaneMixIn.__init__(self)

plane = cutplane.CutPlane(normal=(0, 1, 0))
self._setPlane(plane)

self._dataRange = None
self._data = None
Expand Down

0 comments on commit 7065a3a

Please sign in to comment.