From 7c94e73be7e825b1e5bc98f283efdcc10dd021de Mon Sep 17 00:00:00 2001 From: Olle Hansson <olle.hansson@liu.se> Date: Wed, 15 Feb 2023 08:58:32 +0100 Subject: [PATCH] Closes #128, #134, #138. Working on #136 --- b_asic/GUI/main_window.py | 26 +++++- b_asic/GUI/simulate_sfg_window.py | 149 +++++++++++++++++++++++++----- 2 files changed, 151 insertions(+), 24 deletions(-) diff --git a/b_asic/GUI/main_window.py b/b_asic/GUI/main_window.py index 34cd0d34..3a4633af 100644 --- a/b_asic/GUI/main_window.py +++ b/b_asic/GUI/main_window.py @@ -65,6 +65,8 @@ class MainWindow(QMainWindow): self.operationDragDict = {} self.operationItemSceneList = [] self.signalList = [] + self.mouse_pressed = False + self.mouse_draggin = False self.pressed_operations = [] self.portDict = {} self.signalPortDict = {} @@ -191,6 +193,7 @@ class MainWindow(QMainWindow): operation_positions[op_drag.operation.graph_id] = ( int(op_scene.x()), int(op_scene.y()), + op_drag.is_flipped(), ) try: @@ -251,10 +254,17 @@ class MainWindow(QMainWindow): if positions is None: positions = {} + # print(sfg) for op in sfg.split(): + # print(op) self.create_operation( op, - positions[op.graph_id] if op.graph_id in positions else None, + positions[op.graph_id][0:2] + 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): @@ -484,8 +494,14 @@ class MainWindow(QMainWindow): namespace, self.ui.custom_operations_list ) - def create_operation(self, op, position=None): + def create_operation(self, op, position=None, is_flipped=False): try: + if op in self.operationDragDict: + self.logger.warning( + "Multiple instances of operation with same name" + ) + return + attr_button = DragButton(op.graph_id, op, True, window=self) if position is None: attr_button.move(GRID * 3, GRID * 2) @@ -537,8 +553,14 @@ class MainWindow(QMainWindow): ) operation_label.moveBy(10, -20) attr_button.add_label(operation_label) + + if isinstance(is_flipped, bool): + if is_flipped: + attr_button._flip() + self.operationDragDict[op] = attr_button self.dragOperationSceneDict[attr_button] = attr_button_scene + except Exception as e: self.logger.error( "Unexpected error occurred while creating operation: " + str(e) diff --git a/b_asic/GUI/simulate_sfg_window.py b/b_asic/GUI/simulate_sfg_window.py index 8989d75d..9a7429de 100644 --- a/b_asic/GUI/simulate_sfg_window.py +++ b/b_asic/GUI/simulate_sfg_window.py @@ -1,6 +1,7 @@ """ B-ASIC window to simulate an SFG. """ +import numpy as np from matplotlib.backends.backend_qt5agg import ( FigureCanvasQTAgg as FigureCanvas, ) @@ -9,6 +10,7 @@ from qtpy.QtCore import Qt, Signal from qtpy.QtGui import QKeySequence from qtpy.QtWidgets import ( QCheckBox, + QComboBox, QDialog, QFileDialog, QFormLayout, @@ -24,6 +26,8 @@ from qtpy.QtWidgets import ( QVBoxLayout, ) +from b_asic.signal_generator import Impulse, Step, ZeroPad + class SimulateSFGWindow(QDialog): simulate = Signal() @@ -42,6 +46,8 @@ class SimulateSFGWindow(QDialog): self.simulate_btn.clicked.connect(self.save_properties) self.dialog_layout.addWidget(self.simulate_btn) self.setLayout(self.dialog_layout) + self.input_grid = QGridLayout() + self.input_files = {} def add_sfg_to_dialog(self, sfg): sfg_layout = QVBoxLayout() @@ -66,36 +72,37 @@ class SimulateSFGWindow(QDialog): "iteration_count": spin_box, "show_plot": check_box_plot, "all_results": check_box_all, - "input_values": [], } if sfg.input_count > 0: input_label = QLabel("Input values:") options_layout.addRow(input_label) - input_grid = QGridLayout() x, y = 0, 0 for i in range(sfg.input_count): - input_layout = QHBoxLayout() - input_layout.addStretch() if i % 2 == 0 and i > 0: x += 1 y = 0 input_label = QLabel(f"in{i}") - input_layout.addWidget(input_label) - input_value = QLineEdit() - input_value.setPlaceholderText("e.g. 0, 0, 0") - input_value.setFixedWidth(100) - input_layout.addWidget(input_value) - input_layout.addStretch() - input_layout.setSpacing(10) - input_grid.addLayout(input_layout, x, y) - - self.input_fields[sfg]["input_values"].append(input_value) + self.input_grid.addWidget(input_label, i, 0) + + input_dropdown = QComboBox() + input_dropdown.insertItems( + 0, ["Impulse", "Step", "Input", "File"] + ) + input_dropdown.currentTextChanged.connect( + lambda text, i=i: self.change_input_format(i, text) + ) + self.input_grid.addWidget( + input_dropdown, i, 1, alignment=Qt.AlignLeft + ) + + self.change_input_format(i, "Impulse") + y += 1 - sfg_layout.addLayout(input_grid) + sfg_layout.addLayout(self.input_grid) frame = QFrame() frame.setFrameShape(QFrame.HLine) @@ -105,6 +112,59 @@ class SimulateSFGWindow(QDialog): self.sfg_to_layout[sfg] = sfg_layout self.dialog_layout.addLayout(sfg_layout) + def change_input_format(self, i, text): + grid = self.input_grid.itemAtPosition(i, 2) + if grid: + for j in reversed(range(grid.count())): + item = grid.itemAt(j) + widget = item.widget() + if widget: + widget.hide() + self.input_grid.removeItem(grid) + + param_grid = QGridLayout() + + if text == "Impulse": + delay_label = QLabel("Delay") + param_grid.addWidget(delay_label, 0, 0) + delay_spin_box = QSpinBox() + delay_spin_box.setRange(0, 2147483647) + param_grid.addWidget(delay_spin_box, 0, 1) + elif text == "Step": + delay_label = QLabel("Delay") + param_grid.addWidget(delay_label, 0, 0) + delay_spin_box = QSpinBox() + delay_spin_box.setRange(0, 2147483647) + param_grid.addWidget(delay_spin_box, 0, 1) + elif text == "Input": + input_label = QLabel("Input") + param_grid.addWidget(input_label, 0, 0) + input_sequence = QLineEdit() + param_grid.addWidget(input_sequence, 0, 1) + zpad_label = QLabel("Zpad") + param_grid.addWidget(zpad_label, 1, 0) + zpad_button = QCheckBox() + param_grid.addWidget(zpad_button, 1, 1) + elif text == "File": + file_label = QLabel("Browse") + param_grid.addWidget(file_label, 0, 0) + file_browser = QPushButton("No file selected") + file_browser.clicked.connect( + lambda i=i: self.get_input_file(i, file_browser) + ) + param_grid.addWidget(file_browser, 0, 1) + else: + raise Exception("Input selection is not implemented") + + self.input_grid.addLayout(param_grid, i, 2) + + return + + def get_input_file(self, i, file_browser): + module, accepted = QFileDialog().getOpenFileName() + file_browser.setText(module) + return + def parse_input_values(self, input_values): _input_values = [] for _list in input_values: @@ -128,15 +188,60 @@ class SimulateSFGWindow(QDialog): def save_properties(self): for sfg, _properties in self.input_fields.items(): - input_values = self.parse_input_values( - [ - widget.text().split(",") if widget.text() else [0] - for widget in self.input_fields[sfg]["input_values"] - ] - ) + ic_value = self.input_fields[sfg]["iteration_count"].value() + if ic_value == 0: + self._window.logger.error("Iteration count is set to zero.") + + tmp = [] + + for i in range(self.input_grid.rowCount()): + in_format = ( + self.input_grid.itemAtPosition(i, 1).widget().currentText() + ) + in_param = self.input_grid.itemAtPosition(i, 2) + + tmp2 = [] + + if in_format == "Impulse": + g = Impulse(in_param.itemAtPosition(0, 1).widget().value()) + for j in range(ic_value): + tmp2.append(str(g(j))) + + elif in_format == "Step": + g = Step(in_param.itemAtPosition(0, 1).widget().value()) + for j in range(ic_value): + tmp2.append(str(g(j))) + + elif in_format == "Input": + widget = in_param.itemAtPosition(0, 1).widget() + tmp3 = widget.text().split(",") + if in_param.itemAtPosition(1, 1).widget().isChecked(): + g = ZeroPad(tmp3) + for j in range(ic_value): + tmp2.append(str(g(j))) + else: + tmp2 = tmp3 + + elif in_format == "File": + widget = in_param.itemAtPosition(0, 1).widget() + path = widget.text() + try: + tmp2 = np.loadtxt(path, dtype=str).tolist() + except FileNotFoundError: + self._window.logger.error( + f"Selected input file not found." + ) + continue + else: + raise Exception("Input selection is not implemented") + + tmp.append(tmp2) + + input_values = self.parse_input_values(tmp) + max_len = max(len(list_) for list_ in input_values) min_len = min(len(list_) for list_ in input_values) - ic_value = self.input_fields[sfg]["iteration_count"].value() + if max_len != min_len: self._window.logger.error( "Minimum length of input lists are not equal to maximum " -- GitLab