Exemple #1
0
    def drawGrid(self):
        black_notes = [2,4,6,9,11]
        scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
        scale_bar.setPos(self.piano_width, 0)
        scale_bar.setBrush(QColor(100,100,100))
        clearpen = QPen(QColor(0,0,0,0))
        for i in range(self.end_octave - self.start_octave, self.start_octave - self.start_octave, -1):
            for j in range(self.notes_in_octave, 0, -1):
                scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
                scale_bar.setPos(self.piano_width, self.note_height * j + self.octave_height * (i - 1))
                scale_bar.setPen(clearpen)
                if j not in black_notes:
                    scale_bar.setBrush(QColor(120,120,120))
                else:
                    scale_bar.setBrush(QColor(100,100,100))

        measure_pen = QPen(QColor(0, 0, 0, 120), 3)
        half_measure_pen = QPen(QColor(0, 0, 0, 40), 2)
        line_pen = QPen(QColor(0, 0, 0, 40))
        for i in range(0, int(self.num_measures) + 1):
            measure = QGraphicsLineItem(0, 0, 0, self.piano_height + self.header_height - measure_pen.width(), self.header)
            measure.setPos(self.measure_width * i, 0.5 * measure_pen.width())
            measure.setPen(measure_pen)
            if i < self.num_measures:
                number = QGraphicsSimpleTextItem('%d' % (i + 1), self.header)
                number.setPos(self.measure_width * i + 5, 2)
                number.setBrush(Qt.white)
                for j in self.frange(0, self.time_sig[0]*self.grid_div/self.time_sig[1], 1.):
                    line = QGraphicsLineItem(0, 0, 0, self.piano_height, self.header)
                    line.setZValue(1.0)
                    line.setPos(self.measure_width * i + self.value_width * j, self.header_height)
                    if j == self.time_sig[0]*self.grid_div/self.time_sig[1] / 2.0:
                        line.setPen(half_measure_pen)
                    else:
                        line.setPen(line_pen)
Exemple #2
0
 def makeCoords(self):
     """ draws Coordinates """
     xLabels = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
     yLabels = list(range(1, 26))
     botGrid = []
     leftGrid = []
     # generate pixel coordinates grids
     for n in range(self.board.size):
         (xBot, yBot) = self.grid[self.board.size-1][n]
         yBot += self.baseWidth*0.4/self.baseRectRatio
         xBot -= self.baseWidth*0.1
         botGrid.append((xBot, yBot))
         (xLeft, yLeft) = self.grid[n][0]
         xLeft -= self.baseWidth*1.2
         yLeft -= self.baseWidth*0.3/self.baseRectRatio
         leftGrid.append((xLeft, yLeft))
     # generate Text items and add them to group
     self.coordGroup = QGraphicsItemGroup()
     for n in range(self.board.size):
         leftText = QGraphicsSimpleTextItem(str(yLabels[n]))
         leftText.setPos(*leftGrid[n])
         self.coordGroup.addToGroup(leftText)
         bottomText = QGraphicsSimpleTextItem(xLabels[n])
         bottomText.setPos(*botGrid[n])
         self.coordGroup.addToGroup(bottomText)
     # draw coordinates and update visibility according to self.showCoords
     self.scene.addItem(self.coordGroup)
     self.updateCoords()
 def _updateLabel(self, isLeft):
     """
     Called by updatePositionAndAppearance during init, or later by
     updateConnectivity. Updates drawing and position of the label.
     """
     lbl = self._label
     if self._idx != None:
         if lbl == None:
             bw = _BASE_WIDTH
             num = self._partner_virtual_helix.number()
             tbr = _FM.tightBoundingRect(str(num))
             half_label_h = tbr.height() / 2.0
             half_label_w = tbr.width() / 2.0
             # determine x and y positions
             labelX = bw / 2.0 - half_label_w
             if self._is_on_top:
                 labelY = -0.25 * half_label_h - 0.5 - 0.5 * bw
             else:
                 labelY = 2 * half_label_h + 0.5 + 0.5 * bw
             # adjust x for left vs right
             labelXoffset = 0.25 * bw if isLeft else -0.25 * bw
             labelX += labelXoffset
             # adjust x for numeral 1
             if num == 1:
                 labelX -= half_label_w / 2.0
             # create text item
             lbl = QGraphicsSimpleTextItem(str(num), self)
             lbl.setPos(labelX, labelY)
             lbl.setBrush(_ENAB_BRUSH)
             lbl.setFont(_toHelixNumFont)
             self._label = lbl
         # end if
         lbl.setText(str(self._partner_virtual_helix.number()))
Exemple #4
0
class BasicNode(QGraphicsItemGroup):
    def __init__(self, model, manager, text_color=Qt.black):
        bg_color = model.get_bg_color()
        super(BasicNode, self).__init__()
        self.model = model
        text = model.get_display_text()
        self.manager = manager
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, True)

        self.text_graph = QGraphicsSimpleTextItem(text)
        self.text_graph.setBrush(text_color)
        bound = self.text_graph.boundingRect()
        r = QPointF(bound.width() / 2, bound.height() / 2)
        text_center = self.text_graph.pos() + r
        self.text_graph.setPos(-text_center)
        self.addToGroup(self.text_graph)

        self.box_graph = BoxOutline(bg_color)
        empty_space = QPointF(UNIT, UNIT)
        newr = (empty_space + r)
        self.box_graph.rect = QRectF(-newr, newr)
        self.addToGroup(self.box_graph)
        self.text_graph.setZValue(1.0)
        self.box_graph.setZValue(0.0)

        self.children = []

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedChange:
            self.manager.selection_changed(self, value)
            return value
        else:
            return super(BasicNode, self).itemChange(change, value)

    def get_width(self):
        return self.boundingRect().width()

    def set_left_pos(self, pos):
        pos += QPoint(self.get_width() / 2.0, 0)
        self.setPos(pos)

    def left_pos(self):
        return self.pos() - QPointF(self.get_width() / 2.0, 0)

    def center_pos(self):
        return self.pos()

    def right_pos(self):
        return self.pos() + QPointF(self.get_width() / 2.0, 0)

    """
Exemple #5
0
class WotNode(BaseNode):
    def __init__(self, nx_node, pos):
        """
        Create node in the graph scene

        :param tuple nx_node: Node info
        :param x_y: Position of the node
        """
        super().__init__(nx_node, pos)

        # color around ellipse
        outline_color = QColor('grey')
        outline_style = Qt.SolidLine
        outline_width = 1
        if self.status_wallet:
            outline_color = QColor('black')
            outline_width = 2
        if not self.status_member:
            outline_color = QColor('red')
            outline_style = Qt.SolidLine
        self.setPen(QPen(outline_color, outline_width, outline_style))

        # text inside ellipse
        self.text_item = QGraphicsSimpleTextItem(self)
        self.text_item.setText(self.text)
        text_color = QColor('grey')
        if self.status_wallet == NodeStatus.HIGHLIGHTED:
            text_color = QColor('black')
        self.text_item.setBrush(QBrush(text_color))
        # center ellipse around text
        self.setRect(
            0,
            0,
            self.text_item.boundingRect().width() * 2,
            self.text_item.boundingRect().height() * 2
        )

        #  set anchor to the center
        self.setTransform(
            QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0))
        # center text in ellipse
        self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0)

        # create gradient inside the ellipse
        gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width())
        gradient.setColorAt(0, QColor('white'))
        gradient.setColorAt(1, QColor('darkgrey'))
        self.setBrush(QBrush(gradient))

        # cursor change on hover
        self.setAcceptHoverEvents(True)
        self.setZValue(1)
Exemple #6
0
    def drawHRefs(self):
        if self.xvmax < self.xvmin or self.awidth <= 0:
            return
        minsep = 30
        factor = 1
        unitincrement = self.awidth/float(self.xvmax-self.xvmin)
        xmaxint = self.xvmax
        vx = int(self.xvmin)
        pstart = self.value2point(vx, self.yvmin)
        px = pstart.x()
        pystart = pstart.y()
        pend = self.value2point(xmaxint, self.yvmin)
        pxend = pend.x()
        pyend = pend.y()-2

        try:
            minsep = 10 * max([len(h) for h in self.hheaders])
        except Exception:
            pass

        while (unitincrement*factor < minsep):
            provfactor = 2*factor
            if(unitincrement*provfactor > minsep):
                factor = provfactor
                break
            provfactor = 5*factor
            if(unitincrement*provfactor > minsep):
                factor = provfactor
                break
            factor = 10*factor

#        px+=unitincrement*factor
#        vx +=factor

        while(px <= pxend):
            colour = QtGui.QColor(0, 0, 0, 255)
            PlotLine(px+0.5, pystart+2, px+0.5, pyend, 1.5, colour, self)
            try:
                header = self.hheaders[vx]
            except IndexError:
                header = vx
            nlabel = QGraphicsSimpleTextItem(
                "{}".format(header), self)
            font = nlabel.font()
            font.setPixelSize(20)
            nlabel.setFont(font)
            nlabelrect = nlabel.boundingRect()
            nlabel.setPos(px + 0.5 - nlabelrect.width()/2, pystart+3)
            px += unitincrement*factor
            vx += factor
 def add_color_scale(self):
     x_init = self.position[0] + self.margin + self.width
     y_init = self.position[1] + self.margin
     square_size = 20
     text_title = QGraphicsSimpleTextItem("clearance")
     text_title.setPos(x_init, y_init - square_size)
     self.addToGroup(text_title)
     for i in range(10):
         x = x_init
         y = y_init + 9 * square_size - i * square_size
         rect = QGraphicsRectItem(x, y, square_size, square_size)
         pen = QPen()
         pen.setWidth(0.01)
         value = (float(i)/9 * (self.vertical_clearance_max - self.vertical_clearance_min)) + self.vertical_clearance_min
         color = self.color_interpolation.get_interpolation_from_value(value)
         brush = QBrush(color)
         rect.setPen(pen)
         rect.setBrush(brush)
         self.addToGroup(rect)
         if i == 0:
             text_start = QGraphicsSimpleTextItem("%.2f m" % float(self.vertical_clearance_min))
             text_start.setPos(x + square_size + 5, y)
             self.addToGroup(text_start)
         if i == 9:
             text_end = QGraphicsSimpleTextItem("%.2f m" % float(self.vertical_clearance_max))
             text_end.setPos(x + square_size + 5, y)
             self.addToGroup(text_end)
         else:
             value = self.vertical_clearance_min + (self.vertical_clearance_max-self.vertical_clearance_min) * i/9
             text = QGraphicsSimpleTextItem("%.2f m" % value)
             text.setPos(x + square_size + 5, y)
             self.addToGroup(text)
        def addRectText(x, w, parent, text="", level=0, tooltip=""):
            deltaH = LEVEL_HEIGHT if level else 0
            r = OutlineRect(0, 0, w, parent.rect().height()-deltaH, parent, title=text)
            r.setPos(x, deltaH)

            txt = QGraphicsSimpleTextItem(text, r)
            f = txt.font()
            f.setPointSize(8)
            fm = QFontMetricsF(f)
            elidedText = fm.elidedText(text, Qt.ElideMiddle, w)
            txt.setFont(f)
            txt.setText(elidedText)
            txt.setPos(r.boundingRect().center() - txt.boundingRect().center())
            txt.setY(0)
            return r
Exemple #9
0
    def drawVRefs(self):
        if self.yvmax < self.yvmin or self.aheight <= 0:
            return
        minsep = 30
        factor = 1
        try:
            unitincrement = self.aheight/float(self.yvmax-self.yvmin)
        except ZeroDivisionError:
            msg = "Division by zero in drawVRefs. Limits are {}-{}"
            print(msg.format(self.yvmin, self.yvmax))

        while (unitincrement*factor < minsep):
            provfactor = 2*factor
            if(unitincrement*provfactor > minsep):
                factor = provfactor
                break
            provfactor = 5*factor
            if(unitincrement*provfactor > minsep):
                factor = provfactor
                break
            factor = 10*factor
        if (self.yvmin <= 0):
            vy = int(self.yvmin/factor)*factor
        else:
            vy = (int(self.yvmin/factor)+1)*factor
        pstart = self.value2point(self.xvmin, vy)
        pxstart = pstart.x()
        py = pstart.y()
        pend = self.value2point(self.xvmax, self.yvmax)
        pxend = pend.x()
        pyend = pend.y()

        while(py > pyend):
            colour = QtGui.QColor(0, 0, 0, 200)
            if vy == 0:
                PlotLine(pxstart-2, py, pxend, py, 1.5, QtCore.Qt.black, self)
            else:
                PlotLine(pxstart-2, py, pxend, py, 0.5, colour, self)
            nlabel = QGraphicsSimpleTextItem("{}".format(vy), self)
            font = nlabel.font()
            font.setPixelSize(20)
            nlabel.setFont(font)
            nlabelrect = nlabel.boundingRect()
            nlabel.setPos(pxstart - nlabelrect.width() -
                          5, py-nlabelrect.height()/2)
            py -= unitincrement*factor
            vy += factor
 def create_material_legend(self, *args):
     self.position = args[0], args[1]
     square_size = 20
     material_list_key = sorted(self.material_dict)
     x_init = self.position[0] + self.left_margin
     y_init = self.position[1] + self.top_margin
     i = 0
     for key in material_list_key:
         scene_y = y_init + i * (square_size + 5)
         material = self.material_dict[key]
         surface_colour = material.get_surface_colour()
         rect = QGraphicsRectItem(x_init, scene_y, square_size, square_size)
         pen = QPen()
         pen.setWidthF(0.5)
         rect.setPen(pen)
         BaseGraphic.set_rect_fill(self.visualization_mode, rect, surface_colour)
         self.graphic_items.append(rect)
         text = QGraphicsSimpleTextItem(key)
         text.setPos(x_init + square_size + 5, scene_y)
         self.graphic_items.append(text)
         i += 1
 def create_scale(self):
     section_num = len(self.section_analyzer.section_list)
     section_distance = self.section_analyzer.section_distance
     total_distance = section_num * section_distance
     div = int(Math.integer_division(total_distance, 1.0))
     print(total_distance)
     for i in range(div+1):
         x = self.graph_zero[0] + i * self.length_multiplier + self.line_extend
         y = self.graph_zero[1]
         scale_text = QGraphicsSimpleTextItem("%.2f" % float(i))
         scale_text.setPos(x, y)
         self.addToGroup(scale_text)
     start_to_zero = self.graph_zero[1] - self.position[1]
     step = abs(start_to_zero) // 25
     x = self.graph_zero[0] - 15
     y = self.graph_zero[1]
     for i in range(int(step)-1):
         if i > 0:
             value = i * 25 / 100
             scene_y = y - i * 25
             text = QGraphicsSimpleTextItem("-%.2f" % value)
             text.setPos(x, scene_y)
             self.addToGroup(text)
     start_to_zero = self.position[1] + self.height - self.graph_zero[1]
     step = abs(start_to_zero) // 25
     x = self.graph_zero[0] - 15
     y = self.graph_zero[1]
     for i in range(int(step)-1):
         if i > 0:
             value = i * 25 / 100
             scene_y = y + i * 25
             text = QGraphicsSimpleTextItem("%.2f" % value)
             text.setPos(x, scene_y)
             self.addToGroup(text)
Exemple #12
0
    def drawPiano(self):
        piano_keys_width = self.piano_width - self.padding
        labels = ('B','Bb','A','Ab','G','Gb','F','E','Eb','D','Db','C')
        black_notes = (2,4,6,9,11)
        piano_label = QFont()
        piano_label.setPointSize(6)
        self.piano = QGraphicsRectItem(0, 0, piano_keys_width, self.piano_height)
        self.piano.setPos(0, self.header_height)
        self.addItem(self.piano)

        key = PianoKeyItem(piano_keys_width, self.note_height, self.piano)
        label = QGraphicsSimpleTextItem('C8', key)
        label.setPos(18, 1)
        label.setFont(piano_label)
        key.setBrush(QColor(255, 255, 255))
        for i in range(self.end_octave - self.start_octave, self.start_octave - self.start_octave, -1):
            for j in range(self.notes_in_octave, 0, -1):
                if j in black_notes:
                    key = PianoKeyItem(piano_keys_width/1.4, self.note_height, self.piano)
                    key.setBrush(QColor(0, 0, 0))
                    key.setZValue(1.0)
                    key.setPos(0, self.note_height * j + self.octave_height * (i - 1))
                elif (j - 1) and (j + 1) in black_notes:
                    key = PianoKeyItem(piano_keys_width, self.note_height * 2, self.piano)
                    key.setBrush(QColor(255, 255, 255))
                    key.setPos(0, self.note_height * j + self.octave_height * (i - 1) - self.note_height/2.)
                elif (j - 1) in black_notes:
                    key = PianoKeyItem(piano_keys_width, self.note_height * 3./2, self.piano)
                    key.setBrush(QColor(255, 255, 255))
                    key.setPos(0, self.note_height * j + self.octave_height * (i - 1) - self.note_height/2.)
                elif (j + 1) in black_notes:
                    key = PianoKeyItem(piano_keys_width, self.note_height * 3./2, self.piano)
                    key.setBrush(QColor(255, 255, 255))
                    key.setPos(0, self.note_height * j + self.octave_height * (i - 1))
                if j == 12:
                    label = QGraphicsSimpleTextItem('{}{}'.format(labels[j - 1], self.end_octave - i), key )
                    label.setPos(18, 6)
                    label.setFont(piano_label)
                self.piano_keys.append(key)
Exemple #13
0
    def init_ui(self):

        scene = QGraphicsScene()
        scene.setBackgroundBrush(QColor(100, 100, 100))
        scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex)

        scene.setSceneRect(scene.itemsBoundingRect())

        self.setDragMode(QGraphicsView.RubberBandDrag)
        self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
        self.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)

        self.frame_item = QGraphicsPixmapItem()

        self.text_item_offset = 0
        self.rect_item_array = []
        self.text_item_array = []
        for i in range(0, 5):
            rect_item = QGraphicsRectItem()
            rect_item.setVisible(False)
            rect_item.setZValue(20.0)
            rect_item.setPen(QPen(Qt.red, 5))
            rect_item.setRect(20, 20, 20, 20)
            scene.addItem(rect_item)
            self.rect_item_array.append(rect_item)
            text_item = QGraphicsSimpleTextItem("")
            text_item.setBrush(QBrush(Qt.red))
            text_item.setZValue(20.0)
            text_item.setPos(10, 50)
            text_item.setFont(QFont("黑体", 24))
            text_item.setVisible(False)
            scene.addItem(text_item)
            self.text_item_array.append(text_item)

        scene.addItem(self.frame_item)

        self.curr_factor = 1.0

        self.setScene(scene)
Exemple #14
0
    def _updateLabel(self, is_left):
        """Called by updatePositionAndAppearance during init.
        Updates drawing and position of the label.

        Args:
            is_left (TYPE): Description
        """
        lbl = self._label
        if self._idx is not None:
            bw = _BASE_WIDTH
            num = self._partner_virtual_helix.idNum()
            tBR = _FM.tightBoundingRect(str(num))
            half_label_h = tBR.height()/2.0
            half_label_w = tBR.width()/2.0
            # determine x and y positions
            label_x = bw/2.0 - half_label_w
            if self._is_on_top:
                label_y = -0.25*half_label_h - 0.5 - 0.5*bw
            else:
                label_y = 2*half_label_h + 0.5 + 0.5*bw
            # adjust x for left vs right
            label_x_offset = 0.25*bw if is_left else -0.25*bw
            label_x += label_x_offset
            # adjust x for numeral 1
            if num == 1:
                label_x -= half_label_w/2.0
            # create text item
            if lbl is None:
                lbl = QGraphicsSimpleTextItem(str(num), self)
            lbl.setPos(label_x, label_y)
            lbl.setBrush(_ENAB_BRUSH)
            lbl.setFont(_TO_HELIX_NUM_FONT)
            self._label = lbl

            lbl.setText(str(self._partner_virtual_helix.idNum()))
            lbl.show()
Exemple #15
0
class DigitalClock(Desklet):

    def __init__(self):
        super().__init__()

        self.seconds = QGraphicsSimpleTextItem(self.root)
        self.time = QGraphicsSimpleTextItem(self.root)
        self.date = QGraphicsSimpleTextItem(self.root)

    def set_style(self, style):
        super().set_style(style)

        self.seconds.setBrush(style.foreground_color)
        self.time.setBrush(style.foreground_color)
        self.date.setBrush(style.foreground_color)

        font = QFont(style.font)
        font.setPixelSize(192 * 0.5)
        self.seconds.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(192 * 0.75)
        self.time.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(56)
        self.date.setFont(font)
        self.layout()

    def set_rect(self, rect):
        super().set_rect(rect)
        self.layout()

    def layout(self):
        time_fm = QFontMetrics(self.time.font())
        seconds_fm = QFontMetrics(self.seconds.font())

        x = self.rect.left()
        y = self.rect.top()

        self.time.setPos(x, y)
        self.seconds.setPos(x + time_fm.width("00:00") + 20,
                            y + time_fm.ascent() - seconds_fm.ascent())
        self.date.setPos(x, y + time_fm.ascent())

    def update(self, now):
        date = now.strftime("%A, %d. %B %Y")
        time = now.strftime("%H:%M")
        seconds = now.strftime("%S")

        self.time.setText(time)
        self.seconds.setText(seconds)
        self.date.setText(date)
 def add_title(self):
     if self.label:
         title = QGraphicsSimpleTextItem(self.label)
         title.setPos(self.position[0] + self.margin, self.position[1] + self.line_extend)
         self.addToGroup(title)
Exemple #17
0
class SocketRow(QGraphicsWidget):

    def __init__(self, qt_node, pin):
        super(SocketRow, self).__init__()

        assert qt_node is not None
        self.setParentItem(qt_node)
        self._parent_node = weakref.ref(qt_node)
        self._pin = pin
        self._spacerConstant = 5.0
        self._label = QGraphicsSimpleTextItem(self)

        self._socket = None
        self._outputHook = None

        socket_colour = QColor(*pin.colour)
        socket_type = pin.shape

        if pin.io_type == "input":
            self._socket = QtSocket(self, "input", socket_type)
            self._socket.setColor(socket_colour)

        else:
            self._socket = QtSocket(self, "output", socket_type)
            self._socket.setColor(socket_colour)

        self.setLabelColor(self.defaultColor())
        self.setLabelText(self._pin.name)

        self._socket.setVisible(True)

    def parentNode(self):
        return self._parent_node()

    def pin(self):
        return self._pin

    def socket(self):
        return self._socket

    def defaultColor(self):
        return self._parent_node().labelColor()

    def labelColor(self):
        return self._label.brush().color()

    def setLabelColor(self, color):
        self._label.setBrush(color)

    def labelText(self):
        return self._label.text()

    def setLabelText(self, text):
        self._label.setText(text)

    def refresh(self):
        # Update cosmetics
        colour = QColor(*self._pin.colour)
        self._socket.setColor(colour)
        self._socket.setShape(self._pin.shape)
        self._socket.update()

    def updateLayout(self):
        height = self._label.boundingRect().height()
        hook = self._socket

        if hook.mode() == "output":
            hook_y_pos = (height - hook.boundingRect().height()) / 2.0

        else:
            hook_y_pos = (height - hook.boundingRect().height()) / 2.0
            hook.setPos(0.0, hook_y_pos)

        input_width = self._spacerConstant * 2.0
        self._label.setPos(input_width + self._spacerConstant, 0)

        if hook.mode() == "output":
            hook.setPos(self._label.pos().x() + self._label.boundingRect().width() + self._spacerConstant,
                        hook_y_pos)

            self.resize(hook.pos().x() + hook.boundingRect().width(), height)

        else:
            self.resize(self._label.pos().x() + self._label.boundingRect().width(), height)

    def onDeleted(self):
        if self._socket:
            self._socket.onDeleted()
Exemple #18
0
class ExplorerNode(BaseNode):
    def __init__(self, nx_node, center_pos, nx_pos, steps, steps_max):
        """
        Create node in the graph scene

        :param tuple nx_node: Node info
        :param center_pos: The position of the center node
        :param nx_pos: Position of the nodes in the graph
        :param int steps: The steps from the center identity
        :param int steps_max: The steps max of the graph
        """
        super().__init__(nx_node, nx_pos)

        self.steps = steps
        self.steps_max = steps_max
        self.highlighted = False

        # text inside ellipse
        self.text_item = QGraphicsSimpleTextItem(self)
        self.text_item.setText(self.text)
        # center ellipse around text
        self.setRect(
            0,
            0,
            self.text_item.boundingRect().width() * 2,
            self.text_item.boundingRect().height() * 2
        )

        #  set anchor to the center
        self.setTransform(
            QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0))
        # center text in ellipse
        self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0)

        # cursor change on hover
        self.setAcceptHoverEvents(True)
        self.setZValue(1)

        # animation and moves
        self.timeline = None
        self.loading_timer = QTimer()
        self.loading_timer.timeout.connect(self.next_tick)
        self.loading_counter = 0
        self._refresh_colors()
        self.setPos(center_pos)
        self.move_to(nx_pos)

    def _refresh_colors(self):
        """
        Refresh elements in the node
        """
        # color around ellipse
        outline_color = QColor('black')
        outline_style = Qt.SolidLine
        outline_width = 1
        if self.status_wallet:
            outline_color = QColor('grey')
            outline_width = 2
        if not self.status_member:
            outline_color = QColor('red')
            outline_style = Qt.SolidLine
        self.setPen(QPen(outline_color, outline_width, outline_style))

        if self.highlighted:
            text_color = QColor('grey')
        else:
            text_color = QColor('black')

        if self.status_wallet == NodeStatus.HIGHLIGHTED:
            text_color = QColor('grey')
        self.text_item.setBrush(QBrush(text_color))

        # create gradient inside the ellipse
        gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width())
        color = QColor()
        color.setHsv(120 - 60 / self.steps_max * self.steps,
                     180 + 50 / self.steps_max * self.steps,
                     60 + 170 / self.steps_max * self.steps)
        if self.highlighted:
            color = color.darker(200)
        color = color.lighter(math.fabs(math.sin(self.loading_counter / 100 * math.pi) * 100) + 100)
        gradient.setColorAt(0, color)
        gradient.setColorAt(1, color.darker(150))
        self.setBrush(QBrush(gradient))

    def move_to(self, nx_pos):
        """
        Move to corresponding position
        :param nx_pos:
        :return:
        """
        origin_x = self.x()
        origin_y = self.y()
        final_x = nx_pos[self.id][0]
        final_y = nx_pos[self.id][1]

        def frame_move(frame):
            value = self.timeline.valueForTime(self.timeline.currentTime())
            x = origin_x + (final_x - origin_x) * value
            y = origin_y + (final_y - origin_y) * value
            self.setPos(x, y)
            self.scene().node_moved.emit(self.id, x, y)

        def timeline_ends():
            self.setPos(final_x, final_y)
            self.timeline = None

        # Remember to hold the references to QTimeLine and QGraphicsItemAnimation instances.
        # They are not kept anywhere, even if you invoke QTimeLine.start().
        self.timeline = QTimeLine(1000)
        self.timeline.setFrameRange(0, 100)
        self.timeline.frameChanged.connect(frame_move)
        self.timeline.finished.connect(timeline_ends)

        self.timeline.start()

    def highlight(self):
        """
        Highlight the edge in the scene
        """
        self.highlighted = True
        self._refresh_colors()
        self.update(self.boundingRect())

    def neutralize(self):
        """
        Neutralize the edge in the scene
        """
        self.highlighted = False
        self._refresh_colors()
        self.update(self.boundingRect())

    def start_loading_animation(self):
        """
        Neutralize the edge in the scene
        """
        if not self.loading_timer.isActive():
            self.loading_timer.start(10)

    def stop_loading_animation(self):
        """
        Neutralize the edge in the scene
        """
        self.loading_timer.stop()
        self.loading_counter = 100
        self._refresh_colors()
        self.update(self.boundingRect())

    def next_tick(self):
        """
        Next tick
        :return:
        """
        self.loading_counter += 1
        self.loading_counter %= 100
        self._refresh_colors()
        self.update(self.boundingRect())
Exemple #19
0
class StopWatch(Desklet):

    def __init__(self):
        super().__init__()

        self.timer = Timer()
        self.timeout_handle = None

        self.qtimer = QTimer()
        self.qtimer.timeout.connect(self.my_update)

        self.label = QGraphicsSimpleTextItem("Stopwatch:", self.root)
        self.time = QGraphicsSimpleTextItem("00:00", self.root)
        self.seconds = QGraphicsSimpleTextItem("00'00", self.root)

    def update(self):
        t = self.timer.get_time()
        time = "%02d:%02d" % (t.seconds / (60 * 60), (t.seconds % (60 * 60)) / 60)
        seconds = "%02d'%02d" % (t.seconds % 60, t.microseconds / 10000)

        self.time.setText(time)
        self.seconds.setText(seconds)

    def set_style(self, style):
        super().set_style(style)

        font = QFont(style.font)
        font.setPixelSize(24)
        self.time.setFont(font)
        self.label.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(192 / 2)
        self.time.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(192 / 2 * 0.6)
        self.seconds.setFont(font)

        self.label.setBrush(self.style.foreground_color)
        self.time.setBrush(self.style.foreground_color)
        self.seconds.setBrush(self.style.foreground_color)

        self.layout()

    def set_rect(self, rect):
        super().set_rect(rect)
        self.layout()

    def layout(self):
        x = self.rect.left()
        y = self.rect.top()

        fm = QFontMetrics(self.time.font())
        rect = fm.boundingRect("00:00")

        sfm = QFontMetrics(self.seconds.font())

        self.time.setPos(x, y + 20)
        self.seconds.setPos(x + 20 + rect.width(), y + 20 + fm.ascent() - sfm.ascent())

        self.label.setPos(x, y)

    def my_update(self):
        self.update()

    def is_running(self):
        return self.timer.is_running()

    def start_stop_watch(self):
        self.timer.start_stop()

        if self.timer.is_running():
            self.qtimer.setInterval(31)
            self.qtimer.start()
        else:
            self.qtimer.stop()

    def clear_stop_watch(self):
        self.timer.reset()
    def refresh(self):
        if not self._mdlPlots or not self._mdlOutline or not self._mdlPersos:
            pass

        LINE_HEIGHT = 18
        SPACING = 3
        TEXT_WIDTH = self.sldTxtSize.value()
        CIRCLE_WIDTH = 10
        LEVEL_HEIGHT = 12

        s = self.scene
        s.clear()

        # Get Max Level (max depth)
        root = self._mdlOutline.rootItem
        def maxLevel(item, level=0, max=0):
            if level > max:
                max = level
            for c in item.children():
                m = maxLevel(c, level + 1)
                if m > max:
                    max = m
            return max

        MAX_LEVEL = maxLevel(root)

        # Generate left entries
        # (As of now, plot only)
        plotsID = self._mdlPlots.getPlotsByImportance()
        trackedItems = []
        fm = QFontMetrics(s.font())
        max_name = 0

        for importance in plotsID:
            for ID in importance:
                name = self._mdlPlots.getPlotNameByID(ID)
                ref = references.plotReference(ID, searchable=True)

                trackedItems.append((ID, ref, name))
                max_name = max(fm.width(name), max_name)

        ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING )
        TITLE_WIDTH = max_name + 2 * SPACING


        # Add Folders and Texts
        outline = OutlineRect(0, 0, 0, ROWS_HEIGHT + SPACING + MAX_LEVEL * LEVEL_HEIGHT)
        s.addItem(outline)
        outline.setPos(TITLE_WIDTH + SPACING, 0)

        refCircles = [] # a list of all references, to be added later on the lines

        # A Function to add a rect with centered elided text
        def addRectText(x, w, parent, text="", level=0, tooltip=""):
            deltaH = LEVEL_HEIGHT if level else 0
            r = OutlineRect(0, 0, w, parent.rect().height()-deltaH, parent, title=text)
            r.setPos(x, deltaH)

            txt = QGraphicsSimpleTextItem(text, r)
            f = txt.font()
            f.setPointSize(8)
            fm = QFontMetricsF(f)
            elidedText = fm.elidedText(text, Qt.ElideMiddle, w)
            txt.setFont(f)
            txt.setText(elidedText)
            txt.setPos(r.boundingRect().center() - txt.boundingRect().center())
            txt.setY(0)
            return r

        # A function to returns an item's width, by counting its children
        def itemWidth(item):
            if item.isFolder():
                r = 0
                for c in item.children():
                    r += itemWidth(c)
                return r or TEXT_WIDTH
            else:
                return TEXT_WIDTH

        def listItems(item, rect, level=0):
            delta = 0
            for child in item.children():
                w = itemWidth(child)

                if child.isFolder():
                    parent = addRectText(delta, w, rect, child.title(), level, tooltip=child.title())
                    parent.setToolTip(references.tooltip(references.textReference(child.ID())))
                    listItems(child, parent, level + 1)

                else:
                    rectChild = addRectText(delta, TEXT_WIDTH, rect, "", level, tooltip=child.title())
                    rectChild.setToolTip(references.tooltip(references.textReference(child.ID())))
                    
                    # Find tracked references in that scene (or parent folders)
                    for ID, ref, name in trackedItems:

                        result = []
                        c = child
                        while c:
                            result += references.findReferencesTo(ref, c, recursive=False)
                            c = c.parent()

                        if result:
                            ref2 = result[0]
                            
                            # Create a RefCircle with the reference
                            c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2)
                            
                            # Store it, with the position of that item, to display it on the line later on
                            refCircles.append((ref, c, rect.mapToItem(outline, rectChild.pos())))

                delta += w

        listItems(root, outline)

        OUTLINE_WIDTH = itemWidth(root)

        # Add Plots
        i = 0
        itemsRect = s.addRect(0, 0, 0, 0)
        itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING)

        for ID, ref, name in trackedItems:
            color = randomColor()

            # Rect
            r = QGraphicsRectItem(0, 0, TITLE_WIDTH, LINE_HEIGHT, itemsRect)
            r.setPen(QPen(Qt.NoPen))
            r.setBrush(QBrush(color))
            r.setPos(0, i * LINE_HEIGHT + i * SPACING)
            i += 1

            # Text
            txt = QGraphicsSimpleTextItem(name, r)
            txt.setPos(r.boundingRect().center() - txt.boundingRect().center())

            # Line
            line = PlotLine(0, 0,
                            OUTLINE_WIDTH + SPACING, 0)
            line.setPos(TITLE_WIDTH, r.mapToScene(r.rect().center()).y())
            s.addItem(line)
            line.setPen(QPen(color, 5))
            line.setToolTip(self.tr("Plot: ") + name)

            # We add the circles / references to text, on the line
            for ref2, circle, pos in refCircles:
                if ref2 == ref:
                    circle.setParentItem(line)
                    circle.setPos(pos.x(), 0)

        # self.view.fitInView(0, 0, TOTAL_WIDTH, i * LINE_HEIGHT, Qt.KeepAspectRatioByExpanding) # KeepAspectRatio
        self.view.setSceneRect(0, 0, 0, 0)
Exemple #21
0
class ModuleItem(UMLItem):
    """
    Class implementing a module item.
    """
    ItemType = "module"
    
    def __init__(self, model=None, x=0, y=0, rounded=False,
                 parent=None, scene=None):
        """
        Constructor
        
        @param model module model containing the module data (ModuleModel)
        @param x x-coordinate (integer)
        @param y y-coordinate (integer)
        @keyparam rounded flag indicating a rounded corner (boolean)
        @keyparam parent reference to the parent object (QGraphicsItem)
        @keyparam scene reference to the scene object (QGraphicsScene)
        """
        UMLItem.__init__(self, model, x, y, rounded, parent)
        
        scene.addItem(self)
        
        if self.model:
            self.__createTexts()
            self.__calculateSize()
        
    def __createTexts(self):
        """
        Private method to create the text items of the module item.
        """
        if self.model is None:
            return
        
        boldFont = QFont(self.font)
        boldFont.setBold(True)
        
        classes = self.model.getClasses()
        
        x = self.margin + self.rect().x()
        y = self.margin + self.rect().y()
        self.header = QGraphicsSimpleTextItem(self)
        self.header.setFont(boldFont)
        self.header.setText(self.model.getName())
        self.header.setPos(x, y)
        y += self.header.boundingRect().height() + self.margin
        if classes:
            txt = "\n".join(classes)
        else:
            txt = " "
        self.classes = QGraphicsSimpleTextItem(self)
        self.classes.setFont(self.font)
        self.classes.setText(txt)
        self.classes.setPos(x, y)
        
    def __calculateSize(self):
        """
        Private method to calculate the size of the module item.
        """
        if self.model is None:
            return
        
        width = self.header.boundingRect().width()
        height = self.header.boundingRect().height()
        if self.classes:
            width = max(width, self.classes.boundingRect().width())
            height = height + self.classes.boundingRect().height()
        self.setSize(width + 2 * self.margin, height + 2 * self.margin)
    
    def setModel(self, model):
        """
        Public method to set the module model.
        
        @param model module model containing the module data (ModuleModel)
        """
        self.scene().removeItem(self.header)
        self.header = None
        if self.classes:
            self.scene().removeItem(self.classes)
            self.meths = None
        self.model = model
        self.__createTexts()
        self.__calculateSize()
        
    def paint(self, painter, option, widget=None):
        """
        Public method to paint the item in local coordinates.
        
        @param painter reference to the painter object (QPainter)
        @param option style options (QStyleOptionGraphicsItem)
        @param widget optional reference to the widget painted on (QWidget)
        """
        pen = self.pen()
        if (option.state & QStyle.State_Selected) == \
                QStyle.State(QStyle.State_Selected):
            pen.setWidth(2)
        else:
            pen.setWidth(1)
        
        painter.setPen(pen)
        painter.setBrush(self.brush())
        painter.setFont(self.font)
        
        offsetX = self.rect().x()
        offsetY = self.rect().y()
        w = self.rect().width()
        h = self.rect().height()
        
        painter.drawRect(offsetX, offsetY, w, h)
        y = self.margin + self.header.boundingRect().height()
        painter.drawLine(offsetX, offsetY + y, offsetX + w - 1, offsetY + y)
        
        self.adjustAssociations()
    
    def buildItemDataString(self):
        """
        Public method to build a string to persist the specific item data.
        
        This string must start with ", " and should be built like
        "attribute=value" with pairs separated by ", ". value must not
        contain ", " or newlines.
        
        @return persistence data (string)
        """
        entries = [
            "name={0}".format(self.model.getName()),
        ]
        classes = self.model.getClasses()
        if classes:
            entries.append("classes={0}".format("||".join(classes)))
        
        return ", " + ", ".join(entries)
    
    def parseItemDataString(self, version, data):
        """
        Public method to parse the given persistence data.
        
        @param version version of the data (string)
        @param data persisted data to be parsed (string)
        @return flag indicating success (boolean)
        """
        parts = data.split(", ")
        if len(parts) < 1:
            return False
        
        name = ""
        classes = []
        
        for part in parts:
            key, value = part.split("=", 1)
            if key == "name":
                name = value.strip()
            elif key == "classes":
                classes = value.strip().split("||")
            else:
                return False
        
        self.model = ModuleModel(name, classes)
        self.__createTexts()
        self.__calculateSize()
        
        return True
Exemple #22
0
class QtNode(QGraphicsWidget):

    def __init__(self, node, view):
        super(QtNode, self).__init__()

        self._spacingConstant = 5.0
        self._roundness = 3

        self._labelColor = QColor(255, 255, 255)
        self._label = QGraphicsSimpleTextItem(self)
        self._label.setBrush(self._labelColor)
        self._label.setText(node.name)

        self._selectedColor = QColor(255, 255, 255)
        self._shapePen = QPen(Qt.NoPen)
        self._shapePen.setColor(self._selectedColor)
        self._shapePen.setWidthF(1.5)

        self._brush = QBrush(QColor(*COLOUR_THEMES[node.node_type]))

        self._dropShadowEffect = QGraphicsDropShadowEffect()
        self.setGraphicsEffect(self._dropShadowEffect)

        self._dropShadowEffect.setOffset(0.0, 10.0)
        self._dropShadowEffect.setBlurRadius(8.0)
        self._dropShadowEffect.setColor(QColor(0, 0, 0, 50))

        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.setAcceptHoverEvents(True)

        self.setToolTip(node.tooltip)

        self._name = node.name
        self._node = node
        self._view = weakref.ref(view)

        self._busy = False
        self._socketRows = OrderedDict()

        # Build IO pin socket rows
        for pin_name in node.pin_order:
            if pin_name in node.inputs:
                pin = node.inputs[pin_name]

            else:
                pin = node.outputs[pin_name]

            socket_row = SocketRow(self, pin)
            self._socketRows[pin_name] = socket_row

        self.updateLayout()

    def node(self):
        return self._node

    def view(self):
        return self._view()

    def name(self):
        return self._name

    def setName(self, name):
        self._name = name
        self._label.setText(name)
        self.updateLayout()

    def labelColor(self):
        return self._labelColor

    def onDeleted(self):
        if self.isSelected():
            self.setSelected(False)

        for socket_row in self._socketRows.values():
            socket_row.onDeleted()

        self._socketRows.clear()

    def hoverEnterEvent(self, event):
        self.view().guiOnHoverEnter(self)

    def hoverLeaveEvent(self, event):
        self.view().guiOnHoverExit(self)

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionHasChanged:
            for socket_row in self._socketRows.values():
                socket_row.socket().updateConnectionPositions()

            # Move node
            if not self._busy:
                self._busy = True

                self.view().guiOnMoved(self)
                self._busy = False

        elif change == QGraphicsItem.ItemSelectedHasChanged:
            self.onSelected()

        return QGraphicsItem.itemChange(self, change, value)

    def contextMenuEvent(self, event):
        self.view().guiOnNodeRightClick(self, event)

    def onSelected(self):
        if self.isSelected():
            self._shapePen.setStyle(Qt.SolidLine)
            self.view().guiOnNodeSelected(self)

        else:
            self._shapePen.setStyle(Qt.NoPen)
            self.view().guiOnNodeDeselected(self)

    def paint(self, painter, option, widget):
        shape = QPainterPath()
        shape.addRoundedRect(self.rect(), self._roundness, self._roundness)

        painter.setPen(self._shapePen)
        painter.setBrush(self._brush)
        painter.drawPath(shape)

    def setPos(self, *pos):
        if len(pos) == 1:
            point = QPointF(pos[0])

        else:
            point = QPointF(*pos)

        self._lastPos = point

        QGraphicsWidget.setPos(self, point)

    def mouseDoubleClickEvent(self, event):
        pass

    def mousePressEvent(self, event):
        if event.button() == Qt.RightButton:
            pass

        else:
            QGraphicsWidget.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        self.view().guiOnFinishedMove()

        QGraphicsWidget.mouseReleaseEvent(self, event)

    def mouseMoveEvent(self, event):
        QGraphicsWidget.mouseMoveEvent(self, event)

    def dragMoveEvent(self, *args, **kwargs):
        pass

    def getSocketRow(self, name):
        return self._socketRows[name]

    def refreshSocketRows(self):
        for socket_row in self._socketRows.values():
            socket_row.refresh()

    def updateLayout(self):
        label_width = self._label.boundingRect().width()
        width = label_width
        y_pos = self._label.boundingRect().bottom() + self._spacingConstant

        for socket_row in self._socketRows.values():
            if socket_row.isVisible():
                socket_row.updateLayout()

                socket_row.setPos(self._spacingConstant, y_pos)
                height = socket_row.boundingRect().height()

                y_pos += height

                attributeWidth = socket_row.boundingRect().width()
                if attributeWidth > width:
                    width = attributeWidth

        for socket_row in self._socketRows.values():
            if socket_row.isVisible():
                hook = socket_row.socket()
                if hook.isOutput():
                    hook.setPos(width - hook.boundingRect().width(), hook.pos().y())

        width = self._spacingConstant + width + self._spacingConstant
        self._label.setPos((width - label_width) / 2.0, self._spacingConstant)

        self.resize(width, y_pos + self._spacingConstant)
        self.update()
Exemple #23
0
class Tile(Pixmap):
    """ Tile class defines on screen tiles """

    anim_complete = pyqtSignal()  # Signal for completion of animation
    sheet = None  # Sprite sheet

    def __init__(self, letter, scene, letfile=r"\scrabble_letters.png"):

        self.alphabet = scene.alphabet
        if type(self).sheet is None:
            type(self).sheet = QPixmap(self.alphabet.lang + letfile)

        # Extract letter tile from sheet, scale to cell size for board
        image = type(self).sheet.copy(self.alphabet.TILE_POSITIONS[letter][0],
                                      self.alphabet.TILE_POSITIONS[letter][1],
                                      Cons.TILE_WIDTH, Cons.TILE_HEIGHT)
        image = image.scaled(Cons.WIDTH, Cons.HEIGHT, Qt.IgnoreAspectRatio,
                             Qt.SmoothTransformation)
        super(Tile, self).__init__(image)

        type(self).sheet = None
        self.letter = letter
        self.blank_letter = None
        self.rack_pos = QPointF()
        self.pos = QPointF()
        self.txt = None
        self.scene = scene
        self.alphabet = self.scene.alphabet

        self.pixmap_item.setFlags(QGraphicsItem.ItemIsSelectable
                                  | QGraphicsItem.ItemIsMovable)
        self.pixmap_item.setTransform(QTransform())
        self.pixmap_item.setAcceptedMouseButtons(Qt.LeftButton)
        self.pixmap_item.setZValue(1000)
        self.pixmap_item.letter = letter
        self.pixmap_item.tile = self
        self.pixmap_item.hide()
        # self.add_to_scene(self.scene)
        self.scene.addItem(self.pixmap_item)
        self.pos = QPointF(0, 0)
        self.animation = None
        self.fade = None

    # Draw at position (QPoint) on screen
    def draw_tile(self, position):
        """ Extract letter tile from sheet, scale to cell size for board
            draw at (xpos, ypos) """
        self.pos = position
        self.pixmap_item.show()

    def get_pos(self):
        """ Return position of tile """
        return self.pixmap_item.pos()

    def set_pos(self, x, y):
        """ Move tile to position (x, y) """
        self.pixmap_item.setPos(x, y)

    def hand_cursor(self):
        """ Change cursor to hand cursor """
        self.pixmap_item.setCursor(Qt.PointingHandCursor)

    def reset_cursor(self):
        """ Change cursor to pointer cursor """
        self.pixmap_item.setCursor(Qt.ArrowCursor)

    def move_tile(self, dur, *args):
        """ Create move tile animation
            *args are time fraction, points in path either as
            (time, QPointF) or (time, x, y) """
        if not self.pixmap_item.isVisible():
            self.pixmap_item.setPos(
                QPointF(Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2,
                        Cons.WINDOW_SIZE[1]))
            self.pixmap_item.show()
        animation = QPropertyAnimation(self, b'pos')
        animation.setDuration(dur)
        for val in args:
            if isinstance(val[1], QPointF):
                point = val[1]
            else:
                point = QPointF(val[1], val[2])
            animation.setKeyValueAt(val[0], point)
        self.animation = animation
        return self.animation

    def activate(self, activate):
        """ Accept mouse presses if activate is True """
        if activate:
            self.pixmap_item.setAcceptedMouseButtons(Qt.LeftButton)
        else:
            self.pixmap_item.setAcceptedMouseButtons(Qt.NoButton)

    def dim(self, activate):
        """ Dim tile if activate is True """
        if activate:
            self.pixmap_item.setOpacity(0.4)
        else:
            self.pixmap_item.setOpacity(1)

    def set_in_board(self):
        """ Set tile in board
            No longer moveable """
        self.pixmap_item.setAcceptedMouseButtons(Qt.NoButton)

    def add_letter(self, letter):
        """ Add small letter to blank tile """

        self.txt = QGraphicsSimpleTextItem(letter, self.pixmap_item)
        self.txt.setFont(QFont("Arial", 14, QFont.DemiBold))
        self.txt.setBrush(QBrush(Qt.darkRed))
        wd, ht = self.txt.boundingRect().width(), self.txt.boundingRect(
        ).height()
        self.txt.setPos((Cons.WIDTH - wd) / 2, (Cons.HEIGHT - ht) / 2)

    def get_tile(self):
        """ Move tile from store (bottom centre) to position on rack
            Used in Group Animation """
        return self.move_tile(
            1000,
            (0, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1]),
            (0.2, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, self.rack_pos.y()),
            (1, self.rack_pos))

    def return_tile(self):
        """ Return tile to rack
            Used in Group Animation """
        return self.move_tile(400, (0, self.get_pos()), (1, self.rack_pos))

    def remove_tile(self):
        """ Remove tile from board
            Used in Group Animation """
        return self.move_tile(
            1000, (0, self.get_pos()),
            (0.8, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2,
             self.get_pos().y()),
            (1, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1]))

    def lift_tile(self):
        """ Used in exchange tiles
            Lift chosen tile to set position above rack """
        self.animation = self.move_tile(
            100, (0, self.rack_pos),
            (1, self.rack_pos + QPointF(0, Cons.TILE_LIFT)))
        self.animation.start()

    def drop_tile(self):
        """ Used in exchange tiles
            Drop chosen tile back into rack """
        self.animation = self.move_tile(100, (0, self.get_pos()),
                                        (1, self.rack_pos))
        self.animation.start()

    def name_tile(self, player):
        """ Used in names screen
            Move chosen blank tiles to required position """
        point = QPointF(
            Cons.INPUT_NAMES[player][0] + Cons.INPUT_NAMES[player][2],
            Cons.INPUT_NAMES[player][1] + 50)
        self.animation = self.move_tile(100, (0, self.get_pos()), (1, point))
        self.animation.start()

    def return_blank(self):
        """ Used in names screen
            Return tile to position on board """
        self.animation = self.move_tile(400, (0, self.get_pos()),
                                        (1, self.rack_pos))
        self.animation.start()

    def unfade(self):
        """ Fade in letter on blank tile """
        self.fade = QPropertyAnimation(self, b'opacity')
        self.fade.setDuration(2000)
        self.fade.setStartValue(0)
        self.fade.setEndValue(1)
        self.fade.setEasingCurve(QEasingCurve.InOutSine)
        self.fade.finished.connect(self._fade_end)
        self.fade.start()

    def _fade_end(self):
        """ end of animation """
        self.anim_complete.emit()

    def hide(self):
        """ Hide tile """
        self.pixmap_item.hide()

    def setZValue(self, val):
        """ set ZValue for image """
        self.pixmap_item.setZValue(val)
    def print_side_view(self):
        """
        draw vessel, usbl and vessel reference point on a side_graphicsView
         
        """

        # clear previous scene
        self.side_scene.clear()
        self.side_graphicsView.viewport().update()

        # get vessel spinbox values
        v_length = self.vessel_length_doubleSpinBox.value()
        v_height = v_length / 3

        vrp_x_on_vessel = self.vrp_x_offset_doubleSpinBox.value()

        if util.find_spec('usblcontroller') is not None:
            usbl_x_on_vessel = self.usbl_x_offset_doubleSpinBox.value()
            usbl_z_on_vessel = self.usbl_z_offset_doubleSpinBox.value()
        else:
            usbl_x_on_vessel = 0
            usbl_z_on_vessel = 0

        # get width and height from view
        w_max = self.side_graphicsView.width()
        h_max = self.side_graphicsView.height()

        # set max
        if v_height > v_length:
            max_pix = v_height
        else:
            max_pix = v_length

        # set pixel ratio
        if w_max < h_max:
            pix_ratio = (w_max - 20) / max_pix
        else:
            pix_ratio = (h_max - 20) / max_pix

        # set the size of the vessel
        vessel = QPolygonF([
            QPointF(0, 0),
            QPointF(pix_ratio * v_length, 0),
            QPointF(pix_ratio * v_length * 3 / 4, pix_ratio * v_height),
            QPointF(0, pix_ratio * v_height)
        ])
        self.item = QGraphicsPolygonItem(vessel)
        # set brown color
        self.item.setBrush(QColor(210, 180, 140))

        x_origin_scene = (pix_ratio * v_length / 2)
        y_origin_scene = (pix_ratio * v_height / 2)

        # coordinate system
        line_x_coord = QGraphicsLineItem(
            x_origin_scene, y_origin_scene, pix_ratio * v_length -
            (pix_ratio * v_length - pix_ratio * v_length * 3 / 4) / 2,
            y_origin_scene)
        line_z_coord = QGraphicsLineItem(x_origin_scene, y_origin_scene,
                                         x_origin_scene, pix_ratio * v_height)
        x_label = QGraphicsSimpleTextItem("X", line_x_coord)
        x_label.setPos(
            pix_ratio * v_length -
            (pix_ratio * v_length - pix_ratio * v_length * 3 / 4) / 2 - 30,
            y_origin_scene)
        z_label = QGraphicsSimpleTextItem("Z", line_z_coord)
        z_label.setPos(x_origin_scene - 20, pix_ratio * v_height - 20)

        # set sea background
        sea_polygon = QPolygonF([
            QPointF(-w_max, y_origin_scene),
            QPointF(w_max, y_origin_scene),
            QPointF(x_origin_scene + w_max,
                    h_max + usbl_z_on_vessel * pix_ratio),
            QPointF(-w_max, h_max + usbl_z_on_vessel * pix_ratio)
        ])
        sea = QGraphicsPolygonItem(sea_polygon)
        sea.setBrush(QColor(204, 229, 255))

        x_origin_scene += vrp_x_on_vessel * pix_ratio

        # draw origin point
        origin = QGraphicsEllipseItem(x_origin_scene - 10, y_origin_scene - 10,
                                      20, 20)
        origin.setBrush(Qt.white)
        line_one_origin = QGraphicsLineItem(x_origin_scene - 10,
                                            y_origin_scene,
                                            x_origin_scene + 10,
                                            y_origin_scene)
        line_two_origin = QGraphicsLineItem(x_origin_scene,
                                            y_origin_scene - 10,
                                            x_origin_scene,
                                            y_origin_scene + 10)

        if util.find_spec('usblcontroller') is not None:
            # usbl position
            usbl_circle = QGraphicsEllipseItem(
                x_origin_scene - 10 + usbl_x_on_vessel * pix_ratio,
                y_origin_scene - 10 + usbl_z_on_vessel * pix_ratio, 20, 20)
            usbl_circle.setBrush(QColor(255, 99, 71))

            line_one_usbl = QGraphicsLineItem(
                x_origin_scene - 10 + usbl_x_on_vessel * pix_ratio,
                y_origin_scene + usbl_z_on_vessel * pix_ratio,
                x_origin_scene + 10 + usbl_x_on_vessel * pix_ratio,
                y_origin_scene + usbl_z_on_vessel * pix_ratio)
            line_two_usbl = QGraphicsLineItem(
                x_origin_scene + usbl_x_on_vessel * pix_ratio,
                y_origin_scene - 10 + usbl_z_on_vessel * pix_ratio,
                x_origin_scene + usbl_x_on_vessel * pix_ratio,
                y_origin_scene + 10 + usbl_z_on_vessel * pix_ratio)

            # define labels

            usbl_label = QGraphicsSimpleTextItem("USBL", usbl_circle)
            usbl_label.setPos(
                x_origin_scene - 10 + usbl_x_on_vessel * pix_ratio,
                y_origin_scene + 10 + usbl_z_on_vessel * pix_ratio)

        origin_label = QGraphicsSimpleTextItem("VRP", origin)
        if usbl_x_on_vessel == 0 and usbl_z_on_vessel == 0:
            origin_label.setPos(x_origin_scene + 10, y_origin_scene - 10)
        else:
            origin_label.setPos(x_origin_scene - 10, y_origin_scene + 10)

        # fit view/scene
        self.side_scene.setSceneRect(
            0, 0, pix_ratio * v_length,
            pix_ratio * v_height + usbl_z_on_vessel * pix_ratio)

        self.side_graphicsView.scene().addItem(sea)

        # add vessel to the scene
        self.side_graphicsView.scene().addItem(self.item)
        # add origin to the scene
        self.side_graphicsView.scene().addItem(origin)
        self.side_graphicsView.scene().addItem(line_one_origin)
        self.side_graphicsView.scene().addItem(line_two_origin)

        if util.find_spec('usblcontroller') is not None:
            # add usbl
            self.side_graphicsView.scene().addItem(usbl_circle)
            self.side_graphicsView.scene().addItem(line_one_usbl)
            self.side_graphicsView.scene().addItem(line_two_usbl)

        # add coord system
        self.side_graphicsView.scene().addItem(line_x_coord)
        self.side_graphicsView.scene().addItem(line_z_coord)

        # set background
        self.side_scene.setBackgroundBrush(Qt.white)

        # set antialiasing renderhint
        self.side_graphicsView.setRenderHint(QPainter.Antialiasing)
    def print_top_view(self):
        """
        draw draw vessel, gps, usbl and vessel reference point on a top_graphicsView
         
        """
        # clear previous scene
        self.top_scene.clear()
        self.top_graphicsView.viewport().update()

        # get vessel spinbox values
        v_width = self.vessel_width_doubleSpinBox.value()
        v_length = self.vessel_length_doubleSpinBox.value()
        vrp_x_on_vessel = self.vrp_x_offset_doubleSpinBox.value()
        vrp_y_on_vessel = self.vrp_y_offset_doubleSpinBox.value()
        gps_x_on_vessel = self.gps_x_offset_doubleSpinBox.value()
        gps_y_on_vessel = self.gps_y_offset_doubleSpinBox.value()

        if util.find_spec('usblcontroller') is not None:
            usbl_x_on_vessel = self.usbl_x_offset_doubleSpinBox.value()
            usbl_y_on_vessel = self.usbl_y_offset_doubleSpinBox.value()
        else:
            usbl_x_on_vessel = 0
            usbl_y_on_vessel = 0
        # get width and height from view
        w_max = self.top_graphicsView.width()
        h_max = self.top_graphicsView.height()

        # set max
        if v_width > v_length:
            max_pix = v_width
        else:
            max_pix = v_length

        # set pixel ratio
        if w_max < h_max:
            pix_ratio = (w_max - 20) / max_pix
        else:
            pix_ratio = (h_max - 20) / max_pix

        # set the size of the vessel
        vessel = QPolygonF([
            QPointF(pix_ratio * v_width / 2, 0),
            QPointF(pix_ratio * v_width, pix_ratio * v_length / 4),
            QPointF(pix_ratio * v_width, pix_ratio * v_length),
            QPointF(0, pix_ratio * v_length),
            QPointF(0, pix_ratio * v_length / 4)
        ])
        self.item = QGraphicsPolygonItem(vessel)
        # set brown color
        self.item.setBrush(QColor(210, 180, 140))

        x_origin_scene = (pix_ratio * v_width / 2)
        y_origin_scene = (pix_ratio * v_length / 2)

        # coordinate system
        line_x_coord = QGraphicsLineItem(x_origin_scene, 0, x_origin_scene,
                                         y_origin_scene)
        line_y_coord = QGraphicsLineItem(x_origin_scene, y_origin_scene,
                                         pix_ratio * v_width, y_origin_scene)
        x_label = QGraphicsSimpleTextItem("X", line_x_coord)
        x_label.setPos(x_origin_scene - 10, 0 + 10)
        y_label = QGraphicsSimpleTextItem("Y", line_y_coord)
        y_label.setPos(pix_ratio * v_width - 20, y_origin_scene)

        x_origin_scene += vrp_y_on_vessel * pix_ratio
        y_origin_scene += -vrp_x_on_vessel * pix_ratio

        # draw origin point
        origin = QGraphicsEllipseItem(x_origin_scene - 10, y_origin_scene - 10,
                                      20, 20)
        origin.setBrush(Qt.white)
        line_one_origin = QGraphicsLineItem(x_origin_scene - 10,
                                            y_origin_scene,
                                            x_origin_scene + 10,
                                            y_origin_scene)
        line_two_origin = QGraphicsLineItem(x_origin_scene,
                                            y_origin_scene - 10,
                                            x_origin_scene,
                                            y_origin_scene + 10)

        # gps position
        gps_circle = QGraphicsEllipseItem(
            x_origin_scene - 10 + gps_y_on_vessel * pix_ratio,
            y_origin_scene - 10 - gps_x_on_vessel * pix_ratio, 20, 20)
        gps_circle.setBrush(QColor(143, 188, 143))

        line_one_gps = QGraphicsLineItem(
            x_origin_scene - 10 + gps_y_on_vessel * pix_ratio,
            y_origin_scene - gps_x_on_vessel * pix_ratio,
            x_origin_scene + 10 + gps_y_on_vessel * pix_ratio,
            y_origin_scene - gps_x_on_vessel * pix_ratio)
        line_two_gps = QGraphicsLineItem(
            x_origin_scene + gps_y_on_vessel * pix_ratio,
            y_origin_scene - 10 - gps_x_on_vessel * pix_ratio,
            x_origin_scene + gps_y_on_vessel * pix_ratio,
            y_origin_scene + 10 - gps_x_on_vessel * pix_ratio)
        # gps label
        gps_label = QGraphicsSimpleTextItem("GPS", gps_circle)
        gps_label.setPos(x_origin_scene - 10 + gps_y_on_vessel * pix_ratio,
                         y_origin_scene + 10 - gps_x_on_vessel * pix_ratio)

        if util.find_spec('usblcontroller') is not None:
            # usbl position
            usbl_circle = QGraphicsEllipseItem(
                x_origin_scene - 10 + usbl_y_on_vessel * pix_ratio,
                y_origin_scene - 10 - usbl_x_on_vessel * pix_ratio, 20, 20)
            usbl_circle.setBrush(QColor(255, 99, 71))

            line_one_usbl = QGraphicsLineItem(
                x_origin_scene - 10 + usbl_y_on_vessel * pix_ratio,
                y_origin_scene - usbl_x_on_vessel * pix_ratio,
                x_origin_scene + 10 + usbl_y_on_vessel * pix_ratio,
                y_origin_scene - usbl_x_on_vessel * pix_ratio)
            line_two_usbl = QGraphicsLineItem(
                x_origin_scene + usbl_y_on_vessel * pix_ratio,
                y_origin_scene - 10 - usbl_x_on_vessel * pix_ratio,
                x_origin_scene + usbl_y_on_vessel * pix_ratio,
                y_origin_scene + 10 - usbl_x_on_vessel * pix_ratio)
            # usbl label
            usbl_label = QGraphicsSimpleTextItem("USBL", usbl_circle)
            if usbl_x_on_vessel == gps_x_on_vessel and usbl_y_on_vessel == gps_y_on_vessel:
                usbl_label.setPos(
                    x_origin_scene - 10 + usbl_y_on_vessel * pix_ratio,
                    y_origin_scene - 30 - usbl_x_on_vessel * pix_ratio)
            else:
                usbl_label.setPos(
                    x_origin_scene - 10 + usbl_y_on_vessel * pix_ratio,
                    y_origin_scene + 10 - usbl_x_on_vessel * pix_ratio)

        origin_label = QGraphicsSimpleTextItem("VRP", origin)
        if (usbl_x_on_vessel == 0
                and usbl_y_on_vessel == 0) or (gps_x_on_vessel == 0
                                               and gps_y_on_vessel == 0):
            origin_label.setPos(x_origin_scene + 10, y_origin_scene - 10)
        else:
            origin_label.setPos(x_origin_scene - 10, y_origin_scene + 10)

        # fit view/scene
        self.top_graphicsView.setSceneRect(0, 0, pix_ratio * v_width,
                                           pix_ratio * v_length)

        # add vessel to the scene
        self.top_graphicsView.scene().addItem(self.item)
        # add origin to the scene
        self.top_graphicsView.scene().addItem(origin)
        self.top_graphicsView.scene().addItem(line_one_origin)
        self.top_graphicsView.scene().addItem(line_two_origin)
        # add gps
        self.top_graphicsView.scene().addItem(gps_circle)
        self.top_graphicsView.scene().addItem(line_one_gps)
        self.top_graphicsView.scene().addItem(line_two_gps)

        if util.find_spec('usblcontroller') is not None:
            # add usbl
            self.top_graphicsView.scene().addItem(usbl_circle)
            self.top_graphicsView.scene().addItem(line_one_usbl)
            self.top_graphicsView.scene().addItem(line_two_usbl)

        # add coord system
        self.top_graphicsView.scene().addItem(line_x_coord)
        self.top_graphicsView.scene().addItem(line_y_coord)
        # set background
        self.top_scene.setBackgroundBrush(QColor(204, 229, 255))

        # set antialiasing renderhint
        self.top_graphicsView.setRenderHint(QPainter.Antialiasing)
Exemple #26
0
class PreXoverItem(QGraphicsPathItem):
    def __init__(self,  from_virtual_helix_item, to_virtual_helix_item, index, strand_type, is_low_idx):
        super(PreXoverItem, self).__init__(from_virtual_helix_item)
        self._from_vh_item = from_virtual_helix_item
        self._to_vh_item = to_virtual_helix_item
        self._idx = index
        self._strand_type = strand_type
        # translate from Low to Left for the Path View
        self._is_low_index = is_low_idx
        self._is_active = False
        self._pen = _SCAF_PEN if strand_type == StrandType.SCAFFOLD else _STAP_PEN
        is_on_top = from_virtual_helix_item.isStrandTypeOnTop(strand_type)

        bw = _BASE_WIDTH
        x = bw * index
        y = (-1.25 if is_on_top else 2.25) * bw
        self.setPos(x, y)

        num = to_virtual_helix_item.number()
        tBR = _FM.tightBoundingRect(str(num))
        half_label_H = tBR.height()/2.0
        half_label_W = tBR.width()/2.0

        labelX = bw/2.0 - half_label_W #
        if num == 1:  # adjust for the number one
            labelX -= half_label_W/2.0

        if is_on_top:
            labelY = -0.25*half_label_H - .5
        else:
            labelY = 2*half_label_H + .5

        self._label = QGraphicsSimpleTextItem(self)
        self._label.setPos(labelX, labelY)

        # create a bounding rect item to process click events
        # over a wide area
        self._clickArea = c_a = QGraphicsRectItem(_RECT, self)
        c_a.mousePressEvent = self.mousePress
        yoffset = 0.2*bw if is_on_top else -0.4*bw
        c_a.setPos(0, yoffset)
        c_a.setPen(QPen(Qt.NoPen))

        self.updateStyle()
        self._updateLabel()
        self.setPainterPath()
    # end def

    ### DRAWING METHODS ###
    def remove(self):
        scene = self.scene()
        if scene:
            scene.removeItem(self._label)
            scene.removeItem(self._clickArea)
            scene.removeItem(self)
        self._label = None
        self._clickArea = None
        self._from_vh_item = None
        self._to_vh_item = None
    # end def

    def _updateLabel(self):
        lbl = self._label
        lbl.setBrush(self._label_brush)
        lbl.setFont(_TO_HELIX_NUM_FONT)
        lbl.setText( str(self._to_vh_item.number() ) )
    # end def

    ### TOOL METHODS ###
    def selectToolMousePress(self, event):
        """removexover(from_strand, from_idx, to_strand, to_idx)"""
        pass
    def refresh(self):
        if not self._mdlPlots or not self._mdlOutline or not self._mdlCharacter:
            return

        if not self.isVisible():
            return

        LINE_HEIGHT = 18
        SPACING = 3
        TEXT_WIDTH = self.sldTxtSize.value()
        CIRCLE_WIDTH = 10
        LEVEL_HEIGHT = 12

        s = self.scene
        s.clear()

        # Get Max Level (max depth)
        root = self._mdlOutline.rootItem
        def maxLevel(item, level=0, max=0):
            if level > max:
                max = level
            for c in item.children():
                m = maxLevel(c, level + 1)
                if m > max:
                    max = m
            return max

        MAX_LEVEL = maxLevel(root)

        # Get the list of tracked items (array of references)
        trackedItems = []

        if self.actPlots.isChecked():
            trackedItems += self.plotReferences()

        if self.actCharacters.isChecked():
            trackedItems += self.charactersReferences()

        ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING )

        fm = QFontMetrics(s.font())
        max_name = 0
        for ref in trackedItems:
            name = references.title(ref)
            max_name = max(fm.width(name), max_name)

        TITLE_WIDTH = max_name + 2 * SPACING

        # Add Folders and Texts
        outline = OutlineRect(0, 0, 0, ROWS_HEIGHT + SPACING + MAX_LEVEL * LEVEL_HEIGHT)
        s.addItem(outline)
        outline.setPos(TITLE_WIDTH + SPACING, 0)

        refCircles = [] # a list of all references, to be added later on the lines

        # A Function to add a rect with centered elided text
        def addRectText(x, w, parent, text="", level=0, tooltip=""):
            deltaH = LEVEL_HEIGHT if level else 0
            r = OutlineRect(0, 0, w, parent.rect().height()-deltaH, parent, title=text)
            r.setPos(x, deltaH)

            txt = QGraphicsSimpleTextItem(text, r)
            f = txt.font()
            f.setPointSize(8)
            fm = QFontMetricsF(f)
            elidedText = fm.elidedText(text, Qt.ElideMiddle, w)
            txt.setFont(f)
            txt.setText(elidedText)
            txt.setPos(r.boundingRect().center() - txt.boundingRect().center())
            txt.setY(0)
            return r

        # A function to returns an item's width, by counting its children
        def itemWidth(item):
            if item.isFolder():
                r = 0
                for c in item.children():
                    r += itemWidth(c)
                return r or TEXT_WIDTH
            else:
                return TEXT_WIDTH

        def listItems(item, rect, level=0):
            delta = 0
            for child in item.children():
                w = itemWidth(child)

                if child.isFolder():
                    parent = addRectText(delta, w, rect, child.title(), level, tooltip=child.title())
                    parent.setToolTip(references.tooltip(references.textReference(child.ID())))
                    listItems(child, parent, level + 1)

                else:
                    rectChild = addRectText(delta, TEXT_WIDTH, rect, "", level, tooltip=child.title())
                    rectChild.setToolTip(references.tooltip(references.textReference(child.ID())))
                    
                    # Find tracked references in that scene (or parent folders)
                    for ref in trackedItems:

                        result = []

                        # Tests if POV
                        scenePOV = False  # Will hold true of character is POV of the current text, not containing folder
                        if references.type(ref) == references.CharacterLetter:
                            ID = references.ID(ref)
                            c = child
                            while c:
                                if c.POV() == ID:
                                    result.append(c.ID())
                                    if c == child: scenePOV = True
                                c = c.parent()

                        # Search in notes/references
                        c = child
                        while c:
                            result += references.findReferencesTo(ref, c, recursive=False)
                            c = c.parent()

                        if result:
                            ref2 = result[0]
                            
                            # Create a RefCircle with the reference
                            c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2, important=scenePOV)
                            
                            # Store it, with the position of that item, to display it on the line later on
                            refCircles.append((ref, c, rect.mapToItem(outline, rectChild.pos())))

                delta += w

        listItems(root, outline)

        OUTLINE_WIDTH = itemWidth(root)

        # Add Tracked items
        i = 0
        itemsRect = s.addRect(0, 0, 0, 0)
        itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING)

        # Set of colors for plots (as long as they don't have their own colors)
        colors = [
            "#D97777", "#AE5F8C", "#D9A377", "#FFC2C2", "#FFDEC2", "#D2A0BC",
            "#7B0F0F", "#7B400F", "#620C3D", "#AA3939", "#AA6C39", "#882D61",
            "#4C0000", "#4C2200", "#3D0022",
        ]

        for ref in trackedItems:
            if references.type(ref) == references.CharacterLetter:
                color = self._mdlCharacter.getCharacterByID(references.ID(ref)).color()
            else:
                color = QColor(colors[i % len(colors)])

            # Rect
            r = QGraphicsRectItem(0, 0, TITLE_WIDTH, LINE_HEIGHT, itemsRect)
            r.setPen(QPen(Qt.NoPen))
            r.setBrush(QBrush(color))
            r.setPos(0, i * LINE_HEIGHT + i * SPACING)
            r.setToolTip(references.tooltip(ref))
            i += 1

            # Text
            name = references.title(ref)
            txt = QGraphicsSimpleTextItem(name, r)
            txt.setPos(r.boundingRect().center() - txt.boundingRect().center())

            # Line
            line = PlotLine(0, 0,
                            OUTLINE_WIDTH + SPACING, 0)
            line.setPos(TITLE_WIDTH, r.mapToScene(r.rect().center()).y())
            s.addItem(line)
            line.setPen(QPen(color, 5))
            line.setToolTip(references.tooltip(ref))

            # We add the circles / references to text, on the line
            for ref2, circle, pos in refCircles:
                if ref2 == ref:
                    circle.setParentItem(line)
                    circle.setPos(pos.x(), 0)

        # self.view.fitInView(0, 0, TOTAL_WIDTH, i * LINE_HEIGHT, Qt.KeepAspectRatioByExpanding) # KeepAspectRatio
        self.view.setSceneRect(0, 0, 0, 0)
Exemple #28
0
class Node(QGraphicsEllipseItem):
    def __init__(self, metadata, x_y):
        """
        Create node in the graph scene

        :param dict metadata: Node metadata
        :param x_y: Position of the node
        """
        # unpack tuple
        x, y = x_y

        super(Node, self).__init__()

        self.metadata = metadata
        self.id = metadata['id']
        self.status_wallet = self.metadata['status'] & NODE_STATUS_HIGHLIGHTED
        self.status_member = not self.metadata['status'] & NODE_STATUS_OUT
        self.text = self.metadata['text']
        self.setToolTip(self.metadata['tooltip'])
        self.arcs = []
        self.menu = None
        self.action_sign = None
        self.action_transaction = None
        self.action_contact = None
        self.action_show_member = None

        # color around ellipse
        outline_color = QColor('grey')
        outline_style = Qt.SolidLine
        outline_width = 1
        if self.status_wallet:
            outline_color = QColor('black')
            outline_width = 2
        if not self.status_member:
            outline_color = QColor('red')
            outline_style = Qt.SolidLine
        self.setPen(QPen(outline_color, outline_width, outline_style))

        # text inside ellipse
        self.text_item = QGraphicsSimpleTextItem(self)
        self.text_item.setText(self.text)
        text_color = QColor('grey')
        if self.status_wallet == NODE_STATUS_HIGHLIGHTED:
            text_color = QColor('black')
        self.text_item.setBrush(QBrush(text_color))
        # center ellipse around text
        self.setRect(
            0,
            0,
            self.text_item.boundingRect().width() * 2,
            self.text_item.boundingRect().height() * 2
        )

        #  set anchor to the center
        self.setTransform(
            QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0))
        self.setPos(x, y)
        # center text in ellipse
        self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0)

        # create gradient inside the ellipse
        gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width())
        gradient.setColorAt(0, QColor('white'))
        gradient.setColorAt(1, QColor('darkgrey'))
        self.setBrush(QBrush(gradient))

        # cursor change on hover
        self.setAcceptHoverEvents(True)
        self.setZValue(1)

    def mousePressEvent(self, event: QMouseEvent):
        """
        Click on mouse button

        :param event: mouse event
        """
        if event.button() == Qt.LeftButton:
            # trigger scene signal
            self.scene().node_clicked.emit(self.metadata)

    def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent):
        """
        Mouse enter on node zone

        :param event: scene hover event
        """
        self.setCursor(Qt.ArrowCursor)

    def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent):
        """
        Right click on node to show node menu
        Except on wallet node

        :param event: scene context menu event
        """
        #  no menu on the wallet node
        if self.status_wallet:
            return None
        # create node context menus
        self.menu = QMenu()
        # action show member
        QT_TRANSLATE_NOOP('WoT.Node', 'Informations')
        self.action_show_member = QAction(QCoreApplication.translate('WoT.Node', 'Informations'), self.scene())
        self.menu.addAction(self.action_show_member)
        self.action_show_member.triggered.connect(self.member_action)
        # action add identity as contact
        QT_TRANSLATE_NOOP('WoT.Node', 'Add as contact')
        self.action_contact = QAction(QCoreApplication.translate('WoT.Node', 'Add as contact'), self.scene())
        self.menu.addAction(self.action_contact)
        self.action_contact.triggered.connect(self.contact_action)
        # action transaction toward identity
        QT_TRANSLATE_NOOP('WoT.Node', 'Send money')
        self.action_transaction = QAction(QCoreApplication.translate('WoT.Node', 'Send money'), self.scene())
        self.menu.addAction(self.action_transaction)
        self.action_transaction.triggered.connect(self.transaction_action)
        # action sign identity
        QT_TRANSLATE_NOOP('WoT.Node', 'Certify identity')
        self.action_sign = QAction(QCoreApplication.translate('WoT.Node', 'Certify identity'), self.scene())
        self.menu.addAction(self.action_sign)
        self.action_sign.triggered.connect(self.sign_action)
        # run menu
        self.menu.exec(event.screenPos())

    def add_arc(self, arc):
        """
        Add arc to the arc list

        :param arc: Arc
        """
        self.arcs.append(arc)

    def member_action(self):
        """
        Transaction action to identity node
        """
        # trigger scene signal
        self.scene().node_member.emit(self.metadata)

    def contact_action(self):
        """
        Transaction action to identity node
        """
        # trigger scene signal
        self.scene().node_contact.emit(self.metadata)

    def sign_action(self):
        """
        Sign identity node
        """
        # trigger scene signal
        self.scene().node_signed.emit(self.metadata)

    def transaction_action(self):
        """
        Transaction action to identity node
        """
        # trigger scene signal
        self.scene().node_transaction.emit(self.metadata)
Exemple #29
0
class VCTemporalSeries(VCCommons):
    def __init__(self):
        VCCommons.__init__(self)
        self.__chart=QChart() #After setChart you must call it with chart()
        self._allowHideSeries=True

        #Axis cration
        self.axisX=QDateTimeAxis()
        self.axisX.setTickCount(8);
        self.axisX.setFormat("yyyy-MM");
        self.maxx=None
        self.maxy=None
        self.minx=None
        self.miny=None
        
        
        self.__ohclduration=eOHCLDuration.Day
        self.axisY = QValueAxis()
        self.axisY.setLabelFormat("%i")

        self.setRenderHint(QPainter.Antialiasing);
        
        self.series=[]
        self.popup=MyPopup(self)

    def appendCandlestickSeries(self, name):
        ls=QCandlestickSeries()
        ls.setName(name)
        ls.setIncreasingColor(QColor(Qt.green));
        ls.setDecreasingColor(QColor(Qt.red));
        self.series.append(ls)
        return ls

    def appendCandlestickSeriesData(self, ls, dtaware, ope, hig, clo, low):
        x=dtaware2epochms(dtaware)
        ls.append(QCandlestickSet(float(ope), float(hig), float(clo), float(low), x ))
        if self.maxy==None:
            self.maxy=float(hig)
            self.miny=float(low)
            self.maxx=x
            self.minx=x
        if hig>self.maxy:
            self.maxy=float(hig)
        if low<self.miny:
            self.miny=float(low)
        if x>self.maxx:
            self.maxx=x
        if x<self.minx:
            self.minx=x

    def setOHCLDuration(self, ohclduration):
        self.__ohclduration=ohclduration

    def appendScatterSeries(self, name):
        ls=QScatterSeries()
        ls.setName(name)
        self.series.append(ls)
        return ls

    def appendScatterSeriesData(self, ls, x, y):
        self.appendTemporalSeriesData(ls, x, y)

    def setAxisFormat(self, axis,  min, max, type, zone=None):
        """
            type=0 #Value
            type=1 # Datetime
            
            if zone=None remains in UTC, zone is a zone object.
        """
        if type==0:
            if max-min<=Decimal(0.01):
                axis.setLabelFormat("%.4f")
            elif max-min<=Decimal(100):
                axis.setLabelFormat("%.2f")
            else:
                axis.setLabelFormat("%i")
        elif type==1:
            max=epochms2dtaware(max)#UTC aware
            min=epochms2dtaware(min)
            if max-min<timedelta(days=1):
                axis.setFormat("hh:mm")
            else:
                axis.setFormat("yyyy-MM-dd")

    def setAllowHideSeries(self, boolean):
        self._allowHideSeries=boolean

        
    def appendTemporalSeries(self, name):
        ls=QLineSeries()
        ls.setName(name)
        self.series.append(ls)
        return ls        

    def appendTemporalSeriesData(self, ls, x, y):
        """
            x is a datetime zone aware
        """
        x=dtaware2epochms(x)
        x=float(x)
        y=float(y)
        ls.append(x, y)
        
        if self.maxy==None:#Gives first maxy and miny
            self.maxy=y*1.01
            self.miny=y*0.99
            self.maxx=x*1.01
            self.minx=x*0.99
            
        if y>self.maxy:
            self.maxy=y
        if y<self.miny:
            self.miny=y
        if x>self.maxx:
            self.maxx=x
        if x<self.minx:
            self.minx=x

    def mouseMoveEvent(self, event):     
        ##Sets the place of the popup in the windows to avoid getout of the screen
        ##frmshow can be a frmShowCasilla or a frmShowFicha
        def placePopUp():
            resultado=QPoint(event.x()+15, event.y()+15)
            if event.x()>self.width()-self.popup.width()-15:
                resultado.setX(event.x()-self.popup.width()-15)
            if event.y()>self.height()-self.popup.height()-15:
                resultado.setY(event.y()-self.popup.height()-15)
            return resultado
        def showCurrentPosition():
            if hasattr(self, "qgstiCurrentX")==False:
                self.qgstiCurrentX=QGraphicsSimpleTextItem(self.chart())
                self.qgstiCurrentY=QGraphicsSimpleTextItem(self.chart())
            self.qgstiCurrentX.setPos(event.pos().x(), maxY-10)
            self.qgstiCurrentY.setPos(self.chart().size().width()-47, event.pos().y())
            self.qgstiCurrentX.setText(str(epochms2dtaware(xVal).date()))
            self.qgstiCurrentY.setText(str(round(yVal,2)))
        # ---------------------------------------
        QChartView.mouseMoveEvent(self, event)
        xVal = self.chart().mapToValue(event.pos()).x()
        yVal = self.chart().mapToValue(event.pos()).y()

        maxX = self.axisX.max().toMSecsSinceEpoch()
        minX = self.axisX.min().toMSecsSinceEpoch()
        maxY = self.axisY.max()
        minY = self.axisY.min()
        if xVal <= maxX and  xVal >= minX and yVal <= maxY and yVal >= minY:
            self.popup.move(self.mapToGlobal(placePopUp()))
            self.popup.refresh(self, xVal, yVal)
            showCurrentPosition()
            self.popup.show()
        else:
            self.popup.hide()

    ## Return the value of the serie in x
    def series_value(self, serie, x):
        for point in serie.pointsVector():
            if point.x()>=x:
                return point.y()

    @pyqtSlot()
    def on_marker_clicked(self):
        marker=QObject.sender(self)#Busca el objeto que ha hecho la signal en el slot en el que está conectado, ya que estaban conectados varios objetos a una misma señal
        marker.series().setVisible(not marker.series().isVisible())
        marker.setVisible(True)
        if marker.series().isVisible():
            alpha = 1
        else:
            alpha=0.5

        lbrush=marker.labelBrush()
        color=lbrush.color()
        color.setAlphaF(alpha)
        lbrush.setColor(color)
        marker.setLabelBrush(lbrush)

        brush=marker.brush()
        color=brush.color()
        color.setAlphaF(alpha)
        brush.setColor(color)
        marker.setBrush(brush)
        
        pen=marker.pen()
        color=pen.color()
        color.setAlphaF(alpha)
        pen.setColor(color)
        marker.setPen(pen)

    ## Used to display chart. You cannot use it twice. close the view widget and create another one
    def display(self):
        if self.__chart!=None:
            del self.__chart
        self.__chart=QChart()
        self.setChart(self.__chart)
        if self._animations==True:
            self.chart().setAnimationOptions(QChart.AllAnimations);
        else:
            self.chart().setAnimationOptions(QChart.NoAnimation)
        self.chart().layout().setContentsMargins(0,0,0,0)
        self._display_set_title()

        self.setAxisFormat(self.axisX, self.minx, self.maxx, 1)
        self.setAxisFormat(self.axisY, self.miny, self.maxy, 0)
        self.chart().addAxis(self.axisY, Qt.AlignLeft);
        self.chart().addAxis(self.axisX, Qt.AlignBottom);

        for s in self.series:
            self.chart().addSeries(s)
            s.attachAxis(self.axisX)
            s.attachAxis(self.axisY)
        self.axisY.setRange(self.miny, self.maxy)

        #Legend positions
        if len(self.chart().legend().markers())>6:
            self.chart().legend().setAlignment(Qt.AlignLeft)
        else:
            self.chart().legend().setAlignment(Qt.AlignTop)

        if self._allowHideSeries==True:
            for marker in self.chart().legend().markers():
                try:
                    marker.clicked.disconnect()
                except:
                    pass
                marker.clicked.connect(self.on_marker_clicked)
        self.repaint()
class ClearanceWidthGraph(BaseGraphic):
    def __init__(self, *args):
        super(ClearanceWidthGraph, self).__init__(*args)
        self.dimension_analysis = self.section_analyzer.dimension_analysis
        self.clearance_analysis = self.section_analyzer.clearance_analysis
        self.min_horizontal_clearance = self.dimension_analysis.min_horizontal_clearance
        self.graph_zero = [None, None]
        self.graph_end = [None, None]
        self.clearance_label = QGraphicsSimpleTextItem()
        self.addToGroup(self.clearance_label)
        self.clearance_label.setZValue(1.0)
        self.init_dimension()

    def init_dimension(self):
        super(ClearanceWidthGraph, self).init_dimension()
        height_start = self.dimension_analysis.bounding_rect[2]
        height_end = self.dimension_analysis.bounding_rect[3]
        self.content_height = (height_end - height_start) * self.height_multiplier
        self.update_graph_size()
        self.create_axis()
        self.create_scale()
        self.add_clearance_graph()

    def create_axis(self):
        bounding_end = abs(self.dimension_analysis.bounding_rect[3])
        bounding_start = abs(self.dimension_analysis.bounding_rect[2])
        pen = QPen()
        pen.setWidthF(0.5)
        # horizontal line
        self.graph_zero[0] = self.position[0] + self.margin - self.line_extend
        self.graph_zero[1] = self.position[1] + bounding_start * self.height_multiplier + self.margin
        self.graph_end[0] = self.graph_zero[0] + self.content_width + self.line_extend
        self.graph_end[1] = self.graph_zero[1]
        line_item_horizontal = QGraphicsLineItem(self.graph_zero[0], self.graph_zero[1], self.graph_end[0], self.graph_end[1])
        line_item_horizontal.setPen(pen)
        self.addToGroup(line_item_horizontal)
        center = (self.graph_zero[0] + self.line_extend), self.graph_zero[1]
        y_top = center[1] - (bounding_start*self.height_multiplier)
        y_bottom = center[1]+(bounding_end*self.height_multiplier)
        line_item_vertical = QGraphicsLineItem(center[0], y_top, center[0], y_bottom)
        line_item_vertical.setPen(pen)
        self.addToGroup(line_item_vertical)
        pen_thin = QPen()
        pen_thin.setWidthF(0.2)
        start_graph = center[1] - 10
        while start_graph > center[1] - bounding_start * self.height_multiplier:
            line_item_horizontal = QGraphicsLineItem(self.graph_zero[0], start_graph, self.graph_end[0], start_graph)
            line_item_horizontal.setPen(pen_thin)
            line_item_horizontal.setZValue(-0.5)
            self.addToGroup(line_item_horizontal)
            start_graph -= 10
        start_graph = center[1] + 10
        while start_graph < center[1] + bounding_end * self.height_multiplier:
            line_item_horizontal = QGraphicsLineItem(self.graph_zero[0], start_graph, self.graph_end[0], start_graph)
            line_item_horizontal.setPen(pen_thin)
            line_item_horizontal.setZValue(-0.5)
            self.addToGroup(line_item_horizontal)
            start_graph += 10

    def create_scale(self):
        section_num = len(self.section_analyzer.section_list)
        section_distance = self.section_analyzer.section_distance
        total_distance = section_num * section_distance
        div = int(Math.integer_division(total_distance, 1.0))
        print(total_distance)
        for i in range(div+1):
            x = self.graph_zero[0] + i * self.length_multiplier + self.line_extend
            y = self.graph_zero[1]
            scale_text = QGraphicsSimpleTextItem("%.2f" % float(i))
            scale_text.setPos(x, y)
            self.addToGroup(scale_text)
        start_to_zero = self.graph_zero[1] - self.position[1]
        step = abs(start_to_zero) // 25
        x = self.graph_zero[0] - 15
        y = self.graph_zero[1]
        for i in range(int(step)-1):
            if i > 0:
                value = i * 25 / 100
                scene_y = y - i * 25
                text = QGraphicsSimpleTextItem("-%.2f" % value)
                text.setPos(x, scene_y)
                self.addToGroup(text)
        start_to_zero = self.position[1] + self.height - self.graph_zero[1]
        step = abs(start_to_zero) // 25
        x = self.graph_zero[0] - 15
        y = self.graph_zero[1]
        for i in range(int(step)-1):
            if i > 0:
                value = i * 25 / 100
                scene_y = y + i * 25
                text = QGraphicsSimpleTextItem("%.2f" % value)
                text.setPos(x, scene_y)
                self.addToGroup(text)

    def add_clearance_graph(self):
        print("-----------------------------------------")
        horizontal_clearance = self.clearance_analysis.horizontal_clearance
        x_init = self.graph_zero[0] + self.line_extend
        y_init = self.graph_zero[1]
        for i in range(len(horizontal_clearance)):
            clearance_points = horizontal_clearance[i]
            x = x_init + i * self.dimension_analysis.section_distance * self.length_multiplier
            left = -self.dimension_analysis.domain_length
            right = self.dimension_analysis.domain_length
            if clearance_points[0]:
                left = clearance_points[0]
            if clearance_points[1]:
                right = clearance_points[1]
            clearance = right - left
            y_top = y_init + left * self.height_multiplier
            y_bottom = y_init + right * self.height_multiplier
            pen_red = QPen()
            red = Color.create_qcolor_from_rgb_tuple(Color.red)
            pen_red.setColor(red)
            pen_green = QPen()
            green = Color.create_qcolor_from_rgb_tuple(Color.green)
            pen_green.setColor(green)
            line = QGraphicsLineItem(x, y_top, x, y_bottom)
            if clearance < self.min_horizontal_clearance:
                line.setPen(pen_red)
            else:
                line.setPen(pen_green)
            self.addToGroup(line)
        pass

    def set_distance_pointer(self, distance):
        horizontal_clearance = self.clearance_analysis.horizontal_clearance
        super(ClearanceWidthGraph, self).set_distance_pointer(distance)
        index = int(distance/self.section_distance)
        clearance = None
        if index < len(horizontal_clearance):
            clearance = horizontal_clearance[index]
        x = self.distance_pointer.line().x1()
        y = self.distance_pointer.line().y1() + (self.distance_pointer.line().y2() - self.distance_pointer.line().y1())/8
        self.clearance_label.setPos(x, y)
        if clearance:
            if clearance[1] and clearance[0]:
                distance = clearance[1] - clearance[0]
                self.clearance_label.setText("clearance = %.2f" % distance)
class BaseGraphic(object):
    def __init__(self, *args):
        super(BaseGraphic, self).__init__()
        self.label = args[3]
        self.parent = args[0]
        self.section_analyzer = self.parent.section_analyzer
        self.width = None
        self.height = None
        self.margin = None
        self.position = args[1], args[2]
        self.content_width = None
        self.content_height = None
        self.distance_pointer = None
        self.distance_label = None
        self.section_num = len(self.section_analyzer.section_list)
        self.section_distance = self.section_analyzer.section_distance
        self.length_multiplier = 100.0
        self.height_multiplier = 100.0
        self.line_extend = 20
        self.margin = 50
        self.material_legend = MaterialLegend(self)
        self._inited = False
        self.items = []
        self.add_title()

    def add_title(self):
        if self.label:
            title = QGraphicsSimpleTextItem(self.label)
            title.setPos(self.position[0] + self.margin, self.position[1] + self.line_extend)
            self.addToGroup(title)

    def addToGroup(self, item):
        self.items.append(item)

    def create_distance_pointer(self):
        self.distance_pointer = QGraphicsLineItem()
        pen = QPen()
        pen.setWidthF(1.0)
        pen.setStyle(Qt.DashDotLine)
        color = Color.create_qcolor_from_rgb_tuple_f((1,0,0))
        pen.setColor(color)
        self.distance_pointer.setPen(pen)
        self.distance_pointer.setZValue(1.0)
        self.addToGroup(self.distance_pointer)
        self.distance_label = QGraphicsSimpleTextItem()
        self.distance_label.setZValue(1.0)
        self.addToGroup(self.distance_label)


    def init_dimension(self):
        section_num = len(self.section_analyzer.section_list)
        section_distance = self.section_analyzer.section_distance
        self.content_width = section_num * section_distance * self.length_multiplier
        self.create_distance_pointer()
        self._inited = True

    def update_graph_size(self):
        if self.content_height and self.content_width:
            self.width = self.content_width + self.margin * 2
            self.height = self.content_height + self.margin * 2
        # bounding_rect.setWidth(self.width)
        # bounding_rect.setHeight(self.height)

    def set_distance_pointer(self, distance):
        if self._inited:
            x1 = self.position[0] + self.margin + distance * self.length_multiplier
            y1 = self.position[1]
            x2 = x1
            y2 = y1 + self.height
            self.distance_pointer.setLine(x1, y1, x2, y2)
            self.distance_label.setText("%.2f" % distance)
            self.distance_label.setPos(x2,y2)
        pass

    @staticmethod
    def set_rect_fill(*args):
        if args[0] == 0: #surface color mode
            rect = args[1]
            color = args[2]
            qcolor = Color.create_qcolor_from_rgb_tuple_f(color)
            brush = QBrush(qcolor)
            rect.setBrush(brush)

    def create_legend(self):
        x = self.position[0] + self.width
        y = self.position[1]
        self.material_legend.create_material_legend(x, y)
        for item in self.material_legend.graphic_items:
            self.addToGroup(item)
Exemple #32
0
class PreXoverItem(QGraphicsPathItem):
    def __init__(self,  from_virtual_helix_item, to_virtual_helix_item, index, strand_type, is_low_idx):
        super(PreXoverItem, self).__init__(from_virtual_helix_item)
        self._from_vh_item = from_virtual_helix_item
        self._to_vh_item = to_virtual_helix_item
        self._idx = index
        self._strand_type = strand_type
        # translate from Low to Left for the Path View
        self._is_low_index = is_low_idx
        self._is_active = False
        self._pen = _SCAF_PEN if strand_type == StrandType.SCAFFOLD else _STAP_PEN
        is_on_top = from_virtual_helix_item.isStrandTypeOnTop(strand_type)

        bw = _BASE_WIDTH
        x = bw * index
        y = (-1.25 if is_on_top else 2.25) * bw
        self.setPos(x, y)

        num = to_virtual_helix_item.number()
        tBR = _FM.tightBoundingRect(str(num))
        half_label_H = tBR.height()/2.0
        half_label_W = tBR.width()/2.0

        labelX = bw/2.0 - half_label_W #
        if num == 1:  # adjust for the number one
            labelX -= half_label_W/2.0

        if is_on_top:
            labelY = -0.25*half_label_H - .5
        else:
            labelY = 2*half_label_H + .5

        self._label = QGraphicsSimpleTextItem(self)
        self._label.setPos(labelX, labelY)

        # create a bounding rect item to process click events
        # over a wide area
        self._clickArea = c_a = QGraphicsRectItem(_RECT, self)
        c_a.mousePressEvent = self.mousePress
        yoffset = 0.2*bw if is_on_top else -0.4*bw
        c_a.setPos(0, yoffset)
        c_a.setPen(QPen(Qt.NoPen))

        self.updateStyle()
        self._updateLabel()
        self.setPainterPath()
    # end def

    ### DRAWING METHODS ###
    def remove(self):
        scene = self.scene()
        if scene:
            scene.removeItem(self._label)
            scene.removeItem(self._clickArea)
            scene.removeItem(self)
        self._label = None
        self._clickArea = None
        self._from_vh_item = None
        self._to_vh_item = None
    # end def

    def setPainterPath(self):
        """
        Sets the PainterPath according to the index (low = Left, high = Right)
        and strand position (top = Up, bottom = Down).
        """
        path_LUT = (_PPATH_RD, _PPATH_RU, _PPATH_LD, _PPATH_LU)  # Lookup table
        vhi = self._from_vh_item
        st = self._strand_type
        path = path_LUT[2*int(self._is_low_index) + int(vhi.isStrandTypeOnTop(st))]
        self.setPath(path)
    # end def

    def updateStyle(self):
        """
        If a PreXover can be installed the pen is a bold color,
        otherwise the PreXover is drawn with a disabled or muted color
        """
        from_vh = self._from_vh_item.virtualHelix()
        to_vh = self._to_vh_item.virtualHelix()
        part = self._from_vh_item.part()
        pen = _DISAB_PEN
        self._label_brush = _DISAB_BRUSH
        if part.possibleXoverAt(from_vh, to_vh, self._strand_type, self._idx):
            pen = self._pen
            self._is_active = True
            self._label_brush = _ENAB_BRUSH
        self.setPen(pen)
    # end def

    def _updateLabel(self):
        lbl = self._label
        lbl.setBrush(self._label_brush)
        lbl.setFont(_TO_HELIX_NUM_FONT)
        lbl.setText( str(self._to_vh_item.number() ) )
    # end def

    ### TOOL METHODS ###
    def selectToolMousePress(self, event):
        """removexover(from_strand, from_idx, to_strand, to_idx)"""
        pass
    # end def

    def mousePress(self, event):
        if event.button() != Qt.LeftButton:
            return QGraphicsPathItem.mousePressEvent(self, event)

        if event.modifiers() & Qt.ShiftModifier:
            return  # ignore shift click, user is probably trying to merge

        if self._is_active:
            from_vh = self._from_vh_item.virtualHelix()
            to_vh = self._to_vh_item.virtualHelix()
            from_ss = from_vh.getStrandSetByType(self._strand_type)
            to_ss = to_vh.getStrandSetByType(self._strand_type)
            from_strand = from_ss.getStrand(self._idx)
            to_strand = to_ss.getStrand(self._idx)
            part = self._from_vh_item.part()
            # determine if we are a 5' or a 3' end
            if self.path() in [_PPATH_LU, _PPATH_RD]:  # 3' end of strand5p clicked
                strand5p = from_strand
                strand3p = to_strand
            else:  # 5'
                strand5p = to_strand
                strand3p = from_strand

            # Gotta clear selections when installing a prexover
            # otherwise parenting in screwed up
            self._from_vh_item.viewroot().clearStrandSelections()

            part.createXover(strand5p, self._idx, strand3p, self._idx)
        else:
            event.setAccepted(False)
Exemple #33
0
class Node(QGraphicsEllipseItem):
    def __init__(self, metadata, x_y):
        """
        Create node in the graph scene

        :param dict metadata: Node metadata
        :param x_y: Position of the node
        """
        # unpack tuple
        x, y = x_y

        super(Node, self).__init__()

        self.metadata = metadata
        self.id = metadata['id']
        self.status_wallet = self.metadata['status'] & NODE_STATUS_HIGHLIGHTED
        self.status_member = not self.metadata['status'] & NODE_STATUS_OUT
        self.text = self.metadata['text']
        self.setToolTip(self.metadata['tooltip'])
        self.arcs = []
        self.menu = None
        self.action_sign = None
        self.action_transaction = None
        self.action_contact = None
        self.action_show_member = None

        # color around ellipse
        outline_color = QColor('grey')
        outline_style = Qt.SolidLine
        outline_width = 1
        if self.status_wallet:
            outline_color = QColor('black')
            outline_width = 2
        if not self.status_member:
            outline_color = QColor('red')
            outline_style = Qt.SolidLine
        self.setPen(QPen(outline_color, outline_width, outline_style))

        # text inside ellipse
        self.text_item = QGraphicsSimpleTextItem(self)
        self.text_item.setText(self.text)
        text_color = QColor('grey')
        if self.status_wallet == NODE_STATUS_HIGHLIGHTED:
            text_color = QColor('black')
        self.text_item.setBrush(QBrush(text_color))
        # center ellipse around text
        self.setRect(0, 0,
                     self.text_item.boundingRect().width() * 2,
                     self.text_item.boundingRect().height() * 2)

        #  set anchor to the center
        self.setTransform(QTransform().translate(
            -self.boundingRect().width() / 2.0,
            -self.boundingRect().height() / 2.0))
        self.setPos(x, y)
        # center text in ellipse
        self.text_item.setPos(self.boundingRect().width() / 4.0,
                              self.boundingRect().height() / 4.0)

        # create gradient inside the ellipse
        gradient = QRadialGradient(
            QPointF(0,
                    self.boundingRect().height() / 4),
            self.boundingRect().width())
        gradient.setColorAt(0, QColor('white'))
        gradient.setColorAt(1, QColor('darkgrey'))
        self.setBrush(QBrush(gradient))

        # cursor change on hover
        self.setAcceptHoverEvents(True)
        self.setZValue(1)

    def mousePressEvent(self, event: QMouseEvent):
        """
        Click on mouse button

        :param event: mouse event
        """
        if event.button() == Qt.LeftButton:
            # trigger scene signal
            self.scene().node_clicked.emit(self.metadata)

    def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent):
        """
        Mouse enter on node zone

        :param event: scene hover event
        """
        self.setCursor(Qt.ArrowCursor)

    def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent):
        """
        Right click on node to show node menu
        Except on wallet node

        :param event: scene context menu event
        """
        #  no menu on the wallet node
        if self.status_wallet:
            return None
        # create node context menus
        self.menu = QMenu()
        # action show member
        QT_TRANSLATE_NOOP('WoT.Node', 'Informations')
        self.action_show_member = QAction(
            QCoreApplication.translate('WoT.Node', 'Informations'),
            self.scene())
        self.menu.addAction(self.action_show_member)
        self.action_show_member.triggered.connect(self.member_action)
        # action add identity as contact
        QT_TRANSLATE_NOOP('WoT.Node', 'Add as contact')
        self.action_contact = QAction(
            QCoreApplication.translate('WoT.Node', 'Add as contact'),
            self.scene())
        self.menu.addAction(self.action_contact)
        self.action_contact.triggered.connect(self.contact_action)
        # action transaction toward identity
        QT_TRANSLATE_NOOP('WoT.Node', 'Send money')
        self.action_transaction = QAction(
            QCoreApplication.translate('WoT.Node', 'Send money'), self.scene())
        self.menu.addAction(self.action_transaction)
        self.action_transaction.triggered.connect(self.transaction_action)
        # action sign identity
        QT_TRANSLATE_NOOP('WoT.Node', 'Certify identity')
        self.action_sign = QAction(
            QCoreApplication.translate('WoT.Node', 'Certify identity'),
            self.scene())
        self.menu.addAction(self.action_sign)
        self.action_sign.triggered.connect(self.sign_action)
        # run menu
        self.menu.exec(event.screenPos())

    def add_arc(self, arc):
        """
        Add arc to the arc list

        :param arc: Arc
        """
        self.arcs.append(arc)

    def member_action(self):
        """
        Transaction action to identity node
        """
        # trigger scene signal
        self.scene().node_member.emit(self.metadata)

    def contact_action(self):
        """
        Transaction action to identity node
        """
        # trigger scene signal
        self.scene().node_contact.emit(self.metadata)

    def sign_action(self):
        """
        Sign identity node
        """
        # trigger scene signal
        self.scene().node_signed.emit(self.metadata)

    def transaction_action(self):
        """
        Transaction action to identity node
        """
        # trigger scene signal
        self.scene().node_transaction.emit(self.metadata)
Exemple #34
0
class NodeItem(GraphItem):
    def __init__(self,
                 highlight_level,
                 bounding_box,
                 label,
                 shape,
                 color=None,
                 parent=None,
                 label_pos=None,
                 tooltip=None):
        super(NodeItem, self).__init__(highlight_level, parent)

        self._default_color = self._COLOR_BLACK if color is None else color
        self._brush = QBrush(self._default_color)
        self._label_pen = QPen()
        self._label_pen.setColor(self._default_color)
        self._label_pen.setJoinStyle(Qt.RoundJoin)
        self._ellipse_pen = QPen(self._label_pen)
        self._ellipse_pen.setWidth(1)

        self._incoming_edges = set()
        self._outgoing_edges = set()

        self.parse_shape(shape, bounding_box)
        self.addToGroup(self._graphics_item)

        self._label = QGraphicsSimpleTextItem(label)
        self._label.setFont(GraphItem._LABEL_FONT)
        label_rect = self._label.boundingRect()
        if label_pos is None:
            label_rect.moveCenter(bounding_box.center())
        else:
            label_rect.moveCenter(label_pos)
        self._label.setPos(label_rect.x(), label_rect.y())
        self.addToGroup(self._label)
        if tooltip is not None:
            self.setToolTip(tooltip)

        self.set_node_color()

        self.setAcceptHoverEvents(True)

        self.hovershape = None

    def parse_shape(self, shape, bounding_box):
        if shape in ('box', 'rect', 'rectangle'):
            self._graphics_item = QGraphicsRectItem(bounding_box)
        elif shape in ('ellipse', 'oval', 'circle'):
            self._graphics_item = QGraphicsEllipseItem(bounding_box)
        elif shape in ('box3d', ):
            self._graphics_item = QGraphicsBox3dItem(bounding_box)
        else:
            print("Invalid shape '%s', defaulting to ellipse" % shape,
                  file=sys.stderr)
            self._graphics_item = QGraphicsEllipseItem(bounding_box)

    def set_hovershape(self, newhovershape):
        self.hovershape = newhovershape

    def shape(self):
        if self.hovershape is not None:
            path = QPainterPath()
            path.addRect(self.hovershape)
            return path
        else:
            return super(self.__class__, self).shape()

    def add_incoming_edge(self, edge):
        self._incoming_edges.add(edge)

    def add_outgoing_edge(self, edge):
        self._outgoing_edges.add(edge)

    def set_node_color(self, color=None):
        if color is None:
            color = self._default_color

        self._brush.setColor(color)
        self._ellipse_pen.setColor(color)
        self._label_pen.setColor(color)

        self._graphics_item.setPen(self._ellipse_pen)
        self._label.setBrush(self._brush)
        self._label.setPen(self._label_pen)

    def hoverEnterEvent(self, event):
        # hovered node item in red
        self.set_node_color(self._COLOR_RED)

        if self._highlight_level > 1:
            cyclic_edges = self._incoming_edges.intersection(
                self._outgoing_edges)
            # incoming edges in blue
            incoming_nodes = set()
            for incoming_edge in self._incoming_edges.difference(cyclic_edges):
                incoming_edge.set_node_color(self._COLOR_BLUE)
                incoming_edge.set_label_color(self._COLOR_BLUE)
                if incoming_edge.from_node != self:
                    incoming_nodes.add(incoming_edge.from_node)
            # outgoing edges in green
            outgoing_nodes = set()
            for outgoing_edge in self._outgoing_edges.difference(cyclic_edges):
                outgoing_edge.set_node_color(self._COLOR_GREEN)
                outgoing_edge.set_label_color(self._COLOR_GREEN)
                if outgoing_edge.to_node != self:
                    outgoing_nodes.add(outgoing_edge.to_node)
            # incoming/outgoing edges in teal
            for edge in cyclic_edges:
                edge.set_node_color(self._COLOR_TEAL)

            if self._highlight_level > 2:
                cyclic_nodes = incoming_nodes.intersection(outgoing_nodes)
                # incoming nodes in blue
                for incoming_node in incoming_nodes.difference(cyclic_nodes):
                    incoming_node.set_node_color(self._COLOR_BLUE)
                # outgoing nodes in green
                for outgoing_node in outgoing_nodes.difference(cyclic_nodes):
                    outgoing_node.set_node_color(self._COLOR_GREEN)
                # incoming/outgoing nodes in teal
                for node in cyclic_nodes:
                    node.set_node_color(self._COLOR_TEAL)

    def hoverLeaveEvent(self, event):
        self.set_node_color()
        if self._highlight_level > 1:
            for incoming_edge in self._incoming_edges:
                incoming_edge.set_node_color()
                incoming_edge.set_label_color()
                if self._highlight_level > 2 and incoming_edge.from_node != self:
                    incoming_edge.from_node.set_node_color()
            for outgoing_edge in self._outgoing_edges:
                outgoing_edge.set_node_color()
                outgoing_edge.set_label_color()
                if self._highlight_level > 2 and outgoing_edge.to_node != self:
                    outgoing_edge.to_node.set_node_color()
Exemple #35
0
class VLineChartView(QChartView):

    bar_hovered = pyqtSignal(bool, str)

    def __init__(self, data: pd.DataFrame):
        super(VLineChartView, self).__init__()
        self._stocks = data
        self._category = self._stocks['trade_date']
        self._chart = QChart()
        self._chart.setAnimationOptions(QChart.SeriesAnimations)
        self._series = QStackedBarSeries()
        # 成交量以万股为单位
        self._vol_multiple = 10000
        self.init_chart()
        self._zero_value = (0, self._chart.axisY().min())
        self._max_value = (len(self._chart.axisX().categories()),
                           self._chart.axisY().max())
        self._zero_point = self._chart.mapToPosition(
            QPointF(self._zero_value[0], self._zero_value[1]))
        self._max_point = self._chart.mapToPosition(
            QPointF(self._max_value[0], self._max_value[1]))
        # 计算x轴单个cate的宽度,用来处理横线不能画到边界
        self._cate_width = (self._max_point.x() - self._zero_point.x()) / len(
            self._category)
        self._series.hovered.connect(self.on_series_hovered)

        x_index_list = np.percentile(range(len(self._category)),
                                     [0, 25, 50, 75, 100])
        self._x_axis_list = [
            QGraphicsSimpleTextItem(self._category[int(index)], self._chart)
            for index in x_index_list
        ]
        [axis.setText(axis.text()[4:]) for axis in self._x_axis_list[1:]]
        self._v_b = QGraphicsSimpleTextItem('B', self._chart)
        self._v_b.setZValue(100)

    def on_series_hovered(self, status, index):
        self.bar_hovered.emit(status, self._category[index])

    def clear_series_value(self):
        self._series.clear()
        self._stocks = None
        self._chart.axisY().setRange(0, 10)
        self._chart.axisX().setCategories(list())

    def add_series_values(self, data: pd.DataFrame, is_init=False):
        self._stocks = data
        bar_red = QBarSet('red')
        bar_red.setColor(Qt.red)
        bar_green = QBarSet('green')
        bar_green.setColor(Qt.green)
        for _, stock in self._stocks.iterrows():
            if stock['open'] < stock['close']:
                bar_red.append(stock['vol'] / self._vol_multiple)
                bar_green.append(0)
            else:
                bar_red.append(0)
                bar_green.append(stock['vol'] / self._vol_multiple)

        self._series.append(bar_red)
        self._series.append(bar_green)

        if not is_init:
            self._stocks = data
            self._category = self._stocks['trade_date']
            axis_x = self._chart.axisX()
            axis_y = self._chart.axisY()
            axis_x.setCategories(self._category)
            max_p = self._stocks[[
                'vol',
            ]].stack().max()
            min_p = self._stocks[[
                'vol',
            ]].stack().min()
            axis_y.setRange(min_p / self._vol_multiple * 0.9,
                            max_p / self._vol_multiple * 1.1)
            self._zero_value = (0, self._chart.axisY().min())
            self._max_value = (len(self._chart.axisX().categories()),
                               self._chart.axisY().max())
            # 计算x轴单个cate的宽度,用来处理横线不能画到边界
            self._cate_width = (self._max_point.x() -
                                self._zero_point.x()) / len(self._category)

    def resizeEvent(self, event):
        super(VLineChartView, self).resizeEvent(event)
        self._zero_point = self._chart.mapToPosition(
            QPointF(self._zero_value[0], self._zero_value[1]))
        self._max_point = self._chart.mapToPosition(
            QPointF(self._max_value[0], self._max_value[1]))
        self._cate_width = (self._max_point.x() - self._zero_point.x()) / len(
            self._category)
        # 绘制自定义X轴
        self._x_axis_list[0].setPos(self._zero_point.x() - self._cate_width,
                                    self._zero_point.y() + 10)
        self._x_axis_list[1].setPos(self._max_point.x() * 0.25,
                                    self._zero_point.y() + 10)
        self._x_axis_list[2].setPos(self._max_point.x() * 0.5,
                                    self._zero_point.y() + 10)
        self._x_axis_list[3].setPos(self._max_point.x() * 0.75,
                                    self._zero_point.y() + 10)
        self._x_axis_list[4].setPos(
            self._max_point.x() - self._x_axis_list[-1].boundingRect().width(),
            self._zero_point.y() + 10)
        # 20180207 这个日期的柱形图上面画一个字母b
        vol = self._stocks[self._stocks['trade_date'] ==
                           '20180207']['vol'] / self._vol_multiple
        print('vol:', vol, ' trade_date:', '20180207')
        pos = self._chart.mapToPosition(
            QPointF(list(self._category).index('20180207'), vol))
        pos = QPointF(pos.x() - self._cate_width / 2,
                      pos.y() - self._v_b.boundingRect().height())
        self._v_b.setPos(pos)

    def max_point(self):
        return QPointF(self._max_point.x() + self._cate_width / 2,
                       self._max_point.y())

    def min_point(self):
        return QPointF(self._zero_point.x() - self._cate_width / 2,
                       self._zero_point.y())

    def init_chart(self):
        self.add_series_values(self._stocks, True)
        self._chart.addSeries(self._series)
        self._chart.createDefaultAxes()
        self._chart.setLocalizeNumbers(True)
        axis_x = self._chart.axisX()
        axis_y = self._chart.axisY()
        axis_x.setGridLineVisible(False)
        axis_y.setGridLineVisible(False)
        axis_y.setLabelFormat("%.2f")
        axis_x.setCategories(self._category)
        axis_x.setLabelsVisible(False)
        max_p = self._stocks[[
            'vol',
        ]].stack().max()
        min_p = self._stocks[[
            'vol',
        ]].stack().min()
        axis_y.setRange(min_p / self._vol_multiple * 0.9,
                        max_p / self._vol_multiple * 1.1)

        # chart的图例
        legend = self._chart.legend()
        legend.hide()
        # 设置图例由Series来决定样式
        # legend.setMarkerShape(QLegend.MarkerShapeFromSeries)

        self.setChart(self._chart)
        self._chart.layout().setContentsMargins(0, 0, 0, 0)
        # 设置内边界的bottom为0
        # margins = self._chart.margins()
        # self._chart.setMargins(QMargins(margins.left(), 0, margins.right(), 0))
        self._chart.setBackgroundRoundness(0)
Exemple #36
0
class IndicatorIconView(QGraphicsPixmapItem):
    def __init__(self,
                 parent: ViewBox,
                 icon_path: str,
                 icon_pos: int,
                 color: Optional[List[int]] = None,
                 message: str = ""):
        """An indicator icon for a pyqtgraph ViewBox

        The icon loaded from icon_path will be displayed in the low right corner of the ViewBox.

        :param parent: ViewBox to place indicator in
        :param icon_path: path to icon
        :param icon_pos: position index. Counting from 0 in lower right.
        """
        super().__init__()

        self.parent = parent
        self.icon_pos = icon_pos

        self.label = QGraphicsSimpleTextItem(message)
        self.label.setVisible(False)
        self.parent.scene().addItem(self.label)

        self.set_icon(icon_path, color)
        self.icon_size = [32, 32]

        self.parent.scene().addItem(self)

        self.position_icon()
        self.parent.sigResized.connect(self.position_icon)
        self.setVisible(False)
        self.setAcceptHoverEvents(True)

        self.connected_overlay = None

        self.actions: List[QAction] = []

    def set_icon(self, icon_path: str, color: Optional[List[int]] = None):
        if color is not None:
            image_data = skio.imread(icon_path, plugin="imageio")
            # Set the RGB part to the red channel multiplied by the requested color
            red_channel = image_data[:, :, 0] / 255
            image_data[:, :, 0] = red_channel * color[0]
            image_data[:, :, 1] = red_channel * color[1]
            image_data[:, :, 2] = red_channel * color[2]

            h = image_data.shape[0]
            w = image_data.shape[1]
            image_qi = QImage(image_data.data, w, h, 4 * w,
                              QImage.Format_RGBA8888)

            image_pm = QPixmap.fromImage(image_qi)

            self.label.setBrush(QColor(*color))
        else:
            image_pm = QPixmap(icon_path)
        self.setPixmap(image_pm)

    def position_icon(self):
        # The size of the imageview we are putting the icon ing
        scene_size = self.parent.size()
        # The position of the image within the scene
        scene_pos = self.parent.scenePos()
        # Lower right corner in scene pixel coordinates
        corner_pos_x = scene_size.width() + scene_pos.x()
        corner_pos_y = scene_size.height() + scene_pos.y()

        icon_pos_x = corner_pos_x - self.icon_size[0] * (1 +
                                                         self.icon_pos) - 10
        icon_pos_y = corner_pos_y - self.icon_size[1] - 30
        self.setOffset(icon_pos_x, icon_pos_y)

        label_width = self.label.boundingRect().width()
        self.label.setPos(corner_pos_x - label_width,
                          icon_pos_y - self.icon_size[0])

    def hoverEnterEvent(self, event):
        if self.connected_overlay is not None:
            self.connected_overlay.setVisible(True)
        self.label.setVisible(True)

    def hoverLeaveEvent(self, event):
        if self.connected_overlay is not None:
            self.connected_overlay.setVisible(False)
        self.label.setVisible(False)

    def add_actions(self, actions: List[Tuple[str, Callable]]):
        for text, method in actions:
            action = QAction(text)
            action.triggered.connect(method)
            self.actions.append(action)

    def mouseClickEvent(self, event):
        event.accept()
        if self.actions:
            qm = QMenu()
            for action in self.actions:
                qm.addAction(action)

            qm.exec(event.screenPos().toQPoint())
class Scene(QGraphicsScene):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # initialize 2D grid of cell data
        self.cells = { (i,j): Cell(val = CellType.empty) for i in range(Config.NUM_CELLS_X) for j in range(Config.NUM_CELLS_Y) }
        self.animations = dict()

        self.setItemIndexMethod(QGraphicsScene.NoIndex)
        self.draw_grid()
        self.init_start_goal()
        self.set_diagonal()
        self.repaint_cells()
        self.display_text = QGraphicsSimpleTextItem()
        self.display_text.setPos(5, self.height() - 60)
        self.display_text.setFont(QFont("Helvetica", 12, QFont.Bold))
        
    def drawForeground(self, *args, **kwargs):
        if self.display_text in self.items():
            self.removeItem(self.display_text)
            self.addItem(self.display_text)
        else:
            self.addItem(self.display_text)
        
    def set_text_log(self, s: str) -> None:
        self.display_text.setText(s)

    def init_start_goal(self) -> None:
        """Initialize start and goal positions"""
        height = (Config.NUM_CELLS_Y // 2) - 1
        self.start = Vector2D(1, height)
        self.goal = Vector2D(Config.NUM_CELLS_X - 1, height)

        self.set_cell(self.start, Cell(val = CellType.start))
        self.set_cell(self.goal, Cell(val = CellType.goal))
    
    def set_diagonal(self) -> None:
        """Generates array of possible moves based on Config.DIAGONALS"""
        if Config.DIAGONALS:
            self.neighbor_steps = np.array([[1, 1], [1, -1], [-1, 1], [-1, -1], [-1, 0], [0, 1], [1, 0], [0, -1]])
        else:
            self.neighbor_steps = np.array([[-1, 0], [0, 1], [1, 0], [0, -1]])
                
    def get_unexplored_neighbors(self, cell: Vector2D) -> list:
        """Return neighbors to Vector2D inside the scene"""
        result = []
        
        curr_cell = np.array([cell.x, cell.y])
            
        for step in self.neighbor_steps:
            neighbor = step + curr_cell
            neighbor = Vector2D(x = neighbor[0], y = neighbor[1])

            if in_bounds(neighbor) and not self.is_barrier(neighbor) and self.cell_type(neighbor) != CellType.searched:
                result.append(neighbor)

        return result

    def cost(self, coord: Vector2D) -> float:
        """Return weight of traversing cell at 'coord'"""
        return self.cells[coord].weight
    
    def set_cell(self, coord: Vector2D, new_cell: Cell) -> None:
        """Set value of cell at cells[x][y]"""
        self.cells[coord] = new_cell

    def is_barrier(self, coord: Vector2D):
        """Return whether cell at 'coord' is barrier"""
        return self.cells[coord].val == CellType.barrier
    
    def cell_type(self, coord: Vector2D):
        """Return type of cell at 'coord'"""
        return self.cells[coord].val

    def draw_grid(self) -> None:
        """Draws NUM_CELLS_X by NUM_CELLS_Y grid"""
        width = Config.CELL_LENGTH * Config.NUM_CELLS_X
        height = Config.CELL_LENGTH * Config.NUM_CELLS_Y
        self.setSceneRect(0, 0, width, height)
        pen = QPen(QColor(128, 128, 128), 1)
        # draw cells
        for x in range(0, Config.NUM_CELLS_X + 1):
            col = x * Config.CELL_LENGTH
            self.addLine(col, 0, col, height, pen)
        
        for y in range(0, Config.NUM_CELLS_Y + 1):
            row = y * Config.CELL_LENGTH
            self.addLine(0, row, width, row, pen)

    def resize_update(self) -> None:
        """Resizes grid and keeps 'start' and 'goal' cells inside of view"""
        self.clear()
        self.draw_grid()

        if self.start.x >= Config.NUM_CELLS_X - 1:
            self.start = Vector2D(Config.NUM_CELLS_X - 2, self.start.y)
        if self.start.y >= Config.NUM_CELLS_Y - 1:
            self.start = Vector2D(self.start.x, Config.NUM_CELLS_Y - 2)
        if self.goal.x >= Config.NUM_CELLS_X - 1:
            self.goal = Vector2D(Config.NUM_CELLS_X - 2, self.goal.y)
        if self.goal.y >= Config.NUM_CELLS_Y - 1:
            self.goal = Vector2D(self.goal.x, Config.NUM_CELLS_Y - 2)

        self.cells = { (i,j): Cell(val = CellType.empty) for i in range(Config.NUM_CELLS_X) for j in range(Config.NUM_CELLS_Y) }
        self.set_cell(self.start, Cell(val = CellType.start))
        self.set_cell(self.goal, Cell(val = CellType.goal))
        
        self.repaint_cells()

    def color_cell(self, coord: Vector2D, animate: bool = False) -> None:
        """Colors cell using the specified color. If 'animate' true, drawing is animated"""
        row = coord.y * Config.CELL_LENGTH + 1  # +1 so as to not paint over grid lines
        col = coord.x * Config.CELL_LENGTH + 1
        color = self.cells[coord].val
        pen = QPen(color, 1)
        brush = QBrush(color)

        if animate:
            threading.Thread (
                target=self.animate_rect, \
                args=(col, row, Config.CELL_LENGTH - 2, Config.CELL_LENGTH - 2, pen, brush), \
                daemon=True \
            ).start()

        else:
            self.addRect(col, row, Config.CELL_LENGTH - 2, Config.CELL_LENGTH - 2, pen, brush)  # -2 so as to not paint over grid lines

    def animate_rect(self, x: int, y: int, w: int, h: int, pen: QPen, brush: QBrush, duration: float = 0.125, n_steps: float = 16) -> list:
        """Creates RectObject that transposes from dimensions 0 x 0 to 'w' x 'h' in 'n_steps' steps over the course of 'duration' seconds"""
        rect = RectObject(x, y, w, h, pen, brush)
        rect.setScale(0.0)
        self.addItem(rect)

        time_step = duration / n_steps
        scale_step = 1.0 / n_steps
        scale = 0.0
        
        while scale <= 1.0:
            rect.setScale(scale)
            sleep(time_step)
            scale += scale_step
            self.update()  # this fixes random issue where drawing completely hangs

    def repaint_cells(self) -> None:
        """Repaints all cells"""
        self.set_cell(self.start, Cell(val = CellType.start))
        self.set_cell(self.goal, Cell(val = CellType.goal))
        for x in range(Config.NUM_CELLS_X):
            for y in range(Config.NUM_CELLS_Y):
                self.color_cell(Vector2D(x,y))

    def clear_path(self) -> None:
        """Removes searched and explored-type cells from grid"""
        for x in range(Config.NUM_CELLS_X):
            for y in range(Config.NUM_CELLS_Y):
                if self.cells[Vector2D(x,y)].val == CellType.path \
                or self.cells[Vector2D(x,y)].val == CellType.searched:
                    self.set_cell(Vector2D(x,y), Cell(val = CellType.empty))
                    self.color_cell(Vector2D(x,y))

    def draw_cell_sequence(self, cell_sequence: list, cell_type: CellType, animate: bool = False, prev_thread: threading.Thread = None):
        """
        Draws a sequence of cells and sets them to a given type. If 'animate', animate cells.
        If 'prev_thread', wait for 'prev_thread' before beginning to draw cells
        """
        if prev_thread:  # supports waiting for a previous animation
            prev_thread.join()

        for current_cell in cell_sequence:
            if self.cell_type(current_cell) not in (CellType.goal, CellType.start):
                self.set_cell(current_cell, Cell(val = cell_type))
                self.color_cell(current_cell, animate)
                sleep(0.03125)
Exemple #38
0
class ClassItem(UMLItem):
    """
    Class implementing an UML like class item.
    """
    ItemType = "class"

    def __init__(self,
                 model=None,
                 external=False,
                 x=0,
                 y=0,
                 rounded=False,
                 noAttrs=False,
                 parent=None,
                 scene=None):
        """
        Constructor
        
        @param model class model containing the class data (ClassModel)
        @param external flag indicating a class defined outside our scope
            (boolean)
        @param x x-coordinate (integer)
        @param y y-coordinate (integer)
        @keyparam rounded flag indicating a rounded corner (boolean)
        @keyparam noAttrs flag indicating, that no attributes should be shown
            (boolean)
        @keyparam parent reference to the parent object (QGraphicsItem)
        @keyparam scene reference to the scene object (QGraphicsScene)
        """
        UMLItem.__init__(self, model, x, y, rounded, parent)

        self.external = external
        self.noAttrs = noAttrs

        scene.addItem(self)

        if self.model:
            self.__createTexts()
            self.__calculateSize()

    def __createTexts(self):
        """
        Private method to create the text items of the class item.
        """
        if self.model is None:
            return

        boldFont = QFont(self.font)
        boldFont.setBold(True)

        attrs = self.model.getAttributes()
        meths = self.model.getMethods()

        x = self.margin + self.rect().x()
        y = self.margin + self.rect().y()
        self.header = QGraphicsSimpleTextItem(self)
        self.header.setFont(boldFont)
        self.header.setText(self.model.getName())
        self.header.setPos(x, y)
        y += self.header.boundingRect().height() + self.margin
        if not self.noAttrs and not self.external:
            if attrs:
                txt = "\n".join(attrs)
            else:
                txt = " "
            self.attrs = QGraphicsSimpleTextItem(self)
            self.attrs.setFont(self.font)
            self.attrs.setText(txt)
            self.attrs.setPos(x, y)
            y += self.attrs.boundingRect().height() + self.margin
        else:
            self.attrs = None
        if meths:
            txt = "\n".join(meths)
        else:
            txt = " "
        self.meths = QGraphicsSimpleTextItem(self)
        self.meths.setFont(self.font)
        self.meths.setText(txt)
        self.meths.setPos(x, y)

    def __calculateSize(self):
        """
        Private method to calculate the size of the class item.
        """
        if self.model is None:
            return

        width = self.header.boundingRect().width()
        height = self.header.boundingRect().height()
        if self.attrs:
            width = max(width, self.attrs.boundingRect().width())
            height = height + self.attrs.boundingRect().height() + self.margin
        if self.meths:
            width = max(width, self.meths.boundingRect().width())
            height = height + self.meths.boundingRect().height()
        self.setSize(width + 2 * self.margin, height + 2 * self.margin)

    def setModel(self, model):
        """
        Public method to set the class model.
        
        @param model class model containing the class data (ClassModel)
        """
        self.scene().removeItem(self.header)
        self.header = None
        if self.attrs:
            self.scene().removeItem(self.attrs)
            self.attrs = None
        if self.meths:
            self.scene().removeItem(self.meths)
            self.meths = None
        self.model = model
        self.__createTexts()
        self.__calculateSize()

    def paint(self, painter, option, widget=None):
        """
        Public method to paint the item in local coordinates.
        
        @param painter reference to the painter object (QPainter)
        @param option style options (QStyleOptionGraphicsItem)
        @param widget optional reference to the widget painted on (QWidget)
        """
        pen = self.pen()
        if (option.state & QStyle.State_Selected) == \
                QStyle.State(QStyle.State_Selected):
            pen.setWidth(2)
        else:
            pen.setWidth(1)

        painter.setPen(pen)
        painter.setBrush(self.brush())
        painter.setFont(self.font)

        offsetX = self.rect().x()
        offsetY = self.rect().y()
        w = self.rect().width()
        h = self.rect().height()

        painter.drawRect(offsetX, offsetY, w, h)
        y = self.margin + self.header.boundingRect().height()
        painter.drawLine(offsetX, offsetY + y, offsetX + w - 1, offsetY + y)
        if self.attrs:
            y += self.margin + self.attrs.boundingRect().height()
            painter.drawLine(offsetX, offsetY + y, offsetX + w - 1,
                             offsetY + y)

        self.adjustAssociations()

    def isExternal(self):
        """
        Public method returning the external state.
        
        @return external state (boolean)
        """
        return self.external

    def buildItemDataString(self):
        """
        Public method to build a string to persist the specific item data.
        
        This string must start with ", " and should be built like
        "attribute=value" with pairs separated by ", ". value must not
        contain ", " or newlines.
        
        @return persistence data (string)
        """
        entries = [
            "is_external={0}".format(self.external),
            "no_attributes={0}".format(self.noAttrs),
            "name={0}".format(self.model.getName()),
        ]
        attributes = self.model.getAttributes()
        if attributes:
            entries.append("attributes={0}".format("||".join(attributes)))
        methods = self.model.getMethods()
        if methods:
            entries.append("methods={0}".format("||".join(methods)))

        return ", " + ", ".join(entries)

    def parseItemDataString(self, version, data):
        """
        Public method to parse the given persistence data.
        
        @param version version of the data (string)
        @param data persisted data to be parsed (string)
        @return flag indicating success (boolean)
        """
        parts = data.split(", ")
        if len(parts) < 3:
            return False

        name = ""
        attributes = []
        methods = []

        for part in parts:
            key, value = part.split("=", 1)
            if key == "is_external":
                self.external = Utilities.toBool(value.strip())
            elif key == "no_attributes":
                self.noAttrs = Utilities.toBool(value.strip())
            elif key == "name":
                name = value.strip()
            elif key == "attributes":
                attributes = value.strip().split("||")
            elif key == "methods":
                methods = value.strip().split("||")
            else:
                return False

        self.model = ClassModel(name, methods, attributes)
        self.__createTexts()
        self.__calculateSize()

        return True
Exemple #39
0
    def refresh(self):
        if not self._mdlPlots or not self._mdlOutline or not self._mdlCharacter:
            return

        if not self.isVisible():
            return

        LINE_HEIGHT = 18
        SPACING = 3
        TEXT_WIDTH = self.sldTxtSize.value()
        CIRCLE_WIDTH = 10
        LEVEL_HEIGHT = 12

        s = self.scene
        s.clear()

        # Get Max Level (max depth)
        root = self._mdlOutline.rootItem
        def maxLevel(item, level=0, max=0):
            if level > max:
                max = level
            for c in item.children():
                m = maxLevel(c, level + 1)
                if m > max:
                    max = m
            return max

        MAX_LEVEL = maxLevel(root)

        # Get the list of tracked items (array of references)
        trackedItems = []

        if self.actPlots.isChecked():
            trackedItems += self.plotReferences()

        if self.actCharacters.isChecked():
            trackedItems += self.charactersReferences()

        ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING )

        fm = QFontMetrics(s.font())
        max_name = 0
        for ref in trackedItems:
            name = references.title(ref)
            max_name = max(fm.width(name), max_name)

        TITLE_WIDTH = max_name + 2 * SPACING

        # Add Folders and Texts
        outline = OutlineRect(0, 0, 0, ROWS_HEIGHT + SPACING + MAX_LEVEL * LEVEL_HEIGHT)
        s.addItem(outline)
        outline.setPos(TITLE_WIDTH + SPACING, 0)

        refCircles = [] # a list of all references, to be added later on the lines

        # A Function to add a rect with centered elided text
        def addRectText(x, w, parent, text="", level=0, tooltip=""):
            deltaH = LEVEL_HEIGHT if level else 0
            r = OutlineRect(0, 0, w, parent.rect().height()-deltaH, parent, title=text)
            r.setPos(x, deltaH)

            txt = QGraphicsSimpleTextItem(text, r)
            f = txt.font()
            f.setPointSize(8)
            fm = QFontMetricsF(f)
            elidedText = fm.elidedText(text, Qt.ElideMiddle, w)
            txt.setFont(f)
            txt.setText(elidedText)
            txt.setPos(r.boundingRect().center() - txt.boundingRect().center())
            txt.setY(0)
            return r

        # A function to returns an item's width, by counting its children
        def itemWidth(item):
            if item.isFolder():
                r = 0
                for c in item.children():
                    r += itemWidth(c)
                return r or TEXT_WIDTH
            else:
                return TEXT_WIDTH

        def listItems(item, rect, level=0):
            delta = 0
            for child in item.children():
                w = itemWidth(child)

                if child.isFolder():
                    parent = addRectText(delta, w, rect, child.title(), level, tooltip=child.title())
                    parent.setToolTip(references.tooltip(references.textReference(child.ID())))
                    listItems(child, parent, level + 1)

                else:
                    rectChild = addRectText(delta, TEXT_WIDTH, rect, "", level, tooltip=child.title())
                    rectChild.setToolTip(references.tooltip(references.textReference(child.ID())))
                    
                    # Find tracked references in that scene (or parent folders)
                    for ref in trackedItems:

                        result = []

                        # Tests if POV
                        scenePOV = False  # Will hold true of character is POV of the current text, not containing folder
                        if references.type(ref) == references.CharacterLetter:
                            ID = references.ID(ref)
                            c = child
                            while c:
                                if c.POV() == ID:
                                    result.append(c.ID())
                                    if c == child: scenePOV = True
                                c = c.parent()

                        # Search in notes/references
                        c = child
                        while c:
                            result += references.findReferencesTo(ref, c, recursive=False)
                            c = c.parent()

                        if result:
                            ref2 = result[0]
                            
                            # Create a RefCircle with the reference
                            c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2, important=scenePOV)
                            
                            # Store it, with the position of that item, to display it on the line later on
                            refCircles.append((ref, c, rect.mapToItem(outline, rectChild.pos())))

                delta += w

        listItems(root, outline)

        OUTLINE_WIDTH = itemWidth(root)

        # Add Tracked items
        i = 0
        itemsRect = s.addRect(0, 0, 0, 0)
        itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING)

        # Set of colors for plots (as long as they don't have their own colors)
        colors = [
            "#D97777", "#AE5F8C", "#D9A377", "#FFC2C2", "#FFDEC2", "#D2A0BC",
            "#7B0F0F", "#7B400F", "#620C3D", "#AA3939", "#AA6C39", "#882D61",
            "#4C0000", "#4C2200", "#3D0022",
        ]

        for ref in trackedItems:
            if references.type(ref) == references.CharacterLetter:
                color = self._mdlCharacter.getCharacterByID(references.ID(ref)).color()
            else:
                color = QColor(colors[i % len(colors)])

            # Rect
            r = QGraphicsRectItem(0, 0, TITLE_WIDTH, LINE_HEIGHT, itemsRect)
            r.setPen(QPen(Qt.NoPen))
            r.setBrush(QBrush(color))
            r.setPos(0, i * LINE_HEIGHT + i * SPACING)
            r.setToolTip(references.tooltip(ref))
            i += 1

            # Text
            name = references.title(ref)
            txt = QGraphicsSimpleTextItem(name, r)
            txt.setPos(r.boundingRect().center() - txt.boundingRect().center())

            # Line
            line = PlotLine(0, 0,
                            OUTLINE_WIDTH + SPACING, 0)
            line.setPos(TITLE_WIDTH, r.mapToScene(r.rect().center()).y())
            s.addItem(line)
            line.setPen(QPen(color, 5))
            line.setToolTip(references.tooltip(ref))

            # We add the circles / references to text, on the line
            for ref2, circle, pos in refCircles:
                if ref2 == ref:
                    circle.setParentItem(line)
                    circle.setPos(pos.x(), 0)

        # self.view.fitInView(0, 0, TOTAL_WIDTH, i * LINE_HEIGHT, Qt.KeepAspectRatioByExpanding) # KeepAspectRatio
        self.view.setSceneRect(0, 0, 0, 0)
class ActiveSliceItem(QGraphicsRectItem):
    """ActiveSliceItem for the Path View"""

    def __init__(self, part_item, active_base_index):
        super(ActiveSliceItem, self).__init__(part_item)
        self._part_item = part_item
        self._getActiveTool = part_item._getActiveTool
        self._active_slice = 0
        self._low_drag_bound = 0
        self._high_drag_bound = self.part().maxBaseIdx()
        self._controller = ActiveSliceItemController(self, part_item.part())

        self._label = QGraphicsSimpleTextItem("", parent=self)
        self._label.setPos(0, -18)
        self._label.setFont(_FONT)
        self._label.setBrush(_LABEL_BRUSH)
        self._label.hide()

        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setAcceptHoverEvents(True)
        self.setZValue(styles.ZACTIVESLICEHANDLE)
        self.setRect(QRectF(0, 0, _BASE_WIDTH,\
                      self._part_item.boundingRect().height()))
        self.setPos(active_base_index*_BASE_WIDTH, 0)
        self.setBrush(_BRUSH)
        self.setPen(_PEN)

        # reuse select tool methods for other tools
        self.addSeqToolMousePress = self.selectToolMousePress
        self.addSeqToolMouseMove = self.selectToolMouseMove
        self.breakToolMousePress = self.selectToolMousePress
        self.breakToolMouseMove = self.selectToolMouseMove
        self.insertionToolMousePress = self.selectToolMousePress
        self.insertionToolMouseMove = self.selectToolMouseMove
        self.paintToolMousePress = self.selectToolMousePress
        self.paintToolMouseMove = self.selectToolMouseMove
        self.pencilToolMousePress = self.selectToolMousePress
        self.pencilToolMouseMove = self.selectToolMouseMove
        self.skipToolMousePress = self.selectToolMousePress
        self.skipToolMouseMove = self.selectToolMouseMove
    # end def

    ### SLOTS ###
    def strandChangedSlot(self, sender, vh):
        pass
    # end def

    def updateRectSlot(self, part):
        bw = _BASE_WIDTH
        new_rect = QRectF(0, 0, bw,\
                    self._part_item.virtualHelixBoundingRect().height())
        if new_rect != self.rect():
            self.setRect(new_rect)
        self._hideIfEmptySelection()
        self.updateIndexSlot(part, part.activeBaseIndex())
        return new_rect
    # end def

    def updateIndexSlot(self, part, base_index):
        """The slot that receives active slice changed notifications from
        the part and changes the receiver to reflect the part"""
        label = self._label
        bw = _BASE_WIDTH
        bi = util.clamp(int(base_index), 0, self.part().maxBaseIdx())
        self.setPos(bi * bw, -styles.PATH_HELIX_PADDING)
        self._active_slice = bi
        if label:
            label.setText("%d" % bi)
            label.setX((bw - label.boundingRect().width()) / 2)
    # end def

    ### ACCESSORS ###
    def activeBaseIndex(self):
        return self.part().activeBaseIndex()
    # end def

    def part(self):
        return self._part_item.part()
    # end def

    def partItem(self):
        return self._part_item
    # end def

    ### PUBLIC METHODS FOR DRAWING / LAYOUT ###
    def removed(self):
        scene = self.scene()
        scene.removeItem(self._label)
        scene.removeItem(self)
        self._part_item = None
        self._label = None
        self._controller.disconnectSignals()
        self.controller = None
    # end def

    def resetBounds(self):
        """Call after resizing virtualhelix canvas."""
        self._high_drag_bound = self.part().maxBaseIdx()
    # end def

    ### PRIVATE SUPPORT METHODS ###
    def _hideIfEmptySelection(self):
        vis = self.part().numberOfVirtualHelices() > 0
        self.setVisible(vis)
        self._label.setVisible(vis)
    # end def

    def _setActiveBaseIndex(self, base_index):
        self.part().setActiveBaseIndex(base_index)
    # end def

    ### EVENT HANDLERS ###
    def hoverEnterEvent(self, event):
        self.setCursor(Qt.OpenHandCursor)
        self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex())
        QGraphicsItem.hoverEnterEvent(self, event)
    # end def

    def hoverLeaveEvent(self, event):
        self.setCursor(Qt.ArrowCursor)
        self._part_item.updateStatusBar("")
        QGraphicsItem.hoverLeaveEvent(self, event)
    # end def

    def mousePressEvent(self, event):
        """
        Parses a mousePressEvent, calling the approproate tool method as
        necessary. Stores _move_idx for future comparison.
        """
        if event.button() != Qt.LeftButton:
            event.ignore()
            QGraphicsItem.mousePressEvent(self, event)
            return
        self.scene().views()[0].addToPressList(self)
        self._move_idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH))
        tool_method_name = self._getActiveTool().methodPrefix() + "MousePress"
        if hasattr(self, tool_method_name):  # if the tool method exists
            modifiers = event.modifiers()
            getattr(self, tool_method_name)(modifiers)  # call tool method

    def mouseMoveEvent(self, event):
        """
        Parses a mouseMoveEvent, calling the approproate tool method as
        necessary. Updates _move_idx if it changed.
        """
        tool_method_name = self._getActiveTool().methodPrefix() + "MouseMove"
        if hasattr(self, tool_method_name):  # if the tool method exists
            idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH))
            if idx != self._move_idx:  # did we actually move?
                modifiers = event.modifiers()
                self._move_idx = idx
                getattr(self, tool_method_name)(modifiers, idx)  # call tool method

    def customMouseRelease(self, event):
        """
        Parses a mouseReleaseEvent, calling the approproate tool method as
        necessary. Deletes _move_idx if necessary.
        """
        tool_method_name = self._getActiveTool().methodPrefix() + "MouseRelease"
        if hasattr(self, tool_method_name):  # if the tool method exists
            modifiers = event.modifiers()
            x = event.pos().x()
            getattr(self, tool_method_name)(modifiers, x)  # call tool method
        if hasattr(self, '_move_idx'):
            del self._move_idx

    ### TOOL METHODS ###
    def selectToolMousePress(self, modifiers):
        """
        Set the allowed drag bounds for use by selectToolMouseMove.
        """
        if (modifiers & Qt.AltModifier) and (modifiers & Qt.ShiftModifier):
            self.part().undoStack().beginMacro("Auto-drag Scaffold(s)")
            for vh in self.part().getVirtualHelices():
                # SCAFFOLD
                # resize 3' first
                for strand in vh.scaffoldStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx3p):
                        lo, hi = strand.getResizeBounds(idx3p)
                        if strand.isDrawn5to3():
                            strand.resize((idx5p, hi))
                        else:
                            strand.resize((lo, idx5p))
                # resize 5' second
                for strand in vh.scaffoldStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx5p):
                        lo, hi = strand.getResizeBounds(idx5p)
                        if strand.isDrawn5to3():
                            strand.resize((lo, idx3p))
                        else:
                            strand.resize((idx3p, hi))
                # STAPLE
                # resize 3' first
                for strand in vh.stapleStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx3p):
                        lo, hi = strand.getResizeBounds(idx3p)
                        if strand.isDrawn5to3():
                            strand.resize((idx5p, hi))
                        else:
                            strand.resize((lo, idx5p))
                # resize 5' second
                for strand in vh.stapleStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx3p):
                        lo, hi = strand.getResizeBounds(idx5p)
                        if strand.isDrawn5to3():
                            strand.resize((lo, idx3p))
                        else:
                            strand.resize((idx3p, hi))

            self.part().undoStack().endMacro()
    # end def

    def selectToolMouseMove(self, modifiers, idx):
        """
        Given a new index (pre-validated as different from the prev index),
        calculate the new x coordinate for self, move there, and notify the
        parent strandItem to redraw its horizontal line.
        """
        idx = util.clamp(idx, self._low_drag_bound, self._high_drag_bound)
        x = int(idx * _BASE_WIDTH)
        self.setPos(x, self.y())
        self.updateIndexSlot(None, idx)
        self._setActiveBaseIndex(idx)
        self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex())
Exemple #41
0
class CalendarDesklet(Desklet):

    def __init__(self):
        super().__init__()

        self.model = CalendarModel()

        self.cursor_pos = None

        self.cursor = QGraphicsRectItem(self.root)
        self.header = QGraphicsSimpleTextItem(self.root)

        self.weekdays = []
        days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
        for day in days:
            self.weekdays.append(QGraphicsSimpleTextItem(day, self.root))

        self.header_line = QGraphicsLineItem(self.root)

        self.days = []
        for _ in range(0, 6 * 7):
            self.days.append(QGraphicsSimpleTextItem(self.root))

    def next_month(self):
        self.model.next_month()
        self.layout()

    def previous_month(self):
        self.model.previous_month()
        self.layout()

    def set_rect(self, rect):
        super().set_rect(rect)
        self.layout()

    def set_style(self, style):
        super().set_style(style)

        font = QFont(style.font)
        font.setPixelSize(48)
        self.header.setBrush(style.midcolor)
        self.header.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(32)

        self.header_line.setPen(style.foreground_color)

        self.cursor.setBrush(style.midcolor)
        self.cursor.setPen(QPen(Qt.NoPen))

        for widget in self.weekdays:
            widget.setFont(font)
            widget.setBrush(style.foreground_color)

        for widget in self.days:
            widget.setFont(font)
            widget.setBrush(self.style.foreground_color)

        self.layout()

    def layout(self):
        cell_width = (self.rect.width()) / 7.0
        cell_height = (self.rect.height() - 64) / 7.0

        x = self.rect.left()
        y = self.rect.top()

        fm = QFontMetrics(self.header.font())
        rect = fm.boundingRect(self.header.text())
        self.header.setPos(x + self.rect.width() / 2 - rect.width() / 2,
                           y)

        y += fm.height()

        for row, day in enumerate(self.weekdays):
            fm = QFontMetrics(day.font())
            rect = fm.boundingRect(day.text())
            day.setPos(x + row * cell_width + cell_width / 2 - rect.width() / 2,
                       y)

        y += fm.height()
        self.header_line.setLine(x, y,
                                 x + self.rect.width() - 3, y)

        y += 8

        for n, widget in enumerate(self.days):
            col = n % 7
            row = n // 7

            rect = fm.boundingRect(widget.text())
            widget.setPos(x + col * cell_width + cell_width / 2 - rect.width() / 2,
                          y + row * cell_height + cell_height / 2 - fm.height() / 2)

            # if day.month != self.now.month:
            #    widget.setBrush(self.style.midcolor)
            # else:

        if self.cursor_pos is not None:
            self.cursor.setRect(x + self.cursor_pos[0] * cell_width,
                                y + self.cursor_pos[1] * cell_height,
                                cell_width,
                                cell_height)
            self.cursor.show()
        else:
            self.cursor.hide()

    def update(self, now):
        self.model.update(now)

        # update header
        self.header.setText(
            date(self.model.year, self.model.month, 1).strftime("%B %Y"))

        # calculate the date of the top/left calendar entry
        current_date = date(self.model.year, self.model.month, 1)
        current_date = current_date - timedelta(current_date.weekday())

        self.cursor_pos = None
        for n, widget in enumerate(self.days):
            col = n % 7
            row = n // 7

            if current_date == self.model.today:
                self.cursor_pos = (col, row)

            widget.setText("%d" % current_date.day)
            self.days[n] = widget
            current_date += timedelta(days=1)

        self.layout()