Beispiel #1
0
def test_pixmapGeneratorCache(qtbot, validIconPath):
    anim = iconify.anim.Spin()
    pixGen = iconify.core.PixmapGenerator('delete',
                                          color=QtGui.QColor('blue'),
                                          anim=anim)

    size = QtCore.QSize(24, 24)
    altSize = QtCore.QSize(32, 32)

    # Ensure that the pixmap generators cache is working as expected
    pixmapA = pixGen.pixmap(size)
    pixmapB = pixGen.pixmap(size)
    pixmapC = pixGen.pixmap(altSize)

    assert pixmapA is pixmapB
    assert pixmapA is not pixmapC
Beispiel #2
0
class GlobalTick(QtCore.QObject):
    """
    A singleton timer used to trigger all animation objects created by iconify
    """

    timeout = QtCore.Signal()

    _instance = None  # type: Optional[GlobalTick]

    def __init__(self):
        # type: () -> None
        # Note: No parent so it's owned by Qt
        super(GlobalTick, self).__init__()
        self._tick = QtCore.QTimer()
        self._tick.timeout.connect(self.timeout.emit)
        self._tick.setInterval(17)  # 60fps (ish)
        self._tick.start()

    @classmethod
    def instance(cls):
        # type: () -> GlobalTick
        """
        Return the global instance of the ticker.

        Returns
        -------
        GlobalTick
        """
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance
Beispiel #3
0
def test_pixmapGenerator(qtbot, validIconPath):
    size = QtCore.QSize(24, 24)
    color = QtGui.QColor('blue')
    anim = iconify.anim.Spin()

    basePixmapGen = iconify.core.PixmapGenerator('delete')

    assert os.path.isfile(basePixmapGen.path())
    assert basePixmapGen.color() is None
    assert basePixmapGen.anim() is None

    coloredPixmapGen = iconify.core.PixmapGenerator('delete', color=color)

    assert os.path.isfile(coloredPixmapGen.path())
    assert coloredPixmapGen.color() == color
    assert coloredPixmapGen.anim() is None

    animatedPixmapGen = iconify.core.PixmapGenerator('delete', anim=anim)

    assert os.path.isfile(animatedPixmapGen.path())
    assert animatedPixmapGen.color() is None
    assert animatedPixmapGen.anim() == anim

    baseImage = basePixmapGen.pixmap(size).toImage()
    coloredImage = coloredPixmapGen.pixmap(size).toImage()
    animatedImage = animatedPixmapGen.pixmap(size).toImage()

    assert baseImage.size() == size
    assert coloredImage.size() == size
    assert animatedImage.size() == size

    assert baseImage == baseImage
    assert baseImage != coloredImage
    assert baseImage != animatedImage
Beispiel #4
0
 def __init__(self):
     # type: () -> None
     # Note: No parent so it's owned by Qt
     super(GlobalTick, self).__init__()
     self._tick = QtCore.QTimer()
     self._tick.timeout.connect(self.timeout.emit)
     self._tick.setInterval(17)  # 60fps (ish)
     self._tick.start()
Beispiel #5
0
    def paintEvent(self, event):
        super(IconifyLabel, self).paintEvent(event)

        rect = event.rect()

        if rect.width() > rect.height():
            size = QtCore.QSize(rect.height(), rect.height())
        else:
            size = QtCore.QSize(rect.width(), rect.width())

        pixmap = self._pixmapGenerator.pixmap(size)

        painter = QtGui.QPainter(self)
        halfSize = size / 2
        point = rect.center() - QtCore.QPoint(halfSize.width(),
                                              halfSize.height())
        painter.drawPixmap(point, pixmap)
        painter.end()
Beispiel #6
0
    def resizeEvent(self, event):
        # type: (QtCore.QEvent) -> bool
        """
        Re-implemented to re-calculate the grid size to provide scaling icons

        Parameters
        ----------
        event : QtCore.QEvent
        """
        width = self.viewport().width() - 30
        # The minus 30 above ensures we don't end up with an item width that
        # can't be drawn the expected number of times across the view without
        # being wrapped. Without this, the view can flicker during resize
        tileWidth = width / VIEW_COLUMNS
        iconWidth = int(tileWidth * 0.8)

        self.setGridSize(QtCore.QSize(tileWidth, tileWidth))
        self.setIconSize(QtCore.QSize(iconWidth, iconWidth))

        return super(View, self).resizeEvent(event)
Beispiel #7
0
    def _removeUnsupportedNodes(cls, installLocation):
        # type: (str) -> None
        """
        Removes unsupported nodes from svg files found under the provided
        installLocation and re-writes them in place.

        Parameters
        ----------
        installLocation : str
        """
        for svg in glob.glob(os.path.join(installLocation, '*.svg')):
            dom = QtXml.QDomDocument("initData")

            svgFile = QtCore.QFile(svg)
            svgFile.open(QtCore.QIODevice.ReadOnly)
            dom.setContent(svgFile)
            svgFile.close()

            defNodes = dom.elementsByTagName('defs')
            for i in range(defNodes.count()):
                node = defNodes.item(0)
                node.parentNode().removeChild(node)

            symbolNodes = dom.elementsByTagName('symbol')
            for i in range(symbolNodes.count()):
                node = symbolNodes.item(0)
                node.parentNode().removeChild(node)

            byteArray = QtCore.QByteArray()
            textStream = QtCore.QTextStream(byteArray)
            dom.save(textStream, 0)

            svgFile = QtCore.QFile(svg)
            svgFile.open(QtCore.QIODevice.WriteOnly)
            svgFile.write(byteArray)
            svgFile.close()
Beispiel #8
0
    def data(self, index, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole:
            return self._icons[index.row()]
        elif role == QtCore.Qt.DecorationRole:
            return ico.Icon(self.data(index, role=QtCore.Qt.DisplayRole),
                            anim=anim)
        return None


app = QtWidgets.QApplication([])

anim = ico.anim.Spin()

model = Model(anim)

view = QtWidgets.QListView()
view.setUniformItemSizes(True)
view.setViewMode(QtWidgets.QListView.IconMode)

view.setGridSize(QtCore.QSize(80, 80))
view.setIconSize(QtCore.QSize(64, 64))

view.setModel(model)

anim.tick.connect(view.viewport().update)
anim.start()
view.show()

import sys
sys.exit(app.exec_())
Beispiel #9
0
    def __init__(self, parent=None):
        # type: (Optional[QtWidgets.QWidget]) -> None
        super(Browser, self).__init__(parent=parent)
        self.setMinimumSize(1024, 576)
        self.setWindowTitle('Iconify Browser')

        self._currentIcon = None  # type: Optional[QtGui.QIcon]
        self._currentAnim = None  # type: Optional[ico.anim.BaseAnimation]
        self._currentColor = None  # type: Optional[QtGui.QColor]

        iconNames = ico.path.listIcons()

        self._filterTimer = QtCore.QTimer(self)
        self._filterTimer.setSingleShot(True)
        self._filterTimer.setInterval(AUTO_SEARCH_TIMEOUT)
        self._filterTimer.timeout.connect(self._updateFilter)

        model = Model()
        model.setStringList(sorted(iconNames))

        self._proxyModel = QtCore.QSortFilterProxyModel()
        self._proxyModel.setSourceModel(model)
        self._proxyModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)

        self._listView = View(self)
        self._listView.setUniformItemSizes(True)
        self._listView.setViewMode(QtWidgets.QListView.IconMode)
        self._listView.setModel(self._proxyModel)
        self._listView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self._listView.doubleClicked.connect(self._copyIconText)
        self._listView.selectionModel().currentChanged.connect(
            self._iconChanged
        )

        self._lineEdit = QtWidgets.QLineEdit(self)
        self._lineEdit.setAlignment(QtCore.Qt.AlignCenter)
        self._lineEdit.textChanged.connect(self._triggerDelayedUpdate)
        self._lineEdit.returnPressed.connect(self._triggerImmediateUpdate)

        collections = []
        for iconName in iconNames:
            if ':' not in iconName:
                continue
            collections.append(iconName.split(':', 1)[0])
        collections = sorted(set(collections))

        self._collectionsCombo = QtWidgets.QComboBox(self)
        self._collectionsCombo.addItems([ALL_COLLECTIONS] + collections)
        self._collectionsCombo.currentIndexChanged.connect(
            self._triggerImmediateUpdate
        )

        lyt = QtWidgets.QHBoxLayout()
        lyt.setContentsMargins(0, 0, 0, 0)
        lyt.addWidget(self._collectionsCombo)
        lyt.addWidget(self._lineEdit)

        searchBarFrame = QtWidgets.QFrame(self)
        searchBarFrame.setLayout(lyt)

        self._iconName = QtWidgets.QLabel()
        self._iconName.setAlignment(QtCore.Qt.AlignCenter)

        self._copyButton = QtWidgets.QPushButton('Copy Name', self)
        self._copyButton.clicked.connect(self._copyIconText)

        lyt = QtWidgets.QVBoxLayout()
        lyt.addWidget(searchBarFrame)
        lyt.addWidget(self._listView)
        lyt.addWidget(self._copyButton)

        iconFrame = QtWidgets.QFrame(self)
        iconFrame.setLayout(lyt)

        lyt = QtWidgets.QVBoxLayout()

        self._previewImage = PixmapGeneratorLabel()
        self._previewImage.setFixedSize(QtCore.QSize(200, 200))

        self._animCombo = QtWidgets.QComboBox(self)
        self._animCombo.addItems((NO_ANIM, 'Spin', 'Breathe'))
        self._animCombo.currentIndexChanged.connect(self._animChanged)

        self._colorCombo = QtWidgets.QComboBox(self)
        self._colorCombo.addItems([NO_COLOR] +
                                  sorted(QtGui.QColor.colorNames()))
        self._colorCombo.currentIndexChanged.connect(self._colorChanged)

        self._previewFrame = QtWidgets.QFrame(self)
        self._previewFrame.setFixedWidth(200)

        lyt.addWidget(self._previewImage)
        lyt.addWidget(self._iconName)
        lyt.addWidget(self._animCombo)
        lyt.addWidget(self._colorCombo)
        lyt.addSpacerItem(
            QtWidgets.QSpacerItem(
                0, 0, QtWidgets.QSizePolicy.Expanding,
                QtWidgets.QSizePolicy.Expanding
            )
        )

        self._previewFrame.setLayout(lyt)

        lyt = QtWidgets.QHBoxLayout()
        lyt.setContentsMargins(0, 0, 0, 0)
        lyt.addWidget(iconFrame)
        lyt.addWidget(self._previewFrame)

        centralFrame = QtWidgets.QFrame(self)
        centralFrame.setLayout(lyt)
        self.setCentralWidget(centralFrame)

        QtWidgets.QShortcut(
            QtGui.QKeySequence(QtCore.Qt.Key_Return),
            self,
            self._copyIconText,
        )

        self._lineEdit.setFocus()

        geo = self.geometry()
        desktop = QtWidgets.QApplication.desktop()
        screen = desktop.screenNumber(desktop.cursor().pos())
        centerPoint = desktop.screenGeometry(screen).center()
        geo.moveCenter(centerPoint)
        self.setGeometry(geo)
Beispiel #10
0
class BaseAnimation(QtCore.QObject):
    """
    The base class that should be used for all animations.
    """

    # Emitted when the animation steps
    tick = QtCore.Signal()

    _minFrame = 0
    _maxFrame = 100

    def __init__(self, parent=None):
        # type: (Optional[QtCore.QObject]) -> None
        super(BaseAnimation, self).__init__(parent=parent)
        self._frame = self._minFrame
        self._active = False

    def __add__(self, other):
        # type: (object) -> BaseAnimation
        if isinstance(other, BaseAnimation):
            concatAnim = _ConcatAnim()
            concatAnim.setAnimations((self, other))
            return concatAnim
        raise ValueError("Unsupported operation!")

    def transform(self, rect):
        # type: (QtCore.QRect) -> QtGui.QTransform
        """
        Return a QtGui.QTransform for the current frame that will be used
        when drawing an image in the provided QRect.

        Parameters
        ----------
        rect : QtCore.QRect

        Returns
        -------
        QtGui.QTransform
        """
        return QtGui.QTransform()

    def start(self):
        # type: () -> None
        """
        Start the animation.
        """
        GlobalTick.instance().timeout.connect(self._tick)
        self._active = True

    def stop(self):
        # type: () -> None
        """
        Stop the animation and reset the current frame back to the start.
        """
        self.pause()
        self._frame = self._minFrame

    def pause(self):
        # type: () -> None
        """
        Stop the animation and maintain the current frame
        """
        try:
            GlobalTick.instance().timeout.disconnect(self._tick)
        except RuntimeError:
            pass
        self._active = False

    def toggle(self):
        # type: () -> None
        """
        Start or stop the animation based on it's current state.
        """
        if self.active():
            self.pause()
        else:
            self.start()

    def active(self):
        # type: () -> bool
        """
        Indicate if the animation is currently playing.

        Returns
        -------
        bool
        """
        return self._active

    def frame(self):
        # type: () -> int
        """
        Return the current frame of the animation.

        Returns
        -------
        int
        """
        return self._frame

    def forceTick(self):
        # type: () -> None
        """
        Manually increment the current frame.
        """
        self._tick()

    def incrementFrame(self):
        # type: () -> None
        """
        Called when the animation is ticked allowing subclasses to provide
        custom frame step logic e.g. single shot animations.
        """
        if self._frame == self._maxFrame:
            self._frame = self._minFrame
        else:
            self._frame += 1

    def _tick(self):
        # type: () -> None
        self.incrementFrame()
        self.tick.emit()