Example #1
0
class GraphicsScene(QGraphicsScene):
    def __init__(self):
        super().__init__()

        self._pos = QPointF()
        self._current_item = None

        # Полупрозрачный цвет
        self._item_color = QColor(0, 0, 255, 128)

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

        self._pos = event.scenePos()

        self._current_item = QGraphicsRectItem()
        self._current_item.setBrush(self._item_color)

        self.addItem(self._current_item)
        self._current_item.setRect(QRectF(self._pos, self._pos))

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

        if self._current_item:
            rect = QRectF(self._pos, event.scenePos()).normalized()
            self._current_item.setRect(rect)

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

        # Убираем после отпускания кнопки мыши
        self.removeItem(self._current_item)
        self._current_item = None
Example #2
0
 def create_fromDB(self,pos_list=[],obj_type=""):      
     if obj_type =="rois":
         num_rois = len(pos_list)
         for i in range(num_rois):
             points = pos_list[i]
             rect=QGraphicsRectItem()
             rect.setPen(QPen(Qt.green))
             rect.setRect(points[0],points[1],points[2],points[3])
             self.rectgroup.addToGroup(rect)
         self.scene.addItem(self.rectgroup)
     elif obj_type =="vector1":
         num_vec = len(pos_list)
         for i in range(num_vec):
             points = pos_list[i]
             vec=QGraphicsLineItem()
             vec.setPen(QPen(Qt.green))
             vec.setLine(points[0],points[1],points[2],points[3])
             self.linegroup.addToGroup(vec)
         self.scene.addItem(self.linegroup)
     elif obj_type =="vector2":
         num_vec = len(pos_list)
         for i in range(num_vec):
             points = pos_list[i]
             vec=QGraphicsLineItem()
             vec.setPen(QPen(Qt.green))
             vec.setLine(points[0],points[1],points[2],points[3])
             self.linegroup2.addToGroup(vec)
         self.scene.addItem(self.linegroup2)
Example #3
0
    def __init__(self, parent=None):
        QGraphicsScene.__init__(self, parent)

        # hold the set of keys we're pressing
        self.keys_pressed = set()

        # use a timer to get 60Hz refresh (hopefully)
        self.timer = QBasicTimer()
        self.timer.start(FRAME_TIME_MS, self)

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

        self.player = Player()
        self.player.setPos((SCREEN_WIDTH - self.player.pixmap().width()) / 2,
                           (SCREEN_HEIGHT - self.player.pixmap().height()) / 2)
        self.bullets = [
            Bullet(PLAYER_BULLET_X_OFFSETS[0], PLAYER_BULLET_Y),
            Bullet(PLAYER_BULLET_X_OFFSETS[1], PLAYER_BULLET_Y)
        ]
        for b in self.bullets:
            b.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
            self.addItem(b)
        self.addItem(self.player)

        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)
Example #4
0
class StimulusGraphicsScene(QGraphicsScene):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._invert = False
        self.homography_transform = None
        self.setBackgroundBrush(Qt.black)

        monitor_width = 3200
        monitor_height = 1800

        self.background_image = QGraphicsRectItem(0, 0, 1, 1)
        brush = QBrush()
        brush.setStyle(Qt.SolidPattern)
        brush.setColor(Qt.black)
        self.background_image.setBrush(brush)
        self.addItem(self.background_image)
        self.visible_group = QGraphicsItemGroup()
        self.visible_stimuli = []

    #  self.sceneRectChanged.connect(self.on_sceneRectChanged)

    # test_rect = QGraphicsRectItem(-50, -50, 100, 100)
    # brush2 = QBrush()
    # brush2.setStyle(Qt.CrossPattern)
    # brush2.setColor(Qt.blue)
    # test_rect.setBrush(brush2)
    # self.addItem(test_rect)
    # self.test_rect = test_rect
    #test_rect.setPos(monitor_width/2, monitor_height/2)

    def display_points(self, points):
        #log.debug("Adding {} to scene.".format(points))

        for p in self.visible_stimuli:
            self.removeItem(p)

        self.visible_stimuli = []

        for p in points:
            log.debug("Adding at {} of size {}".format(p.pos(),
                                                       p.rect().width()))
            self.addItem(p)
            self.visible_stimuli.append(p)

    #  self.update()

    @property
    def invert(self):
        return self._invert

    @invert.setter
    def invert(self, value):
        self._invert = value
        self.update()

    def update_background(self):
        self.background_image.setRect(self.sceneRect())
Example #5
0
 def set_boxes(self, boxes):
     for box in boxes:
         box_item = QGraphicsRectItem()
         box_item.setPen(QPen(Qt.red, 4))
         box_item.setBrush(QBrush(Qt.NoBrush))
         box_item.setZValue(1)
         self.scene.addItem(box_item)
         box_item.hide()
         box_item.setRect(QRectF(box[0], box[1], box[2]-box[0], box[3]-box[1]))
         self.box_item_list.append(box_item)
Example #6
0
    def init_background(self):
        window_bg = QGraphicsRectItem()
        window_bg.setRect(-OFSET[0], -OFSET[1], SCREEN_WIDTH, SCREEN_HEIGHT)
        window_bg.setBrush(QBrush(QColor(130, 128, 129)))
        self.addItem(window_bg)

        game_bg = QGraphicsRectItem()
        game_bg.setRect(0, 0, WIDTH - 1, HEIGHT - 1)
        game_bg.setBrush(QBrush(Qt.black))
        self.addItem(game_bg)
Example #7
0
class ImageCropper(QGraphicsView):
    cropped = pyqtSignal(QPointF, QPointF)

    def __init__(
        self,
        parent=None,
    ):
        super().__init__(QGraphicsScene(), parent)
        self.setAlignment(Qt.AlignCenter)
        self._click_pos = None
        self._release_pos = None

    def set_image(self, image):
        qtimage = QImage(image.data, image.shape[1], image.shape[0],
                         QImage.Format_RGB888).rgbSwapped()
        self.scene().clear()
        self._rect = QGraphicsRectItem()
        self._rect.setPen(QPen(Qt.red, 2, Qt.SolidLine))
        self._image = self.scene().addPixmap(QPixmap.fromImage(qtimage))
        self.scene().addItem(self._rect)

    def mousePressEvent(self, event):
        scene_position = self.mapToScene(event.pos())
        image_position = self._image.mapFromScene(scene_position)

        if self._image.contains(image_position):
            self._click_pos = image_position
            self._release_pos = None
        else:
            self._click_pos = None
            self._release_pos = None

    def mouseReleaseEvent(self, event):
        scene_position = self.mapToScene(event.pos())
        image_position = self._image.mapFromScene(scene_position)

        if self._image.contains(image_position):
            self._release_pos = image_position
            if self._click_pos is not None:
                self.cropped.emit(self._click_pos, self._release_pos)
            else:
                self._click_pos = None
        else:
            self._click_pos = None
            self._release_pos = None

    def mouseMoveEvent(self, event):
        scene_position = self.mapToScene(event.pos())
        image_position = self._image.mapFromScene(scene_position)

        if (self._click_pos
                is not None) and (self._image.contains(image_position)):
            self._rect.setRect(QRectF(self._click_pos, scene_position))
        else:
            self._rect.setRect(QRectF())
Example #8
0
 def show_text(self, text, size):
     self.update()
     window_bg = QGraphicsRectItem()
     window_bg.setRect(-OFSET[0], -OFSET[1], SCREEN_WIDTH, SCREEN_HEIGHT)
     window_bg.setBrush(QBrush(Qt.black))
     self.addItem(window_bg)
     self.text = QGraphicsTextItem(text)
     self.text.setDefaultTextColor(Qt.white)
     self.text.setPos(window_bg.rect().center() - QPoint(120, size))
     self.text.setFont(QFont('Press Start', int(size)))
     self.addItem(self.text)
Example #9
0
    def printAttributes(self, background, border, text):
        """
        Prints the attributes of the node
        The attributes are a key, value pair

        :param background: background color of the node
        :param border: border color for the node
        :param text: text color for the node
        """
        y = self.y() + self.headerHeight
        x = self.x()

        self.attributesHeight = 0

        for k, v in self.node.attributes.items():
            key = QGraphicsTextItem()
            key.setFont(Configuration.font)
            key.setDefaultTextColor(QColor(text))
            key.setTextWidth(100)
            key.setPlainText(k)
            keyHeight = int(key.boundingRect().height() / 20 + 0.5) * 20

            value = QGraphicsTextItem()
            value.setFont(Configuration.font)
            value.setDefaultTextColor(QColor(text))
            value.setTextWidth(100)
            value.setPlainText(v)
            valueHeight = int(value.boundingRect().height() / 20 + 0.5) * 20

            height = valueHeight if valueHeight > keyHeight else keyHeight

            keyRect = QGraphicsRectItem()
            keyRect.setRect(x, y, 100, height)
            valueRect = QGraphicsRectItem()
            valueRect.setRect(x + 100, y, 100, height)

            keyRect.setBrush(QBrush(QColor(background)))
            valueRect.setBrush(QBrush(QColor(background)))

            keyRect.setPen(QPen(QColor(border), 2))
            valueRect.setPen(QPen(QColor(border), 2))

            key.setPos(x, y - 2)
            value.setPos(x + 100, y - 2)

            self.attributes.addToGroup(keyRect)
            self.attributes.addToGroup(valueRect)
            self.attributes.addToGroup(key)
            self.attributes.addToGroup(value)

            y = y + height
            self.attributesHeight += height

        self.addToGroup(self.attributes)
Example #10
0
    def __init__(self, parent=None):
        QGraphicsScene.__init__(self, parent)

        bg = QGraphicsRectItem()
        bg.setRect(0, 0, globals.SCREEN_WIDTH, globals.SCREEN_HEIGHT)
        bg.setBrush(QBrush(Qt.black))
        self.addItem(bg)

        self.titleFont = QtGui.QFont()
        self.titleFont.setPointSize(40)
        self.buttonFont = QtGui.QFont()
        self.buttonFont.setPointSize(20)

        self.title = QtWidgets.QGraphicsTextItem('Kario Game')
        self.title.setDefaultTextColor(QtGui.QColor(255, 0, 0))
        self.title.setFont(self.titleFont)
        self.title.setPos(190, 100)

        self.b1 = QtWidgets.QGraphicsTextItem('PLAY')
        self.b1.setDefaultTextColor(QtGui.QColor(255, 0, 0))
        self.b1.setFont(self.buttonFont)
        self.b1.setPos(150, 300)

        self.b2 = QtWidgets.QGraphicsTextItem('INFO')
        self.b2.setDefaultTextColor(QtGui.QColor(255, 0, 0))
        self.b2.setFont(self.buttonFont)
        self.b2.setPos(550, 300)

        button1 = QGraphicsRectItem(147, 300, 104, 60)
        button1.setBrush(QBrush(QtGui.QColor(38, 38, 38)))

        button2 = QGraphicsRectItem(547, 300, 106, 60)
        button2.setBrush(QBrush(QtGui.QColor(38, 38, 38)))

        self.addItem(button1)
        self.addItem(button2)
        self.addItem(self.title)
        self.addItem(self.b1)
        self.addItem(self.b2)

        with open("static/highscore.json") as f:
            data = json.load(f)
        self.highscore = data["highscore"]

        self.hs = QtWidgets.QGraphicsTextItem('Current Highscore: ' +
                                              str(int(self.highscore)))
        self.hs.setDefaultTextColor(QtGui.QColor(200, 0, 0))
        self.hs.setFont(self.buttonFont)
        self.hs.setPos(200, 400)
        self.addItem(self.hs)

        self.view = Camera(self)
        self.view.ensureVisible(bg)
Example #11
0
class PickingStation(VisualizerGraphicItem):
    def __init__(self, ID=0, x=0, y=0):
        super(self.__class__, self).__init__(ID, x, y)
        self._kind_name = 'pickingStation'

        self._items = []
        self._graphics_item = QGraphicsRectItem(self)
        self._items.append(QGraphicsRectItem(self._graphics_item))
        self._items.append(QGraphicsRectItem(self._graphics_item))
        self._text = QGraphicsTextItem(self._graphics_item)

    def set_rect(self, rect):
        scale = config.get('display', 'id_font_scale')
        bold = config.get('display', 'id_font_bold')
        self._text.setFont(QFont('', rect.width() * 0.08 * scale))
        self._text.setPos(rect.x(), rect.y() + 0.6 * rect.height())
        self._text.setDefaultTextColor(
            QColor(config.get('display', 'id_font_color')))
        if self._display_mode == 0:
            if bold:
                self._text.setHtml('<b>P(' + str(self._id) + ')</b>')
            else:
                self._text.setHtml('P(' + str(self._id) + ')')
            self._graphics_item.setRect(rect.x(), rect.y(), rect.width(),
                                        rect.height())
            self._items[0].setRect(rect.x() + rect.width() / 5, rect.y(),
                                   rect.width() / 5, rect.height())
            self._items[1].setRect(rect.x() + rect.width() / 5 * 3, rect.y(),
                                   rect.width() / 5, rect.height())
        elif self._display_mode == 1:
            self._text.setPlainText('')
            self._graphics_item.setRect(rect.x(), rect.y(), rect.width(),
                                        rect.height())
            self._items[0].setRect(rect.x() + rect.width() / 5, rect.y(),
                                   rect.width() / 5, rect.height())
            self._items[1].setRect(rect.x() + rect.width() / 5 * 3, rect.y(),
                                   rect.width() / 5, rect.height())

    def determine_color(self, number, count, pattern=None):
        color = self._colors[0]
        color2 = self._colors[1]
        color.setAlpha(150)
        color2.setAlpha(150)
        brush = QBrush(color)
        brush2 = QBrush(color2)

        self._graphics_item.setBrush(brush)
        self._items[0].setBrush(brush2)
        self._items[1].setBrush(brush2)

    def get_rect(self):
        return self._graphics_item.rect()
    def _configureOutline(self, outline: QGraphicsRectItem) -> QRectF:
        """Adjusts `outline` size with default padding.

        Args:
            outline: Description

        Returns:
            o_rect: `outline` QRectF adjusted by _BOUNDING_RECT_PADDING
        """
        _p = self._BOUNDING_RECT_PADDING
        o_rect = self.rect().adjusted(-_p, -_p, _p, _p)
        outline.setRect(o_rect)
        return o_rect
Example #13
0
    def _configureOutline(self, outline: QGraphicsRectItem) -> QRectF:
        """Adjusts `outline` size with default padding.

        Args:
            outline: Description

        Returns:
            o_rect: `outline` QRectF adjusted by _BOUNDING_RECT_PADDING
        """
        _p = self._BOUNDING_RECT_PADDING
        o_rect = self.rect().adjusted(-_p, -_p, _p, _p)
        outline.setRect(o_rect)
        return o_rect
Example #14
0
    def __init__(self, cam, menu, parent=None):
        QGraphicsScene.__init__(self, parent)
        self.view = cam
        self.menu = menu

        bg = QGraphicsRectItem()
        bg.setRect(0, 0, globals.SCREEN_WIDTH, globals.SCREEN_HEIGHT)
        bg.setBrush(QBrush(Qt.black))
        self.addItem(bg)

        self.button1 = QGraphicsRectItem(40, 500, 110, 60)
        self.button1.setBrush(QBrush(QtGui.QColor(38, 38, 38)))
        self.addItem(self.button1)

        self.buttonFont = QtGui.QFont()
        self.buttonFont.setPointSize(20)
        self.textFont = QtGui.QFont()
        self.textFont.setPointSize(18)
        self.titleFont = QtGui.QFont()
        self.titleFont.setPointSize(30)

        self.b1 = QtWidgets.QGraphicsTextItem('BACK')
        self.b1.setDefaultTextColor(QtGui.QColor(255, 0, 0))
        self.b1.setPos(43, 500)
        self.b1.setFont(self.buttonFont)
        self.addItem(self.b1)

        self.title = QtWidgets.QGraphicsTextItem('How To Play')
        self.title.setDefaultTextColor(QtGui.QColor(255, 0, 0))
        self.title.setPos(200, 25)
        self.title.setFont(self.titleFont)
        self.addItem(self.title)

        text = (
            'Kario can move with left and right arrow keys and jump with space. '
            +
            'Your job is to collect every price as quickly as possible but be aware of '
            +
            'turtle enemys: If they touch you, you will die! How ever, you can'
            +
            'distroy them by jumping on them. If you have collected all of the '
            + 'prices and succesfully make it to the goal, you win the level!')
        self.text = QtWidgets.QGraphicsTextItem(text)
        self.text.setDefaultTextColor(QtGui.QColor(255, 255, 255))
        self.text.setPos(85, 130)
        self.text.setFont(self.textFont)
        self.text.adjustSize()
        self.addItem(self.text)

        self.view.update_scene(self)
Example #15
0
 def updateGraphicsRectItem(rect: QGraphicsRectItem, rectF: QRectF = None, pen: QPen = None, brush: QBrush = None):
     """
     更新QGraphicsRectItem属性
     :param rect: QGraphicsRectItem
     :param rectF: 矩形rect
     :param pen: 边框画笔
     :param brush: 填充画刷
     """
     if rectF:
         rect.setRect(rectF)
     if pen:
         rect.setPen(pen)
     if brush:
         rect.setBrush(brush)
Example #16
0
 def __init__(self, size, scene: QGraphicsScene):
     self.rectItems = []
     self.pixmap = QPixmap(QSize(820, 820))
     self.painter = QPainter(self.pixmap)
     self.scene = scene
     self.owners = None
     self.values = None
     pen = QPen()
     pen.setStyle(Qt.NoPen)
     for index in range(size**2):
         item = QGraphicsRectItem()
         item.setRect(int(index / size), int(index % size), 0.9, 0.9)
         item.setPen(pen)
         scene.addItem(item)
         self.rectItems.append(item)
Example #17
0
 def __init__(self, size, scene: QGraphicsScene):
     self.rectItems = []
     self.pixmap = QPixmap(QSize(820,820))
     self.painter = QPainter(self.pixmap)
     self.scene = scene
     self.owners = None
     self.values = None
     pen = QPen()
     pen.setStyle(Qt.NoPen)
     for index in range(size**2):
         item = QGraphicsRectItem()
         item.setRect(int(index/size), int(index%size), 0.9, 0.9)
         item.setPen(pen)
         scene.addItem(item)
         self.rectItems.append(item)
Example #18
0
class MyView(QWidget):
    def __init__(self):
        super().__init__()
        self.game_init()

    def game_init(self):
        self.scene = QGraphicsScene(parent=self)
        self.player = QGraphicsRectItem()
        self.player.setRect(0, 0, 100, 100)

        # add the item to the scene
        self.scene.addItem(self.player)
        self.view = QGraphicsView(self.scene, parent=self)

        # add a view, widget(invisible)
        self.show()
Example #19
0
class CustomDragWidget(QGraphicsWidget):
    def __init__(self,):
        super().__init__()
        self.squareItem = QGraphicsRectItem()
        self.squareItem.setBrush(QBrush(QColor(Qt.blue)))
        self.squareItem.setPen(QPen(QColor(Qt.black), 2))
        self.squareItem.setRect(0, 0, 50, 50)
        self.squareItem.setParentItem(self)
        self.setAcceptDrops(True)

    def mousePressEvent(self, event):
        mime = QMimeData()
        itemData = QByteArray()
        mime.setData('application/x-dnditemdata', itemData)
        drag = QDrag(self)
        drag.setMimeData(mime)
        drag.exec_(Qt.MoveAction)

    def dropEvent(self, event):
        event.accept()
Example #20
0
    def approve_obj(self):
        self.scene.removeItem(self.rect)
        self.scene.removeItem(self.line)

        viewBBox = self.zoomStack[-1] if len(
            self.zoomStack) else self.sceneRect()
        selectionBBox = self.scene.selectionArea().boundingRect().intersected(
            viewBBox)
        rect = QGraphicsRectItem()
        rect.setRect(selectionBBox)
        rect.setPen(QPen(Qt.green))
        self.rectgroup.addToGroup(rect)
        self.scene.addItem(self.rectgroup)

        line = QGraphicsLineItem()
        line.setLine(QLineF(self.start, self.current))
        line.setPen(QPen(Qt.green))
        self.linegroup.addToGroup(line)
        self.scene.addItem(self.linegroup)

        return (selectionBBox, self.start, self.current)
Example #21
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())
Example #22
0
    def init_ui(self):

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

        scene.setSceneRect(scene.itemsBoundingRect())

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

        self.frame_item = QGraphicsPixmapItem()

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

        scene.addItem(self.frame_item)

        self.curr_factor = 1.0

        self.setScene(scene)
Example #23
0
    def init_ui(self):

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

        scene.setSceneRect(scene.itemsBoundingRect())

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

        self.frame_item = QGraphicsPixmapItem()

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

        scene.addItem(self.frame_item)

        self.curr_factor = 1.0

        self.setScene(scene)
Example #24
0
    def setTiles(self):

        #background
        brush = QBrush(
        )  #QBrush(画刷)是一个基本的图形对象,用于填充如矩形,椭圆形,多边形等形状,QBrush有三种类型,预定义,过渡,和纹理图案
        pix = QPixmap(os.getcwd() + "/robotImages/tile.png")
        brush.setTexture(pix)
        brush.setStyle(24)
        self.setBackgroundBrush(brush)

        #wall:left、right、top、bottom都是QGraphicsRectItem类型
        #left
        left = QGraphicsRectItem()
        pix = QPixmap(os.getcwd() + "/robotImages/tileVert.png")  #获取贴图
        left.setRect(QRectF(0, 0, pix.width(),
                            self.height))  #尺寸:宽是图片宽度 ,高度是战场高度
        brush.setTexture(pix)  #设置贴图函数
        brush.setStyle(
            24
        )  #参数24指平铺格式(参数为枚举类型)详情见 https://doc.qt.io/qt-5/qt.html#BrushStyle-enum
        left.setBrush(brush)
        left.name = 'left'
        self.addItem(left)

        #right
        right = QGraphicsRectItem()
        right.setRect(self.width - pix.width(), 0, pix.width(),
                      self.height)  #尺寸:宽是图片的宽度、高是战场的高
        right.setBrush(brush)
        right.name = 'right'
        self.addItem(right)

        #top
        top = QGraphicsRectItem()
        pix = QPixmap(os.getcwd() + "/robotImages/tileHori.png")
        top.setRect(QRectF(0, 0, self.width, pix.height()))
        brush.setTexture(pix)
        brush.setStyle(24)
        top.setBrush(brush)
        top.name = 'top'
        self.addItem(top)

        #bottom
        bottom = QGraphicsRectItem()
        bottom.setRect(0, self.height - pix.height(), self.width, pix.height())
        bottom.setBrush(brush)
        bottom.name = 'bottom'
        self.addItem(bottom)
Example #25
0
class Desklet(object):

    def __init__(self):
        self.rect = QRectF()
        self.style = Style()
        self.root = QGraphicsItemGroup()

        if False:
            self.debug_rect = QGraphicsRectItem(self.root)
            self.debug_rect.setPen(QPen(QColor(255, 0, 0)))
        else:
            self.debug_rect = None

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

    def set_rect(self, rect):
        self.rect = rect
        if self.debug_rect:
            self.debug_rect.setRect(rect)

    def layout(self):
        pass
Example #26
0
class MyScene(QGraphicsScene):
    def __init__(self, data, parent=None):
        QGraphicsScene.__init__(self, parent)
        self.data = data
        self.rec = QGraphicsRectItem()
        self.plot: MyItem(data) = None
        self.bounding_rect = QGraphicsRectItem()
        self.setBackgroundBrush(QColor('#14161f'))

        self.addItem(self.bounding_rect)
        self.printed = False

    def mouseMoveEvent(self, event: 'QGraphicsSceneMouseEvent'):
        print()

        print("rec rect : ", self.rec.rect())
        print("Scene rect : ", self.sceneRect())
        print("ItemBounding rect : ", self.itemsBoundingRect())
        print("transform : ",
              self.plot.transform().m11(), ", ",
              self.plot.transform().m22())
        item = self.itemAt(event.scenePos(), self.plot.transform())

        if item and isinstance(item, MyItem):
            print()
            print('collides path : ',
                  self.rec.collidesWithPath(item.mapToScene(item.path)))
            print('collides item : ', self.rec.collidesWithItem(item))

        super().mouseMoveEvent(event)

    def print_bound(self, rect):
        self.bounding_rect.setPen(QPen(Qt.green))
        self.bounding_rect.setRect(rect.x() + 5,
                                   rect.y() + 5,
                                   rect.width() - 10,
                                   rect.height() - 10)
Example #27
0
class CplxItem(KineticsDisplayItem):
    defaultWidth = 10
    defaultHeight = 10
    name = constants.ITEM

    def __init__(self, *args, **kwargs):
        KineticsDisplayItem.__init__(self, *args, **kwargs)
        self.gobj = QGraphicsRectItem(0, 0, CplxItem.defaultWidth,
                                      CplxItem.defaultHeight, self)
        self.gobj.mobj = self.mobj
        self._conc = self.mobj.conc
        self._n = self.mobj.n
        doc = "Conc\t: " + str(self._conc) + "\nn\t: " + str(self._n)
        self.gobj.setToolTip(doc)

    def updateValue(self, gobj):
        self._gobj = gobj
        if (isinstance(self._gobj, moose.PoolBase)):
            self._conc = self.mobj.conc
            self._n = self.mobj.n
            doc = "Conc\t: " + str(self._conc) + "\nn\t: " + str(self._n)
            self.gobj.setToolTip(doc)

    def setDisplayProperties(self, x, y, textcolor, bgcolor):
        """Set the display properties of this item."""
        self.setGeometry(self.gobj.boundingRect().width() / 2,
                         self.gobj.boundingRect().height(),
                         self.gobj.boundingRect().width(),
                         self.gobj.boundingRect().height())
        self.setFlag(QGraphicsItem.ItemIsMovable, False)

    def refresh(self, scale):
        defaultWidth = CplxItem.defaultWidth * scale
        defaultHeight = CplxItem.defaultHeight * scale

        self.gobj.setRect(0, 0, defaultWidth, defaultHeight)
Example #28
0
class ZoomableScene(QGraphicsScene):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.noise_area = None
        self.ones_area = None
        self.zeros_area = None
        self.ones_arrow = None
        self.zeros_arrow = None
        self.selection_area = ROI(0,
                                  0,
                                  0,
                                  0,
                                  fillcolor=constants.SELECTION_COLOR,
                                  opacity=constants.SELECTION_OPACITY)
        self.addItem(self.selection_area)

    def draw_noise_area(self, y, h):
        x = self.sceneRect().x()
        w = self.sceneRect().width()

        if self.ones_area is not None:
            self.ones_area.hide()
        if self.zeros_area is not None:
            self.zeros_area.hide()

        if self.noise_area is None or self.noise_area.scene() != self:
            roi = ROI(x,
                      y,
                      w,
                      h,
                      fillcolor=constants.NOISE_COLOR,
                      opacity=constants.NOISE_OPACITY)
            # roi.setPen(QPen(constants.NOISE_COLOR, Qt.FlatCap))
            self.noise_area = roi
            self.addItem(self.noise_area)
        else:
            self.noise_area.show()
            self.noise_area.setY(y)
            self.noise_area.height = h

    def draw_sep_area(self, ymid):
        x = self.sceneRect().x()
        y = self.sceneRect().y()
        h = self.sceneRect().height()
        w = self.sceneRect().width()
        # padding = constants.SEPARATION_PADDING
        padding = 0
        if self.noise_area is not None:
            self.noise_area.hide()

        if self.ones_area is None:
            self.ones_area = QGraphicsRectItem(x, y, w, h / 2 - padding + ymid)
            self.ones_area.setBrush(constants.ONES_AREA_COLOR)
            self.ones_area.setOpacity(constants.SEPARATION_OPACITY)
            self.ones_area.setPen(QPen(constants.TRANSPARENT_COLOR,
                                       Qt.FlatCap))
            self.addItem(self.ones_area)

        else:
            self.ones_area.show()
            self.ones_area.setRect(x, y, w, h / 2 - padding + ymid)

        start = y + h / 2 + padding + ymid
        if self.zeros_area is None:
            self.zeros_area = QGraphicsRectItem(x, start, w, (y + h) - start)
            self.zeros_area.setBrush(constants.ZEROS_AREA_COLOR)
            self.zeros_area.setOpacity(constants.SEPARATION_OPACITY)
            self.zeros_area.setPen(
                QPen(constants.TRANSPARENT_COLOR, Qt.FlatCap))
            self.addItem(self.zeros_area)
        else:
            self.zeros_area.show()
            self.zeros_area.setRect(x, start, w, (y + h) - start)

    def clear(self):
        self.noise_area = None
        self.ones_area = None
        self.zeros_area = None
        self.zeros_arrow = None
        self.ones_arrow = None
        self.selection_area = None
        super().clear()

    def dragEnterEvent(self, event: QGraphicsSceneDragDropEvent):
        event.accept()

    def dragMoveEvent(self, event: QGraphicsSceneDragDropEvent):
        event.accept()
Example #29
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())
Example #30
0
class IDView(QGraphicsView):
    """Simple extension of QGraphicsView
    - containing an image and click-to-zoom/unzoom
    """
    def __init__(self, parent, fnames):
        QGraphicsView.__init__(self)
        self.parent = parent
        self.initUI(fnames)

    def initUI(self, fnames):
        # Make QGraphicsScene
        self.scene = QGraphicsScene()
        # TODO = handle different image sizes.
        self.images = {}
        self.imageGItem = QGraphicsItemGroup()
        self.scene.addItem(self.imageGItem)
        self.updateImage(fnames)
        self.setBackgroundBrush(QBrush(Qt.darkCyan))
        self.parent.tool = "zoom"

        self.boxFlag = False
        self.originPos = QPointF(0, 0)
        self.currentPos = self.originPos
        self.boxItem = QGraphicsRectItem()
        self.boxItem.setPen(QPen(Qt.darkCyan, 1))
        self.boxItem.setBrush(QBrush(QColor(0, 255, 0, 64)))

    def updateImage(self, fnames):
        """Update the image with that from filename"""
        for n in self.images:
            self.imageGItem.removeFromGroup(self.images[n])
            self.images[n].setVisible(False)
        if fnames is not None:
            x = 0
            n = 0
            for fn in fnames:
                self.images[n] = QGraphicsPixmapItem(QPixmap(fn))
                self.images[n].setTransformationMode(Qt.SmoothTransformation)
                self.images[n].setPos(x, 0)
                self.images[n].setVisible(True)
                self.scene.addItem(self.images[n])
                x += self.images[n].boundingRect().width() + 10
                self.imageGItem.addToGroup(self.images[n])
                n += 1

        # Set sensible sizes and put into the view, and fit view to the image.
        br = self.imageGItem.boundingRect()
        self.scene.setSceneRect(
            0,
            0,
            max(1000, br.width()),
            max(1000, br.height()),
        )
        self.setScene(self.scene)
        self.fitInView(self.imageGItem, Qt.KeepAspectRatio)

    def deleteRect(self):
        if self.boxItem.scene() is None:
            return
        self.scene.removeItem(self.boxItem)
        self.parent.rectangle = None

    def mousePressEvent(self, event):
        if self.parent.tool == "rect":
            self.originPos = self.mapToScene(event.pos())
            self.currentPos = self.originPos
            self.boxItem.setRect(QRectF(self.originPos, self.currentPos))
            if self.boxItem.scene() is None:
                self.scene.addItem(self.boxItem)
            self.boxFlag = True
        else:
            super(IDView, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if self.parent.tool == "rect" and self.boxFlag:
            self.currentPos = self.mapToScene(event.pos())
            if self.boxItem is None:
                return
            else:
                self.boxItem.setRect(QRectF(self.originPos, self.currentPos))
        else:
            super(IDView, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        if self.boxFlag:
            self.boxFlag = False
            self.parent.rectangle = self.boxItem.rect()
            self.parent.whichFile = self.parent.vTW.currentIndex()
            return
        """Left/right click to zoom in and out"""
        if (event.button() == Qt.RightButton) or (
                QGuiApplication.queryKeyboardModifiers() == Qt.ShiftModifier):
            self.scale(0.8, 0.8)
        else:
            self.scale(1.25, 1.25)
        self.centerOn(event.pos())

    def resetView(self):
        """Reset the view to its reasonable initial state."""
        self.fitInView(self.imageGItem, Qt.KeepAspectRatio)
Example #31
0
 def _draw_background(self):
     bg = QGraphicsRectItem()
     bg.setRect(-1, -1, SCREEN_WIDTH + 1, SCREEN_HEIGHT + 1)
     bg.setBrush(QBrush(Qt.black))
     self.addItem(bg)
Example #32
0
class CalendarDesklet(Desklet):

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

        self.model = CalendarModel()

        self.cursor_pos = None

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

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

        self.header_line = QGraphicsLineItem(self.root)

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

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

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

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

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

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

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

        self.header_line.setPen(style.foreground_color)

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

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

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

        self.layout()

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

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

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

        y += fm.height()

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

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

        y += 8

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

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

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

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

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

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

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

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

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

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

        self.layout()
Example #33
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]])
    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()
Example #35
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)
Example #36
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())
Example #37
0
    def add_chart(self, text, data, eq=False):
        items = []

        text_item = QGraphicsTextItem(text)
        text_item.setFont(ComparisionChart.arial_font)
        text_item.setPos(0,0)
        items.append(text_item)
        next_y = text_item.boundingRect().height()+5
        if not data:
            text_item = QGraphicsTextItem("prazno")
            text_item.setFont(ComparisionChart.font)
            text_item.setPos(0,next_y)
            items.append(text_item)

            group = self.scene.createItemGroup(items)
            return group

        item_max = 0
        before_max = len("before")
        after_max = len("after")

        def fmt_num(number):
            return "{:.2f}".format(number)
        def fmt_num_align(number, width):
            fmt = "{:^%d.2f}" % width
            return fmt.format(number)

        for item, before, after in data:
            item_max = max(item_max, len(item))
            before_max = max(before_max, len(fmt_num(before)))
            after_max = max(after_max, len(fmt_num(after)))

        before_larger = False
        if before > after:
            before_larger = True


        item_max_s= item_max*9
        before_max_s= before_max*9
        after_max_s= after_max*9

        full_size = before_max_s+5+after_max_s
        start_chart = item_max_s+5

        for item, before, after in data:
            if before_larger:
                large = before
                small = after
            else:
                large = after
                small = before

            if not eq:
                rect_item = QGraphicsRectItem()
                old_height = 0.8*text_item.boundingRect().height()
                rect_item.setRect(start_chart,next_y, full_size,
                        old_height)
                if before_larger:
                    rect_item.setBrush(ComparisionChart.color1_brush)
                else:
                    rect_item.setBrush(ComparisionChart.color2_brush)
                rect_item.setPen(ComparisionChart.no_pen)
                items.append(rect_item)

                rect_item = QGraphicsRectItem()
                new_height = 0.4*text_item.boundingRect().height()
                rect_item.setRect(start_chart,next_y+(old_height-new_height)/2,
                        full_size*(small/large),
                        new_height)
                if before_larger:
                    rect_item.setBrush(ComparisionChart.color2_brush)
                else:
                    rect_item.setBrush(ComparisionChart.color1_brush)
                rect_item.setPen(ComparisionChart.no_pen)
                items.append(rect_item)

            text_item = QGraphicsTextItem(item)
            text_item.setFont(ComparisionChart.font)
            text_item.setPos(0, next_y)
            items.append(text_item)
            
            text_item = QGraphicsTextItem(fmt_num_align(before, before_max))
            text_item.setFont(ComparisionChart.font)
            text_item.setPos(item_max_s, next_y)
            items.append(text_item)

            text_item = QGraphicsTextItem(fmt_num_align(after, after_max))
            text_item.setFont(ComparisionChart.font)
            text_item.setPos(item_max_s+5+before_max_s, next_y)
            items.append(text_item)

            next_y+=text_item.boundingRect().height()


        #barsets = [QBarSet("previous"), QBarSet("current")]
        #cats = []
        #for i, (item, before, now) in enumerate(data):
            #print (item, before, now)
            #barsets[1].append(before)
            #barsets[0].append(now)
            #cats.append(item)
        #axis_y = QBarCategoryAxis()
        #axis_y.append(cats)
        #barseries = QHorizontalBarSeries()
        #barseries.append(barsets)
        #chart = QChart()
        #chart.addSeries(barseries)
        #chart.setTitle(text)
        #chart.setAnimationOptions(QChart.SeriesAnimations)
        #chart.setAxisY(axis_y, barseries)
        #chart.setPos(0, next_y)
        #chart.setPreferredWidth(width)
        #chart.setPreferredHeight(500)
        ##chart.setSize(200,200)
        ##print ("SIZE:", chart.size().toSize().width(),
                ##chart.size().toSize().height())
        ##print ("CHART:", chart.boundingRect().width(),
                ##chart.boundingRect().height())
        #items.append(chart)

        group = self.scene.createItemGroup(items)
        return group
Example #38
0
class MyCanvas(QGraphicsView):
    """
    画布窗体类,继承自QGraphicsView,采用QGraphicsView、QGraphicsScene、QGraphicsItem的绘图框架
    """
    def __init__(self, *args):
        super().__init__(*args)
        self.main_window = None
        self.list_widget = None
        self.item_dict = {}
        self.selected_id = ''

        self.status = ''
        self.temp_algorithm = ''
        self.temp_id = ''
        self.temp_item = None
        self.temp_color = QColor(0, 0, 0)
        self.origin_pos = None
        self.trans_center = None
        self.origin_p_list = None
        self.border = None

    def start_draw_line(self, algorithm, item_id):
        self.status = 'line'
        self.temp_algorithm = algorithm
        self.temp_id = item_id
        self.temp_item = None

    def start_draw_polygon(self, algorithm, item_id):
        self.status = 'polygon'
        self.temp_algorithm = algorithm
        self.temp_id = item_id
        self.temp_item = None

    def start_draw_ellipse(self, algorithm, item_id):
        self.status = 'ellipse'
        self.temp_algorithm = algorithm
        self.temp_id = item_id
        self.temp_item = None

    def start_draw_curve(self, algorithm, item_id):
        self.status = 'curve'
        self.temp_algorithm = algorithm
        self.temp_id = item_id
        self.temp_item = None

    def start_translate(self):
        self.status = 'translate'
        self.temp_item = None

    def start_rotate(self):
        self.status = 'rotate'
        self.temp_item = None
        self.trans_center = None
        self.origin_p_list = None

    def start_scale(self):
        self.status = 'scale'
        self.temp_item = None
        self.trans_center = None
        self.origin_p_list = None

    def start_clip(self, algorithm):
        self.status = 'clip'
        self.temp_algorithm = algorithm
        self.temp_item = None
        self.origin_pos = None
        self.origin_p_list = None

    def start_delete(self):
        if self.selected_id != '':
            self.main_window.is_modified = True
            self.temp_item = self.item_dict[self.selected_id]
            number = self.list_widget.findItems(self.selected_id,
                                                Qt.MatchContains)
            row = self.list_widget.row(number[0])
            # self.list_widget.removeItemWidget(self.number[0])
            temp_id = self.selected_id
            self.clear_selection()
            self.list_widget.clearSelection()
            self.scene().removeItem(self.temp_item)
            self.temp_item = None
            del self.item_dict[temp_id]
            self.list_widget.takeItem(row)
            self.updateScene([self.sceneRect()])

    def start_freedom(self, item_id):
        self.status = 'freedom'
        self.temp_id = item_id
        self.temp_item = None

    def finish_draw(self):
        self.temp_id = self.main_window.get_id(True)

    def clear_selection(self):
        if self.selected_id != '':
            self.item_dict[self.selected_id].selected = False
            self.selected_id = ''

    def selection_changed(self, selected):
        if self.status == 'polygon' or self.status == 'curve':
            self.finish_draw()
        self.trans_center = None
        if self.selected_id != '':
            self.item_dict[self.selected_id].selected = False
            self.item_dict[self.selected_id].update()
        if selected != '':
            self.main_window.statusBar().showMessage('图元选择: %s' % selected)
            self.selected_id = selected
            self.item_dict[selected].selected = True
            self.item_dict[selected].update()
            self.status = ''
            self.updateScene([self.sceneRect()])

    def mousePressEvent(self, event: QMouseEvent) -> None:
        # print('press')
        pos = self.mapToScene(event.localPos().toPoint())
        x = int(pos.x())
        y = int(pos.y())
        if self.status == 'line':
            self.temp_item = MyItem(self.temp_id, self.status,
                                    [[x, y], [x, y]], self.temp_algorithm,
                                    self.temp_color)
            self.scene().addItem(self.temp_item)
            self.main_window.is_modified = True
        elif self.status == 'ellipse':
            self.temp_item = MyItem(self.temp_id, self.status,
                                    [[x, y], [x, y]], self.temp_algorithm,
                                    self.temp_color)
            self.scene().addItem(self.temp_item)
            self.main_window.is_modified = True
        elif self.status == 'polygon' or self.status == 'curve':
            if self.temp_item is None:
                self.temp_item = MyItem(self.temp_id, self.status, [[x, y]],
                                        self.temp_algorithm, self.temp_color)
                self.scene().addItem(self.temp_item)
            else:
                self.temp_item.p_list.append([x, y])
            self.main_window.is_modified = True
        elif self.status == 'translate':
            if self.selected_id != '':
                self.main_window.is_modified = True
                self.temp_item = self.item_dict[self.selected_id]
                self.origin_pos = pos
                self.origin_p_list = self.temp_item.p_list
        elif self.status == 'rotate':
            if self.selected_id != '':
                self.main_window.is_modified = True
                self.temp_item = self.item_dict[self.selected_id]
                self.origin_p_list = self.temp_item.p_list
                if self.trans_center is None:
                    self.trans_center = pos
                else:
                    self.origin_pos = pos
        elif self.status == 'scale':
            if self.selected_id != '':
                self.main_window.is_modified = True
                self.temp_item = self.item_dict[self.selected_id]
                self.origin_p_list = self.temp_item.p_list
                if self.trans_center is None:
                    self.trans_center = pos
                else:
                    self.origin_pos = pos
        elif self.status == 'clip':
            if self.selected_id != '':
                self.temp_item = self.item_dict[self.selected_id]
                if self.temp_item.item_type == 'line':
                    self.main_window.is_modified = True
                    self.origin_pos = pos
                    self.origin_p_list = self.temp_item.p_list
        elif self.status == 'freedom':
            self.main_window.is_modified = True
            self.temp_item = MyItem(self.temp_id, self.status, [[x, y]], '',
                                    self.temp_color)
            self.scene().addItem(self.temp_item)
        self.updateScene([self.sceneRect()])
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event: QMouseEvent) -> None:
        pos = self.mapToScene(event.localPos().toPoint())
        x = int(pos.x())
        y = int(pos.y())
        if self.status == 'line':
            self.temp_item.p_list[1] = [x, y]
        elif self.status == 'ellipse':
            self.temp_item.p_list[1] = [x, y]
        elif self.status == 'polygon':
            self.temp_item.p_list[-1] = [x, y]
        elif self.status == 'curve':
            self.temp_item.p_list[-1] = [x, y]
        elif self.status == 'translate':
            if self.selected_id != '':
                dx = x - int(self.origin_pos.x())
                dy = y - int(self.origin_pos.y())
                self.temp_item.p_list = alg.translate(self.origin_p_list, dx,
                                                      dy)
        elif self.status == 'rotate':
            if self.selected_id != '' and self.trans_center is not None and self.origin_pos is not None:
                x_origin, y_origin = int(self.origin_pos.x() -
                                         self.trans_center.x()), int(
                                             self.origin_pos.y() -
                                             self.trans_center.y())
                len_origin = math.sqrt(x_origin**2 + y_origin**2)
                x_now, y_now = x - int(self.trans_center.x()), y - int(
                    self.trans_center.y())
                len_now = math.sqrt(x_now**2 + y_now**2)
                if len_origin != 0 and len_now != 0:
                    sin_origin = y_origin / len_origin
                    cos_origin = x_origin / len_origin
                    sin_now = y_now / len_now
                    cos_now = x_now / len_now
                    delta_sin = sin_now * cos_origin - cos_now * sin_origin
                    delta_cos = cos_now * cos_origin + sin_now * sin_origin
                    if delta_cos >= 0:
                        r = math.asin(delta_sin)
                    else:
                        r = math.pi - math.asin(delta_sin)
                    self.temp_item.p_list = alg.rotate(
                        self.origin_p_list, int(self.trans_center.x()),
                        int(self.trans_center.y()), r, False)
        elif self.status == 'scale':
            if self.selected_id != '' and self.trans_center is not None and self.origin_pos is not None:
                x_last, y_last = int(self.origin_pos.x() -
                                     self.trans_center.x()), int(
                                         self.origin_pos.y() -
                                         self.trans_center.y())
                len_last = math.sqrt(x_last**2 + y_last**2)
                if len_last != 0:
                    x_now, y_now = x - int(self.trans_center.x()), y - int(
                        self.trans_center.y())
                    len_now = math.sqrt(x_now**2 + y_now**2)
                    self.temp_item.p_list = alg.scale(
                        self.origin_p_list, int(self.trans_center.x()),
                        int(self.trans_center.y()), len_now / len_last)
        elif self.status == 'clip':
            if self.selected_id != '' and self.origin_pos is not None and self.temp_item.item_type == 'line':
                x_min = min(int(self.origin_pos.x()), x)
                x_max = max(int(self.origin_pos.x()), x)
                y_min = min(int(self.origin_pos.y()), y)
                y_max = max(int(self.origin_pos.y()), y)
                '''
                self.temp_item.p_list = alg.clip(self.origin_p_list, x_min, y_min, x_max, y_max, self.temp_algorithm)
                print(self.temp_item.p_list)
                '''
                if self.border is None:
                    self.border = QGraphicsRectItem(x_min - 1, y_min - 1,
                                                    x_max - x_min + 2,
                                                    y_max - y_min + 2)
                    self.scene().addItem(self.border)
                    self.border.setPen(QColor(0, 255, 255))
                else:
                    self.border.setRect(x_min - 1, y_min - 1,
                                        x_max - x_min + 2, y_max - y_min + 2)
        elif self.status == 'freedom':
            self.temp_item.p_list.append([x, y])
        self.updateScene([self.sceneRect()])
        super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event: QMouseEvent) -> None:
        if self.status == 'line':
            self.item_dict[self.temp_id] = self.temp_item
            self.list_widget.addItem(self.temp_id)
            self.finish_draw()
        elif self.status == 'ellipse':
            self.item_dict[self.temp_id] = self.temp_item
            self.list_widget.addItem(self.temp_id)
            self.finish_draw()
        elif self.status == 'polygon':
            self.item_dict[self.temp_id] = self.temp_item
            if not self.list_widget.findItems(self.temp_id, Qt.MatchContains):
                self.list_widget.addItem(self.temp_id)
        elif self.status == 'curve':
            self.item_dict[self.temp_id] = self.temp_item
            if not self.list_widget.findItems(self.temp_id, Qt.MatchContains):
                self.list_widget.addItem(self.temp_id)
        elif self.status == 'clip':
            pos = self.mapToScene(event.localPos().toPoint())
            x = int(pos.x())
            y = int(pos.y())
            if self.selected_id != '' and self.origin_pos is not None and self.temp_item.item_type == 'line':
                x_min = min(int(self.origin_pos.x()), x)
                x_max = max(int(self.origin_pos.x()), x)
                y_min = min(int(self.origin_pos.y()), y)
                y_max = max(int(self.origin_pos.y()), y)
                temp_p_list = alg.clip(self.origin_p_list, x_min, y_min, x_max,
                                       y_max, self.temp_algorithm)
                if len(temp_p_list) == 0:
                    # self.selected_id = ''
                    # print(self.number)
                    number = self.list_widget.findItems(
                        self.selected_id, Qt.MatchContains)
                    row = self.list_widget.row(number[0])
                    # self.list_widget.removeItemWidget(self.number[0])
                    temp_id = self.selected_id
                    self.clear_selection()
                    self.list_widget.clearSelection()
                    self.scene().removeItem(self.temp_item)
                    self.temp_item = None
                    del self.item_dict[temp_id]
                    self.list_widget.takeItem(row)
                else:
                    self.temp_item.p_list = temp_p_list
            if self.border is not None:
                self.scene().removeItem(self.border)
                self.border = None
            self.updateScene([self.sceneRect()])
        elif self.status == 'freedom':
            self.item_dict[self.temp_id] = self.temp_item
            self.list_widget.addItem(self.temp_id)
            self.finish_draw()
        super().mouseReleaseEvent(event)
class MainController(QObject):

    appStart = pyqtSignal()
    newCommand = pyqtSignal(tuple)

    def __init__(self):
        super(MainController, self).__init__()
        self.ser = Serial(WIFLY_SERIAL_PORT, WIFLY_BAUD_RATE)
        self.wiflyReceiver = WiflyReceiver(self.ser)
        self.wiflySender = WiflySender(self.ser)
        self.rover = Rover()
        self.mainWidget = MainWidget()
        self.wiflyReceiverThread = QThread()
        self.wiflyReceiver.moveToThread(self.wiflyReceiverThread)
        self.wiflySenderThread = QThread()
        self.wiflySender.moveToThread(self.wiflySenderThread)
        self.simState = SIMULATION_STATE_PHASE_1
        self.simTimer = QTimer()
        self.simTimer.setSingleShot(True)

        self.wiflyReceiver.msgReceived.connect(self.mainWidget.appendMsg)
        self.wiflyReceiver.msgReceived.connect(self.rover.processData)
        self.newCommand.connect(self.wiflySender.sendMsg)
        self.appStart.connect(self.wiflyReceiver.processMsg)
        self.mainWidget.ui.gearSlider.valueChanged.connect(self.manualGearChange)
        self.mainWidget.ui.upButton.clicked.connect(self.manualMoveForward)
        self.mainWidget.ui.downButton.clicked.connect(self.manualMoveBackward)
        self.mainWidget.ui.leftButton.clicked.connect(self.manualMoveLeft)
        self.mainWidget.ui.rightButton.clicked.connect(self.manualMoveRight)
        self.mainWidget.ui.brakeButton.clicked.connect(self.manualStop)
        self.mainWidget.ui.simulationButton.clicked.connect(self.simulationStart)
        self.rover.newRoverPosition.connect(self.drawRover)
        self.rover.newWallDetected.connect(self.drawNewWall)
        self.simTimer.timeout.connect(self.simulationUpdate)

        self.mapScene = QGraphicsScene(0, 0, WORLD_X / CANVAS_RATIO, WORLD_Y / CANVAS_RATIO)
        self.mainWidget.ui.mappingGraphicsView.setScene(self.mapScene)

        self.roverRect = QGraphicsRectItem()
        self.mapScene.addItem(self.roverRect)

        """
        rect1 = QGraphicsRectItem()
        rect2 = QGraphicsRectItem()
        self.mapScene.addItem(rect1)
        self.mapScene.addItem(rect2)
        rect1.setRect(100, 100, 20, 40)
        rect2.setRect(100, 100, 20, 40)
        #rect.moveBy(10, 50)
        rect2.setTransformOriginPoint(100, 100)
        rect2.setRotation(-10)
        print rect1.rect().center()
        #print rect2.transformOriginPoint().x(), rect2.transformOriginPoint().y()
        """

    @pyqtSlot(tuple, tuple)
    def drawNewWall(self, wallFront, wallRear):
        pFront = QGraphicsRectItem(wallFront[0] / CANVAS_RATIO,
                                   wallFront[1] / CANVAS_RATIO,
                                   DOT_SIZE, DOT_SIZE)
        pRear = QGraphicsRectItem(wallRear[0] / CANVAS_RATIO,
                                  wallRear[1] / CANVAS_RATIO,
                                  DOT_SIZE, DOT_SIZE)
        self.mapScene.addItem(pFront)
        self.mapScene.addItem(pRear)

    @pyqtSlot(tuple, float)
    def drawRover(self, center, orientation):
        self.roverRect.setRect((center[0] - ROVER_WIDTH / 2) / CANVAS_RATIO,
                               (center[1] - ROVER_LENGTH / 2) / CANVAS_RATIO,
                               ROVER_WIDTH / CANVAS_RATIO, ROVER_LENGTH / CANVAS_RATIO)
        self.roverRect.setTransformOriginPoint(center[0] / CANVAS_RATIO, center[1] / CANVAS_RATIO)
        self.roverRect.setRotation(math.degrees(-orientation))

    @pyqtSlot()
    def manualGearChange(self):
        gear = self.mainWidget.ui.gearSlider.value()
        self.mainWidget.ui.gearLcdNumber.display(gear)
        self.rover.roverGear = gear
        self.rover.updateMotorCommand()
        self.newCommand.emit(tuple(self.rover.commandMsg))

    @pyqtSlot()
    def manualMoveForward(self):
        self.rover.roverDirection = ROVER_DIRECTION_FORWARD
        self.rover.updateMotorCommand()
        self.newCommand.emit(tuple(self.rover.commandMsg))

    @pyqtSlot()
    def manualMoveBackward(self):
        self.rover.roverDirection = ROVER_DIRECTION_BACKWARD
        self.rover.updateMotorCommand()
        self.newCommand.emit(tuple(self.rover.commandMsg))

    @pyqtSlot()
    def manualMoveLeft(self):
        self.rover.roverDirection = ROVER_DIRECTION_LEFT
        self.rover.updateMotorCommand()
        self.newCommand.emit(tuple(self.rover.commandMsg))

    @pyqtSlot()
    def manualMoveRight(self):
        self.rover.roverDirection = ROVER_DIRECTION_RIGHT
        self.rover.updateMotorCommand()
        self.newCommand.emit(tuple(self.rover.commandMsg))

    @pyqtSlot()
    def manualStop(self):
        self.mainWidget.ui.gearSlider.setValue(0)

    @pyqtSlot()
    def simulationStart(self):
        self.simState == SIMULATION_STATE_PHASE_1
        self.simTimer.start(5000)

    @pyqtSlot()
    def simulationUpdate(self):
        if self.simState == SIMULATION_STATE_PHASE_1:
            self.simState = SIMULATION_STATE_PHASE_2
            self.rover.roverGear = 2
            self.rover.roverDirection = ROVER_DIRECTION_FORWARD
            self.rover.updateMotorCommand()
            self.newCommand.emit(tuple(self.rover.commandMsg))
            self.simTimer.start(16000)
        elif self.simState == SIMULATION_STATE_PHASE_2:
            self.simState = SIMULATION_STATE_PHASE_3
            self.rover.roverDirection = ROVER_DIRECTION_BACKWARD
            self.rover.updateMotorCommand()
            self.newCommand.emit(tuple(self.rover.commandMsg))
            self.simTimer.start(6100)
        elif self.simState == SIMULATION_STATE_PHASE_3:
            self.simState = SIMULATION_STATE_PHASE_4
            self.rover.roverDirection = ROVER_DIRECTION_LEFT
            self.rover.updateMotorCommand()
            self.newCommand.emit(tuple(self.rover.commandMsg))
            self.simTimer.start(3500)
        elif self.simState == SIMULATION_STATE_PHASE_4:
            self.simState = SIMULATION_STATE_PHASE_5
            self.rover.roverDirection = ROVER_DIRECTION_BACKWARD
            self.rover.updateMotorCommand()
            self.newCommand.emit(tuple(self.rover.commandMsg))
            self.simTimer.start(8300)
        elif self.simState == SIMULATION_STATE_PHASE_5:
            self.rover.roverGear = 0
            self.rover.roverDirection = ROVER_DIRECTION_STOP
            self.rover.updateMotorCommand()
            self.newCommand.emit(tuple(self.rover.commandMsg))

    def start(self):
        self.mainWidget.show()
        self.wiflyReceiverThread.start()
        self.wiflySenderThread.start()
        self.appStart.emit()
Example #40
0
class PreXoverLabel(QGraphicsSimpleTextItem):
    """
    Attributes:
        is_fwd (bool): Description
    """
    _XO_FONT = styles.XOVER_LABEL_FONT
    _XO_BOLD = styles.XOVER_LABEL_FONT_BOLD
    _FM = QFontMetrics(_XO_FONT)

    def __init__(self, is_fwd: bool, pre_xover_item: 'PreXoverItem'):
        """
        Args:
            is_fwd: Description
            pre_xover_item: Description
        """
        super(QGraphicsSimpleTextItem, self).__init__(pre_xover_item)
        self.is_fwd = is_fwd
        self._tbr = None
        self._outline = QGraphicsRectItem(self)
        self.setFont(self._XO_FONT)
        self.setBrush(getBrushObj('#666666'))
    # end def

    def resetItem(self, is_fwd: bool, color: str):
        """
        Args:
            is_fwd: Description
            color: Description
        """
        self.resetTransform()
        self.is_fwd = is_fwd
        self.color = color
    # end def

    def setTextAndStyle(self, text: str, outline: bool = False):
        """
        Args:
            text: Description
            outline: Default is ``False``
        """
        str_txt = str(text)
        self._tbr = tBR = self._FM.tightBoundingRect(str_txt)
        half_label_H = tBR.height() / 2.0
        half_label_W = tBR.width() / 2.0

        labelX = BASE_WIDTH/2.0 - half_label_W
        if str_txt == '1':  # adjust for the number one
            labelX -= tBR.width()

        labelY = half_label_H if self.is_fwd else (BASE_WIDTH - tBR.height())/2

        self.setPos(labelX, labelY)
        self.setText(str_txt)

        if outline:
            self.setFont(self._XO_BOLD)
            self.setBrush(getBrushObj('#ff0000'))
        else:
            self.setFont(self._XO_FONT)
            self.setBrush(getBrushObj('#666666'))

        if outline:
            r = QRectF(self._tbr).adjusted(-half_label_W, 0,
                                           half_label_W, half_label_H)
            self._outline.setRect(r)
            self._outline.setPen(getPenObj('#ff0000', 0.25))
            self._outline.setY(2*half_label_H)
            self._outline.show()
        else:
            self._outline.hide()
Example #41
0
class NodeTemplateItem():
    ''' 
    This represents one node template on the diagram.  A node template can be on many diagrams
    This class creates the rectangle graphics item and the text graphics item and adds them to the scene.
    '''
    def __init__(self, scene, x, y, nodeTemplateDict=None, NZID=None):
        self.scene = scene
        self.logMsg = None
        self.x = x
        self.y = y
        self.nodeTemplateDict = nodeTemplateDict
        #        self.name = self.nodeTemplateDict.get("name", "")   THIS HAS BEEN REPLACED BY THE name FUNCTION - SEE BELOW
        self.diagramType = "Node Template"
        self.displayText = None
        self.model = self.scene.parent.model
        self.gap = 100
        self.relList = []
        # assign a unique key if it doesn't already have one
        if NZID == None:
            self.NZID = str(uuid.uuid4())
        else:
            self.NZID = NZID

        # init graphics objects to none
        self.TNode = None
        self.TNtext = None

        # draw the node template on the diagram
        self.drawIt()

    def name(self, ):
        return self.nodeTemplateDict.get("name", "")

    def getX(self, ):
        return self.TNode.boundingRect().x()

    def getY(self, ):
        return self.TNode.boundingRect().y()

    def getHeight(self, ):
        return self.TNode.boundingRect().height()

    def getWidth(self, ):
        return self.TNode.boundingRect().width()

    def getRelList(self, ):
        '''return a list of all relationitems that are inbound or outbound from this node template.
          do not include self referencing relationships
        '''
        return [
            diagramItem
            for key, diagramItem in self.scene.parent.itemDict.items()
            if diagramItem.diagramType == "Relationship Template" and (
                diagramItem.startNZID == self.NZID
                or diagramItem.endNZID == self.NZID)
        ]

    def getPoint(self, offset=None):
        '''
        This function is used by the template diagram to calculate the location to drop a node template on the diagram
        '''
        if offset is None:
            return QPointF(self.x, self.y)
        else:
            return QPointF(self.x + offset, self.y + offset)

    def getFormat(self, ):
        '''
        determine if the Node Template  has a template format or should use the project default format
        '''
        # get the node Template custom format
        customFormat = self.nodeTemplateDict.get("TNformat", None)

        if not customFormat is None:
            # get the template custom format
            self.nodeFormat = TNodeFormat(formatDict=customFormat)
        else:
            # get the project default format
            self.nodeFormat = TNodeFormat(
                formatDict=self.model.modelData["TNformat"])

    def clearItem(self, ):

        if (not self.TNode is None and not self.TNode.scene() is None):
            self.TNode.scene().removeItem(self.TNode)
        if (not self.TNtext is None and not self.TNtext.scene() is None):
            self.TNtext.scene().removeItem(self.TNtext)

    def drawIt(self, ):

        # get current format as it may have changed
        self.getFormat()

        # create the qgraphicsItems if they don't exist
        if self.TNode is None:
            # create the rectangle
            self.TNode = QGraphicsRectItem(QRectF(
                self.x, self.y, self.nodeFormat.formatDict["nodeWidth"],
                self.nodeFormat.formatDict["nodeHeight"]),
                                           parent=None)
            self.TNode.setZValue(NODELAYER)
            self.TNode.setFlag(QGraphicsItem.ItemIsMovable, True)
            self.TNode.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
            self.TNode.setFlag(QGraphicsItem.ItemIsSelectable, True)
            self.TNode.setSelected(True)
            self.TNode.setData(1, self.NZID)  # get with self.INode.data(1)
            self.TNode.setData(ITEMTYPE, NODETEMPLATE)
            # create the text box
            self.TNtext = QGraphicsTextItem("", parent=None)
            self.TNtext.setPos(self.x, self.y)
            self.TNtext.setFlag(QGraphicsItem.ItemIsMovable, True)
            self.TNtext.setFlag(QGraphicsItem.ItemIsSelectable, False)
            self.TNtext.setData(NODEID, self.NZID)
            self.TNtext.setData(ITEMTYPE, NODETEMPLATETEXT)
            self.TNtext.setZValue(NODELAYER)
            # save the location
            self.x = self.TNode.sceneBoundingRect().x()
            self.y = self.TNode.sceneBoundingRect().y()
            # generate the html and resize the rectangle
            self.formatItem()
            # add the graphics items to the scene
            self.scene.addItem(self.TNode)
            self.scene.addItem(self.TNtext)
        else:
            # generate the html and resize the rectangle
            self.formatItem()

    def formatItem(self, ):

        # configure the formatting aspects of the qgraphics item
        pen = self.nodeFormat.pen()
        brush = self.nodeFormat.brush()
        self.TNode.setBrush(brush)
        self.TNode.setPen(pen)

        # generate the HTML
        genHTML = self.generateHTML()
        self.TNtext.prepareGeometryChange()
        #        print("before html bounding rectangle width:{}".format(self.TNtext.boundingRect().width()))
        #        print("before html text width:{}".format(self.TNtext.textWidth()))
        self.TNtext.setTextWidth(
            -1
        )  # reset the width to unkonwn so it will calculate a new width based on the new html
        self.TNtext.setHtml(genHTML)
        #        print("after html bounding rectangle width:{}".format(self.TNtext.boundingRect().width()))
        #        print("after html text width:{}".format(self.TNtext.textWidth()))

        # make sure minimum width of 120
        if self.TNtext.boundingRect().width() < 120:
            self.TNtext.setTextWidth(120)
        else:
            self.TNtext.setTextWidth(
                self.TNtext.boundingRect().width()
            )  # you have to do a setTextWidth to get the html to render correctly.

        # set the rectangle item to the same size as the formatted html
        self.TNode.prepareGeometryChange()
        currentRect = self.TNode.rect()
        # insure minimum height of 120
        if self.TNtext.boundingRect().height() < 120:
            currentRect.setHeight(120)
        else:
            currentRect.setHeight(self.TNtext.boundingRect().height())
        currentRect.setWidth(self.TNtext.boundingRect().width())
        self.TNode.setRect(currentRect)

    def generateHTML(self, ):
        '''
        Generate the HTML that formats the node template data inside the rectangle
        '''
        # generate the html
        prefix = "<!DOCTYPE html><html><body>"
        #        head = "<head><style>table, th, td {border: 1px solid black; border-collapse: collapse;}</style></head>"
        suffix = "</body></html>"
        #        blankRow = "<tr><td><left>{}</left></td><td><left>{}</left></td><td><left>{}</left></td><td><left>{}</left></td></tr>".format("", "", "", "")

        name = "<center><b>{}</b></center>".format(
            self.nodeTemplateDict.get("name", ""))
        lbls = self.genLblHTML()
        props = self.genPropHTML()
        genHTML = "{}{}<hr>{}<br><hr>{}{}".format(prefix, name, lbls, props,
                                                  suffix)
        #        print("{} html: {}".format(self.name(), genHTML))

        return genHTML

    def genLblHTML(self):
        #        html = '<table width="90%">'
        html = '<table style="width:90%;border:1px solid black;">'
        if len(self.nodeTemplateDict.get("labels", [])) > 0:
            for lbl in self.nodeTemplateDict.get("labels", []):
                if lbl[NODEKEY] == Qt.Checked:
                    nk = "NK"
                else:
                    nk = "&nbsp;&nbsp;"
                if lbl[REQUIRED] == Qt.Checked:
                    rq = "R"
                else:
                    rq = ""

                html = html + '<tr align="left"><td width="15%"><left>{}</left></td><td width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                    nk, lbl[LABEL], "", rq)
            html = html + "</table>"
        else:
            html = '<tr align="left"><td width="15%"><left>{}</left></td><td  width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                "  ", "NO{}LABELS".format("&nbsp;"), "", "")
            html = html + "</table>"

        return html

    def genPropHTML(self):
        #        PROPERTY, DATATYPE, PROPREQ, DEFAULT, EXISTS, UNIQUE, PROPNODEKEY
        html = '<table style="width:90%;border:1px solid black;">'
        if len(self.nodeTemplateDict.get("properties", [])) > 0:
            for prop in self.nodeTemplateDict.get("properties", []):
                if prop[PROPNODEKEY] == Qt.Checked:
                    nk = "NK"
                else:
                    nk = "&nbsp;&nbsp;"
                if prop[PROPREQ] == Qt.Checked:
                    rq = "R"
                else:
                    rq = ""
                if prop[EXISTS] == Qt.Checked:
                    ex = "E"
                else:
                    ex = ""
                if prop[UNIQUE] == Qt.Checked:
                    uq = "U"
                else:
                    uq = ""
                html = html + '<tr align="left"><td width="15%"><left>{}</left></td><td width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                    nk, prop[PROPERTY], rq, ex, uq)
            html = html + "</table>"
        else:
            html = html + '<tr align="left"><td width="15%"><left>{}</left></td><td width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                "&nbsp;&nbsp;", "NO{}PROPERTIES".format("&nbsp;"), "", "", "")
            html = html + "</table>"
        return html

    def moveIt(self, dx, dy):
        '''
        Move the node rectangle and the node textbox to the delta x,y coordinate.
        '''
        #        print("before moveIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))

        self.TNode.moveBy(dx, dy)
        self.x = self.TNode.sceneBoundingRect().x()
        self.y = self.TNode.sceneBoundingRect().y()
        self.TNtext.moveBy(dx, dy)
        #        print("after moveIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))
        # now redraw all the relationships
        self.drawRels()

    def drawRels(self, ):
        '''Redraw all the relationship lines connected to the Node Template Rectangle'''
        # get a list of the relationship items connected to this node template
        self.relList = self.getRelList()

        # assign the correct inbound/outbound side for the rel
        for rel in self.relList:
            if rel.endNodeItem.NZID != rel.startNodeItem.NZID:  # ignore bunny ears
                rel.assignSide()
        # get a set of all the nodes and sides involved
        nodeSet = set()
        for rel in self.relList:
            if rel.endNodeItem.NZID != rel.startNodeItem.NZID:  # ignore bunny ears
                nodeSet.add((rel.endNodeItem, rel.inboundSide))
                nodeSet.add((rel.startNodeItem, rel.outboundSide))

        # tell each node side to assign rel locations
        for nodeSide in nodeSet:
            nodeSide[0].assignPoint(nodeSide[1])

        ############################################

        # now tell them all to redraw
        for rel in self.relList:
            rel.drawIt2()

    def calcOffset(self, index, totRels):
        offset = [-60, -40, -20, 0, 20, 40, 60]
        offsetStart = [3, 2, 2, 1, 1, 0, 0]
        if totRels > 7:
            totRels = 7
        return offset[offsetStart[totRels - 1] + index]

    def assignPoint(self, side):
        # go through all the rels on a side and assign their x,y coord for that side
        self.relList = self.getRelList()
        sideList = [
            rel for rel in self.relList
            if ((rel.startNZID == self.NZID and rel.outboundSide == side) or (
                rel.endNZID == self.NZID and rel.inboundSide == side))
        ]
        totRels = len(sideList)
        if totRels > 0:
            if side == R:
                # calc center of the side
                x = self.x + self.getWidth()
                y = self.y + self.getHeight() / 2
                # sort the rels connected to this side by the y value
                sideList.sort(key=self.getSortY)
                # assign each of them a position on the side starting in the center and working out in both directions
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
            elif side == L:
                x = self.x
                y = self.y + self.getHeight() / 2
                sideList.sort(key=self.getSortY)
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
            elif side == TOP:
                x = self.x + self.getWidth() / 2
                y = self.y
                sideList.sort(key=self.getSortX)
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
            elif side == BOTTOM:
                x = self.x + self.getWidth() / 2
                y = self.y + self.getHeight()
                sideList.sort(key=self.getSortX)
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
            else:
                print("error, no side")

    def getSortY(self, rel):
        # if this node is the start node then return the end node's Y
        if rel.startNZID == self.NZID:
            return rel.endNodeItem.TNode.sceneBoundingRect().center().y()
        # if this node is the end node then return the start node's Y
        if rel.endNZID == self.NZID:
            return rel.startNodeItem.TNode.sceneBoundingRect().center().y()
        # this should never happen
        return 0

    def getSortX(self, rel):
        # if this node is the start node then return the end node's X
        if rel.startNZID == self.NZID:
            return rel.endNodeItem.TNode.sceneBoundingRect().center().x()
        # if this node is the end node then return the start node's X
        if rel.endNZID == self.NZID:
            return rel.startNodeItem.TNode.sceneBoundingRect().center().x()
        # this should never happen
        return 0

    def getObjectDict(self, ):
        '''
        This function returns a dictionary with all the data that represents this node template item.  
        The dictionary is added to the Instance Diagram dictionary.'''
        objectDict = {}
        objectDict["NZID"] = self.NZID
        objectDict["name"] = self.nodeTemplateDict.get("name", "")
        objectDict["displayText"] = self.displayText
        objectDict["x"] = self.TNode.sceneBoundingRect().x()
        objectDict["y"] = self.TNode.sceneBoundingRect().y()
        objectDict["diagramType"] = self.diagramType
        objectDict["labels"] = self.nodeTemplateDict.get("labels", [])
        objectDict["properties"] = self.nodeTemplateDict.get("properties", [])

        return objectDict

    def setLogMethod(self, logMethod=None):
        if logMethod is None:
            if self.logMsg is None:
                self.logMsg = self.noLog
        else:
            self.logMsg = logMethod

    def noLog(self, msg):
        return
Example #42
0
class PreXoverLabel(QGraphicsSimpleTextItem):
    """Summary

    Attributes:
        is_fwd (TYPE): Description
    """
    _XO_FONT = styles.XOVER_LABEL_FONT
    _XO_BOLD = styles.XOVER_LABEL_FONT_BOLD
    _FM = QFontMetrics(_XO_FONT)

    def __init__(self, is_fwd, color, pre_xover_item):
        """Summary

        Args:
            is_fwd (TYPE): Description
            color (TYPE): Description
            pre_xover_item (TYPE): Description
        """
        super(QGraphicsSimpleTextItem, self).__init__(pre_xover_item)
        self.is_fwd = is_fwd
        self._color = color
        self._tbr = None
        self._outline = QGraphicsRectItem(self)
        self.setFont(self._XO_FONT)
        self.setBrush(getBrushObj('#666666'))

    # end def

    def resetItem(self, is_fwd, color):
        """Summary

        Args:
            is_fwd (TYPE): Description
            color (TYPE): Description

        Returns:
            TYPE: Description
        """
        self.is_fwd = is_fwd
        self._color = color

    # end def

    def setTextAndStyle(self, text, outline=False):
        """Summary

        Args:
            text (TYPE): Description
            outline (bool, optional): Description

        Returns:
            TYPE: Description
        """
        str_txt = str(text)
        self._tbr = tBR = self._FM.tightBoundingRect(str_txt)
        half_label_H = tBR.height() / 2.0
        half_label_W = tBR.width() / 2.0

        labelX = BASE_WIDTH / 2.0 - half_label_W
        if str_txt == '1':  # adjust for the number one
            labelX -= tBR.width()

        labelY = half_label_H if self.is_fwd else (BASE_WIDTH -
                                                   tBR.height()) / 2

        self.setPos(labelX, labelY)
        self.setText(str_txt)

        if outline:
            self.setFont(self._XO_BOLD)
            self.setBrush(getBrushObj('#ff0000'))
        else:
            self.setFont(self._XO_FONT)
            self.setBrush(getBrushObj('#666666'))

        if outline:
            r = QRectF(self._tbr).adjusted(-half_label_W, 0, half_label_W,
                                           half_label_H)
            self._outline.setRect(r)
            self._outline.setPen(getPenObj('#ff0000', 0.25))
            self._outline.setY(2 * half_label_H)
            self._outline.show()
        else:
            self._outline.hide()
Example #43
0
class ZoomableScene(QGraphicsScene):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.noise_area = None
        self.ones_area = None
        self.zeros_area = None
        self.ones_arrow = None
        self.zeros_arrow = None
        self.selection_area = ROI(0, 0, 0, 0, fillcolor=constants.SELECTION_COLOR, opacity=constants.SELECTION_OPACITY)
        self.addItem(self.selection_area)

    def draw_noise_area(self, y, h):
        x = self.sceneRect().x()
        w = self.sceneRect().width()

        if self.ones_area is not None:
            self.ones_area.hide()
        if self.zeros_area is not None:
            self.zeros_area.hide()

        if self.noise_area is None or self.noise_area.scene() != self:
            roi = ROI(x, y, w, h, fillcolor=constants.NOISE_COLOR, opacity=constants.NOISE_OPACITY)
           # roi.setPen(QPen(constants.NOISE_COLOR, Qt.FlatCap))
            self.noise_area = roi
            self.addItem(self.noise_area)
        else:
            self.noise_area.show()
            self.noise_area.setY(y)
            self.noise_area.height = h

    def draw_sep_area(self, y_mid):
        x = self.sceneRect().x()
        y = self.sceneRect().y()
        h = self.sceneRect().height()
        w = self.sceneRect().width()
        if self.noise_area is not None:
            self.noise_area.hide()

        if self.ones_area is None:
            self.ones_area = QGraphicsRectItem(x, y, w, h / 2 + y_mid)
            self.ones_area.setBrush(constants.ONES_AREA_COLOR)
            self.ones_area.setOpacity(constants.SEPARATION_OPACITY)
            self.ones_area.setPen(QPen(constants.TRANSPARENT_COLOR, Qt.FlatCap))
            self.addItem(self.ones_area)

        else:
            self.ones_area.show()
            self.ones_area.setRect(x, y, w, h / 2 + y_mid)

        start = y + h / 2 + y_mid
        if self.zeros_area is None:
            self.zeros_area = QGraphicsRectItem(x, start, w, (y + h) - start)
            self.zeros_area.setBrush(constants.ZEROS_AREA_COLOR)
            self.zeros_area.setOpacity(constants.SEPARATION_OPACITY)
            self.zeros_area.setPen(QPen(constants.TRANSPARENT_COLOR, Qt.FlatCap))
            self.addItem(self.zeros_area)
        else:
            self.zeros_area.show()
            self.zeros_area.setRect(x, start, w, (y + h) - start)

    def clear(self):
        self.noise_area = None
        self.ones_area = None
        self.zeros_area = None
        self.zeros_arrow = None
        self.ones_arrow = None
        self.selection_area = None
        super().clear()

    def dragEnterEvent(self, event: QGraphicsSceneDragDropEvent):
        event.accept()

    def dragMoveEvent(self, event: QGraphicsSceneDragDropEvent):
        event.accept()
Example #44
0
class PaintArea(QGraphicsView):

    def __init__(self, width=10, parent=None):
        QGraphicsView.__init__(self, parent)
        self._frame = None
        self._instructions = None
        self.setScene(QGraphicsScene(self))
        self._items = self.scene().createItemGroup([])
        self.setMouseTracking(True)
        self.pen = QPen(Qt.black, width, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        self.painting = False
        self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
        self.viewport().setCursor(self.getCursor())
        self.updateScene()

    def updateScene(self):
        if self._frame:
            self.scene().setBackgroundBrush(Qt.gray)
        oldCanvas = self.canvas()
        self.setSceneRect(QRectF(self.contentsRect()))
        self.centerScene()
        self.scaleItems(oldCanvas, self.canvas())

    def centerScene(self):
        self.centerFrame()
        self.centerInstructions()

    def scaleItems(self, oldCanvas, newCanvas):
        pass

    def canvas(self):
        if self._frame:
            return self._frame.rect()
        return QRectF(self.contentsRect())

    def fitInstructions(self):
        textSize = self._instructions.document().size()
        factor = min(self.canvas().size().width() / textSize.width(),
                     self.canvas().size().height() / textSize.height())
        f = self._instructions.font()
        f.setPointSizeF(f.pointSizeF() * factor)
        self._instructions.setFont(f)

    def centerInstructions(self):
        if self._instructions:
            self.fitInstructions()
            size = self.size()
            textSize = self._instructions.document().size()
            self._instructions.setPos((size.width() - textSize.width()) / 2.0,
                                      (size.height() - textSize.height()) / 2.0)

    def setInstructions(self, text):
        if self._instructions:
            self._instructions.setPlainText(text)
        else:
            self._instructions = self.scene().addText(text, QFont('Arial', 10, QFont.Bold))
            self._instructions.setZValue(-1)
            self._instructions.setDefaultTextColor(QColor(220, 220, 220))
        self._text = text
        self.centerInstructions()

    def setFrame(self, width, height):
        if self._frame:
            self._frame.setRect(0, 0, width, height)
        else:
            self.addFrame(QRectF(0, 0, width, height))
        self.centerScene()

    def addFrame(self, rect):
        self._frame = QGraphicsRectItem(rect)
        self._frame.setPen(QPen(Qt.NoPen))
        self._frame.setBrush(Qt.white)
        self._frame.setZValue(-2)
        self.scene().addItem(self._frame)

    def centerFrame(self):
        if self._frame:
            rect = self._frame.rect()
            size = self.contentsRect()
            factor = min((size.width() + 1) / rect.width(),
                         (size.height() + 1) / rect.height())
            w, h = rect.width() * factor, rect.height() * factor
            self._frame.setRect(size.x() + (size.width() - w) / 2.0,
                                size.y() + (size.height() - h) / 2.0,
                                w, h)

    def resizeEvent(self, event):
        self.updateScene()

    def setBrushSize(self, size):
        self.pen.setWidth(size)
        self.viewport().setCursor(self.getCursor())

    def render(self, painter):
        if self._instructions:
            self.scene().removeItem(self._instructions)
        self.scene().render(painter,
                            source=self.scene().itemsBoundingRect())
        if self._instructions:
            self.scene().addItem(self._instructions)

    def getLines(self):
        items = [item for item in self.scene().items()
                 if item.group() == self._items]
        return self.canvas(), items

    def clear(self):
        for item in self.scene().items():
            if item.group() == self._items:
                self._items.removeFromGroup(item)

    def getCursor(self):
        antialiasing_margin = 1
        size = self.pen.width()
        pixmap = QPixmap(size + antialiasing_margin * 2,
                         size + antialiasing_margin * 2)
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
        painter.drawEllipse(QRectF(QPointF(antialiasing_margin, antialiasing_margin),
                                   QSizeF(size, size)))
        painter.end()
        return QCursor(pixmap)

    def addLine(self, start, end):
        if start == end:
            delta = QPointF(.0001, 0)
            end = start - delta
        line = self.scene().addLine(QLineF(start, end), self.pen)
        self._items.addToGroup(line)

    def drawPoint(self, pos):
        delta = QPointF(.0001, 0)
        line = self.scene().addLine(QLineF(pos, pos - delta), self.pen)
        self._items.addToGroup(line)

    def mousePressEvent(self, event):
        self.start = QPointF(self.mapToScene(event.pos()))
        self.painting = True
        self.addLine(self.start, self.start)

    def mouseReleaseEvent(self, event):
        self.painting = False

    def mouseMoveEvent(self, event):
        pos = QPointF(self.mapToScene(event.pos()))
        if self.painting:
            self.addLine(self.start, pos)
            self.start = pos
Example #45
0
class MapScene(QGraphicsScene):
    selectedObjectItemsChanged = pyqtSignal()

    ##
    # Constructor.
    ##
    def __init__(self, parent):
        super().__init__(parent)
        self.mMapDocument = None
        self.mSelectedTool = None
        self.mActiveTool = None
        self.mObjectSelectionItem = None
        self.mUnderMouse = False
        self.mCurrentModifiers = Qt.NoModifier,
        self.mDarkRectangle = QGraphicsRectItem()
        self.mDefaultBackgroundColor = Qt.darkGray

        self.mLayerItems = QVector()
        self.mObjectItems = QMap()
        self.mObjectLineWidth = 0.0
        self.mSelectedObjectItems = QSet()
        self.mLastMousePos = QPointF()
        self.mShowTileObjectOutlines = False
        self.mHighlightCurrentLayer = False
        self.mGridVisible = False

        self.setBackgroundBrush(self.mDefaultBackgroundColor)
        tilesetManager = TilesetManager.instance()
        tilesetManager.tilesetChanged.connect(self.tilesetChanged)
        tilesetManager.repaintTileset.connect(self.tilesetChanged)
        prefs = preferences.Preferences.instance()
        prefs.showGridChanged.connect(self.setGridVisible)
        prefs.showTileObjectOutlinesChanged.connect(self.setShowTileObjectOutlines)
        prefs.objectTypesChanged.connect(self.syncAllObjectItems)
        prefs.highlightCurrentLayerChanged.connect(self.setHighlightCurrentLayer)
        prefs.gridColorChanged.connect(self.update)
        prefs.objectLineWidthChanged.connect(self.setObjectLineWidth)
        self.mDarkRectangle.setPen(QPen(Qt.NoPen))
        self.mDarkRectangle.setBrush(Qt.black)
        self.mDarkRectangle.setOpacity(darkeningFactor)
        self.addItem(self.mDarkRectangle)
        self.mGridVisible = prefs.showGrid()
        self.mObjectLineWidth = prefs.objectLineWidth()
        self.mShowTileObjectOutlines = prefs.showTileObjectOutlines()
        self.mHighlightCurrentLayer = prefs.highlightCurrentLayer()
        # Install an event filter so that we can get key events on behalf of the
        # active tool without having to have the current focus.
        QCoreApplication.instance().installEventFilter(self)

    ##
    # Destructor.
    ##
    def __del__(self):
        if QCoreApplication.instance():
            QCoreApplication.instance().removeEventFilter(self)

    ##
    # Returns the map document this scene is displaying.
    ##
    def mapDocument(self):
        return self.mMapDocument

    ##
    # Sets the map this scene displays.
    ##
    def setMapDocument(self, mapDocument):
        if (self.mMapDocument):
            self.mMapDocument.disconnect()
            if (not self.mSelectedObjectItems.isEmpty()):
                self.mSelectedObjectItems.clear()
                self.selectedObjectItemsChanged.emit()

        self.mMapDocument = mapDocument
        if (self.mMapDocument):
            renderer = self.mMapDocument.renderer()
            renderer.setObjectLineWidth(self.mObjectLineWidth)
            renderer.setFlag(RenderFlag.ShowTileObjectOutlines, self.mShowTileObjectOutlines)
            self.mMapDocument.mapChanged.connect(self.mapChanged)
            self.mMapDocument.regionChanged.connect(self.repaintRegion)
            self.mMapDocument.tileLayerDrawMarginsChanged.connect(self.tileLayerDrawMarginsChanged)
            self.mMapDocument.layerAdded.connect(self.layerAdded)
            self.mMapDocument.layerRemoved.connect(self.layerRemoved)
            self.mMapDocument.layerChanged.connect(self.layerChanged)
            self.mMapDocument.objectGroupChanged.connect(self.objectGroupChanged)
            self.mMapDocument.imageLayerChanged.connect(self.imageLayerChanged)
            self.mMapDocument.currentLayerIndexChanged.connect(self.currentLayerIndexChanged)
            self.mMapDocument.tilesetTileOffsetChanged.connect(self.tilesetTileOffsetChanged)
            self.mMapDocument.objectsInserted.connect(self.objectsInserted)
            self.mMapDocument.objectsRemoved.connect(self.objectsRemoved)
            self.mMapDocument.objectsChanged.connect(self.objectsChanged)
            self.mMapDocument.objectsIndexChanged.connect(self.objectsIndexChanged)
            self.mMapDocument.selectedObjectsChanged.connect(self.updateSelectedObjectItems)

        self.refreshScene()

    ##
    # Returns whether the tile grid is visible.
    ##
    def isGridVisible(self):
        return self.mGridVisible

    ##
    # Returns the set of selected map object items.
    ##
    def selectedObjectItems(self):
        return QSet(self.mSelectedObjectItems)

    ##
    # Sets the set of selected map object items. This translates to a call to
    # MapDocument.setSelectedObjects.
    ##
    def setSelectedObjectItems(self, items):
        # Inform the map document about the newly selected objects
        selectedObjects = QList()
        #selectedObjects.reserve(items.size())
        for item in items:
            selectedObjects.append(item.mapObject())
        self.mMapDocument.setSelectedObjects(selectedObjects)

    ##
    # Returns the MapObjectItem associated with the given \a mapObject.
    ##
    def itemForObject(self, object):
        return self.mObjectItems[object]

    ##
    # Enables the selected tool at this map scene.
    # Therefore it tells that tool, that this is the active map scene.
    ##
    def enableSelectedTool(self):
        if (not self.mSelectedTool or not self.mMapDocument):
            return
        self.mActiveTool = self.mSelectedTool
        self.mActiveTool.activate(self)
        self.mCurrentModifiers = QApplication.keyboardModifiers()
        if (self.mCurrentModifiers != Qt.NoModifier):
            self.mActiveTool.modifiersChanged(self.mCurrentModifiers)
        if (self.mUnderMouse):
            self.mActiveTool.mouseEntered()
            self.mActiveTool.mouseMoved(self.mLastMousePos, Qt.KeyboardModifiers())

    def disableSelectedTool(self):
        if (not self.mActiveTool):
            return
        if (self.mUnderMouse):
            self.mActiveTool.mouseLeft()
        self.mActiveTool.deactivate(self)
        self.mActiveTool = None

    ##
    # Sets the currently selected tool.
    ##
    def setSelectedTool(self, tool):
        self.mSelectedTool = tool

    ##
    # QGraphicsScene.drawForeground override that draws the tile grid.
    ##
    def drawForeground(self, painter, rect):
        if (not self.mMapDocument or not self.mGridVisible):
            return
            
        offset = QPointF()

        # Take into account the offset of the current layer
        layer = self.mMapDocument.currentLayer()
        if layer:
            offset = layer.offset()
            painter.translate(offset)
        
        prefs = preferences.Preferences.instance()
        self.mMapDocument.renderer().drawGrid(painter, rect.translated(-offset), prefs.gridColor())

    ##
    # Override for handling enter and leave events.
    ##
    def event(self, event):
        x = event.type()
        if x==QEvent.Enter:
            self.mUnderMouse = True
            if (self.mActiveTool):
                self.mActiveTool.mouseEntered()
        elif x==QEvent.Leave:
            self.mUnderMouse = False
            if (self.mActiveTool):
                self.mActiveTool.mouseLeft()
        else:
            pass

        return super().event(event)

    def keyPressEvent(self, event):
        if (self.mActiveTool):
            self.mActiveTool.keyPressed(event)
        if (not (self.mActiveTool and event.isAccepted())):
            super().keyPressEvent(event)

    def mouseMoveEvent(self, mouseEvent):
        self.mLastMousePos = mouseEvent.scenePos()
        if (not self.mMapDocument):
            return
        super().mouseMoveEvent(mouseEvent)
        if (mouseEvent.isAccepted()):
            return
        if (self.mActiveTool):
            self.mActiveTool.mouseMoved(mouseEvent.scenePos(), mouseEvent.modifiers())
            mouseEvent.accept()

    def mousePressEvent(self, mouseEvent):
        super().mousePressEvent(mouseEvent)
        if (mouseEvent.isAccepted()):
            return
        if (self.mActiveTool):
            mouseEvent.accept()
            self.mActiveTool.mousePressed(mouseEvent)

    def mouseReleaseEvent(self, mouseEvent):
        super().mouseReleaseEvent(mouseEvent)
        if (mouseEvent.isAccepted()):
            return
        if (self.mActiveTool):
            mouseEvent.accept()
            self.mActiveTool.mouseReleased(mouseEvent)

    ##
    # Override to ignore drag enter events.
    ##
    def dragEnterEvent(self, event):
        event.ignore()

    ##
    # Sets whether the tile grid is visible.
    ##
    def setGridVisible(self, visible):
        if (self.mGridVisible == visible):
            return
        self.mGridVisible = visible
        self.update()

    def setObjectLineWidth(self, lineWidth):
        if (self.mObjectLineWidth == lineWidth):
            return
        self.mObjectLineWidth = lineWidth
        if (self.mMapDocument):
            self.mMapDocument.renderer().setObjectLineWidth(lineWidth)
            # Changing the line width can change the size of the object items
            if (not self.mObjectItems.isEmpty()):
                for item in self.mObjectItems:
                    item[1].syncWithMapObject()
                self.update()

    def setShowTileObjectOutlines(self, enabled):
        if (self.mShowTileObjectOutlines == enabled):
            return
        self.mShowTileObjectOutlines = enabled
        if (self.mMapDocument):
            self.mMapDocument.renderer().setFlag(RenderFlag.ShowTileObjectOutlines, enabled)
            if (not self.mObjectItems.isEmpty()):
                self.update()

    ##
    # Sets whether the current layer should be highlighted.
    ##
    def setHighlightCurrentLayer(self, highlightCurrentLayer):
        if (self.mHighlightCurrentLayer == highlightCurrentLayer):
            return
        self.mHighlightCurrentLayer = highlightCurrentLayer
        self.updateCurrentLayerHighlight()

    ##
    # Refreshes the map scene.
    ##
    def refreshScene(self):
        self.mLayerItems.clear()
        self.mObjectItems.clear()
        self.removeItem(self.mDarkRectangle)
        self.clear()
        self.addItem(self.mDarkRectangle)
        if (not self.mMapDocument):
            self.setSceneRect(QRectF())
            return

        self.updateSceneRect()
        
        map = self.mMapDocument.map()
        self.mLayerItems.resize(map.layerCount())
        if (map.backgroundColor().isValid()):
            self.setBackgroundBrush(map.backgroundColor())
        else:
            self.setBackgroundBrush(self.mDefaultBackgroundColor)
        layerIndex = 0
        for layer in map.layers():
            layerItem = self.createLayerItem(layer)
            layerItem.setZValue(layerIndex)
            self.addItem(layerItem)
            self.mLayerItems[layerIndex] = layerItem
            layerIndex += 1

        tileSelectionItem = TileSelectionItem(self.mMapDocument)
        tileSelectionItem.setZValue(10000 - 2)
        self.addItem(tileSelectionItem)
        self.mObjectSelectionItem = ObjectSelectionItem(self.mMapDocument)
        self.mObjectSelectionItem.setZValue(10000 - 1)
        self.addItem(self.mObjectSelectionItem)
        self.updateCurrentLayerHighlight()

    ##
    # Repaints the specified region. The region is in tile coordinates.
    ##
    def repaintRegion(self, region, layer):
        renderer = self.mMapDocument.renderer()
        margins = self.mMapDocument.map().drawMargins()
        for r in region.rects():
            boundingRect = QRectF(renderer.boundingRect(r))
            self.update(QRectF(renderer.boundingRect(r).adjusted(-margins.left(),
                                                      -margins.top(),
                                                      margins.right(),
                                                      margins.bottom())))
            boundingRect.translate(layer.offset())
            self.update(boundingRect)

    def currentLayerIndexChanged(self):
        self.updateCurrentLayerHighlight()
        # New layer may have a different offset, affecting the grid
        if self.mGridVisible:
            self.update()
        
    ##
    # Adapts the scene, layers and objects to new map size, orientation or
    # background color.
    ##
    def mapChanged(self):
        self.updateSceneRect()
        for item in self.mLayerItems:
            tli = item
            if type(tli) == TileLayerItem:
                tli.syncWithTileLayer()

        for item in self.mObjectItems.values():
            item.syncWithMapObject()
        map = self.mMapDocument.map()
        if (map.backgroundColor().isValid()):
            self.setBackgroundBrush(map.backgroundColor())
        else:
            self.setBackgroundBrush(self.mDefaultBackgroundColor)

    def tilesetChanged(self, tileset):
        if (not self.mMapDocument):
            return
        if (contains(self.mMapDocument.map().tilesets(), tileset)):
            self.update()

    def tileLayerDrawMarginsChanged(self, tileLayer):
        index = self.mMapDocument.map().layers().indexOf(tileLayer)
        item = self.mLayerItems.at(index)
        item.syncWithTileLayer()

    def layerAdded(self, index):
        layer = self.mMapDocument.map().layerAt(index)
        layerItem = self.createLayerItem(layer)
        self.addItem(layerItem)
        self.mLayerItems.insert(index, layerItem)
        z = 0
        for item in self.mLayerItems:
            item.setZValue(z)
            z += 1

    def layerRemoved(self, index):
        self.mLayerItems.remove(index)

    ##
    # A layer has changed. This can mean that the layer visibility, opacity or
    # offset changed.
    ##
    def layerChanged(self, index):
        layer = self.mMapDocument.map().layerAt(index)
        layerItem = self.mLayerItems.at(index)
        layerItem.setVisible(layer.isVisible())
        multiplier = 1
        if (self.mHighlightCurrentLayer and self.mMapDocument.currentLayerIndex() < index):
            multiplier = opacityFactor
        layerItem.setOpacity(layer.opacity() * multiplier)
        layerItem.setPos(layer.offset())

        # Layer offset may have changed, affecting the scene rect and grid
        self.updateSceneRect()
        if self.mGridVisible:
            self.update()

    ##
    # When an object group has changed it may mean its color or drawing order
    # changed, which affects all its objects.
    ##
    def objectGroupChanged(self, objectGroup):
        self.objectsChanged(objectGroup.objects())
        self.objectsIndexChanged(objectGroup, 0, objectGroup.objectCount() - 1)

    ##
    # When an image layer has changed, it may change size and it may look
    # differently.
    ##
    def imageLayerChanged(self, imageLayer):
        index = self.mMapDocument.map().layers().indexOf(imageLayer)
        item = self.mLayerItems.at(index)
        item.syncWithImageLayer()
        item.update()

    ##
    # When the tile offset of a tileset has changed, it can affect the bounding
    # rect of all tile layers and tile objects. It also requires a full repaint.
    ##
    def tilesetTileOffsetChanged(self, tileset):
        self.update()
        for item in self.mLayerItems:
            tli = item
            if type(tli) == TileLayerItem:
                tli.syncWithTileLayer()
        for item in self.mObjectItems:
            cell = item.mapObject().cell()
            if (not cell.isEmpty() and cell.tile.tileset() == tileset):
                item.syncWithMapObject()

    ##
    # Inserts map object items for the given objects.
    ##
    def objectsInserted(self, objectGroup, first, last):
        ogItem = None
        # Find the object group item for the object group
        for item in self.mLayerItems:
            ogi = item
            if type(ogi)==ObjectGroupItem:
                if (ogi.objectGroup() == objectGroup):
                    ogItem = ogi
                    break

        drawOrder = objectGroup.drawOrder()
        for i in range(first, last+1):
            object = objectGroup.objectAt(i)
            item = MapObjectItem(object, self.mMapDocument, ogItem)
            if (drawOrder == ObjectGroup.DrawOrder.TopDownOrder):
                item.setZValue(item.y())
            else:
                item.setZValue(i)
            self.mObjectItems.insert(object, item)

    ##
    # Removes the map object items related to the given objects.
    ##
    def objectsRemoved(self, objects):
        for o in objects:
            i = self.mObjectItems.find(o)
            self.mSelectedObjectItems.remove(i)
            # python would not force delete QGraphicsItem
            self.removeItem(i)
            self.mObjectItems.erase(o)

    ##
    # Updates the map object items related to the given objects.
    ##
    def objectsChanged(self, objects):
        for object in objects:
            item = self.itemForObject(object)
            item.syncWithMapObject()

    ##
    # Updates the Z value of the objects when appropriate.
    ##
    def objectsIndexChanged(self, objectGroup, first, last):
        if (objectGroup.drawOrder() != ObjectGroup.DrawOrder.IndexOrder):
            return
        for i in range(first, last+1):
            item = self.itemForObject(objectGroup.objectAt(i))
            item.setZValue(i)

    def updateSelectedObjectItems(self):
        objects = self.mMapDocument.selectedObjects()
        items = QSet()
        for object in objects:
            item = self.itemForObject(object)
            if item:
                items.insert(item)

        self.mSelectedObjectItems = items
        self.selectedObjectItemsChanged.emit()

    def syncAllObjectItems(self):
        for item in self.mObjectItems:
            item.syncWithMapObject()

    def createLayerItem(self, layer):
        layerItem = None
        tl = layer.asTileLayer()
        if tl:
            layerItem = TileLayerItem(tl, self.mMapDocument)
        else:
            og = layer.asObjectGroup()
            if og:
                drawOrder = og.drawOrder()
                ogItem = ObjectGroupItem(og)
                objectIndex = 0
                for object in og.objects():
                    item = MapObjectItem(object, self.mMapDocument, ogItem)
                    if (drawOrder == ObjectGroup.DrawOrder.TopDownOrder):
                        item.setZValue(item.y())
                    else:
                        item.setZValue(objectIndex)
                    self.mObjectItems.insert(object, item)
                    objectIndex += 1

                layerItem = ogItem
            else:
                il = layer.asImageLayer()
                if il:
                    layerItem = ImageLayerItem(il, self.mMapDocument)

        layerItem.setVisible(layer.isVisible())
        return layerItem

    def updateSceneRect(self):
        mapSize = self.mMapDocument.renderer().mapSize()
        sceneRect = QRectF(0, 0, mapSize.width(), mapSize.height())

        margins = self.mMapDocument.map().computeLayerOffsetMargins()
        sceneRect.adjust(-margins.left(),
                         -margins.top(),
                         margins.right(),
                         margins.bottom())

        self.setSceneRect(sceneRect)
        self.mDarkRectangle.setRect(sceneRect)
        
    def updateCurrentLayerHighlight(self):
        if (not self.mMapDocument):
            return
        currentLayerIndex = self.mMapDocument.currentLayerIndex()
        if (not self.mHighlightCurrentLayer or currentLayerIndex == -1):
            self.mDarkRectangle.setVisible(False)
            # Restore opacity for all layers
            for i in range(self.mLayerItems.size()):
                layer = self.mMapDocument.map().layerAt(i)
                self.mLayerItems.at(i).setOpacity(layer.opacity())

            return

        # Darken layers below the current layer
        self.mDarkRectangle.setZValue(currentLayerIndex - 0.5)
        self.mDarkRectangle.setVisible(True)
        # Set layers above the current layer to half opacity
        for i in range(1, self.mLayerItems.size()):
            layer = self.mMapDocument.map().layerAt(i)
            if currentLayerIndex < i:
                _x = opacityFactor
            else:
                _x = 1
            multiplier = _x
            self.mLayerItems.at(i).setOpacity(layer.opacity() * multiplier)

    def eventFilter(self, object, event):
        x = event.type()
        if x==QEvent.KeyPress or x==QEvent.KeyRelease:
                keyEvent = event
                newModifiers = keyEvent.modifiers()
                if (self.mActiveTool and newModifiers != self.mCurrentModifiers):
                    self.mActiveTool.modifiersChanged(newModifiers)
                    self.mCurrentModifiers = newModifiers
        else:
            pass

        return False