diff --git a/b_asic/GUI/__init__.py b/b_asic/GUI/__init__.py index d4303b0f33b173e76ab7f042d0aeabf0df5711f4..61d8467332aee05a21d2ac7d4e9c96db04020bf2 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 3a187d9a4b435e751628ce7df7ee7d5876654843..163a12ec117314b79b2f1df869122adaebf24578 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 bc1bee7e4f7738a389959a98ee169f6d2686247d..292c4cc7e77e7479427b490cd42e927b1daca401 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 aa885bd529383f47dfc10db0cdfcf68cd6d53d81..96d6bda00e4697b08c62171d35e124ad1e689558 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 6d25eac3643d3af7a2e5b00f7ad8123fe6a0b807..1cd5678e26eb73d36bd36ce94e13f067413d4a7d 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 60f4de4c57a56479adffd93049205be1b7523540..a66f3c344a08c410cb697209d4508b24a3ca2fad 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 7778d7b62f9c64ed6b2b9842616f5e68ff739751..bf9ec33b40f601c5631ecf19754f93466d4ded04 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 d1d1d27ad5f02f48cbeecd609820b2aa2d9cf83c..2852a227bd54eac14904f54ca2c8d7b0e7f9edd1 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 035555d9196176358a21c40062ca0256b4533e3f..59e93fa6db256ea5c89574b3237afe024bbd79f0 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.