diff --git a/b_asic/scheduler_gui/__init__.py b/b_asic/scheduler_gui/__init__.py index e2cb7dd6e6898d2af7ff92fa8550546152f3eb1f..b0b416cacb5fa920c16ed06af6b0c3689e83d3af 100644 --- a/b_asic/scheduler_gui/__init__.py +++ b/b_asic/scheduler_gui/__init__.py @@ -7,11 +7,11 @@ __author__ = "Andreas Bolin" # __all__ = ['main_window', 'graphics_graph', 'component_item', 'graphics_axes', 'graphics_timeline_item'] from b_asic.scheduler_gui._version import * -from b_asic.scheduler_gui.graphics_axes_item import * -from b_asic.scheduler_gui.graphics_component_item import * -from b_asic.scheduler_gui.graphics_graph_event import * -from b_asic.scheduler_gui.graphics_graph_item import * -from b_asic.scheduler_gui.graphics_signal import * -from b_asic.scheduler_gui.graphics_timeline_item import * +from b_asic.scheduler_gui.axes_item import * +from b_asic.scheduler_gui.operation_item import * +from b_asic.scheduler_gui.scheduler_event import * +from b_asic.scheduler_gui.scheduler_item import * +from b_asic.scheduler_gui.signal_item import * +from b_asic.scheduler_gui.timeline_item import * from b_asic.scheduler_gui.logger import * from b_asic.scheduler_gui.main_window import * diff --git a/b_asic/scheduler_gui/graphics_axes_item.py b/b_asic/scheduler_gui/axes_item.py similarity index 95% rename from b_asic/scheduler_gui/graphics_axes_item.py rename to b_asic/scheduler_gui/axes_item.py index be3446ec67efb25136ee522b707e6188cc002c50..e45e49967e44f770109cab7c434c5fabebcf5ffc 100644 --- a/b_asic/scheduler_gui/graphics_axes_item.py +++ b/b_asic/scheduler_gui/axes_item.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """B-ASIC Scheduler-gui Graphics Axes Item Module. -Contains the scheduler-gui GraphicsAxesItem class for drawing and maintain the +Contains the scheduler-gui AxesItem class for drawing and maintain the axes in a graph. """ from math import pi, sin @@ -20,10 +20,10 @@ from qtpy.QtWidgets import ( ) # B-ASIC -from b_asic.scheduler_gui.graphics_timeline_item import GraphicsTimelineItem +from b_asic.scheduler_gui.timeline_item import TimelineItem -class GraphicsAxesItem(QGraphicsItemGroup): +class AxesItem(QGraphicsItemGroup): """A class to represent axes in a graph.""" _scale: float = 1.0 @@ -39,7 +39,7 @@ class GraphicsAxesItem(QGraphicsItemGroup): _x_arrow: QGraphicsPolygonItem _x_scale: List[QGraphicsLineItem] _x_scale_labels: List[QGraphicsSimpleTextItem] - _x_ledger: List[Union[QGraphicsLineItem, GraphicsTimelineItem]] + _x_ledger: List[Union[QGraphicsLineItem, TimelineItem]] _x_label_offset: float _y_axis: QGraphicsLineItem _event_items: List[QGraphicsItem] @@ -58,7 +58,7 @@ class GraphicsAxesItem(QGraphicsItemGroup): parent: Optional[QGraphicsItem] = None, ): """ - Constructs a GraphicsAxesItem. + Constructs a AxesItem. *parent* is passed to QGraphicsItemGroup's constructor. """ super().__init__(parent=parent) @@ -153,7 +153,7 @@ class GraphicsAxesItem(QGraphicsItemGroup): """Register an object that receives events.""" self._event_items.append(item) - def set_height(self, height: int) -> "GraphicsAxesItem": + def set_height(self, height: int) -> "AxesItem": # TODO: implement, docstring if height < 0: raise ValueError( @@ -161,7 +161,7 @@ class GraphicsAxesItem(QGraphicsItemGroup): ) raise NotImplementedError - def set_width(self, width: int) -> "GraphicsAxesItem": + def set_width(self, width: int) -> "AxesItem": # TODO: docstring if width < 0: raise ValueError( @@ -241,7 +241,7 @@ class GraphicsAxesItem(QGraphicsItemGroup): self._x_ledger.insert( index, - GraphicsTimelineItem( + TimelineItem( 0, 0, 0, diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py index 51492d038a5ca9c48bfa58b38afb03a68db897f7..1bd63565f4edffa3ff30811ace2efb26bb0f40c8 100644 --- a/b_asic/scheduler_gui/main_window.py +++ b/b_asic/scheduler_gui/main_window.py @@ -45,9 +45,9 @@ from qtpy.QtWidgets import ( import b_asic.scheduler_gui.logger as logger from b_asic.graph_component import GraphComponent from b_asic.schedule import Schedule -from b_asic.scheduler_gui.graphics_axes_item import GraphicsAxesItem -from b_asic.scheduler_gui.graphics_component_item import GraphicsComponentItem -from b_asic.scheduler_gui.graphics_graph_item import GraphicsGraphItem +from b_asic.scheduler_gui.axes_item import AxesItem +from b_asic.scheduler_gui.operation_item import OperationItem +from b_asic.scheduler_gui.scheduler_item import SchedulerItem sys.path.insert(0, "icons/") # Needed for *.rc.py files in ui_main_window from b_asic.scheduler_gui.ui_main_window import Ui_MainWindow @@ -91,7 +91,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): _scene: QGraphicsScene _schedule: Union[Schedule, None] - _graph: Union[GraphicsGraphItem, None] + _graph: Union[SchedulerItem, None] _scale: float _debug_rects: QGraphicsItemGroup _splitter_pos: int @@ -148,8 +148,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): ) # dummy rect to be able to setPos() graph self.view.setScene(self._scene) self.view.scale(self._scale, self._scale) - GraphicsComponentItem._scale = self._scale - GraphicsAxesItem._scale = self._scale + OperationItem._scale = self._scale + AxesItem._scale = self._scale self._scene.sceneRectChanged.connect(self.shrink_scene_to_min_size) @property @@ -422,10 +422,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): alert.exec_() def open(self, schedule: Schedule) -> None: - """Take a Schedule and create a GraphicsGraphItem object.""" + """Take a Schedule and create a SchedulerItem object.""" self.close_schedule() self._schedule = deepcopy(schedule) - self._graph = GraphicsGraphItem(self.schedule) + self._graph = SchedulerItem(self.schedule) self._graph.setPos(1 / self._scale, 1 / self._scale) self.menu_close_schedule.setEnabled(True) self._scene.addItem(self._graph) diff --git a/b_asic/scheduler_gui/graphics_component_item.py b/b_asic/scheduler_gui/operation_item.py similarity index 96% rename from b_asic/scheduler_gui/graphics_component_item.py rename to b_asic/scheduler_gui/operation_item.py index 680ac943aa7bb02ff2b5ed34287116e8697e15d6..d11205d98165bcb151f553cfe04ddb530bc037a7 100644 --- a/b_asic/scheduler_gui/graphics_component_item.py +++ b/b_asic/scheduler_gui/operation_item.py @@ -3,7 +3,7 @@ """ B-ASIC Scheduler-gui Graphics Component Item Module. -Contains the scheduler-gui GraphicsComponentItem class for drawing and maintain a component in a graph. +Contains the scheduler-gui OperationItem class for drawing and maintain a component in a graph. """ from typing import Dict, List, Optional, Union @@ -28,7 +28,7 @@ from b_asic.scheduler_gui._preferences import ( ) -class GraphicsComponentItem(QGraphicsItemGroup): +class OperationItem(QGraphicsItemGroup): """Class to represent a component in a graph.""" _scale: float = 1.0 @@ -51,7 +51,7 @@ class GraphicsComponentItem(QGraphicsItemGroup): parent: Optional[QGraphicsItem] = None, ): """ - Construct a GraphicsComponentItem. *parent* is passed to QGraphicsItemGroup's constructor. + Construct a OperationItem. *parent* is passed to QGraphicsItemGroup's constructor. """ super().__init__(parent=parent) self._operation = operation diff --git a/b_asic/scheduler_gui/graphics_graph_event.py b/b_asic/scheduler_gui/scheduler_event.py similarity index 88% rename from b_asic/scheduler_gui/graphics_graph_event.py rename to b_asic/scheduler_gui/scheduler_event.py index 8f06d4b0301896122cb12080f93944497a0830ae..67fe9527dce15c6d717f45b6dc2138c47ce3e426 100644 --- a/b_asic/scheduler_gui/graphics_graph_event.py +++ b/b_asic/scheduler_gui/scheduler_event.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """B-ASIC Scheduler-gui Graphics Graph Event Module. -Contains the scheduler-gui GraphicsGraphEvent class containing event filters and handlers for GraphicsGraphItem objects. +Contains the scheduler-gui SchedulerEvent class containing event filters and handlers for SchedulerItem objects. """ from typing import List, Optional, overload @@ -19,15 +19,15 @@ from qtpy.QtWidgets import ( QGraphicsSceneWheelEvent, ) -from b_asic.scheduler_gui.graphics_axes_item import GraphicsAxesItem -from b_asic.scheduler_gui.graphics_component_item import GraphicsComponentItem -from b_asic.scheduler_gui.graphics_timeline_item import GraphicsTimelineItem +from b_asic.scheduler_gui.axes_item import AxesItem +from b_asic.scheduler_gui.operation_item import OperationItem +from b_asic.scheduler_gui.timeline_item import TimelineItem # sys.settrace -# class GraphicsGraphEvent(QGraphicsItemGroup, QObject): # PySide2 -class GraphicsGraphEvent: # PyQt5 - """Event filter and handlers for GraphicsGraphItem""" +# class SchedulerEvent(QGraphicsItemGroup, QObject): # PySide2 +class SchedulerEvent: # PyQt5 + """Event filter and handlers for SchedulerItem""" class Signals(QObject): # PyQt5 """A class representing signals.""" @@ -35,7 +35,7 @@ class GraphicsGraphEvent: # PyQt5 component_selected = Signal(str) schedule_time_changed = Signal() - _axes: GraphicsAxesItem + _axes: AxesItem _current_pos: QPointF _delta_time: int _signals: Signals # PyQt5 @@ -43,9 +43,7 @@ class GraphicsGraphEvent: # PyQt5 # schedule_time_changed = Signal() # PySide2 # @overload - def is_component_valid_pos( - self, item: GraphicsComponentItem, pos: float - ) -> bool: + def is_component_valid_pos(self, item: OperationItem, pos: float) -> bool: ... # @overload @@ -83,7 +81,7 @@ class GraphicsGraphEvent: # PyQt5 """Installs an event filter for 'filterItems' on 'self', causing all events for 'filterItems' to first pass through 'self's sceneEventFilter() function. 'filterItems' can be one object or a list of objects.""" - item: GraphicsComponentItem + item: OperationItem for item in filterItems: item.installSceneEventFilter(self) @@ -100,7 +98,7 @@ class GraphicsGraphEvent: # PyQt5 def removeSceneEventFilters(self, filterItems) -> None: """Removes an event filter on 'filterItems' from 'self'. 'filterItems' can be one object or a list of objects.""" - item: GraphicsComponentItem + item: OperationItem for item in filterItems: item.removeSceneEventFilter(self) @@ -110,7 +108,7 @@ class GraphicsGraphEvent: # PyQt5 the event chain.""" handler = None - if isinstance(item, GraphicsComponentItem): # one component + if isinstance(item, OperationItem): # one component switch = { # QEvent.FocusIn: self.comp_focusInEvent, # QEvent.GraphicsSceneContextMenu: self.comp_contextMenuEvent, @@ -129,7 +127,7 @@ class GraphicsGraphEvent: # PyQt5 } handler = switch.get(event.type()) - elif isinstance(item, GraphicsTimelineItem): # the timeline + elif isinstance(item, TimelineItem): # the timeline switch = { # QEvent.GraphicsSceneHoverEnter: self.timeline_hoverEnterEvent, # QEvent.GraphicsSceneHoverLeave: self.timeline_hoverLeaveEvent, @@ -157,7 +155,7 @@ class GraphicsGraphEvent: # PyQt5 # return False ############################################### - #### Event Handlers: GraphicsComponentItem #### + #### Event Handlers: OperationItem #### ############################################### def comp_focusInEvent(self, event: QFocusEvent) -> None: ... @@ -203,7 +201,7 @@ class GraphicsGraphEvent: # PyQt5 self._current_pos.setX(self._current_pos.x() + dx) self._redraw_lines(item) - item: GraphicsComponentItem = self.scene().mouseGrabberItem() + item: OperationItem = self.scene().mouseGrabberItem() delta_x = (item.mapToParent(event.pos()) - self._current_pos).x() if delta_x > 0.505: update_pos(item, 1) @@ -216,7 +214,7 @@ class GraphicsGraphEvent: # PyQt5 by default be accepted, and this item is then the mouse grabber. This allows the item to receive future move, release and double-click events. """ - item: GraphicsComponentItem = self.scene().mouseGrabberItem() + item: OperationItem = self.scene().mouseGrabberItem() self._signals.component_selected.emit(item.op_id) # self.component_selected.emit(item.op_id) self._current_pos = item.mapToParent(event.pos()) @@ -225,7 +223,7 @@ class GraphicsGraphEvent: # PyQt5 def comp_mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent) -> None: """Changes the cursor to OpenHandCursor when releasing an object.""" - item: GraphicsComponentItem = self.scene().mouseGrabberItem() + item: OperationItem = self.scene().mouseGrabberItem() self.set_item_inactive(item) self.set_new_starttime(item) pos = item.x() @@ -268,7 +266,7 @@ class GraphicsGraphEvent: # PyQt5 self._delta_time += dx item.set_text(self._delta_time) - item: GraphicsTimelineItem = self.scene().mouseGrabberItem() + item: TimelineItem = self.scene().mouseGrabberItem() delta_x = (item.mapToParent(event.pos()) - self._current_pos).x() if delta_x > 0.505: update_pos(item, 1) @@ -282,7 +280,7 @@ class GraphicsGraphEvent: # PyQt5 by default be accepted, and this item is then the mouse grabber. This allows the item to receive future move, release and double-click events. """ - item: GraphicsTimelineItem = self.scene().mouseGrabberItem() + item: TimelineItem = self.scene().mouseGrabberItem() self._delta_time = 0 item.set_text(self._delta_time) item.show_label() @@ -293,7 +291,7 @@ class GraphicsGraphEvent: # PyQt5 self, event: QGraphicsSceneMouseEvent ) -> None: """Updates the schedule time.""" - item: GraphicsTimelineItem = self.scene().mouseGrabberItem() + item: TimelineItem = self.scene().mouseGrabberItem() item.hide_label() if self._delta_time != 0: self.set_schedule_time(self._delta_time) diff --git a/b_asic/scheduler_gui/graphics_graph_item.py b/b_asic/scheduler_gui/scheduler_item.py similarity index 79% rename from b_asic/scheduler_gui/graphics_graph_item.py rename to b_asic/scheduler_gui/scheduler_item.py index 07d83fa1ea8c33e7264407ae04504492b9a6c87c..fc56da5a644abbec8ff3626722b480bfc4a155fb 100644 --- a/b_asic/scheduler_gui/graphics_graph_item.py +++ b/b_asic/scheduler_gui/scheduler_item.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """B-ASIC Scheduler-gui Graphics Graph Item Module. -Contains the scheduler-gui GraphicsGraphItem class for drawing and +Contains the scheduler-gui SchedulerItem class for drawing and maintain a component in a graph. """ from collections import defaultdict @@ -15,36 +15,34 @@ from qtpy.QtWidgets import QGraphicsItem, QGraphicsItemGroup # B-ASIC from b_asic.schedule import Schedule -from b_asic.scheduler_gui.graphics_axes_item import GraphicsAxesItem -from b_asic.scheduler_gui.graphics_component_item import GraphicsComponentItem -from b_asic.scheduler_gui.graphics_graph_event import GraphicsGraphEvent -from b_asic.scheduler_gui.graphics_signal import GraphicsSignal +from b_asic.scheduler_gui.axes_item import AxesItem +from b_asic.scheduler_gui.operation_item import OperationItem +from b_asic.scheduler_gui.scheduler_event import SchedulerEvent +from b_asic.scheduler_gui.signal_item import SignalItem -class GraphicsGraphItem( - GraphicsGraphEvent, QGraphicsItemGroup -): # PySide2 / PyQt5 - # class GraphicsGraphItem(QGraphicsItemGroup, GraphicsGraphEvent): # PyQt5 +class SchedulerItem(SchedulerEvent, QGraphicsItemGroup): # PySide2 / PyQt5 + # class SchedulerItem(QGraphicsItemGroup, SchedulerEvent): # PyQt5 """A class to represent a graph in a QGraphicsScene. This class is a subclass of QGraphicsItemGroup and contains the objects, axes from - GraphicsAxesItem, as well as components from GraphicsComponentItem. It - also inherits from GraphicsGraphEvent, which acts as a filter for events - to GraphicsComponentItem objects.""" + AxesItem, as well as components from OperationItem. It + also inherits from SchedulerEvent, which acts as a filter for events + to OperationItem objects.""" _schedule: Schedule - _axes: GraphicsAxesItem - _components: List[GraphicsComponentItem] + _axes: AxesItem + _components: List[OperationItem] _components_height: float _x_axis_indent: float _event_items: List[QGraphicsItem] - _signal_dict: Dict[GraphicsComponentItem, Set[GraphicsSignal]] + _signal_dict: Dict[OperationItem, Set[SignalItem]] def __init__( self, schedule: Schedule, parent: Optional[QGraphicsItem] = None ): - """Constructs a GraphicsGraphItem. 'parent' is passed to QGraphicsItemGroup's constructor. + """Constructs a SchedulerItem. 'parent' is passed to QGraphicsItemGroup's constructor. """ # QGraphicsItemGroup.__init__(self, self) - # GraphicsGraphEvent.__init__(self) + # SchedulerEvent.__init__(self) super().__init__(parent=parent) # if isinstance(parent, QGraphicsItem): # super().__init__(parent=parent) @@ -67,9 +65,7 @@ class GraphicsGraphItem( item.setParentItem(None) del item - def is_component_valid_pos( - self, item: GraphicsComponentItem, pos: float - ) -> bool: + def is_component_valid_pos(self, item: OperationItem, pos: float) -> bool: """Takes in a component position and returns true if the component's new position is valid, false otherwise.""" # TODO: implement @@ -96,22 +92,22 @@ class GraphicsGraphItem( return True - def _redraw_lines(self, item: GraphicsComponentItem): + def _redraw_lines(self, item: OperationItem): """Update lines connected to *item*.""" for signal in self._signal_dict[item]: signal.update_path() - def set_item_active(self, item: GraphicsComponentItem): + def set_item_active(self, item: OperationItem): item.set_active() for signal in self._signal_dict[item]: signal.set_active() - def set_item_inactive(self, item: GraphicsComponentItem): + def set_item_inactive(self, item: OperationItem): item.set_inactive() for signal in self._signal_dict[item]: signal.set_inactive() - def set_new_starttime(self, item: GraphicsComponentItem) -> None: + def set_new_starttime(self, item: OperationItem) -> None: """Set new starttime for *item*.""" pos = item.x() op_start_time = self.schedule.start_time_of_operation(item.op_id) @@ -149,11 +145,11 @@ class GraphicsGraphItem( return self._schedule @property - def axes(self) -> GraphicsAxesItem: + def axes(self) -> AxesItem: return self._axes @property - def components(self) -> List[GraphicsComponentItem]: + def components(self) -> List[OperationItem]: return self._components @property @@ -172,7 +168,7 @@ class GraphicsGraphItem( # if not isinstance(op, (Input, Output)): self._components_height += spacing - component = GraphicsComponentItem(operation, parent=self) + component = OperationItem(operation, parent=self) component.setPos( self._x_axis_indent + op_start_time, self._components_height ) @@ -184,9 +180,7 @@ class GraphicsGraphItem( # build axes schedule_time = self.schedule.schedule_time - self._axes = GraphicsAxesItem( - schedule_time, self._components_height - spacing - ) + self._axes = AxesItem(schedule_time, self._components_height - spacing) self._axes.setPos(0, self._components_height + spacing * 2) self._event_items += self._axes.event_items # self._axes.width = schedule_time @@ -205,7 +199,7 @@ class GraphicsGraphItem( dest_component = _components_dict[ signal.destination.operation ] - gui_signal = GraphicsSignal( + gui_signal = SignalItem( component, dest_component, signal, parent=self ) self.addToGroup(gui_signal) @@ -213,4 +207,4 @@ class GraphicsGraphItem( self._signal_dict[dest_component].add(gui_signal) -pprint(GraphicsGraphItem.__mro__) +pprint(SchedulerItem.__mro__) diff --git a/b_asic/scheduler_gui/graphics_signal.py b/b_asic/scheduler_gui/signal_item.py similarity index 89% rename from b_asic/scheduler_gui/graphics_signal.py rename to b_asic/scheduler_gui/signal_item.py index 357429145267fff8616a7eadab7351a157692121..cc269f3c5163a35e100c88bd6c4fee5f424213f9 100644 --- a/b_asic/scheduler_gui/graphics_signal.py +++ b/b_asic/scheduler_gui/signal_item.py @@ -9,24 +9,24 @@ from b_asic.scheduler_gui._preferences import ( SIGNAL_INACTIVE, SIGNAL_WIDTH, ) -from b_asic.scheduler_gui.graphics_component_item import GraphicsComponentItem +from b_asic.scheduler_gui.operation_item import OperationItem # B-ASIC from b_asic.signal import Signal -class GraphicsSignal(QGraphicsPathItem): +class SignalItem(QGraphicsPathItem): _path: Optional[QPainterPath] = None - _src_operation: GraphicsComponentItem - _dest_operation: GraphicsComponentItem + _src_operation: OperationItem + _dest_operation: OperationItem _signal: Signal _active_pen: QPen _inactive_pen: QPen def __init__( self, - src_operation: GraphicsComponentItem, - dest_operation: GraphicsComponentItem, + src_operation: OperationItem, + dest_operation: OperationItem, signal: Signal, parent: Optional[QGraphicsItem] = None, ): diff --git a/b_asic/scheduler_gui/graphics_timeline_item.py b/b_asic/scheduler_gui/timeline_item.py similarity index 89% rename from b_asic/scheduler_gui/graphics_timeline_item.py rename to b_asic/scheduler_gui/timeline_item.py index 826122ab22595c9171d7ae62f0f67bb1dacdf057..97908ac5aecc454171387aac86f6418a7f94742f 100644 --- a/b_asic/scheduler_gui/graphics_timeline_item.py +++ b/b_asic/scheduler_gui/timeline_item.py @@ -3,7 +3,7 @@ """ B-ASIC Scheduler-gui Graphics Timeline Item Module. -Contains the scheduler-gui GraphicsTimelineItem class for drawing and +Contains the scheduler-gui TimelineItem class for drawing and maintain the timeline in a graph. """ from typing import List, Optional, overload @@ -14,8 +14,8 @@ from qtpy.QtGui import QCursor from qtpy.QtWidgets import QGraphicsItem, QGraphicsLineItem, QGraphicsTextItem -class GraphicsTimelineItem(QGraphicsLineItem): - """A class to represent the timeline in GraphicsAxesItem.""" +class TimelineItem(QGraphicsLineItem): + """A class to represent the timeline in AxesItem.""" # _scale: float _delta_time_label: QGraphicsTextItem @@ -25,13 +25,13 @@ class GraphicsTimelineItem(QGraphicsLineItem): self, line: QLineF, parent: Optional[QGraphicsItem] = None ) -> None: """ - Constructs a GraphicsTimelineItem out of 'line'. 'parent' is passed to + Constructs a TimelineItem out of 'line'. 'parent' is passed to QGraphicsLineItem's constructor. """ @overload def __init__(self, parent: Optional[QGraphicsItem] = None) -> None: - """Constructs a GraphicsTimelineItem. 'parent' is passed to + """Constructs a TimelineItem. 'parent' is passed to QGraphicsLineItem's constructor.""" @overload @@ -44,7 +44,7 @@ class GraphicsTimelineItem(QGraphicsLineItem): parent: Optional[QGraphicsItem] = None, ) -> None: """ - Constructs a GraphicsTimelineItem from (x1, y1) to (x2, y2). 'parent' + Constructs a TimelineItem from (x1, y1) to (x2, y2). 'parent' is passed to QGraphicsLineItem's constructor. """