예제 #1
0
 def create_winner_label(self):
     w = QGraphicsTextItem()
     w.setPlainText("%s" % self.mini_game_winner)
     game_board = self.parent()
     print(game_board)
     w.setFont(QFont('SansSerif', self.fonts[self.mini_game_winner]))
     w.setDefaultTextColor(Qt.black)
     w.setPos(self.x(), self.y())
     w.setVisible(False)
     return w
예제 #2
0
class GraphicLine(QGraphicsLineItem):
    """
    This class is a graphic line with an arrow which connects
    two blocks in the scene.

    Attributes
    ----------
    origin : QGraphicsRectItem
        Origin rect of the line.
    destination : QGraphicsRectItem
        Destination rect of the line.
    scene : QGraphicsScene
        Current drawing scene.
    brush : QBrush
        Brush to draw the arrow.
    pen : QPen
        Pen to draw the arrow.
    arrow_head : QGraphicsPolygonItem
        Final arrow of the line.
    arrow_size : int
        Size of the head of the arrow.
    dim_label : QGraphicsTextItem
        Text showing the dimensions of the edge.
    is_valid : bool
        Flag monitoring whether the connection is consistent.

    Methods
    ----------
    gen_endpoints(QRectF, QRectF)
        Returns the shortest connection between the two rects.
    draw_arrow()
        Draws the polygon for the arrow.
    set_valid(bool)
        Assign validity for this line.
    update_dims(tuple)
        Update the line dimensions.
    update_pos(QRectF)
        Update the line position given the new rect position.
    remove_self()
        Delete this line.

    """
    def __init__(self, origin: QGraphicsRectItem,
                 destination: QGraphicsRectItem, scene):
        super(GraphicLine, self).__init__()
        self.origin = origin
        self.destination = destination
        self.scene = scene

        # This flag confirms a legal connection
        self.is_valid = True

        # Get the four sides of the rects
        destination_lines = u.get_sides_of(
            self.destination.sceneBoundingRect())
        origin_lines = u.get_sides_of(self.origin.sceneBoundingRect())

        # Get the shortest edge between the two blocks
        self.setLine(self.gen_endpoints(origin_lines, destination_lines))

        self.brush = QBrush(QColor(style.GREY_0))
        self.pen = QPen(QColor(style.GREY_0))
        self.pen.setWidth(4)
        self.pen.setCapStyle(Qt.RoundCap)
        self.pen.setJoinStyle(Qt.RoundJoin)
        self.setPen(self.pen)

        # Dimensions labels
        self.dim_label = QGraphicsTextItem()
        self.dim_label.setZValue(6)
        self.scene.addItem(self.dim_label)

        # Arrow head
        self.arrow_head = QGraphicsPolygonItem()
        self.arrow_head.setPen(self.pen)
        self.arrow_head.setBrush(self.brush)
        self.arrow_size = 15.0

        self.draw_arrow()

    @staticmethod
    def gen_endpoints(origin_sides: dict, destination_sides: dict) -> QLineF:
        """
        This method finds the shortest path between two rectangles.

        Parameters
        ----------
        origin_sides : dict
            The dictionary {side_label: side_size} of the starting rect.
        destination_sides : dict
            The dictionary {side_label: side_size} of the ending rect.

        Returns
        ----------
        QLineF
            The shortest line.

        """

        # Init the line with the maximum possible value
        shortest_line = QLineF(-sys.maxsize / 2, -sys.maxsize / 2,
                               sys.maxsize / 2, sys.maxsize / 2)
        for o_side, origin_side in origin_sides.items():
            o_mid_x, o_mid_y = u.get_midpoint(o_side, origin_side)

            for d_side, destination_side in destination_sides.items():
                d_mid_x, d_mid_y = u.get_midpoint(d_side, destination_side)

                # Update line
                line = QLineF(o_mid_x, o_mid_y, d_mid_x, d_mid_y)
                if line.length() < shortest_line.length():
                    shortest_line = line

        return shortest_line

    def draw_arrow(self) -> None:
        """
        This method draws an arrow at the end of the line.

        """

        polygon_arrow_head = QPolygonF()

        # Compute the arrow angle
        angle = math.acos(self.line().dx() / self.line().length())
        angle = ((math.pi * 2) - angle)

        # Compute the direction where the arrow points (1 up, -1 down)
        arrow_direction = 1
        if math.asin(self.line().dy() / self.line().length()) < 0:
            arrow_direction = -1

        # First point of the arrow tail
        arrow_p1 = self.line().p2() - arrow_direction * QPointF(
            arrow_direction * math.sin(angle + math.pi / 2.5) *
            self.arrow_size,
            math.cos(angle + math.pi / 2.5) * self.arrow_size)
        # Second point of the arrow tail
        arrow_p2 = self.line().p2() - arrow_direction * QPointF(
            arrow_direction * math.sin(angle + math.pi - math.pi / 2.5) *
            self.arrow_size,
            math.cos(angle + math.pi - math.pi / 2.5) * self.arrow_size)

        # Third point is the line end
        polygon_arrow_head.append(self.line().p2())
        polygon_arrow_head.append(arrow_p2)
        polygon_arrow_head.append(arrow_p1)

        # Add the arrow to the scene
        self.arrow_head.setZValue(1)
        self.arrow_head.setParentItem(self)
        self.arrow_head.setPolygon(polygon_arrow_head)

    def set_valid(self, valid: bool) -> None:
        """
        This method changes the arrow style: if the connection 
        is not valid the arrow becomes red, otherwise it 
        remains grey with dimensions displayed. 
        
        Parameters
        ----------
        valid : bool
            New value for the legality flag.

        """

        if valid:
            self.is_valid = True
            self.pen.setColor(QColor(style.GREY_0))
            self.brush.setColor(QColor(style.GREY_0))
            self.dim_label.setVisible(False)
        else:
            self.is_valid = False
            self.pen.setColor(QColor(style.RED_2))
            self.brush.setColor(QColor(style.RED_2))

            if self.scene.is_dim_visible:
                self.dim_label.setVisible(True)

    def update_dims(self, dims: tuple) -> None:
        """
        This method updates the input & output dimensions.
        
        Parameters
        ----------
        dims : tuple
            The new dimensions to update.

        """

        self.dim_label.setHtml("<div style = 'background-color: " +
                               style.RED_2 +
                               "; color: white; font-family: consolas;'>" +
                               str(dims) + "</div>")
        self.dim_label.setPos(self.line().center())

    def update_pos(self, new_target: QRectF):
        """
        This method updates the line as it origin or its destination has
        changed location.

        Parameters
        ----------
        new_target : QRectF

        """

        if new_target == self.destination:
            self.destination = new_target
        elif new_target == self.origin:
            self.origin = new_target

        # Get the four sides of the rects
        destination_lines = u.get_sides_of(
            self.destination.sceneBoundingRect())
        origin_lines = u.get_sides_of(self.origin.sceneBoundingRect())

        # Get the shortest edge between the two blocks
        self.setLine(self.gen_endpoints(origin_lines, destination_lines))
        self.draw_arrow()
        self.dim_label.setPos(self.line().center())

    def remove_self(self) -> None:
        """
        The line is removed from the scene along with origin and destination
        pointers.

        """

        self.scene.removeItem(self)
        self.scene.edges.remove(self)
        self.scene.removeItem(self.dim_label)
        self.origin = None
        self.destination = None
예제 #3
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        self.player = QMediaPlayer(self)  #创建视频播放器
        self.player.setNotifyInterval(1000)  #信息更新周期, ms

        scene = QGraphicsScene(self)
        self.ui.graphicsView.setScene(scene)

        self.videoItem = QGraphicsVideoItem()  #视频显示画面
        self.videoItem.setSize(QSizeF(320, 220))
        self.videoItem.setFlag(QGraphicsItem.ItemIsMovable)
        self.videoItem.setFlag(QGraphicsItem.ItemIsSelectable)
        self.videoItem.setFlag(QGraphicsItem.ItemIsFocusable)

        scene.addItem(self.videoItem)
        self.player.setVideoOutput(self.videoItem)  #设置视频显示图形项

        self.textItem = QGraphicsTextItem("面朝大海,春暖花开")  #弹幕文字
        font = self.textItem.font()
        font.setPointSize(20)
        self.textItem.setFont(font)
        self.textItem.setDefaultTextColor(Qt.red)
        self.textItem.setPos(100, 220)
        self.textItem.setFlag(QGraphicsItem.ItemIsMovable)
        self.textItem.setFlag(QGraphicsItem.ItemIsSelectable)
        self.textItem.setFlag(QGraphicsItem.ItemIsFocusable)
        scene.addItem(self.textItem)

        self.ui.btnText.setCheckable(True)  #弹幕文字按钮
        self.ui.btnText.setChecked(True)

        self.__duration = ""
        self.__curPos = ""
        self.player.stateChanged.connect(self.do_stateChanged)
        self.player.positionChanged.connect(self.do_positionChanged)
        self.player.durationChanged.connect(self.do_durationChanged)

##  ==============自定义功能函数========================

##  ==============event处理函数==========================

    def closeEvent(self, event):  #窗体关闭时
        # 窗口关闭时不能自动停止播放,需手动停止
        if (self.player.state() == QMediaPlayer.PlayingState):
            self.player.stop()

##  ==========由connectSlotsByName()自动连接的槽函数============

    @pyqtSlot()  ##打开文件
    def on_btnOpen_clicked(self):
        curPath = QDir.currentPath()  #获取系统当前目录
        ##      curPath=os.getcwd()
        title = "选择视频文件"
        filt = "视频文件(*.wmv *.avi);;所有文件(*.*)"
        fileName, flt = QFileDialog.getOpenFileName(self, title, curPath, filt)

        if (fileName == ""):
            return

        fileInfo = QFileInfo(fileName)
        baseName = fileInfo.fileName()
        ##      baseName=os.path.basename(fileName)
        self.ui.LabCurMedia.setText(baseName)
        curPath = fileInfo.absolutePath()
        QDir.setCurrent(curPath)  #重设当前目录

        media = QMediaContent(QUrl.fromLocalFile(fileName))

        self.player.setMedia(media)  #设置播放文件
        self.player.play()

    @pyqtSlot()  ##播放
    def on_btnPlay_clicked(self):
        self.player.play()

    @pyqtSlot()  ##暂停
    def on_btnPause_clicked(self):
        self.player.pause()

    @pyqtSlot()  ##停止
    def on_btnStop_clicked(self):
        self.player.stop()

    @pyqtSlot()  ##全屏
    def on_btnFullScreen_clicked(self):
        self.videoWidget.setFullScreen(True)

    @pyqtSlot()  ##静音按钮
    def on_btnSound_clicked(self):
        mute = self.player.isMuted()
        self.player.setMuted(not mute)
        if mute:
            self.ui.btnSound.setIcon(QIcon(":/icons/images/volumn.bmp"))
        else:
            self.ui.btnSound.setIcon(QIcon(":/icons/images/mute.bmp"))

    @pyqtSlot(int)  ##音量调节
    def on_sliderVolumn_valueChanged(self, value):
        self.player.setVolume(value)

    @pyqtSlot(int)  ##播放进度调节
    def on_sliderPosition_valueChanged(self, value):
        self.player.setPosition(value)

    @pyqtSlot()  ##放大
    def on_btnZoomIn_clicked(self):
        sc = self.videoItem.scale()
        self.videoItem.setScale(sc + 0.1)

    @pyqtSlot()  ##缩小
    def on_btnZoomOut_clicked(self):
        sc = self.videoItem.scale()
        self.videoItem.setScale(sc - 0.1)

    @pyqtSlot(bool)  ##弹幕
    def on_btnText_clicked(self, checked):
        self.textItem.setVisible(checked)

##  =============自定义槽函数===============================

    def do_stateChanged(self, state):
        isPlaying = (state == QMediaPlayer.PlayingState)

        self.ui.btnPlay.setEnabled(not isPlaying)
        self.ui.btnPause.setEnabled(isPlaying)
        self.ui.btnStop.setEnabled(isPlaying)

    def do_durationChanged(self, duration):
        self.ui.sliderPosition.setMaximum(duration)

        secs = duration / 1000  #秒
        mins = secs / 60  #分钟
        secs = secs % 60  #余数秒
        self.__duration = "%d:%d" % (mins, secs)
        self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)

    def do_positionChanged(self, position):
        if (self.ui.sliderPosition.isSliderDown()):
            return  #如果正在拖动滑条,退出

        self.ui.sliderPosition.setSliderPosition(position)

        secs = position / 1000  #秒
        mins = secs / 60  #分钟
        secs = secs % 60  #余数秒
        self.__curPos = "%d:%d" % (mins, secs)
        self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)
예제 #4
0
class CollectDataWidget(QGraphicsView):

    yIncr = 10
    xIncr = 20
    outOfBounds = False
    margin = 25
    trainingMode = 1
    timerLength = 20

    def __init__(self):

        super(CollectDataWidget, self).__init__()
        screen = QDesktopWidget().screenGeometry()
        self.setGeometry(screen)
        self.setWindowTitle("Data Collection")

        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0,
                                screen.right() - self.margin,
                                screen.bottom() - self.margin)
        self.node = Node(self)
        self.scene.addItem(self.node)
        # aktualnie 3:24 z (dx,dy, lambda) = (10, 20, 20)
        text = "Keep your eyes on the blue circle - testing once begun takes ~2 min. - press <Space> to begin"
        self.text = QGraphicsTextItem(text)
        self.text.setPos(100, 0)
        self.scene.addItem(self.text)

        self.thread = CameraThread(self.node)
        self.setScene(self.scene)
        self.showFullScreen()

    def timerEvent(self, event):
        dim = self.scene.sceneRect().bottomRight()
        node = self.node
        pos = node.scenePos()

        if self.trainingMode == 0:
            mousePos = getMousePos()
        elif self.trainingMode == 1:
            if pos.x() > dim.x():
                self.close()
            elif (pos.y() > dim.y() or pos.y() <= 0) and not self.outOfBounds:
                node.moveBy(abs(self.xIncr), 0)
                self.yIncr *= -1

                self.outOfBounds = True
            else:
                node.moveBy(0, self.yIncr)
                if self.outOfBounds:
                    self.outOfBounds = False
        elif self.trainingMode == 2:
            print("Hello")
            radius = self.node.r
            x = random.randint(radius, dim.x() - radius)
            y = random.randint(radius, dim.y() - radius)
            print(x, y)
            node.setPos(x, y)

    def keyPressEvent(self, event):
        key = event.key()
        if key == Qt.Key_Q:
            self.thread.terminate = True
            self.close()
        elif key == Qt.Key_0:
            self.trainingMode = 0
            self.timerLength = 50
        elif key == Qt.Key_1:
            print("Training mode 1 selected")
            self.trainingMode = 1
            self.timerLength = 20
        elif key == Qt.Key_2:
            print("Training mode 2 selected")
            self.trainingMode = 2
            self.timerLength = 2000
        elif key == Qt.Key_V:
            self.node.setVisible(not self.node.isVisible())
        elif key == Qt.Key_Space:
            self.startTimer(self.timerLength)
            self.thread.start()
            self.text.setVisible(False)
예제 #5
0
class BlockItem(QGraphicsPixmapItem):
    def __init__(self, trnsysType, parent, **kwargs):
        super().__init__(None)

        self.logger = parent.logger

        self.w = 120
        self.h = 120
        self.parent = parent
        self.id = self.parent.parent().idGen.getID()
        self.propertyFile = []

        if "displayName" in kwargs:
            self.displayName = kwargs["displayName"]
        else:
            self.displayName = trnsysType + "_" + str(self.id)

        if "loadedBlock" not in kwargs:
            self.parent.parent().trnsysObj.append(self)

        self.inputs = []
        self.outputs = []

        # Export related:
        self.name = trnsysType
        self.trnsysId = self.parent.parent().idGen.getTrnsysID()

        # Transform related
        self.flippedV = False
        self.flippedH = False
        self.rotationN = 0
        self.flippedHInt = -1
        self.flippedVInt = -1

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        # To set flags of this item
        self.setFlags(self.ItemIsSelectable | self.ItemIsMovable)
        self.setFlag(self.ItemSendsScenePositionChanges, True)
        self.setCursor(QCursor(QtCore.Qt.PointingHandCursor))

        self.label = QGraphicsTextItem(self.displayName, self)
        self.label.setVisible(False)

        if self.name == "Bvi":
            self.inputs.append(_cspi.createSinglePipePortItem("i", 0, self))
            self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self))

        if self.name == "StorageTank":
            # Inputs get appended in ConfigStorage
            pass

        self.logger.debug("Block name is " + str(self.name))

        # Update size for generic block:
        if self.name == "Bvi":
            self.changeSize()

        # Experimental, used for detecting genereated blocks attached to storage ports
        self.inFirstRow = False

        # Undo framework related
        self.oldPos = None

        self.origOutputsPos = None
        self.origInputsPos = None

    def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]:
        if type(self) == BlockItem:
            raise AssertionError(
                "`BlockItem' cannot be instantiated directly.")

        currentClassName = BlockItem.__name__
        currentMethodName = f"{currentClassName}.{BlockItem._getImageAccessor.__name__}"

        message = (
            f"{currentMethodName} has been called. However, this method should not be called directly but must\n"
            f"implemented in a child class. This means that a) someone instantiated `{currentClassName}` directly\n"
            f"or b) a child class of it doesn't implement `{currentMethodName}`. Either way that's an\n"
            f"unrecoverable error and therefore the program will be terminated now. Please do get in touch with\n"
            f"the developers if you've encountered this error. Thanks.")

        exception = AssertionError(message)

        # I've seen exception messages mysteriously swallowed that's why we're logging the message here, too.
        self.logger.error(message, exc_info=exception, stack_info=True)

        raise exception

    def addTree(self):
        pass

    # Setter functions
    def setParent(self, p):
        self.parent = p

        if self not in self.parent.parent().trnsysObj:
            self.parent.parent().trnsysObj.append(self)
            # self.logger.debug("trnsysObj are " + str(self.parent.parent().trnsysObj))

    def setId(self, newId):
        self.id = newId

    def setName(self, newName):
        self.displayName = newName
        self.label.setPlainText(newName)

    # Interaction related
    def contextMenuEvent(self, event):
        menu = QMenu()

        a1 = menu.addAction("Launch NotePad++")
        a1.triggered.connect(self.launchNotepadFile)

        rr = _img.ROTATE_TO_RIGHT_PNG.icon()
        a2 = menu.addAction(rr, "Rotate Block clockwise")
        a2.triggered.connect(self.rotateBlockCW)

        ll = _img.ROTATE_LEFT_PNG.icon()
        a3 = menu.addAction(ll, "Rotate Block counter-clockwise")
        a3.triggered.connect(self.rotateBlockCCW)

        a4 = menu.addAction("Reset Rotation")
        a4.triggered.connect(self.resetRotation)

        b1 = menu.addAction("Print Rotation")
        b1.triggered.connect(self.printRotation)

        c1 = menu.addAction("Delete this Block")
        c1.triggered.connect(self.deleteBlockCom)

        menu.exec_(event.screenPos())

    def launchNotepadFile(self):
        self.logger.debug("Launching notpad")
        global FilePath
        os.system("start notepad++ " + FilePath)

    def mouseDoubleClickEvent(self, event):
        if hasattr(self, "isTempering"):
            self.parent.parent().showTVentilDlg(self)
        elif self.name == "Pump":
            self.parent.parent().showPumpDlg(self)
        elif self.name == "TeePiece" or self.name == "WTap_main":
            self.parent.parent().showBlockDlg(self)
        elif self.name in ["SPCnr", "DPCnr", "DPTee"]:
            self.parent.parent().showDoublePipeBlockDlg(self)
        else:
            self.parent.parent().showBlockDlg(self)
            if len(self.propertyFile) > 0:
                for files in self.propertyFile:
                    os.startfile(files, "open")

    def mouseReleaseEvent(self, event):
        # self.logger.debug("Released mouse over block")
        if self.oldPos is None:
            self.logger.debug("For Undo Framework: oldPos is None")
        else:
            if self.scenePos() != self.oldPos:
                self.logger.debug("Block was dragged")
                self.logger.debug("Old pos is" + str(self.oldPos))
                command = MoveCommand(self, self.oldPos, "Move BlockItem")
                self.parent.parent().parent().undoStack.push(command)
                self.oldPos = self.scenePos()

        super(BlockItem, self).mouseReleaseEvent(event)

    # Transform related
    def changeSize(self):
        self._positionLabel()

        w, h = self._getCappedWithAndHeight()

        if self.name == "Bvi":
            delta = 4

            self.inputs[0].setPos(
                -2 * delta + 4 * self.flippedH * delta + self.flippedH * w,
                h / 3)
            self.outputs[0].setPos(
                -2 * delta + 4 * self.flippedH * delta + self.flippedH * w,
                2 * h / 3)
            self.inputs[0].side = 0 + 2 * self.flippedH
            self.outputs[0].side = 0 + 2 * self.flippedH

    def _positionLabel(self):
        width, height = self._getCappedWithAndHeight()
        rect = self.label.boundingRect()
        labelWidth, lableHeight = rect.width(), rect.height()
        labelPosX = (height - labelWidth) / 2
        self.label.setPos(labelPosX, width)

    def _getCappedWithAndHeight(self):
        width = self.w
        height = self.h
        if height < 20:
            height = 20
        if width < 40:
            width = 40
        return width, height

    def updateFlipStateH(self, state):
        self.flippedH = bool(state)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        self.flippedHInt = 1 if self.flippedH else -1

        if self.flippedH:
            for i in range(0, len(self.inputs)):
                distanceToMirrorAxis = self.w / 2.0 - self.origInputsPos[i][0]
                self.inputs[i].setPos(
                    self.origInputsPos[i][0] + 2.0 * distanceToMirrorAxis,
                    self.inputs[i].pos().y(),
                )

            for i in range(0, len(self.outputs)):
                distanceToMirrorAxis = self.w / 2.0 - self.origOutputsPos[i][0]
                self.outputs[i].setPos(
                    self.origOutputsPos[i][0] + 2.0 * distanceToMirrorAxis,
                    self.outputs[i].pos().y(),
                )

        else:
            for i in range(0, len(self.inputs)):
                self.inputs[i].setPos(self.origInputsPos[i][0],
                                      self.inputs[i].pos().y())

            for i in range(0, len(self.outputs)):
                self.outputs[i].setPos(self.origOutputsPos[i][0],
                                       self.outputs[i].pos().y())

    def updateFlipStateV(self, state):
        self.flippedV = bool(state)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        self.flippedVInt = 1 if self.flippedV else -1

        if self.flippedV:
            for i in range(0, len(self.inputs)):
                distanceToMirrorAxis = self.h / 2.0 - self.origInputsPos[i][1]
                self.inputs[i].setPos(
                    self.inputs[i].pos().x(),
                    self.origInputsPos[i][1] + 2.0 * distanceToMirrorAxis,
                )

            for i in range(0, len(self.outputs)):
                distanceToMirrorAxis = self.h / 2.0 - self.origOutputsPos[i][1]
                self.outputs[i].setPos(
                    self.outputs[i].pos().x(),
                    self.origOutputsPos[i][1] + 2.0 * distanceToMirrorAxis,
                )

        else:
            for i in range(0, len(self.inputs)):
                self.inputs[i].setPos(self.inputs[i].pos().x(),
                                      self.origInputsPos[i][1])

            for i in range(0, len(self.outputs)):
                self.outputs[i].setPos(self.outputs[i].pos().x(),
                                       self.origOutputsPos[i][1])

    def updateSidesFlippedH(self):
        if self.rotationN % 2 == 0:
            for p in self.inputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
        if self.rotationN % 2 == 1:
            for p in self.inputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)

    def updateSidesFlippedV(self):
        if self.rotationN % 2 == 1:
            for p in self.inputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
        if self.rotationN % 2 == 0:
            for p in self.inputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)

    def updateSide(self, port, n):
        port.side = (port.side + n) % 4
        # self.logger.debug("Port side is " + str(port.side))

    def rotateBlockCW(self):
        # Rotate block clockwise
        # self.setTransformOriginPoint(50, 50)
        # self.setTransformOriginPoint(self.w/2, self.h/2)
        self.setTransformOriginPoint(0, 0)
        self.setRotation((self.rotationN + 1) * 90)
        self.label.setRotation(-(self.rotationN + 1) * 90)
        self.rotationN += 1
        self.logger.debug("rotated by " + str(self.rotationN))

        for p in self.inputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, 1)

        for p in self.outputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, 1)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

    def rotateBlockToN(self, n):
        if n > 0:
            while self.rotationN != n:
                self.rotateBlockCW()
        if n < 0:
            while self.rotationN != n:
                self.rotateBlockCCW()

    def rotateBlockCCW(self):
        # Rotate block clockwise
        # self.setTransformOriginPoint(50, 50)
        self.setTransformOriginPoint(0, 0)
        self.setRotation((self.rotationN - 1) * 90)
        self.label.setRotation(-(self.rotationN - 1) * 90)
        self.rotationN -= 1
        self.logger.debug("rotated by " + str(self.rotationN))

        for p in self.inputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -1)

        for p in self.outputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -1)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

    def resetRotation(self):
        self.logger.debug("Resetting rotation...")
        self.setRotation(0)
        self.label.setRotation(0)

        for p in self.inputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -self.rotationN)
            # self.logger.debug("Portside of port " + str(p) + " is " + str(p.portSide))

        for p in self.outputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -self.rotationN)
            # self.logger.debug("Portside of port " + str(p) + " is " + str(p.portSide))

        self.rotationN = 0

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

    def printRotation(self):
        self.logger.debug("Rotation is " + str(self.rotationN))

    # Deletion related
    def deleteConns(self):

        for p in self.inputs:
            while len(p.connectionList) > 0:
                p.connectionList[0].deleteConn()

        for p in self.outputs:
            while len(p.connectionList) > 0:
                p.connectionList[0].deleteConn()

    def deleteBlock(self):
        self.parent.parent().trnsysObj.remove(self)
        self.parent.scene().removeItem(self)
        widgetToRemove = self.parent.parent().findChild(
            QTreeView, self.displayName + "Tree")
        if widgetToRemove:
            widgetToRemove.hide()

    def deleteBlockCom(self):
        self.parent.deleteBlockCom(self)

    def getConnections(self):
        """
        Get the connections from inputs and outputs of this block.
        Returns
        -------
        c : :obj:`List` of :obj:`BlockItem`
        """
        c = []
        for i in self.inputs:
            for cl in i.connectionList:
                c.append(cl)
        for o in self.outputs:
            for cl in o.connectionList:
                c.append(cl)
        return c

    # Scaling related
    def mousePressEvent(self, event):  # create resizer
        """
        Using try catch to avoid creating extra resizers.

        When an item is clicked on, it will check if a resizer already existed. If
        there exist a resizer, returns. else, creates one.

        Resizer will not be created for GenericBlock due to complications in the code.
        Resizer will not be created for storageTank as there's already a built in function for it in the storageTank
        dialog.

        Resizers are deleted inside mousePressEvent function inside GUI.py

        """
        self.logger.debug("Inside Block Item mouse click")

        self.isSelected = True
        if self.name == "GenericBlock" or self.name == "StorageTank":
            return
        try:
            self.resizer
        except AttributeError:
            self.resizer = ResizerItem(self)
            self.resizer.setPos(self.w, self.h)
            self.resizer.itemChange(self.resizer.ItemPositionChange,
                                    self.resizer.pos())
        else:
            return

    def setItemSize(self, w, h):
        self.logger.debug("Inside block item set item size")
        self.w, self.h = w, h
        # if h < 20:
        #     self.h = 20
        # if w < 40:
        #     self.w = 40

    def updateImage(self):
        self.logger.debug("Inside block item update image")

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        if self.flippedH:
            self.updateFlipStateH(self.flippedH)

        if self.flippedV:
            self.updateFlipStateV(self.flippedV)

    def _getPixmap(self) -> QPixmap:
        imageAccessor = self._getImageAccessor()

        image = imageAccessor.image(width=self.w, height=self.h).mirrored(
            horizontal=self.flippedH, vertical=self.flippedV)
        pixmap = QPixmap(image)

        return pixmap

    def deleteResizer(self):
        try:
            self.resizer
        except AttributeError:
            self.logger.debug("No resizer")
        else:
            del self.resizer

    # AlignMode related
    def itemChange(self, change, value):
        # self.logger.debug(change, value)
        # Snap grid excludes alignment

        if change == self.ItemPositionChange:
            if self.parent.parent().snapGrid:
                snapSize = self.parent.parent().snapSize
                self.logger.debug("itemchange")
                self.logger.debug(type(value))
                value = QPointF(value.x() - value.x() % snapSize,
                                value.y() - value.y() % snapSize)
                return value
            else:
                # if self.hasElementsInYBand() and not self.elementInY() and not self.aligned:
                if self.parent.parent().alignMode:
                    if self.hasElementsInYBand():
                        return self.alignBlock(value)
                    else:
                        # self.aligned = False
                        return value

                else:
                    return value
        else:
            return super(BlockItem, self).itemChange(change, value)

    def alignBlock(self, value):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem) and t is not self:
                if self.elementInYBand(t):
                    value = QPointF(self.pos().x(), t.pos().y())
                    self.parent.parent().alignYLineItem.setLine(
                        self.pos().x() + self.w / 2,
                        t.pos().y(),
                        t.pos().x() + t.w / 2,
                        t.pos().y())

                    self.parent.parent().alignYLineItem.setVisible(True)

                    qtm = QTimer(self.parent.parent())
                    qtm.timeout.connect(self.timerfunc)
                    qtm.setSingleShot(True)
                    qtm.start(1000)

                    e = QMouseEvent(
                        QEvent.MouseButtonRelease,
                        self.pos(),
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoModifier,
                    )
                    self.parent.mouseReleaseEvent(e)
                    self.parent.parent().alignMode = False
                    # self.setPos(self.pos().x(), t.pos().y())
                    # self.aligned = True

                if self.elementInXBand(t):
                    value = QPointF(t.pos().x(), self.pos().y())
                    self.parent.parent().alignXLineItem.setLine(
                        t.pos().x(),
                        t.pos().y() + self.w / 2,
                        t.pos().x(),
                        self.pos().y() + t.w / 2)

                    self.parent.parent().alignXLineItem.setVisible(True)

                    qtm = QTimer(self.parent.parent())
                    qtm.timeout.connect(self.timerfunc2)
                    qtm.setSingleShot(True)
                    qtm.start(1000)

                    e = QMouseEvent(
                        QEvent.MouseButtonRelease,
                        self.pos(),
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoModifier,
                    )
                    self.parent.mouseReleaseEvent(e)
                    self.parent.parent().alignMode = False

        return value

    def timerfunc(self):
        self.parent.parent().alignYLineItem.setVisible(False)

    def timerfunc2(self):
        self.parent.parent().alignXLineItem.setVisible(False)

    def hasElementsInYBand(self):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem):
                if self.elementInYBand(t):
                    return True

        return False

    def hasElementsInXBand(self):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem):
                if self.elementInXBand(t):
                    return True

        return False

    def elementInYBand(self, t):
        eps = 50
        return self.scenePos().y() - eps <= t.scenePos().y(
        ) <= self.scenePos().y() + eps

    def elementInXBand(self, t):
        eps = 50
        return self.scenePos().x() - eps <= t.scenePos().x(
        ) <= self.scenePos().x() + eps

    def elementInY(self):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem):
                if self.scenePos().y == t.scenePos().y():
                    return True
        return False

    def encode(self):
        portListInputs = []
        portListOutputs = []

        for inp in self.inputs:
            portListInputs.append(inp.id)
        for output in self.outputs:
            portListOutputs.append(output.id)

        blockPosition = (float(self.pos().x()), float(self.pos().y()))

        blockItemModel = BlockItemModel(
            self.name,
            self.displayName,
            blockPosition,
            self.id,
            self.trnsysId,
            portListInputs,
            portListOutputs,
            self.flippedH,
            self.flippedV,
            self.rotationN,
        )

        dictName = "Block-"
        return dictName, blockItemModel.to_dict()

    def decode(self, i, resBlockList):
        model = BlockItemModel.from_dict(i)

        self.setName(model.BlockDisplayName)
        self.setPos(float(model.blockPosition[0]),
                    float(model.blockPosition[1]))
        self.id = model.Id
        self.trnsysId = model.trnsysId

        if len(self.inputs) != len(model.portsIdsIn) or len(
                self.outputs) != len(model.portsIdsOut):
            temp = model.portsIdsIn
            model.portsIdsIn = model.portsIdsOut
            model.portsIdsOut = temp

        for index, inp in enumerate(self.inputs):
            inp.id = model.portsIdsIn[index]

        for index, out in enumerate(self.outputs):
            out.id = model.portsIdsOut[index]

        self.updateFlipStateH(model.flippedH)
        self.updateFlipStateV(model.flippedV)
        self.rotateBlockToN(model.rotationN)

        resBlockList.append(self)

    def decodePaste(self, i, offset_x, offset_y, resConnList, resBlockList,
                    **kwargs):
        self.setPos(
            float(i["BlockPosition"][0] + offset_x),
            float(i["BlockPosition"][1] + offset_y),
        )

        self.updateFlipStateH(i["FlippedH"])
        self.updateFlipStateV(i["FlippedV"])
        self.rotateBlockToN(i["RotationN"])

        for x in range(len(self.inputs)):
            self.inputs[x].id = i["PortsIDIn"][x]

        for x in range(len(self.outputs)):
            self.outputs[x].id = i["PortsIDOut"][x]

        resBlockList.append(self)

    # Export related
    def exportBlackBox(self):
        equation = []
        if (len(self.inputs + self.outputs) == 2 and self.isVisible()
                and not isinstance(self.outputs[0], DoublePipePortItem)):
            files = glob.glob(os.path.join(self.path, "**/*.ddck"),
                              recursive=True)
            if not (files):
                status = "noDdckFile"
            else:
                status = "noDdckEntry"
            lines = []
            for file in files:
                infile = open(file, "r")
                lines += infile.readlines()
            for i in range(len(lines)):
                if "output" in lines[i].lower() and "to" in lines[i].lower(
                ) and "hydraulic" in lines[i].lower():
                    for j in range(i, len(lines) - i):
                        if lines[j][0] == "T":
                            outputT = lines[j].split("=")[0].replace(" ", "")
                            status = "success"
                            break
                    equation = ["T" + self.displayName + "=" + outputT]
                    break
        else:
            status = "noBlackBoxOutput"

        if status == "noDdckFile" or status == "noDdckEntry":
            equation.append("T" + self.displayName + "=1")

        return status, equation

    def exportPumpOutlets(self):
        return "", 0

    def exportMassFlows(self):
        return "", 0

    def exportDivSetting1(self):
        return "", 0

    def exportDivSetting2(self, nUnit):
        return "", nUnit

    def exportPipeAndTeeTypesForTemp(self, startingUnit):
        return "", startingUnit

    def getTemperatureVariableName(self, portItem: SinglePipePortItem) -> str:
        return f"T{self.displayName}"

    def getFlowSolverParametersId(self, portItem: SinglePipePortItem) -> int:
        return self.trnsysId

    def assignIDsToUninitializedValuesAfterJsonFormatMigration(
            self, generator: _id.IdGenerator) -> None:
        pass

    def deleteLoadedFile(self):
        for items in self.loadedFiles:
            try:
                self.parent.parent().fileList.remove(str(items))
            except ValueError:
                self.logger.debug("File already deleted from file list.")
                self.logger.debug("filelist:", self.parent.parent().fileList)
예제 #6
0
class LinkItem(QGraphicsObject):
    """
    A Link item in the canvas that connects two :class:`.NodeItem`\s in the
    canvas.

    The link curve connects two `Anchor` items (see :func:`setSourceItem`
    and :func:`setSinkItem`). Once the anchors are set the curve
    automatically adjusts its end points whenever the anchors move.

    An optional source/sink text item can be displayed above the curve's
    central point (:func:`setSourceName`, :func:`setSinkName`)

    """

    #: Z value of the item
    Z_VALUE = 0

    def __init__(self, *args):
        self.__boundingRect = None
        QGraphicsObject.__init__(self, *args)
        self.setFlag(QGraphicsItem.ItemHasNoContents, True)
        self.setAcceptedMouseButtons(Qt.RightButton | Qt.LeftButton)
        self.setAcceptHoverEvents(True)

        self.setZValue(self.Z_VALUE)

        self.sourceItem = None
        self.sourceAnchor = None
        self.sinkItem = None
        self.sinkAnchor = None

        self.curveItem = LinkCurveItem(self)

        self.sourceIndicator = LinkAnchorIndicator(self)
        self.sinkIndicator = LinkAnchorIndicator(self)
        self.sourceIndicator.hide()
        self.sinkIndicator.hide()

        self.linkTextItem = QGraphicsTextItem(self)

        self.__sourceName = ""
        self.__sinkName = ""

        self.__dynamic = False
        self.__dynamicEnabled = False

        self.hover = False

        self.prepareGeometryChange()
        self.__boundingRect = None

    def setSourceItem(self, item, anchor=None):
        """
        Set the source `item` (:class:`.NodeItem`). Use `anchor`
        (:class:`.AnchorPoint`) as the curve start point (if ``None`` a new
        output anchor will be created using ``item.newOutputAnchor()``).

        Setting item to ``None`` and a valid anchor is a valid operation
        (for instance while mouse dragging one end of the link).

        """
        if item is not None and anchor is not None:
            if anchor not in item.outputAnchors():
                raise ValueError("Anchor must be belong to the item")

        if self.sourceItem != item:
            if self.sourceAnchor:
                # Remove a previous source item and the corresponding anchor
                self.sourceAnchor.scenePositionChanged.disconnect(
                    self._sourcePosChanged)

                if self.sourceItem is not None:
                    self.sourceItem.removeOutputAnchor(self.sourceAnchor)

                self.sourceItem = self.sourceAnchor = None

            self.sourceItem = item

            if item is not None and anchor is None:
                # Create a new output anchor for the item if none is provided.
                anchor = item.newOutputAnchor()

            # Update the visibility of the start point indicator.
            self.sourceIndicator.setVisible(bool(item))

        if anchor != self.sourceAnchor:
            if self.sourceAnchor is not None:
                self.sourceAnchor.scenePositionChanged.disconnect(
                    self._sourcePosChanged)

            self.sourceAnchor = anchor

            if self.sourceAnchor is not None:
                self.sourceAnchor.scenePositionChanged.connect(
                    self._sourcePosChanged)

        self.__updateCurve()

    def setSinkItem(self, item, anchor=None):
        """
        Set the sink `item` (:class:`.NodeItem`). Use `anchor`
        (:class:`.AnchorPoint`) as the curve end point (if ``None`` a new
        input anchor will be created using ``item.newInputAnchor()``).

        Setting item to ``None`` and a valid anchor is a valid operation
        (for instance while mouse dragging one and of the link).

        """
        if item is not None and anchor is not None:
            if anchor not in item.inputAnchors():
                raise ValueError("Anchor must be belong to the item")

        if self.sinkItem != item:
            if self.sinkAnchor:
                # Remove a previous source item and the corresponding anchor
                self.sinkAnchor.scenePositionChanged.disconnect(
                    self._sinkPosChanged)

                if self.sinkItem is not None:
                    self.sinkItem.removeInputAnchor(self.sinkAnchor)

                self.sinkItem = self.sinkAnchor = None

            self.sinkItem = item

            if item is not None and anchor is None:
                # Create a new input anchor for the item if none is provided.
                anchor = item.newInputAnchor()

            # Update the visibility of the end point indicator.
            self.sinkIndicator.setVisible(bool(item))

        if self.sinkAnchor != anchor:
            if self.sinkAnchor is not None:
                self.sinkAnchor.scenePositionChanged.disconnect(
                    self._sinkPosChanged)

            self.sinkAnchor = anchor

            if self.sinkAnchor is not None:
                self.sinkAnchor.scenePositionChanged.connect(
                    self._sinkPosChanged)

        self.__updateCurve()

    def setFont(self, font):
        """
        Set the font for the channel names text item.
        """
        if font != self.font():
            self.linkTextItem.setFont(font)
            self.__updateText()

    def font(self):
        """
        Return the font for the channel names text.
        """
        return self.linkTextItem.font()

    def setChannelNamesVisible(self, visible):
        """
        Set the visibility of the channel name text.
        """
        self.linkTextItem.setVisible(visible)

    def setSourceName(self, name):
        """
        Set the name of the source (used in channel name text).
        """
        if self.__sourceName != name:
            self.__sourceName = name
            self.__updateText()

    def sourceName(self):
        """
        Return the source name.
        """
        return self.__sourceName

    def setSinkName(self, name):
        """
        Set the name of the sink (used in channel name text).
        """
        if self.__sinkName != name:
            self.__sinkName = name
            self.__updateText()

    def sinkName(self):
        """
        Return the sink name.
        """
        return self.__sinkName

    def _sinkPosChanged(self, *arg):
        self.__updateCurve()

    def _sourcePosChanged(self, *arg):
        self.__updateCurve()

    def __updateCurve(self):
        self.prepareGeometryChange()
        self.__boundingRect = None
        if self.sourceAnchor and self.sinkAnchor:
            source_pos = self.sourceAnchor.anchorScenePos()
            sink_pos = self.sinkAnchor.anchorScenePos()
            source_pos = self.curveItem.mapFromScene(source_pos)
            sink_pos = self.curveItem.mapFromScene(sink_pos)

            # Adaptive offset for the curve control points to avoid a
            # cusp when the two points have the same y coordinate
            # and are close together
            delta = source_pos - sink_pos
            dist = math.sqrt(delta.x()**2 + delta.y()**2)
            cp_offset = min(dist / 2.0, 60.0)

            # TODO: make the curve tangent orthogonal to the anchors path.
            path = QPainterPath()
            path.moveTo(source_pos)
            path.cubicTo(source_pos + QPointF(cp_offset, 0),
                         sink_pos - QPointF(cp_offset, 0), sink_pos)

            self.curveItem.setPath(path)
            self.sourceIndicator.setPos(source_pos)
            self.sinkIndicator.setPos(sink_pos)
            self.__updateText()
        else:
            self.setHoverState(False)
            self.curveItem.setPath(QPainterPath())

    def __updateText(self):
        self.prepareGeometryChange()
        self.__boundingRect = None

        if self.__sourceName or self.__sinkName:
            if self.__sourceName != self.__sinkName:
                text = u"{0} \u2192 {1}".format(self.__sourceName,
                                                self.__sinkName)
            else:
                # If the names are the same show only one.
                # Is this right? If the sink has two input channels of the
                # same type having the name on the link help elucidate
                # the scheme.
                text = self.__sourceName
        else:
            text = ""

        self.linkTextItem.setPlainText(text)

        path = self.curveItem.path()
        if not path.isEmpty():
            center = path.pointAtPercent(0.5)
            angle = path.angleAtPercent(0.5)

            brect = self.linkTextItem.boundingRect()

            transform = QTransform()
            transform.translate(center.x(), center.y())
            transform.rotate(-angle)

            # Center and move above the curve path.
            transform.translate(-brect.width() / 2, -brect.height())

            self.linkTextItem.setTransform(transform)

    def removeLink(self):
        self.setSinkItem(None)
        self.setSourceItem(None)
        self.__updateCurve()

    def setHoverState(self, state):
        if self.hover != state:
            self.prepareGeometryChange()
            self.__boundingRect = None
            self.hover = state
            self.sinkIndicator.setHoverState(state)
            self.sourceIndicator.setHoverState(state)
            self.curveItem.setHoverState(state)

    def hoverEnterEvent(self, event):
        # Hover enter event happens when the mouse enters any child object
        # but we only want to show the 'hovered' shadow when the mouse
        # is over the 'curveItem', so we install self as an event filter
        # on the LinkCurveItem and listen to its hover events.
        self.curveItem.installSceneEventFilter(self)
        return QGraphicsObject.hoverEnterEvent(self, event)

    def hoverLeaveEvent(self, event):
        # Remove the event filter to prevent unnecessary work in
        # scene event filter when not needed
        self.curveItem.removeSceneEventFilter(self)
        return QGraphicsObject.hoverLeaveEvent(self, event)

    def sceneEventFilter(self, obj, event):
        if obj is self.curveItem:
            if event.type() == QEvent.GraphicsSceneHoverEnter:
                self.setHoverState(True)
            elif event.type() == QEvent.GraphicsSceneHoverLeave:
                self.setHoverState(False)

        return QGraphicsObject.sceneEventFilter(self, obj, event)

    def boundingRect(self):
        if self.__boundingRect is None:
            self.__boundingRect = self.childrenBoundingRect()
        return self.__boundingRect

    def shape(self):
        return self.curveItem.shape()

    def setEnabled(self, enabled):
        """
        Reimplemented from :class:`QGraphicsObject`

        Set link enabled state. When disabled the link is rendered with a
        dashed line.

        """
        # This getter/setter pair override a property from the base class.
        # They should be renamed to e.g. setLinkEnabled/linkEnabled
        self.curveItem.setLinkEnabled(enabled)

    def isEnabled(self):
        return self.curveItem.isLinkEnabled()

    def setDynamicEnabled(self, enabled):
        """
        Set the link's dynamic enabled state.

        If the link is `dynamic` it will be rendered in red/green color
        respectively depending on the state of the dynamic enabled state.

        """
        if self.__dynamicEnabled != enabled:
            self.__dynamicEnabled = enabled
            if self.__dynamic:
                self.__updatePen()

    def isDynamicEnabled(self):
        """
        Is the link dynamic enabled.
        """
        return self.__dynamicEnabled

    def setDynamic(self, dynamic):
        """
        Mark the link as dynamic (i.e. it responds to
        :func:`setDynamicEnabled`).

        """
        if self.__dynamic != dynamic:
            self.__dynamic = dynamic
            self.__updatePen()

    def isDynamic(self):
        """
        Is the link dynamic.
        """
        return self.__dynamic

    def __updatePen(self):
        self.prepareGeometryChange()
        self.__boundingRect = None
        if self.__dynamic:
            if self.__dynamicEnabled:
                color = QColor(0, 150, 0, 150)
            else:
                color = QColor(150, 0, 0, 150)

            normal = QPen(QBrush(color), 2.0)
            hover = QPen(QBrush(color.darker(120)), 2.1)
        else:
            normal = QPen(QBrush(QColor("#9CACB4")), 2.0)
            hover = QPen(QBrush(QColor("#7D7D7D")), 2.1)

        self.curveItem.setCurvePenSet(normal, hover)
예제 #7
0
class SegmentItemBase(QGraphicsItemGroup):
    def __init__(self, startNode, endNode, parent: "ConnectionBase"):
        """
        A connection is displayed as a chain of segmentItems (stored in Connection.segments)
        Parameters.
        ----------
        startNode
        endNode
        parent: type(parent): Connection
        """

        super().__init__(None)
        self.logger = parent.logger

        self.setFlag(self.ItemIsSelectable, True)

        self.dragged = False
        self.initialised = False
        self.connection = parent

        self.firstChild = None
        self.secondChild = None
        self.cornerChild = None

        self.linePoints = None

        self.startNode = startNode
        self.endNode = endNode

        # These nodes are the nodes before and after the crossing
        self.start = None
        self.end = None

        # Unused. Related to interrupting segments for a clearer diagram
        self.disrBeforeNode = None
        self.disrAfterNode = None
        self.disrBeforeSeg = None
        self.disrAfterSeg = None
        self.disrBefore = False
        self.disrAfter = False
        self.hasBridge = False
        self.bridgedSegment = None

        # Only for editorMode 1
        self.firstLine = None
        self.secondLine = None
        self.secondCorner = None
        self.thirdCorner = None

        self.keyPr = 0
        # Used to only create the child objects once
        self._isDraggingInProgress = False

        self.insertInParentSegments()

        self.label = QGraphicsTextItem(self.connection.displayName)
        self.connection.parent.diagramScene.addItem(self.label)
        self.label.setVisible(False)
        self.label.setFlag(self.ItemIsMovable, True)
        self.labelMass = QGraphicsTextItem()
        self.connection.parent.diagramScene.addItem(self.labelMass)
        self.labelMass.setVisible(False)
        self.labelMass.setFlag(self.ItemIsMovable, True)

        self.setToolTip(self.connection.displayName)

    def segLength(self):
        return calcDist(self.line().p1(), self.line().p2())

    def interpolate(
        self,
        partLen2,
        totLenConn,
    ):
        # c1_r = 0
        # c1_b = 255
        c1_r = 160
        c1_b = 160
        c1_g = 160

        # c2_r = 255
        # c2_b = 0
        c2_r = 0
        c2_b = 0
        c2_g = 0

        try:
            f1 = int(partLen2 / totLenConn)
            f2 = int((totLenConn - partLen2) / totLenConn)
        except ZeroDivisionError:
            return QColor(100, 100, 100)
        else:
            return QColor(f1 * c2_r + f2 * c1_r, f1 * c2_g + f2 * c1_g,
                          f1 * c2_b + f2 * c1_b)

    def line(self):
        return self.linePoints

    def setLine(self, *args):
        self.setZValue(-1)
        if len(args) == 2:
            p1, p2 = args
            x1 = p1.x()
            y1 = p1.y()
            x2 = p2.x()
            y2 = p2.y()
        else:
            x1, y1, x2, y2 = args

        self._setLineImpl(x1, y1, x2, y2)

    def _setLineImpl(self, x1, y1, x2, y2):
        raise NotImplementedError()

    def updateGrad(self):
        raise NotImplementedError()

    def insertInParentSegments(self):
        """
        This function inserts the segment in correct order to the segment list of the connection.
        Returns
        -------

        """
        prevSeg = None

        for s in self.connection.segments:
            if s.endNode is self.startNode:
                prevSeg = s

        # Todo: Add support for disr segments

        # if the startNode parent is a connection:
        if not hasattr(self.startNode.parent, "fromPort"):
            self.connection.segments.insert(
                self.connection.segments.index(prevSeg) + 1, self)
        else:

            self.connection.segments.insert(0, self)

    def mousePressEvent(self, e):

        if e.button() == 1:
            self.keyPr = 1
            self.logger.debug("Setting key to 1")

            self.connection.selectConnection()
            if self.isVertical():
                try:
                    self.oldX = self.startNode.parent.scenePos().x()
                except AttributeError:
                    pass
                else:
                    self.logger.debug("set oldx")

    def mouseMoveEvent(self, e):
        self.logger.debug(self.connection.parent.editorMode)
        if self.keyPr == 1:
            self.logger.debug("moved with button 1")
            newPos = e.pos()

            if self.connection.parent.editorMode == 0:
                if not self._isDraggingInProgress:
                    self.initInMode0()
                else:
                    self.dragInMode0(newPos)

            elif self.connection.parent.editorMode == 1:
                if type(self.startNode.parent) is CornerItem and type(
                        self.endNode.parent) is CornerItem:
                    if not self.startNode.parent.isVisible():
                        self.startNode.parent.setVisible(True)
                    if not self.endNode.parent.isVisible():
                        self.endNode.parent.setVisible(True)
                    if self.isVertical():

                        self.logger.debug("Segment is vertical: %s",
                                          self.connection.segments.index(self))
                        self.endNode.parent.setPos(
                            newPos.x(),
                            self.endNode.parent.scenePos().y())
                        self.startNode.parent.setPos(
                            newPos.x(),
                            self.startNode.parent.scenePos().y())
                        self.updateGrad()

                    if self.isHorizontal():
                        self.logger.debug("Segment is horizontal")
                        self.endNode.parent.setPos(
                            self.endNode.parent.scenePos().x(), newPos.y())
                        self.startNode.parent.setPos(
                            self.startNode.parent.scenePos().x(), newPos.y())

                elif type(self.endNode.parent
                          ) is CornerItem and self.isVertical():
                    self.logger.debug("Segment is vertical and can't be moved")

                if self.isHorizontal():
                    isFirstSegment = hasattr(
                        self.startNode.parent,
                        "fromPort") and not self.startNode.prevN()
                    isLastSegment = hasattr(
                        self.endNode.parent,
                        "fromPort") and not self.endNode.nextN()

                    if isLastSegment:
                        self.logger.debug("A last segment is being dragged.")
                        if not self._isDraggingInProgress:
                            self._initInMode1(False)
                        self._dragInMode1(False, newPos)
                    elif isFirstSegment:
                        self.logger.debug("A first segment is being dragged.")
                        if not self._isDraggingInProgress:
                            self._initInMode1(True)
                        self._dragInMode1(True, newPos)
            else:
                self.logger.debug(
                    "Unrecognized editorMode in segmentItem mouseMoveEvent")

    def deleteNextHorizSeg(self, b, nextS):
        if b:
            pass
        else:
            nodeTodelete1 = self.endNode
            nodeTodelete2 = self.endNode.nextN()
            self.endNode = nextS.endNode

            self.startNode.setNext(self.endNode)
            self.endNode.setPrev(self.startNode)

            # x-position of the ending point of the next segment line

            posx1 = self.connection.segments[
                self.connection.segments.index(self) + 2].line().p2().x()

            self.connection.parent.diagramScene.removeItem(nextS)
            self.connection.segments.remove(nextS)
            self.connection.parent.diagramScene.removeItem(
                nodeTodelete1.parent)

            indexOfSelf = self.connection.segments.index(self)
            nextVS = self.connection.segments[indexOfSelf + 1]

            self.connection.parent.diagramScene.removeItem(nextVS)
            self.connection.segments.remove(nextVS)
            self.connection.parent.diagramScene.removeItem(
                nodeTodelete2.parent)

            self.setLine(
                self.startNode.parent.scenePos().x(),
                self.startNode.parent.scenePos().y(),
                posx1,
                self.startNode.parent.scenePos().y(),
            )

    def deletePrevHorizSeg(self, b, prevS):
        if b:
            pass
        else:
            nodeTodelete1 = self.startNode
            nodeTodelete2 = self.startNode.prevN()
            self.startNode = prevS.startNode

            self.startNode.setNext(self.endNode)
            self.endNode.setPrev(self.startNode)

            posx1 = self.connection.segments[
                self.connection.segments.index(self) - 2].line().p1().x()

            self.connection.parent.diagramScene.removeItem(prevS)
            self.connection.segments.remove(prevS)
            self.connection.parent.diagramScene.removeItem(
                nodeTodelete1.parent)

            indexOfSelf = self.connection.segments.index(self)
            nextVS = self.connection.segments[indexOfSelf - 1]

            self.connection.parent.diagramScene.removeItem(nextVS)
            self.connection.segments.remove(nextVS)
            self.connection.parent.diagramScene.removeItem(
                nodeTodelete2.parent)

            self.setLine(
                posx1,
                self.endNode.parent.scenePos().y(),
                self.endNode.parent.scenePos().x(),
                self.endNode.parent.scenePos().y(),
            )

    def deleteSegment(self):
        nodeToConnect = self.startNode.prevN()
        nodeToConnect2 = self.endNode.nextN()

        nodeToConnect.setNext(nodeToConnect2)

        self.connection.parent.diagramScene.removeItem(self)
        self.connection.segments.remove(self)
        self.connection.parent.diagramScene.removeItem(self.startNode.parent)
        self.connection.parent.diagramScene.removeItem(self.endNode.parent)

    def splitSegment(self):
        pass

    def mouseReleaseEvent(self, e):
        # Should be same as below
        # self.scene().removeItem(self)

        if e.button() == 1:
            self.keyPr = 0

            if self.connection.parent.editorMode == 0:
                if self._isDraggingInProgress:
                    self.cornerChild.setFlag(
                        self.ItemSendsScenePositionChanges, True)

                    self.hide()
                    self.connection.segments.remove(self)
                    self.connection.parent.diagramScene.removeItem(self)

            elif self.connection.parent.editorMode == 1:
                if self.isVertical():
                    try:
                        self.oldX
                    except AttributeError:
                        pass
                    else:
                        command = HorizSegmentMoveCommand(
                            self, self.oldX, "Moving segment command")

                        self.connection.parent.parent().undoStack.push(command)
                        self.oldX = self.scenePos().x()

                if self.isHorizontal():
                    if type(self.startNode.parent) is CornerItem and type(
                            self.endNode.parent) is CornerItem:
                        try:

                            nextHorizSeg = self.connection.segments[
                                self.connection.segments.index(self) + 2]
                            prevHorizSeg = self.connection.segments[
                                self.connection.segments.index(self) - 2]
                        except IndexError:
                            self.logger.debug("no next or prev segments")
                        else:
                            if nextHorizSeg.isHorizontal(
                            ) and int(self.endNode.parent.pos().y() -
                                      10) <= int(nextHorizSeg.line().p2().y(
                                      )) <= int(self.endNode.parent.pos().y() +
                                                10):
                                self.deleteNextHorizSeg(False, nextHorizSeg)
                                self.logger.debug("next horizontal")
                                return

                            if prevHorizSeg.isHorizontal() and int(
                                    self.startNode.parent.pos().y() - 10
                            ) <= int(prevHorizSeg.line().p2().y()) <= int(
                                    self.startNode.parent.pos().y() + 10):
                                self.deletePrevHorizSeg(False, prevHorizSeg)
                                self.logger.debug("previous horizontal")
                                return

                if self.secondCorner is not None:
                    self.logger.debug("Second corner is not none")
                    # if PortItem
                    if hasattr(self.endNode.parent, "fromPort"):
                        segbef = self.connection.segments[
                            self.connection.getNodePos(
                                self.secondCorner.node.prevN().parent)]

                        segbef.setLine(
                            segbef.line().p1().x(),
                            segbef.line().p1().y(),
                            segbef.line().p2().x(),
                            self.secondCorner.scenePos().y(),
                        )
                        self.setLine(
                            self.thirdCorner.scenePos().x(),
                            self.thirdCorner.scenePos().y(),
                            self.line().p2().x(),
                            self.line().p2().y(),
                        )
                        self.secondCorner.setFlag(
                            self.ItemSendsScenePositionChanges, True)
                        self.thirdCorner.setFlag(
                            self.ItemSendsScenePositionChanges, True)

                        # Allow for iterative branching
                        self.secondCorner = None
                        self.thirdCorner = None
                        self.firstLine = None
                        self.secondLine = None
                        self._isDraggingInProgress = False

                    # if PortItem
                    elif hasattr(self.startNode.parent, "fromPort"):

                        segafter = self.connection.segments[
                            self.connection.getNodePos(
                                self.thirdCorner.node.nextN().parent)]

                        segafter.setLine(
                            segafter.line().p1().x(),
                            self.thirdCorner.scenePos().y(),
                            segafter.line().p2().x(),
                            segafter.line().p2().y(),
                        )
                        self.setLine(
                            self.line().p1().x(),
                            self.line().p1().y(),
                            self.secondCorner.scenePos().x(),
                            self.secondCorner.scenePos().y(),
                        )

                        self.secondCorner.setFlag(
                            self.ItemSendsScenePositionChanges, True)
                        self.thirdCorner.setFlag(
                            self.ItemSendsScenePositionChanges, True)

                        # Allow for iterative branching
                        self.secondCorner = None
                        self.thirdCorner = None
                        self.firstLine = None
                        self.secondLine = None
                        self._isDraggingInProgress = False

                    else:
                        self.logger.debug("getting no start or end")

                else:
                    self.logger.debug("Second corner is none")
            else:
                pass

    def initInMode0(self):
        if (hasattr(self.startNode.parent,
                    "fromPort")) and (self.startNode.prevN() is not None):
            self.disrAfterNode = self.startNode
            self.start = self.startNode.prevN().prevN()

            segments = self.connection.segments
            for s in segments:
                if s.startNode is self.start:
                    self.disrBeforeSeg = s

            self.disrAfterSeg = self
            self.disrBefore = True

        else:
            self.start = self.startNode

        if (hasattr(self.endNode.parent,
                    "fromPort")) and (self.endNode.nextN() is not None):
            self.disrBeforeNode = self.endNode
            self.end = self.endNode.nextN().nextN()

            segments = self.connection.segments
            for s in segments:
                if s.endNode is self.end:
                    self.disrAfterSeg = s

            self.disrBeforeSeg = self
            self.disrAfter = True

        else:
            self.end = self.endNode

        rad = self.connection.getRadius()

        self.cornerChild = CornerItem(-rad, -rad, 2 * rad, 2 * rad, self.start,
                                      self.end, self.connection)
        self.firstChild = self._createSegment(self.start,
                                              self.cornerChild.node)
        self.secondChild = self._createSegment(self.cornerChild.node, self.end)

        self.start.setNext(self.cornerChild.node)
        self.end.setPrev(self.cornerChild.node)

        self.firstChild.setVisible(False)
        self.secondChild.setVisible(False)
        self.cornerChild.setVisible(False)

        self.connection.parent.diagramScene.addItem(self.firstChild)
        self.connection.parent.diagramScene.addItem(self.secondChild)
        self.connection.parent.diagramScene.addItem(self.cornerChild)

        self._isDraggingInProgress = True

    def _initInMode1(self, b):

        rad = self.connection.getRadius()

        if b:
            if (hasattr(self.startNode.parent,
                        "fromPort")) and (self.startNode.prevN() is None):
                # We are at the toPort.
                # self.end = self.endNode
                # self.start = self.startNode

                self.secondCorner = CornerItem(-rad, -rad, 2 * rad, 2 * rad,
                                               self.startNode, None,
                                               self.connection)
                self.thirdCorner = CornerItem(-rad, -rad, 2 * rad, 2 * rad,
                                              self.secondCorner.node,
                                              self.endNode, self.connection)

                self.secondCorner.node.setNext(self.thirdCorner.node)
                self.startNode.setNext(self.secondCorner.node)
                self.endNode.setPrev(self.thirdCorner.node)

                self.endNode = self.secondCorner.node

                self.firstLine = self._createSegment(self.secondCorner.node,
                                                     self.thirdCorner.node)
                self.secondLine = self._createSegment(
                    self.thirdCorner.node, self.thirdCorner.node.nextN())

                self.secondCorner.setVisible(False)
                self.thirdCorner.setVisible(False)
                self.firstLine.setVisible(False)
                self.secondLine.setVisible(False)
                # self.thirdLine.setVisible(False)

                self.connection.parent.diagramScene.addItem(self.secondCorner)
                self.connection.parent.diagramScene.addItem(self.thirdCorner)
                self.connection.parent.diagramScene.addItem(self.firstLine)
                self.connection.parent.diagramScene.addItem(self.secondLine)
                self.logger.debug("inited")

                self._isDraggingInProgress = True
        else:
            if (hasattr(self.endNode.parent,
                        "fromPort")) and (self.endNode.nextN() is None):
                # We are at the toPort.
                # self.end = self.endNode
                # self.start = self.startNode

                self.secondCorner = CornerItem(-rad, -rad, 2 * rad, 2 * rad,
                                               self.startNode, None,
                                               self.connection)
                self.thirdCorner = CornerItem(-rad, -rad, 2 * rad, 2 * rad,
                                              self.secondCorner.node,
                                              self.endNode, self.connection)

                self.secondCorner.node.setNext(self.thirdCorner.node)
                self.startNode.setNext(self.secondCorner.node)
                self.endNode.setPrev(self.thirdCorner.node)

                self.startNode = self.thirdCorner.node

                self.firstLine = self._createSegment(
                    self.secondCorner.node.prevN(), self.secondCorner.node)
                self.secondLine = self._createSegment(self.secondCorner.node,
                                                      self.thirdCorner.node)

                self.secondCorner.setVisible(False)
                self.thirdCorner.setVisible(False)
                self.firstLine.setVisible(False)
                self.secondLine.setVisible(False)
                # self.thirdLine.setVisible(False)

                self.connection.parent.diagramScene.addItem(self.secondCorner)
                self.connection.parent.diagramScene.addItem(self.thirdCorner)
                self.connection.parent.diagramScene.addItem(self.firstLine)
                self.connection.parent.diagramScene.addItem(self.secondLine)
                self.logger.debug("inited")

                self._isDraggingInProgress = True

    def _createSegment(self, startNode, endNode) -> "SegmentItemBase":
        raise NotImplementedError()

    def isVertical(self):
        return self.line().p1().x() == self.line().p2().x()

    def isHorizontal(self):
        return self.line().p1().y() == self.line().p2().y()

    def dragInMode0(self, newPos):
        p1 = self.line().p1()
        p2 = self.line().p2()

        if len(self.scene().items(newPos)) == 0:

            self.firstChild.setLine(p1.x(), p1.y(), newPos.x(), newPos.y())
            self.secondChild.setLine(newPos.x(), newPos.y(), p2.x(), p2.y())

            self.cornerChild.setPos(newPos)

            self.firstChild.updateGrad()
            self.secondChild.updateGrad()

            # Bring corner to front
            self.cornerChild.setZValue(100)
            self.firstChild.setZValue(1)
            self.secondChild.setZValue(1)

            self.firstChild.setVisible(True)
            self.secondChild.setVisible(True)
            self.cornerChild.setVisible(True)

    def _dragInMode1(self, b, newPos):
        self.logger.debug("after inited")

        if b:
            self.thirdCorner.setPos(newPos.x() - 10, newPos.y())

            self.secondCorner.setPos(newPos.x() - 10,
                                     self.connection.fromPort.scenePos().y())
            self.thirdCorner.node.nextN().parent.setY(newPos.y())

            self.firstLine.setLine(
                self.secondCorner.scenePos().x(),
                self.secondCorner.scenePos().y(),
                self.thirdCorner.scenePos().x(),
                newPos.y(),
            )
            self.secondLine.setLine(
                self.thirdCorner.scenePos().x(),
                self.thirdCorner.scenePos().y(),
                self.thirdCorner.node.nextN().parent.scenePos().x(),
                self.thirdCorner.node.nextN().parent.scenePos().y(),
            )
            self.setLine(
                self.startNode.parent.fromPort.scenePos().x(),
                self.startNode.parent.fromPort.scenePos().y(),
                self.secondCorner.scenePos().x(),
                self.secondCorner.scenePos().y(),
            )

            self.secondCorner.setZValue(100)
            self.thirdCorner.setZValue(100)
            self.firstLine.setZValue(1)
            self.secondLine.setZValue(1)

            self.secondCorner.setVisible(True)
            self.thirdCorner.setVisible(True)
            self.firstLine.setVisible(True)
            self.secondLine.setVisible(True)

        else:
            self.secondCorner.setPos(newPos.x() + 10, newPos.y())

            self.thirdCorner.setPos(newPos.x() + 10,
                                    self.connection.toPort.scenePos().y())
            self.secondCorner.node.prevN().parent.setY(newPos.y())

            self.firstLine.setLine(
                self.secondCorner.node.prevN().parent.scenePos().x(),
                newPos.y(),
                self.secondCorner.scenePos().x(),
                newPos.y(),
            )
            self.secondLine.setLine(
                self.secondCorner.scenePos().x(),
                self.secondCorner.scenePos().y(),
                self.thirdCorner.scenePos().x(),
                self.thirdCorner.scenePos().y(),
            )
            self.setLine(
                self.thirdCorner.scenePos().x(),
                self.thirdCorner.scenePos().y(),
                self.endNode.parent.toPort.scenePos().x(),
                self.endNode.parent.toPort.scenePos().y(),
            )

            self.secondCorner.setZValue(100)
            self.thirdCorner.setZValue(100)
            self.firstLine.setZValue(1)
            self.secondLine.setZValue(1)

            self.secondCorner.setVisible(True)
            self.thirdCorner.setVisible(True)
            self.firstLine.setVisible(True)
            self.secondLine.setVisible(True)

    def renameConn(self):
        self.scene().parent().showSegmentDlg(self)

    def printItemsAt(self):
        self.logger.debug("Items at startnode are %s",
                          str(self.scene().items(self.line().p1())))
        self.logger.debug("Items at endnode are %s",
                          str(self.scene().items(self.line().p2())))

        for s in self.connection.segments:
            self.logger.debug(
                "Segment in list is %s has startnode %s endnode %s",
                str(s),
                str(s.startNode.parent),
                str(s.endNode.parent),
            )

    def contextMenuEvent(self, event):
        menu = self._getContextMenu()

        menu.exec(event.screenPos())

    def _getContextMenu(self) -> QMenu:
        menu = QMenu()
        a1 = menu.addAction("Rename...")
        a1.triggered.connect(self.renameConn)
        a2 = menu.addAction("Delete this connection")
        a2.triggered.connect(
            self.connection.createDeleteUndoCommandAndAddToStack)
        a3 = menu.addAction("Invert this connection")
        a3.triggered.connect(self.connection.invertConnection)
        a4 = menu.addAction("Toggle name")
        a4.triggered.connect(self.connection.toggleLabelVisible)
        a5 = menu.addAction("Toggle mass flow")
        a5.triggered.connect(self.connection.toggleMassFlowLabelVisible)
        return menu

    def setLabelVisible(self, isVisible: bool) -> None:
        self.label.setVisible(isVisible)

    def toggleLabelVisible(self) -> None:
        wasVisible = self.label.isVisible()
        self.setLabelVisible(not wasVisible)

    def setMassFlowLabelVisible(self, isVisible: bool) -> None:
        self.labelMass.setVisible(isVisible)

    def toggleMassFlowLabelVisible(self) -> None:
        wasVisible = self.labelMass.isVisible()
        self.setMassFlowLabelVisible(not wasVisible)

    def setSelect(self, isSelected: bool) -> None:
        raise NotImplementedError()

    @staticmethod
    def _createSelectPen() -> QPen:
        color = QColor(125, 242, 189)
        width = 4

        selectPen = QPen(color, width)
        return selectPen

    def setColorAndWidthAccordingToMassflow(self, color, width):
        raise NotImplementedError()
예제 #8
0
class TVentil(BlockItem, MassFlowNetworkContributorMixin):
    def __init__(self, trnsysType, parent, **kwargs):
        super(TVentil, self).__init__(trnsysType, parent, **kwargs)

        self.h = 40
        self.w = 40
        self.isTempering = False
        self.positionForMassFlowSolver = 1.0
        self.posLabel = QGraphicsTextItem(str(self.positionForMassFlowSolver),
                                          self)
        self.posLabel.setVisible(False)

        self.inputs.append(_cspi.createSinglePipePortItem("i", 0, self))
        self.inputs.append(_cspi.createSinglePipePortItem("i", 1, self))
        self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self))

        self.changeSize()

    def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]:
        return _img.T_VENTIL_SVG

    def changeSize(self):
        w = self.w
        h = self.h

        delta = 20
        # Limit the block size:
        if h < 20:
            h = 20
        if w < 40:
            w = 40

        # center label:
        rect = self.label.boundingRect()
        lw, lh = rect.width(), rect.height()
        lx = (w - lw) / 2

        self.label.setPos(lx, h - self.flippedV * (h + h / 2))
        self.posLabel.setPos(lx + 5, -15)

        self.origInputsPos = [[0, delta], [delta, 0]]
        self.origOutputsPos = [[w, delta]]
        self.inputs[0].setPos(self.origInputsPos[0][0],
                              self.origInputsPos[0][1])
        self.inputs[1].setPos(self.origInputsPos[1][0],
                              self.origInputsPos[1][1])
        self.outputs[0].setPos(self.origOutputsPos[0][0],
                               self.origOutputsPos[0][1])

        self.updateFlipStateH(self.flippedH)
        self.updateFlipStateV(self.flippedV)

        self.inputs[0].side = (self.rotationN + 2 * self.flippedH) % 4
        self.inputs[1].side = (self.rotationN + 1 + 2 * self.flippedV) % 4
        self.outputs[0].side = (self.rotationN + 2 - 2 * self.flippedH) % 4

        return w, h

    def rotateBlockCW(self):
        super().rotateBlockCW()
        # Rotate valve position label back so it will always stay horizontal
        self._updateRotation()

    def rotateBlockCCW(self):
        super().rotateBlockCCW()
        # Rotate valve position label back so it will always stay horizontal
        self._updateRotation()

    def resetRotation(self):
        super().resetRotation()
        # Rotate valve position label back so it will always stay horizontal
        self._updateRotation()

    def _updateRotation(self):
        self.posLabel.setRotation(-self.rotationN * 90)

    def setComplexDiv(self, b):
        self.isTempering = bool(b)

    def setPositionForMassFlowSolver(self, f):
        self.positionForMassFlowSolver = f

    def encode(self):
        dictName, dct = super(TVentil, self).encode()
        dct["IsTempering"] = self.isTempering
        dct["PositionForMassFlowSolver"] = self.positionForMassFlowSolver
        return dictName, dct

    def decode(self, i, resBlockList):
        super().decode(i, resBlockList)
        if "IsTempering" not in i or "PositionForMassFlowSolver" not in i:
            self.logger.debug("Old version of diagram")
            self.positionForMassFlowSolver = 1.0
        else:
            self.isTempering = i["IsTempering"]
            self.positionForMassFlowSolver = i["PositionForMassFlowSolver"]

    def decodePaste(self, i, offset_x, offset_y, resConnList, resBlockList,
                    **kwargs):
        super(TVentil, self).decodePaste(i, offset_x, offset_y, resConnList,
                                         resBlockList, **kwargs)
        if "IsTempering" or "PositionForMassFlowSolver" not in i:
            self.logger.debug("Old version of diagram")
            self.positionForMassFlowSolver = 1.0
        else:
            self.isTempering = i["IsTempering"]
            self.positionForMassFlowSolver = i["PositionForMassFlowSolver"]

    def exportMassFlows(self):
        if not self.isTempering:
            resStr = "xFrac" + self.displayName + " = " + str(
                self.positionForMassFlowSolver) + "\n"
            equationNr = 1
            return resStr, equationNr
        else:
            return "", 0

    def exportDivSetting1(self):
        if self.isTempering:
            constants = 1
            f = "T_set_" + self.displayName + "=50\n"
            return f, constants
        else:
            return "", 0

    def exportDivSetting2(self, nUnit):
        if self.isTempering:
            f = ""
            nUnit = nUnit + 1
            f += "UNIT %d TYPE 811 ! Passive Divider for heating \n" % nUnit
            f += "PARAMETERS 1" + "\n"
            f += "5 !Nb.of iterations before fixing the value \n"
            f += "INPUTS 4 \n"

            if (self.outputs[0].pos().y() == self.inputs[0].pos().y()
                    or self.outputs[0].pos().x() == self.inputs[0].pos().x()):
                first = self.inputs[0]
                second = self.inputs[1]

            f += "T" + first.connectionList[0].displayName + "\n"
            f += "T" + second.connectionList[0].displayName + "\n"
            f += "Mfr" + self.outputs[0].connectionList[0].displayName + "\n"

            f += "T_set_" + self.displayName + "\n"
            f += "*** INITIAL INPUT VALUES" + "\n"
            f += "35.0 21.0 800.0 T_set_" + self.displayName + "\n"

            f += "EQUATIONS 1\n"
            f += "xFrac" + self.displayName + " =  1.-[%d,5] \n\n" % nUnit

            return f, nUnit
        else:
            return "", nUnit

    def getInternalPiping(self) -> _mfs.InternalPiping:
        teePiece, modelPortItemsToGraphicalPortItem = self._getModelAndMapping(
        )

        return _mfs.InternalPiping([teePiece],
                                   modelPortItemsToGraphicalPortItem)

    def _getModelAndMapping(self):
        input1 = _mfn.PortItem("TVentil Input 1", _mfn.PortItemType.INPUT)
        input2 = _mfn.PortItem("TVentil Input 2", _mfn.PortItemType.INPUT)
        output = _mfn.PortItem("TVentil Output", _mfn.PortItemType.OUTPUT)
        teePiece = _mfn.Diverter(self.displayName, self.trnsysId, output,
                                 input1, input2)
        modelPortItemsToGraphicalPortItem = {
            input1: self.inputs[0],
            input2: self.inputs[1],
            output: self.outputs[0]
        }
        return teePiece, modelPortItemsToGraphicalPortItem

    def exportPipeAndTeeTypesForTemp(self, startingUnit):
        if self.isVisible():
            f = ""
            unitNumber = startingUnit
            tNr = 929  # Temperature calculation from a tee-piece

            unitText = ""
            ambientT = 20

            equationConstant = 1

            unitText += "UNIT " + str(unitNumber) + " TYPE " + str(tNr) + "\n"
            unitText += "!" + self.displayName + "\n"
            unitText += "PARAMETERS 0\n"
            unitText += "INPUTS 6\n"

            openLoops, nodesToIndices = self._getOpenLoopsAndNodeToIndices()
            assert len(openLoops) == 1
            openLoop = openLoops[0]

            assert len(openLoop.realNodes) == 1
            realNode = openLoop.realNodes[0]

            outputVariables = realNode.serialize(
                nodesToIndices).outputVariables
            for outputVariable in outputVariables:
                if not outputVariable:
                    continue

                unitText += outputVariable.name + "\n"

            unitText += f"T{self.outputs[0].connectionList[0].displayName}\n"
            unitText += f"T{self.inputs[0].connectionList[0].displayName}\n"
            unitText += f"T{self.inputs[1].connectionList[0].displayName}\n"

            unitText += "***Initial values\n"
            unitText += 3 * "0 " + 3 * (str(ambientT) + " ") + "\n"

            unitText += "EQUATIONS 1\n"
            unitText += "T" + self.displayName + "= [" + str(
                unitNumber) + "," + str(equationConstant) + "]\n"

            unitNumber += 1
            f += unitText + "\n"

            return f, unitNumber
        else:
            return "", startingUnit