Skip to content
Snippets Groups Projects
Commit 66d0c250 authored by Oscar Gustafsson's avatar Oscar Gustafsson :bicyclist:
Browse files

Add typing, renaming, convenience methods/properties

parent 863e7004
No related branches found
No related tags found
No related merge requests found
Pipeline #93928 failed
This commit is part of merge request !284. Comments created here will be created in the context of that merge request.
from typing import TYPE_CHECKING, Optional, cast
from qtpy.QtCore import QPointF from qtpy.QtCore import QPointF
from qtpy.QtGui import QPainterPath, QPen from qtpy.QtGui import QPainterPath, QPen
from qtpy.QtWidgets import QGraphicsPathItem, QMenu from qtpy.QtWidgets import QGraphicsPathItem, QMenu
...@@ -5,35 +7,49 @@ from qtpy.QtWidgets import QGraphicsPathItem, QMenu ...@@ -5,35 +7,49 @@ from qtpy.QtWidgets import QGraphicsPathItem, QMenu
from b_asic.GUI._preferences import GRID, LINECOLOR, PORTHEIGHT, PORTWIDTH from b_asic.GUI._preferences import GRID, LINECOLOR, PORTHEIGHT, PORTWIDTH
from b_asic.signal import Signal from b_asic.signal import Signal
if TYPE_CHECKING:
from b_asic.GUI.drag_button import DragButton
from b_asic.GUI.main_window import MainWindow
from b_asic.GUI.port_button import PortButton
from b_asic.port import InputPort, OutputPort
class Arrow(QGraphicsPathItem): class Arrow(QGraphicsPathItem):
"""Arrow/connection in signal flow graph GUI.""" """
Arrow/connection in signal flow graph GUI.
def __init__(self, source, destination, window, signal=None, parent=None): Parameters
""" ----------
Parameters source_port_button : :class:`~b_asic.GUI.port_button.PortButton`
---------- Source port button.
source destination_port_button : :class:`~b_asic.GUI.port_button.PortButton`
Source operation. Destination port button.
destination window : :class:`~b_asic.GUI.main_window.MainWindow`
Destination operation. Window containing signal flow graph.
window signal : Signal, optional
Window containing signal flow graph. Let arrow represent *signal*.
signal : Signal, optional parent : optional
Let arrow represent *signal*. Parent.
parent : optional """
Parent.
""" def __init__(
self,
source_port_button: "PortButton",
destination_port_button: "PortButton",
window: "MainWindow",
signal: Optional[Signal] = None,
parent=None,
):
super().__init__(parent) super().__init__(parent)
self.source = source self._source_port_button = source_port_button
if signal is None: if signal is None:
signal = Signal(source.port, destination.port) signal = Signal(source_port_button.port, destination_port_button.port)
self.signal = signal self.signal = signal
self.destination = destination self._destination_port_button = destination_port_button
self._window = window self._window = window
self.moveLine() self.update_arrow()
self.source.moved.connect(self.moveLine) self._source_port_button.moved.connect(self.update_arrow)
self.destination.moved.connect(self.moveLine) self._destination_port_button.moved.connect(self.update_arrow)
def contextMenuEvent(self, event): def contextMenuEvent(self, event):
"""Open right-click menu.""" """Open right-click menu."""
...@@ -41,6 +57,54 @@ class Arrow(QGraphicsPathItem): ...@@ -41,6 +57,54 @@ class Arrow(QGraphicsPathItem):
menu.addAction("Delete", self.remove) menu.addAction("Delete", self.remove)
menu.exec_(self.cursor().pos()) menu.exec_(self.cursor().pos())
@property
def source_operation_button(self) -> "DragButton":
"""The source DragButton."""
return self._source_port_button._operation_button
@property
def destination_operation_button(self) -> "DragButton":
"""The destination DragButton."""
return self._destination_port_button._operation_button
@property
def source_operation(self) -> "Operation":
"""The source Operation."""
return self._source_port_button.operation
@property
def destination_operation(self) -> "Operation":
"""The destination Operation."""
return self._destination_port_button.operation
@property
def source_port_button(self) -> "PortButton":
"""The source PortButton."""
return self._source_port_button
@property
def destination_port_button(self) -> "PortButton":
"""The destination PortButton."""
return self._destination_port_button
@property
def source_port(self) -> "OutputPort":
"""The source OutputPort."""
return cast("OutputPort", self._source_port_button.port)
@property
def desination_port(self) -> "InputPort":
"""The destination InputPort."""
return cast("InputPort", self._destination_port_button.port)
def set_source_operation(self, source: "Operation"):
"""Set operation of the source DragButton"""
self._source_port_button._operation_button.operation = source
def set_destination_operation(self, destination: "Operation"):
"""Set operation of the destination DragButton"""
self._destination_port_button._operation_button.operation = destination
def remove(self): def remove(self):
"""Remove line and connections to signals etc.""" """Remove line and connections to signals etc."""
self.signal.remove_destination() self.signal.remove_destination()
...@@ -49,8 +113,8 @@ class Arrow(QGraphicsPathItem): ...@@ -49,8 +113,8 @@ class Arrow(QGraphicsPathItem):
if self in self._window._arrows: if self in self._window._arrows:
self._window._arrows.remove(self) self._window._arrows.remove(self)
if self in self._window._signal_ports: if self in self._window._arrow_ports:
for port1, port2 in self._window._signal_ports[self]: for port1, port2 in self._window._arrow_ports[self]:
for ( for (
operation, operation,
operation_ports, operation_ports,
...@@ -73,30 +137,39 @@ class Arrow(QGraphicsPathItem): ...@@ -73,30 +137,39 @@ class Arrow(QGraphicsPathItem):
is not self._window._operation_to_sfg[operation] is not self._window._operation_to_sfg[operation]
} }
del self._window._signal_ports[self] del self._window._arrow_ports[self]
def moveLine(self): def update_arrow(self):
""" """
Draw a line connecting ``self.source`` with ``self.destination``. Update coordinates for arrow.
Used as callback when moving operations. Used as callback when moving operations.
""" """
ORTHOGONAL = True ORTHOGONAL = True
OFFSET = 2 * PORTWIDTH OFFSET = 2 * PORTWIDTH
self.setPen(QPen(LINECOLOR, 3)) self.setPen(QPen(LINECOLOR, 3))
source_flipped = self.source.operation.is_flipped() source_flipped = self.source_operation_button.is_flipped()
destination_flipped = self.destination.operation.is_flipped() destination_flipped = self.destination_operation_button.is_flipped()
x0 = ( x0 = (
self.source.operation.x() self.source_operation_button.x()
+ self.source.x() + self.source_port_button.x()
+ (PORTWIDTH if not source_flipped else 0) + (PORTWIDTH if not source_flipped else 0)
) )
y0 = self.source.operation.y() + self.source.y() + PORTHEIGHT / 2 y0 = (
self.source_operation_button.y()
+ self.source_port_button.y()
+ PORTHEIGHT / 2
)
x1 = ( x1 = (
self.destination.operation.x() self.destination_operation_button.x()
+ self.destination.x() + self.destination_port_button.x()
+ (0 if not destination_flipped else PORTWIDTH) + (0 if not destination_flipped else PORTWIDTH)
) )
y1 = self.destination.operation.y() + self.destination.y() + PORTHEIGHT / 2 y1 = (
self.destination_operation_button.y()
+ self._destination_port_button.y()
+ PORTHEIGHT / 2
)
xmid = (x0 + x1) / 2 xmid = (x0 + x1) / 2
ymid = (y0 + y1) / 2 ymid = (y0 + y1) / 2
both_flipped = source_flipped and destination_flipped both_flipped = source_flipped and destination_flipped
......
...@@ -5,7 +5,7 @@ Contains a GUI class for drag buttons. ...@@ -5,7 +5,7 @@ Contains a GUI class for drag buttons.
""" """
import os.path import os.path
from typing import List from typing import TYPE_CHECKING, List
from qtpy.QtCore import QSize, Qt, Signal from qtpy.QtCore import QSize, Qt, Signal
from qtpy.QtGui import QIcon from qtpy.QtGui import QIcon
...@@ -18,6 +18,9 @@ from b_asic.gui_utils.decorators import decorate_class, handle_error ...@@ -18,6 +18,9 @@ from b_asic.gui_utils.decorators import decorate_class, handle_error
from b_asic.operation import Operation from b_asic.operation import Operation
from b_asic.port import InputPort from b_asic.port import InputPort
if TYPE_CHECKING:
from b_asic.GUI.main_window import MainWindow
@decorate_class(handle_error) @decorate_class(handle_error)
class DragButton(QPushButton): class DragButton(QPushButton):
...@@ -29,8 +32,11 @@ class DragButton(QPushButton): ...@@ -29,8 +32,11 @@ class DragButton(QPushButton):
Parameters Parameters
---------- ----------
operation : :class:`~b_asic.operation.Operation` operation : :class:`~b_asic.operation.Operation`
is_show_name : bool The operation that the drag button corresponds to.
window show_name : bool
Whether to show the name.
window : MainWindow
Parent MainWindow.
parent parent
""" """
...@@ -40,16 +46,15 @@ class DragButton(QPushButton): ...@@ -40,16 +46,15 @@ class DragButton(QPushButton):
def __init__( def __init__(
self, self,
operation: Operation, operation: Operation,
is_show_name: bool, show_name: bool,
window, window,
parent=None, parent=None,
): ):
self.name = operation.graph_id self.name = operation.graph_id
self.ports: List[PortButton] = [] self._ports: List[PortButton] = []
self.is_show_name = is_show_name self.show_name = show_name
self._window = window self._window = window
self.operation = operation self.operation = operation
self.clicked = 0
self.pressed = False self.pressed = False
self._m_press = False self._m_press = False
self._m_drag = False self._m_drag = False
...@@ -94,6 +99,10 @@ class DragButton(QPushButton): ...@@ -94,6 +99,10 @@ class DragButton(QPushButton):
super().mousePressEvent(event) super().mousePressEvent(event)
@property
def port_list(self) -> List[PortButton]:
return self._ports
def mouseMoveEvent(self, event): def mouseMoveEvent(self, event):
if event.buttons() == Qt.MouseButton.LeftButton and self._m_press: if event.buttons() == Qt.MouseButton.LeftButton and self._m_press:
self._m_drag = True self._m_drag = True
...@@ -133,7 +142,7 @@ class DragButton(QPushButton): ...@@ -133,7 +142,7 @@ class DragButton(QPushButton):
def _flip(self, event=None): def _flip(self, event=None):
self._flipped = not self._flipped self._flipped = not self._flipped
for pb in self.ports: for pb in self._ports:
if isinstance(pb.port, InputPort): if isinstance(pb.port, InputPort):
newx = MINBUTTONSIZE - PORTWIDTH if self._flipped else 0 newx = MINBUTTONSIZE - PORTWIDTH if self._flipped else 0
else: else:
...@@ -188,10 +197,10 @@ class DragButton(QPushButton): ...@@ -188,10 +197,10 @@ class DragButton(QPushButton):
self._window._scene.removeItem(self._window._drag_operation_scenes[self]) self._window._scene.removeItem(self._window._drag_operation_scenes[self])
_signals = [] _signals = []
for signal, ports in self._window._signal_ports.items(): for signal, ports in self._window._arrow_ports.items():
if any( if any(
map( map(
lambda port: set(port).intersection(set(self.ports)), lambda port: set(port).intersection(set(self._ports)),
ports, ports,
) )
): ):
...@@ -217,7 +226,7 @@ class DragButton(QPushButton): ...@@ -217,7 +226,7 @@ class DragButton(QPushButton):
is not self._window._operation_to_sfg[self] is not self._window._operation_to_sfg[self]
} }
for port in self._window._ports[self]: for port in self._ports:
if port in self._window._pressed_ports: if port in self._window._pressed_ports:
self._window._pressed_ports.remove(port) self._window._pressed_ports.remove(port)
...@@ -251,11 +260,11 @@ class DragButton(QPushButton): ...@@ -251,11 +260,11 @@ class DragButton(QPushButton):
port.setFixedSize(PORTWIDTH, PORTHEIGHT) port.setFixedSize(PORTWIDTH, PORTHEIGHT)
port.move(0, dist) port.move(0, dist)
port.show() port.show()
self.ports.append(port) self._ports.append(port)
for i, dist in enumerate(output_ports_dist): for i, dist in enumerate(output_ports_dist):
port = PortButton(">", self, op.output(i)) port = PortButton(">", self, op.output(i))
port.setFixedSize(PORTWIDTH, PORTHEIGHT) port.setFixedSize(PORTWIDTH, PORTHEIGHT)
port.move(MINBUTTONSIZE - PORTWIDTH, dist) port.move(MINBUTTONSIZE - PORTWIDTH, dist)
port.show() port.show()
self.ports.append(port) self._ports.append(port)
...@@ -9,7 +9,7 @@ import logging ...@@ -9,7 +9,7 @@ import logging
import os import os
import sys import sys
from collections import deque from collections import deque
from typing import Dict, List, Optional, Tuple, cast from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Tuple, cast
from qtpy.QtCore import QCoreApplication, QFileInfo, QSettings, QSize, Qt, QThread from qtpy.QtCore import QCoreApplication, QFileInfo, QSettings, QSize, Qt, QThread
from qtpy.QtGui import QCursor, QIcon, QKeySequence, QPainter from qtpy.QtGui import QCursor, QIcon, QKeySequence, QPainter
...@@ -52,6 +52,9 @@ from b_asic.signal_flow_graph import SFG ...@@ -52,6 +52,9 @@ from b_asic.signal_flow_graph import SFG
from b_asic.simulation import Simulation from b_asic.simulation import Simulation
from b_asic.special_operations import Input, Output from b_asic.special_operations import Input, Output
if TYPE_CHECKING:
from qtpy.QtWidgets import QGraphicsProxyWidget
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
QCoreApplication.setOrganizationName("Linköping University") QCoreApplication.setOrganizationName("Linköping University")
...@@ -68,24 +71,23 @@ class MainWindow(QMainWindow): ...@@ -68,24 +71,23 @@ class MainWindow(QMainWindow):
self._ui.setupUi(self) self._ui.setupUi(self)
self.setWindowIcon(QIcon("small_logo.png")) self.setWindowIcon(QIcon("small_logo.png"))
self._scene = QGraphicsScene(self) self._scene = QGraphicsScene(self)
self._operations_from_name = {} self._operations_from_name: Dict[str, Operation] = {}
self._zoom = 1 self._zoom = 1
self._sfg_name_i = 0 self._drag_operation_scenes: Dict[DragButton, "QGraphicsProxyWidget"] = {}
self._drag_operation_scenes = {}
self._drag_buttons: Dict[Operation, DragButton] = {} self._drag_buttons: Dict[Operation, DragButton] = {}
self._arrows: List[Arrow] = [] self._arrows: List[Arrow] = []
self._mouse_pressed = False self._mouse_pressed = False
self._mouse_dragging = False self._mouse_dragging = False
self._starting_port = None self._starting_port = None
self._pressed_operations = [] self._pressed_operations: List[DragButton] = []
self._ports = {} self._arrow_ports: Dict[Arrow, List[Tuple[PortButton, PortButton]]] = {}
self._signal_ports = {}
self._operation_to_sfg: Dict[DragButton, SFG] = {} self._operation_to_sfg: Dict[DragButton, SFG] = {}
self._pressed_ports = [] self._pressed_ports: List[PortButton] = []
self._sfg_dict = {} self._sfg_dict: Dict[str, SFG] = {}
self._window = self self._window = self
self._ports = {}
self._logger = logging.getLogger(__name__) self._logger = logging.getLogger(__name__)
self._plot: Dict[Simulation, PlotWindow] = dict() self._plot: Dict[Simulation, PlotWindow] = {}
# Create Graphics View # Create Graphics View
self._graphics_view = QGraphicsView(self._scene, self) self._graphics_view = QGraphicsView(self._scene, self)
...@@ -102,7 +104,7 @@ class MainWindow(QMainWindow): ...@@ -102,7 +104,7 @@ class MainWindow(QMainWindow):
# Add operations # Add operations
self._max_recent_files = 4 self._max_recent_files = 4
self._recent_files = [] self._recent_files: List[str] = []
self._recent_files_paths = deque(maxlen=self._max_recent_files) self._recent_files_paths = deque(maxlen=self._max_recent_files)
self.add_operations_from_namespace( self.add_operations_from_namespace(
...@@ -112,14 +114,16 @@ class MainWindow(QMainWindow): ...@@ -112,14 +114,16 @@ class MainWindow(QMainWindow):
b_asic.special_operations, self._ui.special_operations_list b_asic.special_operations, self._ui.special_operations_list
) )
self._shortcut_core = QShortcut(QKeySequence("Ctrl+R"), self._ui.operation_box) self._shortcut_refresh_operations = QShortcut(
self._shortcut_core.activated.connect( QKeySequence("Ctrl+R"), self._ui.operation_box
)
self._shortcut_refresh_operations.activated.connect(
self._refresh_operations_list_from_namespace self._refresh_operations_list_from_namespace
) )
self._scene.selectionChanged.connect(self._select_operations) self._scene.selectionChanged.connect(self._select_operations)
self.move_button_index = 0 self.move_button_index = 0
self.is_show_names = True self._show_names = True
self._check_show_names = QAction("Show operation names") self._check_show_names = QAction("Show operation names")
self._check_show_names.triggered.connect(self.view_operation_names) self._check_show_names.triggered.connect(self.view_operation_names)
...@@ -133,13 +137,13 @@ class MainWindow(QMainWindow): ...@@ -133,13 +137,13 @@ class MainWindow(QMainWindow):
self._ui.aboutBASIC.triggered.connect(self.display_about_page) self._ui.aboutBASIC.triggered.connect(self.display_about_page)
self._ui.keybindsBASIC.triggered.connect(self.display_keybindings_page) self._ui.keybindsBASIC.triggered.connect(self.display_keybindings_page)
self._ui.core_operations_list.itemClicked.connect( self._ui.core_operations_list.itemClicked.connect(
self.on_list_widget_item_clicked self._on_list_widget_item_clicked
) )
self._ui.special_operations_list.itemClicked.connect( self._ui.special_operations_list.itemClicked.connect(
self.on_list_widget_item_clicked self._on_list_widget_item_clicked
) )
self._ui.custom_operations_list.itemClicked.connect( self._ui.custom_operations_list.itemClicked.connect(
self.on_list_widget_item_clicked self._on_list_widget_item_clicked
) )
self._ui.save_menu.triggered.connect(self.save_work) self._ui.save_menu.triggered.connect(self.save_work)
self._ui.load_menu.triggered.connect(self.load_work) self._ui.load_menu.triggered.connect(self.load_work)
...@@ -187,13 +191,13 @@ class MainWindow(QMainWindow): ...@@ -187,13 +191,13 @@ class MainWindow(QMainWindow):
def view_operation_names(self) -> None: def view_operation_names(self) -> None:
if self._check_show_names.isChecked(): if self._check_show_names.isChecked():
self.is_show_names = True self._show_names = True
else: else:
self.is_show_names = False self._show_names = False
for operation in self._drag_operation_scenes: for operation in self._drag_operation_scenes:
operation.label.setOpacity(self.is_show_names) operation.label.setOpacity(self._show_names)
operation.is_show_name = self.is_show_names operation.show_name = self._show_names
def _save_work(self) -> None: def _save_work(self) -> None:
sfg = cast(SFG, self.sfg_widget.sfg) sfg = cast(SFG, self.sfg_widget.sfg)
...@@ -265,7 +269,7 @@ class MainWindow(QMainWindow): ...@@ -265,7 +269,7 @@ class MainWindow(QMainWindow):
self._load_sfg(sfg, positions) self._load_sfg(sfg, positions)
self._logger.info("Loaded SFG from path: " + str(module)) self._logger.info("Loaded SFG from path: " + str(module))
def _load_sfg(self, sfg, positions=None) -> None: def _load_sfg(self, sfg: SFG, positions=None) -> None:
if positions is None: if positions is None:
positions = {} positions = {}
...@@ -276,29 +280,29 @@ class MainWindow(QMainWindow): ...@@ -276,29 +280,29 @@ class MainWindow(QMainWindow):
positions[op.graph_id][-1] if op.graph_id in positions else None, positions[op.graph_id][-1] if op.graph_id in positions else None,
) )
def connect_ports(ports): def connect_ports(ports: Sequence[InputPort]):
for port in ports: for port in ports:
for signal in port.signals: for signal in port.signals:
source = [ sources = [
source source
for source in self._ports[ for source in self._drag_buttons[
self._drag_buttons[signal.source.operation] signal.source.operation
] ].port_list
if source.port is signal.source if source.port is signal.source
] ]
destination = [ destinations = [
destination destination
for destination in self._ports[ for destination in self._drag_buttons[
self._drag_buttons[signal.destination.operation] signal.destination.operation
] ].port_list
if destination.port is signal.destination if destination.port is signal.destination
] ]
if source and destination: if sources and destinations:
self._connect_button(source[0], destination[0]) self._connect_button(sources[0], destinations[0])
for port in self._pressed_ports: for pressed_port in self._pressed_ports:
port.select_port() pressed_port.select_port()
for op in sfg.split(): for op in sfg.split():
connect_ports(op.inputs) connect_ports(op.inputs)
...@@ -312,13 +316,13 @@ class MainWindow(QMainWindow): ...@@ -312,13 +316,13 @@ class MainWindow(QMainWindow):
def _create_recent_file_actions_and_menus(self): def _create_recent_file_actions_and_menus(self):
for i in range(self._max_recent_files): for i in range(self._max_recent_files):
recentFileAction = QAction(self._ui.recent_sfg) recent_file_action = QAction(self._ui.recent_sfg)
recentFileAction.setVisible(False) recent_file_action.setVisible(False)
recentFileAction.triggered.connect( recent_file_action.triggered.connect(
lambda b=0, x=recentFileAction: self._open_recent_file(x) lambda b=0, x=recent_file_action: self._open_recent_file(x)
) )
self._recent_files.append(recentFileAction) self._recent_files.append(recent_file_action)
self._ui.recent_sfg.addAction(recentFileAction) self._ui.recent_sfg.addAction(recent_file_action)
self._update_recent_file_list() self._update_recent_file_list()
...@@ -370,8 +374,7 @@ class MainWindow(QMainWindow): ...@@ -370,8 +374,7 @@ class MainWindow(QMainWindow):
self._drag_buttons.clear() self._drag_buttons.clear()
self._drag_operation_scenes.clear() self._drag_operation_scenes.clear()
self._arrows.clear() self._arrows.clear()
self._ports.clear() self._arrow_ports.clear()
self._signal_ports.clear()
self._sfg_dict.clear() self._sfg_dict.clear()
self._scene.clear() self._scene.clear()
self._logger.info("Workspace cleared.") self._logger.info("Workspace cleared.")
...@@ -379,11 +382,11 @@ class MainWindow(QMainWindow): ...@@ -379,11 +382,11 @@ class MainWindow(QMainWindow):
def create_sfg_from_toolbar(self) -> None: def create_sfg_from_toolbar(self) -> None:
inputs = [] inputs = []
outputs = [] outputs = []
for op in self._pressed_operations: for pressed_op in self._pressed_operations:
if isinstance(op.operation, Input): if isinstance(pressed_op.operation, Input):
inputs.append(op.operation) inputs.append(pressed_op.operation)
elif isinstance(op.operation, Output): elif isinstance(pressed_op.operation, Output):
outputs.append(op.operation) outputs.append(pressed_op.operation)
name, accepted = QInputDialog.getText( name, accepted = QInputDialog.getText(
self, "Create SFG", "Name: ", QLineEdit.Normal self, "Create SFG", "Name: ", QLineEdit.Normal
...@@ -436,12 +439,12 @@ class MainWindow(QMainWindow): ...@@ -436,12 +439,12 @@ class MainWindow(QMainWindow):
return False return False
try: try:
_signal_source_index = [ signal_source_index = [
source.operation.outputs.index(port) source.operation.outputs.index(port)
for port in source.operation.outputs for port in source.operation.outputs
if signal in port.signals if signal in port.signals
] ]
_signal_2_source_index = [ signal_2_source_index = [
source2.operation.outputs.index(port) source2.operation.outputs.index(port)
for port in source2.operation.outputs for port in source2.operation.outputs
if signal_2 in port.signals if signal_2 in port.signals
...@@ -450,12 +453,12 @@ class MainWindow(QMainWindow): ...@@ -450,12 +453,12 @@ class MainWindow(QMainWindow):
return False # Signal output connections not matching return False # Signal output connections not matching
try: try:
_signal_destination_index = [ signal_destination_index = [
dest.operation.inputs.index(port) dest.operation.inputs.index(port)
for port in dest.operation.inputs for port in dest.operation.inputs
if signal in port.signals if signal in port.signals
] ]
_signal_2_destination_index = [ signal_2_destination_index = [
dest2.operation.inputs.index(port) dest2.operation.inputs.index(port)
for port in dest2.operation.inputs for port in dest2.operation.inputs
if signal_2 in port.signals if signal_2 in port.signals
...@@ -464,37 +467,33 @@ class MainWindow(QMainWindow): ...@@ -464,37 +467,33 @@ class MainWindow(QMainWindow):
return False # Signal input connections not matching return False # Signal input connections not matching
return ( return (
_signal_source_index == _signal_2_source_index signal_source_index == signal_2_source_index
and _signal_destination_index == _signal_2_destination_index and signal_destination_index == signal_2_destination_index
) )
for _pressed_op in self._pressed_operations: for _pressed_op in self._pressed_operations:
for operation in sfg.operations: for operation in sfg.operations:
for input_ in operation.inputs: for input_ in operation.inputs:
for signal in input_.signals: for signal in input_.signals:
for line in self._signal_ports: for arrow in self._arrow_ports:
if check_equality(line.signal, signal): if check_equality(arrow.signal, signal):
line.source.operation.operation = ( arrow.set_source_operation(signal.source.operation)
signal.source.operation arrow.set_destination_operation(
)
line.destination.operation.operation = (
signal.destination.operation signal.destination.operation
) )
for output_ in operation.outputs: for output_ in operation.outputs:
for signal in output_.signals: for signal in output_.signals:
for line in self._signal_ports: for arrow in self._arrow_ports:
if check_equality(line.signal, signal): if check_equality(arrow.signal, signal):
line.source.operation.operation = ( arrow.set_source_operation(signal.source.operation)
signal.source.operation arrow.set_destination_operation(
)
line.destination.operation.operation = (
signal.destination.operation signal.destination.operation
) )
for op in self._pressed_operations: for pressed_op in self._pressed_operations:
op.setToolTip(sfg.name) pressed_op.setToolTip(sfg.name)
self._operation_to_sfg[op] = sfg self._operation_to_sfg[pressed_op] = sfg
self._sfg_dict[sfg.name] = sfg self._sfg_dict[sfg.name] = sfg
...@@ -541,6 +540,10 @@ class MainWindow(QMainWindow): ...@@ -541,6 +540,10 @@ class MainWindow(QMainWindow):
self.add_operations_from_namespace(namespace, self._ui.custom_operations_list) self.add_operations_from_namespace(namespace, self._ui.custom_operations_list)
def _update(self):
self._scene.update()
self._graphics_view.update()
def add_operation( def add_operation(
self, self,
op: Operation, op: Operation,
...@@ -581,7 +584,6 @@ class MainWindow(QMainWindow): ...@@ -581,7 +584,6 @@ class MainWindow(QMainWindow):
"border-color: black; border-width: 2px" "border-color: black; border-width: 2px"
) )
attr_button.add_ports() attr_button.add_ports()
self._ports[attr_button] = attr_button.ports
icon_path = os.path.join( icon_path = os.path.join(
os.path.dirname(__file__), os.path.dirname(__file__),
...@@ -608,7 +610,7 @@ class MainWindow(QMainWindow): ...@@ -608,7 +610,7 @@ class MainWindow(QMainWindow):
) )
attr_button_scene.setFlag(QGraphicsItem.ItemIsSelectable, True) attr_button_scene.setFlag(QGraphicsItem.ItemIsSelectable, True)
operation_label = QGraphicsTextItem(op.name, attr_button_scene) operation_label = QGraphicsTextItem(op.name, attr_button_scene)
if not self.is_show_names: if not self._show_names:
operation_label.setOpacity(0) operation_label.setOpacity(0)
operation_label.setTransformOriginPoint( operation_label.setTransformOriginPoint(
operation_label.boundingRect().center() operation_label.boundingRect().center()
...@@ -651,7 +653,7 @@ class MainWindow(QMainWindow): ...@@ -651,7 +653,7 @@ class MainWindow(QMainWindow):
) )
self._logger.info("Finished refreshing operation list.") self._logger.info("Finished refreshing operation list.")
def on_list_widget_item_clicked(self, item) -> None: def _on_list_widget_item_clicked(self, item) -> None:
self._create_operation_item(item) self._create_operation_item(item)
def keyPressEvent(self, event) -> None: def keyPressEvent(self, event) -> None:
...@@ -714,8 +716,8 @@ class MainWindow(QMainWindow): ...@@ -714,8 +716,8 @@ class MainWindow(QMainWindow):
self._logger.info( self._logger.info(
"Connecting: %s -> %s." "Connecting: %s -> %s."
% ( % (
source.operation.operation.type_name(), source.operation.type_name(),
destination.operation.operation.type_name(), destination.operation.type_name(),
) )
) )
try: try:
...@@ -723,18 +725,18 @@ class MainWindow(QMainWindow): ...@@ -723,18 +725,18 @@ class MainWindow(QMainWindow):
except StopIteration: except StopIteration:
arrow = Arrow(source, destination, self) arrow = Arrow(source, destination, self)
if arrow not in self._signal_ports: if arrow not in self._arrow_ports:
self._signal_ports[arrow] = [] self._arrow_ports[arrow] = []
self._signal_ports[arrow].append((source, destination)) self._arrow_ports[arrow].append((source, destination))
self._scene.addItem(arrow) self._scene.addItem(arrow)
self._arrows.append(arrow) self._arrows.append(arrow)
self.update() self.update()
def paintEvent(self, event) -> None: def paintEvent(self, event) -> None:
for signal in self._signal_ports.keys(): for arrow in self._arrow_ports:
signal.moveLine() arrow.update_arrow()
def _select_operations(self) -> None: def _select_operations(self) -> None:
selected = [button.widget() for button in self._scene.selectedItems()] selected = [button.widget() for button in self._scene.selectedItems()]
......
...@@ -9,6 +9,7 @@ from qtpy.QtWidgets import QMenu, QPushButton ...@@ -9,6 +9,7 @@ from qtpy.QtWidgets import QMenu, QPushButton
if TYPE_CHECKING: if TYPE_CHECKING:
from b_asic.GUI.drag_button import DragButton from b_asic.GUI.drag_button import DragButton
from b_asic.operation import Operation
from b_asic.port import Port from b_asic.port import Port
...@@ -19,20 +20,19 @@ class PortButton(QPushButton): ...@@ -19,20 +20,19 @@ class PortButton(QPushButton):
Parameters Parameters
---------- ----------
name : str name : str
operation : :class:`~b_asic.GUI.drag_button.DragButton` operation_button : :class:`~b_asic.GUI.drag_button.DragButton`
port : :class:`~b_asic.port.Port` port : :class:`~b_asic.port.Port`
""" """
connectionRequested = Signal(QPushButton) connectionRequested = Signal(QPushButton)
moved = Signal() moved = Signal()
def __init__(self, name: str, operation: "DragButton", port: "Port"): def __init__(self, name: str, operation_button: "DragButton", port: "Port"):
super().__init__(name, parent=operation) super().__init__(name, parent=operation_button)
self.pressed = False self.pressed = False
self._window = operation._window self._window = operation_button._window
self.port = port self.port = port
self.operation = operation self._operation_button = operation_button
self.clicked = 0
self._m_drag = False self._m_drag = False
self._m_press = False self._m_press = False
self.setAcceptDrops(True) self.setAcceptDrops(True)
...@@ -41,6 +41,11 @@ class PortButton(QPushButton): ...@@ -41,6 +41,11 @@ class PortButton(QPushButton):
self.setStyleSheet("background-color: white") self.setStyleSheet("background-color: white")
self.connectionRequested.connect(self._window._connect_callback) self.connectionRequested.connect(self._window._connect_callback)
@property
def operation(self) -> "Operation":
"""Operation associated with PortButton."""
return self._operation_button.operation
def contextMenuEvent(self, event): def contextMenuEvent(self, event):
menu = QMenu() menu = QMenu()
menu.addAction("Connect", lambda: self.connectionRequested.emit(self)) menu.addAction("Connect", lambda: self.connectionRequested.emit(self))
......
...@@ -52,7 +52,7 @@ class PropertiesWindow(QDialog): ...@@ -52,7 +52,7 @@ class PropertiesWindow(QDialog):
self._show_name_layout = QHBoxLayout() self._show_name_layout = QHBoxLayout()
self._check_show_name = QCheckBox("Show name?") self._check_show_name = QCheckBox("Show name?")
self._check_show_name.setChecked(self.operation.is_show_name) self._check_show_name.setChecked(self.operation.show_name)
self._check_show_name.setLayoutDirection(Qt.RightToLeft) self._check_show_name.setLayoutDirection(Qt.RightToLeft)
self._check_show_name.setStyleSheet("spacing: 170px") self._check_show_name.setStyleSheet("spacing: 170px")
self._show_name_layout.addWidget(self._check_show_name) self._show_name_layout.addWidget(self._check_show_name)
...@@ -155,10 +155,10 @@ class PropertiesWindow(QDialog): ...@@ -155,10 +155,10 @@ class PropertiesWindow(QDialog):
if self._check_show_name.isChecked(): if self._check_show_name.isChecked():
self.operation.label.setOpacity(1) self.operation.label.setOpacity(1)
self.operation.is_show_name = True self.operation.show_name = True
else: else:
self.operation.label.setOpacity(0) self.operation.label.setOpacity(0)
self.operation.is_show_name = False self.operation.show_name = False
self.operation.operation.set_latency_offsets( self.operation.operation.set_latency_offsets(
{ {
......
...@@ -9,7 +9,7 @@ def interleave(*args) -> List[Num]: ...@@ -9,7 +9,7 @@ def interleave(*args) -> List[Num]:
""" """
Interleave a number of arrays. Interleave a number of arrays.
For the input ``interleave([1, 2], [3, 4])``, return ``[1, 2, 3, 4]``. For the input ``interleave([1, 2], [3, 4])``, return ``[1, 3, 2, 4]``.
Parameters Parameters
---------- ----------
......
...@@ -224,7 +224,7 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch): ...@@ -224,7 +224,7 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch):
assert not widget._arrows assert not widget._arrows
# Click on first port # Click on first port
in1_port = widget._ports[widget._drag_buttons[in1]][0] in1_port = widget._drag_buttons[in1].port_list[0]
qtbot.mouseClick( qtbot.mouseClick(
in1_port, in1_port,
QtCore.Qt.MouseButton.LeftButton, QtCore.Qt.MouseButton.LeftButton,
...@@ -232,7 +232,7 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch): ...@@ -232,7 +232,7 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch):
assert len(widget._pressed_ports) == 1 assert len(widget._pressed_ports) == 1
# Click on second port # Click on second port
sqrt_in_port = widget._ports[widget._drag_buttons[sqrt]][0] sqrt_in_port = widget._drag_buttons[sqrt].port_list[0]
qtbot.mouseClick( qtbot.mouseClick(
sqrt_in_port, sqrt_in_port,
QtCore.Qt.MouseButton.LeftButton, QtCore.Qt.MouseButton.LeftButton,
...@@ -248,13 +248,13 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch): ...@@ -248,13 +248,13 @@ def test_add_operation_and_create_sfg(qtbot, monkeypatch):
assert len(widget._arrows) == 1 assert len(widget._arrows) == 1
# Click on first port # Click on first port
sqrt_out_port = widget._ports[widget._drag_buttons[sqrt]][1] sqrt_out_port = widget._drag_buttons[sqrt].port_list[1]
qtbot.mouseClick( qtbot.mouseClick(
sqrt_out_port, sqrt_out_port,
QtCore.Qt.MouseButton.LeftButton, QtCore.Qt.MouseButton.LeftButton,
) )
# Click on second port # Click on second port
out1_port = widget._ports[widget._drag_buttons[out1]][0] out1_port = widget._drag_buttons[out1].port_list[0]
qtbot.mouseClick( qtbot.mouseClick(
out1_port, out1_port,
QtCore.Qt.MouseButton.LeftButton, QtCore.Qt.MouseButton.LeftButton,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment