From 4924c05321219854aad289070f5fdc04ad8007da Mon Sep 17 00:00:00 2001 From: chris garnier Date: Fri, 19 Jan 2024 15:19:01 -0800 Subject: [PATCH 1/5] updated pydm drawing line rules and rules env variable to support those rules --- pydm/widgets/drawing.py | 8 +++++--- pydm/widgets/rules.py | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pydm/widgets/drawing.py b/pydm/widgets/drawing.py index b22bd20d9..146ca77d7 100644 --- a/pydm/widgets/drawing.py +++ b/pydm/widgets/drawing.py @@ -12,7 +12,9 @@ logger = logging.getLogger(__name__) - +_penRuleProperties = {"Set Pen Color": ["penColor", QColor], + "Set Pen Style": ["penStyle", int], + "Set Pen Width": ["penWidth", float]} def deg_to_qt(deg): """ Converts from degrees to QT degrees. @@ -63,7 +65,7 @@ class PyDMDrawing(QWidget, PyDMWidget): init_channel : str, optional The channel to be used by the widget. """ - + def __init__(self, parent=None, init_channel=None): self._rotation = 0.0 self._brush = QBrush(Qt.SolidPattern) @@ -447,7 +449,7 @@ def alarm_severity_changed(self, new_alarm_severity): self.penStyle = self._original_pen_style -class PyDMDrawingLine(PyDMDrawing): +class PyDMDrawingLine(PyDMDrawing,new_properties= _penRuleProperties): """ A widget with a line drawn in it. This class inherits from PyDMDrawing. diff --git a/pydm/widgets/rules.py b/pydm/widgets/rules.py index bb7d7cf08..f0607072f 100644 --- a/pydm/widgets/rules.py +++ b/pydm/widgets/rules.py @@ -5,6 +5,7 @@ from qtpy.QtCore import QThread, QMutex, Signal from qtpy.QtWidgets import QWidget, QApplication +from qtpy.QtGui import QColor, QPainter, QBrush, QPen from ..utilities import is_qt_designer from .channel import PyDMChannel @@ -355,7 +356,7 @@ def calculate_expression(self, widget_ref, idx, rule): pass calc_vals.append(v) - eval_env = {"np": np, "ch": calc_vals} + eval_env = {"np": np, "ch": calc_vals, "QColor": QColor} eval_env.update({k: v for k, v in math.__dict__.items() if k[0] != "_"}) expression = rule["rule"]["expression"] From f17043d322786dfb0d12e2db09a2e2950461543f Mon Sep 17 00:00:00 2001 From: chris garnier Date: Fri, 19 Jan 2024 15:25:32 -0800 Subject: [PATCH 2/5] removed unused imports from add --- pydm/widgets/drawing.py | 1 - pydm/widgets/rules.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pydm/widgets/drawing.py b/pydm/widgets/drawing.py index 146ca77d7..ae8c47ea3 100644 --- a/pydm/widgets/drawing.py +++ b/pydm/widgets/drawing.py @@ -65,7 +65,6 @@ class PyDMDrawing(QWidget, PyDMWidget): init_channel : str, optional The channel to be used by the widget. """ - def __init__(self, parent=None, init_channel=None): self._rotation = 0.0 self._brush = QBrush(Qt.SolidPattern) diff --git a/pydm/widgets/rules.py b/pydm/widgets/rules.py index f0607072f..79f41891e 100644 --- a/pydm/widgets/rules.py +++ b/pydm/widgets/rules.py @@ -5,7 +5,7 @@ from qtpy.QtCore import QThread, QMutex, Signal from qtpy.QtWidgets import QWidget, QApplication -from qtpy.QtGui import QColor, QPainter, QBrush, QPen +from qtpy.QtGui import QColor from ..utilities import is_qt_designer from .channel import PyDMChannel From deccb7a99b434c9b8d45aa563f6da0f182c5589a Mon Sep 17 00:00:00 2001 From: chris garnier Date: Mon, 12 Feb 2024 14:21:25 -0800 Subject: [PATCH 3/5] added conftests --- pydm/tests/conftest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pydm/tests/conftest.py b/pydm/tests/conftest.py index 01960ade9..73a8988c6 100644 --- a/pydm/tests/conftest.py +++ b/pydm/tests/conftest.py @@ -126,6 +126,10 @@ def qapp(qapp_args): ------- An instance of PyDMApplication. """ + # Don't pass along the default app name we get from pytest-qt otherwise PyDM will misinterpret it as a ui file name + if "pytest-qt-qapp" == qapp_args[0]: + qapp_args.remove("pytest-qt-qapp") + yield PyDMApplication(use_main_window=False, *qapp_args) From 455d85ac77de147e6ff06e9a84ac9c7e877b3c44 Mon Sep 17 00:00:00 2001 From: chris garnier Date: Mon, 12 Feb 2024 14:40:13 -0800 Subject: [PATCH 4/5] ran reformatter on code --- pydm/widgets/drawing.py | 62 +++++++++++++++++++++++++++++++---------- pydm/widgets/rules.py | 18 +++++++++--- 2 files changed, 61 insertions(+), 19 deletions(-) diff --git a/pydm/widgets/drawing.py b/pydm/widgets/drawing.py index ae8c47ea3..2b86a49bd 100644 --- a/pydm/widgets/drawing.py +++ b/pydm/widgets/drawing.py @@ -12,9 +12,13 @@ logger = logging.getLogger(__name__) -_penRuleProperties = {"Set Pen Color": ["penColor", QColor], - "Set Pen Style": ["penStyle", int], - "Set Pen Width": ["penWidth", float]} +_penRuleProperties = { + "Set Pen Color": ["penColor", QColor], + "Set Pen Style": ["penStyle", int], + "Set Pen Width": ["penWidth", float], +} + + def deg_to_qt(deg): """ Converts from degrees to QT degrees. @@ -65,6 +69,7 @@ class PyDMDrawing(QWidget, PyDMWidget): init_channel : str, optional The channel to be used by the widget. """ + def __init__(self, parent=None, init_channel=None): self._rotation = 0.0 self._brush = QBrush(Qt.SolidPattern) @@ -216,11 +221,15 @@ def get_inner_max(self): origHeight = self.height() if origWidth == 0: - logger.error("Invalid width. The value must be greater than {0}".format(origWidth)) + logger.error( + "Invalid width. The value must be greater than {0}".format(origWidth) + ) return if origHeight == 0: - logger.error("Invalid height. The value must be greater than {0}".format(origHeight)) + logger.error( + "Invalid height. The value must be greater than {0}".format(origHeight) + ) return if origWidth <= origHeight: @@ -448,7 +457,7 @@ def alarm_severity_changed(self, new_alarm_severity): self.penStyle = self._original_pen_style -class PyDMDrawingLine(PyDMDrawing,new_properties= _penRuleProperties): +class PyDMDrawingLine(PyDMDrawing, new_properties=_penRuleProperties): """ A widget with a line drawn in it. This class inherits from PyDMDrawing. @@ -825,7 +834,9 @@ def draw_item(self, painter): super(PyDMDrawingImage, self).draw_item(painter) x, y, w, h = self.get_bounds(maxsize=True, force_no_pen=True) if not isinstance(self._pixmap, QMovie): - _scaled = self._pixmap.scaled(int(w), int(h), self._aspect_ratio_mode, Qt.SmoothTransformation) + _scaled = self._pixmap.scaled( + int(w), int(h), self._aspect_ratio_mode, Qt.SmoothTransformation + ) # Make sure the image is centered if smaller than the widget itself if w > _scaled.width(): logger.debug("Centering image horizontally ...") @@ -1063,7 +1074,9 @@ def draw_item(self, painter): super(PyDMDrawingArc, self).draw_item(painter) maxsize = not self.is_square() x, y, w, h = self.get_bounds(maxsize=maxsize) - painter.drawArc(QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle)) + painter.drawArc( + QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle) + ) class PyDMDrawingPie(PyDMDrawingArc): @@ -1090,7 +1103,9 @@ def draw_item(self, painter): super(PyDMDrawingPie, self).draw_item(painter) maxsize = not self.is_square() x, y, w, h = self.get_bounds(maxsize=maxsize) - painter.drawPie(QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle)) + painter.drawPie( + QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle) + ) class PyDMDrawingChord(PyDMDrawingArc): @@ -1117,7 +1132,9 @@ def draw_item(self, painter): super(PyDMDrawingChord, self).draw_item(painter) maxsize = not self.is_square() x, y, w, h = self.get_bounds(maxsize=maxsize) - painter.drawChord(QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle)) + painter.drawChord( + QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle) + ) class PyDMDrawingPolygon(PyDMDrawing): @@ -1236,17 +1253,24 @@ def p2d(pt): midpoint_x = (point1.x() + point2.x()) / 2 midpoint_y = (point1.y() + point2.y()) / 2 midpoint = QPointF(midpoint_x, midpoint_y) - points = PyDMDrawingLine._arrow_points(point1, midpoint, 6, 6) # 6 = arbitrary arrow size + points = PyDMDrawingLine._arrow_points( + point1, midpoint, 6, 6 + ) # 6 = arbitrary arrow size painter.drawPolygon(points) # Draw the arrows if self._arrow_end_point_selection and (len(self._points[1]) >= 2): - points = PyDMDrawingLine._arrow_points(p2d(self._points[1]), p2d(self._points[0]), 6, 6) + points = PyDMDrawingLine._arrow_points( + p2d(self._points[1]), p2d(self._points[0]), 6, 6 + ) painter.drawPolygon(points) if self._arrow_start_point_selection and (len(self._points[1]) >= 2): points = PyDMDrawingLine._arrow_points( - p2d(self._points[len(self._points) - 2]), p2d(self._points[len(self._points) - 1]), 6, 6 + p2d(self._points[len(self._points) - 2]), + p2d(self._points[len(self._points) - 1]), + 6, + 6, ) painter.drawPolygon(points) @@ -1288,10 +1312,18 @@ def validate_point(i, point): try: point = ast.literal_eval(point) except SyntaxError: - logger.error("point %d must be two numbers, comma-separated, received '%s'", i, pt) + logger.error( + "point %d must be two numbers, comma-separated, received '%s'", + i, + pt, + ) return if not isinstance(point, (list, tuple)) or len(point) != 2: - logger.error("point %d must be two numbers, comma-separated, received '%s'", i, pt) + logger.error( + "point %d must be two numbers, comma-separated, received '%s'", + i, + pt, + ) return try: point = list(map(float, point)) # ensure all values are float diff --git a/pydm/widgets/rules.py b/pydm/widgets/rules.py index 79f41891e..02d534264 100644 --- a/pydm/widgets/rules.py +++ b/pydm/widgets/rules.py @@ -182,9 +182,18 @@ def register(self, widget, rules): for ch_idx, ch in enumerate(channels_list): conn_cb = functools.partial(self.callback_conn, widget_ref, idx, ch_idx) - value_cb = functools.partial(self.callback_value, widget_ref, idx, ch_idx, ch["trigger"]) - enums_cb = functools.partial(self.callback_enum, widget_ref, idx, ch_idx) - c = PyDMChannel(ch["channel"], connection_slot=conn_cb, value_slot=value_cb, enum_strings_slot=enums_cb) + value_cb = functools.partial( + self.callback_value, widget_ref, idx, ch_idx, ch["trigger"] + ) + enums_cb = functools.partial( + self.callback_enum, widget_ref, idx, ch_idx + ) + c = PyDMChannel( + ch["channel"], + connection_slot=conn_cb, + value_slot=value_cb, + enum_strings_slot=enums_cb, + ) item["channels"].append(c) rules_db.append(item) @@ -367,7 +376,8 @@ def calculate_expression(self, widget_ref, idx, rule): self.emit_value(widget_ref, name, prop, val) except Exception: logger.exception( - f"Error while evaluating Rule with name: {name} and type: {prop} " f"and expression: {expression}" + f"Error while evaluating Rule with name: {name} and type: {prop} " + f"and expression: {expression}" ) def emit_value(self, widget_ref, name, prop, val): From 7e3fc6571444056fd902c4b06190db836d51ec1a Mon Sep 17 00:00:00 2001 From: chris garnier Date: Tue, 13 Feb 2024 16:35:42 -0800 Subject: [PATCH 5/5] ran pre commits --- pydm/widgets/drawing.py | 32 ++++++++------------------------ pydm/widgets/rules.py | 11 +++-------- 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/pydm/widgets/drawing.py b/pydm/widgets/drawing.py index 2b86a49bd..1ba7ea93d 100644 --- a/pydm/widgets/drawing.py +++ b/pydm/widgets/drawing.py @@ -221,15 +221,11 @@ def get_inner_max(self): origHeight = self.height() if origWidth == 0: - logger.error( - "Invalid width. The value must be greater than {0}".format(origWidth) - ) + logger.error("Invalid width. The value must be greater than {0}".format(origWidth)) return if origHeight == 0: - logger.error( - "Invalid height. The value must be greater than {0}".format(origHeight) - ) + logger.error("Invalid height. The value must be greater than {0}".format(origHeight)) return if origWidth <= origHeight: @@ -834,9 +830,7 @@ def draw_item(self, painter): super(PyDMDrawingImage, self).draw_item(painter) x, y, w, h = self.get_bounds(maxsize=True, force_no_pen=True) if not isinstance(self._pixmap, QMovie): - _scaled = self._pixmap.scaled( - int(w), int(h), self._aspect_ratio_mode, Qt.SmoothTransformation - ) + _scaled = self._pixmap.scaled(int(w), int(h), self._aspect_ratio_mode, Qt.SmoothTransformation) # Make sure the image is centered if smaller than the widget itself if w > _scaled.width(): logger.debug("Centering image horizontally ...") @@ -1074,9 +1068,7 @@ def draw_item(self, painter): super(PyDMDrawingArc, self).draw_item(painter) maxsize = not self.is_square() x, y, w, h = self.get_bounds(maxsize=maxsize) - painter.drawArc( - QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle) - ) + painter.drawArc(QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle)) class PyDMDrawingPie(PyDMDrawingArc): @@ -1103,9 +1095,7 @@ def draw_item(self, painter): super(PyDMDrawingPie, self).draw_item(painter) maxsize = not self.is_square() x, y, w, h = self.get_bounds(maxsize=maxsize) - painter.drawPie( - QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle) - ) + painter.drawPie(QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle)) class PyDMDrawingChord(PyDMDrawingArc): @@ -1132,9 +1122,7 @@ def draw_item(self, painter): super(PyDMDrawingChord, self).draw_item(painter) maxsize = not self.is_square() x, y, w, h = self.get_bounds(maxsize=maxsize) - painter.drawChord( - QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle) - ) + painter.drawChord(QRectF(x, y, w, h), int(self._start_angle), int(self._span_angle)) class PyDMDrawingPolygon(PyDMDrawing): @@ -1253,16 +1241,12 @@ def p2d(pt): midpoint_x = (point1.x() + point2.x()) / 2 midpoint_y = (point1.y() + point2.y()) / 2 midpoint = QPointF(midpoint_x, midpoint_y) - points = PyDMDrawingLine._arrow_points( - point1, midpoint, 6, 6 - ) # 6 = arbitrary arrow size + points = PyDMDrawingLine._arrow_points(point1, midpoint, 6, 6) # 6 = arbitrary arrow size painter.drawPolygon(points) # Draw the arrows if self._arrow_end_point_selection and (len(self._points[1]) >= 2): - points = PyDMDrawingLine._arrow_points( - p2d(self._points[1]), p2d(self._points[0]), 6, 6 - ) + points = PyDMDrawingLine._arrow_points(p2d(self._points[1]), p2d(self._points[0]), 6, 6) painter.drawPolygon(points) if self._arrow_start_point_selection and (len(self._points[1]) >= 2): diff --git a/pydm/widgets/rules.py b/pydm/widgets/rules.py index 02d534264..df915ffb6 100644 --- a/pydm/widgets/rules.py +++ b/pydm/widgets/rules.py @@ -182,12 +182,8 @@ def register(self, widget, rules): for ch_idx, ch in enumerate(channels_list): conn_cb = functools.partial(self.callback_conn, widget_ref, idx, ch_idx) - value_cb = functools.partial( - self.callback_value, widget_ref, idx, ch_idx, ch["trigger"] - ) - enums_cb = functools.partial( - self.callback_enum, widget_ref, idx, ch_idx - ) + value_cb = functools.partial(self.callback_value, widget_ref, idx, ch_idx, ch["trigger"]) + enums_cb = functools.partial(self.callback_enum, widget_ref, idx, ch_idx) c = PyDMChannel( ch["channel"], connection_slot=conn_cb, @@ -376,8 +372,7 @@ def calculate_expression(self, widget_ref, idx, rule): self.emit_value(widget_ref, name, prop, val) except Exception: logger.exception( - f"Error while evaluating Rule with name: {name} and type: {prop} " - f"and expression: {expression}" + f"Error while evaluating Rule with name: {name} and type: {prop} " f"and expression: {expression}" ) def emit_value(self, widget_ref, name, prop, val):