Newer
Older
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
# 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,
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 graphics_component_item import GraphicsComponentItem
from graphics_axes_item import GraphicsAxesItem
from graphics_timeline_item import GraphicsTimelineItem
# sys.settrace
# class GraphicsGraphEvent(QGraphicsItemGroup, QObject): # PySide2
class GraphicsGraphEvent(): # PyQt5
class Signals(QObject): # PyQt5
"""A class respresenting signals."""
component_selected = Signal(str)
schedule_time_changed = Signal()
signals: Signals # PyQt5
# component_selected = Signal(str) # PySide2
# schedule_time_changed = Signal() # PySide2
@overload
def is_component_valid_pos(self, pos: float, end_time: int) -> bool: ...
@overload
def is_valid_delta_time(self, delta_time: int) -> bool: ...
@overload
def set_schedule_time(self, delta_time: int) -> None: ...
# def __init__(self, parent: Optional[QGraphicsItem] = None): # PySide2
# QObject.__init__(self)
# QGraphicsItemGroup.__init__(self, parent)
def __init__(self, parent: Optional[QGraphicsItem] = None): # PyQt5
# QGraphicsItemGroup.__init__(self, parent)
# QObject.__init__(self)
super().__init__()
self.signals = self.Signals()
#################
#### Filters ####
#################
@overload
def installSceneEventFilters(self, filterItems: QGraphicsItem) -> None: ...
@overload
def installSceneEventFilters(self, filterItems: List[QGraphicsItem]) -> None: ...
def installSceneEventFilters(self, filterItems) -> None:
"""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."""
@overload
def removeSceneEventFilters(self, filterItems: QGraphicsItem) -> None: ...
@overload
def removeSceneEventFilters(self, filterItems: List[QGraphicsItem]) -> None: ...
def removeSceneEventFilters(self, filterItems) -> None:
"""Removes an event filter on 'filterItems' from 'self'. 'filterItems' can
be one object or a list of objects."""
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
the event chain."""
if isinstance(item, GraphicsComponentItem): # one component
# QEvent.FocusIn: self.comp_focusInEvent,
# QEvent.GraphicsSceneContextMenu: self.comp_contextMenuEvent,
# QEvent.GraphicsSceneDragEnter: self.comp_dragEnterEvent,
# QEvent.GraphicsSceneDragMove: self.comp_dragMoveEvent,
# QEvent.GraphicsSceneDragLeave: self.comp_dragLeaveEvent,
# QEvent.GraphicsSceneDrop: self.comp_dropEvent,
# QEvent.GraphicsSceneHoverEnter: self.comp_hoverEnterEvent,
# QEvent.GraphicsSceneHoverMove: self.comp_hoverMoveEvent,
# QEvent.GraphicsSceneHoverLeave: self.comp_hoverLeaveEvent,
QEvent.GraphicsSceneMouseMove: self.comp_mouseMoveEvent,
QEvent.GraphicsSceneMousePress: self.comp_mousePressEvent,
QEvent.GraphicsSceneMouseRelease: self.comp_mouseReleaseEvent,
# QEvent.GraphicsSceneMouseDoubleClick: self.comp_mouseDoubleClickEvent,
# QEvent.GraphicsSceneWheel: self.comp_wheelEvent
elif isinstance(item, GraphicsTimelineItem): # the timeline
switch = {
# QEvent.GraphicsSceneHoverEnter: self.timeline_hoverEnterEvent,
# QEvent.GraphicsSceneHoverLeave: self.timeline_hoverLeaveEvent,
QEvent.GraphicsSceneMouseMove: self.timeline_mouseMoveEvent,
QEvent.GraphicsSceneMousePress: self.timeline_mousePressEvent,
QEvent.GraphicsSceneMouseRelease: self.timeline_mouseReleaseEvent,
}
handler = switch.get(event.type())
raise TypeError(f"Received an unexpected event '{event.type()}' "
f"from an '{type(item).__name__}' object.")
return False # returns False if event is ignored and pass through event to its child
# def sceneEvent(self, event: QEvent) -> bool:
# print(f'sceneEvent() --> {event.type()}')
# # event.accept()
# # QApplication.sendEvent(self.scene(), event)
# return False
###############################################
#### Event Handlers: GraphicsComponentItem ####
###############################################
def comp_focusInEvent(self, event: QFocusEvent) -> None: ...
def comp_contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None: ...
def comp_dragEnterEvent(self, event: QGraphicsSceneDragDropEvent) -> None: ...
def comp_dragMoveEvent(self, event: QGraphicsSceneDragDropEvent) -> None: ...
def comp_dragLeaveEvent(self, event: QGraphicsSceneDragDropEvent) -> None: ...
def comp_dropEvent(self, event: QGraphicsSceneDragDropEvent) -> None: ...
def comp_hoverEnterEvent(self, event: QGraphicsSceneHoverEvent) -> None: ...
def comp_hoverMoveEvent(self, event: QGraphicsSceneHoverEvent) -> None: ...
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,
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."""
item: GraphicsComponentItem = self.scene().mouseGrabberItem()
dx = (item.mapToParent(event.pos()) - self._current_pos).x()
self._current_pos.setX(self._current_pos.x() + 1.0)
elif dx < -0.505:
pos = item.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
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()
self.signals.component_selected.emit(item.op_id)
# self.component_selected.emit(item.op_id)
def comp_mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Changes the cursor to OpenHandCursor when releasing an object."""
item: GraphicsComponentItem = self.scene().mouseGrabberItem()
item.setCursor(QCursor(Qt.OpenHandCursor))
def comp_mouseDoubleClickEvent(self, event: QGraphicsSceneMouseEvent) -> None: ...
def comp_wheelEvent(self, event: QGraphicsSceneWheelEvent) -> None: ...
def timeline_mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""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."""
# Qt.DragMoveCursor
# button = event.button()
item: GraphicsTimelineItem = self.scene().mouseGrabberItem()
dx = (item.mapToParent(event.pos()) - self._current_pos).x()
if dx > 0.505:
pos = item.x() + 1.0
if self.is_valid_delta_time(self._delta_time + 1):
# self.prepareGeometryChange()
item.setX(pos)
self._current_pos.setX(self._current_pos.x() + 1.0)
self._delta_time += 1
elif dx < -0.505:
pos = item.x() - 1.0
if self.is_valid_delta_time(self._delta_time - 1):
# self.prepareGeometryChange()
item.setX(pos)
self._current_pos.setX(self._current_pos.x() - 1.0)
self._delta_time -= 1
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
allows the item to receive future move, release and double-click events."""
item: GraphicsTimelineItem = self.scene().mouseGrabberItem()
item.set_text(self._delta_time)
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()
item.hide_label()
if self._delta_time != 0:
self.set_schedule_time(self._delta_time)
self.signals.schedule_time_changed.emit()