diagramscene.qrc

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file>images/pointer.png</file>
    <file>images/linepointer.png</file>
    <file>images/textpointer.png</file>
    <file>images/bold.png</file>
    <file>images/italic.png</file>
    <file>images/underline.png</file>
    <file>images/floodfill.png</file>
    <file>images/bringtofront.png</file>
    <file>images/delete.png</file>
    <file>images/sendtoback.png</file>
    <file>images/linecolor.png</file>
    <file>images/background1.png</file>
    <file>images/background2.png</file>
    <file>images/background3.png</file>
    <file>images/background4.png</file>
</qresource>
</RCC>

diagramscene.py

import math

from PySide6 import QtCore, QtGui, QtWidgets

import diagramscene_rc


class Arrow(QtWidgets.QGraphicsLineItem):
    def __init__(self, startItem, endItem, parent=None, scene=None):
        super(Arrow, self).__init__(parent, scene)

        self.arrowHead = QtGui.QPolygonF()

        self.myStartItem = startItem
        self.myEndItem = endItem
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)
        self.myColor = QtCore.Qt.black
        self.setPen(QtGui.QPen(self.myColor, 2, QtCore.Qt.SolidLine,
                QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))

    def setColor(self, color):
        self.myColor = color

    def startItem(self):
        return self.myStartItem

    def endItem(self):
        return self.myEndItem

    def boundingRect(self):
        extra = (self.pen().width() + 20) / 2.0
        p1 = self.line().p1()
        p2 = self.line().p2()
        return QtCore.QRectF(p1, QtCore.QSizeF(p2.x() - p1.x(), p2.y() - p1.y())).normalized().adjusted(-extra, -extra, extra, extra)

    def shape(self):
        path = super(Arrow, self).shape()
        path.addPolygon(self.arrowHead)
        return path

    def updatePosition(self):
        line = QtCore.QLineF(self.mapFromItem(self.myStartItem, 0, 0), self.mapFromItem(self.myEndItem, 0, 0))
        self.setLine(line)

    def paint(self, painter, option, widget=None):
        if (self.myStartItem.collidesWithItem(self.myEndItem)):
            return

        myStartItem = self.myStartItem
        myEndItem = self.myEndItem
        myColor = self.myColor
        myPen = self.pen()
        myPen.setColor(self.myColor)
        arrowSize = 20.0
        painter.setPen(myPen)
        painter.setBrush(self.myColor)

        centerLine = QtCore.QLineF(myStartItem.pos(), myEndItem.pos())
        endPolygon = myEndItem.polygon()
        p1 = endPolygon.at(0) + myEndItem.pos()

        intersectPoint = QtCore.QPointF()
        for i in endPolygon:
            p2 = i + myEndItem.pos()
            polyLine = QtCore.QLineF(p1, p2)
            intersectType, intersectPoint = polyLine.intersect(centerLine)
            if intersectType == QtCore.QLineF.BoundedIntersection:
                break
            p1 = p2

        self.setLine(QtCore.QLineF(intersectPoint, myStartItem.pos()))
        line = self.line()

        angle = math.acos(line.dx() / line.length())
        if line.dy() >= 0:
            angle = (math.pi * 2.0) - angle

        arrowP1 = line.p1() + QtCore.QPointF(math.sin(angle + math.pi / 3.0) * arrowSize,
                                        math.cos(angle + math.pi / 3) * arrowSize)
        arrowP2 = line.p1() + QtCore.QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrowSize,
                                        math.cos(angle + math.pi - math.pi / 3.0) * arrowSize)

        self.arrowHead.clear()
        for point in [line.p1(), arrowP1, arrowP2]:
            self.arrowHead.append(point)

        painter.drawLine(line)
        painter.drawPolygon(self.arrowHead)
        if self.isSelected():
            painter.setPen(QtGui.QPen(myColor, 1, QtCore.Qt.DashLine))
            myLine = QtCore.QLineF(line)
            myLine.translate(0, 4.0)
            painter.drawLine(myLine)
            myLine.translate(0,-8.0)
            painter.drawLine(myLine)


class DiagramTextItem(QtWidgets.QGraphicsTextItem):
    lostFocus = QtCore.Signal(QtWidgets.QGraphicsTextItem)

    selectedChange = QtCore.Signal(QtWidgets.QGraphicsItem)

    def __init__(self, parent=None, scene=None):
        super(DiagramTextItem, self).__init__(parent, scene)

        self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable)

    def itemChange(self, change, value):
        if change == QtWidgets.QGraphicsItem.ItemSelectedChange:
            self.selectedChange.emit(self)
        return value

    def focusOutEvent(self, event):
        self.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
        self.lostFocus.emit(self)
        super(DiagramTextItem, self).focusOutEvent(event)

    def mouseDoubleClickEvent(self, event):
        if self.textInteractionFlags() == QtCore.Qt.NoTextInteraction:
            self.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
        super(DiagramTextItem, self).mouseDoubleClickEvent(event)


class DiagramItem(QtWidgets.QGraphicsPolygonItem):
    Step, Conditional, StartEnd, Io = range(4)

    def __init__(self, diagramType, contextMenu, parent=None, scene=None):
        super(DiagramItem, self).__init__(parent, scene)

        self.arrows = []

        self.diagramType = diagramType
        self.myContextMenu = contextMenu

        path = QtGui.QPainterPath()
        if self.diagramType == self.StartEnd:
            path.moveTo(200, 50)
            path.arcTo(150, 0, 50, 50, 0, 90)
            path.arcTo(50, 0, 50, 50, 90, 90)
            path.arcTo(50, 50, 50, 50, 180, 90)
            path.arcTo(150, 50, 50, 50, 270, 90)
            path.lineTo(200, 25)
            self.myPolygon = path.toFillPolygon()
        elif self.diagramType == self.Conditional:
            self.myPolygon = QtGui.QPolygonF([
                    QtCore.QPointF(-100, 0), QtCore.QPointF(0, 100),
                    QtCore.QPointF(100, 0), QtCore.QPointF(0, -100),
                    QtCore.QPointF(-100, 0)])
        elif self.diagramType == self.Step:
            self.myPolygon = QtGui.QPolygonF([
                    QtCore.QPointF(-100, -100), QtCore.QPointF(100, -100),
                    QtCore.QPointF(100, 100), QtCore.QPointF(-100, 100),
                    QtCore.QPointF(-100, -100)])
        else:
            self.myPolygon = QtGui.QPolygonF([
                    QtCore.QPointF(-120, -80), QtCore.QPointF(-70, 80),
                    QtCore.QPointF(120, 80), QtCore.QPointF(70, -80),
                    QtCore.QPointF(-120, -80)])

        self.setPolygon(self.myPolygon)
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)

    def removeArrow(self, arrow):
        try:
            self.arrows.remove(arrow)
        except ValueError:
            pass

    def removeArrows(self):
        for arrow in self.arrows[:]:
            arrow.startItem().removeArrow(arrow)
            arrow.endItem().removeArrow(arrow)
            self.scene().removeItem(arrow)

    def addArrow(self, arrow):
        self.arrows.append(arrow)

    def image(self):
        pixmap = QtGui.QPixmap(250, 250)
        pixmap.fill(QtCore.Qt.transparent)
        painter = QtGui.QPainter(pixmap)
        painter.setPen(QtGui.QPen(QtCore.Qt.black, 8))
        painter.translate(125, 125)
        painter.drawPolyline(self.myPolygon)
        return pixmap

    def contextMenuEvent(self, event):
        self.scene().clearSelection()
        self.setSelected(True)
        self.myContextMenu.exec_(event.screenPos())

    def itemChange(self, change, value):
        if change == QtWidgets.QGraphicsItem.ItemPositionChange:
            for arrow in self.arrows:
                arrow.updatePosition()

        return value


class DiagramScene(QtWidgets.QGraphicsScene):
    InsertItem, InsertLine, InsertText, MoveItem  = range(4)

    itemInserted = QtCore.Signal(DiagramItem)

    textInserted = QtCore.Signal(QtWidgets.QGraphicsTextItem)

    itemSelected = QtCore.Signal(QtWidgets.QGraphicsItem)

    def __init__(self, itemMenu, parent=None):
        super(DiagramScene, self).__init__(parent)

        self.myItemMenu = itemMenu
        self.myMode = self.MoveItem
        self.myItemType = DiagramItem.Step
        self.line = None
        self.textItem = None
        self.myItemColor = QtCore.Qt.white
        self.myTextColor = QtCore.Qt.black
        self.myLineColor = QtCore.Qt.black
        self.myFont = QtGui.QFont()

    def setLineColor(self, color):
        self.myLineColor = color
        if self.isItemChange(Arrow):
            item = self.selectedItems()[0]
            item.setColor(self.myLineColor)
            self.update()

    def setTextColor(self, color):
        self.myTextColor = color
        if self.isItemChange(DiagramTextItem):
            item = self.selectedItems()[0]
            item.setDefaultTextColor(self.myTextColor)

    def setItemColor(self, color):
        self.myItemColor = color
        if self.isItemChange(DiagramItem):
            item = self.selectedItems()[0]
            item.setBrush(self.myItemColor)

    def setFont(self, font):
        self.myFont = font
        if self.isItemChange(DiagramTextItem):
            item = self.selectedItems()[0]
            item.setFont(self.myFont)

    def setMode(self, mode):
        self.myMode = mode

    def setItemType(self, type):
        self.myItemType = type

    def editorLostFocus(self, item):
        cursor = item.textCursor()
        cursor.clearSelection()
        item.setTextCursor(cursor)

        if not item.toPlainText():
            self.removeItem(item)
            item.deleteLater()

    def mousePressEvent(self, mouseEvent):
        if (mouseEvent.button() != QtCore.Qt.LeftButton):
            return

        if self.myMode == self.InsertItem:
            item = DiagramItem(self.myItemType, self.myItemMenu)
            item.setBrush(self.myItemColor)
            self.addItem(item)
            item.setPos(mouseEvent.scenePos())
            self.itemInserted.emit(item)
        elif self.myMode == self.InsertLine:
            self.line = QtWidgets.QGraphicsLineItem(QtCore.QLineF(mouseEvent.scenePos(),
                                        mouseEvent.scenePos()))
            self.line.setPen(QtGui.QPen(self.myLineColor, 2))
            self.addItem(self.line)
        elif self.myMode == self.InsertText:
            textItem = DiagramTextItem()
            textItem.setFont(self.myFont)
            textItem.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
            textItem.setZValue(1000.0)
            textItem.lostFocus.connect(self.editorLostFocus)
            textItem.selectedChange.connect(self.itemSelected)
            self.addItem(textItem)
            textItem.setDefaultTextColor(self.myTextColor)
            textItem.setPos(mouseEvent.scenePos())
            self.textInserted.emit(textItem)

        super(DiagramScene, self).mousePressEvent(mouseEvent)

    def mouseMoveEvent(self, mouseEvent):
        if self.myMode == self.InsertLine and self.line:
            newLine = QtCore.QLineF(self.line.line().p1(), mouseEvent.scenePos())
            self.line.setLine(newLine)
        elif self.myMode == self.MoveItem:
            super(DiagramScene, self).mouseMoveEvent(mouseEvent)

    def mouseReleaseEvent(self, mouseEvent):
        if self.line and self.myMode == self.InsertLine:
            startItems = self.items(self.line.line().p1())
            if len(startItems) and startItems[0] == self.line:
                startItems.pop(0)
            endItems = self.items(self.line.line().p2())
            if len(endItems) and endItems[0] == self.line:
                endItems.pop(0)

            self.removeItem(self.line)
            self.line = None

            if len(startItems) and len(endItems) and \
                    isinstance(startItems[0], DiagramItem) and \
                    isinstance(endItems[0], DiagramItem) and \
                    startItems[0] != endItems[0]:
                startItem = startItems[0]
                endItem = endItems[0]
                arrow = Arrow(startItem, endItem)
                arrow.setColor(self.myLineColor)
                startItem.addArrow(arrow)
                endItem.addArrow(arrow)
                arrow.setZValue(-1000.0)
                self.addItem(arrow)
                arrow.updatePosition()

        self.line = None
        super(DiagramScene, self).mouseReleaseEvent(mouseEvent)

    def isItemChange(self, type):
        for item in self.selectedItems():
            if isinstance(item, type):
                return True
        return False


class MainWindow(QtWidgets.QMainWindow):
    InsertTextButton = 10

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

        self.createActions()
        self.createMenus()
        self.createToolBox()

        self.scene = DiagramScene(self.itemMenu)
        self.scene.setSceneRect(QtCore.QRectF(0, 0, 5000, 5000))
        self.scene.itemInserted.connect(self.itemInserted)
        self.scene.textInserted.connect(self.textInserted)
        self.scene.itemSelected.connect(self.itemSelected)

        self.createToolbars()

        layout = QtWidgets.QHBoxLayout()
        layout.addWidget(self.toolBox)
        self.view = QtWidgets.QGraphicsView(self.scene)
        layout.addWidget(self.view)

        self.widget = QtWidgets.QWidget()
        self.widget.setLayout(layout)

        self.setCentralWidget(self.widget)
        self.setWindowTitle("Diagramscene")

    def backgroundButtonGroupClicked(self, button):
        buttons = self.backgroundButtonGroup.buttons()
        for myButton in buttons:
            if myButton != button:
                button.setChecked(False)

        text = button.text()
        if text == "Blue Grid":
            self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background1.png')))
        elif text == "White Grid":
            self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background2.png')))
        elif text == "Gray Grid":
            self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background3.png')))
        else:
            self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background4.png')))

        self.scene.update()
        self.view.update()

    def buttonGroupClicked(self, id):
        buttons = self.buttonGroup.buttons()
        for button in buttons:
            if self.buttonGroup.button(id) != button:
                button.setChecked(False)

        if id == self.InsertTextButton:
            self.scene.setMode(DiagramScene.InsertText)
        else:
            self.scene.setItemType(id)
            self.scene.setMode(DiagramScene.InsertItem)

    def deleteItem(self):
        for item in self.scene.selectedItems():
            if isinstance(item, DiagramItem):
                item.removeArrows()
            self.scene.removeItem(item)

    def pointerGroupClicked(self, i):
        self.scene.setMode(self.pointerTypeGroup.checkedId())

    def bringToFront(self):
        if not self.scene.selectedItems():
            return

        selectedItem = self.scene.selectedItems()[0]
        overlapItems = selectedItem.collidingItems()

        zValue = 0
        for item in overlapItems:
            if (item.zValue() >= zValue and isinstance(item, DiagramItem)):
                zValue = item.zValue() + 0.1
        selectedItem.setZValue(zValue)

    def sendToBack(self):
        if not self.scene.selectedItems():
            return

        selectedItem = self.scene.selectedItems()[0]
        overlapItems = selectedItem.collidingItems()

        zValue = 0
        for item in overlapItems:
            if (item.zValue() <= zValue and isinstance(item, DiagramItem)):
                zValue = item.zValue() - 0.1
        selectedItem.setZValue(zValue)

    def itemInserted(self, item):
        self.pointerTypeGroup.button(DiagramScene.MoveItem).setChecked(True)
        self.scene.setMode(self.pointerTypeGroup.checkedId())
        self.buttonGroup.button(item.diagramType).setChecked(False)

    def textInserted(self, item):
        self.buttonGroup.button(self.InsertTextButton).setChecked(False)
        self.scene.setMode(self.pointerTypeGroup.checkedId())

    def currentFontChanged(self, font):
        self.handleFontChange()

    def fontSizeChanged(self, font):
        self.handleFontChange()

    def sceneScaleChanged(self, scale):
        newScale = int(scale[:-1]) / 100.0
        oldMatrix = self.view.matrix()
        self.view.resetMatrix()
        self.view.translate(oldMatrix.dx(), oldMatrix.dy())
        self.view.scale(newScale, newScale)

    def textColorChanged(self):
        self.textAction = self.sender()
        self.fontColorToolButton.setIcon(self.createColorToolButtonIcon(
                    ':/images/textpointer.png',
                    QtGui.QColor(self.textAction.data())))
        self.textButtonTriggered()

    def itemColorChanged(self):
        self.fillAction = self.sender()
        self.fillColorToolButton.setIcon(self.createColorToolButtonIcon(
                    ':/images/floodfill.png',
                    QtGui.QColor(self.fillAction.data())))
        self.fillButtonTriggered()

    def lineColorChanged(self):
        self.lineAction = self.sender()
        self.lineColorToolButton.setIcon(self.createColorToolButtonIcon(
                    ':/images/linecolor.png',
                    QtGui.QColor(self.lineAction.data())))
        self.lineButtonTriggered()

    def textButtonTriggered(self):
        self.scene.setTextColor(QtGui.QColor(self.textAction.data()))

    def fillButtonTriggered(self):
        self.scene.setItemColor(QtGui.QColor(self.fillAction.data()))

    def lineButtonTriggered(self):
        self.scene.setLineColor(QtGui.QColor(self.lineAction.data()))

    def handleFontChange(self):
        font = self.fontCombo.currentFont()
        font.setPointSize(int(self.fontSizeCombo.currentText()))
        if self.boldAction.isChecked():
            font.setWeight(QtGui.QFont.Bold)
        else:
            font.setWeight(QtGui.QFont.Normal)
        font.setItalic(self.italicAction.isChecked())
        font.setUnderline(self.underlineAction.isChecked())

        self.scene.setFont(font)

    def itemSelected(self, item):
        font = item.font()
        color = item.defaultTextColor()
        self.fontCombo.setCurrentFont(font)
        self.fontSizeCombo.setEditText(str(font.pointSize()))
        self.boldAction.setChecked(font.weight() == QtGui.QFont.Bold)
        self.italicAction.setChecked(font.italic())
        self.underlineAction.setChecked(font.underline())

    def about(self):
        QtWidgets.QMessageBox.about(self, "About Diagram Scene",
                "The <b>Diagram Scene</b> example shows use of the graphics framework.")

    def createToolBox(self):
        self.buttonGroup = QtWidgets.QButtonGroup()
        self.buttonGroup.setExclusive(False)
        self.buttonGroup.idClicked.connect(self.buttonGroupClicked)

        layout = QtWidgets.QGridLayout()
        layout.addWidget(self.createCellWidget("Conditional", DiagramItem.Conditional),
                0, 0)
        layout.addWidget(self.createCellWidget("Process", DiagramItem.Step), 0,
                1)
        layout.addWidget(self.createCellWidget("Input/Output", DiagramItem.Io),
                1, 0)

        textButton = QtWidgets.QToolButton()
        textButton.setCheckable(True)
        self.buttonGroup.addButton(textButton, self.InsertTextButton)
        textButton.setIcon(QtGui.QIcon(QtGui.QPixmap(':/images/textpointer.png')
                            .scaled(30, 30)))
        textButton.setIconSize(QtCore.QSize(50, 50))

        textLayout = QtWidgets.QGridLayout()
        textLayout.addWidget(textButton, 0, 0, QtCore.Qt.AlignHCenter)
        textLayout.addWidget(QtWidgets.QLabel("Text"), 1, 0,
                QtCore.Qt.AlignCenter)
        textWidget = QtWidgets.QWidget()
        textWidget.setLayout(textLayout)
        layout.addWidget(textWidget, 1, 1)

        layout.setRowStretch(3, 10)
        layout.setColumnStretch(2, 10)

        itemWidget = QtWidgets.QWidget()
        itemWidget.setLayout(layout)

        self.backgroundButtonGroup = QtWidgets.QButtonGroup()
        self.backgroundButtonGroup.buttonClicked.connect(self.backgroundButtonGroupClicked)

        backgroundLayout = QtWidgets.QGridLayout()
        backgroundLayout.addWidget(self.createBackgroundCellWidget("Blue Grid",
                ':/images/background1.png'), 0, 0)
        backgroundLayout.addWidget(self.createBackgroundCellWidget("White Grid",
                ':/images/background2.png'), 0, 1)
        backgroundLayout.addWidget(self.createBackgroundCellWidget("Gray Grid",
                ':/images/background3.png'), 1, 0)
        backgroundLayout.addWidget(self.createBackgroundCellWidget("No Grid",
                ':/images/background4.png'), 1, 1)

        backgroundLayout.setRowStretch(2, 10)
        backgroundLayout.setColumnStretch(2, 10)

        backgroundWidget = QtWidgets.QWidget()
        backgroundWidget.setLayout(backgroundLayout)

        self.toolBox = QtWidgets.QToolBox()
        self.toolBox.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Ignored))
        self.toolBox.setMinimumWidth(itemWidget.sizeHint().width())
        self.toolBox.addItem(itemWidget, "Basic Flowchart Shapes")
        self.toolBox.addItem(backgroundWidget, "Backgrounds")

    def createActions(self):
        self.toFrontAction = QtGui.QAction(
                QtGui.QIcon(':/images/bringtofront.png'), "Bring to &Front",
                self, shortcut="Ctrl+F", statusTip="Bring item to front",
                triggered=self.bringToFront)

        self.sendBackAction = QtGui.QAction(
                QtGui.QIcon(':/images/sendtoback.png'), "Send to &Back", self,
                shortcut="Ctrl+B", statusTip="Send item to back",
                triggered=self.sendToBack)

        self.deleteAction = QtGui.QAction(QtGui.QIcon(':/images/delete.png'),
                "&Delete", self, shortcut="Delete",
                statusTip="Delete item from diagram",
                triggered=self.deleteItem)

        self.exitAction = QtGui.QAction("E&xit", self, shortcut="Ctrl+X",
                statusTip="Quit Scenediagram example", triggered=self.close)

        self.boldAction = QtGui.QAction(QtGui.QIcon(':/images/bold.png'),
                "Bold", self, checkable=True, shortcut="Ctrl+B",
                triggered=self.handleFontChange)

        self.italicAction = QtGui.QAction(QtGui.QIcon(':/images/italic.png'),
                "Italic", self, checkable=True, shortcut="Ctrl+I",
                triggered=self.handleFontChange)

        self.underlineAction = QtGui.QAction(
                QtGui.QIcon(':/images/underline.png'), "Underline", self,
                checkable=True, shortcut="Ctrl+U",
                triggered=self.handleFontChange)

        self.aboutAction = QtGui.QAction("A&bout", self, shortcut="Ctrl+B",
                triggered=self.about)

    def createMenus(self):
        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenu.addAction(self.exitAction)

        self.itemMenu = self.menuBar().addMenu("&Item")
        self.itemMenu.addAction(self.deleteAction)
        self.itemMenu.addSeparator()
        self.itemMenu.addAction(self.toFrontAction)
        self.itemMenu.addAction(self.sendBackAction)

        self.aboutMenu = self.menuBar().addMenu("&Help")
        self.aboutMenu.addAction(self.aboutAction)

    def createToolbars(self):
        self.editToolBar = self.addToolBar("Edit")
        self.editToolBar.addAction(self.deleteAction)
        self.editToolBar.addAction(self.toFrontAction)
        self.editToolBar.addAction(self.sendBackAction)

        self.fontCombo = QtWidgets.QFontComboBox()
        self.fontCombo.currentFontChanged.connect(self.currentFontChanged)

        self.fontSizeCombo = QtWidgets.QComboBox()
        self.fontSizeCombo.setEditable(True)
        for i in range(8, 30, 2):
            self.fontSizeCombo.addItem(str(i))
        validator = QtGui.QIntValidator(2, 64, self)
        self.fontSizeCombo.setValidator(validator)
        self.fontSizeCombo.currentIndexChanged.connect(self.fontSizeChanged)

        self.fontColorToolButton = QtWidgets.QToolButton()
        self.fontColorToolButton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
        self.fontColorToolButton.setMenu(
                self.createColorMenu(self.textColorChanged, QtCore.Qt.black))
        self.textAction = self.fontColorToolButton.menu().defaultAction()
        self.fontColorToolButton.setIcon(
                self.createColorToolButtonIcon(':/images/textpointer.png',
                        QtCore.Qt.black))
        self.fontColorToolButton.setAutoFillBackground(True)
        self.fontColorToolButton.clicked.connect(self.textButtonTriggered)

        self.fillColorToolButton = QtWidgets.QToolButton()
        self.fillColorToolButton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
        self.fillColorToolButton.setMenu(
                self.createColorMenu(self.itemColorChanged, QtCore.Qt.white))
        self.fillAction = self.fillColorToolButton.menu().defaultAction()
        self.fillColorToolButton.setIcon(
                self.createColorToolButtonIcon(':/images/floodfill.png',
                        QtCore.Qt.white))
        self.fillColorToolButton.clicked.connect(self.fillButtonTriggered)

        self.lineColorToolButton = QtWidgets.QToolButton()
        self.lineColorToolButton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
        self.lineColorToolButton.setMenu(
                self.createColorMenu(self.lineColorChanged, QtCore.Qt.black))
        self.lineAction = self.lineColorToolButton.menu().defaultAction()
        self.lineColorToolButton.setIcon(
                self.createColorToolButtonIcon(':/images/linecolor.png',
                        QtCore.Qt.black))
        self.lineColorToolButton.clicked.connect(self.lineButtonTriggered)

        self.textToolBar = self.addToolBar("Font")
        self.textToolBar.addWidget(self.fontCombo)
        self.textToolBar.addWidget(self.fontSizeCombo)
        self.textToolBar.addAction(self.boldAction)
        self.textToolBar.addAction(self.italicAction)
        self.textToolBar.addAction(self.underlineAction)

        self.colorToolBar = self.addToolBar("Color")
        self.colorToolBar.addWidget(self.fontColorToolButton)
        self.colorToolBar.addWidget(self.fillColorToolButton)
        self.colorToolBar.addWidget(self.lineColorToolButton)

        pointerButton = QtWidgets.QToolButton()
        pointerButton.setCheckable(True)
        pointerButton.setChecked(True)
        pointerButton.setIcon(QtGui.QIcon(':/images/pointer.png'))
        linePointerButton = QtWidgets.QToolButton()
        linePointerButton.setCheckable(True)
        linePointerButton.setIcon(QtGui.QIcon(':/images/linepointer.png'))

        self.pointerTypeGroup = QtWidgets.QButtonGroup()
        self.pointerTypeGroup.addButton(pointerButton, DiagramScene.MoveItem)
        self.pointerTypeGroup.addButton(linePointerButton,
                DiagramScene.InsertLine)
        self.pointerTypeGroup.idClicked.connect(self.pointerGroupClicked)

        self.sceneScaleCombo = QtWidgets.QComboBox()
        self.sceneScaleCombo.addItems(["50%", "75%", "100%", "125%", "150%"])
        self.sceneScaleCombo.setCurrentIndex(2)
        self.sceneScaleCombo.currentTextChanged.connect(self.sceneScaleChanged)

        self.pointerToolbar = self.addToolBar("Pointer type")
        self.pointerToolbar.addWidget(pointerButton)
        self.pointerToolbar.addWidget(linePointerButton)
        self.pointerToolbar.addWidget(self.sceneScaleCombo)

    def createBackgroundCellWidget(self, text, image):
        button = QtWidgets.QToolButton()
        button.setText(text)
        button.setIcon(QtGui.QIcon(image))
        button.setIconSize(QtCore.QSize(50, 50))
        button.setCheckable(True)
        self.backgroundButtonGroup.addButton(button)

        layout = QtWidgets.QGridLayout()
        layout.addWidget(button, 0, 0, QtCore.Qt.AlignHCenter)
        layout.addWidget(QtWidgets.QLabel(text), 1, 0, QtCore.Qt.AlignCenter)

        widget = QtWidgets.QWidget()
        widget.setLayout(layout)

        return widget

    def createCellWidget(self, text, diagramType):
        item = DiagramItem(diagramType, self.itemMenu)
        icon = QtGui.QIcon(item.image())

        button = QtWidgets.QToolButton()
        button.setIcon(icon)
        button.setIconSize(QtCore.QSize(50, 50))
        button.setCheckable(True)
        self.buttonGroup.addButton(button, diagramType)

        layout = QtWidgets.QGridLayout()
        layout.addWidget(button, 0, 0, QtCore.Qt.AlignHCenter)
        layout.addWidget(QtWidgets.QLabel(text), 1, 0, QtCore.Qt.AlignCenter)

        widget = QtWidgets.QWidget()
        widget.setLayout(layout)

        return widget

    def createColorMenu(self, slot, defaultColor):
        colors = [QtCore.Qt.black, QtCore.Qt.white, QtCore.Qt.red, QtCore.Qt.blue, QtCore.Qt.yellow]
        names = ["black", "white", "red", "blue", "yellow"]

        colorMenu = QtWidgets.QMenu(self)
        for color, name in zip(colors, names):
            action = QtGui.QAction(self.createColorIcon(color), name, self,
                    triggered=slot)
            action.setData(QtGui.QColor(color))
            colorMenu.addAction(action)
            if color == defaultColor:
                colorMenu.setDefaultAction(action)
        return colorMenu

    def createColorToolButtonIcon(self, imageFile, color):
        pixmap = QtGui.QPixmap(50, 80)
        pixmap.fill(QtCore.Qt.transparent)
        painter = QtGui.QPainter(pixmap)
        image = QtGui.QPixmap(imageFile)
        target = QtCore.QRect(0, 0, 50, 60)
        source = QtCore.QRect(0, 0, 42, 42)
        painter.fillRect(QtCore.QRect(0, 60, 50, 80), color)
        painter.drawPixmap(target, image, source)
        painter.end()

        return QtGui.QIcon(pixmap)

    def createColorIcon(self, color):
        pixmap = QtGui.QPixmap(20, 20)
        painter = QtGui.QPainter(pixmap)
        painter.setPen(QtCore.Qt.NoPen)
        painter.fillRect(QtCore.QRect(0, 0, 20, 20), color)
        painter.end()

        return QtGui.QIcon(pixmap)


if __name__ == '__main__':

    import sys

    app = QtWidgets.QApplication(sys.argv)

    mainWindow = MainWindow()
    mainWindow.setGeometry(100, 100, 800, 500)
    mainWindow.show()

    sys.exit(app.exec_())

diagramscene_rc.py

# Resource object code (Python 3)
# Created by: object code
# Created by: The Resource Compiler for Qt version 5.14.0
# WARNING! All changes made in this file will be lost!

from PySide6 import QtCore

qt_resource_data = b"\
\x00\x00\x00\xf7\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x0b\x00\x00\x00\x0c\x08\x06\x00\x00\x00\xb4\xa9G\x9e\
\x00\x00\x00\xbeIDAT(S\x85\x911\x0e@@\
\x10EWM$J7\xa1\xa4\x918\x85^t\xaa=\
\x8aNT{\x80\xadun\xa0\xd1l\xe7\x12\xc4\x97\x19\
\xb1!YQ\xfcb\xfe\xbc\xfc\x99\xcc\x08\x00\x82t\x1c\
\x07\xa6i\x82\x10\xc2)\xcf\xf3.\xf0\xd68\x8e\xa8\xaa\
\x8aU\x14\x05\x03I\x92X\xef\x05?\xd5u\x1d\xc3Z\
k\xd0T\xf2\x9c 5\xeb\xbafx]W\xdc\xfeg\
r\x9a\xa6\x88\xe3\x18O\xcf\x09n\xdb\x06\xdf\xf7Q\x96\
\xa5]\xc1\x09Ss\x9eg^AJ\xf9\x9f<\x0c\x03\
\xc3J\xa9\xff\xe4\xb6m\x19^\x96\xe5?9\xcfs\x84\
a\x88}\xdf\xdf\xc9T\x18c\xec\xe1IA\x10 \x8a\
\x22[7M\x03\x9b\xdc\xf7\xfd\xf5\xce\x8fWgY\xc6\
\x13N\xfaWVX\xe8@\xda\xc6\x00\x00\x00\x00IE\
ND\xaeB`\x82\
\x00\x00\x01\x1a\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00*\x00\x00\x00+\x02\x03\x00\x00\x00s\xf1\xf2m\
\x00\x00\x00\x0cPLTE\xff\xff\xff\x80\x80\x80\x00\x00\
\x00\xff\xff\xffEJK8\x00\x00\x00\x01tRNS\
\x00@\xe6\xd8f\x00\x00\x00\xbcIDATx^M\
\xcb\xbd\x89\x041\x0c\x86a\xa1\xd0U8\x1c\xdc\x8f&\
\xd8\x12\xa6\x0a\xb3\xe1\xe6N.2\x07\x02\xdb\x07[\xc0\
\x96\xb4U\x9cG?3V\xf4!\xde\x07B\xcd\xe0\x17\
F\xbd\xf6\xb6\xec\x1a\xef\xa6A\x024\xb2A\x80`$\
\xcf\x9d\x9a\xee8\x8b~x\x83O~d\xb30hW\
\x102t\x22\x05\x98\x91\x89\x0c\xe4P\x88\x0c\xd4D\xe4\
 \xce\xdc\xc1\x98\x89\x833q \x89\x02\xe4\x9d\x1d`\
\xa1.@\xff\xe9\x02\xfd\xf1*\x0e\xd2\xfe{\x81P\xda\
\x02\x8e\xef\x02>\x0bx\xb3l\x01\x7f]\x1a\x03f\x1d\
4\x00\x03B\x15\xb0\xe4\x0a$7P$W\xc0\x92+\
\xe8\x92\x1b\x90\xdc\x80\xe4\x0a$7\xf0so\x1cp_\
[v<\xc7?\xd6Qh R\x85\xdb_\x00\x00\x00\
\x00IEND\xaeB`\x82\
\x00\x00\x00\xfa\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x0b\x00\x00\x00\x0c\x08\x06\x00\x00\x00\xb4\xa9G\x9e\
\x00\x00\x00\xc1IDAT(S\xcd\x901\x0a\x840\
\x10E\xc7\xceV\xb0\xd3F\x10o`\xe5\x01\xbcB@\
\x0b\x9bt\x22\x11\xbc\x94\x9d'\xd2\x03x\x03\x03\x19\xf7\
\x0f\xb8\xd9,l\xbf\x81Of\xde\xfc|\xc8P\x1c\xc7\
LD\xa2(\x8a8\xcfs~\x1d\xc2\xfd\xc9\xd34e\
\xd2ZsQ\x14\x02\x86a\xe0y\x9e\xc5\x8c\x1b=8\
\xe6\xe382a\xa0\x94\x12\x88\xfa[\xe0\x98;\xe7B\
3\xc0/3\xea\x7fJ\xee\xbaN\xcc\xd7u\x05\x0f\xd0\
\x83\xf7}\xef\x93\xb1&\xc0}\xdf\x03\xf3q\x1c\xc2\x97\
e\xf1\xc9\xeb\xba\x0a\x9c\xa6)0?!\xdb\xb6\xf9d\
\xa8\xaek\x19\x94e\xc9m\xdbrUU\xd27M\xc3\
\xd6Z\x9f\xfc\xc8\x18\xc3Y\x96\x89)I\x12\xc6_\xce\
\xf3|o\xe9\x063 8\xcd\x08\x1exv\x00\x00\x00\
\x00IEND\xaeB`\x82\
\x00\x00\x00r\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
\x00\x00\x00\x06PLTE\xff\xff\xff\x00\x00\x00U\xc2\
\xd3~\x00\x00\x00'IDATH\xc7c`\x80\x82\
\x06\x0640*0*0*0*\x80*\xf0\x1f\x15\
\xfc\x1b\x0d\xa0Q\x81Q\x81Q\x01\x22\x05\x00\xd5;N\
\xf0s\xe3o\xe9\x00\x00\x00\x00IEND\xaeB`\
\x82\
\x00\x00\x02\xf1\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00*\x00\x00\x00,\x08\x03\x00\x00\x00$D\xdat\
\x00\x00\x012PLTE\xff\xff\xff\xfe\xfe\xfe\x01\x01\
\x01\xbe\xbe\xbe\xfd\xfd\xfd\x00\x00\x00ddd\xd2\xd2\xd2\
|||\xfb\xfb\xfb\xe7\xe7\xe7\x84\x84\x84\xd7\xd7\xd7\xe0\
\xe0\xe0\xe1\xe1\xe1\x0c\x0c\x0c(((\xf5\xf5\xf5\xb3\xb3\
\xb3\x02\x02\x02\x95\x95\x95...\x11\x11\x11kkk\
\x03\x03\x03rrrIII\xfc\xfc\xfc\x13\x13\x13\x04\
\x04\x04\x9f\x9f\x9f\xc4\xc4\xc4\xa9\xa9\xa9\x05\x05\x05WW\
W\x17\x17\x17\xf6\xf6\xf6\x16\x16\x16\xa6\xa6\xa6\xa0\xa0\xa0\
```$$$>>>###\xb7\xb7\xb7M\
MM\xf8\xf8\xf8\xc0\xc0\xc0000\x09\x09\x09\xec\xec\
\xec   \x8a\x8a\x8a\xda\xda\xda\xf1\xf1\xf1\x0d\x0d\x0d\
\x99\x99\x99\x19\x19\x19\xf9\xf9\xf9\xcd\xcd\xcd\xf4\xf4\xf49\
99---;;;\x12\x12\x12CCC\xc2\xc2\
\xc2\xa4\xa4\xa4\xdc\xdc\xdcUUUhhhZZZ\
PPP\xf0\xf0\xf0\x06\x06\x06\x1f\x1f\x1fttt\xb1\
\xb1\xb1]]]!!!666\x08\x08\x08\xea\xea\
\xea\xdb\xdb\xdb\x81\x81\x81\x9c\x9c\x9c\x8b\x8b\x8buuu\
\xf2\xf2\xf2%%%\xce\xce\xceHHHccc\xba\
\xba\xbaSSS888\xf7\xf7\xf7\xe4\xe4\xe4\xa2\xa2\
\xa2JJJ\xf3\xf3\xf3___\xf1i\x00\xec\x00\x00\
\x00\x01tRNS\x00@\xe6\xd8f\x00\x00\x01mI\
DATx^\xd5\x92\xc5v\xc30\x10E=\x92\x1d\
f\xe6\x94\x99\x99\x99\x99\x99\xe1\xff\x7f\xa1\x9e\x89\x93S\
\xa9\xb2Nvm\xdf\xf2\xea\xfa\xbdY\xd8\xf8+\xf10\
\xeb[X\xcc\x047\x13<\x96\x10\xc6\xb5\xadB\xda\x9a\
om\x0d@\xb3\xad,\xe8\xda\x1a\xe2\xb5\xf4\xd4\xddq\
\xbf\xa1\x0d\x14{\x1b\xed\x09\xd0\xbb\x03\x0d\x93\x0d\xeaM\
\xd8A+3\x82n.\xac5\xc39\xbb\x95\xe5\xbb\xa9\
\xdb\xa7\xbd\xc0G\xcedG'~1;\xa7q\x87\xda\
\xd1,\x00\xf8\xe8\xda\x16\xcd~\x17\x19\x09\xc3\x88\x94\xd1\
]\xd5\xb4\xf6\xe1n\xbf\xdf66\xe9\x92\x90\xab\xeb\xa5\
\xf7\x09\xdb\x84a\xea\xcf\xbb\xeeg\xd1\x1c\x1dC`\xa6\
\xd1]\x89\xbb\x98S\xd3\xb8\xef\xa9\x81\x19Z\xa8\x80\xda\
M\xd1\xeb<\xbd\xc2B\x06\xbf[T\x9b\xe6\x12\x9a\xcb\
N\x0f\x1c\xd0\xb5w\xca\xfd5z[\xaf\x83\x8d$\xba\
[\xca\x0b\xb6q_\x0a\x8b\xee*\xdc\xc0\x9e\xa5\x08K\
)\xf6\x83\x962i\xf3\x87\xe9\xdfgj\xb7\x0a\xb2{\
\xe8b\xb2#\xd9\x84\x02\xf2c.\xe4\x04\xd9\xe9\x99d\
\x9eS\xc3\x85H/i\xe9\x0aDzmS\x96\x8c\x08\
\x14n\xa2Ho\x8b\x02\x8d\x97\xb0\xf5\x1e\xa4\xad\x07\xda\
z\x14XE\xfd\xd7W\xe9\x82'\xa1\xe1\x19\x97J/\
r\xab\x19C^~\xads\xce\xf9\x1b}\xfd\xce1\x1f\
\xe0`\xcc'\xademL\xcc\x12\xc2\xbcN#\x139\
A\x89y\xc1P5\xfc~\xeb\xff\xca\x17Uq \xbb\
\xd7\xbb.\xca\x00\x00\x00\x00IEND\xaeB`\x82\
\
\x00\x00\x01>\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4l;\
\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\
\xa7\x93\x00\x00\x00\xf3IDAT8\xcb\xed\x94An\
\x830\x10E\x9f%\xe0\x0c\xbdC/\xd0\x13\xe5\xfaU\
b\x9b\xd83\x01w\x81\x0d$\x85\xaa1\xca\xaa\x1d\x89\
\x8d\x0dO\xef{\x067m\xdb&\x0e\x94\xaa\x9a\xad\xf5\
\x06@D\xaa\xa0]\xd7\xed\xee5\xbc\xa8\xfe\xc1\x7f\x01\
l\x8c\xd9\xdbJ\x87\x8dS\xda`\x8c\x03\x0c\x01\xf4\x0a\
\xd2Ct\x98\xb7\xf7\x83G1*h\x81z\x10\x07\xd1\
\x1d<\xe3A&\xa0\xf6\x0b48\x88\x97Jp\x1aa\
\x88Kt\xf5\x93e\xb4\xd3#5\xc6i\x80[\x00)\
\xd1=\xa8\x83`W`_\x01\x96\x1c}\xb6|0\x95\
jp\xfep\x06\xba\x15\xd4\xe5\x14v\x01\xfft\xfd\xdd\
U\xb8\xe4\xce\xdb\x05\x5c&A\xfd\xb2\x064{\x17\xf5\
\xe6\x8f\x10\xce\xdf\xa1\xc54\xe6\x89\xa8j^\xf8\x9cF\
j\xb6t\x10\xb3\xa9\xac\x1a\xf84\xf8z\xce\xa6\x16b\
\x0fj\xef\x1bXRT\x81\xa5\x98nLE\xf4p\xeb\
\x9f\x07\x9b\x8f\xd3\xaf\xdf\xfd\x02\xd6\xbd\xde\xdfp\xdb\x04\
\x83\x00\x00\x00\x00IEND\xaeB`\x82\
\x00\x00\x00\xad\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x0f\x00\x00\x00\x18\x02\x03\x00\x00\x00XkO\xfa\
\x00\x00\x00\x09PLTE\xff\xff\xff\xff\xff\xff\x00\x00\
\x00\x8e\xf4\xc3\xec\x00\x00\x00\x01tRNS\x00@\xe6\
\xd8f\x00\x00\x00RIDAT\x08\x1d\x05\xc1\xb1\x0d\
\xc20\x14\x05\xc0\x8b\x04\x1b\xd0<O\xe3\x8a\x9a\xe6G\
r\x1f\x17a\x1aW\x9e\x80A\xb9\xf3\x82@\xeb\xc8B\
.d g'\xb5H]\xa4\x06\xa9\xb3K\xd5\x92\xfa\
\xfed\xcc\x8f\xdc\x17\xd9\x83\xf6\x1e\xe4\xd8\xdd\xe3\xd8\x1d\
sa.\xb4\x8e'\xf0\x07\xd5\x18\x11\x1b\xedM#\xf4\
\x00\x00\x00\x00IEND\xaeB`\x82\
\x00\x00\x00p\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
\x00\x00\x00\x06PLTE\x00\xff\xff\xff\xff\xff\xb1\xb8\
^\xa0\x00\x00\x00%IDATx^\xed\xcc!\x12\
\x00\x00\x04\x00A\xff\x7f4\x82\x11du/n\xb8\xd8\
j\xca\x0b\x00\x00\xf0\x9d\x01\x00@\x03\x94\x98\xeb\xc0\x19\
8\xa1\x84\x00\x00\x00\x00IEND\xaeB`\x82\
\x00\x00\x00\x91\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00*\x00\x00\x00+\x01\x03\x00\x00\x004Q\x88\xbd\
\x00\x00\x00\x06PLTE\xff\xff\xff\x00\x00\x00U\xc2\
\xd3~\x00\x00\x00\x01tRNS\x00@\xe6\xd8f\x00\
\x00\x009IDAT\x18Wc`\xc0\x05\x14 T\
\x01\x84\xfa\x01&\x19\xff\x80)f\x08\x8f\xfd\x03\x98\xe2\
\x7f\x00\xa6\xe4\x0f\x80)\xfb\x060U\x0f\xd1\xf6oP\
k\xe3\x87hc\x83P,\x0c\x84\x00\x00\x91\xca\x1c\x09\
\xf6#*\xfe\x00\x00\x00\x00IEND\xaeB`\x82\
\
\x00\x00\x01%\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4l;\
\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\
\xa7\x93\x00\x00\x00\xdaIDATH\xc7\xed\x94A\x0e\
\x820\x10E\x1fF8\x83w\xf0\xfe\x87\xf0\x1a^@\
\xb1\xa5t\xa6\x1a\x5c\xb4\x04\x8c\xa2\x11\xca\xc2\xc4I\xd8\
\xd0\xe4\xe5\xf5\xf7g\x8a\xb2,;\x16L\x08\xa1x\xf5\
\x7f\x0b\xa0\xaa\xb3\xa0UUM\x9emXi\xfe\xe0\x1f\
\x06o30\xbaU\xc0\xdd\xed\x0a7\x0f\xa1\x05u \
\x96b\xb7\xcf`\x1c\x5c\x826\xa0\x16\xc4f\x8aB\xed\
\x00\xf5\x16\xe4\x92\x09,\x97h)&~\x9a\xcb\xd8\xd7\
\xe0\xcd\x08\xdcd\x02\xbb\xf3`\xaa9\xc1\xed9A\xfb\
\xac\xcd\x00~\xb7\xfe>g\x5c\xc7\x8cC\x93\xe2H\x19\
O-\xeaW\x95\xed\x8e\x87!KI\x96\xbe\x8e\xa6\x92\
\x1a1\xeb\xf1\xfc)V\xaa\xefk\xb0 \xc9TG\x0f\
\xf85\xb8M\xd7V\x03\xe2 \x98\xc7\xaa\xf5\xb7\x98\x05\
\xd6\xde\xd4>\xf7W\x1a\xb8:\x00\x8a\xa5\xcbfj\xee\
\x91a\xa9f\xc0\x0f\xb5]\x00\x00\x00\x00IEND\
\xaeB`\x82\
\x00\x00\x00`\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
\x00\x00\x00\x03PLTE\xff\xff\xff\xa7\xc4\x1b\xc8\x00\
\x00\x00\x18IDATx^\xed\xc01\x01\x00\x00\x00\
\xc2 \xfb\xa76\xc5>X\x0b\x00\xe0\x08o\x00\x01\x01\
>\xc31\x00\x00\x00\x00IEND\xaeB`\x82\
\x00\x00\x03?\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4l;\
\x00\x00\x00\x04gAMA\x00\x00\xd6\xd8\xd4OX2\
\x00\x00\x00\x19tEXtSoftware\
\x00Adobe ImageRead\
yq\xc9e<\x00\x00\x02\xd1IDAT8\xcb}\
\x95KhSA\x14\x86\x93\xe6\xd1\x08I(\x04[\x17\
\x055\xeeZ\xbbP\xb2\xb1\xda\x85\x8f]\xb5\xbe\x16v\
)-BIW\xed\xce\x8d\x0a\xa2\xe0\xba\xab\x14\x84\x8a\
+QDE\x17\x0a\x8aU\xf1\x01\x1a\xb0V#\xad\xa2\
\xc5\xb6\x92j\x95\xbe4\xcd\xc3\xe3\x7fn\xced\xe6N\
\xd2\x16>\xe6\xde\xce?\x7ff\xcec\xae\x87\x88<&\
\xf8\xf3\x01~\xa8\x07\x01Pgk\x0cm\x9d\xa1\x0d\xf2\
\xda\xca\x9c!\xf2\x8a\x11Q\x7f\x7f^\x16l\x04a\xe0\
\xafa\xeaw\xb4\x03\x03J\xdb\x08\x22\xe2\xe15\x85\x8e\
\xe9\xbf\xa1!*uwS\xa1,f6\x83(\xcfW\
iS)*\xf5\xf4P)\x18T\xda8hp\xe6\xcd\
\xe3\x97`Z\xec\xed\xa5BK\x0b\xe5\xf0\xfe]\x9bo\
U\xe6\xca\xb44<L\xc5d\x92\x0amm\xb4\x8c\xf7\
q\xad\x8d;Z1\xa6\xd5d2\xbf\x8a\x9d\xe6Z[\
\xe9/\xde\xff\x80\x050\xed^\x10\xe3\xe7\x02L\xa1\xaf\
h'\xc1ep\xd6\xe3)\x8a\xb6I\x19\x87\xf8\x1fK\
`QF\xc5/\xb79\xe5a\x9a\x83\xe9\x0aL\x97\xc4\
t\x04\x1c\xd7\x9av\xd0\xac\x8c\x83\x12|\xfa\x0c\xe6\xc4\
\xf0\xb7\x8c\xccb\x22A+\x83\x83\xb4\xdc\xd7G\x0b0\
\xe5\xb9\x8c\xec\xf4\x986\xed\x02;\x1c/#\xc6aI\
\x14}\x043 +?\xc2\xfc\x88\xc5h\x1e\xf1\xfc\x19\
\x8f;\xef\xef@\x0a\x1c\xd1\xa6\xd8\xb4g\x97x\x84\xed\
\xf2\x89J\xa2\x1cs\x0e\xc1l\x0d\xde\x8b\xe9a\xb7i\
\xbb\x91d\xbf]\x9b\x01\x99\xe0D\xd1\x0c\x8e\xff\x0d;\
\x9d\xc2\xb3\xc9KpA\x9b\x9e\x00\x1d\x95j\x90\xb2\xac\
\xd5M\x01\x95\xfd,b\xfa\x15\xc7\xff\x84g\x13\x0e\xc3\
Mm\xdc\x09\xb6\xcb\x9a@U\xe7\xd9\xc5?\x8f\xecO\
#Q\x13\x88iF\x12\xa5\xf8\x00\xd2\xe0\x896_\xdf\
X\x99\xce\xc1t\x0a%\x95A\xf6\xc7\xc4\xe0\x01x\x05\
\xde\x821\x19\xdf\x80Q\xbb1\xecP\xa8\xde\xcf\xc2\xf4\
\x0bL\xc7a\xca\xbb\xba\x0f.\x81\xd3\xe0*x.\x86\
i\x19\xf9\xc7\x1eUw\xa8\xdf\xd5\xd2\xb3\xe8\xfdI\x98\
\xa6a\xca\x09\xba\x0b\xce\x83\x03F\x83\xdc\x03\xcf\xc0\x0b\
I\x22\x8f\x8f\xc15\xf7\xdd\x12\xae\xb4\xf4\x04n\xa9\x0c\
.\x94\xd7H\x16/\xbc\x0d\xce\x81\xfd\xee\xecw*s\
6{*?rK6\x90\xd4-\xdd\xe8j\xe9\xd1P\
\x88\x1eb\xbc\x0e\xce\x80}\xee:\xed\x90$1tG\
\xc2t\x03\x5c\x04\x87\xb4v\xb7\xdd\xd2M<qE\xe2\
\xb9\xb7\xba\xf8\xd5%\x14Su>R\xbex\xe8\xa0\xd6\
\x1e\x05\x09\xf3\x12\xf2I\xd0\xb7\xb1\xe0\xa4>R\x97\xb4\
\xa9}mV:\xf4\x94\xd6\xb2\xe9\x1e\xf1\x88\xda\xa5\xd6\
\xa0\xcc\xe5H;\xc1\x965.\xfa\xa8\xcc)mB\xd6\
\xea\x8b\xde\xfa4\xf1\x82MN\x9c\xca\xe1\x89\xac\xf3i\
\x8a\x88\xa6Y\xd6\xa8Syku\x9eO>\x8e\x1b\xec\
\x0f\xe4\x1a\xda\xa0h\xebM\xed\x7f=\xa9\x97\x96\x02\xf1\
+\x1c\x00\x00\x00\x00IEND\xaeB`\x82\
\x00\x00\x00\x8d\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x1b\x00\x00\x00\x1b\x01\x03\x00\x00\x00\xb7\x1af\x16\
\x00\x00\x00\x06PLTE\xff\xff\xff\x00\x00\x00U\xc2\
\xd3~\x00\x00\x00\x01tRNS\x00@\xe6\xd8f\x00\
\x00\x005IDAT\x08\x99c`\xc0\x02\xd8\x1b\x80\
\x04\xff\x01L\x82\xfd\x01H\xba\x00DX\x80\x08\x19\x10\
\xc1\x07\xd6\x02\x22\x98A\xfa\x18A\x0a\x19\xc0\x0a\xeb@\
\x84=\x16B\x0e\xddF\x00\xb5\x00\x09@\xa31\xbf^\
\x00\x00\x00\x00IEND\xaeB`\x82\
\x00\x00\x01\x12\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x0b\x00\x00\x00\x0d\x08\x06\x00\x00\x00\x7f\xf5\x94;\
\x00\x00\x00\xd9IDAT(S}\x901\x0eE@\
\x10\x86G$$\x1a\x0d\x0d\xd1\x22Qp\x80m\x5c@\
\xe7<\x0e!\x0aGq\x19\xb5N\xa9\xc1x3\xb2\x8b\
\xf7\xec\xdb\xe4\xcbfv\xfe\xf9gv\xc00\x0c\x04\x80\
\x07\xf4fY\x16&I\x82\x9f\x03\xc4\xbe\xef\x94;\x05\
i\x9a2$\x08\xc3\xf0QX\xd75\x17\x01\x05\x04U\
\xde]\xe8v\x1c\x87s\xb6m\xe3\xc3Y\x0a\xefDQ\
\xc4\xe2 \x08\xf4\xce\xeb\xbab\xdb\xb6j\x94\xbe\xefO\
\xb1|(\x8a\x82\xc9\xf3\x1c}\xdfg\x03!\x04\x0e\xc3\
\xa0L@\xb7\x0d\xd34Y\xdcu\xdd%\xfe\x9ey\xdb\
6\x9c\xa6\x89c\xd9!\x8ec\x1c\xc7\x11\xd5\xcco\x1f\
$d\xbe\xaa\xaa\xff\xdbX\x96E\x8dF]^\xb7A\
\xcc\xf3\x8cM\xd3\xa0\xccgYv9{\x9e\xa7p]\
\xf7\xe7\xd3\xdamH\xa8\xa8,K\xd5\xf1\x00\xd0\xc0\x13\
\xc8\x06\xaf\x16(\x00\x00\x00\x00IEND\xaeB`\
\x82\
\x00\x00\x00t\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
\x00\x00\x00\x06PLTE\xc0\xc0\xc0\xff\xff\xff+i\
\x87\xb4\x00\x00\x00)IDATHKc\xf8\x0f\x05\
\x0d\x0cP0*0*0*0*@\xa4\x00\x0c\xd8\
C\xc4\xff\x8d\x0a\x8c\x0a\x8c\x0a\x8c\x0a`\x17\x00\x00?\
x\xe4\xb7\xe3\x900_\x00\x00\x00\x00IEND\xae\
B`\x82\
"

qt_resource_name = b"\
\x00\x06\
\x07\x03}\xc3\
\x00i\
\x00m\x00a\x00g\x00e\x00s\
\x00\x0a\
\x02\xfcBG\
\x00i\
\x00t\x00a\x00l\x00i\x00c\x00.\x00p\x00n\x00g\
\x00\x0d\
\x06C\xe3g\
\x00f\
\x00l\x00o\x00o\x00d\x00f\x00i\x00l\x00l\x00.\x00p\x00n\x00g\
\x00\x0d\
\x08\xd5\xc4\xe7\
\x00u\
\x00n\x00d\x00e\x00r\x00l\x00i\x00n\x00e\x00.\x00p\x00n\x00g\
\x00\x0f\
\x00I\xdb\xa7\
\x00b\
\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x002\x00.\x00p\x00n\x00g\
\x00\x0f\
\x05\xaa\x0c\xc7\
\x00t\
\x00e\x00x\x00t\x00p\x00o\x00i\x00n\x00t\x00e\x00r\x00.\x00p\x00n\x00g\
\x00\x0e\
\x0f\x0d\x22'\
\x00s\
\x00e\x00n\x00d\x00t\x00o\x00b\x00a\x00c\x00k\x00.\x00p\x00n\x00g\
\x00\x0b\
\x0a+\x97\xe7\
\x00p\
\x00o\x00i\x00n\x00t\x00e\x00r\x00.\x00p\x00n\x00g\
\x00\x0f\
\x00P\xdb\xa7\
\x00b\
\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x001\x00.\x00p\x00n\x00g\
\x00\x0d\
\x05l\x22\xc7\
\x00l\
\x00i\x00n\x00e\x00c\x00o\x00l\x00o\x00r\x00.\x00p\x00n\x00g\
\x00\x10\
\x0f\x9b\x88g\
\x00b\
\x00r\x00i\x00n\x00g\x00t\x00o\x00f\x00r\x00o\x00n\x00t\x00.\x00p\x00n\x00g\
\x00\x0f\
\x00K\xdb\xa7\
\x00b\
\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x004\x00.\x00p\x00n\x00g\
\x00\x0a\
\x0c\xad\x0f\x07\
\x00d\
\x00e\x00l\x00e\x00t\x00e\x00.\x00p\x00n\x00g\
\x00\x0f\
\x03J#\xe7\
\x00l\
\x00i\x00n\x00e\x00p\x00o\x00i\x00n\x00t\x00e\x00r\x00.\x00p\x00n\x00g\
\x00\x08\
\x06'Zg\
\x00b\
\x00o\x00l\x00d\x00.\x00p\x00n\x00g\
\x00\x0f\
\x00J\xdb\xa7\
\x00b\
\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x003\x00.\x00p\x00n\x00g\
"

qt_resource_struct = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x0f\x00\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00l\x00\x00\x00\x00\x00\x01\x00\x00\x03\x17\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x01\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x0f\xf5\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x01\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x0a\xa7\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x00\xf2\x00\x00\x00\x00\x00\x01\x00\x00\x08u\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x00\x12\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x01\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x0eN\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x01\x16\x00\x00\x00\x00\x00\x01\x00\x00\x08\xe9\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x00\x03\x8d\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xdf\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x00,\x00\x00\x00\x00\x00\x01\x00\x00\x00\xfb\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x00L\x00\x00\x00\x00\x00\x01\x00\x00\x02\x19\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x00\xd6\x00\x00\x00\x00\x00\x01\x00\x00\x07\xc4\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x01\x80\x00\x00\x00\x00\x00\x01\x00\x00\x0b\x0b\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x00\xb4\x00\x00\x00\x00\x00\x01\x00\x00\x06\x82\
\x00\x00\x01e\xaf\x16\xd2\x9d\
\x00\x00\x016\x00\x00\x00\x00\x00\x01\x00\x00\x09~\
\x00\x00\x01e\xaf\x16\xd2\x9d\
"

def qInitResources():
    QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)

def qCleanupResources():
    QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)

qInitResources()