diff options
author | sumit | 2020-04-29 16:21:15 +0530 |
---|---|---|
committer | sumit | 2020-04-29 16:21:15 +0530 |
commit | 44a9cd8f7c9a4fcd62b54321cf6e030b426256a9 (patch) | |
tree | f39b8688d309d720cd5197869ac6d3b761beb72f | |
parent | dcacd690cf195f76451401655874f8ef5efd2c60 (diff) | |
download | Chemical-PFD-44a9cd8f7c9a4fcd62b54321cf6e030b426256a9.tar.gz Chemical-PFD-44a9cd8f7c9a4fcd62b54321cf6e030b426256a9.tar.bz2 Chemical-PFD-44a9cd8f7c9a4fcd62b54321cf6e030b426256a9.zip |
implement zig-zag line
-rw-r--r-- | line.py | 60 | ||||
-rw-r--r-- | shapes.py | 358 |
2 files changed, 312 insertions, 106 deletions
@@ -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) @@ -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) |