Пример #1
0
    def initialize(self) -> None:
        """
        Method to initialize the display of this item

        :return: None
        """
        op = self.sceneBoundingRect().center()
        self.setTransformOriginPoint(op)
        self.setRotation(self.angle)
        cx, cy = self.center
        r1, r2 = self.height / 2, self.width / 2
        # Draw major axis
        major_axis = QGraphicsLineItem(-r2, 0, r2, 0)
        major_axis.setPos(cx, cy)
        major_axis.setParentItem(self)
        # Draw minor axis
        minor_axis = QGraphicsLineItem(-r1, 0, r1, 0)
        minor_axis.setPos(cx, cy)
        minor_axis.setParentItem(self)
        minor_axis.setRotation(90)
        rect = EditingRectangle(self.x, self.y, self.center[0], self.center[1],
                                self.width, self.height)
        rect.setTransformOriginPoint(rect.sceneBoundingRect().center())
        rect.setRotation(self.angle)
        self.indicators.extend([
            major_axis,
            minor_axis,
        ])
        self.edit_rect = rect
        self.rect = self.boundingRect()
        self.edit_rect.activate(False)
        self.setEnabled(False)
Пример #2
0
    def __init__(self, name, surname, birth, death, mom, dad, photo, scene):
        self.circle = callbackEllipse(-40, -40, 80, 80)

        self.name = name
        self.circle.name = name
        self.surname = surname
        self.circle.surname = surname
        humans[name + " " + surname] = self
        self.birth = birth
        self.circle.birth = birth
        self.death = death
        self.circle.death = death
        self.circle.mom = mom
        self.circle.dad = dad
        self.photo = photo
        self.family = []
        self.edges = []

        self.scene = scene

        self.circle.setFlag(QGraphicsItem.isWidget(self.circle))
        self.circle.setFlag(QGraphicsItem.ItemIsMovable)
        self.circle.setToolTip(self.name + " " + self.surname)


        if mom != "" and mom in humans and mom != name + " " + surname:
            self.family.append(humans[mom])
            humans[mom].family.append(self)
            line = QGraphicsLineItem(QLineF(self.circle.pos(), humans[mom].circle.pos()))
            line.setFlag(QGraphicsLineItem.ItemIsMovable)
            self.scene.addItem(line)
            self.edges.append(line)
            humans[mom].edges.append(line)
            line.setParentItem(self.circle)


        if dad != "" and dad in humans and dad != name + " " + surname:
            self.family.append(humans[dad])
            humans[dad].family.append(self)
            line = QGraphicsLineItem(QLineF(self.circle.pos(), humans[dad].circle.pos()))
            line.setFlag(QGraphicsLineItem.ItemIsMovable)
            self.scene.addItem(line)
            self.edges.append(line)
            humans[dad].edges.append(line)

        self.scene.addItem(self.circle)
Пример #3
0
    def onMouseMove_draw(self, imageview, event):
        self._navIntr.onMouseMove_default(imageview, event)

        o = imageview.scene().data2scene.map(
            QPointF(imageview.oldX, imageview.oldY))
        n = imageview.scene().data2scene.map(QPointF(imageview.x, imageview.y))

        # Draw temporary line for the brush stroke so the user gets feedback before the data is really updated.
        pen = QPen(QBrush(self._brushingCtrl._brushingModel.drawColor),
                   self._brushingCtrl._brushingModel.brushSize, Qt.SolidLine,
                   Qt.RoundCap, Qt.RoundJoin)
        line = QGraphicsLineItem(o.x(), o.y(), n.x(), n.y())
        line.setPen(pen)

        imageview.scene().addItem(line)
        line.setParentItem(imageview.scene().dataRectItem)

        self._lineItems.append(line)
        self._brushingCtrl._brushingModel.moveTo(imageview.mousePos)
Пример #4
0
    def onMouseMove_draw(self, imageview, event):
        self._navIntr.onMouseMove_default(imageview, event)

        o = imageview.scene().data2scene.map(QPointF(imageview.oldX, imageview.oldY))
        n = imageview.scene().data2scene.map(QPointF(imageview.x, imageview.y))

        # Draw temporary line for the brush stroke so the user gets feedback before the data is really updated.
        pen = QPen(
            QBrush(self._brushingCtrl._brushingModel.drawColor),
            self._brushingCtrl._brushingModel.brushSize,
            Qt.SolidLine,
            Qt.RoundCap,
            Qt.RoundJoin,
        )
        line = QGraphicsLineItem(o.x(), o.y(), n.x(), n.y())
        line.setPen(pen)

        imageview.scene().addItem(line)
        line.setParentItem(imageview.scene().dataRectItem)

        self._lineItems.append(line)
        self._brushingCtrl._brushingModel.moveTo(imageview.mousePos)
Пример #5
0
class AbstractSliceTool(QGraphicsObject):
    """Summary

    Attributes:
        angles (TYPE): Description
        FILTER_NAME (str): Description
        is_started (bool): Description
        manager (TYPE): Description
        part_item (TYPE): Description
        sgv (TYPE): Description
        vectors (TYPE): Description
    """
    _RADIUS = styles.SLICE_HELIX_RADIUS
    _CENTER_OF_HELIX = QPointF(_RADIUS, _RADIUS)
    FILTER_NAME = 'virtual_helix'
    # _CENTER_OF_HELIX = QPointF(0. 0.)
    """Abstract base class to be subclassed by all other pathview tools."""
    def __init__(self, manager):
        """Summary

        Args:
            manager (TYPE): Description
        """
        super(AbstractSliceTool, self).__init__(parent=manager.viewroot)
        """ Pareting to viewroot to prevent orphan _line_item from occuring
        """
        self.sgv = None
        self.manager = manager
        self._active = False
        self._last_location = None
        self._line_item = QGraphicsLineItem(self)
        self._line_item.hide()
        self._vhi = None

        self.hide()
        self.is_started = False
        self.angles = [math.radians(x) for x in range(0, 360, 30)]
        self.vectors = self.setVectors()
        self.part_item = None

    # end def

    ######################## Drawing #######################################
    def setVectors(self):
        """Summary

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        return [
            QLineF(rad, rad, rad * (1. + 2. * math.cos(x)),
                   rad * (1. + 2. * math.sin(x))) for x in self.angles
        ]

    # end def

    def setVirtualHelixItem(self, virtual_helix_item):
        """Summary

        Args:
            virtual_helix_item (cadnano.gui.views.sliceview.virtualhelixitem.VirtualHelixItem): Description

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        self._vhi = virtual_helix_item
        li = self._line_item
        li.setParentItem(virtual_helix_item)
        li.setLine(rad, rad, rad, rad)
        # li.setLine(0., 0., 0., 0.)

    # end def

    def resetTool(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._line_item.setParentItem(self)

    def idNum(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if self._vhi is not None:
            return self._vhi.idNum()

    def setPartItem(self, part_item):
        """Summary

        Args:
            part_item (TYPE): Description

        Returns:
            TYPE: Description
        """
        self.part_item = part_item

    # end def

    def boundingRect(self):
        """Required to prevent NotImplementedError()
        """
        return QRectF()

    def eventToPosition(self, part_item, event):
        """take an event and return a position as a QPointF
        update widget as well

        Args:
            part_item (TYPE): Description
            event (TYPE): Description
        """
        if self.is_started:
            return self.findNearestPoint(part_item, event.scenePos())
        else:
            return event.pos()

    # end def

    def findNearestPoint(self, part_item, target_scenepos):
        """
        Args:
            part_item (TYPE): Description
            target_scenepos (TYPE): Description
        """
        li = self._line_item
        pos = li.mapFromScene(target_scenepos)

        line = li.line()
        mouse_point_vec = QLineF(self._CENTER_OF_HELIX, pos)

        # Check if the click happened on the origin VH
        if mouse_point_vec.length() < self._RADIUS:
            # return part_item.mapFromScene(target_scenepos)
            return None

        angle_min = 9999
        direction_min = None
        for vector in self.vectors:
            angle_new = mouse_point_vec.angleTo(vector)
            if angle_new < angle_min:
                direction_min = vector
                angle_min = angle_new
        if direction_min is not None:
            li.setLine(direction_min)
            return part_item.mapFromItem(li, direction_min.p2())
        else:
            print("default point")
            line.setP2(pos)
            li.setLine(line)
            return part_item.mapFromItem(li, pos)

    # end def

    def findNextPoint(self, part_item, target_part_pos):
        """
        Args:
            part_item (TYPE): Description
            target_part_pos (TYPE): Description
        """
        li = self._line_item
        pos = li.mapFromItem(part_item, target_part_pos)
        for i, vector in enumerate(self.vectors):
            if vector.p2() == pos:
                return part_item.mapFromItem(li, self.vectors[i - 1].p2())
        # origin VirtualHelixItem is overlapping destination VirtualHelixItem
        return part_item.mapFromItem(li, self.vectors[0].p2())

    # end def

    def hideLineItem(self):
        """Summary

        Returns:
            TYPE: Description
        """
        li = self._line_item
        li.setParentItem(self)
        line = li.line()
        line.setP2(self._CENTER_OF_HELIX)
        li.setLine(line)
        li.hide()
        self.is_started = False

    # end def

    def hoverMoveEvent(self, part_item, event):
        """Summary

        Args:
            part_item (TYPE): Description
            event (TYPE): Description

        Returns:
            TYPE: Description
        """
        return self.eventToPosition(part_item, event)

    # end def

    def setActive(self, will_be_active, old_tool=None):
        """
        Called by SliceToolManager.setActiveTool when the tool becomes
        active. Used, for example, to show/hide tool-specific ui elements.

        Args:
            will_be_active (TYPE): Description
            old_tool (None, optional): Description
        """
        if self._active and not will_be_active:
            self.deactivate()
        self._active = will_be_active
        self.sgv = self.manager.window.slice_graphics_view
        if hasattr(self, 'getCustomContextMenu'):
            # print("connecting ccm")
            try:  # Hack to prevent multiple connections
                self.sgv.customContextMenuRequested.disconnect()
            except:
                pass
            self.sgv.customContextMenuRequested.connect(
                self.getCustomContextMenu)

    # end def

    def deactivate(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if hasattr(self, 'getCustomContextMenu'):
            # print("disconnecting ccm")
            self.sgv.customContextMenuRequested.disconnect(
                self.getCustomContextMenu)
        self.sgv = None
        self.is_started = False
        self.hideLineItem()
        self._vhi = None
        self.part_item = None
        self.hide()
        self._active = False

    # end def

    def isActive(self):
        """Returns isActive
        """
        return self._active
Пример #6
0
class AbstractSliceTool(QGraphicsObject):
    """Summary

    Attributes:
        angles (TYPE): Description
        FILTER_NAME (str): Description
        is_started (bool): Description
        manager (TYPE): Description
        part_item (TYPE): Description
        sgv (TYPE): Description
        vectors (TYPE): Description
    """
    _RADIUS = styles.SLICE_HELIX_RADIUS
    _CENTER_OF_HELIX = QPointF(_RADIUS, _RADIUS)
    FILTER_NAME = 'virtual_helix'
    # _CENTER_OF_HELIX = QPointF(0. 0.)
    """Abstract base class to be subclassed by all other pathview tools."""
    def __init__(self, manager):
        """Summary

        Args:
            manager (TYPE): Description
        """
        super(AbstractSliceTool, self).__init__(parent=manager.viewroot)
        """ Pareting to viewroot to prevent orphan _line_item from occuring
        """
        self.sgv = None
        self.manager = manager
        self._active = False
        self._last_location = None
        self._line_item = QGraphicsLineItem(self)
        self._line_item.hide()
        self._vhi = None

        self.hide()
        self.is_started = False
        self.angles = [math.radians(x) for x in range(0, 360, 30)]
        self.vectors = self.setVectors()
        self.part_item = None

        self.vhi_hint_item = QGraphicsEllipseItem(_DEFAULT_RECT, self)
        self.vhi_hint_item.setPen(_MOD_PEN)
        self.vhi_hint_item.setZValue(styles.ZPARTITEM)
    # end def

    ######################## Drawing #######################################
    def setVectors(self):
        """Summary

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        return [QLineF(rad, rad,
                       rad*(1. + 2.*math.cos(x)), rad*(1. + 2.*math.sin(x))
                       ) for x in self.angles]
    # end def

    def setVirtualHelixItem(self, virtual_helix_item):
        """Summary

        Args:
            virtual_helix_item (cadnano.gui.views.sliceview.virtualhelixitem.VirtualHelixItem): Description

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        self._vhi = virtual_helix_item
        li = self._line_item
        li.setParentItem(virtual_helix_item)
        li.setLine(rad, rad, rad, rad)
        # li.setLine(0., 0., 0., 0.)
    # end def

    def setSelectionFilter(self, filter_name_list):
        if 'virtual_helix' in filter_name_list:
            self.vhi_hint_item.setPen(_MOD_PEN)
        else:
            self.vhi_hint_item.setPen(_INACTIVE_PEN)
    # end def

    def resetTool(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._line_item.setParentItem(self)

    def idNum(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if self._vhi is not None:
            return self._vhi.idNum()

    def setPartItem(self, part_item):
        """Summary

        Args:
            part_item (TYPE): Description

        Returns:
            TYPE: Description
        """
        self.vhi_hint_item.setParentItem(part_item)
        self.part_item = part_item
    # end def

    def boundingRect(self):
        """Required to prevent NotImplementedError()
        """
        return QRectF()

    def eventToPosition(self, part_item, event):
        """take an event and return a position as a QPointF
        update widget as well

        Args:
            part_item (TYPE): Description
            event (TYPE): Description
        """
        if self.is_started:
            pos = self.findNearestPoint(part_item, event.scenePos())
        else:
            pos =  event.pos()
        self.vhi_hint_item.setPos(  pos -
                                    QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
        return pos
    # end def

    def setHintPos(self, pos):
        self.vhi_hint_item.setPos(  pos -
                                    QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
    # end def

    def findNearestPoint(self, part_item, target_scenepos):
        """
        Args:
            part_item (TYPE): Description
            target_scenepos (TYPE): Description
        """
        li = self._line_item
        pos = li.mapFromScene(target_scenepos)

        line = li.line()
        mouse_point_vec = QLineF(self._CENTER_OF_HELIX, pos)

        # Check if the click happened on the origin VH
        if mouse_point_vec.length() < self._RADIUS:
            # return part_item.mapFromScene(target_scenepos)
            return None

        angle_min = 9999
        direction_min = None
        for vector in self.vectors:
            angle_new = mouse_point_vec.angleTo(vector)
            if angle_new < angle_min:
                direction_min = vector
                angle_min = angle_new
        if direction_min is not None:
            li.setLine(direction_min)
            return part_item.mapFromItem(li, direction_min.p2())
        else:
            print("default point")
            line.setP2(pos)
            li.setLine(line)
            return part_item.mapFromItem(li, pos)
    # end def

    def findNextPoint(self, part_item, target_part_pos):
        """
        Args:
            part_item (TYPE): Description
            target_part_pos (TYPE): Description
        """
        li = self._line_item
        pos = li.mapFromItem(part_item, target_part_pos)
        for i, vector in enumerate(self.vectors):
            if vector.p2() == pos:
                return part_item.mapFromItem(li, self.vectors[i - 1].p2())
        # origin VirtualHelixItem is overlapping destination VirtualHelixItem
        return part_item.mapFromItem(li, self.vectors[0].p2())
    # end def

    def hideLineItem(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self.vhi_hint_item.hide()
        li = self._line_item
        li.hide()
        li.setParentItem(self)
        line = li.line()
        line.setP2(self._CENTER_OF_HELIX)
        li.setLine(line)
        # li.hide()
        self.is_started = False
    # end def

    # def hoverEnterEvent(self, event):
    #     self.vhi_hint_item.show()
    #     #print("Slice VHI hoverEnterEvent")

    # # def hoverMoveEvent(self, event):
    #     # print("Slice VHI hoverMoveEvent")

    # def hoverLeaveEvent(self, event):
    #     # self.vhi_hint_item.hide()
    #     #print("Slice VHI hoverLeaveEvent")


    def hoverMoveEvent(self, part_item, event):
        """Summary

        Args:
            part_item (TYPE): Description
            event (TYPE): Description

        Returns:
            TYPE: Description
        """
        # self.vhi_hint_item.setPos(  event.pos()-
        #                             QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
        pos = self.eventToPosition(part_item, event)
        return pos
    # end def

    def setActive(self, will_be_active, old_tool=None):
        """
        Called by SliceToolManager.setActiveTool when the tool becomes
        active. Used, for example, to show/hide tool-specific ui elements.

        Args:
            will_be_active (TYPE): Description
            old_tool (None, optional): Description
        """
        if self._active and not will_be_active:
            self.deactivate()
        self._active = will_be_active
        self.sgv = self.manager.window.slice_graphics_view
        if hasattr(self, 'getCustomContextMenu'):
            # print("connecting ccm")
            try:    # Hack to prevent multiple connections
                self.sgv.customContextMenuRequested.disconnect()
            except:
                pass
            self.sgv.customContextMenuRequested.connect(self.getCustomContextMenu)
    # end def

    def deactivate(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if hasattr(self, 'getCustomContextMenu'):
            # print("disconnecting ccm")
            self.sgv.customContextMenuRequested.disconnect(self.getCustomContextMenu)
        self.sgv = None
        self.is_started = False
        self.hideLineItem()
        self._vhi = None
        self.part_item = None
        self.hide()
        self._active = False
    # end def

    def isActive(self):
        """Returns isActive
        """
        return self._active
Пример #7
0
class AbstractGridTool(AbstractTool):
    _RADIUS = styles.GRID_HELIX_RADIUS
    _CENTER_OF_HELIX = QPointF(_RADIUS, _RADIUS)
    FILTER_NAME = 'virtual_helix'
    # _CENTER_OF_HELIX = QPointF(0. 0.)
    """Abstract base class to be subclassed by all other pathview tools."""
    def __init__(self, manager: AbstractToolManager):
        """Summary

        Args:
            manager (TYPE): Description
        """
        # Setting parent to viewroot to prevent orphan _line_item from occurring
        super(AbstractGridTool, self).__init__(parent=manager.viewroot)
        self.slice_graphics_view = manager.window.grid_graphics_view
        self.manager = manager
        self._active = False
        self._last_location = None
        self._line_item = QGraphicsLineItem(self)
        self._line_item.hide()
        self._vhi = None

        self.hide()
        self.is_started = False
        self.angles = [math.radians(x) for x in range(0, 360, 30)]
        self.vectors = self.setVectors()
        self.part_item = None

        self.vhi_hint_item = QGraphicsEllipseItem(_DEFAULT_RECT, self)
        self.vhi_hint_item.setPen(_MOD_PEN)
        self.vhi_hint_item.setZValue(styles.ZPARTITEM)

    # end def

    ######################## Drawing #######################################
    def setVectors(self):
        """Summary

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        return [
            QLineF(rad, rad, rad * (1. + 2. * math.cos(x)),
                   rad * (1. + 2. * math.sin(x))) for x in self.angles
        ]

    # end def

    def setVirtualHelixItem(self, virtual_helix_item):
        """Summary

        Args:
            virtual_helix_item (cadnano.views.gridview.virtualhelixitem.VirtualHelixItem): Description

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        self._vhi = virtual_helix_item
        li = self._line_item
        li.setParentItem(virtual_helix_item)
        li.setLine(rad, rad, rad, rad)
        # li.setLine(0., 0., 0., 0.)

    # end def

    def setSelectionFilter(self, filter_name_list):
        if 'virtual_helix' in filter_name_list:
            self.vhi_hint_item.setPen(_MOD_PEN)
        else:
            self.vhi_hint_item.setPen(_INACTIVE_PEN)

    # end def

    def resetTool(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._line_item.setParentItem(self)

    def idNum(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if self._vhi is not None:
            return self._vhi.idNum()

    def setPartItem(self, part_item):
        """Summary

        Args:
            part_item (TYPE): Description

        Returns:
            TYPE: Description
        """
        self.vhi_hint_item.setParentItem(part_item)
        self.part_item = part_item

    # end def

    def boundingRect(self):
        """Required to prevent NotImplementedError()
        """
        return QRectF()

    def eventToPosition(self, part_item, event):
        """take an event and return a position as a QPointF
        update widget as well

        Args:
            part_item (TYPE): Description
            event (TYPE): Description
        """
        if self.is_started:
            pos = self.findNearestPoint(part_item, event.scenePos())
        else:
            pos = event.pos()
        self.vhi_hint_item.setPos(pos -
                                  QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
        return pos

    # end def

    def setHintPos(self, pos):
        self.vhi_hint_item.setPos(pos -
                                  QPointF(_RADIUS - DELTA, _RADIUS - DELTA))

    # end def

    def findNearestPoint(self, part_item: QAbstractPartItem,
                         target_scenepos: QPointF) -> QPointF:
        """
        Args:
            part_item: Description
            target_scenepos: position in the Scene
        """
        li = self._line_item
        pos = li.mapFromScene(target_scenepos)

        line = li.line()
        mouse_point_vec = QLineF(self._CENTER_OF_HELIX, pos)

        # Check if the click happened on the origin VH
        if mouse_point_vec.length() < self._RADIUS:
            # return part_item.mapFromScene(target_scenepos)
            return None

        angle_min = 9999
        direction_min = None
        for vector in self.vectors:
            angle_new = mouse_point_vec.angleTo(vector)
            if angle_new < angle_min:
                direction_min = vector
                angle_min = angle_new
        if direction_min is not None:
            li.setLine(direction_min)
            return part_item.mapFromItem(li, direction_min.p2())
        else:
            print("default point")
            line.setP2(pos)
            li.setLine(line)
            return part_item.mapFromItem(li, pos)

    # end def

    def findNextPoint(self, part_item: QAbstractPartItem,
                      target_part_pos: QPointF) -> QPointF:
        """
        Args:
            part_item: Description
            target_part_pos: Position in the Part
        """
        li = self._line_item
        pos = li.mapFromItem(part_item, target_part_pos)
        for i, vector in enumerate(self.vectors):
            if vector.p2() == pos:
                return part_item.mapFromItem(li, self.vectors[i - 1].p2())
        # origin VirtualHelixItem is overlapping destination VirtualHelixItem
        return part_item.mapFromItem(li, self.vectors[0].p2())

    # end def

    def hideLineItem(self):
        """ Hide the ``_line_item`` and the ``vhi_hint_item``
        set ``is_started`` to :bool:`False`
        """
        # print("hideLineItem")
        self.vhi_hint_item.hide()
        li = self._line_item
        li.hide()
        li.setParentItem(self)
        line = li.line()
        line.setP2(self._CENTER_OF_HELIX)
        li.setLine(line)
        self.is_started = False

    # end def

    # def hoverEnterEvent(self, event):
    #     self.vhi_hint_item.show()
    #     #print("Grid VHI hoverEnterEvent")

    # # def hoverMoveEvent(self, event):
    #     # print("Grid VHI hoverMoveEvent")

    # def hoverLeaveEvent(self, event):
    #     # self.vhi_hint_item.hide()
    #     #print("Grid VHI hoverLeaveEvent")

    def hoverMoveEvent(self, part_item, event):
        """Summary

        Args:
            part_item (TYPE): Description
            event (TYPE): Description

        Returns:
            TYPE: Description
        """
        # self.vhi_hint_item.setPos(  event.pos()-
        #                             QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
        pos = self.eventToPosition(part_item, event)
        return pos

    # end def

    def setActive(self, will_be_active, old_tool=None):
        """
        Called by GridToolManager.setActiveTool when the tool becomes
        active. Used, for example, to show/hide tool-specific ui elements.

        Args:
            will_be_active (TYPE): Description
            old_tool (None, optional): Description
        """
        if self._active and not will_be_active:
            self.deactivate()
        self._active = will_be_active
        self.slice_graphics_view = self.manager.window.grid_graphics_view
        if hasattr(self, 'getCustomContextMenu'):
            # print("connecting ccm")
            try:  # Hack to prevent multiple connections
                self.slice_graphics_view.customContextMenuRequested.disconnect(
                )
            except (AttributeError, TypeError):
                pass
            self.slice_graphics_view.customContextMenuRequested.connect(
                self.getCustomContextMenu)

    # end def

    def deactivate(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if hasattr(self, 'getCustomContextMenu'):
            # print("disconnecting ccm")
            self.slice_graphics_view.customContextMenuRequested.disconnect(
                self.getCustomContextMenu)
        self.slice_graphics_view = None
        self.is_started = False
        self.hideLineItem()
        self._vhi = None
        self.part_item = None
        self.hide()
        self._active = False

    # end def

    def isActive(self) -> bool:
        """Returns isActive
        """
        return self._active
Пример #8
0
class LineLabel(QGraphicsTextItem):
    nameChanged = pyqtSignal()
    
    def __init__(self, pos, parent=None):
        super(LineLabel, self).__init__()
        # initial text
        self.setPlainText("abc")
        # stores index of first point of segment
        self.index = None
        # distance from line segment
        self.gap = None
        # set graphical setting
        self.setFlags(QGraphicsItem.ItemIsMovable |
                      QGraphicsItem.ItemIsSelectable |
                      QGraphicsItem.ItemIsFocusable)
        self.setTextInteractionFlags(Qt.NoTextInteraction)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        # set center of text label at mouse pos
        self.setPos(pos - self.boundingRect().center())
        self.setParentItem(parent)
        # add line item to test label
        self.line = QGraphicsLineItem()
        self.line.setParentItem(self)
        self.line.setPen(QPen(Qt.black, 2, Qt.SolidLine))
        self.line.setFlag(QGraphicsItem.ItemStacksBehindParent)
        # reset position of line
        self.resetPos()
        self.values = defaultdict(lambda: 0)
        
    def paint(self, painter, option, widget):
        # draw ellipse shape
        painter.save()  # save painter
        painter.setPen(QPen(Qt.black, 2, Qt.SolidLine))  # set pen to painter
        painter.setBrush(QBrush(Qt.white))  # set brush
        painter.drawEllipse(self.boundingRect())  # draw ellipse
        painter.restore()  # restore painter as before drawing ellipse
        super(LineLabel, self).paint(painter, option, widget)

    def updateLabel(self):
        # finds new position on segment
        offset = self.gap  # distance from segment
        points = self.parentItem().points  # points of line
        firstPoint = points[self.index]  # first point of segment on which label is attached
        endPoint = points[self.index + 1]  # second point
        center = self.mapToParent(self.boundingRect().center())
        newPos = center
        # if segment is vertical
        if firstPoint.x() == endPoint.x():
            newPos.setX(firstPoint.x() + self.gap)
            if min(firstPoint.y(), endPoint.y()) > newPos.y():
                newPos.setY(min(firstPoint.y(), endPoint.y()))
            elif newPos.y() > max(firstPoint.y(), endPoint.y()):
                newPos.setY(max(firstPoint.y(), endPoint.y()))
        # segment is horizontal
        elif firstPoint.y() == endPoint.y():
            newPos.setY(firstPoint.y() + self.gap)
            if min(firstPoint.x(), endPoint.x()) > newPos.x():
                newPos.setX(min(firstPoint.x(), endPoint.x()))
            elif newPos.x() > max(firstPoint.x(), endPoint.x()):
                newPos.setX(max(firstPoint.x(), endPoint.x()))
        # transfer center positon to top left
        newPos -= QPointF(self.boundingRect().width() / 2, self.boundingRect().height() / 2)
        self.setPos(newPos)

    def resetPos(self):
        """ finds the segment of line on which mouse is clicked for adding label
        and resets it's position on that segment
        """
        points = self.parentItem().points
        min_A = QPointF()
        min_B = QPointF()
        min_dis = math.inf
        for i in range(len(points) - 1):
            A = points[i]
            B = points[i + 1]
            C = QPointF(self.pos() + self.boundingRect().center())
            BAx = B.x() - A.x()
            BAy = B.y() - A.y()
            CAx = C.x() - A.x()
            CAy = C.y() - A.y()
            length = math.sqrt(BAx * BAx + BAy * BAy)
            if BAx == 0:
                if not min(A.y(), B.y()) <= C.y() <= max(A.y(), B.y()):
                    continue
            if BAy == 0:
                if not min(A.x(), B.x()) <= C.x() <= max(A.x(), B.x()):
                    continue
            if length > 0:
                dis = (BAx * CAy - CAx * BAy) / length
                if abs(dis) < abs(min_dis):
                    min_dis = dis
                    min_A = A
                    min_B = B
                    self.index = i
        point = self.mapFromScene(min_A)
        if min_A.x() == min_B.x():
            self.setPos(self.parentItem().mapFromScene(QPointF(min_A.x() + 10, self.y())))
            self.gap = 10 + self.boundingRect().width() / 2
        else:
            self.setPos(self.parentItem().mapFromScene(QPointF(self.x(), min_A.y() - 30)))
            self.gap = -30 + self.boundingRect().height() / 2

    def itemChange(self, change, value):
        # if position of label changes
        if change == QGraphicsItem.ItemPositionChange and self.scene():
            newPos = QPointF(value)  # new position
            newPos += QPointF(self.boundingRect().width() / 2, self.boundingRect().height() / 2)  # pos of center
            points = self.parentItem().points
            firstPoint = points[self.index]
            endPoint = points[self.index + 1]
            if firstPoint.x() == endPoint.x():
                if min(firstPoint.y(), endPoint.y()) > newPos.y():
                    newPos.setY(min(firstPoint.y(), endPoint.y()))
                elif newPos.y() > max(firstPoint.y(), endPoint.y()):
                    newPos.setY(max(firstPoint.y(), endPoint.y()))
            elif firstPoint.y() == endPoint.y():
                if min(firstPoint.x(), endPoint.x()) > newPos.x():
                    newPos.setX(min(firstPoint.x(), endPoint.x()))
                elif newPos.x() > max(firstPoint.x(), endPoint.x()):
                    newPos.setX(max(firstPoint.x(), endPoint.x()))
            newPos -= QPointF(self.boundingRect().width() / 2,
                              self.boundingRect().height() / 2)  # change center pos to top-left
            return newPos
        if change == QGraphicsItem.ItemPositionHasChanged and self.scene():
            self.updateGap()
            self.updateLine()
            return
        return super(LineLabel, self).itemChange(change, value)

    def updateGap(self):
        # updates distance of line from it's connection segment
        points = self.parentItem().points
        firstPoint = points[self.index]
        endPoint = points[self.index + 1]
        firstPoint = self.mapFromParent(firstPoint)
        endPoint = self.mapFromParent(endPoint)
        center = self.boundingRect().center()
        if firstPoint.x() == endPoint.x():
            self.gap = center.x() - firstPoint.x()
        else:
            self.gap = center.y() - firstPoint.y()

    def updateLine(self):
        # updates line item of label
        points = self.parentItem().points
        firstPoint = points[self.index]
        endPoint = points[self.index + 1]
        point = self.mapFromParent(firstPoint)
        center = self.boundingRect().center()
        if firstPoint.x() == endPoint.x():
            self.line.setLine(center.x(), center.y(), point.x(), center.y())
        else:
            self.line.setLine(center.x(), center.y(), center.x(), point.y())

    def mouseDoubleClickEvent(self, event):
        # set text editable
        self.setTextInteractionFlags(Qt.TextEditorInteraction)
        self.setFocus()
        super(LineLabel, self).mouseDoubleClickEvent(event)

    def focusOutEvent(self, event):
        super(LineLabel, self).focusOutEvent(event)
        self.setTextInteractionFlags(Qt.NoTextInteraction)  # set text non interactive
        self.nameChanged.emit()

    def __getstate__(self):
        return {
            "text": self.toPlainText(),
            "index": self.index,
            "gap": self.gap,
            "pos": (self.pos().x(), self.pos().y()),
            "values": self.values
        }

    def __setstate__(self, dict):
        self.setPlainText(dict['text'])
        self.index = dict['index']
        self.gap = dict['gap']
        for key, value in dict['values'].items():
            self.values[key] = value