class PlotWindow(QWidget): def __init__(self, tab): super(PlotWindow, self).__init__() self.tab = tab self.allAxes = {} self.curveList = [] self.extraLines = [] self.layout = QHBoxLayout() self.graph_layout = QVBoxLayout() self.gbox_layout = QVBoxLayout() self.tabGBActor = QTabWidget() self.dateplot = DatePlot(self) self.customize = Customize(self) self.button_arrow = self.ButtonArrow() self.button_del_graph = self.ButtonDelete() self.gbox_layout.addWidget(self.dateplot) self.gbox_layout.addWidget(self.customize) self.gbox_layout.addWidget(self.tabGBActor) self.gbox_layout.addWidget(self.button_del_graph) self.layout.addLayout(self.graph_layout) self.layout.addWidget(self.button_arrow) self.layout.addLayout(self.gbox_layout) for widget in [self.dateplot, self.customize, self.tabGBActor]: widget.setMaximumWidth(400) self.setLayout(self.layout) @property def mainwindow(self): return self.tab.mainwindow @property def config(self): return self.dateplot.config @property def axes2curves(self): d = {ax: [] for ax in [None] + list(self.allAxes.values())} for curve in self.curveList: d[curve.getAxes()].append(curve) return d @property def line2Curve(self): return {curve.line: curve for curve in self.curveList} @property def axes2id(self): d = {ax: id for id, ax in self.allAxes.items()} d[None] = None return d def createGraph(self, custom): try: self.graph.close() self.graph_layout.removeWidget(self.graph) self.graph.deleteLater() except AttributeError: pass self.graph = Graph(self, custom) self.graph_layout.insertWidget(0, self.graph) def getAxes(self, newType, i=-1): for i, ax in self.allAxes.items(): try: curve = self.axes2curves[ax][0] if curve.type == newType: return ax except IndexError: return ax if i == 3: raise ValueError('No Axe available') return i + 1 def setAxes(self, allAxes): for idAxes, oldAxes in list(self.allAxes.items()): self.unsetLines(oldAxes, allAxes) self.allAxes.pop(idAxes, None) self.allAxes = allAxes def unsetLines(self, axes, newAxes): while axes.lines: line = axes.lines[0] axes.lines.remove(line) try: curve = self.line2Curve[line] curve.line = False if curve.getAxes() not in newAxes.values(): curve.setAxes(None) except KeyError: pass del line def addCurve(self, curveConf): new_curve = Curve(self, curveConf) axes = self.getAxes(new_curve.type) if isinstance(axes, int): idAxes = axes self.customize.allAxes[idAxes].checkbox.setChecked(2) axes = self.allAxes[idAxes] new_curve.setAxes(axes) self.appendCurve(new_curve) self.graph.plotCurves(new_curve) return new_curve def appendCurve(self, new_curve): self.curveList.append(new_curve) self.customize.appendRow(new_curve) def switchCurve(self, axeId, curve): ax = self.allAxes[axeId] if axeId is not None else None self.graph.switchCurve(ax, curve) def removeCurve(self, curve): self.curveList.remove(curve) self.graph.removeCurve(curve) try: checkbox = curve.checkbox checkbox.setCheckable(True) checkbox.setChecked(0) except RuntimeError: pass # Checkbox could have been already deleted def constructGroupbox(self, config): while self.tabGBActor.count(): widget = self.tabGBActor.widget(0) self.clearLayout(widget.layout()) self.tabGBActor.removeTab(0) widget.close() widget.deleteLater() sortedModule = self.sortCfg(config) for actorname in sorted(sortedModule): config = sortedModule[actorname] if config: t = TabActor(self, config) self.tabGBActor.addTab(t, actorname) def showhideConfig(self, button_arrow): if not self.tabGBActor.isHidden(): self.tabGBActor.hide() self.dateplot.hide() self.customize.hide() self.button_del_graph.hide() button_arrow.setIcon(self.mainwindow.icon_arrow_left) else: self.tabGBActor.show() self.button_del_graph.show() self.dateplot.show() self.customize.show() button_arrow.setIcon(self.mainwindow.icon_arrow_right) def ButtonDelete(self): button = QPushButton('Remove Graph') button.clicked.connect(partial(self.removeGraph, self.layout)) return button def ButtonArrow(self): button_arrow = QPushButton() button_arrow.setIcon(self.mainwindow.icon_arrow_right) button_arrow.clicked.connect(partial(self.showhideConfig, button_arrow)) button_arrow.setStyleSheet('border: 0px') return button_arrow def removeGraph(self, layout): self.clearLayout(layout) self.tab.removeGraph(self) def clearLayout(self, layout): if layout is not None: while layout.count(): item = layout.takeAt(0) widget = item.widget() if widget is not None: widget.deleteLater() else: self.clearLayout(item.layout()) def table2label(self, tablename, mergeAIT=False): for key, label in self.mainwindow.cuArms.items(): if key in tablename: return label if mergeAIT: return 'AIT' else: return tablename.split('__')[0].upper() def sortCfg(self, config): sortedDict = {} for dev in config: label = self.table2label(tablename=dev.tablename, mergeAIT=False) try: sortedDict[label].append(dev) except KeyError: sortedDict[label] = [dev] return sortedDict
class MainWindow(QMainWindow): def __init__(self, appctx, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.appctx = appctx self.setup_center_ui() self.setup_log_ui() self.setup_command_dock_ui() self.setup_menu() def setup_center_ui(self): """ Set up the central widget area, which includes: DatasetWidget LogWidget """ self.setWindowTitle(f"CLARITE v{self.appctx.VERSION}") self.setWindowIcon(QIcon(":/images/clarite_logo.png")) self.setContentsMargins(10, 10, 10, 10) # Set up the central widget splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.setMinimumSize(800, 600) self.setCentralWidget(splitter) # Add the main sections dataset_widget = DatasetWidget(parent=self) splitter.addWidget(dataset_widget) self.log_tabs = QTabWidget(parent=self) self.log_tabs.setTabPosition(QTabWidget.North) splitter.addWidget(self.log_tabs) # Set the initial sizes (and relative ratio) of the two groups splitter.setSizes([500, 100]) def setup_log_ui(self): """Add log tabs each with individual widgets""" # Normal Log info_log_widget = LogWidget(parent=self) self.appctx.signals.log_info.connect(info_log_widget.append) self.log_tabs.addTab(info_log_widget, "Info Log") # Python Log python_log_widget = LogWidget( parent=self, filetype="Python Files (*.py)", initial_log=["import clarite\n\n"], ) python_log_widget.btn_clear.setHidden( True ) # Don't allow the python log to be cleared- too tricky self.appctx.signals.log_python.connect(python_log_widget.append) self.log_tabs.addTab(python_log_widget, "Python Log") def setup_command_dock_ui(self): """ Set up the dock widgets, which includes: CommandDockWidget """ # Initialize command dock and place on the left self.command_dock_widget = CommandDockWidget(parent=self) self.addDockWidget(Qt.LeftDockWidgetArea, self.command_dock_widget) def setup_menu(self): """Set up the file menu""" # Add menubar and get a reference to it menubar = self.menuBar() # Add menus file_menu = menubar.addMenu("File") edit_menu = menubar.addMenu("Edit") view_menu = menubar.addMenu("View") help_menu = menubar.addMenu("Help") # Add to File menu exit_action = QAction("Exit", parent=self) exit_action.setShortcut("Ctrl+Q") exit_action.setStatusTip("Exit application") exit_action.triggered.connect(self.close) file_menu.addAction(exit_action) # Add to Edit menu preferences_action = QAction("Preferences", parent=self) preferences_action.setStatusTip("Edit preferences") preferences_action.triggered.connect( lambda: PreferencesDialog(parent=self.appctx.main_window).show() ) edit_menu.addAction(preferences_action) # Add to View menu view_commands_menu = view_menu.addMenu("Commands") # Show/Hide show_commands_action = self.command_dock_widget.toggleViewAction() show_commands_action.setStatusTip("Show/Hide the command dock") show_commands_action.setText("Show") view_commands_menu.addAction(show_commands_action) # Dock/Undock (These are reversed booleans since True = floating and it is displaying docked status instead) dock_commands_action = QAction("Dock", parent=self) dock_commands_action.setStatusTip("Dock/Undock the command dock") dock_commands_action.setCheckable(True) dock_commands_action.setChecked(not self.command_dock_widget.isFloating()) dock_commands_action.triggered.connect( lambda make_floating: self.command_dock_widget.setFloating( not make_floating ) ) self.command_dock_widget.topLevelChanged.connect( lambda is_floating: dock_commands_action.setChecked(not is_floating) ) view_commands_menu.addAction(dock_commands_action) showLogsButton = QAction("Logs", parent=self) showLogsButton.setStatusTip("Show the logs") showLogsButton.setCheckable(True) showLogsButton.setChecked(not self.log_tabs.isHidden()) showLogsButton.triggered.connect(self.log_tabs.setVisible) view_menu.addAction(showLogsButton) # Add to Help menu showAboutButton = QAction("About", parent=self) showAboutButton.setStatusTip("Show information about CLARITE") showAboutButton.triggered.connect( lambda: AboutDialog(parent=self.appctx.main_window).show() ) help_menu.addAction(showAboutButton) showLicenseButton = QAction("License Info", parent=self) showLicenseButton.setStatusTip("Show the license (GPLv3) for the CLARITE GUI") showLicenseButton.triggered.connect( lambda: LicenseDialog(parent=self.appctx.main_window).show() ) help_menu.addAction(showLicenseButton)