From 3f3e52c30ef1b3d6302bb9feebde2238308666fa Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson <oscar.gustafsson@gmail.com> Date: Mon, 3 Apr 2023 19:39:02 +0200 Subject: [PATCH] Add edit method to SFG and Schedule plus typing --- b_asic/GUI/__init__.py | 4 +- b_asic/GUI/drag_button.py | 3 +- b_asic/GUI/main_window.py | 62 +++++++++++++++-------------- b_asic/gui_utils/plot_window.py | 7 +++- b_asic/schedule.py | 6 +++ b_asic/scheduler_gui/__init__.py | 4 +- b_asic/scheduler_gui/main_window.py | 24 ++++++----- b_asic/scheduler_gui/signal_item.py | 3 +- b_asic/signal_flow_graph.py | 6 +++ 9 files changed, 69 insertions(+), 50 deletions(-) diff --git a/b_asic/GUI/__init__.py b/b_asic/GUI/__init__.py index d4303b0f..61d84673 100644 --- a/b_asic/GUI/__init__.py +++ b/b_asic/GUI/__init__.py @@ -2,6 +2,6 @@ Graphical user interface for B-ASIC. """ -from b_asic.GUI.main_window import MainWindow, start_gui +from b_asic.GUI.main_window import MainWindow, start_editor -__all__ = ['MainWindow', 'start_gui'] +__all__ = ['MainWindow', 'start_editor'] diff --git a/b_asic/GUI/drag_button.py b/b_asic/GUI/drag_button.py index 3a187d9a..163a12ec 100644 --- a/b_asic/GUI/drag_button.py +++ b/b_asic/GUI/drag_button.py @@ -5,6 +5,7 @@ Contains a GUI class for drag buttons. """ import os.path +from typing import List from qtpy.QtCore import QSize, Qt, Signal from qtpy.QtGui import QIcon @@ -44,7 +45,7 @@ class DragButton(QPushButton): parent=None, ): self.name = operation.graph_id - self.ports = [] + self.ports: List[PortButton] = [] self.is_show_name = is_show_name self._window = window self.operation = operation diff --git a/b_asic/GUI/main_window.py b/b_asic/GUI/main_window.py index bc1bee7e..292c4cc7 100644 --- a/b_asic/GUI/main_window.py +++ b/b_asic/GUI/main_window.py @@ -10,7 +10,7 @@ import os import sys from collections import deque from pprint import pprint -from typing import Dict, List, Optional, Tuple +from typing import Dict, List, Optional, Tuple, cast from qtpy.QtCore import QCoreApplication, QFileInfo, QSettings, QSize, Qt from qtpy.QtGui import QCursor, QIcon, QKeySequence, QPainter @@ -199,7 +199,7 @@ class MainWindow(QMainWindow): operation.is_show_name = self.is_show_names def _save_work(self) -> None: - sfg = self.sfg_widget.sfg + sfg = cast(SFG, self.sfg_widget.sfg) file_dialog = QFileDialog() file_dialog.setDefaultSuffix(".py") module, accepted = file_dialog.getSaveFileName() @@ -401,49 +401,49 @@ class MainWindow(QMainWindow): self.logger.info("Created SFG with name: %s from selected operations." % name) def check_equality(signal: Signal, signal_2: Signal) -> bool: + source = cast(OutputPort, signal.source) + source2 = cast(OutputPort, signal_2.source) + dest = cast(InputPort, signal.destination) + dest2 = cast(InputPort, signal_2.destination) if not ( - signal.source.operation.type_name() - == signal_2.source.operation.type_name() - and signal.destination.operation.type_name() - == signal_2.destination.operation.type_name() + source.operation.type_name() == source2.operation.type_name() + and dest.operation.type_name() == dest2.operation.type_name() ): return False if ( - hasattr(signal.source.operation, "value") - and hasattr(signal_2.source.operation, "value") - and hasattr(signal.destination.operation, "value") - and hasattr(signal_2.destination.operation, "value") + hasattr(source.operation, "value") + and hasattr(source2.operation, "value") + and hasattr(dest.operation, "value") + and hasattr(dest2.operation, "value") ): if not ( - signal.source.operation.value == signal_2.source.operation.value - and signal.destination.operation.value - == signal_2.destination.operation.value + source.operation.value == source2.operation.value + and dest.operation.value == dest2.operation.value ): return False if ( - hasattr(signal.source.operation, "name") - and hasattr(signal_2.source.operation, "name") - and hasattr(signal.destination.operation, "name") - and hasattr(signal_2.destination.operation, "name") + hasattr(source.operation, "name") + and hasattr(source2.operation, "name") + and hasattr(dest.operation, "name") + and hasattr(dest2.operation, "name") ): if not ( - signal.source.operation.name == signal_2.source.operation.name - and signal.destination.operation.name - == signal_2.destination.operation.name + source.operation.name == source2.operation.name + and dest.operation.name == dest2.operation.name ): return False try: _signal_source_index = [ - signal.source.operation.outputs.index(port) - for port in signal.source.operation.outputs + source.operation.outputs.index(port) + for port in source.operation.outputs if signal in port.signals ] _signal_2_source_index = [ - signal_2.source.operation.outputs.index(port) - for port in signal_2.source.operation.outputs + source2.operation.outputs.index(port) + for port in source2.operation.outputs if signal_2 in port.signals ] except ValueError: @@ -451,13 +451,13 @@ class MainWindow(QMainWindow): try: _signal_destination_index = [ - signal.destination.operation.inputs.index(port) - for port in signal.destination.operation.inputs + dest.operation.inputs.index(port) + for port in dest.operation.inputs if signal in port.signals ] _signal_2_destination_index = [ - signal_2.destination.operation.inputs.index(port) - for port in signal_2.destination.operation.inputs + dest2.operation.inputs.index(port) + for port in dest2.operation.inputs if signal_2 in port.signals ] except ValueError: @@ -786,12 +786,14 @@ class MainWindow(QMainWindow): self._keybindings_page.show() -def start_gui(): +def start_editor(sfg: Optional[SFG] = None): app = QApplication(sys.argv) window = MainWindow() + if sfg: + window._load_sfg(sfg) window.show() sys.exit(app.exec_()) if __name__ == "__main__": - start_gui() + start_editor() diff --git a/b_asic/gui_utils/plot_window.py b/b_asic/gui_utils/plot_window.py index aa885bd5..96d6bda0 100644 --- a/b_asic/gui_utils/plot_window.py +++ b/b_asic/gui_utils/plot_window.py @@ -2,7 +2,7 @@ import re import sys -from typing import Dict, List, Optional +from typing import Dict, List, Mapping, Optional, Sequence, Union from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar @@ -21,6 +21,9 @@ from qtpy.QtWidgets import ( # QFrame,; QScrollArea,; QLineEdit,; QSizePolicy,; QVBoxLayout, ) +from b_asic.operation import ResultKey +from b_asic.types import Num + class PlotWindow(QDialog): """ @@ -38,7 +41,7 @@ class PlotWindow(QDialog): def __init__( self, - sim_result: Dict[str, List[complex]], + sim_result: Mapping[ResultKey, Sequence[Num]], sfg_name: Optional[str] = None, parent=None, ): diff --git a/b_asic/schedule.py b/b_asic/schedule.py index 6d25eac3..1cd5678e 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -314,6 +314,12 @@ class Schedule: """If the current schedule is cyclic.""" return self._cyclic + def edit(self) -> None: + """Edit schedule in GUI.""" + from b_asic.scheduler_gui.main_window import start_scheduler + + start_scheduler(self) + def increase_time_resolution(self, factor: int) -> "Schedule": """ Increase time resolution for a schedule. diff --git a/b_asic/scheduler_gui/__init__.py b/b_asic/scheduler_gui/__init__.py index 60f4de4c..a66f3c34 100644 --- a/b_asic/scheduler_gui/__init__.py +++ b/b_asic/scheduler_gui/__init__.py @@ -3,6 +3,6 @@ B-ASIC Scheduler-gui Module. Graphical user interface for B-ASIC scheduler. """ -from b_asic.scheduler_gui.main_window import MainWindow, start_gui +from b_asic.scheduler_gui.main_window import MainWindow, start_scheduler -__all__ = ['MainWindow', 'start_gui'] +__all__ = ['MainWindow', 'start_scheduler'] diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py index 7778d7b6..bf9ec33b 100644 --- a/b_asic/scheduler_gui/main_window.py +++ b/b_asic/scheduler_gui/main_window.py @@ -14,7 +14,7 @@ import webbrowser from collections import deque from copy import deepcopy from importlib.machinery import SourceFileLoader -from typing import Optional, Union, cast +from typing import List, Optional, Union, cast # Qt/qtpy import qtpy @@ -96,8 +96,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): """Schedule of an SFG with scheduled Operations.""" _scene: QGraphicsScene - _schedule: Union[Schedule, None] - _graph: Union[SchedulerItem, None] + _schedule: Optional[Schedule] + _graph: Optional[SchedulerItem] _scale: float _debug_rectangles: QGraphicsItemGroup _splitter_pos: int @@ -129,8 +129,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.menu_quit.triggered.connect(self.close) self.menu_node_info.triggered.connect(self.show_info_table) self.menu_exit_dialog.triggered.connect(self.hide_exit_dialog) - self.actionReorder.triggered.connect(self._actionReorder) - self.actionPlot_schedule.triggered.connect(self._actionTbtn) + self.actionReorder.triggered.connect(self._action_reorder) + self.actionPlot_schedule.triggered.connect(self._plot_schedule) self.splitter.splitterMoved.connect(self._splitter_moved) self.actionDocumentation.triggered.connect(self._open_documentation) self.actionAbout.triggered.connect(self._open_about_window) @@ -151,7 +151,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): # Recent files self.maxFileNr = 4 - self.recentFilesList = [] + self.recentFilesList: List[QAction] = [] self.recentFilePaths = deque(maxlen=self.maxFileNr) self.createActionsAndMenus() @@ -174,11 +174,11 @@ class MainWindow(QMainWindow, Ui_MainWindow): # Slots # ######### @Slot() - def _actionTbtn(self) -> None: + def _plot_schedule(self) -> None: # TODO: remove if self.schedule is None: return - self.schedule.plot() + self.schedule.show() if self._graph is not None: print(f"filtersChildEvents(): {self._graph.filtersChildEvents()}") # self._print_button_pressed('callback_pushButton()') @@ -189,7 +189,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): webbrowser.open_new_tab("https://da.gitlab-pages.liu.se/B-ASIC/") @Slot() - def _actionReorder(self) -> None: + def _action_reorder(self) -> None: """Callback to reorder all operations vertically based on start time.""" if self.schedule is None: return @@ -694,12 +694,14 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.updateRecentActionList() -def start_gui() -> None: +def start_scheduler(schedule: Optional[Schedule] = None) -> None: app = QApplication(sys.argv) window = MainWindow() + if schedule: + window.open(schedule) window.show() sys.exit(app.exec_()) if __name__ == "__main__": - start_gui() + start_scheduler() diff --git a/b_asic/scheduler_gui/signal_item.py b/b_asic/scheduler_gui/signal_item.py index d1d1d27a..2852a227 100644 --- a/b_asic/scheduler_gui/signal_item.py +++ b/b_asic/scheduler_gui/signal_item.py @@ -6,7 +6,7 @@ in the schedule. """ -from typing import TYPE_CHECKING, Optional, cast +from typing import TYPE_CHECKING, cast from qtpy.QtCore import QPointF from qtpy.QtGui import QPainterPath, QPen @@ -42,7 +42,6 @@ class SignalItem(QGraphicsPathItem): The parent QGraphicsItem passed to QGraphicsPathItem. """ - _path: Optional[QPainterPath] = None _src_operation: OperationItem _dest_operation: OperationItem _signal: Signal diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py index 035555d9..59e93fa6 100644 --- a/b_asic/signal_flow_graph.py +++ b/b_asic/signal_flow_graph.py @@ -1378,6 +1378,12 @@ class SFG(AbstractOperation): return Schedule(self, scheduling_algorithm="ASAP").schedule_time + def edit(self) -> None: + """Edit SFG in GUI.""" + from b_asic.GUI.main_window import start_editor + + start_editor(self) + def unfold(self, factor: int) -> "SFG": """ Unfold the SFG *factor* times. Return a new SFG without modifying the original. -- GitLab