summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsumit2020-04-29 16:21:15 +0530
committersumit2020-04-29 16:21:15 +0530
commit44a9cd8f7c9a4fcd62b54321cf6e030b426256a9 (patch)
treef39b8688d309d720cd5197869ac6d3b761beb72f
parentdcacd690cf195f76451401655874f8ef5efd2c60 (diff)
downloadChemical-PFD-44a9cd8f7c9a4fcd62b54321cf6e030b426256a9.tar.gz
Chemical-PFD-44a9cd8f7c9a4fcd62b54321cf6e030b426256a9.tar.bz2
Chemical-PFD-44a9cd8f7c9a4fcd62b54321cf6e030b426256a9.zip
implement zig-zag line
-rw-r--r--line.py60
-rw-r--r--shapes.py358
2 files changed, 312 insertions, 106 deletions
diff --git a/line.py b/line.py
new file mode 100644
index 0000000..941016d
--- /dev/null
+++ b/line.py
@@ -0,0 +1,60 @@
+from PyQt5.QtGui import QFont, QPen
+from PyQt5.QtWidgets import QGraphicsLineItem, QLineEdit, QGraphicsProxyWidget, QGraphicsItem
+from PyQt5.QtCore import Qt, QPointF, QRectF
+
+
+class Line(QGraphicsItem):
+ def __init__(self, startPoint, endPoint, **args):
+ QGraphicsItem.__init__(self, **args)
+ self.startPoint = startPoint
+ self.endPoint = endPoint
+ self.startGripItem = None
+ self.endGripItem = None
+
+ self.setFlag(QGraphicsItem.ItemIsSelectable, True)
+ # self.setFlag(QGraphicsItem.ItemIsMovable, True)
+ self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
+ self.setAcceptHoverEvents(True)
+
+ def setStartGripItem(self, item):
+ self.startGripItem = item
+
+ def setEndGripItem(self, item):
+ self.endGripItem = item
+
+ def boundingRect(self):
+ x0, y0 = self.startPoint.x(), self.startPoint.y()
+ x1, y1 = self.endPoint.x(), self.endPoint.y()
+ return QRectF(min(x0, x1), min(y0, y1), abs(x1 - x0), abs(y1 - y0))
+
+ def paint(self, painter, style, widget=None):
+ x0, y0 = self.startPoint.x(), self.startPoint.y()
+ x1, y1 = self.endPoint.x(), self.endPoint.y()
+ painter.drawLine(x0, y0, (x0 + x1) / 2, y0)
+ painter.drawLine((x0 + x1) / 2, y0, (x0 + x1) / 2, y1)
+ painter.drawLine((x0 + x1) / 2, y1, x1, y1)
+
+ def updateLine(self, startPoint=None, endPoint=None):
+
+ """This function is used to update connecting line when it add on
+ canvas and when it's grip item moves
+ :return:
+ """
+ if self.startGripItem and self.endGripItem:
+ item = self.startGripItem
+ self.startPoint = item.parentItem().mapToScene(item.pos())
+ item = self.endGripItem
+ self.endPoint = item.parentItem().mapToScene(item.pos())
+ if startPoint:
+ self.startPoint = startPoint
+ if endPoint:
+ self.endPoint = endPoint
+ self.prepareGeometryChange()
+ self.update(self.boundingRect())
+
+ def removeFromCanvas(self):
+ """This function is used to remove connecting line from canvas
+ :return:
+ """
+ if self.scene():
+ self.scene().removeItem(self)
diff --git a/shapes.py b/shapes.py
index 9b62b64..45a6f36 100644
--- a/shapes.py
+++ b/shapes.py
@@ -2,10 +2,13 @@ import random
from PyQt5 import QtCore
from PyQt5.QtSvg import QGraphicsSvgItem, QSvgRenderer
-from PyQt5.QtWidgets import QLineEdit, QGraphicsItem, QGraphicsEllipseItem, QGraphicsProxyWidget, QGraphicsPathItem
-from PyQt5.QtGui import QPen, QColor, QFont, QCursor, QPainterPath, QPainter
-from PyQt5.QtCore import Qt, QRectF, QPointF, QSizeF
-from PyQt5.uic.properties import QtGui
+from PyQt5.QtWidgets import QLineEdit, QGraphicsItem, QGraphicsEllipseItem, QGraphicsProxyWidget, QGraphicsPathItem, \
+ QGraphicsSceneHoverEvent
+from PyQt5.QtGui import QPen, QColor, QFont, QCursor, QPainterPath, QPainter, QDrag
+from PyQt5.QtCore import Qt, QRectF, QPointF, QSizeF, QEvent, QMimeData
+from PyQt5.uic.properties import QtGui, QtWidgets
+
+from line import Line
class GripItem(QGraphicsPathItem):
@@ -14,40 +17,39 @@ class GripItem(QGraphicsPathItem):
Takes two parameters, reference item (On which the grip items are to appear) and the grip index
"""
circle = QPainterPath()
- circle.addEllipse(QRectF(-5, -5, 20, 20))
+ circle.addEllipse(QRectF(-10, -10, 20, 20))
- def __init__(self, annotation_item, index):
+ def __init__(self, annotation_item, path=None, parent=None):
"""
Extends PyQt5's QGraphicsPathItem to create the general structure of the Grabbable points for resizing shapes.
"""
- super(GripItem, self).__init__()
+ if path is None:
+ path = GripItem.circle
+ QGraphicsPathItem.__init__(self, parent)
self.m_annotation_item = annotation_item
- self.m_index = index
+ # self.m_index = index
- self.setPath(GripItem.circle)
+ self.setPath(path)
self.setPen(QPen(QColor(), -1))
- self.setFlag(QGraphicsItem.ItemIsSelectable, True)
- self.setFlag(QGraphicsItem.ItemIsMovable, True)
- self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
+
self.setAcceptHoverEvents(True)
- self.setZValue(11)
self.setCursor(QCursor(Qt.PointingHandCursor))
- def hoverEnterEvent(self, event):
- """
- defines shape highlighting on Mouse Over
- """
- self.setPen(QPen(QColor("black"), 2))
- self.setBrush(QColor("red"))
- super(GripItem, self).hoverEnterEvent(event)
-
- def hoverLeaveEvent(self, event):
- """
- defines shape highlighting on Mouse Leave
- """
- self.setPen(QPen(Qt.transparent))
- self.setBrush(Qt.transparent)
- super(GripItem, self).hoverLeaveEvent(event)
+ # def hoverEnterEvent(self, event):
+ # """
+ # defines shape highlighting on Mouse Over
+ # """
+ # self.setPen(QPen(QColor("black"), 2))
+ # self.setBrush(QColor("red"))
+ # super(GripItem, self).hoverEnterEvent(event)
+ #
+ # def hoverLeaveEvent(self, event):
+ # """
+ # defines shape highlighting on Mouse Leave
+ # """
+ # self.setPen(QPen(Qt.transparent))
+ # self.setBrush(Qt.transparent)
+ # super(GripItem, self).hoverLeaveEvent(event)
def mouseReleaseEvent(self, event):
"""
@@ -56,26 +58,37 @@ class GripItem(QGraphicsPathItem):
self.setSelected(False)
super(GripItem, self).mouseReleaseEvent(event)
- def itemChange(self, change, value):
- """
- Calls movepoint from reference item, with the index of this grip item
- """
- if change == QGraphicsItem.ItemPositionChange and self.isEnabled():
- self.m_annotation_item.movePoint(self.m_index, value)
- return super(GripItem, self).itemChange(change, value)
+ # def itemChange(self, change, value):
+ # """
+ # Calls movepoint from reference item, with the index of this grip item
+ # """
+ # if change == QGraphicsItem.ItemPositionChange and self.isEnabled():
+ # self.m_annotation_item.movePoint(self.m_index, value)
+ # return super(GripItem, self).itemChange(change, value)
-class DirectionGripItem(GripItem):
+
+class SizeGripItem(GripItem):
"""
Extends grip items for vertical and horizontal directions, with hover events and directional changes
"""
- def __init__(self, annotation_item, direction=Qt.Horizontal, parent=None):
- """
- Extends grip items for vertical and horizontal directions, with hover events and directional changes
- """
- super(DirectionGripItem, self).__init__(annotation_item, parent)
+ def __init__(self, annotation_item, index, direction=Qt.Horizontal, parent=None):
+ self.width = self.height = 0
+ if direction is Qt.Horizontal:
+ self.height = annotation_item.boundingRect().height()
+ else:
+ self.width = annotation_item.boundingRect().width()
+
+ path = QPainterPath()
+ path.addRect(QRectF(0, 0, self.width, self.height))
+ super(SizeGripItem, self).__init__(annotation_item, path=path, parent=parent)
+ self.setFlag(QGraphicsItem.ItemIsSelectable, True)
+ self.setFlag(QGraphicsItem.ItemIsMovable, True)
+ self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
+ self.setZValue(1)
self._direction = direction
+ self.m_index = index
@property
def direction(self):
@@ -84,22 +97,62 @@ class DirectionGripItem(GripItem):
"""
return self._direction
+ def update_path(self):
+ if self._direction is Qt.Horizontal:
+ self.height = self.m_annotation_item.boundingRect().height()
+ else:
+ self.width = self.m_annotation_item.boundingRect().width()
+ path = QPainterPath()
+ path.addRect(QRectF(0, 0, self.width, self.height))
+ self.setPath(path)
+
+ def update_position(self):
+ """updates grip items
+ """
+ self.update_path()
+ pos = self.m_annotation_item.mapToScene(self.point(self.m_index))
+ x = self.m_annotation_item.boundingRect().x()
+ y = self.m_annotation_item.boundingRect().y()
+ pos.setX(pos.x() + x)
+ pos.setY(pos.y() + y)
+ self.setEnabled(False)
+ self.setPos(pos)
+ self.setEnabled(True)
+
+ def point(self, index):
+ """
+ yields a list of positions of grip items in a node item
+ """
+ x = self.m_annotation_item.boundingRect().width()
+ y = self.m_annotation_item.boundingRect().height()
+ if 0 <= index < 4:
+ return [
+ QPointF(0, 0),
+ QPointF(0, 0),
+ QPointF(0, y),
+ QPointF(x, 0)
+ ][index]
+
def hoverEnterEvent(self, event):
"""
Changes cursor to horizontal resize or vertical resize depending on the direction of the grip item on mouse enter
"""
+ self.setPen(QPen(QColor("black"), 2))
+ self.setBrush(QColor("red"))
if self._direction == Qt.Horizontal:
self.setCursor(QCursor(Qt.SizeHorCursor))
else:
self.setCursor(QCursor(Qt.SizeVerCursor))
- super(DirectionGripItem, self).hoverEnterEvent(event)
+ super(SizeGripItem, self).hoverEnterEvent(event)
def hoverLeaveEvent(self, event):
"""
reverts cursor to default on mouse leave
"""
+ self.setPen(QPen(Qt.transparent))
+ self.setBrush(Qt.transparent)
self.setCursor(QCursor(Qt.ArrowCursor))
- super(DirectionGripItem, self).hoverLeaveEvent(event)
+ super(SizeGripItem, self).hoverLeaveEvent(event)
def itemChange(self, change, value):
"""
@@ -114,7 +167,102 @@ class DirectionGripItem(GripItem):
p.setY(value.y())
self.m_annotation_item.movePoint(self.m_index, p)
return p
- return super(DirectionGripItem, self).itemChange(change, value)
+ return super(SizeGripItem, self).itemChange(change, value)
+
+ def removeFromCanvas(self):
+ if self.scene():
+ self.scene().removeItem(self)
+
+
+class LineGripItem(GripItem):
+ def __init__(self, annotation_item, index, parent=None):
+ """
+ Extends grip items for connecting lines , with hover events and mouse events
+ """
+ super(LineGripItem, self).__init__(annotation_item, parent=parent)
+ self.m_index = index
+ self.connectedLines = []
+ self.tempLine = None
+ self.previousHoveredItem = None
+ self.setFlag(QGraphicsItem.ItemIsSelectable, True)
+ self.setZValue(2)
+
+ def point(self, index):
+ """
+ yields a list of positions of grip items in a node item
+ """
+ radiusOfGripItem = self.boundingRect().width() / 2
+ x = self.m_annotation_item.boundingRect().width()
+ y = self.m_annotation_item.boundingRect().height()
+ if 0 <= index < 4:
+ return [
+ QPointF(x / 2, 0),
+ QPointF(0, y / 2),
+ QPointF(x / 2, y),
+ QPointF(x, y / 2)
+ ][index]
+
+ def update_position(self):
+ # print('updating grip item ', self.m_index)
+ pos = self.point(self.m_index)
+ x = self.m_annotation_item.boundingRect().x()
+ y = self.m_annotation_item.boundingRect().y()
+ pos.setX(pos.x() + x)
+ pos.setY(pos.y() + y)
+ self.setEnabled(False)
+ self.setPos(pos)
+ self.setEnabled(True)
+ for line in self.connectedLines:
+ line.updateLine()
+
+ def mousePressEvent(self, mouseEvent):
+ if mouseEvent.button() != Qt.LeftButton:
+ return
+ radiusOfGripItem = self.boundingRect().width() / 2
+ startPoint = endPoint = self.parentItem().mapToScene(self.pos())
+
+ self.tempLine = Line(startPoint, endPoint)
+ self.scene().addItem(self.tempLine)
+ super().mousePressEvent(mouseEvent)
+
+ def mouseMoveEvent(self, mouseEvent):
+ if self.tempLine:
+ endPoint = mouseEvent.scenePos()
+ self.tempLine.updateLine(endPoint=endPoint)
+ super().mouseMoveEvent(mouseEvent)
+ item = self.scene().itemAt(mouseEvent.scenePos().x(), mouseEvent.scenePos().y(),
+ self.m_annotation_item.transform())
+ # print(self.m_annotation_item.transform())
+
+ if self.previousHoveredItem and item != self.previousHoveredItem and \
+ item not in self.previousHoveredItem.lineGripItems:
+ self.previousHoveredItem.hideGripItem()
+
+ if type(item) == NodeItem:
+ self.previousHoveredItem = item
+ item.showGripItem()
+
+ def mouseReleaseEvent(self, mouseEvent):
+ if self.tempLine:
+ item = self.scene().itemAt(mouseEvent.scenePos().x(), mouseEvent.scenePos().y(),
+ self.transform())
+ if type(item) == LineGripItem:
+ endPoint = item.parentItem().mapToScene(item.pos())
+ self.tempLine.updateLine(endPoint=endPoint)
+ self.connectedLines.append(self.tempLine)
+ item.connectedLines.append(self.tempLine)
+ self.tempLine.setStartGripItem(self)
+ self.tempLine.setEndGripItem(item)
+
+ else:
+ self.scene().removeItem(self.tempLine)
+ super().mouseReleaseEvent(mouseEvent)
+ self.tempLine = None
+ self.previousHoveredItem = None
+
+ def removeConnectedLines(self):
+ for line in self.connectedLines:
+ line.removeFromCanvas()
class NodeItem(QGraphicsSvgItem):
@@ -126,18 +274,16 @@ class NodeItem(QGraphicsSvgItem):
self.renderer = QSvgRenderer("svg/" + "Column" + ".svg")
self.setSharedRenderer(self.renderer)
- self.setZValue(1)
+ self.setZValue(2)
self.setAcceptHoverEvents(True)
+ self.setAcceptDrops(True)
self.setFlags(QGraphicsSvgItem.ItemIsMovable |
QGraphicsSvgItem.ItemIsSelectable |
QGraphicsSvgItem.ItemSendsGeometryChanges)
- self.gripItems = []
+ self.lineGripItems = []
+ self.sizeGripItems = []
- # def shape(self):
- # path = QtGui.QPainterPath()
- # path.addRect(QRectF(-10 , -10 ,50 , 50 ))
- # return path
def boundingRect(self):
return self.rect
@@ -154,12 +300,11 @@ class NodeItem(QGraphicsSvgItem):
def movePoint(self, i, p):
"""Move grip item with changing rect of node item
"""
- radiusOfGripItem = self.gripItems[i].boundingRect().width() / 2
x = self.boundingRect().x()
y = self.boundingRect().y()
width = self.boundingRect().width()
height = self.boundingRect().height()
- p_new = self.gripItems[i].pos()
+ p_new = self.sizeGripItems[i].pos()
if i == 0 or i == 1:
self.rect = QRectF(x + p.x() - p_new.x(), y + p.y() - p_new.y(), width - p.x() + p_new.x(),
@@ -169,12 +314,13 @@ class NodeItem(QGraphicsSvgItem):
self.rect = QRectF(x, y, width + p.x() - p_new.x(), height + p.y() - p_new.y())
self.update_rect()
- self.update_items_positions([i])
+ self.updateSizeGripItem([i])
+ self.updateLineGripItem()
def addGripItem(self):
- """adds grip items and the to parent
+ """adds grip items
"""
- if self.scene() and not self.gripItems:
+ if self.scene() and not self.lineGripItems:
for i, (direction) in enumerate(
(
Qt.Vertical,
@@ -183,61 +329,40 @@ class NodeItem(QGraphicsSvgItem):
Qt.Horizontal,
)
):
- item = DirectionGripItem(self, direction, i)
+ item = LineGripItem(self, i)
+ item.setParentItem(self)
+ self.scene().addItem(item)
+ self.lineGripItems.append(item)
+ item = SizeGripItem(self, i, direction)
self.scene().addItem(item)
- self.gripItems.append(item)
+ self.sizeGripItems.append(item)
+
- def update_items_positions(self, index_no_updates=None):
+
+ def updateLineGripItem(self, index_no_updates=None):
+ # index_no_updates = index_no_updates or []
+ for item in self.lineGripItems:
+ item.update_position()
+
+ def updateSizeGripItem(self, index_no_updates=None):
"""updates grip items
"""
index_no_updates = index_no_updates or []
- for i, (item, direction) in enumerate(
- zip(
- self.gripItems,
- (
- Qt.Vertical,
- Qt.Horizontal,
- Qt.Vertical,
- Qt.Horizontal,
- ),
- ),
- ):
+ for i, item in zip(range(len(self.sizeGripItems)), self.sizeGripItems):
if i not in index_no_updates:
- itemToUpdate = self.gripItems[i]
- pos = self.mapToScene(self.point(i))
- x = self.boundingRect().x()
- y = self.boundingRect().y()
- pos.setX(pos.x() + x)
- pos.setY(pos.y() + y)
- itemToUpdate._direction = direction
- itemToUpdate.setEnabled(False)
- itemToUpdate.setPos(pos)
- itemToUpdate.setEnabled(True)
-
- def point(self, index):
- """
- yields a list of positions of grip items in a node item
- """
- radiusOfGripItem = self.gripItems[index].boundingRect().width() / 2
- x = self.boundingRect().width() - radiusOfGripItem
- y = self.boundingRect().height() - radiusOfGripItem
- if 0 <= index < 4:
- return [
- QPointF(x / 2, 0),
- QPointF(0, y / 2),
- QPointF(x / 2, y),
- QPointF(x, y / 2)
- ][index]
+ item.update_position()
def itemChange(self, change, value):
"""Overloads and extends QGraphicsSvgItem to also update gripitem
"""
if change == QGraphicsItem.ItemPositionHasChanged:
- self.update_items_positions()
+ self.updateLineGripItem()
+ self.updateSizeGripItem()
return
if change == QGraphicsItem.ItemSceneHasChanged:
self.addGripItem()
- self.update_items_positions()
+ self.updateLineGripItem()
+ self.updateSizeGripItem()
return
return super(NodeItem, self).itemChange(change, value)
@@ -251,24 +376,45 @@ class NodeItem(QGraphicsSvgItem):
"""This function is used to remove item from canvas
:return:
"""
+ for item in self.lineGripItems:
+ item.removeConnectedLines()
+ for item in self.sizeGripItems:
+ item.removeFromCanvas()
self.scene().removeItem(self)
- def mousePressEvent(self, event):
- # select object
- super(NodeItem, self).mousePressEvent(event)
-
def hoverEnterEvent(self, event):
"""defines shape highlighting on Mouse Over
"""
- for item in self.gripItems:
- item.setPen(QPen(QColor("black"), 2))
- item.setBrush(QColor("red"))
- super(NodeItem, self).hoverEnterEvent(event)
+ self.showGripItem()
+ super(NodeItem, self).hoverEnterEvent(event)
def hoverLeaveEvent(self, event):
"""defines shape highlighting on Mouse Leave
"""
- for item in self.gripItems:
+ self.hideGripItem()
+ super(NodeItem, self).hoverLeaveEvent(event)
+
+ def showGripItem(self):
+ for item in self.lineGripItems:
+ item.setPen(QPen(QColor("black"), 2))
+ item.setBrush(QColor("red"))
+ for item in self.sizeGripItems:
+ item.setPen(QPen(QColor("black"), 2))
+ item.setBrush(QColor("red"))
+
+ def hideGripItem(self):
+ for item in self.lineGripItems:
+ item.setPen(QPen(Qt.transparent))
+ item.setBrush(Qt.transparent)
+ for item in self.sizeGripItems:
item.setPen(QPen(Qt.transparent))
item.setBrush(Qt.transparent)
- super(NodeItem, self).hoverLeaveEvent(event)
+
+ # def mousePressEvent(self, event):
+ # self.setSelected(True)
+ # self.showGripItem()
+ # super(NodeItem, self).mousePressEvent(event)
+
+ # def mouseReleaseEvent(self, event):
+ # self.hideGripItem()
+ # super(NodeItem, self).mouseReleaseEvent(event)