Exemplo n.º 1
0
    def __init__(self, parent=None):
        QGraphicsView.__init__(self, parent)

        self.scene = QGraphicsScene(self)
        self.scene.setBackgroundBrush(Qt.yellow)
        self.setScene(self.scene)

        center_rect = QGraphicsRectItem(-10, -10, 20, 20)
        self.scene.addItem(center_rect)

        rect = QGraphicsRectItem(0, 0, 100, 100)
        rect.setPos(-100, -100)
        self.scene.addItem(rect)

        rect2 = QGraphicsRectItem(0, 0, 100, 100)
        self.scene.addItem(rect2)

        text = self.scene.addText("Hello WOrld")

        # self.scene.addLine(QLineF(0, 10, -20, -20), QPen(Qt.black))

        rect2.moveBy(50, 50)
        rect2.setRotation(50)
        rect2.moveBy(-50, -50)

        print(self.scene.width(), self.scene.height())

        self.resize(400, 400)
Exemplo n.º 2
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)
Exemplo n.º 3
0
    def makeRoad(self, parent):
        self.line_space = (parent.height() / (LINE_COUNT - 2)) - LINE_H

        bg = QGraphicsRectItem()
        bg.setRect(0, 0, parent.width(), parent.height())
        bg.setBrush(QBrush(Qt.gray))
        self.scene.addItem(bg)

        self.lines = []
        self.topLineIndex = 0
        ax = (parent.width() / 2) - (LINE_W / 2)

        for i in range(LINE_COUNT):
            line = QGraphicsRectItem()
            ay = (i - 1) * (LINE_H + self.line_space)
            line.setRect(0, 0, LINE_W, LINE_H)
            line.setPos(ax, ay)
            line.setBrush(QBrush(Qt.white))
            self.scene.addItem(line)
            self.lines.append(line)
        """ Because of the lines, the scene isn't in the middle """
        """ So we add an extra rectangle to center the scene """
        spaceFill = QGraphicsRectItem()
        ay = (LINE_COUNT - 1) * (LINE_H + self.line_space) - self.line_space
        spaceFill.setRect(ax, ay, LINE_W, self.line_space)
        self.scene.addItem(spaceFill)

        self.setFixedSize(parent.width(), parent.height())
Exemplo n.º 4
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)
Exemplo n.º 5
0
    def create_scene_tile(self, x: int, y: int, tile) -> QGraphicsItem:
        x, y = self.pos_to_scene(x, y)

        width  = 2 * qt_drawings.tile_size if tile.is_horizontal else qt_drawings.tile_size
        height = qt_drawings.tile_size if tile.is_horizontal else 2 * qt_drawings.tile_size
        item = QGraphicsRectItem(0, 0, width, height)
        item.setPos(x, y)
        item.setBrush(qt_drawings.tile_to_brush(tile))
        item.setPen(qt_drawings.black_pen)

        self.scene.addItem(item)

        return item
Exemplo n.º 6
0
    def display_current(self):
        """Create a rectangle showing the current window."""
        if self.idx_current in self.scene.items():
            self.scene.removeItem(self.idx_current)

        item = QGraphicsRectItem(0, CURR['pos0'],
                                 self.parent.value('window_length'),
                                 CURR['pos1'])
        # it's necessary to create rect first, and then move it
        item.setPos(self.parent.value('window_start'), 0)
        item.setPen(QPen(Qt.lightGray))
        item.setBrush(QBrush(Qt.lightGray))
        item.setZValue(-10)
        self.scene.addItem(item)
        self.idx_current = item
Exemplo n.º 7
0
    def display_current(self):
        """Create a rectangle showing the current window."""
        if self.idx_current in self.scene.items():
            self.scene.removeItem(self.idx_current)

        item = QGraphicsRectItem(0,
                                 CURR['pos0'],
                                 self.parent.value('window_length'),
                                 CURR['pos1'])
        # it's necessary to create rect first, and then move it
        item.setPos(self.parent.value('window_start'), 0)
        item.setPen(QPen(Qt.lightGray))
        item.setBrush(QBrush(Qt.lightGray))
        item.setZValue(-10)
        self.scene.addItem(item)
        self.idx_current = item
Exemplo n.º 8
0
class AnimatedClock():
    updateTimer = None
    calDataLock = threading.Lock()
    calDataUpdated = False
    curCalendars = None
    
    def __init__(self, scene, widthClkTextArea, heightClkTextArea, borders, updateSecs):
        self.masterScene = scene
        self.widthClkTextArea = widthClkTextArea
        self.heightClkTextArea = heightClkTextArea
        self.borders = borders
        self.updateSecs = updateSecs
        # Background
        self.textBkgd = QGraphicsRectItem(0, 0, self.widthClkTextArea, self.heightClkTextArea)
        self.textBkgd.setPos(self.borders[3], self.borders[0])
        self.textBkgd.setBrush(QColor("light green"))
        self.textBkgd.setZValue(10)
        scene.addItem(self.textBkgd)
        # Text Item
        self.textItem = QGraphicsTextItem()
        self.textItem.setFont(QFont("Segoe UI", 80))
        self.textItem.setDefaultTextColor(QColor("black"))
        self.textItem.setPos(QPointF(self.borders[3]+10,self.borders[0]+5))
        self.textItem.setHtml("<B>Clock</B>")
        self.textItem.setZValue(20)
        self.textItem.setTextWidth(self.widthClkTextArea-20)
        scene.addItem(self.textItem)
        
    def start(self):
        self.updateTimer = QTimer()
        self.updateTimer.setInterval(self.updateSecs * 1000)
        self.updateTimer.timeout.connect(self.updateClock)
        self.updateTimer.start()

    def stop (self):
        if self.updateTimer != None:
            self.updateTimer.stop()
    
    def updateClock(self):
        localtime = time.localtime()
#        dateString  = time.strftime("%a %d %b %Y", localtime)
        timeString  = time.strftime("%H:%M:%S", localtime)
        self.textItem.setHtml(timeString)
#        self.textItem.setTextWidth(self.widthCalTextArea-20)
        self.textItem.update()
Exemplo n.º 9
0
    def on_actItem_Rect(self):  # 添加一个矩形  _triggered
        rect = QRectF(-50, -25, 100, 50)
        item = QGraphicsRectItem(rect)  # x,y 为左上角的图元局部坐标,图元中心点为0,0
        item.rect = rect
        item.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable)
        item.brush = Qt.yellow
        item.setBrush(QBrush(item.brush))
        item.style = Qt.SolidLine
        #item.setTransform(QTransform())
        self.view.frontZ = self.view.frontZ + 1
        item.setZValue(self.view.frontZ)
        item.setPos(-50 + (QtCore.qrand() % 100), -50 + (QtCore.qrand() % 100))
        self.view.seqNum = self.view.seqNum + 1
        item.setData(self.view.ItemId, self.view.seqNum)
        item.setData(self.view.ItemDesciption, "矩形")

        self.scene.addItem(item)
        self.scene.clearSelection()
        item.setSelected(True)
Exemplo n.º 10
0
 def add_game_grid(self):
     '''
     Adds an QGraphicsItem for each square in the game.
     Qt uses QGraphicsItems to draw objects in the QGraphicsScene.
     QGraphicsRectItem is a subclass of QGraphicsItem, and is useful for
     easily drawing rectangular items.
     This method should only be called once, otherwise it creates duplicates!
     '''
     x = 0
     y = 0
     for i in range(self.game.get_width()):
         for j in range(self.game.get_height()):
             new_square = QGraphicsRectItem(0, 0, self.square_size,
                                            self.square_size)
             new_square.setPos(x, y)
             self.square_graphics.append(new_square)
             self.scene.addItem(new_square)
             y += self.square_size
         x += self.square_size
         y = 0
Exemplo n.º 11
0
    def __init__(self, scene):
        super(Setbuttons, self).__init__()

        self.scene = scene
        self.buttons = {}  # Register of buttons as {name: button}

        buttonParent = QGraphicsRectItem()
        buttonParent.persistent = True

        self.playButton, self.acceptButton, self.passButton = None, None, None
        self.challengeButton, self.exchangeButton, self.quitButton = None, None, None
        self.nextButton, self.backButton, self.endButton, self.newButton = None, None, None, None

        self.setup_buttons(buttonParent)
        self.set_button_pos()
        # self.reset_tips()
        self.scene.addItem(buttonParent)
        buttonParent.setScale(0.75)
        buttonParent.setPos(200, 200)
        buttonParent.setZValue(65)
Exemplo n.º 12
0
    def __init__(self, scene):
        super(Setbuttons, self).__init__()

        self.scene = scene
        self.buttons = {}  # Register of buttons as {name: button}

        self.setupButton, self.checkButton, self.loadButton, self.saveButton = None, None, None, None
        self.clearButton, self.playButton, self.printButton, self.solveButton = None, None, None, None
        self.printButton, self.solveButton, self.stepButton, self.quitButton = None, None, None, None
        self.hintButton, self.restartButton = None, None

        buttonParent = QGraphicsRectItem()
        self.playButton = None
        self.checkButton = None
        self.setup_buttons(buttonParent)
        self.set_button_pos()
        self.reset_tips()
        buttonParent.setScale(0.75)
        buttonParent.setPos(Cons.BUTTON_X, Cons.BUTTON_Y)
        buttonParent.setZValue(65)
        self.scene.addItem(buttonParent)
Exemplo n.º 13
0
    def display_markers(self):
        """Add markers on top of first plot."""
        for item in self.idx_markers:
            self.scene.removeItem(item)
        self.idx_markers = []

        window_start = self.parent.value('window_start')
        window_length = self.parent.value('window_length')
        window_end = window_start + window_length
        y_distance = self.parent.value('y_distance')

        markers = []
        if self.parent.info.markers is not None:
            if self.parent.value('marker_show'):
                markers = self.parent.info.markers

        for mrk in markers:
            if window_start <= mrk['end'] and window_end >= mrk['start']:

                mrk_start = max((mrk['start'], window_start))
                mrk_end = min((mrk['end'], window_end))
                color = QColor(self.parent.value('marker_color'))

                item = QGraphicsRectItem(mrk_start, 0,
                                         mrk_end - mrk_start,
                                         len(self.idx_label) * y_distance)
                item.setPen(color)
                item.setBrush(color)
                item.setZValue(-9)
                self.scene.addItem(item)

                item = TextItem_with_BG(color.darker(200))
                item.setText(mrk['name'])
                item.setPos(mrk['start'],
                            len(self.idx_label) *
                            self.parent.value('y_distance'))
                item.setFlag(QGraphicsItem.ItemIgnoresTransformations)
                item.setRotation(-90)
                self.scene.addItem(item)
                self.idx_markers.append(item)
Exemplo n.º 14
0
    def display_markers(self):
        """Add markers on top of first plot."""
        for item in self.idx_markers:
            self.scene.removeItem(item)
        self.idx_markers = []

        window_start = self.parent.value('window_start')
        window_length = self.parent.value('window_length')
        window_end = window_start + window_length
        y_distance = self.parent.value('y_distance')

        markers = []
        if self.parent.info.markers is not None:
            if self.parent.value('marker_show'):
                markers = self.parent.info.markers

        for mrk in markers:
            if window_start <= mrk['end'] and window_end >= mrk['start']:

                mrk_start = max((mrk['start'], window_start))
                mrk_end = min((mrk['end'], window_end))
                color = QColor(self.parent.value('marker_color'))

                item = QGraphicsRectItem(mrk_start, 0,
                                         mrk_end - mrk_start,
                                         len(self.idx_label) * y_distance)
                item.setPen(color)
                item.setBrush(color)
                item.setZValue(-9)
                self.scene.addItem(item)

                item = TextItem_with_BG(color.darker(200))
                item.setText(mrk['name'])
                item.setPos(mrk['start'],
                            len(self.idx_label) *
                            self.parent.value('y_distance'))
                item.setFlag(QGraphicsItem.ItemIgnoresTransformations)
                item.setRotation(-90)
                self.scene.addItem(item)
                self.idx_markers.append(item)
Exemplo n.º 15
0
    def __init__(self, simu, f, motion_manager):
        """AircraftItem constructor, creates the ellipse and adds to the scene"""
        super().__init__(None)
        self.setZValue(radarview.PLOT_Z_VALUE)

        # instance variables
        self.motion_manager = motion_manager
        self.flight = f
        self.simulation = simu

        # list to store the comet elements as ellipses
        self.comete = []

        # create the tooltip
        tooltip = f.type.name + ' ' + f.call_sign + ' ' + f.qfu

        time = self.simulation.t
        for (idx, ti) in enumerate(range(time - 4, time + 1)):
            if idx < 4:
                item = QGraphicsRectItem()
                item.setPen(DEP_PEN if self.flight.type ==
                            traffic.Movement.DEP else ARR_PEN)
            else:
                item = QGraphicsEllipseItem()
                item.setBrush(DEP_BRUSH if self.flight.type ==
                              traffic.Movement.DEP else ARR_BRUSH)
                item.setToolTip(tooltip)

            self.comete.append(item)
            self.addToGroup(item)
            position = self.flight.get_position(ti)
            item.setPos(position.x, position.y)

        # compute the width of each element
        self.update_size()
        # connect to ask_inspection_signal in order to toggle_highlight this item
        self.motion_manager.radarView.ask_inspection_signal.connect(
            self.toggle_highlight)
Exemplo n.º 16
0
class Square(QGraphicsView):

    def __init__(self, x, y, a, b):
        self.x = x
        self.y = y
        self.a = a
        self.b = b
        self.square = QGraphicsRectItem(self.x, self.y, self.a, self.b)

    def draw_square(self, scene):
        scene.addItem(self.square)

    def move_square(self, m, n):
        self.square.setPos(m, n)

    def rotate_square(self, r):
        self.square.setRotation(r)

    def scale_square(self, s):
        self.square.setScale((s + 50) / 100)

    def recolor_square(self, r, g, b):
        self.square.setBrush(QColor(r, g, b))
Exemplo n.º 17
0
class ForcedXoverNode3(QGraphicsRectItem):
    """
    This is a QGraphicsRectItem to allow actions and also a 
    QGraphicsSimpleTextItem to allow a label to be drawn
    """
    def __init__(self, virtual_helix_item, xover_item, strand3p, idx):
        super(ForcedXoverNode3, self).__init__(virtual_helix_item)
        self._vhi = virtual_helix_item
        self._xover_item = xover_item
        self._idx = idx
        self._is_on_top = virtual_helix_item.isStrandOnTop(strand3p)
        self._is_drawn_5_to_3 = strand3p.strandSet().isDrawn5to3()
        self._strand_type = strand3p.strandSet().strandType()

        self._partner_virtual_helix = virtual_helix_item

        self._blank_thing = QGraphicsRectItem(_blankRect, self)
        self._blank_thing.setBrush(QBrush(Qt.white))
        self._path_thing = QGraphicsPathItem(self)
        self.configurePath()

        self.setPen(_NO_PEN)
        self._label = None
        self.setPen(_NO_PEN)
        self.setBrush(_NO_BRUSH)
        self.setRect(_rect)

        self.setZValue(styles.ZENDPOINTITEM + 1)
    # end def

    def updateForFloatFromVHI(self, virtual_helix_item, strand_type, idx_x, idx_y):
        """

        """
        self._vhi = virtual_helix_item
        self.setParentItem(virtual_helix_item)
        self._strand_type = strand_type
        self._idx = idx_x
        self._is_on_top = self._is_drawn_5_to_3 = True if idx_y == 0 else False
        self.updatePositionAndAppearance(is_from_strand=False)
    # end def

    def updateForFloatFromStrand(self, virtual_helix_item, strand3p, idx):
        """

        """
        self._vhi = virtual_helix_item
        self._strand = strand3p
        self.setParentItem(virtual_helix_item)
        self._idx = idx
        self._is_on_top = virtual_helix_item.isStrandOnTop(strand3p)
        self._is_drawn_5_to_3 = strand3p.strandSet().isDrawn5to3()
        self._strand_type = strand3p.strandSet().strandType()
        self.updatePositionAndAppearance()
    # end def

    def strandType(self):
        return self._strand_type
    # end def

    def configurePath(self):
        self._path_thing.setBrush(QBrush(styles.RED_STROKE))
        path = PPR3 if self._is_drawn_5_to_3 else PPL3
        offset = -_BASE_WIDTH if self._is_drawn_5_to_3 else _BASE_WIDTH
        self._path_thing.setPath(path)
        self._path_thing.setPos(offset, 0)

        offset = -_BASE_WIDTH if self._is_drawn_5_to_3 else 0
        self._blank_thing.setPos(offset, 0)

        self._blank_thing.show()
        self._path_thing.show()
    # end def

    def refreshXover(self):
        self._xover_item.refreshXover()
    # end def

    def setPartnerVirtualHelix(self, virtual_helix_item):
        self._partner_virtual_helix = virtual_helix_item
    # end def

    def idx(self):
        return self._idx
    # end def

    def virtualHelixItem(self):
        return self._vhi
    # end def

    def point(self):
        return self._vhi.upperLeftCornerOfBaseType(self._idx, self._strand_type)
    # end def

    def floatPoint(self):
        pt = self.pos()
        return pt.x(), pt.y()
    # end def

    def isOnTop(self):
        return self._is_on_top
    # end def

    def isDrawn5to3(self):
        return self._is_drawn_5_to_3
    # end def

    def updatePositionAndAppearance(self, is_from_strand=True):
        """
        Sets position by asking the VirtualHelixItem
        Sets appearance by choosing among pre-defined painterpaths (from
        normalstrandgraphicsitem) depending on drawing direction.
        """
        self.setPos(*self.point())
        n5 = self._xover_item._node5
        if is_from_strand:
            from_strand, from_idx = (n5._strand, n5._idx) if n5 != self else (None, None)
            if self._strand.canInstallXoverAt(self._idx, from_strand, from_idx):
                self.configurePath()
                # We can only expose a 5' end. But on which side?
                is_left = True if self._is_drawn_5_to_3 else False
                self._updateLabel(is_left)
            else:
                self.hideItems()
        else:
            self.hideItems()
    # end def

    def updateConnectivity(self):
        is_left = True if self._is_drawn_5_to_3 else False
        self._updateLabel(is_left)
    # end def

    def remove(self):
        """
        Clean up this joint
        """
        scene = self.scene()
        scene.removeItem(self._label)
        self._label = None
        scene.removeItem(self._path_thing)
        self._path_thing = None
        scene.removeItem(self._blank_thing)
        self._blank_thing = None
        scene.removeItem(self)
    # end def

    def _updateLabel(self, is_left):
        """
        Called by updatePositionAndAppearance during init, or later by
        updateConnectivity. Updates drawing and position of the label.
        """
        lbl = self._label
        if self._idx != 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
            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 == 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.number()) )
            lbl.show()
        # end if
    # end def

    def hideItems(self):
        if self._label:
            self._label.hide()
        if self._blank_thing:
            self._path_thing.hide()
        if self._blank_thing:
            self._blank_thing.hide()
Exemplo n.º 18
0
class PianoRoll(QGraphicsScene):
    '''the piano roll'''

    midievent = pyqtSignal(list)
    measureupdate = pyqtSignal(int)
    modeupdate = pyqtSignal(str)

    def __init__(self, time_sig='4/4', num_measures=4, quantize_val='1/8'):
        QGraphicsScene.__init__(self)
        self.setBackgroundBrush(QColor(50, 50, 50))
        self.mousePos = QPointF()

        self.notes = []
        self.selected_notes = []
        self.piano_keys = []

        self.marquee_select = False
        self.insert_mode = False
        self.velocity_mode = False
        self.place_ghost = False
        self.ghost_note = None
        self.default_ghost_vel = 100
        self.ghost_vel = self.default_ghost_vel

        ## dimensions
        self.padding = 2

        ## piano dimensions
        self.note_height = 10
        self.start_octave = -2
        self.end_octave = 8
        self.notes_in_octave = 12
        self.total_notes = (self.end_octave - self.start_octave) \
                * self.notes_in_octave + 1
        self.piano_height = self.note_height * self.total_notes
        self.octave_height = self.notes_in_octave * self.note_height

        self.piano_width = 34

        ## height
        self.header_height = 20
        self.total_height = self.piano_height - self.note_height + self.header_height
        #not sure why note_height is subtracted

        ## width
        self.full_note_width = 250  # i.e. a 4/4 note
        self.snap_value = None
        self.quantize_val = quantize_val

        ### dummy vars that will be changed
        self.time_sig = 0
        self.measure_width = 0
        self.num_measures = 0
        self.max_note_length = 0
        self.grid_width = 0
        self.value_width = 0
        self.grid_div = 0
        self.piano = None
        self.header = None
        self.play_head = None

        self.setTimeSig(time_sig)
        self.setMeasures(num_measures)
        self.setGridDiv()
        self.default_length = 1. / self.grid_div

    # -------------------------------------------------------------------------
    # Callbacks

    def movePlayHead(self, transport_info):
        # TODO: need conversion between frames and PPQ
        x = 105.  # works for 120bpm
        total_duration = self.time_sig[0] * self.num_measures * x
        pos = transport_info['frame'] / x
        frac = (pos % total_duration) / total_duration
        self.play_head.setPos(QPointF(frac * self.grid_width, 0))

    def setTimeSig(self, time_sig):
        try:
            new_time_sig = list(map(float, time_sig.split('/')))
            if len(new_time_sig) == 2:
                self.time_sig = new_time_sig

                self.measure_width = self.full_note_width * self.time_sig[
                    0] / self.time_sig[1]
                self.max_note_length = self.num_measures * self.time_sig[
                    0] / self.time_sig[1]
                self.grid_width = self.measure_width * self.num_measures
                self.setGridDiv()
        except ValueError:
            pass

    def setMeasures(self, measures):
        try:
            self.num_measures = float(measures)
            self.max_note_length = self.num_measures * self.time_sig[
                0] / self.time_sig[1]
            self.grid_width = self.measure_width * self.num_measures
            self.refreshScene()
        except:
            pass

    def setDefaultLength(self, length):
        try:
            v = list(map(float, length.split('/')))
            if len(v) < 3:
                self.default_length = \
                        v[0] if len(v)==1 else \
                        v[0] / v[1]
                pos = self.enforce_bounds(self.mousePos)
                if self.insert_mode: self.makeGhostNote(pos.x(), pos.y())
        except ValueError:
            pass

    def setGridDiv(self, div=None):
        if not div: div = self.quantize_val
        try:
            val = list(map(int, div.split('/')))
            if len(val) < 3:
                self.quantize_val = div
                self.grid_div = val[0] if len(val) == 1 else val[1]
                self.value_width = self.full_note_width / float(
                    self.grid_div) if self.grid_div else None
                self.setQuantize(div)

                self.refreshScene()
        except ValueError:
            pass

    def setQuantize(self, value):
        try:
            val = list(map(float, value.split('/')))
            if len(val) == 1:
                self.quantize(val[0])
                self.quantize_val = value
            elif len(val) == 2:
                self.quantize(val[0] / val[1])
                self.quantize_val = value
        except ValueError:
            pass

    # -------------------------------------------------------------------------
    # Event Callbacks

    def keyPressEvent(self, event):
        QGraphicsScene.keyPressEvent(self, event)
        if event.key() == Qt.Key_F:
            if not self.insert_mode:
                self.velocity_mode = False
                self.insert_mode = True
                self.makeGhostNote(self.mousePos.x(), self.mousePos.y())
                self.modeupdate.emit('insert_mode')
            elif self.insert_mode:
                self.insert_mode = False
                if self.place_ghost: self.place_ghost = False
                self.removeItem(self.ghost_note)
                self.ghost_note = None
                self.modeupdate.emit('')
        elif event.key() == Qt.Key_D:
            if self.velocity_mode:
                self.velocity_mode = False
                self.modeupdate.emit('')
            else:
                if self.insert_mode:
                    self.removeItem(self.ghost_note)
                self.ghost_note = None
                self.insert_mode = False
                self.place_ghost = False
                self.velocity_mode = True
                self.modeupdate.emit('velocity_mode')
        elif event.key() == Qt.Key_A:
            if all((note.isSelected() for note in self.notes)):
                for note in self.notes:
                    note.setSelected(False)
                self.selected_notes = []
            else:
                for note in self.notes:
                    note.setSelected(True)
                self.selected_notes = self.notes[:]
        elif event.key() in (Qt.Key_Delete, Qt.Key_Backspace):
            self.notes = [
                note for note in self.notes if note not in self.selected_notes
            ]
            for note in self.selected_notes:
                self.removeItem(note)
                self.midievent.emit([
                    "midievent-remove", note.note[0], note.note[1],
                    note.note[2], note.note[3]
                ])
                del note
            self.selected_notes = []

    def mousePressEvent(self, event):
        QGraphicsScene.mousePressEvent(self, event)
        if not (any(key.pressed for key in self.piano_keys)
                or any(note.pressed for note in self.notes)):
            for note in self.selected_notes:
                note.setSelected(False)
            self.selected_notes = []

            if event.button() == Qt.LeftButton:
                if self.insert_mode:
                    self.place_ghost = True
                else:
                    self.marquee_select = True
                    self.marquee_rect = QRectF(event.scenePos().x(),
                                               event.scenePos().y(), 1, 1)
                    self.marquee = QGraphicsRectItem(self.marquee_rect)
                    self.marquee.setBrush(QColor(255, 255, 255, 100))
                    self.addItem(self.marquee)
        else:
            for s_note in self.notes:
                if s_note.pressed and s_note in self.selected_notes:
                    break
                elif s_note.pressed and s_note not in self.selected_notes:
                    for note in self.selected_notes:
                        note.setSelected(False)
                    self.selected_notes = [s_note]
                    break
            for note in self.selected_notes:
                if not self.velocity_mode:
                    note.mousePressEvent(event)

    def mouseMoveEvent(self, event):
        QGraphicsScene.mouseMoveEvent(self, event)
        self.mousePos = event.scenePos()
        if not (any((key.pressed for key in self.piano_keys))):
            m_pos = event.scenePos()
            if self.insert_mode and self.place_ghost:  #placing a note
                m_width = self.ghost_rect.x() + self.ghost_rect_orig_width
                if m_pos.x() > m_width:
                    m_new_x = self.snap(m_pos.x())
                    self.ghost_rect.setRight(m_new_x)
                    self.ghost_note.setRect(self.ghost_rect)
                #self.adjust_note_vel(event)
            else:
                m_pos = self.enforce_bounds(m_pos)

                if self.insert_mode:  #ghostnote follows mouse around
                    (m_new_x, m_new_y) = self.snap(m_pos.x(), m_pos.y())
                    self.ghost_rect.moveTo(m_new_x, m_new_y)
                    try:
                        self.ghost_note.setRect(self.ghost_rect)
                    except RuntimeError:
                        self.ghost_note = None
                        self.makeGhostNote(m_new_x, m_new_y)

                elif self.marquee_select:
                    marquee_orig_pos = event.buttonDownScenePos(Qt.LeftButton)
                    if marquee_orig_pos.x() < m_pos.x() and marquee_orig_pos.y(
                    ) < m_pos.y():
                        self.marquee_rect.setBottomRight(m_pos)
                    elif marquee_orig_pos.x() < m_pos.x(
                    ) and marquee_orig_pos.y() > m_pos.y():
                        self.marquee_rect.setTopRight(m_pos)
                    elif marquee_orig_pos.x() > m_pos.x(
                    ) and marquee_orig_pos.y() < m_pos.y():
                        self.marquee_rect.setBottomLeft(m_pos)
                    elif marquee_orig_pos.x() > m_pos.x(
                    ) and marquee_orig_pos.y() > m_pos.y():
                        self.marquee_rect.setTopLeft(m_pos)
                    self.marquee.setRect(self.marquee_rect)
                    self.selected_notes = []
                    for item in self.collidingItems(self.marquee):
                        if item in self.notes:
                            self.selected_notes.append(item)

                    for note in self.notes:
                        if note in self.selected_notes: note.setSelected(True)
                        else: note.setSelected(False)

                elif self.velocity_mode:
                    if Qt.LeftButton == event.buttons():
                        for note in self.selected_notes:
                            note.updateVelocity(event)

                elif not self.marquee_select:  #move selected
                    if Qt.LeftButton == event.buttons():
                        x = y = False
                        if any(note.back.stretch
                               for note in self.selected_notes):
                            x = True
                        elif any(note.front.stretch
                                 for note in self.selected_notes):
                            y = True
                        for note in self.selected_notes:
                            note.back.stretch = x
                            note.front.stretch = y
                            note.moveEvent(event)

    def mouseReleaseEvent(self, event):
        if not (any((key.pressed for key in self.piano_keys)) or any(
            (note.pressed for note in self.notes))):
            if event.button() == Qt.LeftButton:
                if self.place_ghost and self.insert_mode:
                    self.place_ghost = False
                    note_start = self.get_note_start_from_x(
                        self.ghost_rect.x())
                    note_num = self.get_note_num_from_y(self.ghost_rect.y())
                    note_length = self.get_note_length_from_x(
                        self.ghost_rect.width())
                    self.drawNote(note_num, note_start, note_length,
                                  self.ghost_vel)
                    self.midievent.emit([
                        "midievent-add", note_num, note_start, note_length,
                        self.ghost_vel
                    ])
                    self.makeGhostNote(self.mousePos.x(), self.mousePos.y())
                elif self.marquee_select:
                    self.marquee_select = False
                    self.removeItem(self.marquee)
        elif not self.marquee_select:
            for note in self.selected_notes:
                old_info = note.note[:]
                note.mouseReleaseEvent(event)
                if self.velocity_mode:
                    note.setSelected(True)
                if not old_info == note.note:
                    self.midievent.emit([
                        "midievent-remove", old_info[0], old_info[1],
                        old_info[2], old_info[3]
                    ])
                    self.midievent.emit([
                        "midievent-add", note.note[0], note.note[1],
                        note.note[2], note.note[3]
                    ])

    # -------------------------------------------------------------------------
    # Internal Functions

    def drawHeader(self):
        self.header = QGraphicsRectItem(0, 0, self.grid_width,
                                        self.header_height)
        #self.header.setZValue(1.0)
        self.header.setPos(self.piano_width, 0)
        self.addItem(self.header)

    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)

    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)

    def drawPlayHead(self):
        self.play_head = QGraphicsLineItem(self.piano_width,
                                           self.header_height,
                                           self.piano_width, self.total_height)
        self.play_head.setPen(QPen(QColor(255, 255, 255, 50), 2))
        self.play_head.setZValue(1.)
        self.addItem(self.play_head)

    def refreshScene(self):
        list(map(self.removeItem, self.notes))
        self.selected_notes = []
        self.piano_keys = []
        self.clear()
        self.drawPiano()
        self.drawHeader()
        self.drawGrid()
        self.drawPlayHead()
        for note in self.notes[:]:
            if note.note[1] >= (self.num_measures * self.time_sig[0]):
                self.notes.remove(note)
                self.midievent.emit([
                    "midievent-remove", note.note[0], note.note[1],
                    note.note[2], note.note[3]
                ])
            elif note.note[2] > self.max_note_length:
                new_note = note.note[:]
                new_note[2] = self.max_note_length
                self.notes.remove(note)
                self.drawNote(new_note[0], new_note[1], self.max_note_length,
                              new_note[3], False)
                self.midievent.emit([
                    "midievent-remove", note.note[0], note.note[1],
                    note.note[2], note.note[3]
                ])
                self.midievent.emit([
                    "midievent-add", new_note[0], new_note[1], new_note[2],
                    new_note[3]
                ])
        list(map(self.addItem, self.notes))
        if self.views():
            self.views()[0].setSceneRect(self.itemsBoundingRect())

    def clearNotes(self):
        self.clear()
        self.notes = []
        self.selected_notes = []
        self.drawPiano()
        self.drawHeader()
        self.drawGrid()

    def makeGhostNote(self, pos_x, pos_y):
        """creates the ghostnote that is placed on the scene before the real one is."""
        if self.ghost_note:
            self.removeItem(self.ghost_note)
        length = self.full_note_width * self.default_length
        (start, note) = self.snap(pos_x, pos_y)
        self.ghost_vel = self.default_ghost_vel
        self.ghost_rect = QRectF(start, note, length, self.note_height)
        self.ghost_rect_orig_width = self.ghost_rect.width()
        self.ghost_note = QGraphicsRectItem(self.ghost_rect)
        self.ghost_note.setBrush(QColor(230, 221, 45, 100))
        self.addItem(self.ghost_note)

    def drawNote(self,
                 note_num,
                 note_start=None,
                 note_length=None,
                 note_velocity=None,
                 add=True):
        """
        note_num: midi number, 0 - 127
        note_start: 0 - (num_measures * time_sig[0]) so this is in beats
        note_length: 0 - (num_measures  * time_sig[0]/time_sig[1]) this is in measures
        note_velocity: 0 - 127
        """

        info = [note_num, note_start, note_length, note_velocity]

        if not note_start % (self.num_measures *
                             self.time_sig[0]) == note_start:
            #self.midievent.emit(["midievent-remove", note_num, note_start, note_length, note_velocity])
            while not note_start % (self.num_measures *
                                    self.time_sig[0]) == note_start:
                self.setMeasures(self.num_measures + 1)
            self.measureupdate.emit(self.num_measures)
            self.refreshScene()

        x_start = self.get_note_x_start(note_start)
        if note_length > self.max_note_length:
            note_length = self.max_note_length + 0.25
        x_length = self.get_note_x_length(note_length)
        y_pos = self.get_note_y_pos(note_num)

        note = NoteItem(self.note_height, x_length, info)
        note.setPos(x_start, y_pos)

        self.notes.append(note)
        if add:
            self.addItem(note)

    # -------------------------------------------------------------------------
    # Helper Functions

    def frange(self, x, y, t):
        while x < y:
            yield x
            x += t

    def quantize(self, value):
        self.snap_value = float(
            self.full_note_width) * value if value else None

    def snap(self, pos_x, pos_y=None):
        if self.snap_value:
            pos_x = int(round((pos_x - self.piano_width) / self.snap_value)) \
                    * self.snap_value + self.piano_width
        if pos_y:
            pos_y = int((pos_y - self.header_height) / self.note_height) \
                    * self.note_height + self.header_height
        return (pos_x, pos_y) if pos_y else pos_x

    def adjust_note_vel(self, event):
        m_pos = event.scenePos()
        #bind velocity to vertical mouse movement
        self.ghost_vel += (event.lastScenePos().y() - m_pos.y()) / 10
        if self.ghost_vel < 0:
            self.ghost_vel = 0
        elif self.ghost_vel > 127:
            self.ghost_vel = 127

        m_width = self.ghost_rect.x() + self.ghost_rect_orig_width
        if m_pos.x() < m_width:
            m_pos.setX(m_width)
        m_new_x = self.snap(m_pos.x())
        self.ghost_rect.setRight(m_new_x)
        self.ghost_note.setRect(self.ghost_rect)

    def enforce_bounds(self, pos):
        if pos.x() < self.piano_width:
            pos.setX(self.piano_width)
        elif pos.x() > self.grid_width + self.piano_width:
            pos.setX(self.grid_width + self.piano_width)
        if pos.y() < self.header_height + self.padding:
            pos.setY(self.header_height + self.padding)
        return pos

    def get_note_start_from_x(self, note_x):
        return (note_x - self.piano_width) / (
            self.grid_width / self.num_measures / self.time_sig[0])

    def get_note_x_start(self, note_start):
        return self.piano_width + \
                (self.grid_width / self.num_measures / self.time_sig[0]) * note_start

    def get_note_x_length(self, note_length):
        return float(self.time_sig[1]) / self.time_sig[
            0] * note_length * self.grid_width / self.num_measures

    def get_note_length_from_x(self, note_x):
        return float(self.time_sig[0]) / self.time_sig[1] * self.num_measures / self.grid_width \
                * note_x

    def get_note_y_pos(self, note_num):
        return self.header_height + self.note_height * (self.total_notes -
                                                        note_num - 1)

    def get_note_num_from_y(self, note_y_pos):
        return -(((note_y_pos - self.header_height) / self.note_height) -
                 self.total_notes + 1)
Exemplo n.º 19
0
    def mouseMoveEvent(self, event):
        """When normal selection, update power spectrum with current selection.
        Otherwise, show the range of the new marker.
        """
        if not self.scene:
            return

        if self.idx_sel in self.scene.items():
            self.scene.removeItem(self.idx_sel)
            self.idx_sel = None

        chk_marker = self.parent.notes.action['new_bookmark'].isChecked()
        chk_event = self.parent.notes.action['new_event'].isChecked()

        if chk_marker or chk_event:
            xy_scene = self.mapToScene(event.pos())
            y_distance = self.parent.value('y_distance')
            pos = QRectF(self.sel_xy[0],
                         0,
                         xy_scene.x() - self.sel_xy[0],
                         len(self.idx_label) * y_distance)
            item = QGraphicsRectItem(pos.normalized())
            item.setPen(NoPen)

            if chk_marker:
                color = QColor(self.parent.value('annot_bookmark_color'))

            elif chk_event:
                eventtype = self.parent.notes.idx_eventtype.currentText()
                color = convert_name_to_color(eventtype)

            item.setBrush(QBrush(color.lighter(115)))
            item.setZValue(-10)
            self.scene.addItem(item)
            self.idx_sel = item
            return

        xy_scene = self.mapToScene(event.pos())
        pos = QRectF(self.sel_xy[0], self.sel_xy[1],
                     xy_scene.x() - self.sel_xy[0],
                     xy_scene.y() - self.sel_xy[1])
        self.idx_sel = QGraphicsRectItem(pos.normalized())
        self.idx_sel.setPen(QPen(QColor(LINE_COLOR), LINE_WIDTH))
        self.scene.addItem(self.idx_sel)

        if self.idx_info in self.scene.items():
            self.scene.removeItem(self.idx_info)

        duration = '{0:0.2f}s'.format(abs(xy_scene.x() - self.sel_xy[0]))

        # get y-size, based on scaling too
        y = abs(xy_scene.y() - self.sel_xy[1])
        scale = self.parent.value('y_scale') * self.chan_scale[self.sel_chan]
        height = '{0:0.3f}uV'.format(y / scale)

        item = TextItem_with_BG()
        item.setText(duration + ' ' + height)
        item.setPos(self.sel_xy[0], self.sel_xy[1])
        self.scene.addItem(item)
        self.idx_info = item

        trial = 0
        time = self.parent.traces.data.axis['time'][trial]
        beg_win = min((self.sel_xy[0], xy_scene.x()))
        end_win = max((self.sel_xy[0], xy_scene.x()))
        time_of_interest = time[(time >= beg_win) & (time < end_win)]
        if len(time_of_interest) > MINIMUM_N_SAMPLES:
            data = self.parent.traces.data(trial=trial,
                                           chan=self.chan[self.sel_chan],
                                           time=time_of_interest)
            n_data = len(data)
            n_pad = (power(2, ceil(log2(n_data))) - n_data) / 2
            data = pad(data, (int(ceil(n_pad)), int(floor(n_pad))), 'constant')

            self.parent.spectrum.display(data)
Exemplo n.º 20
0
 def _set_square(disk: QGraphicsRectItem, x0, y0, r):
     """Helper to center `square` on `x0`, `y0` w radius `r`"""
     disk.setRect(0, 0, 2 * r, 2 * r)
     disk.setPos(x0 - r, y0 - r)
Exemplo n.º 21
0
class ForcedXoverNode3(QGraphicsRectItem):
    """
    This is a QGraphicsRectItem to allow actions and also a
    QGraphicsSimpleTextItem to allow a label to be drawn

    Attributes:
        is_forward (TYPE): Description
    """
    def __init__(self, virtual_helix_item, xover_item, strand3p, idx):
        """Summary

        Args:
            virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): from vhi
            xover_item (TYPE): Description
            strand3p (Strand): reference to the 3' strand
            idx (int): the base index within the virtual helix
        """
        super(ForcedXoverNode3, self).__init__(virtual_helix_item)
        self._vhi = virtual_helix_item
        self._xover_item = xover_item
        self._idx = idx

        self.is_forward = strand3p.strandSet().isForward()
        self._is_on_top = self.is_forward

        self._partner_virtual_helix = virtual_helix_item

        self._blank_thing = QGraphicsRectItem(_blankRect, self)
        self._blank_thing.setBrush(QBrush(Qt.white))
        self._path_thing = QGraphicsPathItem(self)
        self.configurePath()

        self._label = None
        self.setPen(_NO_PEN)
        self.setBrush(_NO_BRUSH)
        self.setRect(_rect)

        self.setZValue(styles.ZENDPOINTITEM + 1)
    # end def

    def updateForFloatFromVHI(self, virtual_helix_item, is_forward, idx_x, idx_y):
        """
        Args:
            virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): Description
            is_forward (TYPE): Description
            idx_x (TYPE): Description
            idx_y (TYPE): Description
        """
        self._vhi = virtual_helix_item
        self.setParentItem(virtual_helix_item)
        self._idx = idx_x
        self._is_on_top = self.is_forward = True if is_forward else False
        self.updatePositionAndAppearance(is_from_strand=False)
    # end def

    def updateForFloatFromStrand(self, virtual_helix_item, strand3p, idx):
        """
        Args:
            virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): Description
            strand3p (Strand): reference to the 3' strand
            idx (int): the base index within the virtual helix
        """
        self._vhi = virtual_helix_item
        self._strand = strand3p
        self.setParentItem(virtual_helix_item)
        self._idx = idx
        self._is_on_top = self.is_forward = strand3p.strandSet().isForward()
        self.updatePositionAndAppearance()
    # end def

    def configurePath(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._path_thing.setBrush(getBrushObj(_PENCIL_COLOR))
        path = PPR3 if self.is_forward else PPL3
        offset = -_BASE_WIDTH if self.is_forward else _BASE_WIDTH
        self._path_thing.setPath(path)
        self._path_thing.setPos(offset, 0)

        offset = -_BASE_WIDTH if self.is_forward else 0
        self._blank_thing.setPos(offset, 0)

        self._blank_thing.show()
        self._path_thing.show()
    # end def

    def refreshXover(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._xover_item.refreshXover()
    # end def

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

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

        Returns:
            TYPE: Description
        """
        self._partner_virtual_helix = virtual_helix_item
    # end def

    def idx(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._idx
    # end def

    def virtualHelixItem(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._vhi
    # end def

    def point(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._vhi.upperLeftCornerOfBaseType(self._idx, self.is_forward)
    # end def

    def floatPoint(self):
        """Summary

        Returns:
            TYPE: Description
        """
        pt = self.pos()
        return pt.x(), pt.y()
    # end def

    def isForward(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self.is_forward
    # end def

    def updatePositionAndAppearance(self, is_from_strand=True):
        """
        Sets position by asking the VirtualHelixItem
        Sets appearance by choosing among pre-defined painterpaths (from
        normalstrandgraphicsitem) depending on drawing direction.

        Args:
            is_from_strand (bool, optional): Description
        """
        self.setPos(*self.point())
        n5 = self._xover_item._node5
        if is_from_strand:
            from_strand, from_idx = (n5._strand, n5._idx) if n5 != self else (None, None)
            if self._strand.canInstallXoverAt(self._idx, from_strand, from_idx):
                self.configurePath()
                # We can only expose a 5' end. But on which side?
                is_left = True if self.is_forward else False
                self._updateLabel(is_left)
            else:
                self.hideItems()
        else:
            self.hideItems()
    # end def

    def remove(self):
        """Clean up this joint
        """
        scene = self.scene()
        scene.removeItem(self._label)
        self._label = None
        scene.removeItem(self._path_thing)
        self._path_thing = None
        scene.removeItem(self._blank_thing)
        self._blank_thing = None
        scene.removeItem(self)
    # end def

    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()
        # end if
    # end def

    def hideItems(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if self._label:
            self._label.hide()
        if self._blank_thing:
            self._path_thing.hide()
        if self._blank_thing:
            self._blank_thing.hide()
Exemplo n.º 22
0
    def mouseMoveEvent(self, event):
        """When normal selection, update power spectrum with current selection.
        Otherwise, show the range of the new marker.
        """
        if not self.scene:
            return

        if self.event_sel or self.deselect:
            return

        if self.sel_xy[0] is None or self.sel_xy[1] is None:
            return

        if self.idx_sel in self.scene.items():
            self.scene.removeItem(self.idx_sel)
            self.idx_sel = None

        chk_marker = self.parent.notes.action['new_bookmark'].isChecked()
        chk_event = self.parent.notes.action['new_event'].isChecked()

        if chk_marker or chk_event:
            xy_scene = self.mapToScene(event.pos())
            y_distance = self.parent.value('y_distance')
            pos = QRectF(self.sel_xy[0], 0,
                         xy_scene.x() - self.sel_xy[0],
                         len(self.idx_label) * y_distance)
            item = QGraphicsRectItem(pos.normalized())
            item.setPen(NoPen)

            if chk_marker:
                color = QColor(self.parent.value('annot_bookmark_color'))

            elif chk_event:
                eventtype = self.parent.notes.idx_eventtype.currentText()
                color = convert_name_to_color(eventtype)

            item.setBrush(QBrush(color.lighter(115)))
            item.setZValue(-10)
            self.scene.addItem(item)
            self.idx_sel = item
            return

        xy_scene = self.mapToScene(event.pos())
        pos = QRectF(self.sel_xy[0], self.sel_xy[1],
                     xy_scene.x() - self.sel_xy[0],
                     xy_scene.y() - self.sel_xy[1])
        self.idx_sel = QGraphicsRectItem(pos.normalized())
        self.idx_sel.setPen(QPen(QColor(LINE_COLOR), LINE_WIDTH))
        self.scene.addItem(self.idx_sel)

        if self.idx_info in self.scene.items():
            self.scene.removeItem(self.idx_info)

        duration = '{0:0.3f}s'.format(abs(xy_scene.x() - self.sel_xy[0]))

        # get y-size, based on scaling too
        y = abs(xy_scene.y() - self.sel_xy[1])
        scale = self.parent.value('y_scale') * self.chan_scale[self.sel_chan]
        height = '{0:0.3f}uV'.format(y / scale)

        item = TextItem_with_BG()
        item.setText(duration + ' ' + height)
        item.setPos(self.sel_xy[0], self.sel_xy[1])
        self.scene.addItem(item)
        self.idx_info = item

        trial = 0
        time = self.parent.traces.data.axis['time'][trial]
        beg_win = min((self.sel_xy[0], xy_scene.x()))
        end_win = max((self.sel_xy[0], xy_scene.x()))
        time_of_interest = time[(time >= beg_win) & (time < end_win)]
        if len(time_of_interest) > MINIMUM_N_SAMPLES:
            data = self.parent.traces.data(trial=trial,
                                           chan=self.chan[self.sel_chan],
                                           time=time_of_interest)
            n_data = len(data)
            n_pad = (power(2, ceil(log2(n_data))) - n_data) / 2
            data = pad(data, (int(ceil(n_pad)), int(floor(n_pad))), 'constant')

            self.parent.spectrum.display(data)
Exemplo n.º 23
0
class ForcedXoverNode3(QGraphicsRectItem):
    """
    This is a QGraphicsRectItem to allow actions and also a
    QGraphicsSimpleTextItem to allow a label to be drawn

    Attributes:
        is_forward (TYPE): Description
    """

    def __init__(self, virtual_helix_item, xover_item, strand3p, idx):
        """Summary

        Args:
            virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): from vhi
            xover_item (TYPE): Description
            strand3p (Strand): reference to the 3' strand
            idx (int): the base index within the virtual helix
        """
        super(ForcedXoverNode3, self).__init__(virtual_helix_item)
        self._vhi = virtual_helix_item
        self._xover_item = xover_item
        self._idx = idx

        self.is_forward = strand3p.strandSet().isForward()
        self._is_on_top = self.is_forward

        self._partner_virtual_helix = virtual_helix_item

        self._blank_thing = QGraphicsRectItem(_blankRect, self)
        self._blank_thing.setBrush(QBrush(Qt.white))
        self._path_thing = QGraphicsPathItem(self)
        self.configurePath()

        self._label = None
        self.setPen(_NO_PEN)
        self.setBrush(_NO_BRUSH)
        self.setRect(_rect)

        self.setZValue(styles.ZENDPOINTITEM + 1)
    # end def

    def updateForFloatFromVHI(self, virtual_helix_item, is_forward, idx_x, idx_y):
        """
        Args:
            virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): Description
            is_forward (TYPE): Description
            idx_x (TYPE): Description
            idx_y (TYPE): Description
        """
        self._vhi = virtual_helix_item
        self.setParentItem(virtual_helix_item)
        self._idx = idx_x
        self._is_on_top = self.is_forward = True if is_forward else False
        self.updatePositionAndAppearance(is_from_strand=False)
    # end def

    def updateForFloatFromStrand(self, virtual_helix_item, strand3p, idx):
        """
        Args:
            virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): Description
            strand3p (Strand): reference to the 3' strand
            idx (int): the base index within the virtual helix
        """
        self._vhi = virtual_helix_item
        self._strand = strand3p
        self.setParentItem(virtual_helix_item)
        self._idx = idx
        self._is_on_top = self.is_forward = strand3p.strandSet().isForward()
        self.updatePositionAndAppearance()
    # end def

    def configurePath(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._path_thing.setBrush(getBrushObj(_PENCIL_COLOR))
        path = PPR3 if self.is_forward else PPL3
        offset = -_BASE_WIDTH if self.is_forward else _BASE_WIDTH
        self._path_thing.setPath(path)
        self._path_thing.setPos(offset, 0)

        offset = -_BASE_WIDTH if self.is_forward else 0
        self._blank_thing.setPos(offset, 0)

        self._blank_thing.show()
        self._path_thing.show()
    # end def

    def refreshXover(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._xover_item.refreshXover()
    # end def

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

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

        Returns:
            TYPE: Description
        """
        self._partner_virtual_helix = virtual_helix_item
    # end def

    def idx(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._idx
    # end def

    def virtualHelixItem(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._vhi
    # end def

    def point(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._vhi.upperLeftCornerOfBaseType(self._idx, self.is_forward)
    # end def

    def floatPoint(self):
        """Summary

        Returns:
            TYPE: Description
        """
        pt = self.pos()
        return pt.x(), pt.y()
    # end def

    def isForward(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self.is_forward
    # end def

    def updatePositionAndAppearance(self, is_from_strand=True):
        """
        Sets position by asking the VirtualHelixItem
        Sets appearance by choosing among pre-defined painterpaths (from
        normalstrandgraphicsitem) depending on drawing direction.

        Args:
            is_from_strand (bool, optional): Description
        """
        self.setPos(*self.point())
        n5 = self._xover_item._node5
        if is_from_strand:
            from_strand, from_idx = (n5._strand, n5._idx) if n5 != self else (None, None)
            if self._strand.canInstallXoverAt(self._idx, from_strand, from_idx):
                self.configurePath()
                # We can only expose a 5' end. But on which side?
                is_left = True if self.is_forward else False
                self._updateLabel(is_left)
            else:
                self.hideItems()
        else:
            self.hideItems()
    # end def

    def remove(self):
        """Clean up this joint
        """
        scene = self.scene()
        scene.removeItem(self._label)
        self._label = None
        scene.removeItem(self._path_thing)
        self._path_thing = None
        scene.removeItem(self._blank_thing)
        self._blank_thing = None
        scene.removeItem(self)
    # end def

    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()
        # end if
    # end def

    def hideItems(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if self._label:
            self._label.hide()
        if self._blank_thing:
            self._path_thing.hide()
        if self._blank_thing:
            self._blank_thing.hide()
Exemplo n.º 24
0
class OverlayGraphics(QGraphicsView):
    def __init__(self):
        super(OverlayGraphics, self).__init__()
        self.setStyleSheet("background:transparent")  # ビューの背景透明化
        self.overlayScene = QGraphicsScene()
        self.setScene(self.overlayScene)
        self.overlayScene.setSceneRect(QRectF(self.rect()))
        self.createItem()

        self.luRect = QRect()
        self.rbRect = QRect()
        self.isSelected = False
        self.setTargetMode(False)
        self.hide()  # 初期状態は非表示

    def createItem(self):
        #  ターゲットマーカの作成
        self.target_circle = QGraphicsEllipseItem(
            QtCore.QRectF(-10, -10, 20, 20))
        self.target_circle.setBrush(QBrush(Qt.red))
        self.target_circle.setPen(QPen(Qt.black))
        self.overlayScene.addItem(self.target_circle)
        self.setTargetMode(False)

        # モーダルの作成:モーダルはターゲット位置に追従する
        self.pop_rect = QGraphicsRectItem(QtCore.QRectF(0, 0, 100, 60),
                                          self.target_circle)
        self.pop_rect.setBrush(QBrush(Qt.gray))
        self.pop_rect.setPen(QPen(Qt.gray))
        self.pop_rect.setOpacity(0.8)  # 透明度を設定

        self.operate_text = QGraphicsSimpleTextItem("", self.pop_rect)
        self.operate_text.setScale(1.7)
        self.sub_operate_text = QGraphicsSimpleTextItem("", self.pop_rect)
        self.sub_operate_text.setScale(1.7)
        self.setTargetPos(400, 180, DirectionEnum.VERTICAL.value)

    # オーバレイヤのサイズが変わると呼び出される.シーンのサイズをビューの大きさに追従(-5 はマージン)
    def resizeEvent(self, event):
        self.overlayScene.setSceneRect(
            QRectF(0, 0,
                   self.size().width() - 5,
                   self.size().height() - 5))

    # ウィンドウ左上からの位置(画面位置からウインドウ左上の位置を引く)
    def setTargetPos(self, x_pos, y_pos, direction):
        self.target_circle.setPos(QPointF(x_pos, y_pos))
        self.setPopPos(direction)

    def setPopTextPos(self, text1, text2):
        lentext1 = len(text1)
        lentext2 = len(text2)
        if lentext2 == 0:
            self.operate_text.setPos(
                (self.pop_rect.rect().size().width() / 2) -
                (lentext1 / 2 * 14), 15)
        else:
            self.operate_text.setPos(
                (self.pop_rect.rect().size().width() / 2) -
                (lentext1 / 2 * 14), 5)
            self.sub_operate_text.setPos(
                (self.pop_rect.rect().size().width() / 2) -
                (lentext2 / 2 * 14), 30)

    def setPopPos(self, direction):
        if direction == DirectionEnum.VERTICAL.value:
            # モーダルを右に表示しきれない場合に左に表示
            if self.target_circle.pos().x() > self.overlayScene.width(
            ) - self.pop_rect.rect().size().width() * 1.5:
                self.pop_rect.setPos(
                    -self.pop_rect.rect().size().width() * 1.5,
                    -self.pop_rect.rect().size().height() / 2)
            else:  # 右に表示
                self.pop_rect.setPos(self.pop_rect.rect().size().width() / 2,
                                     -self.pop_rect.rect().size().height() / 2)

        else:
            # モーダルを下に表示しきれない場合に上に表示
            if self.target_circle.pos().y() > self.overlayScene.height(
            ) - self.pop_rect.rect().size().height() * 1.5:
                self.pop_rect.setPos(
                    -self.pop_rect.rect().size().width() / 2,
                    -self.pop_rect.rect().size().height() * 1.5)
            else:  # 下に表示
                self.pop_rect.setPos(-self.pop_rect.rect().size().width() / 2,
                                     self.pop_rect.rect().size().height() / 2)

    def setTargetMode(self, active):
        self.targetMode = active
        if active:
            self.target_circle.setRect(-10, -10, 20, 20)
        else:  # ターゲットを非表示にする
            self.target_circle.setRect(0, 0, 0, 0)

    # def targetVisible(self, visible):
    #     if visible:
    #         self.target_circle.setRect(-10, -10, 20, 20)
    #     else:
    #         self.target_circle.setRect(0, 0, 0, 0)

    def feedbackShow(self, text1, text2, direction):
        if self.isSelected:
            self.operate_text.setText(text1)
            self.sub_operate_text.setText(text2)
            # ターゲットモードがアクティブでないとき,ターゲットマーカの位置は選択セルに依存
            if not self.targetMode:
                if direction == DirectionEnum.HORIZON.value:
                    x_pos = (self.luRect.left() + self.rbRect.right()) / 2 + 20
                    y_pos = self.rbRect.bottom(
                    ) - self.rbRect.height() / 2 + 20
                else:
                    x_pos = self.rbRect.right() - self.rbRect.width() / 2 + 20
                    y_pos = (self.luRect.top() + self.rbRect.bottom()) / 2 + 20

                self.setTargetPos(x_pos, y_pos, direction)
                self.setPopTextPos(text1, text2)
            self.show()
Exemplo n.º 25
0
class ForcedXoverNode3(QGraphicsRectItem):
    """
    This is a QGraphicsRectItem to allow actions and also a 
    QGraphicsSimpleTextItem to allow a label to be drawn
    """
    def __init__(self, virtual_helix_item, xover_item, strand3p, idx):
        super(ForcedXoverNode3, self).__init__(virtual_helix_item)
        self._vhi = virtual_helix_item
        self._xover_item = xover_item
        self._idx = idx
        self._is_on_top = virtual_helix_item.isStrandOnTop(strand3p)
        self._is_drawn_5_to_3 = strand3p.strandSet().isDrawn5to3()
        self._strand_type = strand3p.strandSet().strandType()

        self._partner_virtual_helix = virtual_helix_item

        self._blank_thing = QGraphicsRectItem(_blankRect, self)
        self._blank_thing.setBrush(QBrush(Qt.white))
        self._path_thing = QGraphicsPathItem(self)
        self.configurePath()

        self.setPen(_NO_PEN)
        self._label = None
        self.setPen(_NO_PEN)
        self.setBrush(_NO_BRUSH)
        self.setRect(_rect)

        self.setZValue(styles.ZENDPOINTITEM + 1)

    # end def

    def updateForFloatFromVHI(self, virtual_helix_item, strand_type, idx_x,
                              idx_y):
        """

        """
        self._vhi = virtual_helix_item
        self.setParentItem(virtual_helix_item)
        self._strand_type = strand_type
        self._idx = idx_x
        self._is_on_top = self._is_drawn_5_to_3 = True if idx_y == 0 else False
        self.updatePositionAndAppearance(is_from_strand=False)

    # end def

    def updateForFloatFromStrand(self, virtual_helix_item, strand3p, idx):
        """

        """
        self._vhi = virtual_helix_item
        self._strand = strand3p
        self.setParentItem(virtual_helix_item)
        self._idx = idx
        self._is_on_top = virtual_helix_item.isStrandOnTop(strand3p)
        self._is_drawn_5_to_3 = strand3p.strandSet().isDrawn5to3()
        self._strand_type = strand3p.strandSet().strandType()
        self.updatePositionAndAppearance()

    # end def

    def strandType(self):
        return self._strand_type

    # end def

    def configurePath(self):
        self._path_thing.setBrush(QBrush(styles.RED_STROKE))
        path = PPR3 if self._is_drawn_5_to_3 else PPL3
        offset = -_BASE_WIDTH if self._is_drawn_5_to_3 else _BASE_WIDTH
        self._path_thing.setPath(path)
        self._path_thing.setPos(offset, 0)

        offset = -_BASE_WIDTH if self._is_drawn_5_to_3 else 0
        self._blank_thing.setPos(offset, 0)

        self._blank_thing.show()
        self._path_thing.show()

    # end def

    def refreshXover(self):
        self._xover_item.refreshXover()

    # end def

    def setPartnerVirtualHelix(self, virtual_helix_item):
        self._partner_virtual_helix = virtual_helix_item

    # end def

    def idx(self):
        return self._idx

    # end def

    def virtualHelixItem(self):
        return self._vhi

    # end def

    def point(self):
        return self._vhi.upperLeftCornerOfBaseType(self._idx,
                                                   self._strand_type)

    # end def

    def floatPoint(self):
        pt = self.pos()
        return pt.x(), pt.y()

    # end def

    def isOnTop(self):
        return self._is_on_top

    # end def

    def isDrawn5to3(self):
        return self._is_drawn_5_to_3

    # end def

    def updatePositionAndAppearance(self, is_from_strand=True):
        """
        Sets position by asking the VirtualHelixItem
        Sets appearance by choosing among pre-defined painterpaths (from
        normalstrandgraphicsitem) depending on drawing direction.
        """
        self.setPos(*self.point())
        n5 = self._xover_item._node5
        if is_from_strand:
            from_strand, from_idx = (n5._strand,
                                     n5._idx) if n5 != self else (None, None)
            if self._strand.canInstallXoverAt(self._idx, from_strand,
                                              from_idx):
                self.configurePath()
                # We can only expose a 5' end. But on which side?
                is_left = True if self._is_drawn_5_to_3 else False
                self._updateLabel(is_left)
            else:
                self.hideItems()
        else:
            self.hideItems()

    # end def

    def updateConnectivity(self):
        is_left = True if self._is_drawn_5_to_3 else False
        self._updateLabel(is_left)

    # end def

    def remove(self):
        """
        Clean up this joint
        """
        scene = self.scene()
        scene.removeItem(self._label)
        self._label = None
        scene.removeItem(self._path_thing)
        self._path_thing = None
        scene.removeItem(self._blank_thing)
        self._blank_thing = None
        scene.removeItem(self)

    # end def

    def _updateLabel(self, is_left):
        """
        Called by updatePositionAndAppearance during init, or later by
        updateConnectivity. Updates drawing and position of the label.
        """
        lbl = self._label
        if self._idx != 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
            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 == 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.number()))
            lbl.show()
        # end if

    # end def

    def hideItems(self):
        if self._label:
            self._label.hide()
        if self._blank_thing:
            self._path_thing.hide()
        if self._blank_thing:
            self._blank_thing.hide()
Exemplo n.º 26
0
class PhotoViewer(QtWidgets.QGraphicsView):
    photoClicked = QtCore.pyqtSignal(QtCore.QPoint)

    def __init__(self, parent):
        super(PhotoViewer, self).__init__(parent)

        # all gravestone-denoting polygons
        self.selection_polygons = []

        self.box_creation_mode = False
        self.box_start_point = None
        self._box_graphic = None

        self.line_selection_mode = False
        self.start_line_select = None
        self.line_graphic = None

        self.ctrl_held = False

        # the polygons currently selected for editing
        self.selected_polygons = []
        self.update_selected = None

        self._zoom = 0
        self._empty = True
        self.scene = QtWidgets.QGraphicsScene(self)
        self._photo = QtWidgets.QGraphicsPixmapItem()

        self.scene.addItem(self._photo)
        self.setScene(self.scene)
        self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30)))
        self.setFrameShape(QtWidgets.QFrame.NoFrame)

    def add_selected_polygon(self, polygon):
        self.selected_polygons.append(polygon)

        if self.update_selected is not None:
            self.update_selected()

    def remove_selected_polygon(self, polygon):
        self.selected_polygons.remove(polygon)

        if self.update_selected is not None:
            self.update_selected(self.selected_polygons)

    def has_photo(self):
        return not self._empty

    def pixmap(self):
        return self._photo

    def fitInView(self, scale=True):
        rect = QtCore.QRectF(self._photo.pixmap().rect())
        if not rect.isNull():
            self.setSceneRect(rect)
            if self.has_photo():
                unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
                self.scale(1 / unity.width(), 1 / unity.height())
                viewrect = self.viewport().rect()
                scenerect = self.transform().mapRect(rect)
                factor = min(viewrect.width() / scenerect.width(),
                             viewrect.height() / scenerect.height())
                self.scale(factor, factor)
            self._zoom = 0

    def set_photo(self, pixmap=None):
        self._zoom = 0
        if pixmap and not pixmap.isNull():
            self._empty = False
            self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
            self._photo.setPixmap(pixmap)

            self.selection_polygons = []
            self.box_creation_mode = False
            self.box_start_point = None
            self._box_graphic = None

            for poly in self.selected_polygons:
                self.remove_selected_polygon(poly)
        else:
            self._empty = True
            self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
            self._photo.setPixmap(QtGui.QPixmap())
        self.fitInView()

    def wheelEvent(self, event):
        if self.has_photo():
            if event.angleDelta().y() > 0:
                factor = 1.25
                self._zoom += 1
            else:
                factor = 0.8
                self._zoom -= 1
            if self._zoom > 0:
                self.scale(factor, factor)
            elif self._zoom == 0:
                self.fitInView()
            else:
                self._zoom = 0

    def delete_selected(self):
        for selected in self.selected_polygons:
            selected.deselect()
            self.scene.removeItem(selected)
            self.selection_polygons.remove(selected)

        self.selected_polygons = []

    def any_selection_nodes_under_mouse(self):
        for selected in self.selected_polygons:
            for node in selected._nodes:
                if node.isUnderMouse():
                    return True

        return False

    def deselect_all(self):
        for polygon in self.selected_polygons:
            polygon.deselect()
        self.selected_polygons = []
        if self.update_selected is not None:
            self.update_selected()

    def remove_all(self):
        """ Delete all polygons """
        self.deselect_all()
        for polygon in self.selection_polygons:
            self.scene.removeItem(polygon)
        self.selection_polygons.clear()

    def mousePressEvent(self, event):
        if not self._photo.isUnderMouse():
            return
        if self.box_creation_mode:
            photo_click_point = self.mapToScene(event.pos()).toPoint()
            self.box_start_point = photo_click_point

            self._box_graphic = QGraphicsRectItem(0, 0, 1, 1)
            self._box_graphic.setBrush(QBrush(Qt.transparent))
            self._box_graphic.setPen(
                QPen(Qt.blue, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
            self._box_graphic.setPos(photo_click_point)
            self.scene.addItem(self._box_graphic)
        elif self.line_selection_mode and self.start_line_select is None:
            photo_click_point = self.mapToScene(event.pos()).toPoint()
            self.start_line_select = photo_click_point
            self.line_graphic = QGraphicsLineItem()
            self.line_graphic.setPen(
                QPen(Qt.green, 4, Qt.DotLine, Qt.RoundCap, Qt.RoundJoin))
            self.scene.addItem(self.line_graphic)
        else:
            # this is pretty hacky and ugly but it works well
            if not self.any_selection_nodes_under_mouse(
            ) and not self.ctrl_held:
                self.deselect_all()
            super(PhotoViewer, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        if not self._photo.isUnderMouse():
            return
        if self.box_creation_mode and self.box_start_point is not None:
            photo_click_point = self.mapToScene(event.pos()).toPoint()
            polygon_coords = [
                QPointF(self.box_start_point.x(), self.box_start_point.y()),
                QPointF(self.box_start_point.x(), photo_click_point.y()),
                QPointF(photo_click_point.x(), photo_click_point.y()),
                QPointF(photo_click_point.x(), self.box_start_point.y())
            ]
            selection_polygon = SelectionPolygon(polygon_coords, self)
            self.add_selection_polygon(selection_polygon)
            self.scene.removeItem(self._box_graphic)

            self.box_creation_mode = False
            self.box_start_point = None
            self._box_graphic = None
            self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
        elif self.line_selection_mode and self.start_line_select is not None:
            # line select
            self.deselect_all()

            photo_click_point = self.mapToScene(event.pos()).toPoint()
            self.scene.removeItem(self.line_graphic)

            for polygon in self.selection_polygons:
                line = [
                    np.array([photo_click_point.x(),
                              photo_click_point.y()]),
                    np.array([
                        self.start_line_select.x(),
                        self.start_line_select.y()
                    ])
                ]
                centroid = polygon.centroid()

                # max node dist from centroid, used for approximations
                max_dist = 0.0
                for point in polygon.polygon_points:
                    # todo manhattan length is a bad approx of euclid. dist, maybe its not worth the inaccuracy
                    dist = (point - centroid).manhattanLength()
                    if dist > max_dist:
                        max_dist = dist

                np_centroid = np.array([centroid.x(), centroid.y()])
                distance_from_line = np.abs(
                    np.cross(line[1] - line[0],
                             line[0] - np_centroid)) / norm(line[0] - line[1])

                if distance_from_line <= max_dist:
                    min_x = min(photo_click_point.x(),
                                self.start_line_select.x()) * .95
                    max_x = max(photo_click_point.x(),
                                self.start_line_select.x()) * 1.05
                    min_y = min(photo_click_point.y(),
                                self.start_line_select.y()) * .95
                    max_y = max(photo_click_point.y(),
                                self.start_line_select.x()) * 1.05
                    if min_x < centroid.x() < max_x and min_y < centroid.y(
                    ) < max_y:
                        polygon.select()

            self.start_line_select = None
            self.line_graphic = None
        else:
            super(PhotoViewer, self).mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):
        if self.box_creation_mode and self.box_start_point is not None and self._box_graphic is not None:
            mouse_point = self.mapToScene(event.pos()).toPoint()
            self._box_graphic.setRect(
                QRectF(0, 0,
                       mouse_point.x() - self.box_start_point.x(),
                       mouse_point.y() -
                       self.box_start_point.y()).normalized())
        elif self.line_selection_mode and self.start_line_select is not None and self.line_graphic is not None:
            mouse_point = self.mapToScene(event.pos()).toPoint()
            self.line_graphic.setLine(
                QLineF(mouse_point, self.start_line_select))
        super(PhotoViewer, self).mouseMoveEvent(event)

    def add_selection_polygon(self, selection_polygon):
        self.selection_polygons.append(selection_polygon)
        self.scene.addItem(selection_polygon)

    def pixmap_width_and_height(self):
        return self._photo.pixmap().width(), self._photo.pixmap().height()
Exemplo n.º 27
0
    buttonParent = QGraphicsRectItem()
    ellipseButton = Button(QPixmap(':/images/ellipse.png'), buttonParent)
    figure8Button = Button(QPixmap(':/images/figure8.png'), buttonParent)
    randomButton = Button(QPixmap(':/images/random.png'), buttonParent)
    tiledButton = Button(QPixmap(':/images/tile.png'), buttonParent)
    centeredButton = Button(QPixmap(':/images/centered.png'), buttonParent)

    ellipseButton.setPos(-100, -100)
    figure8Button.setPos(100, -100)
    randomButton.setPos(0, 0)
    tiledButton.setPos(-100, 100)
    centeredButton.setPos(100, 100)

    scene.addItem(buttonParent)
    buttonParent.setScale(0.75)
    buttonParent.setPos(200, 200)
    buttonParent.setZValue(65)

    # States.
    rootState = QState()
    ellipseState = QState(rootState)
    figure8State = QState(rootState)
    randomState = QState(rootState)
    tiledState = QState(rootState)
    centeredState = QState(rootState)

    # Values.
    for i, item in enumerate(items):
        # Ellipse.
        ellipseState.assignProperty(
            item, 'pos',
Exemplo n.º 28
0
class GameArea(QWidget):
    #constants of widget
    RATIO_WITH_SHIPLIST = 11 / 14
    RATIO_WITHOUT_SHIPLIST = 1
    EPS = 0.3

    #signals
    shipPlaced = pyqtSignal(Ship)

    def __init__(self, parent=None):
        super(GameArea, self).__init__(parent)
        self.__ui = Ui_GameArea()
        self.__ui.setupUi(self)

        self.__ratio = self.RATIO_WITH_SHIPLIST
        self.__scaleFactor = 1

        self.controller = Controller()
        self.controller._accept = self.__accept
        self.controller._decline = self.__decline
        self.__gameModel = None

        self.__shipList = {
            "boat": ShipListItem(length=1, name="boat", count=4),
            "destroyer": ShipListItem(length=2, name="destroyer", count=3),
            "cruiser": ShipListItem(length=3, name="cruiser", count=2),
            "battleship": ShipListItem(length=4, name="battleship", count=1),
        }

        # resources
        self.__cellImages = {"intact": None, "hit": None, "miss": None}

        self.__sprites = {"explosion": None, "splash": None}

        self.__originalTileSize = 0
        self.tileSize = 0

        self.__shipListImage = QImage()
        self.__counterImage = QImage()

        # drawing items
        self.__placedShips = []
        self.__field = [QGraphicsPixmapItem() for _ in range(100)]
        self.__letters = [QGraphicsTextItem() for _ in range(10)]
        self.__numbers = [QGraphicsTextItem() for _ in range(10)]
        for i in range(10):
            self.__letters[i].setDefaultTextColor(QColor.fromRgb(0, 0, 0))
            self.__numbers[i].setDefaultTextColor(QColor.fromRgb(0, 0, 0))

        self.__spriteAnimations = []

        self.__shipListItem = QGraphicsPixmapItem()
        self.__ghostShip = QGraphicsPixmapItem(
        )  # data: 0 - rotation; 1 - ShipListItem
        self.__placer = QGraphicsRectItem()
        self.__dragShip = False

        self.__targetPixmap = None
        self.__targets = []
        self.__scanEffect = None

        # prepare Qt objects
        self.__scene = QGraphicsScene()
        self.__loadResources()
        self.__initGraphicsView()
        self.__adjustedToSize = 0

    def serviceModel(self, game_model):
        self.removeModel()
        self.__gameModel = game_model
        self.__gameModel.shipKilled.connect(self.__shootAround)

    def removeModel(self):
        if self.__gameModel:
            self.shipKilled.disconnect()
            self.__gameModel = None

    def __loadResources(self):
        if DEBUG_RESOURCE:
            resourcesPath = os.path.join(os.path.dirname(__file__),
                                         DEBUG_RESOURCE)
        else:
            resourcesPath = Environment.Resources.path()

        first = True
        for imageName in self.__cellImages:
            image = QImage(
                os.path.join(resourcesPath, "img", "cells",
                             f"{imageName}.png"))
            if first:
                first = False
                self.__originalTileSize = min(image.width(), image.height())
            else:
                self.__originalTileSize = min(self.__originalTileSize,
                                              image.width(), image.height())
            self.__cellImages[imageName] = image

        for spriteName in self.__sprites:
            image = QImage(
                os.path.join(resourcesPath, "img", "cells",
                             f"{spriteName}.png"))
            self.__sprites[spriteName] = image

        for shipName, ship in self.__shipList.items():
            ship.image = QImage(
                os.path.join(resourcesPath, "img", "ships", f"{shipName}.png"))

        self.__shipListImage = QImage(
            os.path.join(resourcesPath, "img", "backgrounds", "shiplist.png"))
        self.__counterImage = QImage(
            os.path.join(resourcesPath, "img", "miscellaneous",
                         "shipcounter.png"))

        self.__targetPixmap = QPixmap(
            os.path.join(resourcesPath, "img", "cells", "target.png"))

    def __initGraphicsView(self):
        self.__ui.graphicsView.setScene(self.__scene)
        self.__ui.graphicsView.viewport().installEventFilter(self)
        self.__ui.graphicsView.setRenderHints(
            QPainter.RenderHint.HighQualityAntialiasing
            | QPainter.RenderHint.TextAntialiasing
            | QPainter.RenderHint.SmoothPixmapTransform)
        self.__ui.graphicsView.horizontalScrollBar().blockSignals(True)
        self.__ui.graphicsView.verticalScrollBar().blockSignals(True)

        for cell in self.__field:
            cell.setData(0, "intact")
            pixmap = QPixmap.fromImage(self.__cellImages["intact"])
            cell.setPixmap(pixmap)
            cell.setTransformationMode(
                Qt.TransformationMode.SmoothTransformation)
            self.__scene.addItem(cell)

        ca_letters = ["А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "К"]
        # ca_letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
        ca_numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]

        font = QFont("Roboto")
        font.setPixelSize(int(self.__originalTileSize * 0.8))
        for i in range(10):
            self.__letters[i].setPlainText(ca_letters[i])
            self.__letters[i].setFont(font)
            self.__numbers[i].setPlainText(ca_numbers[i])
            self.__numbers[i].setFont(font)
            self.__scene.addItem(self.__letters[i])
            self.__scene.addItem(self.__numbers[i])

        self.__shipListItem.setPixmap(QPixmap.fromImage(self.__shipListImage))
        self.__shipListItem.setTransformationMode(
            Qt.TransformationMode.SmoothTransformation)
        self.__scene.addItem(self.__shipListItem)

        font.setPixelSize(int(self.__originalTileSize * 0.3))
        for _, ship in self.__shipList.items():
            t = QTransform().rotate(90)
            ship.shipItem.setPixmap(
                QPixmap.fromImage(ship.image).transformed(t))
            ship.shipItem.setTransformationMode(
                Qt.TransformationMode.SmoothTransformation)
            ship.counterItem.setPixmap(QPixmap.fromImage(self.__counterImage))
            ship.counterItem.setTransformationMode(
                Qt.TransformationMode.SmoothTransformation)
            ship.counterText.setPlainText(str(ship.count))
            ship.counterText.setFont(font)
            self.__scene.addItem(ship.shipItem)
            self.__scene.addItem(ship.counterItem)
            self.__scene.addItem(ship.counterText)

        self.__ghostShip.setTransformationMode(
            Qt.TransformationMode.SmoothTransformation)
        self.__ghostShip.setOpacity(0.7)

        pen = QPen()
        pen.setWidth(2)
        pen.setStyle(Qt.PenStyle.DashLine)
        pen.setJoinStyle(Qt.PenJoinStyle.RoundJoin)
        self.__placer.setPen(pen)

    def __setCell(self, x, y, cell_type):
        if cell_type not in self.__cellImages.keys():
            raise ValueError(
                f"Type is {cell_type}. Allowed \"intact\", \"miss\", \"hit\"")

        cellItem = self.__field[y * 10 + x]
        cellItem.setData(0, cell_type)
        pixmap = QPixmap.fromImage(self.__cellImages[cell_type])
        cellItem.setPixmap(pixmap)

    def __runAnimation(self, x, y, animation, looped=False):
        sprite = SpriteItem()
        sprite.setData(0, QPoint(x, y))
        spritePixmap = QPixmap.fromImage(self.__sprites[animation])

        sprite.setSpriteMap(spritePixmap, 60, 60, 5)
        sprite.setScale(self.__scaleFactor)
        sprite.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)
        sprite.setZValue(10)

        self.__spriteAnimations.append(sprite)
        self.__scene.addItem(sprite)

        def removeAnimation():
            self.__scene.removeItem(sprite)
            self.__spriteAnimations.remove(sprite)
            sprite.stopAnimation()

        sprite.startAnimation(100, looped, removeAnimation)

    def __shootAround(self, ship: Ship):
        shipCells = []
        for i in range(ship.length):
            shipCells.append(ship.pos +
                             (QPoint(0, i) if ship.vertical else QPoint(i, 0)))
        cells = []

        for cell in shipCells:
            arounds = [
                cell + QPoint(i, j) for i in range(-1, 2)
                for j in range(-1, 2)
            ]
            for candidate in arounds:
                if 0 <= candidate.x() < 10 and 0 <= candidate.y() < 10:
                    if candidate not in cells:
                        cells.append(candidate)

        for cell in cells:
            if cell not in shipCells:
                self.__setCell(cell.x(), cell.y(), "miss")
                self.__runAnimation(cell.x(), cell.y(), "splash")
        log.debug(
            f"name: {ship.name} | length: {ship.length} | pos: {ship.pos} | vertical: {ship.vertical}"
        )

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self, width):
        return width / self.__ratio

    def hideShipList(self):
        self.__ratio = self.RATIO_WITHOUT_SHIPLIST
        self.__scene.removeItem(self.__shipListItem)
        for _, ship in self.__shipList.items():
            self.__scene.removeItem(ship.shipItem)

        self.__adjustedToSize = None
        resize = QResizeEvent(self.size(), self.size())
        QApplication.postEvent(self, resize)

    def getPlacedShips(self):
        return self.__placedShips

    def placedShipsCount(self):
        return len(self.__placedShips)

    def hideShips(self):
        for ship in self.__placedShips:
            self.__scene.removeItem(ship)

    def removePlacedShips(self):
        if self.__shipListItem.scene() is None:
            return

        for ship in self.__placedShips:
            shipListItem = ship.data(1)
            shipListItem.count += 1
            shipListItem.counterText.setPlainText(str(shipListItem.count))
            self.__scene.removeItem(ship)

        self.__placedShips.clear()

    def shuffleShips(self):
        if self.__shipListItem.scene() is None:
            return

        self.removePlacedShips()

        def findPossibleCells(length, rotation):
            vertical = rotation.isVertical()
            if vertical == rotation.isHorizontal():
                raise Exception(
                    "Unknown state! Rotation is not horizontal and not vertical."
                )  # wtf

            width = 1 if vertical else length
            height = length if vertical else 1

            cells = []

            for x in range(10):
                for y in range(10):
                    if QRect(0, 0, 10, 10) != QRect(0, 0, 10, 10).united(
                            QRect(x, y, width, height)):
                        break
                    if self.__validatePosition(x, y, width, height):
                        cells.append(QPoint(x, y))

            return cells

        shipList = list(self.__shipList.values())
        shipList.sort(key=lambda ship: ship.length, reverse=True)
        for shipItem in shipList:
            for i in range(shipItem.count):
                rot = random.choice(list(Rotation))
                cells = findPossibleCells(shipItem.length, rot)

                if not cells:
                    rot = rot.next()
                    cells = findPossibleCells(shipItem.length, rot)

                if not cells:
                    return

                cell = random.choice(cells)
                self.__placeShip(shipItem, cell.x(), cell.y(), rot)

    def resizeEvent(self, event):
        size = event.size()
        if size == self.__adjustedToSize:
            return

        self.__adjustedToSize = size

        nowWidth = size.width()
        nowHeight = size.height()

        width = min(nowWidth, nowHeight * self.__ratio)
        height = min(nowHeight, nowWidth / self.__ratio)

        h_margin = round((nowWidth - width) / 2) - 2
        v_margin = round((nowHeight - height) / 2) - 2

        self.setContentsMargins(
            QMargins(h_margin, v_margin, h_margin, v_margin))
        self.__resizeScene()

    def scanEffect(self, x, y):
        """
        :return: True on success, False otherwise
        """
        if self.__scanEffect:
            return False

        def scanFinisedCallback():
            self.__scene.removeItem(self.__scanEffect)
            del self.__scanEffect
            self.__scanEffect = None

            target = FadingPixmapItem(self.__targetPixmap)
            target.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)
            target.setScale(self.__scaleFactor)
            target.setData(0, (x, y))
            self.__targets.append(target)
            self.__scene.addItem(target)

        self.__scanEffect = FloatingGradientItem(
            QRectF(self.tileSize, self.tileSize, self.__originalTileSize * 10,
                   self.__originalTileSize * 10), scanFinisedCallback)

        self.__scanEffect.setScale(self.__scaleFactor)

        self.__scanEffect.setBackwards(True)
        self.__scene.addItem(self.__scanEffect)
        return True

    def __resizeScene(self):
        width = self.__ui.graphicsView.width()
        height = self.__ui.graphicsView.height()
        self.__scene.setSceneRect(0, 0, width, height)

        self.tileSize = min(width / 11, height / (11 / self.__ratio))
        self.__scaleFactor = self.tileSize / self.__originalTileSize

        for i, cell in enumerate(self.__field):
            x = i % 10
            y = i // 10
            cell.setScale(self.__scaleFactor)
            cell.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)

        for sprite in self.__spriteAnimations:
            pos = sprite.data(0)
            sprite.setPos((pos.x() + 1) * self.tileSize,
                          (pos.y() + 1) * self.tileSize)
            sprite.setScale(self.__scaleFactor)

        for i in range(10):
            letter = self.__letters[i]
            letter.setScale(self.__scaleFactor)
            offsetX = (self.tileSize -
                       letter.boundingRect().width() * self.__scaleFactor) / 2
            offsetY = (self.tileSize -
                       letter.boundingRect().height() * self.__scaleFactor) / 2
            letter.setPos((i + 1) * self.tileSize + offsetX, offsetY)

            number = self.__numbers[i]
            number.setScale(self.__scaleFactor)
            offsetX = (self.tileSize -
                       number.boundingRect().width() * self.__scaleFactor) / 2
            offsetY = (self.tileSize -
                       number.boundingRect().height() * self.__scaleFactor) / 2
            number.setPos(offsetX, (i + 1) * self.tileSize + offsetY)

        xPos = 0
        for _, ship in self.__shipList.items():
            xPos += (ship.length - 1)
            xOffset = xPos * self.tileSize

            ship.shipItem.setScale(self.__scaleFactor)
            ship.shipItem.setPos(self.tileSize + xOffset,
                                 self.tileSize * (12 + self.EPS))

            ship.counterItem.setScale(self.__scaleFactor)
            ship.counterItem.setPos(self.tileSize + xOffset,
                                    self.tileSize * (12.65 + self.EPS))

            counterSize = ship.counterItem.boundingRect()
            textSize = ship.counterText.boundingRect()
            textXOffset = (counterSize.width() -
                           textSize.width()) * self.__scaleFactor / 2
            textYOffset = (counterSize.height() -
                           textSize.height()) * self.__scaleFactor / 2
            textX = ship.counterItem.pos().x() + textXOffset
            textY = ship.counterItem.pos().y() + textYOffset
            ship.counterText.setScale(self.__scaleFactor)
            ship.counterText.setPos(textX, textY)

        for ship in self.__placedShips:
            mapPos = ship.data(2)
            ship.setPos((mapPos.x() + 1) * self.tileSize,
                        (mapPos.y() + 1) * self.tileSize)
            ship.setScale(self.__scaleFactor)

        for target in self.__targets:
            x, y = target.data(0)
            target.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)
            target.setScale(self.__scaleFactor)

        if self.__scanEffect:
            self.__scanEffect.setPos(self.tileSize, self.tileSize)
            self.__scanEffect.setScale(self.__scaleFactor)

        shipListX = self.tileSize
        shipListY = self.tileSize * (11 + self.EPS)
        self.__shipListItem.setScale(self.__scaleFactor)
        self.__shipListItem.setPos(shipListX, shipListY)
        self.__ghostShip.setScale(self.__scaleFactor)

    def eventFilter(self, obj, event):
        if obj is self.__ui.graphicsView.viewport():
            if event.type() == QEvent.MouseButtonPress:
                self.__viewportMousePressEvent(event)
            elif event.type() == QEvent.MouseButtonRelease:
                self.__viewportMouseReleaseEvent(event)
            elif event.type() == QEvent.MouseMove:
                self.__viewportMouseMoveEvent(event)

        return super().eventFilter(obj, event)

    def sceneToMap(self, x, y):
        x -= self.tileSize
        y -= self.tileSize
        x //= self.tileSize
        y //= self.tileSize
        return int(x), int(y)

    def __initGhostShip(self, ship, pos):
        self.__ghostShip.setPixmap(QPixmap.fromImage(ship.image))
        self.__ghostShip.setPos(pos)
        self.__ghostShip.setRotation(0)

        width = self.__ghostShip.boundingRect().width()
        height = self.__ghostShip.boundingRect().height()
        self.__ghostShip.setOffset(-width / 2, -height / 2)
        self.__ghostShip.setData(0, Rotation.UP)
        self.__ghostShip.setData(1, ship)

        self.__placer.setRect(0, 0, self.tileSize, self.tileSize * ship.length)
        self.__placer.setZValue(50)

        self.__scene.addItem(self.__ghostShip)
        self.__ghostShip.setZValue(100)

    def __rotateGhostShip(self, rotation=None):
        rotation = rotation if rotation else self.__ghostShip.data(0).next()
        self.__ghostShip.setData(0, rotation)
        self.__ghostShip.setRotation(rotation.value)

        placerRect = self.__placer.rect()
        maxSide = max(placerRect.width(), placerRect.height())
        minSide = min(placerRect.width(), placerRect.height())

        if rotation.isHorizontal():
            self.__placer.setRect(0, 0, maxSide, minSide)
        elif rotation.isVertical():
            self.__placer.setRect(0, 0, minSide, maxSide)
        else:
            raise Exception(
                "Unknown state! Rotation is not horizontal and not vertical."
            )  # wtf
        self.__validatePlacer()

    def __ghostShipLongSurface(self):
        pos = self.__ghostShip.pos()
        x = pos.x()
        y = pos.y()
        rot: Rotation = self.__ghostShip.data(0)
        length = self.__ghostShip.data(1).length
        if rot.isHorizontal():
            x -= self.tileSize * length / 2
            return x, y

        if rot.isVertical():
            y -= self.tileSize * length / 2
            return x, y

    def __validatePosition(self, x, y, width=1, height=1):
        positionRect = QRectF((x + 1) * self.tileSize, (y + 1) * self.tileSize,
                              self.tileSize * width, self.tileSize * height)

        isPlacerValid = True
        for ship in self.__placedShips:
            shipRect = ship.mapRectToScene(ship.boundingRect()).adjusted(
                -self.tileSize / 2, -self.tileSize / 2, self.tileSize / 2,
                self.tileSize / 2)
            isPlacerValid = not positionRect.intersects(shipRect)
            if not isPlacerValid:
                break
        return isPlacerValid

    def __validatePlacer(self):
        sceneX, sceneY = self.__ghostShipLongSurface()
        x, y = self.sceneToMap(sceneX, sceneY)
        self.__placer.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)

        permittedArea = QRectF(self.__ui.graphicsView.viewport().geometry())
        permittedArea.setTopLeft(QPointF(self.tileSize, self.tileSize))
        permittedArea.setBottomRight(
            QPointF(self.tileSize * 12, self.tileSize * 12))
        placerSize = self.__placer.boundingRect()
        placerRect = QRectF(sceneX, sceneY, placerSize.width(),
                            placerSize.height())

        isPlacerValid = False
        # first validation - ship can be placed inside game field
        if permittedArea.contains(self.__ghostShip.pos(
        )) and permittedArea == permittedArea.united(placerRect):
            if self.__placer.scene() == None:
                self.__scene.addItem(self.__placer)
            x, y = self.sceneToMap(sceneX, sceneY)
            self.__placer.setPos((x + 1) * self.tileSize,
                                 (y + 1) * self.tileSize)
            isPlacerValid = True

        else:
            if self.__placer.scene() == self.__scene:
                self.__scene.removeItem(self.__placer)

        # second validation - placer does not intersect with other ships
        if isPlacerValid:
            isPlacerValid = self.__validatePosition(
                x, y,
                placerSize.width() / self.tileSize,
                placerSize.height() / self.tileSize)

        # set color of placer
        pen = self.__placer.pen()
        if isPlacerValid:
            pen.setColor(Qt.GlobalColor.darkGreen)
        else:
            pen.setColor(Qt.GlobalColor.red)
        self.__placer.setPen(pen)
        self.__placer.setData(0, isPlacerValid)

    def __placeShip(self, shipListItem, x, y, rotation):
        sceneX, sceneY = (x + 1) * self.tileSize, (y + 1) * self.tileSize

        shipListItem.count -= 1
        shipListItem.counterText.setPlainText(str(shipListItem.count))

        pixmap = QPixmap(shipListItem.image).transformed(QTransform().rotate(
            (rotation.value)))
        placedShip = QGraphicsPixmapItem(pixmap)
        placedShip.setData(0, rotation)
        placedShip.setData(1, shipListItem)
        placedShip.setData(2, QPoint(x, y))  # position in map coordinates

        placedShip.setPos(sceneX, sceneY)
        placedShip.setTransformationMode(
            Qt.TransformationMode.SmoothTransformation)
        placedShip.setScale(self.__scaleFactor)

        self.__placedShips.append(placedShip)
        self.__scene.addItem(placedShip)

    def __placeGhostShip(self):
        isPlacingPermitted = self.__placer.data(0)
        if isPlacingPermitted:
            sceneX = self.__placer.pos().x() + self.tileSize / 2
            sceneY = self.__placer.pos().y() + self.tileSize / 2
            mapX, mapY = self.sceneToMap(sceneX, sceneY)
            rotation = self.__ghostShip.data(0)
            if rotation.isVertical():
                vertical = True
            elif rotation.isHorizontal():
                vertical = False
            else:
                raise Exception(
                    "Unknown state! Rotation is not horizontal and not vertical."
                )  # wtf

            shipListItem = self.__ghostShip.data(1)
            self.__placeShip(shipListItem, mapX, mapY, rotation)

            log.debug(
                f"ship \"{shipListItem.name}\"; "
                f"position ({mapX}, {mapY}); "
                f"oriented {'vertically' if vertical else 'horizontally'}")

            self.shipPlaced.emit(
                Ship(name=shipListItem.name,
                     length=shipListItem.length,
                     pos=QPoint(mapX, mapY),
                     vertical=vertical))

    def __viewportMousePressEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            if self.__shipListItem.scene():
                # check press on shiplist
                shipUnderMouse = None
                for _, ship in self.__shipList.items():
                    if ship.shipItem.isUnderMouse():
                        shipUnderMouse = ship
                        break

                # check press on field
                rotation = Rotation.RIGHT
                if shipUnderMouse == None:
                    for ship in self.__placedShips:
                        if ship.isUnderMouse():
                            rotation = ship.data(0)
                            shipListItem = ship.data(1)

                            if shipListItem.count == 0:
                                shipListItem.shipItem.setGraphicsEffect(None)

                            shipListItem.count += 1
                            shipListItem.counterText.setPlainText(
                                str(shipListItem.count))
                            shipUnderMouse = shipListItem
                            self.__placedShips.remove(ship)
                            self.__scene.removeItem(ship)
                            break

                # if ship grabbed
                if shipUnderMouse and shipUnderMouse.count > 0:
                    self.__initGhostShip(shipUnderMouse, event.pos())
                    self.__rotateGhostShip(rotation)
                    self.__dragShip = True

            x, y = self.sceneToMap(event.pos().x(), event.pos().y())
            if x >= 0 and x < 10 and y >= 0 and y < 10:
                if self.controller.isBot:
                    return
                self.controller.emitHit(x, y)

        if event.button() == Qt.MouseButton.RightButton:
            if self.__dragShip:
                self.__rotateGhostShip()

    def __viewportMouseReleaseEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            if self.__dragShip:
                self.__scene.removeItem(self.__ghostShip)
                self.__dragShip = False
            if self.__placer.scene() != None:
                self.__scene.removeItem(self.__placer)

            # self.__placeShip()
            self.__placeGhostShip()
            self.__placer.setData(0, False)

    def __viewportMouseMoveEvent(self, event):
        if self.__dragShip:
            self.__ghostShip.setPos(event.pos())

            permittedArea = QRectF(
                self.__ui.graphicsView.viewport().geometry())
            permittedArea.setTopLeft(QPointF(self.tileSize, self.tileSize))

            # stop dragging ship if mouse out of field
            # if not permittedArea.contains(event.pos()):
            #     self.__scene.removeItem(self.__ghostShip)
            #     self.__dragShip = False

            self.__validatePlacer()

    def __accept(self, x, y, hit_type: CellState):
        log.debug(
            f" -- ACCEPTED -- hit on point ({x}, {y}) hit type: {hit_type}")
        cell = self.__field[y * 10 + x]

        if cell.data(0) != "intact":
            return
        if hit_type in [CellState.HIT, CellState.KILLED]:
            self.__setCell(x, y, 'hit')
            self.__runAnimation(x, y, "explosion", looped=True)
            for target in self.__targets:
                if (x, y) == target.data(0):
                    self.__scene.removeItem(target)
                    self.__targets.remove(target)
                    break
        elif hit_type in [CellState.MISS]:
            self.__setCell(x, y, 'miss')
            self.__runAnimation(x, y, "splash", looped=False)

        if hit_type == CellState.KILLED:
            for ship in self.__placedShips:
                rotation = ship.data(0)
                length = ship.data(1).length
                position = ship.data(2)
                width = 1 if rotation.isVertical() else length
                height = length if rotation.isVertical() else 1
                rect = QRect(position.x(), position.y(), width, height)
                if rect.contains(x, y):
                    self.__scene.addItem(ship)

    def __decline(self, x, y):
        log.debug(f"declined hit on point ({x}, {y})")
Exemplo n.º 29
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)
Exemplo n.º 30
0
class AnimatedCalendar():
    updatesRunning = False
    updateTimer = None
    listUpdateThread = None
    calDataLock = threading.Lock()
    calDataUpdated = False
    curCalendars = None
    
    def __init__(self, scene, widthCalTextArea, heightCalTextArea, borders, calFeeds, calUpdateSecs):
        self.masterScene = scene
        self.widthCalTextArea = widthCalTextArea
        self.heightCalTextArea = heightCalTextArea
        self.borders = borders
        self.calFeeds = calFeeds
        self.calendarUpdateSecs = calUpdateSecs
        # Background
        self.textBkgd = QGraphicsRectItem(0, 0, self.widthCalTextArea, self.heightCalTextArea)
        self.textBkgd.setPos(self.borders[3], self.borders[0])
        self.textBkgd.setBrush(QColor("light green"))
        self.textBkgd.setZValue(10)
        
        scene.addItem(self.textBkgd)
        # Text Item
        self.textItem = QGraphicsTextItem()
        self.textItem.setFont(QFont("Segoe UI", 24))
        self.textItem.setDefaultTextColor(QColor("black"))
        self.textItem.setPos(QPointF(self.borders[3]+10,self.borders[0]+10))
        self.textItem.setHtml("<B>Hello</B>Hello")
        self.textItem.setZValue(20)
        self.textItem.setTextWidth(self.widthCalTextArea-20)
        scene.addItem(self.textItem)
        
    def start(self):
        self.updatesRunning = True
        QTimer.singleShot(100, self.updateCalendar)
        self.listUpdateThread = CalendarUpdateThread(self, self.calFeeds, self.calendarUpdateSecs)
        self.listUpdateThread.start()
#        print("CalStarted")

    def stop (self):
        self.updatesRunning = False
        if self.updateTimer != None:
            self.updateTimer.stop()
        if self.listUpdateThread != None:
            self.listUpdateThread.stop()
    
    def setNewCalendarEntries(self, calendars):
        with self.calDataLock:
            self.curCalendars = calendars
            self.calDataUpdated = True
        
    def updateCalendar(self):
#        print("Update cal")
        
        with self.calDataLock:
            if self.calDataUpdated and self.curCalendars != None:
                for calEvents in self.curCalendars:
                    calStr = ""
                    lastDay = -1
                    for anEvent in calEvents:
                        # date, duration, summary, location, UID
                        eventDate = anEvent[0]
                        duration = anEvent[1]
                        summary = anEvent[2]
                        location = anEvent[3]
                        if lastDay != eventDate.day:
                            if lastDay != -1:
                                calStr += "<br/>"
                            calStr += "<b>" + anEvent[0].strftime("%a") + " (" + anEvent[0].strftime("%d %B)") + ")</b><br/>"
                            lastDay = eventDate.day
                        strDurTime = str(duration).rpartition(":")[0]
                        durStr = (str(duration.days) + "day" + ("s" if duration.days != 1 else "")) if duration.days > 0 else strDurTime
                        locStr = "<small>("+location+")</small>" if location != "" else ""
                        calStr += anEvent[0].strftime("%H:%M") + " <small>(" + durStr + ")</small> " + summary + " " + locStr + "<br/>"
#                        print (anEvent)
    #                    print(date)
                    self.textItem.setHtml(calStr)
                    self.textItem.setTextWidth(self.widthCalTextArea-20)
                    self.textItem.update()
            self.calDataUpdated = False
        
        if not self.updatesRunning:
            return 
        self.updateTimer = QTimer()
        self.updateTimer.setInterval(5000)
        self.updateTimer.setSingleShot(True)
        self.updateTimer.timeout.connect(self.updateCalendar)
        self.updateTimer.start()
Exemplo n.º 31
0
class BankNodeItem (NodeItem):
    maincolor = FlPalette.bank
    altcolor = FlPalette.bankvar
    label = "%s Bank"
    
    def __init__ (self, nodeobj, parent=None, view=None, state=1):
        super().__init__(nodeobj, parent, view, state)
        self.rect = QRectF()
        self.setZValue(-1)
        self.updatecomment()
        self.updatebanktype()
        self.updatebankmode()
    
    def nudgechildren(self):
        super().nudgechildren()
        for sub in self.sublist():
            sub.setrank(self)
    
    def sublist (self):
        ID = self.nodeobj.ID
        itemtable = self.view.itemtable
        if self.state == 1 and ID in itemtable and not self.iscollapsed():
            children = []
            for child in self.nodeobj.subnodes:
                if child in itemtable[ID]:
                    item = itemtable[ID][child]
                else:
                    continue
                if item.state > -1:
                    children.append(item)
            return children
        else:
            return []
    
    def treeposition (self, ranks=None):
        self.updatelayout(external=True)
        return super().treeposition(ranks)
    
    def graphicsetup (self):
        super().graphicsetup()
        darkbrush = QBrush(FlPalette.bg)
        nopen = QPen(0)
        viewport = self.view.viewport()
        
        self.btypeicon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.btypeicon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.btypeicon.x()
        self.fggroup.addToGroup(self.btypeicon)
        
        self.centerbox = QGraphicsRectItem(self)
        self.centerbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        self.centerbox.setRect(QRectF())
        self.centerbox.setBrush(darkbrush)
        self.centerbox.setPen(nopen)
        self.centerbox.setPos(0, self.nodelabel.y()+self.nodelabel.boundingRect().height()+self.style.itemmargin*2)
        self.fggroup.addToGroup(self.centerbox)
    
    def updatebanktype (self):
        types = {"talk": "(T)", "response": "(R)", "": ""}
        self.nodelabel.setText("%s Bank %s" % (self.realid(), types[self.nodeobj.banktype]))
    
    def updatebankmode (self):
        icons = {"First": "bank-first", "All": "bank-all", "Append": "bank-append", "": "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.bankmode])
        self.btypeicon.setPixmap(pixmap)
        if self.nodeobj.bankmode:
            self.btypeicon.setToolTip("Bank mode: %s" % self.nodeobj.bankmode)
        else:
            self.btypeicon.setToolTip("")
    
    def updatecenterbox (self):
        verticalpos = self.centerbox.y()
        maxwidth = self.style.nodetextwidth
        subnodes = self.sublist()
        for subnode in subnodes:
            if subnode.nodeobj.typename == "bank":
                subnode.updatelayout(external=True)
            noderect = subnode.boundingRect()
            nodeheight = noderect.height()
            nodewidth = noderect.width()
            subnode.show()
            subnode.yoffset = self.mapToScene(0,verticalpos + nodeheight/2+self.style.activemargin).y()-self.y_bottom()
            verticalpos += nodeheight+self.style.activemargin*2
            maxwidth = max(maxwidth, nodewidth)
        centerrect = self.centerbox.rect()
        centerrect.setWidth(maxwidth+self.style.selectmargin*2)
        centerrect.setHeight(verticalpos-self.centerbox.y())
        self.centerbox.setRect(centerrect)
        centerrect = self.centerbox.mapRectToParent(centerrect)
        
        self.comment.setY(centerrect.bottom()+self.style.itemmargin)
    
    def updatelayout (self, external=False):
        subnodes = self.sublist()
        if self.iscollapsed():
            rect = self.nodelabel.mapRectToParent(self.nodelabel.boundingRect())
        else:
            self.updatecenterbox()
            rect = self.fggroup.childrenBoundingRect()
        mainrect = rect.marginsAdded(self.style.banknodemargins)
        self.mainbox.setRect(mainrect)
        self.shadowbox.setRect(mainrect)
        self.selectbox.setRect(mainrect.marginsAdded(self.style.selectmargins))
        activerect = mainrect.marginsAdded(self.style.activemargins)
        self.activebox.setRect(activerect)
        oldypos = self.centerbox.mapToScene(self.centerbox.pos()).y()
        self.graphgroup.setPos(-activerect.width()//2-activerect.x(), -activerect.height()//2-activerect.y())
        newypos = self.centerbox.mapToScene(self.centerbox.pos()).y()
        for subnode in subnodes:
            subnode.yoffset += newypos - oldypos
            subnode.setY(self.y())
        self.prepareGeometryChange()
        self.rect = self.graphgroup.mapRectToParent(mainrect)
        if not external:
            self.view.updatelayout()
    
    def setY (self, y):
        super().setY(y)
        for subnode in self.sublist():
            subnode.setY(y)
    
    def contextMenuEvent (self, event):
        menu = QMenu()
        if self.isselected():
            window = FlGlob.mainwindow
            menu.addAction(window.actions["collapse"])
            if self.isghost():
                menu.addAction(window.actions["selectreal"])
            menu.addAction(window.actions["copynode"])
            menu.addMenu(window.subnodemenu)
            menu.addMenu(window.addmenu)
            menu.addAction(window.actions["moveup"])
            menu.addAction(window.actions["movedown"])
            menu.addAction(window.actions["parentswap"])
            menu.addAction(window.actions["unlinknode"])
            menu.addAction(window.actions["unlinkstree"])
            menu.addAction(window.actions["settemplate"])
            menu.addMenu(window.transformmenu)
        if not menu.isEmpty():
            menu.exec_(event.screenPos())
Exemplo n.º 32
0
class TextInputWidget(QGraphicsObject):

    input_entered = pyqtSignal(str)
    input_cancelled = pyqtSignal(str)
    font = QFont('monospace', 16)

    def __init__(self,
                 mode: str = 'number',
                 label: str = '',
                 getter=None,
                 setter=None,
                 parser=str,
                 validator=None,
                 parent: Optional[QGraphicsItem] = None):
        QGraphicsObject.__init__(self, parent)
        self.getter: Callable[[], str] = getter
        self.setter: Callable[[str], None] = setter
        self.parser: Callable[[str], Any] = parser
        self.validator: Callable[[Any], bool] = validator
        self.accept_button = Button("btn_accept", "Accept", parent=self)
        self.accept_button.set_base_color([ButtonColor.GREEN])
        self.accept_button.clicked.connect(self.handle_input_accepted)
        self.cancel_button = Button("btn_cancel", "Cancel", parent=self)
        self.cancel_button.set_base_color([ButtonColor.RED])
        self.cancel_button.clicked.connect(
            lambda: self.input_cancelled.emit(self.text_field.toPlainText()))
        self.accept_button.set_height(12)
        self.cancel_button.set_height(12)
        self.hor_padding = 2
        self.background_rect = QGraphicsRectItem(parent=self)
        self.background_rect.setBrush(QBrush(QColor(50, 50, 50, 200)))
        self.text_field = NumberInputItem(self)
        self.text_field.setFont(self.font)
        self.text_field.setTextInteractionFlags(Qt.TextEditable)
        self.text_field.setDefaultTextColor(Qt.white)
        self.text_field.text_changed.connect(self.adjust_layout)
        self.text_field.set_is_number_mode(mode == 'number')
        if self.getter is not None:
            self.text_field.setPlainText(str(self.getter()))
            self.adjust_layout()
        self.text_field.accepted.connect(
            lambda: self.accept_button.click_button(artificial_emit=True))
        self.text_field.cancelled.connect(
            lambda: self.cancel_button.click_button(artificial_emit=True))
        self.text_label = QGraphicsTextItem(self)
        self.text_label.setFont(self.font)
        self.text_label.setPlainText(label)
        self.text_label.setDefaultTextColor(Qt.white)
        self.setVisible(False)

    def paint(self,
              painter: QPainter,
              option: QStyleOptionGraphicsItem,
              widget: Optional[QWidget] = ...) -> None:
        pass

    def boundingRect(self) -> QRectF:
        return self.background_rect.boundingRect().united(self.accept_button.boundingRect())\
            .united(self.cancel_button.boundingRect())

    def adjust_layout(self):
        self.accept_button.fit_to_contents()
        self.cancel_button.fit_to_contents()
        total_width = 3 * self.hor_padding + self.text_field.boundingRect().width() \
                      + self.text_label.boundingRect().width()
        total_width = max(
            total_width,
            3 * self.hor_padding + self.accept_button.boundingRect().width() +
            self.cancel_button.boundingRect().width())
        total_height = self.text_field.boundingRect().height() + self.accept_button.boundingRect().height() \
                       + 3 * self.hor_padding
        self.background_rect.setRect(0, 0, total_width, total_height)
        self.setTransformOriginPoint(
            QPointF(0.5 * total_width, 0.5 * total_height))
        self.text_label.setPos(-0.5 * total_width + self.hor_padding,
                               -0.5 * total_height + self.hor_padding)
        self.text_field.setPos(
            self.hor_padding + self.text_label.pos().x() +
            self.text_label.boundingRect().width(),
            self.text_label.pos().y())
        self.background_rect.setPos(-0.5 * total_width, -0.5 * total_height)
        self.accept_button.set_width(
            (total_width - 3 * self.hor_padding) * 0.5)
        self.cancel_button.set_width(
            (total_width - 3 * self.hor_padding) * 0.5)
        self.accept_button.setPos(-0.5 * total_width + self.hor_padding,
                                  2 * self.hor_padding)
        self.cancel_button.setPos(self.accept_button.pos() + QPointF(
            self.hor_padding + self.accept_button.boundingRect().width(), 0.0))
        self.accept_button.set_disabled(
            len(self.text_field.toPlainText()) == 0)
        if self.validator is not None:
            try:
                value = self.parser(self.text_field.toPlainText())
                is_valid = self.validator(value)
            except ValueError:
                is_valid = False
            self.text_field.set_is_valid(is_valid)
            self.accept_button.set_disabled(not is_valid)
        self.update()

    def get_value(self) -> str:
        return self.text_field.toPlainText()

    def set_value(self, text: str):
        self.text_field.setPlainText(text)
        self.adjust_layout()
        self.set_focus()

    def set_focus(self):
        self.text_field.setFocus(Qt.PopupFocusReason)
        cursor = self.text_field.textCursor()
        cursor.movePosition(QTextCursor.EndOfLine)
        self.text_field.setTextCursor(cursor)

    def set_getter_setter_parser_validator(self, getter: Callable[[], Any],
                                           setter: Callable[[Any], None],
                                           parser: Callable[[str], Any],
                                           validator: Callable[[Any], bool]):
        self.getter = getter
        self.setter = setter
        self.parser = parser
        self.validator = validator
        if self.getter is not None:
            self.text_field.setPlainText(str(self.getter()))
            self.adjust_layout()

    def set_label(self, label: str):
        self.text_label.setPlainText(label)
        self.adjust_layout()

    def handle_input_accepted(self):
        self.setter(self.parser(self.text_field.toPlainText()))
        self.input_entered.emit(self.text_field.toPlainText())

    def handle_input_cancelled(self):
        self.input_cancelled.emit(str(self.getter()))
Exemplo n.º 33
0
class MainFunction(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.round = 50

        # set range.
        self.gScene = QGraphicsScene(0, 0,
                                     self.ui.graphicsView.width() - 5,
                                     self.ui.graphicsView.height() - 5,
                                     self.ui.graphicsView)
        print 'graphics View x %f', self.ui.graphicsView.width()
        print 'graphics View y %f', self.ui.graphicsView.height()
        self.ui.graphicsView.setScene(self.gScene)

        # test circle
        self.circle = QGraphicsEllipseItem()
        red = QBrush(Qt.red)
        pen = QPen(Qt.black)
        pen.setWidth(6)

        # test line
        self.x_line = QGraphicsLineItem(self.gScene.width() / 2, 0,
                                        self.gScene.width() / 2,
                                        self.gScene.height())
        self.gScene.addItem(self.x_line)
        self.y_line = QGraphicsLineItem(0,
                                        self.gScene.width() / 2,
                                        self.gScene.height(),
                                        self.gScene.width() / 2)
        self.gScene.addItem(self.y_line)

        #self.circle2 = DrawCircles(int(self.gScene.width()/2), int(self.gScene.height()/2))
        #self.gScene.addItem(self.circle2)

        print 'gScene View x %f', self.gScene.width() / 2
        print 'gScene View y %f', self.gScene.height() / 2

        self.circle = self.gScene.addEllipse(
            self.gScene.width() / 2 - self.round,
            self.gScene.height() / 2 - self.round, self.round * 2,
            self.round * 2, pen, red)

        # check Item argv.
        self.g_item = QGraphicsRectItem(self.gScene.width() / 2,
                                        self.gScene.height() / 2, 100, 100)
        self.gScene.addItem(self.g_item)
        self.g1_item = QGraphicsRectItem(self.gScene.width() / 2,
                                         self.gScene.height() / 2, 100, 100)
        self.gScene.addItem(self.g1_item)
        # self.gScene.addItem(self.circles)
        self.show()

    def slot_ok(self):
        random_x = np.random.random_integers(-300, 300)
        random_y = np.random.random_integers(-300, 300)

        # 값 조정은 display로 한다.
        self.ui.layer_a.display(100)

        tip = ''
        self.circle.setPos(float(random_x), float(random_y))
        self.g1_item.setPos(float(random_x), float(random_y))

        print 'x > %s' % self.g_item.x()
        print 'circle -> %d' % self.circle.x()
        print 'circle -> %d' % self.circle.y()

        if self.g_item.x() != self.circle.x():
            tip += ' move x > %f\n' % (self.g_item.x() - self.circle.x())
        if self.g_item.y() != self.circle.y():
            tip += ' move y > %f' % (self.g_item.y() - self.circle.y())

        self.ui.information.setText(tip)
Exemplo n.º 34
0
    buttonParent = QGraphicsRectItem()
    ellipseButton = Button(QPixmap(':/images/ellipse.png'), buttonParent)
    figure8Button = Button(QPixmap(':/images/figure8.png'), buttonParent)
    randomButton = Button(QPixmap(':/images/random.png'), buttonParent)
    tiledButton = Button(QPixmap(':/images/tile.png'), buttonParent)
    centeredButton = Button(QPixmap(':/images/centered.png'), buttonParent)

    ellipseButton.setPos(-100, -100)
    figure8Button.setPos(100, -100)
    randomButton.setPos(0, 0)
    tiledButton.setPos(-100, 100)
    centeredButton.setPos(100, 100)

    scene.addItem(buttonParent)
    buttonParent.setScale(0.75)
    buttonParent.setPos(200, 200)
    buttonParent.setZValue(65)

    # States.
    rootState = QState()
    ellipseState = QState(rootState)
    figure8State = QState(rootState)
    randomState = QState(rootState)
    tiledState = QState(rootState)
    centeredState = QState(rootState)

    # Values.
    for i, item in enumerate(items):
        # Ellipse.
        ellipseState.assignProperty(item, 'pos',
                QPointF(math.cos((i / 63.0) * 6.28) * 250,
Exemplo n.º 35
0
    def setAxisIntersect(self, intersect):
        self._axisIntersect = intersect
        # print "SkeletonsLayer(axis=%d) is updating intersect=%d" % (self._axis, self._axisIntersect)

        nodes, eIntersected, ePlane = self._3d._skeletons.intersect(self._axis, self._axisIntersect)

        # update existing items
        toRemove = []
        for node, item in self._node2view.items():
            if node.pos[self._axis] != self._axisIntersect:
                self._scene.removeItem(item)
                toRemove.append(node)
            elif node.pointF(self._axis) != item.pos():
                item.setPos(self._scene.data2scene.map(node.pointF(self._axis)))
            if node.isSelected() != item.isSelected():
                item.setSelected(node.isSelected())
                assert item.isSelected() == node.isSelected()
            i = 0
            newSize = [0, 0]
            for j in range(3):
                if j == self._axis:
                    continue
                newSize[i] = node.shape[j]
                i += 1
            newRectF = QRectF(0, 0, *newSize)
            newRectF = self._scene.data2scene.mapRect(newRectF)

            item.setRect(
                QRectF(
                    old_div(-newRectF.width(), 2.0),
                    old_div(-newRectF.height(), 2.0),
                    newRectF.width(),
                    newRectF.height(),
                )
            )

        for r in toRemove:
            del self._node2view[r]

        # add new views for nodes
        for n in nodes:
            if n in self._node2view:
                continue

            pos2D = list(n.pos)
            del pos2D[self._axis]

            shape2D = n.shape2D(self._axis)
            itm = QGraphicsSkeletonNode(shape2D, skeletons=self._3d._skeletons, node=n)
            itm.setPos(self._scene.data2scene.map(QPointF(*pos2D)))
            itm.setSelected(n.isSelected())

            self._scene.addItem(itm)
            self._node2view[n] = itm

        for itm in list(self._edge2view.values()):
            self._scene.removeItem(itm)
        self._edge2view = dict()

        for e in ePlane:
            l = QLineF(e[0].pointF(), e[1].pointF())

            c1 = e[0].color()
            c2 = e[1].color()
            assert sys.version_info.major == 2, (
                "Alert! This function has not been "
                "tested under python 3. Please remove this assertion and be wary of any "
                "strnage behavior you encounter"
            )
            mixColor = QColor((c1.red() + c2.red()) // 2, (c1.green() + c2.green()) // 2, (c1.blue() + c2.blue()) // 2)

            line = QGraphicsLineItem(self._scene.data2scene.map(l))
            line.setPen(QPen(mixColor))
            self._scene.addItem(line)
            self._edge2view[e] = line

        for theEdge, e in eIntersected:
            c1 = theEdge[0].color()
            c2 = theEdge[1].color()
            assert sys.version_info.major == 2, (
                "Alert! This function has not been "
                "tested under python 3. Please remove this assertion and be wary of any "
                "strnage behavior you encounter"
            )
            mixColor = QColor((c1.red() + c2.red()) // 2, (c1.green() + c2.green()) // 2, (c1.blue() + c2.blue()) // 2)

            nodeSize = 6
            p = QGraphicsRectItem(old_div(-nodeSize, 2), old_div(-nodeSize, 2), nodeSize, nodeSize)
            pos2D = list(e)
            del pos2D[self._axis]
            p.setPos(self._scene.data2scene.map(QPointF(*pos2D)))
            p.setPen(QPen(mixColor))
            self._scene.addItem(p)
            self._edge2view[e] = p
Exemplo n.º 36
0
class PianoRoll(QGraphicsScene):
    '''the piano roll'''

    midievent = pyqtSignal(list)
    measureupdate = pyqtSignal(int)
    modeupdate = pyqtSignal(str)

    def __init__(self, time_sig = '4/4', num_measures = 4, quantize_val = '1/8'):
        QGraphicsScene.__init__(self)
        self.setBackgroundBrush(QColor(50, 50, 50))
        self.mousePos = QPointF()

        self.notes = []
        self.selected_notes = []
        self.piano_keys = []

        self.marquee_select = False
        self.insert_mode = False
        self.velocity_mode = False
        self.place_ghost = False
        self.ghost_note = None
        self.default_ghost_vel = 100
        self.ghost_vel = self.default_ghost_vel

        ## dimensions
        self.padding = 2

        ## piano dimensions
        self.note_height = 10
        self.start_octave = -2
        self.end_octave = 8
        self.notes_in_octave = 12
        self.total_notes = (self.end_octave - self.start_octave) \
                * self.notes_in_octave + 1
        self.piano_height = self.note_height * self.total_notes
        self.octave_height = self.notes_in_octave * self.note_height

        self.piano_width = 34

        ## height
        self.header_height = 20
        self.total_height = self.piano_height - self.note_height + self.header_height
        #not sure why note_height is subtracted

        ## width
        self.full_note_width = 250 # i.e. a 4/4 note
        self.snap_value = None
        self.quantize_val = quantize_val

        ### dummy vars that will be changed
        self.time_sig = 0
        self.measure_width = 0
        self.num_measures = 0
        self.max_note_length = 0
        self.grid_width = 0
        self.value_width = 0
        self.grid_div = 0
        self.piano = None
        self.header = None
        self.play_head = None

        self.setTimeSig(time_sig)
        self.setMeasures(num_measures)
        self.setGridDiv()
        self.default_length = 1. / self.grid_div


    # -------------------------------------------------------------------------
    # Callbacks

    def movePlayHead(self, transport_info):
        # TODO: need conversion between frames and PPQ
        x = 105. # works for 120bpm
        total_duration = self.time_sig[0] * self.num_measures * x
        pos = transport_info['frame'] / x
        frac = (pos % total_duration) / total_duration
        self.play_head.setPos(QPointF(frac * self.grid_width, 0))

    def setTimeSig(self, time_sig):
        try:
           new_time_sig = list(map(float, time_sig.split('/')))
           if len(new_time_sig)==2:
               self.time_sig = new_time_sig

               self.measure_width = self.full_note_width * self.time_sig[0]/self.time_sig[1]
               self.max_note_length = self.num_measures * self.time_sig[0]/self.time_sig[1]
               self.grid_width = self.measure_width * self.num_measures
               self.setGridDiv()
        except ValueError:
            pass

    def setMeasures(self, measures):
        try:
            self.num_measures = float(measures)
            self.max_note_length = self.num_measures * self.time_sig[0]/self.time_sig[1]
            self.grid_width = self.measure_width * self.num_measures
            self.refreshScene()
        except:
            pass

    def setDefaultLength(self, length):
        try:
            v = list(map(float, length.split('/')))
            if len(v) < 3:
                self.default_length = \
                        v[0] if len(v)==1 else \
                        v[0] / v[1]
                pos = self.enforce_bounds(self.mousePos)
                if self.insert_mode: self.makeGhostNote(pos.x(), pos.y())
        except ValueError:
            pass

    def setGridDiv(self, div=None):
        if not div: div = self.quantize_val
        try:
            val = list(map(int, div.split('/')))
            if len(val) < 3:
                self.quantize_val = div
                self.grid_div = val[0] if len(val)==1 else val[1]
                self.value_width = self.full_note_width / float(self.grid_div) if self.grid_div else None
                self.setQuantize(div)

                self.refreshScene()
        except ValueError:
            pass

    def setQuantize(self, value):
        try:
            val = list(map(float, value.split('/')))
            if len(val) == 1:
                self.quantize(val[0])
                self.quantize_val = value
            elif len(val) == 2:
                self.quantize(val[0] / val[1])
                self.quantize_val = value
        except ValueError:
            pass

    # -------------------------------------------------------------------------
    # Event Callbacks

    def keyPressEvent(self, event):
        QGraphicsScene.keyPressEvent(self, event)
        if event.key() == Qt.Key_F:
            if not self.insert_mode:
                self.velocity_mode = False
                self.insert_mode = True
                self.makeGhostNote(self.mousePos.x(), self.mousePos.y())
                self.modeupdate.emit('insert_mode')
            elif self.insert_mode:
                self.insert_mode = False
                if self.place_ghost: self.place_ghost = False
                self.removeItem(self.ghost_note)
                self.ghost_note = None
                self.modeupdate.emit('')
        elif event.key() == Qt.Key_D:
            if self.velocity_mode:
                self.velocity_mode = False
                self.modeupdate.emit('')
            else:
                if self.insert_mode:
                    self.removeItem(self.ghost_note)
                self.ghost_note = None
                self.insert_mode = False
                self.place_ghost = False
                self.velocity_mode = True
                self.modeupdate.emit('velocity_mode')
        elif event.key() == Qt.Key_A:
            if all((note.isSelected() for note in self.notes)):
                for note in self.notes:
                    note.setSelected(False)
                self.selected_notes = []
            else:
                for note in self.notes:
                    note.setSelected(True)
                self.selected_notes = self.notes[:]
        elif event.key() in (Qt.Key_Delete, Qt.Key_Backspace):
            self.notes = [note for note in self.notes if note not in self.selected_notes]
            for note in self.selected_notes:
                self.removeItem(note)
                self.midievent.emit(["midievent-remove", note.note[0], note.note[1], note.note[2], note.note[3]])
                del note
            self.selected_notes = []

    def mousePressEvent(self, event):
        QGraphicsScene.mousePressEvent(self, event)
        if not (any(key.pressed for key in self.piano_keys)
                or any(note.pressed for note in self.notes)):
            for note in self.selected_notes:
                note.setSelected(False)
            self.selected_notes = []

            if event.button() == Qt.LeftButton:
                if self.insert_mode:
                    self.place_ghost = True
                else:
                    self.marquee_select = True
                    self.marquee_rect = QRectF(event.scenePos().x(), event.scenePos().y(), 1, 1)
                    self.marquee = QGraphicsRectItem(self.marquee_rect)
                    self.marquee.setBrush(QColor(255, 255, 255, 100))
                    self.addItem(self.marquee)
        else:
            for s_note in self.notes:
                if s_note.pressed and s_note in self.selected_notes:
                    break
                elif s_note.pressed and s_note not in self.selected_notes:
                    for note in self.selected_notes:
                        note.setSelected(False)
                    self.selected_notes = [s_note]
                    break
            for note in self.selected_notes:
                if not self.velocity_mode:
                    note.mousePressEvent(event)

    def mouseMoveEvent(self, event):
        QGraphicsScene.mouseMoveEvent(self, event)
        self.mousePos = event.scenePos()
        if not (any((key.pressed for key in self.piano_keys))):
            m_pos = event.scenePos()
            if self.insert_mode and self.place_ghost: #placing a note
                m_width = self.ghost_rect.x() + self.ghost_rect_orig_width
                if m_pos.x() > m_width:
                    m_new_x = self.snap(m_pos.x())
                    self.ghost_rect.setRight(m_new_x)
                    self.ghost_note.setRect(self.ghost_rect)
                #self.adjust_note_vel(event)
            else:
                m_pos = self.enforce_bounds(m_pos)

                if self.insert_mode: #ghostnote follows mouse around
                    (m_new_x, m_new_y) = self.snap(m_pos.x(), m_pos.y())
                    self.ghost_rect.moveTo(m_new_x, m_new_y)
                    try:
                        self.ghost_note.setRect(self.ghost_rect)
                    except RuntimeError:
                        self.ghost_note = None
                        self.makeGhostNote(m_new_x, m_new_y)

                elif self.marquee_select:
                    marquee_orig_pos = event.buttonDownScenePos(Qt.LeftButton)
                    if marquee_orig_pos.x() < m_pos.x() and marquee_orig_pos.y() < m_pos.y():
                        self.marquee_rect.setBottomRight(m_pos)
                    elif marquee_orig_pos.x() < m_pos.x() and marquee_orig_pos.y() > m_pos.y():
                        self.marquee_rect.setTopRight(m_pos)
                    elif marquee_orig_pos.x() > m_pos.x() and marquee_orig_pos.y() < m_pos.y():
                        self.marquee_rect.setBottomLeft(m_pos)
                    elif marquee_orig_pos.x() > m_pos.x() and marquee_orig_pos.y() > m_pos.y():
                        self.marquee_rect.setTopLeft(m_pos)
                    self.marquee.setRect(self.marquee_rect)
                    self.selected_notes = []
                    for item in self.collidingItems(self.marquee):
                        if item in self.notes:
                            self.selected_notes.append(item)

                    for note in self.notes:
                        if note in self.selected_notes: note.setSelected(True)
                        else: note.setSelected(False)

                elif self.velocity_mode:
                    if Qt.LeftButton == event.buttons():
                        for note in self.selected_notes:
                            note.updateVelocity(event)

                elif not self.marquee_select: #move selected
                    if Qt.LeftButton == event.buttons():
                        x = y = False
                        if any(note.back.stretch for note in self.selected_notes):
                            x = True
                        elif any(note.front.stretch for note in self.selected_notes):
                            y = True
                        for note in self.selected_notes:
                            note.back.stretch = x
                            note.front.stretch = y
                            note.moveEvent(event)

    def mouseReleaseEvent(self, event):
        if not (any((key.pressed for key in self.piano_keys)) or any((note.pressed for note in self.notes))):
            if event.button() == Qt.LeftButton:
                if self.place_ghost and self.insert_mode:
                    self.place_ghost = False
                    note_start = self.get_note_start_from_x(self.ghost_rect.x())
                    note_num = self.get_note_num_from_y(self.ghost_rect.y())
                    note_length = self.get_note_length_from_x(self.ghost_rect.width())
                    self.drawNote(note_num, note_start, note_length, self.ghost_vel)
                    self.midievent.emit(["midievent-add", note_num, note_start, note_length, self.ghost_vel])
                    self.makeGhostNote(self.mousePos.x(), self.mousePos.y())
                elif self.marquee_select:
                    self.marquee_select = False
                    self.removeItem(self.marquee)
        elif not self.marquee_select:
            for note in self.selected_notes:
                old_info = note.note[:]
                note.mouseReleaseEvent(event)
                if self.velocity_mode:
                    note.setSelected(True)
                if not old_info == note.note:
                    self.midievent.emit(["midievent-remove", old_info[0], old_info[1], old_info[2], old_info[3]])
                    self.midievent.emit(["midievent-add", note.note[0], note.note[1], note.note[2], note.note[3]])

    # -------------------------------------------------------------------------
    # Internal Functions

    def drawHeader(self):
        self.header = QGraphicsRectItem(0, 0, self.grid_width, self.header_height)
        #self.header.setZValue(1.0)
        self.header.setPos(self.piano_width, 0)
        self.addItem(self.header)

    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)

    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)

    def drawPlayHead(self):
        self.play_head = QGraphicsLineItem(self.piano_width, self.header_height, self.piano_width, self.total_height)
        self.play_head.setPen(QPen(QColor(255,255,255,50), 2))
        self.play_head.setZValue(1.)
        self.addItem(self.play_head)

    def refreshScene(self):
        list(map(self.removeItem, self.notes))
        self.selected_notes = []
        self.piano_keys = []
        self.clear()
        self.drawPiano()
        self.drawHeader()
        self.drawGrid()
        self.drawPlayHead()
        for note in self.notes[:]:
            if note.note[1] >= (self.num_measures * self.time_sig[0]):
                self.notes.remove(note)
                self.midievent.emit(["midievent-remove", note.note[0], note.note[1], note.note[2], note.note[3]])
            elif note.note[2] > self.max_note_length:
                new_note = note.note[:]
                new_note[2] = self.max_note_length
                self.notes.remove(note)
                self.drawNote(new_note[0], new_note[1], self.max_note_length, new_note[3], False)
                self.midievent.emit(["midievent-remove", note.note[0], note.note[1], note.note[2], note.note[3]])
                self.midievent.emit(["midievent-add", new_note[0], new_note[1], new_note[2], new_note[3]])
        list(map(self.addItem, self.notes))
        if self.views():
            self.views()[0].setSceneRect(self.itemsBoundingRect())

    def clearNotes(self):
        self.clear()
        self.notes = []
        self.selected_notes = []
        self.drawPiano()
        self.drawHeader()
        self.drawGrid()

    def makeGhostNote(self, pos_x, pos_y):
        """creates the ghostnote that is placed on the scene before the real one is."""
        if self.ghost_note:
            self.removeItem(self.ghost_note)
        length = self.full_note_width * self.default_length
        (start, note) = self.snap(pos_x, pos_y)
        self.ghost_vel = self.default_ghost_vel
        self.ghost_rect = QRectF(start, note, length, self.note_height)
        self.ghost_rect_orig_width = self.ghost_rect.width()
        self.ghost_note = QGraphicsRectItem(self.ghost_rect)
        self.ghost_note.setBrush(QColor(230, 221, 45, 100))
        self.addItem(self.ghost_note)

    def drawNote(self, note_num, note_start=None, note_length=None, note_velocity=None, add=True):
        """
        note_num: midi number, 0 - 127
        note_start: 0 - (num_measures * time_sig[0]) so this is in beats
        note_length: 0 - (num_measures  * time_sig[0]/time_sig[1]) this is in measures
        note_velocity: 0 - 127
        """

        info = [note_num, note_start, note_length, note_velocity]

        if not note_start % (self.num_measures * self.time_sig[0]) == note_start:
            #self.midievent.emit(["midievent-remove", note_num, note_start, note_length, note_velocity])
            while not note_start % (self.num_measures * self.time_sig[0]) == note_start:
                self.setMeasures(self.num_measures+1)
            self.measureupdate.emit(self.num_measures)
            self.refreshScene()

        x_start = self.get_note_x_start(note_start)
        if note_length > self.max_note_length:
            note_length = self.max_note_length + 0.25
        x_length = self.get_note_x_length(note_length)
        y_pos = self.get_note_y_pos(note_num)

        note = NoteItem(self.note_height, x_length, info)
        note.setPos(x_start, y_pos)

        self.notes.append(note)
        if add:
            self.addItem(note)

    # -------------------------------------------------------------------------
    # Helper Functions

    def frange(self, x, y, t):
        while x < y:
            yield x
            x += t

    def quantize(self, value):
        self.snap_value = float(self.full_note_width) * value if value else None

    def snap(self, pos_x, pos_y = None):
        if self.snap_value:
            pos_x = int(round((pos_x - self.piano_width) / self.snap_value)) \
                    * self.snap_value + self.piano_width
        if pos_y:
            pos_y = int((pos_y - self.header_height) / self.note_height) \
                    * self.note_height + self.header_height
        return (pos_x, pos_y) if pos_y else pos_x

    def adjust_note_vel(self, event):
        m_pos = event.scenePos()
        #bind velocity to vertical mouse movement
        self.ghost_vel += (event.lastScenePos().y() - m_pos.y())/10
        if self.ghost_vel < 0:
            self.ghost_vel = 0
        elif self.ghost_vel > 127:
            self.ghost_vel = 127

        m_width = self.ghost_rect.x() + self.ghost_rect_orig_width
        if m_pos.x() < m_width:
            m_pos.setX(m_width)
        m_new_x = self.snap(m_pos.x())
        self.ghost_rect.setRight(m_new_x)
        self.ghost_note.setRect(self.ghost_rect)


    def enforce_bounds(self, pos):
        if pos.x() < self.piano_width:
            pos.setX(self.piano_width)
        elif pos.x() > self.grid_width + self.piano_width:
            pos.setX(self.grid_width + self.piano_width)
        if pos.y() < self.header_height + self.padding:
            pos.setY(self.header_height + self.padding)
        return pos

    def get_note_start_from_x(self, note_x):
        return (note_x - self.piano_width) / (self.grid_width / self.num_measures / self.time_sig[0])


    def get_note_x_start(self, note_start):
        return self.piano_width + \
                (self.grid_width / self.num_measures / self.time_sig[0]) * note_start

    def get_note_x_length(self, note_length):
        return float(self.time_sig[1]) / self.time_sig[0] * note_length * self.grid_width / self.num_measures

    def get_note_length_from_x(self, note_x):
        return float(self.time_sig[0]) / self.time_sig[1] * self.num_measures / self.grid_width \
                * note_x


    def get_note_y_pos(self, note_num):
        return self.header_height + self.note_height * (self.total_notes - note_num - 1)

    def get_note_num_from_y(self, note_y_pos):
        return -(((note_y_pos - self.header_height) / self.note_height) - self.total_notes + 1)
Exemplo n.º 37
0
class PianoRoll(QGraphicsScene):
    '''the piano roll'''

    noteclicked = pyqtSignal(int,bool)
    midievent = pyqtSignal(list)
    measureupdate = pyqtSignal(int)
    modeupdate = pyqtSignal(str)

    default_ghost_vel = 100

    def __init__(self, time_sig = '4/4', num_measures = 4, quantize_val = '1/8'):
        QGraphicsScene.__init__(self)
        self.setBackgroundBrush(QColor(50, 50, 50))

        self.notes = []
        self.removed_notes = []
        self.selected_notes = []
        self.piano_keys = []

        self.marquee_select = False
        self.marquee_rect = None
        self.marquee = None

        self.ghost_note = None
        self.ghost_rect = None
        self.ghost_rect_orig_width = None
        self.ghost_vel = self.default_ghost_vel

        self.ignore_mouse_events = False
        self.insert_mode = False
        self.velocity_mode = False
        self.place_ghost = False
        self.last_mouse_pos = QPointF()

        ## dimensions
        self.padding = 2

        ## piano dimensions
        self.note_height = 10
        self.start_octave = -2
        self.end_octave = 8
        self.notes_in_octave = 12
        self.total_notes = (self.end_octave - self.start_octave) * self.notes_in_octave + 1
        self.piano_height = self.note_height * self.total_notes
        self.octave_height = self.notes_in_octave * self.note_height

        self.piano_width = 34

        ## height
        self.header_height = 20
        self.total_height = self.piano_height - self.note_height + self.header_height
        #not sure why note_height is subtracted

        ## width
        self.full_note_width = 250 # i.e. a 4/4 note
        self.snap_value = None
        self.quantize_val = quantize_val

        ### dummy vars that will be changed
        self.time_sig = (0,0)
        self.measure_width = 0
        self.num_measures = 0
        self.max_note_length = 0
        self.grid_width = 0
        self.value_width = 0
        self.grid_div = 0
        self.piano = None
        self.header = None
        self.play_head = None

        self.setGridDiv()
        self.default_length = 1. / self.grid_div


    # -------------------------------------------------------------------------
    # Callbacks

    def movePlayHead(self, transportInfo):
        ticksPerBeat = transportInfo['ticksPerBeat']
        max_ticks = ticksPerBeat * self.time_sig[0] * self.num_measures
        cur_tick = ticksPerBeat * self.time_sig[0] * transportInfo['bar'] + ticksPerBeat * transportInfo['beat'] + transportInfo['tick']
        frac = (cur_tick % max_ticks) / max_ticks
        self.play_head.setPos(QPointF(frac * self.grid_width, 0))

    def setTimeSig(self, time_sig):
        self.time_sig = time_sig
        self.measure_width = self.full_note_width * self.time_sig[0]/self.time_sig[1]
        self.max_note_length = self.num_measures * self.time_sig[0]/self.time_sig[1]
        self.grid_width = self.measure_width * self.num_measures
        self.setGridDiv()

    def setMeasures(self, measures):
        #try:
        self.num_measures = float(measures)
        self.max_note_length = self.num_measures * self.time_sig[0]/self.time_sig[1]
        self.grid_width = self.measure_width * self.num_measures
        self.refreshScene()
        #except:
            #pass

    def setDefaultLength(self, length):
        v = list(map(float, length.split('/')))
        if len(v) < 3:
            self.default_length = v[0] if len(v) == 1 else v[0] / v[1]
            pos = self.enforce_bounds(self.last_mouse_pos)
            if self.insert_mode:
                self.makeGhostNote(pos.x(), pos.y())

    def setGridDiv(self, div=None):
        if not div: div = self.quantize_val
        try:
            val = list(map(int, div.split('/')))
            if len(val) < 3:
                self.quantize_val = div
                self.grid_div = val[0] if len(val)==1 else val[1]
                self.value_width = self.full_note_width / float(self.grid_div) if self.grid_div else None
                self.setQuantize(div)

                self.refreshScene()
        except ValueError:
            pass

    def setQuantize(self, value):
        val = list(map(float, value.split('/')))
        if len(val) == 1:
            self.quantize(val[0])
            self.quantize_val = value
        elif len(val) == 2:
            self.quantize(val[0] / val[1])
            self.quantize_val = value

    # -------------------------------------------------------------------------
    # Event Callbacks

    def keyPressEvent(self, event):
        QGraphicsScene.keyPressEvent(self, event)

        if event.key() == Qt.Key_F:
            if not self.insert_mode:
                # turn off velocity mode
                self.velocity_mode = False
                # enable insert mode
                self.insert_mode = True
                self.place_ghost = False
                self.makeGhostNote(self.last_mouse_pos.x(), self.last_mouse_pos.y())
                self.modeupdate.emit('insert_mode')
            else:
                # turn off insert mode
                self.insert_mode = False
                self.place_ghost = False
                if self.ghost_note is not None:
                    self.removeItem(self.ghost_note)
                    self.ghost_note = None
                self.modeupdate.emit('')

        elif event.key() == Qt.Key_D:
            if not self.velocity_mode:
                # turn off insert mode
                self.insert_mode = False
                self.place_ghost = False
                if self.ghost_note is not None:
                    self.removeItem(self.ghost_note)
                    self.ghost_note = None
                # enable velocity mode
                self.velocity_mode = True
                self.modeupdate.emit('velocity_mode')
            else:
                # turn off velocity mode
                self.velocity_mode = False
                self.modeupdate.emit('')

        elif event.key() == Qt.Key_A:
            for note in self.notes:
                if not note.isSelected():
                    has_unselected = True
                    break
            else:
                has_unselected = False

            # select all notes
            if has_unselected:
                for note in self.notes:
                    note.setSelected(True)
                self.selected_notes = self.notes[:]
            # unselect all
            else:
                for note in self.notes:
                    note.setSelected(False)
                self.selected_notes = []

        elif event.key() in (Qt.Key_Delete, Qt.Key_Backspace):
            # remove selected notes from our notes list
            self.notes = [note for note in self.notes if note not in self.selected_notes]
            # delete the selected notes
            for note in self.selected_notes:
                self.removeItem(note)
                self.midievent.emit(["midievent-remove", note.note[0], note.note[1], note.note[2], note.note[3]])
                del note
            self.selected_notes = []

    def mousePressEvent(self, event):
        QGraphicsScene.mousePressEvent(self, event)

        # mouse click on left-side piano area
        if self.piano.contains(event.scenePos()):
            self.ignore_mouse_events = True
            return

        clicked_notes = []

        for note in self.notes:
            if note.pressed or note.back.stretch or note.front.stretch:
                clicked_notes.append(note)

        print("clicked_notes", clicked_notes)

        # mouse click on existing notes
        if clicked_notes:
            keep_selection = all(note in self.selected_notes for note in clicked_notes)
            if keep_selection:
                for note in self.selected_notes:
                    note.setSelected(True)
                return

            for note in self.selected_notes:
                if note not in clicked_notes:
                    note.setSelected(False)
            for note in clicked_notes:
                if note not in self.selected_notes:
                    note.setSelected(True)

            self.selected_notes = clicked_notes
            return

        # mouse click on empty area (no note selected)
        for note in self.selected_notes:
            note.setSelected(False)
        self.selected_notes = []

        if event.button() != Qt.LeftButton:
            return

        if self.insert_mode:
            self.place_ghost = True
        else:
            self.marquee_select = True
            self.marquee_rect = QRectF(event.scenePos().x(), event.scenePos().y(), 1, 1)
            self.marquee = QGraphicsRectItem(self.marquee_rect)
            self.marquee.setBrush(QColor(255, 255, 255, 100))
            self.addItem(self.marquee)

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

        self.last_mouse_pos = event.scenePos()

        if self.ignore_mouse_events:
            return

        pos = self.enforce_bounds(self.last_mouse_pos)

        if self.insert_mode:
            if self.ghost_note is None:
                self.makeGhostNote(pos.x(), pos.y())
            max_x = self.grid_width + self.piano_width

            # placing note, only width needs updating
            if self.place_ghost:
                pos_x = pos.x()
                min_x = self.ghost_rect.x() + self.ghost_rect_orig_width
                if pos_x < min_x:
                    pos_x = min_x
                new_x = self.snap(pos_x)
                self.ghost_rect.setRight(new_x)
                self.ghost_note.setRect(self.ghost_rect)
                #self.adjust_note_vel(event)

            # ghostnote following mouse around
            else:
                pos_x = pos.x()
                if pos_x + self.ghost_rect.width() >= max_x:
                    pos_x = max_x - self.ghost_rect.width()
                elif pos_x > self.piano_width + self.ghost_rect.width()*3/4:
                    pos_x -= self.ghost_rect.width()/2
                new_x, new_y = self.snap(pos_x, pos.y())
                self.ghost_rect.moveTo(new_x, new_y)
                self.ghost_note.setRect(self.ghost_rect)
            return

        if self.marquee_select:
            marquee_orig_pos = event.buttonDownScenePos(Qt.LeftButton)
            if marquee_orig_pos.x() < pos.x() and marquee_orig_pos.y() < pos.y():
                self.marquee_rect.setBottomRight(pos)
            elif marquee_orig_pos.x() < pos.x() and marquee_orig_pos.y() > pos.y():
                self.marquee_rect.setTopRight(pos)
            elif marquee_orig_pos.x() > pos.x() and marquee_orig_pos.y() < pos.y():
                self.marquee_rect.setBottomLeft(pos)
            elif marquee_orig_pos.x() > pos.x() and marquee_orig_pos.y() > pos.y():
                self.marquee_rect.setTopLeft(pos)
            self.marquee.setRect(self.marquee_rect)

            for note in self.selected_notes:
                note.setSelected(False)
            self.selected_notes = []

            for item in self.collidingItems(self.marquee):
                if item in self.notes:
                    item.setSelected(True)
                    self.selected_notes.append(item)
            return

        if event.buttons() != Qt.LeftButton:
            return

        if self.velocity_mode:
            for note in self.selected_notes:
                note.updateVelocity(event)
            return

        x = y = False
        for note in self.selected_notes:
            if note.back.stretch:
                x = True
                break
        for note in self.selected_notes:
            if note.front.stretch:
                y = True
                break
        for note in self.selected_notes:
            note.back.stretch = x
            note.front.stretch = y
            note.moveEvent(event)

    def mouseReleaseEvent(self, event):
        QGraphicsScene.mouseReleaseEvent(self, event)

        if self.ignore_mouse_events:
            self.ignore_mouse_events = False
            return

        if self.marquee_select:
            self.marquee_select = False
            self.removeItem(self.marquee)
            self.marquee = None

        if self.insert_mode and self.place_ghost:
            self.place_ghost = False
            note_start = self.get_note_start_from_x(self.ghost_rect.x())
            note_num = self.get_note_num_from_y(self.ghost_rect.y())
            note_length = self.get_note_length_from_x(self.ghost_rect.width())
            note = self.drawNote(note_num, note_start, note_length, self.ghost_vel)
            note.setSelected(True)
            self.selected_notes.append(note)
            self.midievent.emit(["midievent-add", note_num, note_start, note_length, self.ghost_vel])
            pos = self.enforce_bounds(self.last_mouse_pos)
            pos_x = pos.x()
            if pos_x > self.piano_width + self.ghost_rect.width()*3/4:
                pos_x -= self.ghost_rect.width()/2
            self.makeGhostNote(pos_x, pos.y())

        for note in self.selected_notes:
            note.back.stretch = False
            note.front.stretch = False

    # -------------------------------------------------------------------------
    # Internal Functions

    def drawHeader(self):
        self.header = QGraphicsRectItem(0, 0, self.grid_width, self.header_height)
        #self.header.setZValue(1.0)
        self.header.setPos(self.piano_width, 0)
        self.addItem(self.header)

    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, 78, self.piano)
        label = QGraphicsSimpleTextItem('C9', 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, 0, -1):
            for j in range(self.notes_in_octave, 0, -1):
                note = (self.end_octave - i + 3) * 12 - j
                if j in black_notes:
                    key = PianoKeyItem(piano_keys_width/1.4, self.note_height, note, 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, note, 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, note, 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, note, 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 + 1), key)
                    label.setPos(18, 6)
                    label.setFont(piano_label)
                self.piano_keys.append(key)

    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)

    def drawPlayHead(self):
        self.play_head = QGraphicsLineItem(self.piano_width, self.header_height, self.piano_width, self.total_height)
        self.play_head.setPen(QPen(QColor(255,255,255,50), 2))
        self.play_head.setZValue(1.)
        self.addItem(self.play_head)

    def refreshScene(self):
        list(map(self.removeItem, self.notes))
        self.selected_notes = []
        self.piano_keys = []
        self.place_ghost = False
        if self.ghost_note is not None:
            self.removeItem(self.ghost_note)
            self.ghost_note = None
        self.clear()
        self.drawPiano()
        self.drawHeader()
        self.drawGrid()
        self.drawPlayHead()

        for note in self.notes[:]:
            if note.note[1] >= (self.num_measures * self.time_sig[0]):
                self.notes.remove(note)
                self.removed_notes.append(note)
                #self.midievent.emit(["midievent-remove", note.note[0], note.note[1], note.note[2], note.note[3]])
            elif note.note[2] > self.max_note_length:
                new_note = note.note[:]
                new_note[2] = self.max_note_length
                self.notes.remove(note)
                self.drawNote(new_note[0], new_note[1], self.max_note_length, new_note[3], False)
                self.midievent.emit(["midievent-remove", note.note[0], note.note[1], note.note[2], note.note[3]])
                self.midievent.emit(["midievent-add", new_note[0], new_note[1], new_note[2], new_note[3]])

        for note in self.removed_notes[:]:
            if note.note[1] < (self.num_measures * self.time_sig[0]):
                self.removed_notes.remove(note)
                self.notes.append(note)

        list(map(self.addItem, self.notes))
        if self.views():
            self.views()[0].setSceneRect(self.itemsBoundingRect())

    def clearNotes(self):
        self.clear()
        self.notes = []
        self.removed_notes = []
        self.selected_notes = []
        self.drawPiano()
        self.drawHeader()
        self.drawGrid()

    def makeGhostNote(self, pos_x, pos_y):
        """creates the ghostnote that is placed on the scene before the real one is."""
        if self.ghost_note is not None:
            self.removeItem(self.ghost_note)
        length = self.full_note_width * self.default_length
        pos_x, pos_y = self.snap(pos_x, pos_y)
        self.ghost_vel = self.default_ghost_vel
        self.ghost_rect = QRectF(pos_x, pos_y, length, self.note_height)
        self.ghost_rect_orig_width = self.ghost_rect.width()
        self.ghost_note = QGraphicsRectItem(self.ghost_rect)
        self.ghost_note.setBrush(QColor(230, 221, 45, 100))
        self.addItem(self.ghost_note)

    def drawNote(self, note_num, note_start, note_length, note_velocity, add=True):
        """
        note_num: midi number, 0 - 127
        note_start: 0 - (num_measures * time_sig[0]) so this is in beats
        note_length: 0 - (num_measures  * time_sig[0]/time_sig[1]) this is in measures
        note_velocity: 0 - 127
        """

        info = [note_num, note_start, note_length, note_velocity]

        if not note_start % (self.num_measures * self.time_sig[0]) == note_start:
            #self.midievent.emit(["midievent-remove", note_num, note_start, note_length, note_velocity])
            while not note_start % (self.num_measures * self.time_sig[0]) == note_start:
                self.setMeasures(self.num_measures+1)
            self.measureupdate.emit(self.num_measures)
            self.refreshScene()

        x_start = self.get_note_x_start(note_start)
        if note_length > self.max_note_length:
            note_length = self.max_note_length + 0.25
        x_length = self.get_note_x_length(note_length)
        y_pos = self.get_note_y_pos(note_num)

        note = NoteItem(self.note_height, x_length, info)
        note.setPos(x_start, y_pos)

        self.notes.append(note)

        if add:
            self.addItem(note)

        return note

    # -------------------------------------------------------------------------
    # Helper Functions

    def frange(self, x, y, t):
        while x < y:
            yield x
            x += t

    def quantize(self, value):
        self.snap_value = float(self.full_note_width) * value if value else None

    def snap(self, pos_x, pos_y = None):
        if self.snap_value:
            pos_x = int(round((pos_x - self.piano_width) / self.snap_value)) * self.snap_value + self.piano_width
        if pos_y is not None:
            pos_y = int((pos_y - self.header_height) / self.note_height) * self.note_height + self.header_height
        return (pos_x, pos_y) if pos_y is not None else pos_x

    def adjust_note_vel(self, event):
        m_pos = event.scenePos()
        #bind velocity to vertical mouse movement
        self.ghost_vel += (event.lastScenePos().y() - m_pos.y())/10
        if self.ghost_vel < 0:
            self.ghost_vel = 0
        elif self.ghost_vel > 127:
            self.ghost_vel = 127

        m_width = self.ghost_rect.x() + self.ghost_rect_orig_width
        if m_pos.x() < m_width:
            m_pos.setX(m_width)
        m_new_x = self.snap(m_pos.x())
        self.ghost_rect.setRight(m_new_x)
        self.ghost_note.setRect(self.ghost_rect)

    def enforce_bounds(self, pos):
        pos = QPointF(pos)
        if pos.x() < self.piano_width:
            pos.setX(self.piano_width)
        elif pos.x() >= self.grid_width + self.piano_width:
            pos.setX(self.grid_width + self.piano_width - 1)
        if pos.y() < self.header_height + self.padding:
            pos.setY(self.header_height + self.padding)
        return pos

    def get_note_start_from_x(self, note_x):
        return (note_x - self.piano_width) / (self.grid_width / self.num_measures / self.time_sig[0])

    def get_note_x_start(self, note_start):
        return self.piano_width + (self.grid_width / self.num_measures / self.time_sig[0]) * note_start

    def get_note_x_length(self, note_length):
        return float(self.time_sig[1]) / self.time_sig[0] * note_length * self.grid_width / self.num_measures

    def get_note_length_from_x(self, note_x):
        return float(self.time_sig[0]) / self.time_sig[1] * self.num_measures / self.grid_width * note_x

    def get_note_y_pos(self, note_num):
        return self.header_height + self.note_height * (self.total_notes - note_num - 1)

    def get_note_num_from_y(self, note_y_pos):
        return -(int((note_y_pos - self.header_height) / self.note_height) - self.total_notes + 1)

    def move_note(self, old_note, new_note):
        self.midievent.emit(["midievent-remove", old_note[0], old_note[1], old_note[2], old_note[3]])
        self.midievent.emit(["midievent-add", new_note[0], new_note[1], new_note[2], new_note[3]])
Exemplo n.º 38
0
class Scene(QGraphicsScene):
    def __init__(self, parent=None):
        QGraphicsScene.__init__(self, parent)

        # set pritisnutih tastera
        self.keys_pressed = set()

        # pozadina
        self.bg = QGraphicsRectItem()
        self.bg.setRect(-1, -1, SCREEN_WIDTH + 2, SCREEN_HEIGHT + 2)
        self.bg.setBrush(QBrush(Qt.black))
        self.addItem(self.bg)

        # brojaci za pomeranje protivnika
        self.left = 1
        self.right = 5

        # lista protivnika
        self.enemies = []
        # nasumicni indeks protivnika koji puca
        self.randomEnemyIndex = randint(0, len(self.enemies))
        # nasumicna lista indeksa protivnika koji ce imati specijalnu moc
        self.enemyPowerUps = []

        # pravljenje i iscrtavanje protivnika
        self.threadFinished = False
        _thread.start_new_thread(self.draw_enemies, ())
        while not self.threadFinished:
            continue
        self.threadFinished = False

        # igrac 1 (plavi)
        self.player1 = Player1()
        self.player1.setPos(20, 530)
        self.addItem(self.player1)

        # igrac 2 (crveni)
        self.player2 = Player2()
        self.player2.setPos(589, 530)
        self.addItem(self.player2)

        # metak igraca 1 (plavi)
        self.bullet1 = Bullet1(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y)
        self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.addItem(self.bullet1)

        # metak igraca 2 (crveni)
        self.bullet2 = Bullet2(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y)
        self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.addItem(self.bullet2)

        # pobednik
        self.winner = 0

        # power up i power down igraca 1 (plavi)
        self.player1PowerUp = QGraphicsPixmapItem()
        self.player1PowerUp.setPixmap(QPixmap("Images/powerUp.png"))
        self.player1PowerDown = QGraphicsPixmapItem()
        self.player1PowerDown.setPixmap(QPixmap("Images/powerDown.png"))

        # power up i power down igraca 2 (crveni)
        self.player2PowerUp = QGraphicsPixmapItem()
        self.player2PowerUp.setPixmap(QPixmap("Images/powerUp.png"))
        self.player2PowerDown = QGraphicsPixmapItem()
        self.player2PowerDown.setPixmap(QPixmap("Images/powerDown.png"))

        # protivnicki metak (narandzasti)
        self.bulletEnemy = BulletEnemy(ENEMY_BULLET_X_OFFSET,
                                       ENEMY_BULLET_Y_OFFSET)
        self.bulletEnemy.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.addItem(self.bulletEnemy)

        # polje za rezultate
        self.scoreField = QGraphicsRectItem()
        self.scoreField.setRect(672, -1, 128, SCREEN_HEIGHT + 2)
        self.scoreField.setBrush(QBrush(Qt.darkGray))
        self.addItem(self.scoreField)

        # trenutni nivo
        self.level = 1

        # iscrtavanje trenutnog nivoa
        self.levelFont = QFont()
        self.levelFont.setPixelSize(25)
        self.levelFont.setBold(1)
        self.levelField = QGraphicsSimpleTextItem("Level: " + str(self.level))
        self.levelField.setBrush(QBrush(Qt.green))
        self.levelField.setPos(677, 20)
        self.levelField.setFont(self.levelFont)
        self.addItem(self.levelField)

        self.playerFont = QFont()
        self.playerFont.setPixelSize(20)
        self.playerFont.setBold(1)

        # iscrtavanje broja zivota igraca 1
        self.player1Lives = QGraphicsSimpleTextItem("Player 1: ")
        self.player1Lives.setBrush(QBrush(Qt.blue))
        self.player1Lives.setPos(674, 130)
        self.player1Lives.setFont(self.playerFont)
        self.addItem(self.player1Lives)
        self.livesPlayer1 = [
            LifePlayer1(680, 175),
            LifePlayer1(720, 175),
            LifePlayer1(760, 175)
        ]
        for l in self.livesPlayer1:
            self.addItem(l)

        # iscrtavanje broja zivota igraca 2
        self.player2Lives = QGraphicsSimpleTextItem("Player 2: ")
        self.player2Lives.setBrush(QBrush(Qt.blue))
        self.player2Lives.setPos(674, 330)
        self.player2Lives.setFont(self.playerFont)
        self.addItem(self.player2Lives)
        self.livesPlayer2 = [
            LifePlayer2(680, 375),
            LifePlayer2(720, 375),
            LifePlayer2(760, 375)
        ]
        for l in self.livesPlayer2:
            self.addItem(l)

        self.scoreFont = QFont()
        self.scoreFont.setPixelSize(20)
        self.scoreFont.setBold(1)

        # iscrtavanje rezultata igraca 1
        self.player1Score = 0
        self.player1Scores = QGraphicsSimpleTextItem("Score: \n" +
                                                     str(self.player1Score))
        self.player1Scores.setBrush(QBrush(Qt.blue))
        self.player1Scores.setPos(674, 220)
        self.player1Scores.setFont(self.scoreFont)
        self.addItem(self.player1Scores)

        # iscrtavanje rezultata igraca 1
        self.player2Score = 0
        self.player2Scores = QGraphicsSimpleTextItem("Score: \n" +
                                                     str(self.player2Score))
        self.player2Scores.setBrush(QBrush(Qt.blue))
        self.player2Scores.setPos(674, 420)
        self.player2Scores.setFont(self.scoreFont)
        self.addItem(self.player2Scores)

        # tajmer za iscrtavanje slike 60 puta u sekndi (60 fps)
        self.timer = QBasicTimer()
        self.timer.start(16, self)

        # tajmer za pomeranje neprijatelja
        self.timerEnemy = QTimer()
        self.timerEnemy.timeout.connect(self.game_update_enemy)
        self.timerEnemy.start(1000)

        # icrtavanje scene
        self.view = QGraphicsView(self)
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.show()
        self.view.setFixedSize(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.setSceneRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
        self.view.setGeometry(560, 240, 0, 0)

    def keyPressEvent(self, event):
        self.keys_pressed.add(event.key())

    def keyReleaseEvent(self, event):
        self.keys_pressed.remove(event.key())

    def timerEvent(self, event):
        self.game_update()
        self.update()

    def game_update(self):
        self.player1.game_update(self.keys_pressed)
        self.player2.game_update(self.keys_pressed)

        for e in self.enemies:
            # ako je neprijatelj zavrsio sa padanjem, brisemo ga
            if e.frames == -1:
                self.removeItem(e)
                self.enemies.remove(e)
                continue
            # ako je neprijatelj izabran za padanje, nastavlja da pada
            if e.chosen:
                e.collapse()

            # igrac 1 pogodio neprijatelja
            if e.x() <= self.bullet1.x() <= e.x() + 32:
                if e.y() <= self.bullet1.y() <= e.y() + 26:
                    if e.powerUp:
                        temp = randint(0, 3)
                        if temp == 0:
                            if self.player1.speed == 2:
                                self.removeItem(self.player1PowerDown)
                            self.player1.speed = 8
                            self.player1PowerUp.setPos(770, 130)
                            self.addItem(self.player1PowerUp)
                        elif temp == 1:
                            if self.player1.speed == 8:
                                self.removeItem(self.player1PowerUp)
                            self.player1.speed = 2
                            self.player1PowerDown.setPos(770, 130)
                            self.addItem(self.player1PowerDown)
                        elif temp == 2:
                            if self.player1.lives == 3:
                                pass
                            elif self.player1.lives == 2:
                                self.livesPlayer1.append(LifePlayer1(760, 175))
                                self.player1.lives += 1
                                self.addItem(self.livesPlayer1[-1])
                            elif self.player1.lives == 1:
                                self.livesPlayer1.append(LifePlayer1(720, 175))
                                self.player1.lives += 1
                                self.addItem((self.livesPlayer1[-1]))
                            else:
                                pass
                        else:
                            self.player1Score += 100
                            self.player1Scores.setText("Score: \n" +
                                                       str(self.player1Score))
                    self.removeItem(e)
                    self.enemies.remove(e)
                    self.removeItem(self.bullet1)
                    self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
                    self.addItem(self.bullet1)
                    self.player1Score += 10
                    self.player1Scores.setText("Score: \n" +
                                               str(self.player1Score))
                    continue

            # igrac 2 pogodio neprijatelja
            if e.x() <= self.bullet2.x() <= e.x() + 32:
                if e.y() <= self.bullet2.y() <= e.y() + 26:
                    if e.powerUp:
                        temp = randint(0, 3)
                        if temp == 0:
                            if self.player2.speed == 2:
                                self.removeItem(self.player2PowerDown)
                            self.player2.speed = 8
                            self.player2PowerUp.setPos(770, 330)
                            self.addItem(self.player2PowerUp)
                        elif temp == 1:
                            if self.player2.speed == 8:
                                self.removeItem(self.player2PowerUp)
                            self.player2.speed = 2
                            self.player2PowerDown.setPos(770, 330)
                            self.addItem(self.player2PowerDown)
                        elif temp == 2:
                            if self.player2.lives == 3:
                                pass
                            elif self.player2.lives == 2:
                                self.livesPlayer2.append(LifePlayer2(760, 375))
                                self.player2.lives += 1
                                self.addItem(self.livesPlayer2[-1])
                            elif self.player2.lives == 1:
                                self.livesPlayer2.append(LifePlayer2(720, 375))
                                self.player2.lives += 1
                                self.addItem((self.livesPlayer2[-1]))
                            else:
                                pass
                        else:
                            self.player2Score += 100
                            self.player2Scores.setText("Score: \n" +
                                                       str(self.player2Score))
                    self.removeItem(e)
                    self.enemies.remove(e)
                    self.removeItem(self.bullet2)
                    self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
                    self.addItem(self.bullet2)
                    self.player2Score += 10
                    self.player2Scores.setText("Score: \n" +
                                               str(self.player2Score))
                    continue

            # na igraca 1 se obrusio neprijatelj
            if self.player1.y() <= e.y() + 26 <= self.player1.y() + 53:
                if self.player1.x() <= e.x(
                ) <= self.player1.x() + 69 or self.player1.x(
                ) <= e.x() + 32 <= self.player1.x() + 69:
                    if self.player1.lives > 0:
                        if self.player1.speed == 8:
                            self.removeItem(self.player1PowerUp)
                        elif self.player1.speed == 2:
                            self.removeItem(self.player1PowerDown)
                        self.player1.speed = 4
                        e.frames = -1
                        self.player1.lives -= 1
                        self.removeItem(self.livesPlayer1[-1])
                        self.livesPlayer1.remove(self.livesPlayer1[-1])
                        self.player1.setPos(20, 530)
                        if self.player1.lives <= 0:
                            self.removeItem(self.player1)
                            if self.player1.speed == 8:
                                self.removeItem(self.player1PowerUp)
                            elif self.player1.speed == 2:
                                self.removeItem(self.player1PowerDown)
                            if self.player2.lives > 0:
                                self.winner = 2

            # na igraca 2 se obrusio neprijatelj
            if self.player2.y() <= e.y() + 26 <= self.player2.y() + 53:
                if self.player2.x() <= e.x(
                ) <= self.player2.x() + 69 or self.player2.x(
                ) <= e.x() + 32 <= self.player2.x() + 69:
                    if self.player2.lives > 0:
                        if self.player2.speed == 8:
                            self.removeItem(self.player1PowerUp)
                        elif self.player2.speed == 2:
                            self.removeItem(self.player2PowerDown)
                        self.player2.speed = 4
                        e.frames = -1
                        self.player2.lives -= 1
                        self.removeItem(self.livesPlayer2[-1])
                        self.livesPlayer2.remove(self.livesPlayer2[-1])
                        self.player2.setPos(589, 530)
                        if self.player2.lives <= 0:
                            self.removeItem(self.player2)
                            if self.player2.speed == 8:
                                self.removeItem(self.player2PowerUp)
                            elif self.player2.speed == 2:
                                self.removeItem(self.player2PowerDown)
                            if self.player1.lives > 0:
                                self.winner = 1

        # igraca 1 pogodio laser neprijatelja
        if self.player1.x() + 69 >= self.bulletEnemy.x() >= self.player1.x():
            if self.player1.y() + 53 >= self.bulletEnemy.y() >= self.player1.y(
            ):
                if self.player1.lives > 0:
                    if self.player1.speed == 8:
                        self.removeItem(self.player1PowerUp)
                    elif self.player1.speed == 2:
                        self.removeItem(self.player1PowerDown)
                    self.player1.speed = 4
                    self.bulletEnemy.active = False
                    self.player1.lives -= 1
                    self.removeItem(self.livesPlayer1[-1])
                    self.livesPlayer1.remove(self.livesPlayer1[-1])
                    self.player1.setPos(20, 530)
                    if self.player1.lives <= 0:
                        self.removeItem(self.player1)
                        if self.player2.lives > 0:
                            self.winner = 2

        # igraca 2 pogodio laser neprijatelja
        if self.player2.x() + 69 >= self.bulletEnemy.x() >= self.player2.x():
            if self.player2.y() + 53 >= self.bulletEnemy.y() >= self.player2.y(
            ):
                if self.player2.lives > 0:
                    if self.player2.speed == 8:
                        self.removeItem(self.player2PowerUp)
                    elif self.player2.speed == 2:
                        self.removeItem(self.player2PowerDown)
                    self.player2.speed = 4
                    self.bulletEnemy.active = False
                    self.player2.lives -= 1
                    self.removeItem(self.livesPlayer2[-1])
                    self.livesPlayer2.remove(self.livesPlayer2[-1])
                    self.player2.setPos(589, 530)
                    if self.player2.lives <= 0:
                        self.removeItem(self.player2)
                        if self.player1.lives > 0:
                            self.winner = 1

        # pomeranje metaka
        self.bullet1.game_update(self.keys_pressed, self.player1)
        self.bullet2.game_update(self.keys_pressed, self.player2)
        try:
            self.bulletEnemy.game_update(self.enemies[self.randomEnemyIndex])
            if not self.bulletEnemy.active:
                self.randomEnemyIndex = randint(0, len(self.enemies))
        except:
            self.randomEnemyIndex = randint(0, len(self.enemies))

        # nasumicno biranje obrusavanja
        try:
            if randint(0, 500) == 0:
                self.enemies[randint(0, len(self.enemies))].chosen = True
        except:
            pass

        # kraj igre
        if self.player1.lives == 0 and self.player2.lives == 0:
            self.timer.stop()
            self.timerEnemy.stop()
            self.removeItem(self.bg)
            self.bg.setPos(-128, 0)
            self.addItem(self.bg)
            fontWinner = QFont()
            fontWinner.setPixelSize(40)
            textWinner = QGraphicsSimpleTextItem()
            textWinner.setFont(fontWinner)
            if self.winner == 1:
                textWinner.setText("WINNER PLAYER 1")
                textWinner.setBrush(QBrush(Qt.blue))
                self.player1.setPos(310, 300)
                self.addItem(self.player1)
            elif self.winner == 2:
                textWinner.setText("WINNER PLAYER 2")
                textWinner.setBrush(QBrush(Qt.red))
                self.player2.setPos(310, 300)
                self.addItem(self.player2)
            textWinner.setPos(180, 200)
            self.addItem(textWinner)

        # pobedjen nivo
        if len(self.enemies) == 0:
            self.timer.stop()
            self.timerEnemy.stop()
            if self.player1.lives > 0:
                self.removeItem(self.player1)
                self.removeItem(self.bullet1)
            if self.player2.lives > 0:
                self.removeItem(self.player2)
                self.removeItem(self.bullet2)
            self.removeItem(self.bulletEnemy)
            self.new_level()

    # pomeranje neprijatelja
    def game_update_enemy(self):
        if 0 < self.right < 9:
            self.right += 1
            if self.right == 9:
                self.right = 0
                self.left = 1
            for e in self.enemies:
                e.move_right()
        elif 0 < self.left < 9:
            self.left += 1
            if self.left == 9:
                self.left = 0
                self.right = 1
            for e in self.enemies:
                e.move_left()

    # pravljenje novog nivoa
    def new_level(self):
        self.level += 1
        self.levelField.setText("Level: " + str(self.level))

        self.left = 1
        self.right = 5

        self.threadFinished = False
        _thread.start_new_thread(self.draw_enemies, ())
        while not self.threadFinished:
            continue
        self.threadFinished = False

        for e in self.enemies:
            e.collapseSpeed += self.level
            e.collapseFrames = 700 / e.collapseSpeed

        if self.player1.lives > 0:
            self.player1.setPos(20, 530)
            self.bullet1 = Bullet1(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y)
            self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
            self.addItem(self.bullet1)
            self.addItem(self.player1)
        if self.player2.lives > 0:
            self.player2.setPos(589, 530)
            self.bullet2 = Bullet2(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y)
            self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
            self.addItem(self.bullet2)
            self.addItem(self.player2)

        self.bulletEnemy = BulletEnemy(ENEMY_BULLET_X_OFFSET,
                                       ENEMY_BULLET_Y_OFFSET)
        self.bulletEnemy.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.bulletEnemy.speed += self.level
        self.bulletEnemy.frames = 700 / self.bulletEnemy.speed
        self.addItem(self.bulletEnemy)

        self.timer.start(16, self)
        self.timerEnemy.start(1000)

    def draw_enemies(self):
        self.threadFinished = False
        self.enemies = [
            Enemy(131, 10),
            Enemy(173, 10),
            Enemy(215, 10),
            Enemy(257, 10),
            Enemy(299, 10),
            Enemy(341, 10),
            Enemy(383, 10),
            Enemy(425, 10),
            Enemy(467, 10),
            Enemy(509, 10),
            Enemy(131, 50),
            Enemy(173, 50),
            Enemy(215, 50),
            Enemy(257, 50),
            Enemy(299, 50),
            Enemy(341, 50),
            Enemy(383, 50),
            Enemy(425, 50),
            Enemy(467, 50),
            Enemy(509, 50),
            Enemy(131, 90),
            Enemy(173, 90),
            Enemy(215, 90),
            Enemy(257, 90),
            Enemy(299, 90),
            Enemy(341, 90),
            Enemy(383, 90),
            Enemy(425, 90),
            Enemy(467, 90),
            Enemy(509, 90)
        ]

        pool = multiprocessing.Pool(processes=1)
        result = pool.apply_async(get_enemy_power_ups,
                                  (len(self.enemies) - 1, 5))
        self.enemyPowerUps = result.get(timeout=1)
        pool.close()

        for i in self.enemyPowerUps:
            self.enemies[i].setPixmap(QPixmap("Images/enemyPowerUp.png"))
            self.enemies[i].powerUp = True

        for e in self.enemies:
            self.addItem(e)

        self.randomEnemyIndex = randint(0, len(self.enemies))

        self.threadFinished = True
Exemplo n.º 39
0
class NodeItem(QGraphicsItem):
    def __init__ (self, nodeobj, parent=None, view=None, state=1):
        super().__init__()
        self.edge = None
        self.linkIDs = None
        self.children = None
        self.childpos = None
        self.nodeobj = nodeobj
        self.style = FlGlob.mainwindow.style
        self.view = weakref.proxy(view)
        self.refID = parent.realid() if parent is not None else None
        self.state = state
        self.setrank(parent)
        self.setCursor(Qt.ArrowCursor)
        self.yoffset = 0
        self.graphicsetup()
        self.setstate(state)
    
    def id (self):
        return (self.refID, self.nodeobj.ID)
    
    def realid (self):
        return self.nodeobj.ID
    
    def childlist (self, generate=False):
        ID = self.nodeobj.ID
        itemtable = self.view.itemtable
        if self.state == 1 and ID in itemtable and not self.iscollapsed():
            if self.children and self.nodeobj.linkIDs == self.linkIDs and None not in [c() for c in self.children]:
                ret = self.children
            else:
                children = []
                for child in self.nodeobj.linkIDs:
                    if child in itemtable[ID]:
                        item = itemtable[ID][child]
                    else:
                        continue
                    children.append(weakref.ref(item))
                self.linkIDs = self.nodeobj.linkIDs.copy()
                self.children = children
                ret = children
        else:
            ret = []
        if generate:
            x = self.x()
            y = self.y()
            self.childpos = []
            for target in ret:
                t = target()
                self.childpos.append((t.x()+t.boundingRect().left()-self.style.activemargin-x, t.y()-y))
            if self.edge:
                if self.childpos != self.edge.childpos:
                    self.edge.prepareGeometryChange()
                    self.edge.sourceright = self.boundingRect().right()
                    self.edge.update(self.edge.boundingRect())
        return ret
    
    def setedge (self, edge):
        self.edge = edge
        edge.setX(self.x())
    
    def setactive (self, active):
        if active:
            self.activebox.show()
            self.mainbox.setBrush(QBrush(self.altcolor))
        else:
            self.activebox.hide()
            self.mainbox.setBrush(QBrush(self.maincolor))
    
    def setselected (self, selected):
        if selected:
            self.selectbox.show()
        else:
            self.selectbox.hide()
    
    def setstate (self, state):
        self.state = state
        if state == 1: # normal
            self.show()
            self.graphgroup.setOpacity(1)
            self.shadowbox.show()
        elif state == 0: # ghost
            self.show()
            self.graphgroup.setOpacity(0.7)
            self.shadowbox.hide()
        elif state == -1: # hidden
            self.hide()
    
    def setplaymode (self, playmode):
        if playmode:
            self.setOpacity(0.5)
        else:
            self.setOpacity(1)
    
    def setY (self, y):
        parent = self.view.itembyID(self.refID)
        y += self.getyoffset()
        if self.edge is not None:
            self.edge.setY(y)
        super().setY(y)
    
    def setrank (self, parent):
        if parent is None:
            return
        if self.issubnode():
            x = parent.x()
            self.setX(x)
        else:
            x = parent.x()+self.style.rankwidth
            self.setX(x)
            self.nudgechildren()
        if self.edge is not None:
            self.edge.setX(x)
    
    def nudgechildren (self):
        for child in self.childlist():
            child().setrank(self)
    
    def getyoffset (self):
        if self.nodeobj.nodebank == -1:
            return self.yoffset
        else:
            return self.view.itembyID(self.refID).getyoffset() + self.yoffset
    
    def hide (self):
        super().hide()
        if self.edge:
            self.edge.hide()
    
    def show (self):
        super().show()
        if self.edge:
            self.edge.show()
    
    def issubnode (self):
        return self.nodeobj.nodebank is not -1
    
    def isghost (self):
        return not self.state
    
    def realnode (self):
        return self.view.itembyID(self.nodeobj.ID)
    
    def isactive (self):
        return self.view.activenode is self
    
    def isselected (self):
        return self.view.selectednode is self
    
    def iscollapsed (self):
        return self.id() in self.view.collapsednodes
    
    def y_top (self):
        return self.y() - self.boundingRect().height()//2
    
    def y_bottom (self):
        return self.y() + self.boundingRect().height()//2
    
    def bulkshift (self, children, diff):
        self.setY(self.y() + diff)
        if children is None:
            children = [c() for c in self.childlist()]
        for child in children:
            child.bulkshift(None, diff)
    
    def treeposition (self, ranks=None):
        if ranks is None:
            ranks = dict()
        localranks = dict()
        children = [c() for c in self.childlist()]
        for child in children:
            localranks = child.treeposition(localranks)
        rank = self.x() // self.style.rankwidth
        if children:
            top = children[0].y_top()
            bottom = children[-1].y_bottom()
            self.setY((top+bottom)//2)
        localranks[rank] = [self.y_top, self.y_bottom]
        streeshift = None
        for r in localranks:
            if r in ranks:
                rankshift = ranks[r][1]() + self.style.rowgap - localranks[r][0]()
                if streeshift is None or rankshift > streeshift:
                    streeshift = rankshift
                ranks[r][1] = localranks[r][1]
            else:
                ranks[r] = localranks[r]
        if streeshift:
            self.bulkshift(children, streeshift)
        return ranks
    
    def siblings (self):
        if self.refID is None:
            return None
        parent = self.view.nodecontainer.nodes[self.refID]
        if self.issubnode():
            return parent.subnodes
        else:
            return parent.linkIDs
    
    def siblingabove (self):
        sibs = self.siblings()
        if sibs is None or self.nodeobj.ID not in sibs:
            return None
        myindex = sibs.index(self.nodeobj.ID)
        if myindex:
            sibID = (self.refID, sibs[myindex-1])
            return self.view.itembyfullID(sibID)
        else:
            return None
    
    def siblingbelow (self):
        sibs = self.siblings()
        if sibs is None or self.nodeobj.ID not in sibs:
            return None
        myindex = sibs.index(self.nodeobj.ID)
        if len(sibs) > myindex+1:
            sibID = (self.refID, sibs[myindex+1])
            return self.view.itembyfullID(sibID)
        else:
            return None
    
    def subtreesize (self, depth=-1):
        """Find vertical extents of a subtree.
        
        Returns min/max y coordinates up to given depth (negative depth means
        whole subtree)."""

        # calculate child positions for EgdeItem only once when calculating scenerect
        if depth<0:
            generate = True
        else:
            generate = False
        
        children = [c() for c in self.childlist(generate=generate)]
        maxdepth = abs(depth)
        if children and depth:
            nextdepth = depth-1
            ymin = self.y_top()
            ymax = self.y_bottom()
            for child in children:
                top, bottom, depth = child.subtreesize(nextdepth)
                ymin = min(ymin, top)
                ymax = max(ymax, bottom)
                maxdepth = max(maxdepth, depth)
        else:
            ymin = self.y_top()
            ymax = self.y_bottom()
        return ymin, ymax, maxdepth
        
    def boundingRect (self):
        return self.rect
    
    def paint (self, painter, style, widget):
        pass
    
    def pixmap (self, path):
        return QPixmap(path).scaledToWidth(self.style.boldheight, Qt.SmoothTransformation)
    
    def graphicsetup (self):
        lightbrush = QBrush(FlPalette.light)
        mainbrush = QBrush(self.maincolor)
        altbrush = QBrush(self.altcolor)
        nopen = QPen(0)
        viewport = self.view.viewport()
        
        self.graphgroup = QGraphicsItemGroup(self)
        self.fggroup = QGraphicsItemGroup(self)
        
        self.shadowbox = QGraphicsRectItem(self)
        self.shadowbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        self.shadowbox.setBrush(FlPalette.dark)
        self.shadowbox.setPen(nopen)
        self.shadowbox.setPos(*(self.style.shadowoffset,)*2)
        self.graphgroup.addToGroup(self.shadowbox)
        
        self.activebox = QGraphicsRectItem(self)
        self.activebox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        activepen = QPen(self.maincolor, self.style.selectmargin, join=Qt.MiterJoin)
        self.activebox.setPen(activepen)
        self.activebox.hide()
        self.graphgroup.addToGroup(self.activebox)
        
        self.selectbox = QGraphicsRectItem(self)
        self.selectbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        selectpen = QPen(FlPalette.light, self.style.selectmargin, join=Qt.MiterJoin)
        self.selectbox.setPen(selectpen)
        self.selectbox.hide()
        self.graphgroup.addToGroup(self.selectbox)
        
        self.mainbox = QGraphicsRectItem(self)
        self.mainbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        self.mainbox.setBrush(mainbrush)
        self.mainbox.setPen(nopen)
        self.graphgroup.addToGroup(self.mainbox)
        
        self.nodelabel = QGraphicsSimpleTextItemCond(self, viewport)
        self.nodelabel.setBrush(lightbrush)
        self.nodelabel.setFont(self.style.boldfont)
        self.nodelabel.setText(self.label % self.realid())
        self.nodelabel.setPos(self.style.itemmargin, self.style.itemmargin)
        self.fggroup.addToGroup(self.nodelabel)
        
        self.icon = self.pixmap("images/blank.png")
        self.iwidth = self.icon.width()
        self.iconx = self.style.nodetextwidth
        
        self.condicon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.condicon.setPos(self.iconx-self.iwidth, self.style.itemmargin)
        self.iconx = self.condicon.x()
        self.fggroup.addToGroup(self.condicon)
        
        self.randicon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.randicon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.randicon.x()
        self.fggroup.addToGroup(self.randicon)
        
        self.exiticon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.exiticon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.exiticon.x()
        self.fggroup.addToGroup(self.exiticon)
        
        self.entericon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.entericon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.entericon.x()
        self.fggroup.addToGroup(self.entericon)
        
        self.persisticon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.persisticon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.persisticon.x()
        self.fggroup.addToGroup(self.persisticon)
        
        self.comment = QGraphicsTextItemCond(self, viewport)
        self.comment.setTextWidth(self.style.nodetextwidth)
        self.comment.setDefaultTextColor(FlPalette.light)
        self.comment.setPos(0, self.nodelabel.y()+self.nodelabel.boundingRect().height()+self.style.itemmargin)
        self.fggroup.addToGroup(self.comment)
        
        self.graphgroup.addToGroup(self.fggroup)
        
        self.view.nodedocs[self.realid()]["comment"].contentsChanged.connect(self.updatecomment)
        self.updatecondition()
        self.updateenterscripts()
        self.updateexitscripts()
        self.updaterandweight()
        self.updatepersistence()
        
        # Never call updatelayout() from here (or any inheritable reimplementation)!
    
    def collapse (self, collapse):
        for item in self.fggroup.childItems():
            if item is not self.nodelabel:
                if collapse:
                    item.hide()
                else:
                    item.show()
        self.updatelayout()
    
    def updatecondition (self):
        icons = {True: "key", False: "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hascond()])
        self.condicon.setPixmap(pixmap)
        if self.nodeobj.hascond():
            self.condicon.setToolTip("Condition")
        else:
            self.condicon.setToolTip("")
    
    def updateenterscripts (self):
        icons = {True: "script-enter", False: "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hasenterscripts()])
        self.entericon.setPixmap(pixmap)
        if self.nodeobj.hasenterscripts():
            self.entericon.setToolTip("Enter Scripts")
        else:
            self.entericon.setToolTip("")
    
    def updateexitscripts (self):
        icons = {True: "script-exit", False: "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hasexitscripts()])
        self.exiticon.setPixmap(pixmap)
        if self.nodeobj.hasexitscripts():
            self.exiticon.setToolTip("Exit Scripts")
        else:
            self.exiticon.setToolTip("")
    
    def updaterandweight (self):
        icons = {True: "dice", False: "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[bool(self.nodeobj.randweight)])
        self.randicon.setPixmap(pixmap)
        if self.nodeobj.randweight:
            self.randicon.setToolTip("Random Weight: %s" % self.nodeobj.randweight)
        else:
            self.randicon.setToolTip("")
    
    def updatepersistence (self):
        icons = {"Mark": "mark", "OncePerConv": "once", "OnceEver": "onceever", "": "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.persistence])
        self.persisticon.setPixmap(pixmap)
        if self.nodeobj.persistence:
            self.persisticon.setToolTip("Persistence: %s" % self.nodeobj.persistence)
        else:
            self.persisticon.setToolTip("")
    
    def updatecomment (self):
        self.fggroup.removeFromGroup(self.comment)
        contents = self.view.nodedocs[self.realid()]["comment"].toPlainText()
        if not contents:
            self.comment.hide()
        else:
            self.comment.show()
            self.comment.setPlainText(contents)
            self.fggroup.addToGroup(self.comment)
        self.updatelayout()
    
    def updatelayout (self):
        if self.iscollapsed():
            rect = self.nodelabel.mapRectToParent(self.nodelabel.boundingRect())
        else:
            rect = self.fggroup.childrenBoundingRect()
        mainrect = rect.marginsAdded(self.style.nodemargins)
        self.mainbox.setRect(mainrect)
        self.shadowbox.setRect(mainrect)
        self.selectbox.setRect(mainrect.marginsAdded(self.style.selectmargins))
        activerect = mainrect.marginsAdded(self.style.activemargins)
        self.activebox.setRect(activerect)
        self.graphgroup.setPos(-activerect.width()//2-activerect.x(), -activerect.height()//2-activerect.y())
        self.prepareGeometryChange()
        self.rect = self.graphgroup.mapRectToParent(mainrect)
        self.view.updatelayout()
    
    def mouseDoubleClickEvent (self, event):
        super().mouseDoubleClickEvent(event)
        event.accept()
        if event.button() == Qt.LeftButton:
            self.view.setactivenode(self)
    
    def mousePressEvent (self, event):
        super().mousePressEvent(event)
        if event.button() & (Qt.LeftButton | Qt.RightButton) :
            self.view.setselectednode(self)
            event.accept()
    
    def __repr__ (self):
        return "<%s %s>" % (type(self).__name__, self.id())
Exemplo n.º 40
0
    def updateLine(self):
        if self.points is not None:
            diameter = 2*self.radius
            rect = QRectF(-self.radius, -self.radius, diameter, diameter)

            if self.itemPos is not None:
                # TODO: NaNの時のEllipseItemの挙動を考える
                point = self.points[self.itemPos]

                if not isinstance(self.item, self.itemType):
                    print("call")
                    scene = self.scene()
                    if scene is not None:
                        scene.removeItem(self.item)

                    self.item = self.itemType(self)
                    self.item.setZValue(10)
                    self.item.setBrush(self.color)
                    self.item.setRect(rect)
                    self.setItemIsMovable(self.isItemMovable)

                elif self.drawItemFlag:
                    self.item.show()

                self.item.setPos(*point)
                self.item.mouseMoveEvent = self.generateItemMouseMoveEvent(self.item, point)
                self.item.mousePressEvent = self.generateItemMousePressEvent(self.item, point)

                self.textItem.setPos(*point)
                prev_range = range(self.itemPos, -1, -self.markDelta)[1:]
                next_range = range(self.itemPos, len(self.points), self.markDelta)[1:]
                num_mark = len(prev_range) + len(next_range)

                rect_half = QRectF(-self.radius/2, -self.radius/2, diameter/2, diameter/2)
                while num_mark < len(self.markItemList) and len(self.markItemList)!=0:
                    markItem = self.markItemList.pop()
                    markTextItem = self.markTextItemList.pop()
                    scene = self.scene()
                    if scene is not None:
                        scene.removeItem(markItem)
                        scene.removeItem(markTextItem)

                current_path = os.path.dirname(os.path.realpath(__file__))
                while len(self.markItemList) < num_mark:
                    # TODO: 目盛りを矢印に.
                    # markItem = QGraphicsSvgItem(os.path.join(current_path, "svg", "small_arrow.svg"), self)
                    markItem = QGraphicsRectItem(self)
                    markItem.setBrush(Qt.black)
                    markItem.setRect(rect_half)
                    markItem.setZValue(9)

                    # markItem.setFlags(QGraphicsItem.ItemIgnoresParentOpacity)
                    # markItem.setOpacity(1)

                    # print(markItem.boundingRect())
                    # xlate = markItem.boundingRect().center()
                    # t = QTransform()
                    # # t.translate(xlate.x(), xlate.y())
                    # t.rotate(90)
                    # t.scale(0.03, 0.03)
                    # # t.translate(-xlate.x(), -xlate.y())
                    # markItem.setTransform(t)

                    self.markItemList.append(markItem)

                    markTextItem = GraphicsTextItemWithBackground(self)
                    markTextItem.setBackgroundColor(Qt.black)
                    markTextItem.setDefaultTextColor(Qt.white)
                    self.markTextItemList.append(markTextItem)

                for markItem, markTextItem, index in zip(self.markItemList, self.markTextItemList, chain(prev_range, next_range)):
                    markItem.setPos(*self.points[index])

                    markTextItem.setPos(*self.points[index])
                    markTextItem.setPlainText(str(int((index-self.itemPos)/self.markDelta)))

                    if self.drawMarkItemFlag:
                        markItem.show()
                        markTextItem.show()
                    else:
                        markItem.hide()
                        markTextItem.hide()


            else:
                self.item.hide()
                self.textItem.hide()

                for item, textItem in zip(self.markItemList, self.markTextItemList):
                    item.hide()
                    textItem.hide()

            self.update()
Exemplo n.º 41
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)
Exemplo n.º 42
0
    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)