Skip to content
Snippets Groups Projects
Commit a518bcc2 authored by Oscar Gustafsson's avatar Oscar Gustafsson :bicyclist:
Browse files

More cleanup and refactoring

parent af2d2fd8
No related branches found
No related tags found
1 merge request!78Add scheduler GUI
Pipeline #74624 failed
......@@ -5,7 +5,7 @@ ASIC toolbox that simplifies circuit design and optimization.
# NOTE: If this import gives an error,
# make sure the C++ module has been compiled and installed properly.
# See the included README.md for more information on how to build/install.
from _b_asic import *
# from _b_asic import *
# Python modules.
from b_asic.core_operations import *
from b_asic.graph_component import *
......
......@@ -20,6 +20,8 @@ class Constant(AbstractOperation):
output(0): self.param("value")
"""
_execution_time = 0
def __init__(self, value: Number = 0, name: Name = ""):
"""Construct a Constant operation with the given value."""
super().__init__(input_count=0, output_count=1, name=name, latency_offsets={'out0' : 0})
......
......@@ -290,7 +290,7 @@ class AbstractOperation(Operation, AbstractGraphComponent):
_input_ports: List[InputPort]
_output_ports: List[OutputPort]
_execution_time: Union[int, None]
_execution_time: Union[int, None] = None
def __init__(self, input_count: int, output_count: int, name: Name = "", input_sources: Optional[Sequence[Optional[SignalSourceProvider]]] = None, latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct an operation with the given input/output count.
......@@ -305,7 +305,6 @@ class AbstractOperation(Operation, AbstractGraphComponent):
self._input_ports = [InputPort(self, i) for i in range(input_count)]
self._output_ports = [OutputPort(self, i) for i in range(output_count)]
self._execution_time = None
# Connect given input sources, if any.
if input_sources is not None:
......
......@@ -4,39 +4,18 @@
Contains the scheduler-gui GraphicsComponentItem class for drawing and maintain a component in a graph.
"""
import os
import sys
from typing import Any, Optional
from pprint import pprint
from typing import (
Any, Union, Optional, overload, final, Dict, OrderedDict, List)
# 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
Union, Optional, Dict, List)
# QGraphics and QPainter imports
from qtpy.QtCore import (
Qt, QObject, QRect, QRectF, QPoint, QSize, QSizeF, QByteArray, Slot, QEvent)
from qtpy.QtGui import (
QPaintEvent, QPainter, QPainterPath, QColor, QBrush, QPen, QFont, QPolygon, QIcon, QPixmap,
QLinearGradient, QTransform, QCursor)
from qtpy.QtCore import Qt, QPointF
from qtpy.QtGui import QPainterPath, QColor, QBrush, QPen, QCursor
from qtpy.QtWidgets import (
QGraphicsView, QGraphicsScene, QGraphicsWidget,
QGraphicsLayout, QGraphicsLinearLayout, QGraphicsGridLayout, QGraphicsLayoutItem, QGraphicsAnchorLayout,
QGraphicsItem, QGraphicsItemGroup, QGraphicsPathItem, QGraphicsRectItem,
QStyleOptionGraphicsItem, QWidget, QGraphicsObject, QGraphicsSceneMouseEvent, QGraphicsSimpleTextItem,
QGraphicsEllipseItem)
from qtpy.QtCore import (
QPoint, QPointF)
QGraphicsSimpleTextItem, QGraphicsEllipseItem)
# B-ASIC
import logger
from b_asic.schedule import Schedule
# from b_asic.graph_component import GraphComponent
from b_asic.graph_component import GraphComponent
class GraphicsComponentItem(QGraphicsItemGroup):
......@@ -52,18 +31,15 @@ class GraphicsComponentItem(QGraphicsItemGroup):
_execution_time_item: QGraphicsRectItem
_label_item: QGraphicsSimpleTextItem
_port_items: List[QGraphicsEllipseItem]
def __init__(self, op_id: str, latency_offsets: Dict[str, int], execution_time: Optional[int] = None, height: float = 0.75, parent: Optional[QGraphicsItem] = None):
def __init__(self, operation: GraphComponent, height: float = 0.75, parent: Optional[QGraphicsItem] = None):
"""Constructs a GraphicsComponentItem. 'parent' is passed to QGraphicsItemGroup's constructor."""
super().__init__(parent=parent)
self._op_id = op_id
self._operation = operation
self._height = height
self._ports = {k:{'latency':float(v)} for k,v in latency_offsets.items()}
self._end_time = 0
for latency in latency_offsets.values():
self._end_time = max(self._end_time, latency)
self._execution_time = execution_time
self._ports = {k:{'latency':float(v)} for k,v in operation.latency_offsets.items()}
self._end_time = max(operation.latency_offsets.values())
self._port_items = []
self.setFlag(QGraphicsItem.ItemIsMovable) # mouse move events
......@@ -71,46 +47,47 @@ class GraphicsComponentItem(QGraphicsItemGroup):
# self.setAcceptHoverEvents(True) # mouse hover events
self.setAcceptedMouseButtons(Qt.LeftButton) # accepted buttons for movements
self.setCursor(QCursor(Qt.OpenHandCursor)) # default cursor when hovering over object
self._make_component()
# def sceneEvent(self, event: QEvent) -> bool:
# print(f'Component -->\t\t\t\t{event.type()}')
# # event.accept()
# # QApplication.sendEvent(self.scene(), event)
# return True
def clear(self) -> None:
"""Sets all children's parent to 'None' and delete the axis."""
for item in self.childItems():
item.setParentItem(None)
del item
@property
def op_id(self) -> str:
"""Get the op-id."""
return self._op_id
return self._operation.graph_id
@property
def height(self) -> float:
"""Get or set the current component height. Setting the height to a new
value will update the component automatically."""
return self._height
@height.setter
def height(self, height: float) -> None:
if self._height != height:
self.clear()
self._height = height
self._make_component()
@property
def end_time(self) -> int:
"""Get the relative end time."""
return self._end_time
@property
def event_items(self) -> List[QGraphicsItem]:
"""Returnes a list of objects, that receives events."""
......@@ -123,22 +100,21 @@ class GraphicsComponentItem(QGraphicsItemGroup):
pen1.setWidthF(2/self._scale)
# pen1.setCapStyle(Qt.RoundCap) # Qt.FlatCap, Qt.SquareCap (default), Qt.RoundCap
pen1.setJoinStyle(Qt.RoundJoin) # Qt.MiterJoin, Qt.BevelJoin (default), Qt.RoundJoin, Qt.SvgMiterJoin
brush2 = QBrush(Qt.black) # used by port filling
pen2 = QPen(Qt.black) # used by port outline
pen2.setWidthF(0)
# pen2.setCosmetic(True)
port_size = 7/self._scale # the diameter of an port
gray = QColor(Qt.gray)
gray.setAlpha(100) # 0-255
brush3 = QBrush(gray) # used by execution time
green = QColor(Qt.magenta)
green.setAlpha(200) # 0-255
pen3 = QPen() # used by execution time outline
pen3.setColor(green)
pen3.setWidthF(3/self._scale)
## component path
def draw_component_path(keys: List[str], revered: bool) -> None:
......@@ -169,14 +145,17 @@ class GraphicsComponentItem(QGraphicsItemGroup):
input_keys = sorted(input_keys)
output_keys = [key for key in self._ports.keys() if key.lower().startswith("out")]
output_keys = sorted(output_keys, reverse=True)
# Set the starting position
x = self._ports[input_keys[0]]['latency']
if input_keys:
x = self._ports[input_keys[0]]['latency']
else:
x = 0
y = 0
old_x = x
old_y = y
component_path = QPainterPath(QPointF(x, y)) # starting point
# draw the path
draw_component_path(input_keys, False) # draw input side
draw_component_path(output_keys, True) # draw ouput side
......@@ -198,22 +177,22 @@ class GraphicsComponentItem(QGraphicsItemGroup):
self._port_items[-1].setPos(port_pos.x(), port_pos.y())
## op-id/label
self._label_item = QGraphicsSimpleTextItem(self._op_id)
self._label_item = QGraphicsSimpleTextItem(self._operation.graph_id)
self._label_item.setScale(self._label_item.scale() / self._scale)
center = self._component_item.boundingRect().center()
center -= self._label_item.boundingRect().center() / self._scale
self._label_item.setPos(self._component_item.pos() + center)
## execution time
if self._execution_time:
self._execution_time_item = QGraphicsRectItem(0, 0, self._execution_time, self._height)
if self._operation.execution_time:
self._execution_time_item = QGraphicsRectItem(0, 0, self._operation.execution_time, self._height)
self._execution_time_item.setPen(pen3)
# self._execution_time_item.setBrush(brush3)
## item group, consist of component_item, port_items and execution_time_item
self.addToGroup(self._component_item)
for port in self._port_items:
self.addToGroup(port)
self.addToGroup(self._label_item)
if self._execution_time:
if self._operation.execution_time:
self.addToGroup(self._execution_time_item)
......@@ -5,38 +5,15 @@
Contains the scheduler-gui GraphicsGraphEvent class containing event filters and handlers for GraphicsGraphItem objects.
"""
import os
import sys
from typing import Any, Optional
from pprint import pprint
from typing import Any, Union, Optional, overload, Final, final, List
# from typing_extensions import Self, Final, Literal, LiteralString, TypeAlias, final
import numpy as np
from copy import deepcopy
from itertools import combinations
import qtpy
from qtpy import QtCore
from qtpy import QtGui
from qtpy import QtWidgets
from typing import Optional, overload, List
# QGraphics and QPainter imports
from qtpy.QtCore import (
Qt, QObject, QRect, QRectF, QPoint, QSize, QSizeF, QByteArray, Signal, Slot, QEvent)
from qtpy.QtGui import (
QPaintEvent, QPainter, QPainterPath, QColor, QBrush, QPen, QFont, QPolygon, QIcon, QPixmap,
QLinearGradient, QTransform, QCursor, QFocusEvent)
from qtpy.QtCore import Qt, QObject, Signal, QEvent, QPointF
from qtpy.QtGui import QCursor, QFocusEvent
from qtpy.QtWidgets import (
QGraphicsView, QGraphicsScene, QGraphicsWidget,
QGraphicsLayout, QGraphicsLinearLayout, QGraphicsGridLayout, QGraphicsLayoutItem, QGraphicsAnchorLayout,
QGraphicsItem, QGraphicsItemGroup, QGraphicsPathItem, QGraphicsLineItem, QGraphicsRectItem,
QStyleOptionGraphicsItem, QWidget,
QGraphicsObject, QGraphicsSceneMouseEvent, QGraphicsSceneHoverEvent, QGraphicsSceneContextMenuEvent,
QGraphicsSceneDragDropEvent, QGraphicsSceneWheelEvent)
from qtpy.QtCore import (
QPoint, QPointF)
from abc import ABC
QGraphicsItem, QGraphicsSceneMouseEvent, QGraphicsSceneHoverEvent,
QGraphicsSceneContextMenuEvent, QGraphicsSceneDragDropEvent, QGraphicsSceneWheelEvent)
from graphics_component_item import GraphicsComponentItem
from graphics_axes_item import GraphicsAxesItem
from graphics_timeline_item import GraphicsTimelineItem
......@@ -51,7 +28,7 @@ class GraphicsGraphEvent: # PyQt5
"""A class respresenting signals."""
component_selected = Signal(str)
schedule_time_changed = Signal()
_axes: GraphicsAxesItem
_current_pos: QPointF
_delta_time: int
......@@ -59,12 +36,12 @@ class GraphicsGraphEvent: # PyQt5
# component_selected = Signal(str) # PySide2
# schedule_time_changed = Signal() # PySide2
@overload
#@overload
def is_component_valid_pos(self, pos: float, end_time: int) -> bool: ...
@overload
#@overload
def is_valid_delta_time(self, delta_time: int) -> bool: ...
@overload
#@overload
def set_schedule_time(self, delta_time: int) -> None: ...
# def __init__(self, parent: Optional[QGraphicsItem] = None): # PySide2
......@@ -91,7 +68,7 @@ class GraphicsGraphEvent: # PyQt5
item: GraphicsComponentItem
for item in filterItems:
item.installSceneEventFilter(self)
@overload
def removeSceneEventFilters(self, filterItems: QGraphicsItem) -> None: ...
@overload
......@@ -102,8 +79,8 @@ class GraphicsGraphEvent: # PyQt5
item: GraphicsComponentItem
for item in filterItems:
item.removeSceneEventFilter(self)
def sceneEventFilter(self, item: QGraphicsItem, event: QEvent) -> bool:
"""Returns true if the event was filtered (i.e. stopped), otherwise false.
If false is returned, the event is forwarded to the appropriate child in
......@@ -128,7 +105,7 @@ class GraphicsGraphEvent: # PyQt5
# QEvent.GraphicsSceneWheel: self.comp_wheelEvent
}
handler = switch.get(event.type())
elif isinstance(item, GraphicsTimelineItem): # the timeline
switch = {
# QEvent.GraphicsSceneHoverEnter: self.timeline_hoverEnterEvent,
......@@ -138,11 +115,11 @@ class GraphicsGraphEvent: # PyQt5
QEvent.GraphicsSceneMouseRelease: self.timeline_mouseReleaseEvent,
}
handler = switch.get(event.type())
else:
raise TypeError(f"Received an unexpected event '{event.type()}' "
f"from an '{type(item).__name__}' object.")
if handler is not None:
handler(event)
return True
......@@ -169,7 +146,7 @@ class GraphicsGraphEvent: # PyQt5
def comp_hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent) -> None: ...
def comp_mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Set the position of the graphical element in the graphic scene,
"""Set the position of the graphical element in the graphic scene,
translate coordinates of the cursor within the graphic element in the
coordinate system of the parent object. The object can only move
horizontally in x-axis scale steps."""
......@@ -189,7 +166,7 @@ class GraphicsGraphEvent: # PyQt5
# self.prepareGeometryChange()
item.setX(pos)
self._current_pos.setX(self._current_pos.x() - 1.0)
def comp_mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Changes the cursor to ClosedHandCursor when grabbing an object and
stores the current position in item's parent coordinates. 'event' will
......@@ -201,7 +178,7 @@ class GraphicsGraphEvent: # PyQt5
self._current_pos = item.mapToParent(event.pos())
item.setCursor(QCursor(Qt.ClosedHandCursor))
event.accept()
def comp_mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Changes the cursor to OpenHandCursor when releasing an object."""
item: GraphicsComponentItem = self.scene().mouseGrabberItem()
......@@ -209,14 +186,14 @@ class GraphicsGraphEvent: # PyQt5
def comp_mouseDoubleClickEvent(self, event: QGraphicsSceneMouseEvent) -> None: ...
def comp_wheelEvent(self, event: QGraphicsSceneWheelEvent) -> None: ...
###############################################
#### Event Handlers: GraphicsLineTem ####
###############################################
def timeline_mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Set the position of the graphical element in the graphic scene,
"""Set the position of the graphical element in the graphic scene,
translate coordinates of the cursor within the graphic element in the
coordinate system of the parent object. The object can only move
horizontally in x-axis scale steps."""
......@@ -240,7 +217,7 @@ class GraphicsGraphEvent: # PyQt5
self._current_pos.setX(self._current_pos.x() - 1.0)
self._delta_time -= 1
item.set_text(self._delta_time)
def timeline_mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Stores the current position in item's parent coordinates. 'event' will
by default be accepted, and this item is then the mouse grabber. This
......@@ -251,7 +228,7 @@ class GraphicsGraphEvent: # PyQt5
item.show_label()
self._current_pos = item.mapToParent(event.pos())
event.accept()
def timeline_mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Updates the schedule time."""
item: GraphicsTimelineItem = self.scene().mouseGrabberItem()
......
......@@ -118,13 +118,13 @@ class GraphicsGraphItem(GraphicsGraphEvent, QGraphicsItemGroup): # PySide2 /
for op_id, op_start_time in self.schedule.start_times.items():
op = self.schedule.sfg.find_by_id(op_id)
if not isinstance(op, (Input, Output)):
self._components_height += spacing
component = GraphicsComponentItem(op_id, op.latency_offsets, op.execution_time)
component.setPos(self._x_axis_indent + op_start_time, self._components_height)
self._components.append(component)
self._components_height += component.height
self._event_items += component.event_items
# if not isinstance(op, (Input, Output)):
self._components_height += spacing
component = GraphicsComponentItem(op)
component.setPos(self._x_axis_indent + op_start_time, self._components_height)
self._components.append(component)
self._components_height += component.height
self._event_items += component.event_items
# self._components_height += spacing
# build axes
......
......@@ -24,7 +24,6 @@ from qtpy.QtWidgets import (
# QGraphics and QPainter imports
from qtpy.QtCore import QRectF, QByteArray
from qtpy.QtGui import QIcon
from qtpy.QtWidgets import QGraphicsScene, QGraphicsItemGroup
# B-ASIC
......
......@@ -19,6 +19,8 @@ class Input(AbstractOperation):
Its value will be updated on each iteration when simulating the SFG.
"""
_execution_time = 0
def __init__(self, name: Name = ""):
"""Construct an Input operation."""
super().__init__(input_count=0, output_count=1, name=name, latency_offsets={'out0' : 0})
......@@ -57,6 +59,8 @@ class Output(AbstractOperation):
destinations.
"""
_execution_time = 0
def __init__(self, src0: Optional[SignalSourceProvider] = None, name: Name = ""):
"""Construct an Output operation."""
super().__init__(input_count=1, output_count=0,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment