File indexing completed on 2025-01-18 09:12:06
0001 import matplotlib
0002
0003 matplotlib.use("QtAgg")
0004
0005 from PyQt5 import QtCore, QtWidgets, QtGui
0006
0007 from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg, NavigationToolbar2QT
0008 from matplotlib.figure import Figure
0009 import matplotlib.pyplot as plt
0010
0011 from PyQt5 import QtCore, QtWidgets
0012
0013
0014 class MatplotlibWidget(QtWidgets.QWidget):
0015 """
0016 This widget is supposed to support a processor that renders its output to
0017 a matplotlib figure.
0018 For performance reasons, it only renders the content if the widget is_active.
0019 """
0020
0021 def __init__(self, processor, parent=None):
0022 super(MatplotlibWidget, self).__init__()
0023 self.processor = processor
0024 self.fig, self.axes = processor.get_figure_axes()
0025
0026 self.canvas = FigureCanvasQTAgg(self.fig)
0027 toolbar = NavigationToolbar2QT(self.canvas, self)
0028
0029 self.layout = QtWidgets.QVBoxLayout()
0030 self.layout.addWidget(toolbar)
0031 self.layout.addWidget(self.canvas)
0032 self.setLayout(self.layout)
0033
0034 self.is_active = False
0035
0036 def change_step(self, step):
0037 try:
0038 for ax in self.axes.flatten():
0039 ax.cla()
0040 except:
0041 self.axes.cla()
0042
0043 if self.is_active:
0044 self.processor.draw(self.fig, self.axes, step)
0045 self.canvas.draw()
0046
0047
0048 class LogWidget(QtWidgets.QTextEdit):
0049 """
0050 This is a widget dedicated to rendering the log
0051 of a certain step.
0052 """
0053
0054 def __init__(self, steps, parent=None):
0055 super(LogWidget, self).__init__()
0056 self.steps = steps
0057
0058 font = QtGui.QFont()
0059 font.setFamily("monospace [Consolas]")
0060 font.setFixedPitch(True)
0061 font.setStyleHint(QtGui.QFont.TypeWriter)
0062
0063 self.setFont(font)
0064 self.setReadOnly(True)
0065 self.setLineWrapMode(QtWidgets.QTextEdit.NoWrap)
0066
0067 def change_step(self, step):
0068 if step >= len(self.steps):
0069 self.setText(f"Error: cannot display log for step {step}")
0070 else:
0071 self.setText("".join(self.steps[step]))
0072
0073
0074 class MainWindow(QtWidgets.QWidget):
0075 """
0076 This is the main window. It sets the gui up etc.
0077 Most importantly, it calls .step_changed() on the active tab-widget
0078 if the step-slider has changed
0079 """
0080
0081 def __init__(self, processors, steps, *args, **kwargs):
0082 super(MainWindow, self).__init__(*args, **kwargs)
0083 self.setWindowTitle("GSF Debugger")
0084
0085 layout = QtWidgets.QVBoxLayout()
0086
0087
0088 self.label = QtWidgets.QLabel("step: 0", self)
0089 layout.addWidget(self.label)
0090
0091
0092 self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
0093 self.slider.setMinimum(0)
0094 self.slider.setMaximum(len(steps))
0095 self.slider.valueChanged.connect(self.step_changed)
0096
0097 def disable():
0098 for p in self.processor_widgets:
0099 if hasattr(p, "is_active"):
0100 p.is_active = False
0101
0102 self.slider.sliderPressed.connect(disable)
0103
0104 def switch(i=None):
0105 if i is None:
0106 i = self.tabs.currentIndex()
0107 for p in self.processor_widgets:
0108 if hasattr(p, "is_active"):
0109 p.is_active = False
0110 if hasattr(self.processor_widgets[i], "is_active"):
0111 self.processor_widgets[i].is_active = True
0112 self.step_changed()
0113
0114 self.slider.sliderReleased.connect(switch)
0115
0116 def bwd():
0117 self.slider.setValue(max(self.slider.value() - 1, 0))
0118 self.step_changed()
0119
0120 bwdBtn = QtWidgets.QPushButton("-")
0121 bwdBtn.pressed.connect(bwd)
0122
0123 def fwd():
0124 self.slider.setValue(min(self.slider.value() + 1, len(steps)))
0125 self.step_changed()
0126
0127 fwdBtn = QtWidgets.QPushButton("+")
0128 fwdBtn.pressed.connect(fwd)
0129
0130 hlayout = QtWidgets.QHBoxLayout()
0131 hlayout.addWidget(bwdBtn, 1)
0132 hlayout.addWidget(self.slider, 18)
0133 hlayout.addWidget(fwdBtn, 1)
0134
0135 layout.addLayout(hlayout)
0136
0137
0138 self.processor_widgets = []
0139 self.tabs = QtWidgets.QTabWidget(self)
0140 for p in processors:
0141 self.processor_widgets.append(MatplotlibWidget(p))
0142 self.tabs.addTab(self.processor_widgets[-1], p.name())
0143
0144 self.processor_widgets.append(LogWidget(steps))
0145 self.tabs.addTab(self.processor_widgets[-1], "Log")
0146 self.tabs.currentChanged.connect(switch)
0147
0148 layout.addWidget(self.tabs)
0149
0150
0151 switch(0)
0152 self.step_changed()
0153
0154
0155 self.setLayout(layout)
0156 self.show()
0157
0158 def step_changed(self):
0159 self.label.setText(f"step: {self.slider.value()}")
0160 for w in self.processor_widgets:
0161 w.change_step(self.slider.value())