diff --git a/b_asic/GUI/arrow.py b/b_asic/GUI/arrow.py index 9fbfd53854f86c106d1e5a3ea6828ec3fc4738bc..ee0443bab33084c21d8b300aa6a31f21e6b805b5 100644 --- a/b_asic/GUI/arrow.py +++ b/b_asic/GUI/arrow.py @@ -46,8 +46,8 @@ class Arrow(QGraphicsPathItem): self.signal.remove_destination() self.signal.remove_source() self._window.scene.removeItem(self) - if self in self._window.signalList: - self._window.signalList.remove(self) + if self in self._window._arrow_list: + self._window._arrow_list.remove(self) if self in self._window.signalPortDict: for port1, port2 in self._window.signalPortDict[self]: @@ -57,18 +57,20 @@ class Arrow(QGraphicsPathItem): ) in self._window.portDict.items(): if ( port1 in operation_ports or port2 in operation_ports - ) and operation in self._window.opToSFG: + ) and operation in self._window._operation_to_sfg: self._window.logger.info( "Operation detected in existing SFG, removing SFG" " with name:" - f" {self._window.opToSFG[operation].name}." + f" {self._window._operation_to_sfg[operation].name}." ) - del self._window.sfg_dict[self._window.opToSFG[operation].name] - self._window.opToSFG = { - op: self._window.opToSFG[op] - for op in self._window.opToSFG - if self._window.opToSFG[op] - is not self._window.opToSFG[operation] + del self._window.sfg_dict[ + self._window._operation_to_sfg[operation].name + ] + self._window._operation_to_sfg = { + op: self._window._operation_to_sfg[op] + for op in self._window._operation_to_sfg + if self._window._operation_to_sfg[op] + is not self._window._operation_to_sfg[operation] } del self._window.signalPortDict[self] diff --git a/b_asic/GUI/drag_button.py b/b_asic/GUI/drag_button.py index 432477eb42c7ff1dcb6984ba996f9b1a9253fe99..3a187d9a4b435e751628ce7df7ee7d5876654843 100644 --- a/b_asic/GUI/drag_button.py +++ b/b_asic/GUI/drag_button.py @@ -10,16 +10,11 @@ from qtpy.QtCore import QSize, Qt, Signal from qtpy.QtGui import QIcon from qtpy.QtWidgets import QAction, QMenu, QPushButton -from b_asic.GUI._preferences import ( - GAP, - GRID, - MINBUTTONSIZE, - PORTHEIGHT, - PORTWIDTH, -) +from b_asic.GUI._preferences import GAP, GRID, MINBUTTONSIZE, PORTHEIGHT, PORTWIDTH from b_asic.GUI.port_button import PortButton from b_asic.GUI.properties_window import PropertiesWindow from b_asic.GUI.utils import decorate_class, handle_error +from b_asic.operation import Operation from b_asic.port import InputPort @@ -32,9 +27,8 @@ class DragButton(QPushButton): Parameters ---------- - name - operation - is_show_name + operation : :class:`~b_asic.operation.Operation` + is_show_name : bool window parent """ @@ -44,13 +38,12 @@ class DragButton(QPushButton): def __init__( self, - name, - operation, - is_show_name, + operation: Operation, + is_show_name: bool, window, parent=None, ): - self.name = name + self.name = operation.graph_id self.ports = [] self.is_show_name = is_show_name self._window = window @@ -64,22 +57,25 @@ class DragButton(QPushButton): self._flipped = False self._properties_window = None self.label = None + self._context_menu = None super().__init__(parent) def contextMenuEvent(self, event): - menu = QMenu() - properties = QAction("Properties") - menu.addAction(properties) - properties.triggered.connect(self.show_properties_window) - - delete = QAction("Delete") - menu.addAction(delete) - delete.triggered.connect(self.remove) - - flip = QAction("Flip horizontal") - menu.addAction(flip) - flip.triggered.connect(self._flip) - menu.exec_(self.cursor().pos()) + if self._context_menu is None: + menu = QMenu() + properties = QAction("Properties") + menu.addAction(properties) + properties.triggered.connect(self.show_properties_window) + + delete = QAction("Delete") + menu.addAction(delete) + delete.triggered.connect(self.remove) + + flip = QAction("Flip horizontal") + menu.addAction(flip) + flip.triggered.connect(self._flip) + self._context_menu = menu + self._context_menu.exec_(self.cursor().pos()) def show_properties_window(self, event=None): self._properties_window = PropertiesWindow(self, self._window) @@ -106,9 +102,7 @@ class DragButton(QPushButton): if button is self: continue - button.move( - button.mapToParent(event.pos() - self._mouse_press_pos) - ) + button.move(button.mapToParent(event.pos() - self._mouse_press_pos)) self._window.scene.update() self._window.graphic_view.update() @@ -187,17 +181,13 @@ class DragButton(QPushButton): else: self._window.pressed_operations.append(self) - for signal in self._window.signalList: + for signal in self._window._arrow_list: signal.update() def remove(self, event=None): """Remove button/operation from signal flow graph.""" - self._window.logger.info( - f"Removing operation with name {self.operation.name}." - ) - self._window.scene.removeItem( - self._window.dragOperationSceneDict[self] - ) + self._window.logger.info("Removing operation with name " + self.operation.name) + self._window.scene.removeItem(self._window.dragOperationSceneDict[self]) _signals = [] for signal, ports in self._window.signalPortDict.items(): @@ -208,24 +198,25 @@ class DragButton(QPushButton): ) ): self._window.logger.info( - f"Removed signal with name: {signal.signal.name} to/from" - f" operation: {self.operation.name}." + "Removed signal with name: %s to/from operation: %s." + % (signal.signal.name, self.operation.name) ) _signals.append(signal) for signal in _signals: signal.remove() - if self in self._window.opToSFG: + if self in self._window._operation_to_sfg: self._window.logger.info( - "Operation detected in existing SFG, removing SFG with name:" - f" {self._window.opToSFG[self].name}." + "Operation detected in existing SFG, removing SFG with name: " + + self._window._operation_to_sfg[self].name ) - del self._window.sfg_dict[self._window.opToSFG[self].name] - self._window.opToSFG = { - op: self._window.opToSFG[op] - for op in self._window.opToSFG - if self._window.opToSFG[op] is not self._window.opToSFG[self] + del self._window.sfg_dict[self._window._operation_to_sfg[self].name] + self._window._operation_to_sfg = { + op: self._window._operation_to_sfg[op] + for op in self._window._operation_to_sfg + if self._window._operation_to_sfg[op] + is not self._window._operation_to_sfg[self] } for port in self._window.portDict[self]: @@ -238,8 +229,8 @@ class DragButton(QPushButton): if self in self._window.dragOperationSceneDict: del self._window.dragOperationSceneDict[self] - if self.operation in self._window.operationDragDict: - del self._window.operationDragDict[self.operation] + if self.operation in self._window._operation_drag_buttons: + del self._window._operation_drag_buttons[self.operation] def add_ports(self): def _determine_port_distance(opheight, ports): @@ -258,14 +249,14 @@ class DragButton(QPushButton): output_ports_dist = _determine_port_distance(height, op.output_count) input_ports_dist = _determine_port_distance(height, op.input_count) for i, dist in enumerate(input_ports_dist): - port = PortButton(">", self, op.input(i), self._window) + port = PortButton(">", self, op.input(i)) port.setFixedSize(PORTWIDTH, PORTHEIGHT) port.move(0, dist) port.show() self.ports.append(port) for i, dist in enumerate(output_ports_dist): - port = PortButton(">", self, op.output(i), self._window) + port = PortButton(">", self, op.output(i)) port.setFixedSize(PORTWIDTH, PORTHEIGHT) port.move(MINBUTTONSIZE - PORTWIDTH, dist) port.show() diff --git a/b_asic/GUI/main_window.py b/b_asic/GUI/main_window.py index dcf10df8792d5544a77c5acb6fbdbe7626f2dd2c..240a935cd639f9a865a7b389c3560de04a7f58d4 100644 --- a/b_asic/GUI/main_window.py +++ b/b_asic/GUI/main_window.py @@ -9,7 +9,7 @@ import logging import os import sys from pprint import pprint -from typing import List, Optional, Tuple +from typing import Dict, List, Optional, Tuple from qtpy.QtCore import QFileInfo, QSize, Qt from qtpy.QtGui import QCursor, QIcon, QKeySequence, QPainter @@ -69,16 +69,15 @@ class MainWindow(QMainWindow): self.zoom = 1 self.sfg_name_i = 0 self.dragOperationSceneDict = {} - self.operationDragDict = {} - self.operationItemSceneList = [] - self.signalList = [] + self._operation_drag_buttons: Dict[Operation, DragButton] = {} + self._arrow_list: List[Arrow] = [] self.mouse_pressed = False self.mouse_dragging = False self.starting_port = [] self.pressed_operations = [] self.portDict = {} self.signalPortDict = {} - self.opToSFG = {} + self._operation_to_sfg: Dict[DragButton, SFG] = {} self.pressed_ports = [] self.sfg_dict = {} self._window = self @@ -183,7 +182,7 @@ class MainWindow(QMainWindow): else: self.is_show_names = False - for operation in self.dragOperationSceneDict.keys(): + for operation in self.dragOperationSceneDict: operation.label.setOpacity(self.is_show_names) operation.is_show_name = self.is_show_names @@ -272,14 +271,14 @@ class MainWindow(QMainWindow): source = [ source for source in self.portDict[ - self.operationDragDict[signal.source.operation] + self._operation_drag_buttons[signal.source.operation] ] if source.port is signal.source ] destination = [ destination for destination in self.portDict[ - self.operationDragDict[signal.destination.operation] + self._operation_drag_buttons[signal.destination.operation] ] if destination.port is signal.destination ] @@ -294,8 +293,8 @@ class MainWindow(QMainWindow): connect_ports(op.inputs) for op in sfg.split(): - self.operationDragDict[op].setToolTip(sfg.name) - self.opToSFG[self.operationDragDict[op]] = sfg + self._operation_drag_buttons[op].setToolTip(sfg.name) + self._operation_to_sfg[self._operation_drag_buttons[op]] = sfg self.sfg_dict[sfg.name] = sfg self.update() @@ -308,10 +307,9 @@ class MainWindow(QMainWindow): self.logger.info("Clearing workspace from operations and SFGs.") self.pressed_operations.clear() self.pressed_ports.clear() - self.operationItemSceneList.clear() - self.operationDragDict.clear() + self._operation_drag_buttons.clear() self.dragOperationSceneDict.clear() - self.signalList.clear() + self._arrow_list.clear() self.portDict.clear() self.signalPortDict.clear() self.sfg_dict.clear() @@ -436,7 +434,7 @@ class MainWindow(QMainWindow): for op in self.pressed_operations: op.setToolTip(sfg.name) - self.opToSFG[op] = sfg + self._operation_to_sfg[op] = sfg self.sfg_dict[sfg.name] = sfg @@ -495,11 +493,11 @@ class MainWindow(QMainWindow): is_flipped : bool, default: False """ try: - if op in self.operationDragDict: + if op in self._operation_drag_buttons: self.logger.warning("Multiple instances of operation with same name") return - attr_button = DragButton(op.graph_id, op, True, window=self) + attr_button = DragButton(op, True, window=self) if position is None: attr_button.move(GRID * 3, GRID * 2) else: @@ -555,7 +553,7 @@ class MainWindow(QMainWindow): if is_flipped: attr_button._flip() - self.operationDragDict[op] = attr_button + self._operation_drag_buttons[op] = attr_button self.dragOperationSceneDict[attr_button] = attr_button_scene except Exception as e: @@ -654,16 +652,16 @@ class MainWindow(QMainWindow): ) ) try: - line = Arrow(source, destination, self, signal=next(signal_exists)) + arrow = Arrow(source, destination, self, signal=next(signal_exists)) except StopIteration: - line = Arrow(source, destination, self) + arrow = Arrow(source, destination, self) - if line not in self.signalPortDict: - self.signalPortDict[line] = [] + if arrow not in self.signalPortDict: + self.signalPortDict[arrow] = [] - self.signalPortDict[line].append((source, destination)) - self.scene.addItem(line) - self.signalList.append(line) + self.signalPortDict[arrow].append((source, destination)) + self.scene.addItem(arrow) + self._arrow_list.append(arrow) self.update() diff --git a/b_asic/GUI/port_button.py b/b_asic/GUI/port_button.py index 27d3e2ca5ac34e4a704d73823c670d6ba423117f..5bb7d1a588e57e35f4de22354cacde4c498e6c52 100644 --- a/b_asic/GUI/port_button.py +++ b/b_asic/GUI/port_button.py @@ -1,10 +1,16 @@ """ B-ASIC port button module. """ +from typing import TYPE_CHECKING + from qtpy.QtCore import QMimeData, Qt, Signal from qtpy.QtGui import QDrag from qtpy.QtWidgets import QMenu, QPushButton +if TYPE_CHECKING: + from b_asic.GUI.drag_button import DragButton + from b_asic.port import Port + class PortButton(QPushButton): """ @@ -12,20 +18,18 @@ class PortButton(QPushButton): Parameters ---------- - name - operation - port - window - parent + name : str + operation : :class:`~b_asic.GUI.drag_button.DragButton` + port : :class:`~b_asic.port.Port` """ connectionRequested = Signal(QPushButton) moved = Signal() - def __init__(self, name, operation, port, window, parent=None): + def __init__(self, name: str, operation: "DragButton", port: "Port"): super().__init__(name, parent=operation) self.pressed = False - self._window = window + self._window = operation._window self.port = port self.operation = operation self.clicked = 0 @@ -49,10 +53,7 @@ class PortButton(QPushButton): super().mousePressEvent(event) def mouseReleaseEvent(self, event): - if ( - event.button() == Qt.MouseButton.LeftButton - and self._window.mouse_pressed - ): + if event.button() == Qt.MouseButton.LeftButton and self._window.mouse_pressed: self._window.mouse_pressed = False if self._window.mouse_dragging: self._window.mouse_dragging = False @@ -89,7 +90,7 @@ class PortButton(QPushButton): self.update() super().dropEvent(event) - def _toggle_port(self, pressed=False): + def _toggle_port(self, pressed: bool = False): self.pressed = not pressed self.setStyleSheet( f"background-color: {'white' if not self.pressed else 'grey'}" @@ -110,5 +111,5 @@ class PortButton(QPushButton): else: self._window.pressed_ports.append(self) - for signal in self._window.signalList: + for signal in self._window._arrow_list: signal.update() diff --git a/test/test_gui.py b/test/test_gui.py index 7e339634fbce95e1fc5da811c5a1ed83e8060194..1feca3c65b9ed9510e9e7776b01726e8e6b3060e 100644 --- a/test/test_gui.py +++ b/test/test_gui.py @@ -36,7 +36,7 @@ def test_flip(qtbot, datadir): widget._load_from_file(datadir.join('twotapfir.py')) sfg = widget.sfg_dict['twotapfir'] op = sfg.find_by_name("cmul2") - dragbutton = widget.operationDragDict[op[0]] + dragbutton = widget._operation_drag_buttons[op[0]] assert not dragbutton.is_flipped() dragbutton._flip() assert dragbutton.is_flipped() @@ -48,12 +48,12 @@ def test_sfg_invalidated_by_remove_of_operation(qtbot, datadir): qtbot.addWidget(widget) widget._load_from_file(datadir.join('twotapfir.py')) sfg = widget.sfg_dict['twotapfir'] - ops_before_remove = len(widget.operationDragDict) + ops_before_remove = len(widget._operation_drag_buttons) op = sfg.find_by_name("cmul2") - dragbutton = widget.operationDragDict[op[0]] + dragbutton = widget._operation_drag_buttons[op[0]] dragbutton.remove() assert not widget.sfg_dict - assert ops_before_remove - 1 == len(widget.operationDragDict) + assert ops_before_remove - 1 == len(widget._operation_drag_buttons) widget.exit_app() @@ -63,14 +63,14 @@ def test_sfg_invalidated_by_deleting_of_operation(qtbot, datadir): qtbot.addWidget(widget) widget._load_from_file(datadir.join('twotapfir.py')) sfg = widget.sfg_dict['twotapfir'] - ops_before_remove = len(widget.operationDragDict) + ops_before_remove = len(widget._operation_drag_buttons) op = sfg.find_by_name("cmul2") - dragbutton = widget.operationDragDict[op[0]] + dragbutton = widget._operation_drag_buttons[op[0]] # Click qtbot.mouseClick(dragbutton, QtCore.Qt.MouseButton.LeftButton) qtbot.keyClick(widget, QtCore.Qt.Key.Key_Delete) assert not widget.sfg_dict - assert ops_before_remove - 1 == len(widget.operationDragDict) + assert ops_before_remove - 1 == len(widget._operation_drag_buttons) widget.exit_app() @@ -81,7 +81,7 @@ def test_select_operation(qtbot, datadir): widget._load_from_file(datadir.join('twotapfir.py')) sfg = widget.sfg_dict['twotapfir'] op = sfg.find_by_name("cmul2")[0] - dragbutton = widget.operationDragDict[op] + dragbutton = widget._operation_drag_buttons[op] assert not dragbutton.pressed assert not widget.pressed_operations @@ -98,7 +98,7 @@ def test_select_operation(qtbot, datadir): # Select another operation op2 = sfg.find_by_name("add1")[0] - dragbutton2 = widget.operationDragDict[op2] + dragbutton2 = widget._operation_drag_buttons[op2] assert not dragbutton2.pressed # Click @@ -172,7 +172,7 @@ def test_properties_window_smoke_test(qtbot, datadir): widget._load_from_file(datadir.join('twotapfir.py')) sfg = widget.sfg_dict['twotapfir'] op = sfg.find_by_name("cmul2")[0] - dragbutton = widget.operationDragDict[op] + dragbutton = widget._operation_drag_buttons[op] dragbutton.show_properties_window() assert dragbutton._properties_window.operation == dragbutton qtbot.mouseClick(dragbutton._properties_window.ok, QtCore.Qt.MouseButton.LeftButton) @@ -187,7 +187,7 @@ def test_properties_window_change_name(qtbot, datadir): widget._load_from_file(datadir.join('twotapfir.py')) sfg = widget.sfg_dict['twotapfir'] op = sfg.find_by_name("cmul2")[0] - dragbutton = widget.operationDragDict[op] + dragbutton = widget._operation_drag_buttons[op] assert dragbutton.name == "cmul2" assert dragbutton.operation.name == "cmul2" dragbutton.show_properties_window() @@ -212,15 +212,15 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch): widget.create_operation(sqrt) widget.create_operation(out1) # Should be three operations - assert len(widget.operationDragDict) == 3 + assert len(widget._operation_drag_buttons) == 3 # These particular three for op in (in1, sqrt, out1): - assert op in widget.operationDragDict + assert op in widget._operation_drag_buttons # No signals - assert not widget.signalList + assert not widget._arrow_list # Click on first port - in1_port = widget.portDict[widget.operationDragDict[in1]][0] + in1_port = widget.portDict[widget._operation_drag_buttons[in1]][0] qtbot.mouseClick( in1_port, QtCore.Qt.MouseButton.LeftButton, @@ -228,7 +228,7 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch): assert len(widget.pressed_ports) == 1 # Click on second port - sqrt_in_port = widget.portDict[widget.operationDragDict[sqrt]][0] + sqrt_in_port = widget.portDict[widget._operation_drag_buttons[sqrt]][0] qtbot.mouseClick( sqrt_in_port, QtCore.Qt.MouseButton.LeftButton, @@ -241,16 +241,16 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch): # Not sure why this won't work # qtbot.keyClick(widget, QtCore.Qt.Key.Key_Space, delay=10) # Still one selected!? - assert len(widget.signalList) == 1 + assert len(widget._arrow_list) == 1 # Click on first port - sqrt_out_port = widget.portDict[widget.operationDragDict[sqrt]][1] + sqrt_out_port = widget.portDict[widget._operation_drag_buttons[sqrt]][1] qtbot.mouseClick( sqrt_out_port, QtCore.Qt.MouseButton.LeftButton, ) # Click on second port - out1_port = widget.portDict[widget.operationDragDict[out1]][0] + out1_port = widget.portDict[widget._operation_drag_buttons[out1]][0] qtbot.mouseClick( out1_port, QtCore.Qt.MouseButton.LeftButton, @@ -258,17 +258,17 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch): ) # Connect widget._connect_callback() - assert len(widget.signalList) == 2 + assert len(widget._arrow_list) == 2 # Select input op qtbot.mouseClick( - widget.operationDragDict[in1], + widget._operation_drag_buttons[in1], QtCore.Qt.MouseButton.LeftButton, ) # And output op qtbot.mouseClick( - widget.operationDragDict[out1], + widget._operation_drag_buttons[out1], QtCore.Qt.MouseButton.LeftButton, QtCore.Qt.KeyboardModifier.ControlModifier, )