diff --git a/b_asic/scheduler-gui/component_item.py b/b_asic/scheduler-gui/component_item.py new file mode 100644 index 0000000000000000000000000000000000000000..a2f557688424a24cf5cab1d426e4bef65a900cc5 --- /dev/null +++ b/b_asic/scheduler-gui/component_item.py @@ -0,0 +1,98 @@ +import os +import sys +from typing import Any +from pprint import pprint +from typing import Any, AnyStr, Generic, Protocol, TypeVar, Union, Optional, overload, Final, final +# from typing_extensions import Self, Final, Literal, LiteralString, TypeAlias, final +import numpy as np + +import qtpy +from qtpy import QtCore +from qtpy import QtGui +from qtpy import QtWidgets + +# QGraphics and QPainter imports +from qtpy.QtCore import ( + Qt, QObject, QRect, QRectF, QPoint, QSize, QSizeF, QByteArray) +from qtpy.QtGui import ( + QPaintEvent, QPainter, QPainterPath, QColor, QBrush, QPen, QFont, QPolygon, QIcon, QPixmap, + QLinearGradient, QTransform) +from qtpy.QtWidgets import ( + QGraphicsView, QGraphicsScene, QGraphicsWidget, + QGraphicsLayout, QGraphicsLinearLayout, QGraphicsGridLayout, QGraphicsLayoutItem, QGraphicsAnchorLayout, + QGraphicsItem, QGraphicsItemGroup, QGraphicsPathItem) +from qtpy.QtCore import ( + QPoint, QPointF) + +# B-ASIC +import logger +from b_asic.schedule import Schedule + + +class ComponentItem(QGraphicsItemGroup, QGraphicsLayoutItem): + + _scale: float + _component_item: QGraphicsPathItem + _execution_time_item: QGraphicsPathItem + + + # def __init__(self, scale: float, *args, **kwargs): + def __init__(self, scale: float, parent = None): + super().__init__(parent=parent) + self._scale = scale + + + brush = QBrush(Qt.lightGray, bs=Qt.SolidPattern) + pen = QPen(Qt.SolidLine) + pen.setWidthF(2/self._scale) + pen.setBrush(Qt.darkGray) + # pen.setCapStyle(Qt.RoundCap) # Qt.FlatCap, Qt.SquareCap (default), Qt.RoundCap + pen.setJoinStyle(Qt.RoundJoin) # Qt.MiterJoin, Qt.BevelJoin (default), Qt.RoundJoin, Qt.SvgMiterJoin + + # component path + component_path = QPainterPath(QPoint(0,0)) + component_path.lineTo(0, 10) + component_path.lineTo(40, 10) + component_path.lineTo(40, 0) + component_path.closeSubpath() + + # component item + self._component_item = QGraphicsPathItem(component_path) + self._component_item.setPen(pen) + self._component_item.setBrush(brush) + self._component_item.setPos(5,0) # in parent (i.e. item_group) coordinates + + # execution time square + execution_time_path = QPainterPath(QPoint(0,0)) + execution_time_path.addRect(0, 0, 10.0, 10.0) + + # execution time item + green_color = QColor(Qt.magenta) + green_color.setAlpha(200) # 0-255 + pen.setColor(green_color) + self._execution_time_item = QGraphicsPathItem(execution_time_path) + self._execution_time_item.setPen(pen) + + # item group, consist of time_item and component_item + # item_group = QGraphicsItemGroup() + # item_group.setScale(self._scale) + self.addToGroup(self._component_item) + self.addToGroup(self._execution_time_item) + + + + + # # QGraphicsLayoutItem virtual functions + # def setGeometry(rect): ... + def sizeHint(self, which: Qt.SizeHint, constraint: QSizeF = QSizeF()) -> QSizeF: + switch = { + Qt.MinimumSize: self.boundingRect().size(), + Qt.PreferredSize: self.boundingRect().size(), + Qt.MaximumSize: QSizeF(float("inf"), float("inf")) + } + return switch.get(which, constraint) + + + # # QGraphicsItem virtual functions + # def boundingRect(): ... + # def paint(): ... \ No newline at end of file diff --git a/b_asic/scheduler-gui/graphics_scene.py b/b_asic/scheduler-gui/graphics_scene.py index b2f03672f5eb654abf0d666cb9ebc4737cf61e53..53a9bd511a2fead7b5490dd751da303182b03ac8 100644 --- a/b_asic/scheduler-gui/graphics_scene.py +++ b/b_asic/scheduler-gui/graphics_scene.py @@ -11,6 +11,7 @@ from typing import Any from pprint import pprint from typing import Any, AnyStr, Generic, Protocol, TypeVar, Union, Optional, overload, Final, final # from typing_extensions import Self, Final, Literal, LiteralString, TypeAlias, final +import numpy as np import qtpy from qtpy import QtCore @@ -22,7 +23,7 @@ from qtpy.QtCore import ( Qt, QObject, QRect, QRectF, QPoint, QSize, QByteArray) from qtpy.QtGui import ( QPaintEvent, QPainter, QPainterPath, QColor, QBrush, QPen, QFont, QPolygon, QIcon, QPixmap, - QLinearGradient) + QLinearGradient, QTransform) from qtpy.QtWidgets import ( QGraphicsView, QGraphicsScene, QGraphicsWidget, QGraphicsLayout, QGraphicsLinearLayout, QGraphicsGridLayout, QGraphicsLayoutItem, QGraphicsAnchorLayout, @@ -33,6 +34,7 @@ from qtpy.QtCore import ( # B-ASIC import logger from b_asic.schedule import Schedule +from component_item import ComponentItem @@ -41,6 +43,7 @@ class GraphicsScene(QGraphicsScene): """GraphicsScene subclass of QGraphicsScene acts as a scene to place items on""" _id: Final[int] _schedule: Final[Schedule] + _scale: float # _schedule: Final[Schedule] # def __init__(self, id: int, schedule: Optional["Schedule"] = None, *args, **kwargs): @@ -52,65 +55,76 @@ class GraphicsScene(QGraphicsScene): self._id = id if isinstance(schedule, Schedule): self._schedule = schedule - print('From GraphicsScene/schedule:\t\t', end='') - pprint(schedule) - print('From GraphicsScene/self._schedule:\t', end='') - pprint(self._schedule) - # print('') + self._scale = 10.0 + # print('From GraphicsScene/schedule:\t\t', end='') + # pprint(schedule) + # print('From GraphicsScene/self._schedule:\t', end='') + # pprint(self._schedule) + # print('') + # print('########### _start_times:') + # pprint(self._schedule._start_times) + # print('########### _laps:') + # pprint(self._schedule._laps.items()) + # print('########### _schedule_time:\t', self._schedule._schedule_time) + # print('########### _cyclic:\t\t', self._schedule._cyclic) + # print('########### _resolution:\t', self._schedule._resolution) + # for op_id, op_start_time in self._schedule._start_times.items(): + # print(op_id, op_start_time) + - scale = 10.0 - brush = QBrush(Qt.lightGray, bs=Qt.SolidPattern) - # pen = QPen(brush, 10, s=Qt.SolidLine, c=Qt.SquareCap, j=Qt.BevelJoin) - pen = QPen(Qt.SolidLine) - pen.setWidthF(2/scale) - pen.setBrush(Qt.darkGray) - # pen.setCapStyle(Qt.RoundCap) # Qt.FlatCap, Qt.SquareCap (default), Qt.RoundCap - pen.setJoinStyle(Qt.RoundJoin) # Qt.MiterJoin, Qt.BevelJoin (default), Qt.RoundJoin, Qt.SvgMiterJoin + # pprint(ComponentItem.__mro__) + component = ComponentItem(self._scale) - # the group consist of a time_item and a component_item - item_group = QGraphicsItemGroup() - item_group.setScale(scale) + # add item group to the scene + self.addItem(component) - component_path = QPainterPath(QPoint(0,0)) - component_path.lineTo(0, 10) - component_path.lineTo(40, 10) - component_path.lineTo(40, 0) - # component_path.lineTo(0, 0) - component_path.closeSubpath() - - # pen.setCosmetic(True) # Dont scale pen - component_item = QGraphicsPathItem(component_path, item_group) - component_item.setPen(pen) - component_item.setBrush(brush) - # item_group.addToGroup(component_item) - component_item.setPos(5,0) # in parent (item_group) coordinates + #################################################################### + print('boundingRect():', component.boundingRect()) + print('sceneBoundingRect():', component.sceneBoundingRect()) + print('childrenBoundingRect():', component.childrenBoundingRect()) + print('Qt.MinimumSize: ', component.sizeHint(Qt.MinimumSize)) + print('Qt.PreferredSize:', component.sizeHint(Qt.PreferredSize)) + print('Qt.MaximumSize: ', component.sizeHint(Qt.MaximumSize)) - time_path = QPainterPath(QPoint(0,0)) - time_path.lineTo(0, 10) - time_path.lineTo(10, 10) - time_path.lineTo(10, 0) - # time_path.lineTo(0, 0) - time_path.closeSubpath() + # # add the component group to scene + # group_layout_item = QGraphicsLayoutItem() + # group_layout_item.setGraphicsItem(item_group) - green_color = QColor(Qt.magenta) - green_color.setAlpha(200) # 0-255 - - pen.setColor(green_color) - # pen.setBrush(Qt.green) - time_item = QGraphicsPathItem(time_path, item_group) - time_item.setPen(pen) - # item_group.addToGroup(time_item) - + # grid_layout = QGraphicsGridLayout() + # print('ContentsMargins:', grid_layout.getContentsMargins()) + # print('Spacing: [{}, {}]'.format(grid_layout.horizontalSpacing() , grid_layout.verticalSpacing())) + # grid_layout.setContentsMargins(10.0, 10.0, 10.0, 10.0) + # grid_layout.setSpacing(10.0) + # grid_layout.addItem(group_layout_item, 0, 1) + # linear_layout = QGraphicsLinearLayout() - # add the component group to scene - self.addItem(item_group) + # self.addItem(grid_layout) - + # def drawBackground(self, painter: QPainter, exposed_rect: QRectF): + # pen = QPen(Qt.DotLine) + # # pen = QPen(Qt.DotLine) + # # pen.setDashOffset(self._scale) + # pen.setDashPattern([1, self._scale]) + # pen.setBrush(Qt.lightGray) + # pen.setCosmetic(True) + + # # vertical lines + # for x in np.arange(0, exposed_rect.width() - self._scale, self._scale): + # self.addLine(x, 0, x, exposed_rect.height() - self._scale, pen) + + # # horizontal lines + # # for y in np.arange(0, exposed_rect.height() - self._scale, self._scale): + # # self.addLine(0, y, exposed_rect.width() - self._scale, y, pen) + + # # self._ view->fitInView(scene->itemsVBoundingRect()) + # # print(type(self.parent)) + # # self.parent.fitInView(self.itemsVBoundingRect()) + def plot_schedule(self): self._schedule.plot_schedule() diff --git a/b_asic/scheduler-gui/main_window.py b/b_asic/scheduler-gui/main_window.py index 3b44c09bf2e46bf7c5d2c94a9284dd573883b901..99279bec21b3fb4929aadc87aac2c90534b2a4ee 100644 --- a/b_asic/scheduler-gui/main_window.py +++ b/b_asic/scheduler-gui/main_window.py @@ -55,16 +55,16 @@ if __debug__: if __debug__: # Print some system version information QT_API = os.environ.get('QT_API') - print('Qt version (runtime): ', str(QtCore.qVersion())) - print('Qt version (compiletime):', QtCore.__version__) - print('QT_API: ', QT_API) + log.debug('Qt version (runtime): {}'.format(QtCore.qVersion())) + log.debug('Qt version (compiletime): {}'.format(QtCore.__version__)) + log.debug('QT_API: {}'.format(QT_API)) if QT_API.lower().startswith('pyside'): import PySide2 - print('PySide version: ', PySide2.__version__) + log.debug('PySide version: {}'.format(PySide2.__version__)) if QT_API.lower().startswith('pyqt'): from qtpy.QtCore import PYQT_VERSION_STR - print('PyQt version: ', PYQT_VERSION_STR) - print('QtPy version: ', qtpy.__version__) + log.debug('PyQt version: {}'.format(PYQT_VERSION_STR)) + log.debug('QtPy version: {}'.format(qtpy.__version__)) # Autocompile the .ui form to a python file. try: # PyQt5, try autocompile @@ -109,6 +109,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): _scenes: dict[str, GraphicsScene] _scene_count: int _open_file_dialog_opened: bool + _scale: float def __init__(self): """Initialize Schedule-gui.""" @@ -116,6 +117,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self._scenes = {} self._scene_count = 0 self._open_file_dialog_opened = False + self._scale = 10.0 QIcon.setThemeName('breeze') log.debug('themeName: \'{}\''.format(QIcon.themeName())) @@ -168,6 +170,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): # self.graphic_view.setRenderHint(QPainter.Antialiasing) # self.graphic_view.setGeometry(20, 20, self.width(), self.height()) # self.graphic_view.setDragMode(QGraphicsView.RubberBandDrag) + self.graphics_view.scale(self._scale, self._scale) @@ -242,7 +245,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): #TODO: Unique hash keys #TODO: self.open(schedule_obj_list[ret_tuple[0]) - scene = GraphicsScene(self._scene_count, schedule, self) + scene = GraphicsScene(self._scene_count, schedule, self.graphics_view) #scene = QGraphicsScene() self._scenes[self._scene_count] = scene self.graphics_view.setScene(scene) @@ -250,6 +253,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.graphics_view.setRenderHint(QPainter.Antialiasing) # self.graphics_view.setGeometry(20, 20, self.width(), self.height()) self.graphics_view.setDragMode(QGraphicsView.RubberBandDrag) + # self.graphics_view.scale(10.0, 10.0) self._scene_count += 1