Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • da/B-ASIC
  • lukja239/B-ASIC
  • robal695/B-ASIC
3 results
Show changes
Commits on Source (2)
...@@ -5,8 +5,10 @@ This class creates a dragbutton which can be clicked, dragged and dropped. ...@@ -5,8 +5,10 @@ This class creates a dragbutton which can be clicked, dragged and dropped.
import os.path import os.path
from PyQt5.QtWidgets import QPushButton from properties_window import PropertiesWindow
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import QPushButton, QMenu, QAction
from PyQt5.QtCore import Qt, QSize, pyqtSignal
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from utils import decorate_class, handle_error from utils import decorate_class, handle_error
...@@ -14,8 +16,11 @@ from utils import decorate_class, handle_error ...@@ -14,8 +16,11 @@ from utils import decorate_class, handle_error
@decorate_class(handle_error) @decorate_class(handle_error)
class DragButton(QPushButton): class DragButton(QPushButton):
def __init__(self, name, operation, operation_path_name, window, parent = None): connectionRequested = pyqtSignal(QPushButton)
moved = pyqtSignal()
def __init__(self, name, operation, operation_path_name, is_show_name, window, parent = None):
self.name = name self.name = name
self.is_show_name = is_show_name
self._window = window self._window = window
self.operation = operation self.operation = operation
self.operation_path_name = operation_path_name self.operation_path_name = operation_path_name
...@@ -23,6 +28,20 @@ class DragButton(QPushButton): ...@@ -23,6 +28,20 @@ class DragButton(QPushButton):
self.pressed = False self.pressed = False
super(DragButton, self).__init__(self._window) super(DragButton, self).__init__(self._window)
def contextMenuEvent(self, event):
menu = QMenu()
properties = QAction("Properties")
menu.addAction(properties)
properties.triggered.connect(self.show_properties_window)
menu.exec_(self.cursor().pos())
def show_properties_window(self):
self.properties_window = PropertiesWindow(self, self.__window)
self.properties_window.show()
def add_label(self, label):
self.label = label
def mousePressEvent(self, event): def mousePressEvent(self, event):
self._mouse_press_pos = None self._mouse_press_pos = None
self._mouse_move_pos = None self._mouse_move_pos = None
...@@ -38,20 +57,20 @@ class DragButton(QPushButton): ...@@ -38,20 +57,20 @@ class DragButton(QPushButton):
if self.clicked == 1: if self.clicked == 1:
self.pressed = True self.pressed = True
self.setStyleSheet("background-color: grey; border-style: solid;\ self.setStyleSheet("background-color: grey; border-style: solid;\
border-color: black; border-width: 2px; border-radius: 10px") border-color: black; border-width: 2px")
path_to_image = os.path.join('operation_icons', self.operation_path_name + '_grey.png') path_to_image = os.path.join('operation_icons', self.operation_path_name + '_grey.png')
self.setIcon(QIcon(path_to_image)) self.setIcon(QIcon(path_to_image))
self.setIconSize(QSize(50, 50)) self.setIconSize(QSize(55, 55))
self._window.pressed_button.append(self) self._window.pressed_button.append(self)
elif self.clicked == 2: elif self.clicked == 2:
self.clicked = 0 self.clicked = 0
self.pressed = False self.pressed = False
self.setStyleSheet("background-color: white; border-style: solid;\ self.setStyleSheet("background-color: white; border-style: solid;\
border-color: black; border-width: 2px; border-radius: 10px") border-color: black; border-width: 2px")
path_to_image = os.path.join('operation_icons', self.operation_path_name + '.png') path_to_image = os.path.join('operation_icons', self.operation_path_name + '.png')
self.setIcon(QIcon(path_to_image)) self.setIcon(QIcon(path_to_image))
self.setIconSize(QSize(50, 50)) self.setIconSize(QSize(55, 55))
self._window.pressed_button.remove(self) self._window.pressed_button.remove(self)
super(DragButton, self).mousePressEvent(event) super(DragButton, self).mousePressEvent(event)
......
"""@package docstring
B-ASIC GUI Module.
This python file is the main window of the GUI for B-ASIC.
"""
from os import getcwd, path
import sys
from drag_button import DragButton
from gui_interface import Ui_main_window
from arrow import Arrow
from port_button import PortButton
from b_asic import Operation
import b_asic.core_operations as c_oper
import b_asic.special_operations as s_oper
from utils import decorate_class, handle_error
from numpy import linspace
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QAction,\
QStatusBar, QMenuBar, QLineEdit, QPushButton, QSlider, QScrollArea, QVBoxLayout,\
QHBoxLayout, QDockWidget, QToolBar, QMenu, QLayout, QSizePolicy, QListWidget,\
QListWidgetItem, QGraphicsView, QGraphicsScene, QShortcut
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon, QFont, QPainter, QPen, QBrush, QKeySequence
@decorate_class(handle_error)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_main_window()
self.ui.setupUi(self)
self.setWindowTitle(" ")
self.setWindowIcon(QIcon('small_logo.png'))
self.scene = None
self._operations_from_name = dict()
self.zoom = 1
self.operationList = []
self.signalList = []
self.pressed_button = []
self.portList = []
self.pressed_ports = []
self.source = None
self._window = self
self.init_ui()
self.add_operations_from_namespace(c_oper, self.ui.core_operations_list)
self.add_operations_from_namespace(s_oper, self.ui.special_operations_list)
self.shortcut_core = QShortcut(QKeySequence("Ctrl+R"), self.ui.operation_box)
self.shortcut_core.activated.connect(self._refresh_operations_list_from_namespace)
def init_ui(self):
self.ui.core_operations_list.itemClicked.connect(self.on_list_widget_item_clicked)
self.ui.special_operations_list.itemClicked.connect(self.on_list_widget_item_clicked)
self.ui.exit_menu.triggered.connect(self.exit_app)
self.create_graphics_view()
def create_graphics_view(self):
self.scene = QGraphicsScene()
self.graphic_view = QGraphicsView(self.scene, self)
self.graphic_view.setRenderHint(QPainter.Antialiasing)
self.graphic_view.setGeometry(250, 40, 600, 520)
self.graphic_view.setDragMode(QGraphicsView.ScrollHandDrag)
def wheelEvent(self, event):
old_zoom = self.zoom
self.zoom += event.angleDelta().y()/2500
self.graphic_view.scale(self.zoom, self.zoom)
self.zoom = old_zoom
def exit_app(self, checked):
QApplication.quit()
def _determine_port_distance(self, length, ports):
"""Determine the distance between each port on the side of an operation.
The method returns the distance that each port should have from 0.
"""
return [length / 2] if ports == 1 else linspace(0, length, ports)
def _create_port(self, operation, output_port=True):
text = ">" if output_port else "<"
button = PortButton(text, operation, self)
button.setStyleSheet("background-color: white")
button.connectionRequested.connect(self.connectButton)
return button
def add_ports(self, operation):
_output_ports_dist = self._determine_port_distance(50 - 15, operation.operation.output_count)
_input_ports_dist = self._determine_port_distance(50 - 15, operation.operation.input_count)
for dist in _input_ports_dist:
port = self._create_port(operation)
port.move(0, dist)
port.show()
for dist in _output_ports_dist:
port = self._create_port(operation)
port.move(50 - 15, dist)
port.show()
def get_operations_from_namespace(self, namespace):
return [comp for comp in dir(namespace) if hasattr(getattr(namespace, comp), "type_name")]
def add_operations_from_namespace(self, namespace, _list):
for attr_name in self.get_operations_from_namespace(namespace):
attr = getattr(namespace, attr_name)
try:
attr.type_name()
item = QListWidgetItem(attr_name)
_list.addItem(item)
self._operations_from_name[attr_name] = attr
except NotImplementedError:
pass
def _create_operation(self, item):
try:
attr_oper = self._operations_from_name[item.text()]()
attr_button = DragButton(attr_oper.graph_id, attr_oper, attr_oper.type_name().lower(), self)
attr_button.move(250, 100)
attr_button.setFixedSize(50, 50)
attr_button.setStyleSheet("background-color: white; border-style: solid;\
border-color: black; border-width: 2px; border-radius: 10px")
self.add_ports(attr_button)
icon_path = path.join("operation_icons", f"{attr_oper.type_name().lower()}.png")
if not path.exists(icon_path):
icon_path = path.join("operation_icons", f"custom_operation.png")
attr_button.setIcon(QIcon(icon_path))
attr_button.setIconSize(QSize(50, 50))
attr_button.setParent(None)
self.scene.addWidget(attr_button)
self.operationList.append(attr_button)
except Exception as e:
print("Unexpected error occured: ", e)
def _refresh_operations_list_from_namespace(self):
self.ui.core_operations_list.clear()
self.ui.special_operations_list.clear()
self.add_operations_from_namespace(c_oper, self.ui.core_operations_list)
self.add_operations_from_namespace(s_oper, self.ui.special_operations_list)
def print_input_port_1(self):
print("Input port 1")
def print_input_port_2(self):
print("Input port 2")
def print_output_port_1(self):
print("Output port 1")
def print_output_port_2(self):
print("Output port 2")
def on_list_widget_item_clicked(self, item):
self._create_operation(item)
def keyPressEvent(self, event):
pressed_buttons = []
for op in self.operationList:
if op.pressed:
pressed_buttons.append(op)
if event.key() == Qt.Key_Delete:
for pressed_op in pressed_buttons:
self.operationList.remove(pressed_op)
pressed_op.remove()
super().keyPressEvent(event)
def connectButton(self, button):
if len(self.pressed_ports) < 2:
return
for i in range(len(self.pressed_ports) - 1):
line = Arrow(self.pressed_ports[i], self.pressed_ports[i + 1], self)
self.scene.addItem(line)
self.signalList.append(line)
self.update()
def paintEvent(self, event):
for signal in self.signalList:
signal.moveLine()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
"""@package docstring """@package docstring
B-ASIC GUI Module. B-ASIC GUI Module.
This python file is an example of how a GUI can be implemented This python file is the main window of the GUI for B-ASIC.
using buttons and textboxes.
""" """
from os import getcwd, path
import sys import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QAction,\ from drag_button import DragButton
QStatusBar, QMenuBar, QLineEdit, QPushButton, QSlider, QScrollArea, QVBoxLayout,\ from gui_interface import Ui_main_window
QHBoxLayout, QDockWidget, QToolBar, QMenu from arrow import Arrow
from PyQt5.QtCore import Qt, QSize, pyqtSlot from port_button import PortButton
from PyQt5.QtGui import QIcon, QFont, QPainter, QPen, QColor
from b_asic.core_operations import Addition
class DragButton(QPushButton):
def __init__(self, name, window, parent = None):
self.name = name
self.__menu = None
self.__window = window
self.counter = 0
self.clicked = 0
self.pressed = False
print("Constructor" + self.name)
super(DragButton, self).__init__(self.__window)
self.__window.setContextMenuPolicy(Qt.CustomContextMenu)
self.__window.customContextMenuRequested.connect(self.create_menu)
@pyqtSlot(QAction)
def actionClicked(self, action):
print("Triggern "+ self.name, self.__menu.name)
#self.__window.check_for_remove_op(self.name)
#def show_context_menu(self, point):
# show context menu
def create_menu(self, point):
self.counter += 1
# create context menu
popMenu = MyMenu('Menu' + str(self.counter))
popMenu.addAction(QAction('Add a signal', self))
popMenu.addAction(QAction('Remove a signal', self))
#action = QAction('Remove operation', self)
popMenu.addAction('Remove operation', lambda:self.removeAction(self))
popMenu.addSeparator()
popMenu.addAction(QAction('Remove all signals', self))
self.__window.menuList.append(popMenu)
#self.__window.actionList.append(action)
self.__menu = popMenu
self.pressed = False
self.__menu.exec_(self.__window.sender().mapToGlobal(point))
self.__menu.triggered.connect(self.actionClicked)
def removeAction(self, op):
print(op.__menu.name, op.name)
op.remove()
"""This class is made to create a draggable button"""
def mousePressEvent(self, event):
self._mouse_press_pos = None
self._mouse_move_pos = None
self.clicked += 1
if self.clicked == 1:
self.pressed = True
self.setStyleSheet("background-color: grey; border-style: solid;\
border-color: black; border-width: 2px; border-radius: 10px")
elif self.clicked == 2:
self.clicked = 0
self.presseed = False
self.setStyleSheet("background-color: white; border-style: solid;\
border-color: black; border-width: 2px; border-radius: 10px")
if event.button() == Qt.LeftButton:
self._mouse_press_pos = event.globalPos()
self._mouse_move_pos = event.globalPos()
super(DragButton, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if event.buttons() == Qt.LeftButton:
cur_pos = self.mapToGlobal(self.pos())
global_pos = event.globalPos()
diff = global_pos - self._mouse_move_pos
new_pos = self.mapFromGlobal(cur_pos + diff)
self.move(new_pos)
self.pressed = False
self._mouse_move_pos = global_pos
super(DragButton, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if self._mouse_press_pos is not None:
moved = event.globalPos() - self._mouse_press_pos
if moved.manhattanLength() > 3:
event.ignore()
return
super(DragButton, self).mouseReleaseEvent(event)
def remove(self):
self.deleteLater()
class SubWindow(QWidget):
"""Creates a sub window """
def create_window(self, window_width, window_height):
"""Creates a window
"""
parent = None
super(SubWindow, self).__init__(parent)
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.resize(window_width, window_height)
from b_asic import Operation
import b_asic.core_operations as c_oper
import b_asic.special_operations as s_oper
from utils import decorate_class, handle_error
class MyMenu(QMenu): from numpy import linspace
def __init__(self, name, parent = None):
self.name = name
super(MyMenu, self).__init__()
class MainWindow(QMainWindow): from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QAction,\
"""Main window for the program""" QStatusBar, QMenuBar, QLineEdit, QPushButton, QSlider, QScrollArea, QVBoxLayout,\
# pylint: disable=too-many-instance-attributes QHBoxLayout, QDockWidget, QToolBar, QMenu, QLayout, QSizePolicy, QListWidget,\
# Eight is reasonable in this case. QListWidgetItem, QGraphicsView, QGraphicsScene, QShortcut, QGraphicsTextItem,\
def __init__(self, *args, **kwargs): QGraphicsProxyWidget
super(MainWindow, self).__init__(*args, **kwargs) from PyQt5.QtCore import Qt, QSize
self.init_ui() from PyQt5.QtGui import QIcon, QFont, QPainter, QPen, QBrush, QKeySequence
self.counter = 0
self.operations = []
self.menuList = []
self.actionList = []
def init_ui(self): @decorate_class(handle_error)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_main_window()
self.ui.setupUi(self)
self.setWindowTitle(" ") self.setWindowTitle(" ")
self.setWindowIcon(QIcon('small_logo.png')) self.setWindowIcon(QIcon('small_logo.png'))
self.create_operation_menu() self.scene = None
self.create_menu_bar() self._operations_from_name = dict()
self.setStatusBar(QStatusBar(self)) self.zoom = 1
self.operationList = []
def create_operation_menu(self): self.signalList = []
self.operation_box = QDockWidget("Operation Box", self) self.pressed_button = []
self.operation_box.setAllowedAreas(Qt.LeftDockWidgetArea) self.portList = []
self.test = QToolBar(self) self.pressed_ports = []
self.operation_list = QMenuBar(self) self.source = None
self.test.addWidget(self.operation_list) self._window = self
self.test.setOrientation(Qt.Vertical)
self.operation_list.setStyleSheet("background-color:rgb(222,222,222); vertical")
basic_operations = self.operation_list.addMenu('Basic operations')
special_operations = self.operation_list.addMenu('Special operations')
self.addition_menu_item = QAction('&Addition', self)
self.addition_menu_item.setStatusTip("Add addition operation to workspace")
self.addition_menu_item.triggered.connect(self.create_addition_operation)
basic_operations.addAction(self.addition_menu_item)
self.subtraction_menu_item = QAction('&Subtraction', self)
self.subtraction_menu_item.setStatusTip("Add subtraction operation to workspace")
self.subtraction_menu_item.triggered.connect(self.create_subtraction_operation)
basic_operations.addAction(self.subtraction_menu_item)
self.multiplication_menu_item = QAction('&Multiplication', self)
self.multiplication_menu_item.setStatusTip("Add multiplication operation to workspace")
self.multiplication_menu_item.triggered.connect(self.create_multiplication_operation)
basic_operations.addAction(self.multiplication_menu_item)
self.division_menu_item = QAction('&Division', self)
self.division_menu_item.setStatusTip("Add division operation to workspace")
#self.division_menu_item.triggered.connect(self.create_division_operation)
basic_operations.addAction(self.division_menu_item)
self.constant_menu_item = QAction('&Constant', self)
self.constant_menu_item.setStatusTip("Add constant operation to workspace")
#self.constant_menu_item.triggered.connect(self.create_constant_operation)
basic_operations.addAction(self.constant_menu_item)
self.square_root_menu_item = QAction('&Square root', self)
self.square_root_menu_item.setStatusTip("Add square root operation to workspace")
#self.square_root_menu_item.triggered.connect(self.create_square_root_operation)
basic_operations.addAction(self.square_root_menu_item)
self.complex_conjugate_menu_item = QAction('&Complex conjugate', self)
self.complex_conjugate_menu_item.setStatusTip("Add complex conjugate operation to workspace")
#self.complex_conjugate_menu_item.triggered.connect(self.create_complex_conjugate_operation)
basic_operations.addAction(self.complex_conjugate_menu_item)
self.max_menu_item = QAction('&Max', self)
self.max_menu_item.setStatusTip("Add max operation to workspace")
#self.max_menu_item.triggered.connect(self.create_max_operation)
basic_operations.addAction(self.max_menu_item)
self.min_menu_item = QAction('&Min', self)
self.min_menu_item.setStatusTip("Add min operation to workspace")
#self.min_menu_item.triggered.connect(self.create_min_operation)
basic_operations.addAction(self.min_menu_item)
self.absolute_menu_item = QAction('&Absolute', self)
self.absolute_menu_item.setStatusTip("Add absolute operation to workspace")
#self.absolute_menu_item.triggered.connect(self.create_absolute_operation)
basic_operations.addAction(self.absolute_menu_item)
self.constant_addition_menu_item = QAction('&Constant addition', self)
self.constant_addition_menu_item.setStatusTip("Add constant addition operation to workspace")
#self.constant_addition_menu_item.triggered.connect(self.create_constant_addition_operation)
basic_operations.addAction(self.constant_addition_menu_item)
self.constant_subtraction_menu_item = QAction('&Constant subtraction', self)
self.constant_subtraction_menu_item.setStatusTip("Add constant subtraction operation to workspace")
#self.constant_subtraction_menu_item.triggered.connect(self.create_constant_subtraction_operation)
basic_operations.addAction(self.constant_subtraction_menu_item)
self.constant_multiplication_menu_item = QAction('&Constant multiplication', self)
self.constant_multiplication_menu_item.setStatusTip("Add constant multiplication operation to workspace")
#self.constant_multiplication_menu_item.triggered.connect(self.create_constant_multiplication_operation)
basic_operations.addAction(self.constant_multiplication_menu_item)
self.constant_division_menu_item = QAction('&Constant division', self)
self.constant_division_menu_item.setStatusTip("Add constant division operation to workspace")
#self.constant_division_menu_item.triggered.connect(self.create_constant_division_operation)
basic_operations.addAction(self.constant_division_menu_item)
self.butterfly_menu_item = QAction('&Butterfly', self)
self.butterfly_menu_item.setStatusTip("Add butterfly operation to workspace")
#self.butterfly_menu_item.triggered.connect(self.create_butterfly_operation)
basic_operations.addAction(self.butterfly_menu_item)
self.operation_box.setWidget(self.operation_list)
self.operation_box.setMaximumSize(240, 400)
self.operation_box.setFeatures(QDockWidget.NoDockWidgetFeatures)
self.operation_box.setFixedSize(300, 500)
self.operation_box.setStyleSheet("background-color: white; border-style: solid;\
border-color: black; border-width: 2px")
self.addDockWidget(Qt.LeftDockWidgetArea, self.operation_box)
def create_addition_operation(self):
self.counter += 1
# Create drag button
addition_operation = DragButton("OP" + str(self.counter), self)
addition_operation.move(250, 100)
addition_operation.setFixedSize(50, 50)
addition_operation.setStyleSheet("background-color: white; border-style: solid;\
border-color: black; border-width: 2px; border-radius: 10px")
addition_operation.clicked.connect(self.create_sub_window)
#self.addition_operation.setIcon(QIcon("GUI'\'operation_icons'\'plus.png"))
addition_operation.setText("OP" + str(self.counter))
addition_operation.setIconSize(QSize(50, 50))
addition_operation.show()
self.operations.append(addition_operation)
# set context menu policies
#self.addition_operation.setContextMenuPolicy(Qt.CustomContextMenu)
#self.addition_operation.customContextMenuRequested.connect(self.show_context_menu)
#self.action.triggered.connect(lambda checked: self.remove(self.addition_operation.name))
def check_for_remove_op(self, name):
self.remove(name)
def remove(self, name):
for op in self.operations:
print(name, op.name)
if op.name == name:
self.operations.remove(op)
op.remove()
def create_subtraction_operation(self):
self.subtraction_operation = DragButton("sub" + str(self.counter), self)
self.subtraction_operation.move(250, 100)
self.subtraction_operation.setFixedSize(50, 50)
self.subtraction_operation.setStyleSheet("background-color: white; border-style: solid;\
border-color: black; border-width: 2px; border-radius: 10px")
self.subtraction_operation.setIcon(QIcon("GUI'\'operation_icons'\'minus.png"))
self.subtraction_operation.setIconSize(QSize(50, 50))
self.subtraction_operation.clicked.connect(self.create_sub_window)
self.subtraction_operation.show()
# set context menu policies
self.subtraction_operation.setContextMenuPolicy(Qt.CustomContextMenu)
self.subtraction_operation.customContextMenuRequested.connect(self.show_context_menu)
# create context menu
self.button_context_menu = QMenu(self)
self.button_context_menu.addAction(QAction('Add a signal', self))
self.button_context_menu.addAction(QAction('Remove a signal', self))
self.button_context_menu.addSeparator()
self.button_context_menu.addAction(QAction('Remove all signals', self))
def create_multiplication_operation(self):
self.multiplication_operation = DragButton(self)
self.multiplication_operation.move(250, 100)
self.multiplication_operation.setFixedSize(50, 50)
self.multiplication_operation.setStyleSheet("background-color: white; border-style: solid;\
border-color: black; border-width: 2px; border-radius: 10px")
self.multiplication_operation.clicked.connect(self.create_sub_window)
self.multiplication_operation.setIcon(QIcon(r"GUI\operation_icons\plus.png"))
self.multiplication_operation.setIconSize(QSize(50, 50))
self.multiplication_operation.show()
# set context menu policies
self.multiplication_operation.setContextMenuPolicy(Qt.CustomContextMenu)
self.multiplication_operation.customContextMenuRequested.connect(self.show_context_menu)
# create context menu
self.button_context_menu = QMenu(self)
self.button_context_menu.addAction(QAction('Add a signal', self))
self.button_context_menu.addAction(QAction('Remove a signal', self))
self.button_context_menu.addSeparator()
self.button_context_menu.addAction(QAction('Remove all signals', self))
def create_menu_bar(self):
# Menu buttons
load_button = QAction("Load", self)
save_button = QAction("Save", self)
exit_button = QAction("Exit", self)
exit_button.setShortcut("Ctrl+Q")
exit_button.triggered.connect(self.exit_app)
edit_button = QAction("Edit", self)
edit_button.setStatusTip("Open edit menu")
edit_button.triggered.connect(self.on_edit_button_click)
view_button = QAction("View", self)
view_button.setStatusTip("Open view menu")
view_button.triggered.connect(self.on_view_button_click)
menu_bar = QMenuBar()
menu_bar.setStyleSheet("background-color:rgb(222, 222, 222)")
self.setMenuBar(menu_bar)
file_menu = menu_bar.addMenu("&File")
file_menu.addAction(save_button)
file_menu.addSeparator()
file_menu.addAction(exit_button)
edit_menu = menu_bar.addMenu("&Edit")
edit_menu.addAction(edit_button)
edit_menu.addSeparator()
view_menu = menu_bar.addMenu("&View")
view_menu.addAction(view_button)
def create_sub_window(self):
""" Example of how to create a sub window
"""
self.sub_window = SubWindow()
self.sub_window.create_window(400, 300)
self.sub_window.setWindowTitle("Properties")
self.sub_window.properties_label = QLabel(self.sub_window) self.init_ui()
self.sub_window.properties_label.setText('Properties') self.add_operations_from_namespace(c_oper, self.ui.core_operations_list)
self.sub_window.properties_label.setFixedWidth(400) self.add_operations_from_namespace(s_oper, self.ui.special_operations_list)
self.sub_window.properties_label.setFont(QFont('SansSerif', 14, QFont.Bold))
self.sub_window.properties_label.setAlignment(Qt.AlignCenter)
self.sub_window.name_label = QLabel(self.sub_window)
self.sub_window.name_label.setText('Name:')
self.sub_window.name_label.move(20, 40)
self.sub_window.name_line = QLineEdit(self.sub_window)
self.sub_window.name_line.setPlaceholderText("Write a name here")
self.sub_window.name_line.move(70, 40)
self.sub_window.name_line.resize(100, 20)
self.sub_window.id_label = QLabel(self.sub_window)
self.sub_window.id_label.setText('Id:')
self.sub_window.id_label.move(20, 70)
self.sub_window.id_line = QLineEdit(self.sub_window)
self.sub_window.id_line.setPlaceholderText("Write an id here")
self.sub_window.id_line.move(70, 70)
self.sub_window.id_line.resize(100, 20)
self.sub_window.show() self.shortcut_core = QShortcut(QKeySequence("Ctrl+R"), self.ui.operation_box)
self.shortcut_core.activated.connect(self._refresh_operations_list_from_namespace)
def keyPressEvent(self, event): self.move_button_index = 0
for op in self.operations: self.is_show_names = True
if event.key() == Qt.Key_Delete and op.pressed:
self.operations.remove(op)
op.remove()
def on_file_button_click(self):
print("File")
def on_edit_button_click(self): self.check_show_names = QAction("Show operation names")
print("Edit") self.check_show_names.triggered.connect(self.view_operation_names)
self.check_show_names.setCheckable(True)
self.check_show_names.setChecked(1)
self.ui.view_menu.addAction(self.check_show_names)
def on_view_button_click(self): def init_ui(self):
print("View") self.ui.core_operations_list.itemClicked.connect(self.on_list_widget_item_clicked)
self.ui.special_operations_list.itemClicked.connect(self.on_list_widget_item_clicked)
self.ui.exit_menu.triggered.connect(self.exit_app)
self.create_graphics_view()
def create_graphics_view(self):
self.scene = QGraphicsScene()
self.graphic_view = QGraphicsView(self.scene, self)
self.graphic_view.setRenderHint(QPainter.Antialiasing)
self.graphic_view.setGeometry(250, 40, 600, 520)
self.graphic_view.setDragMode(QGraphicsView.ScrollHandDrag)
def wheelEvent(self, event):
old_zoom = self.zoom
self.zoom += event.angleDelta().y()/2500
self.graphic_view.scale(self.zoom, self.zoom)
self.zoom = old_zoom
def view_operation_names(self):
if self.check_show_names.isChecked():
self.is_show_names = True
else:
self.is_show_names = False
for operation in self.operationList:
operation.label.setOpacity(self.is_show_names)
operation.is_show_name = self.is_show_names
def exit_app(self, checked): def exit_app(self, checked):
QApplication.quit() QApplication.quit()
def clicked(self): def _determine_port_distance(self, length, ports):
print("Drag button clicked") """Determine the distance between each port on the side of an operation.
The method returns the distance that each port should have from 0.
"""
return [length / 2] if ports == 1 else linspace(0, length, ports)
def _create_port(self, operation, output_port=True):
text = ">" if output_port else "<"
button = PortButton(text, operation, self)
button.setStyleSheet("background-color: white")
button.connectionRequested.connect(self.connectButton)
return button
def add_ports(self, operation):
_output_ports_dist = self._determine_port_distance(55 - 17, operation.operation.output_count)
_input_ports_dist = self._determine_port_distance(55 - 17, operation.operation.input_count)
for dist in _input_ports_dist:
port = self._create_port(operation)
port.move(0, dist)
port.show()
for dist in _output_ports_dist:
port = self._create_port(operation)
port.move(55 - 12, dist)
port.show()
def get_operations_from_namespace(self, namespace):
return [comp for comp in dir(namespace) if hasattr(getattr(namespace, comp), "type_name")]
def add_operations_from_namespace(self, namespace, _list):
for attr_name in self.get_operations_from_namespace(namespace):
attr = getattr(namespace, attr_name)
try:
attr.type_name()
item = QListWidgetItem(attr_name)
_list.addItem(item)
self._operations_from_name[attr_name] = attr
except NotImplementedError:
pass
def _create_operation(self, item):
try:
attr_oper = self._operations_from_name[item.text()]()
attr_button = DragButton(attr_oper.graph_id, attr_oper, attr_oper.type_name().lower(), True, self)
attr_button.move(250, 100)
attr_button.setFixedSize(55, 55)
attr_button.setStyleSheet("background-color: white; border-style: solid;\
border-color: black; border-width: 2px")
self.add_ports(attr_button)
icon_path = path.join("operation_icons", f"{attr_oper.type_name().lower()}.png")
if not path.exists(icon_path):
icon_path = path.join("operation_icons", f"custom_operation.png")
attr_button.setIcon(QIcon(icon_path))
attr_button.setIconSize(QSize(55, 55))
attr_button.setParent(None)
attr_button_scene = self.scene.addWidget(attr_button)
attr_button_scene.moveBy(self.move_button_index * 100, 0)
self.move_button_index += 1
operation_label = QGraphicsTextItem(attr_oper.type_name(), attr_button_scene)
if not self.is_show_names:
operation_label.setOpacity(0)
operation_label.setTransformOriginPoint(operation_label.boundingRect().center())
operation_label.moveBy(10, -20)
attr_button.add_label(operation_label)
self.operationList.append(attr_button)
except Exception as e:
print("Unexpected error occured: ", e)
def _refresh_operations_list_from_namespace(self):
self.ui.core_operations_list.clear()
self.ui.special_operations_list.clear()
self.add_operations_from_namespace(c_oper, self.ui.core_operations_list)
self.add_operations_from_namespace(s_oper, self.ui.special_operations_list)
def on_list_widget_item_clicked(self, item):
self._create_operation(item)
def keyPressEvent(self, event):
pressed_buttons = []
for op in self.operationList:
if op.pressed:
pressed_buttons.append(op)
if event.key() == Qt.Key_Delete:
for pressed_op in pressed_buttons:
self.operationList.remove(pressed_op)
pressed_op.remove()
self.move_button_index -= 1
super().keyPressEvent(event)
def connectButton(self, button):
if len(self.pressed_ports) < 2:
return
for i in range(len(self.pressed_ports) - 1):
line = Arrow(self.pressed_ports[i], self.pressed_ports[i + 1], self)
self.scene.addItem(line)
self.signalList.append(line)
self.update()
def paintEvent(self, event):
for signal in self.signalList:
signal.moveLine()
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication(sys.argv) app = QApplication(sys.argv)
window = MainWindow() window = MainWindow()
window.resize(960, 720)
window.show() window.show()
app.exec_() sys.exit(app.exec_())
from PyQt5.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\
QLabel, QCheckBox
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIntValidator
class PropertiesWindow(QDialog):
def __init__(self, operation, main_window):
super(PropertiesWindow, self).__init__()
self.operation = operation
self.main_window = main_window
self.setWindowFlags(Qt.WindowTitleHint | Qt.WindowCloseButtonHint)
self.setWindowTitle("Properties")
self.name_layout = QHBoxLayout()
self.name_layout.setSpacing(50)
self.name_label = QLabel("Name:")
self.edit_name = QLineEdit(self.operation.operation_path_name)
self.name_layout.addWidget(self.name_label)
self.name_layout.addWidget(self.edit_name)
self.vertical_layout = QVBoxLayout()
self.vertical_layout.addLayout(self.name_layout)
if self.operation.operation_path_name == "c":
self.constant_layout = QHBoxLayout()
self.constant_layout.setSpacing(50)
self.constant_value = QLabel("Constant:")
self.edit_constant = QLineEdit(str(self.operation.operation.value))
self.only_accept_int = QIntValidator()
self.edit_constant.setValidator(self.only_accept_int)
self.constant_layout.addWidget(self.constant_value)
self.constant_layout.addWidget(self.edit_constant)
self.vertical_layout.addLayout(self.constant_layout)
self.show_name_layout = QHBoxLayout()
self.check_show_name = QCheckBox("Show name?")
if self.operation.is_show_name:
self.check_show_name.setChecked(1)
else:
self.check_show_name.setChecked(0)
self.check_show_name.setLayoutDirection(Qt.RightToLeft)
self.check_show_name.setStyleSheet("spacing: 170px")
self.show_name_layout.addWidget(self.check_show_name)
self.vertical_layout.addLayout(self.show_name_layout)
self.ok = QPushButton("OK")
self.ok.clicked.connect(self.save_properties)
self.vertical_layout.addWidget(self.ok)
self.setLayout(self.vertical_layout)
def save_properties(self):
self.operation.name = self.edit_name.text()
self.operation.label.setPlainText(self.operation.name)
if self.operation.operation_path_name == "c":
self.operation.operation.value = self.edit_constant.text()
if self.check_show_name.isChecked():
self.operation.label.setOpacity(1)
self.operation.is_show_name = True
else:
self.operation.label.setOpacity(0)
self.operation.is_show_name = False
self.reject()
\ No newline at end of file