From 869b0bdfb8e369f8e95881f1282f35c1f2f43c50 Mon Sep 17 00:00:00 2001 From: Johannes Kung <johku144@student.liu.se> Date: Thu, 4 Jul 2024 15:46:19 +0200 Subject: [PATCH] Added a signal viewer graphics item --- src/simudator/gui/gui.py | 20 ++++++- src/simudator/gui/signal_viewer.py | 84 ++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 src/simudator/gui/signal_viewer.py diff --git a/src/simudator/gui/gui.py b/src/simudator/gui/gui.py index 48297b3..a5a30b1 100644 --- a/src/simudator/gui/gui.py +++ b/src/simudator/gui/gui.py @@ -24,16 +24,18 @@ from qtpy.QtWidgets import ( ) from simudator.core.processor import Processor +from simudator.core.signal import Signal from simudator.gui.breakpoint_window import BreakpointWindow from simudator.gui.cpu_graphics_scene import CpuGraphicsScene from simudator.gui.custom_toolbar import CustomToolBar from simudator.gui.dialogs.lambda_breakpoint_dialog import LambdaBreakpointDialog from simudator.gui.module_graphics_item.module_graphics_item import ModuleGraphicsItem from simudator.gui.orientation import Orientation +from simudator.gui.pipeline import PipeLine from simudator.gui.port_graphics_item import PortGraphicsItem from simudator.gui.run_continuously_thread import RunThread from simudator.gui.signal_graphics_item import SignalGraphicsItem -from simudator.gui.pipeline import PipeLine +from simudator.gui.signal_viewer import SignalViewer class View(QGraphicsView): @@ -363,7 +365,7 @@ class GUI(QMainWindow): signal.connect(self.updateCpuClockCycle) def init_pipeline(self) -> None: - """Initialize the pipeline diagram. + """Initialize the pipeline diagram. Sets its height, width and instructions. """ @@ -987,6 +989,20 @@ class GUI(QMainWindow): """ self.cpu_graphics_scene.addAllSignals() + def add_signal_viewer(self, signal: Signal, label: str | None = None) -> None: + """ + Add a signal viewer to the graphics scene. + + Parameters + ---------- + signal : Signal + Processor signal to view. + label : str | None + Optional label of the signal viewer. + """ + viewer = SignalViewer(signal, label) + self.cpu_graphics_scene.addItem(viewer) + if __name__ == '__main__': QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) diff --git a/src/simudator/gui/signal_viewer.py b/src/simudator/gui/signal_viewer.py new file mode 100644 index 0000000..3c00b00 --- /dev/null +++ b/src/simudator/gui/signal_viewer.py @@ -0,0 +1,84 @@ +from qtpy.QtCore import QPointF, QRectF, Qt +from qtpy.QtCore import Signal as pyqtSignal +from qtpy.QtCore import Slot +from qtpy.QtGui import QPainter, QPainterPath, QPainterPathStroker, QPalette, QPen +from qtpy.QtWidgets import ( + QGraphicsItem, + QGraphicsWidget, + QStyleOptionGraphicsItem, + QWidget, +) + +from simudator.core.signal import Signal + + +class SignalViewer(QGraphicsWidget): + DEFAULT_WIDTH = 50 + DEFAULT_HEIGHT = 50 + + def __init__( + self, + signal: Signal, + label: str | None = None, + parent: QGraphicsItem | None = None, + flags: Qt.WindowFlags | Qt.WindowType = Qt.WindowFlags(), + ) -> None: + super().__init__(parent, flags) + self._signal = signal + self._label = label + self._width: int = SignalViewer.DEFAULT_WIDTH + self._height: int = SignalViewer.DEFAULT_HEIGHT + self.outline_width: float = 1 + self.setFlag(QGraphicsItem.ItemIsMovable) + self.setFiltersChildEvents(False) + + def paint( + self, + painter: QPainter | None = None, + option: QStyleOptionGraphicsItem | None = None, + widget: QWidget | None = None, + ) -> None: + painter.save() + + # Draw outline of the items shape with fill + palette: QPalette = option.palette + pen = QPen(palette.color(QPalette.ColorRole.Dark)) + brush = palette.brush(QPalette.ColorRole.Base) + painter.setPen(pen) + painter.setBrush(brush) + painter.drawPath(self.shape()) + + # Draw label if any + value_height_offset = self._height / 2 + if self._label is not None: + # TODO: Proper positioning on the y-axis + x_pos = self._width / 2 - len(self._label) * 3 + text_pos = QPointF(x_pos, self._height / 3) + painter.setPen(palette.text().color()) + painter.setBrush(palette.text()) + painter.drawText(text_pos, self._label) + value_height_offset = self._height * 2 / 3 + + # Draw signal value + # TODO: Proper positioning on the y-axis + text_pos = QPointF(0, value_height_offset) + painter.setPen(palette.text().color()) + painter.setBrush(palette.text()) + painter.drawText(text_pos, str(self._signal.get_value())) + + painter.restore() + + @Slot() + def update(self, rect: QRectF | None = None): + super().update() + + def shape(self) -> QPainterPath: + path = QPainterPath() + path.addRect(0, 0, self._width, self._height) + # outline_painter = QPainterPathStroker() + # outline_painter.setWidth(self.outline_width) + # return outline_painter.createStroke(path) + return path + + def boundingRect(self) -> QRectF: + return QRectF(0, 0, self._width, self._height) -- GitLab