2012-11-26 20:49:16 +01:00
|
|
|
/*
|
|
|
|
* Copyright 2012 Marco Martin <mart@kde.org>
|
2014-05-12 18:47:49 +02:00
|
|
|
* Copyright 2014 David Edmundson <davidedmudnson@kde.org>
|
2012-11-26 20:49:16 +01:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Library General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this program; if not, write to the
|
|
|
|
* Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "iconitem.h"
|
2013-03-13 12:05:06 +01:00
|
|
|
#include <QDebug>
|
|
|
|
#include <QPaintEngine>
|
2012-11-26 20:49:16 +01:00
|
|
|
#include <QPainter>
|
|
|
|
#include <QPropertyAnimation>
|
2014-05-12 18:47:49 +02:00
|
|
|
#include <QPixmap>
|
|
|
|
#include <QSGSimpleTextureNode>
|
|
|
|
#include <QQuickWindow>
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2013-10-05 01:38:31 +02:00
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kiconeffect.h>
|
2015-10-20 11:44:52 +02:00
|
|
|
#include <KIconTheme>
|
2013-03-13 12:05:06 +01:00
|
|
|
|
2014-05-12 18:47:49 +02:00
|
|
|
#include "fadingnode_p.h"
|
2014-10-15 13:22:27 +02:00
|
|
|
#include <QuickAddons/ManagedTextureNode>
|
2014-09-25 14:33:39 +02:00
|
|
|
#include "units.h"
|
2013-02-02 04:43:20 +01:00
|
|
|
|
2013-02-01 17:26:26 +01:00
|
|
|
IconItem::IconItem(QQuickItem *parent)
|
2014-05-12 18:47:49 +02:00
|
|
|
: QQuickItem(parent),
|
2018-04-13 09:05:17 +02:00
|
|
|
m_svgIcon(nullptr),
|
2016-06-01 14:47:56 +02:00
|
|
|
m_status(Plasma::Svg::Normal),
|
2012-11-26 20:49:16 +01:00
|
|
|
m_active(false),
|
2016-01-06 20:21:15 +01:00
|
|
|
m_animated(true),
|
2016-01-20 11:28:56 +01:00
|
|
|
m_usesPlasmaTheme(true),
|
2017-02-26 11:27:58 +01:00
|
|
|
m_roundToIconSize(true),
|
2015-03-24 11:50:28 +01:00
|
|
|
m_textureChanged(false),
|
|
|
|
m_sizeChanged(false),
|
2016-03-11 14:07:44 +01:00
|
|
|
m_allowNextAnimation(false),
|
2016-07-12 10:02:47 +02:00
|
|
|
m_blockNextAnimation(false),
|
2017-04-03 15:42:29 +02:00
|
|
|
m_implicitHeightSetByUser(false),
|
|
|
|
m_implicitWidthSetByUser(false),
|
2014-06-18 19:22:02 +02:00
|
|
|
m_colorGroup(Plasma::Theme::NormalColorGroup),
|
2012-11-26 20:49:16 +01:00
|
|
|
m_animValue(0)
|
|
|
|
{
|
|
|
|
m_animation = new QPropertyAnimation(this);
|
2017-07-10 22:24:50 +02:00
|
|
|
connect(m_animation, &QPropertyAnimation::valueChanged,
|
|
|
|
this, &IconItem::valueChanged);
|
|
|
|
connect(m_animation, &QPropertyAnimation::finished,
|
|
|
|
this, &IconItem::animationFinished);
|
2012-11-26 20:49:16 +01:00
|
|
|
m_animation->setTargetObject(this);
|
|
|
|
m_animation->setEasingCurve(QEasingCurve::InOutQuad);
|
2014-05-12 18:47:49 +02:00
|
|
|
m_animation->setDuration(250); //FIXME from theme
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2013-02-01 18:18:52 +01:00
|
|
|
setFlag(ItemHasContents, true);
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2017-01-08 16:16:59 +01:00
|
|
|
connect(KIconLoader::global(), &KIconLoader::iconLoaderSettingsChanged,
|
|
|
|
this, &IconItem::updateImplicitSize);
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2017-04-03 15:42:29 +02:00
|
|
|
connect(this, &IconItem::implicitWidthChanged, this, &IconItem::implicitWidthChanged2);
|
|
|
|
connect(this, &IconItem::implicitHeightChanged, this, &IconItem::implicitHeightChanged2);
|
|
|
|
|
2017-01-08 16:16:59 +01:00
|
|
|
updateImplicitSize();
|
2012-11-26 20:49:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
IconItem::~IconItem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-01-08 16:16:59 +01:00
|
|
|
void IconItem::updateImplicitSize()
|
|
|
|
{
|
2017-03-24 06:19:15 +09:00
|
|
|
if (!m_imageIcon.isNull()) {
|
|
|
|
const QSize &s = m_imageIcon.size();
|
|
|
|
|
|
|
|
if (s.isValid()) {
|
2017-04-03 15:42:29 +02:00
|
|
|
if (!m_implicitWidthSetByUser && !m_implicitHeightSetByUser) {
|
|
|
|
setImplicitSize(s.width(), s.height());
|
|
|
|
} else if (!m_implicitWidthSetByUser) {
|
|
|
|
setImplicitWidth(s.width());
|
|
|
|
} else if (!m_implicitHeightSetByUser) {
|
|
|
|
setImplicitHeight(s.height());
|
|
|
|
}
|
2017-03-24 06:19:15 +09:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (m_svgIcon) { // FIXME: Check Svg::isValid()? Considered expensive by apidox.
|
2017-03-28 12:49:21 +02:00
|
|
|
//resize() resets the icon to its implicit size, specified
|
|
|
|
m_svgIcon->resize();
|
|
|
|
QSize s;
|
|
|
|
const QString &sourceString = m_source.toString();
|
|
|
|
//plasma theme icon, where one file contains multiple images
|
|
|
|
if (m_svgIcon->hasElement(sourceString)) {
|
|
|
|
s = m_svgIcon->elementSize(sourceString);
|
|
|
|
//normal icon: one image per file, page size is icon size
|
|
|
|
} else {
|
|
|
|
s = m_svgIcon->size();
|
|
|
|
}
|
2017-03-24 06:19:15 +09:00
|
|
|
if (s.isValid()) {
|
2017-04-03 15:42:29 +02:00
|
|
|
if (!m_implicitWidthSetByUser && !m_implicitHeightSetByUser) {
|
|
|
|
setImplicitSize(s.width(), s.height());
|
|
|
|
} else if (!m_implicitWidthSetByUser) {
|
|
|
|
setImplicitWidth(s.width());
|
|
|
|
} else if (!m_implicitHeightSetByUser) {
|
|
|
|
setImplicitHeight(s.height());
|
|
|
|
}
|
2017-03-24 06:19:15 +09:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall back to initializing implicit size to the Dialog size.
|
2017-01-08 16:16:59 +01:00
|
|
|
const int implicitSize = KIconLoader::global()->currentSize(KIconLoader::Dialog);
|
2017-04-03 15:42:29 +02:00
|
|
|
|
|
|
|
if (!m_implicitWidthSetByUser && !m_implicitHeightSetByUser) {
|
|
|
|
setImplicitSize(implicitSize, implicitSize);
|
|
|
|
} else if (!m_implicitWidthSetByUser) {
|
|
|
|
setImplicitWidth(implicitSize);
|
|
|
|
} else if (!m_implicitHeightSetByUser) {
|
|
|
|
setImplicitHeight(implicitSize);
|
|
|
|
}
|
2017-01-08 16:16:59 +01:00
|
|
|
}
|
|
|
|
|
2012-11-26 20:49:16 +01:00
|
|
|
void IconItem::setSource(const QVariant &source)
|
|
|
|
{
|
|
|
|
if (source == m_source) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-23 11:31:15 +02:00
|
|
|
disconnect(KIconLoader::global(), &KIconLoader::iconChanged, this, &IconItem::iconLoaderIconChanged);
|
|
|
|
|
2017-12-02 11:39:43 +01:00
|
|
|
const bool oldValid = isValid();
|
|
|
|
|
2012-11-26 20:49:16 +01:00
|
|
|
m_source = source;
|
2016-03-04 23:44:57 +01:00
|
|
|
QString sourceString = source.toString();
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2016-01-19 10:14:49 +01:00
|
|
|
// If the QIcon was created with QIcon::fromTheme(), try to load it as svg
|
2016-03-04 23:44:57 +01:00
|
|
|
if (source.canConvert<QIcon>() && !source.value<QIcon>().name().isEmpty()) {
|
|
|
|
sourceString = source.value<QIcon>().name();
|
2016-01-19 10:14:49 +01:00
|
|
|
}
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2016-03-04 23:44:57 +01:00
|
|
|
if (!sourceString.isEmpty()) {
|
2018-01-15 10:22:18 +01:00
|
|
|
// If a file:// URL or a absolute path is passed, take the image pointed by that from disk
|
|
|
|
QString localFile;
|
2017-05-29 17:18:42 +02:00
|
|
|
if (sourceString.startsWith(QLatin1String("file:"))) {
|
2018-01-15 10:22:18 +01:00
|
|
|
localFile = QUrl(sourceString).toLocalFile();
|
|
|
|
} else if (sourceString.startsWith(QLatin1Char('/'))) {
|
|
|
|
localFile = sourceString;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!localFile.isEmpty()) {
|
2018-09-19 15:48:27 +02:00
|
|
|
if (sourceString.endsWith(QLatin1String(".svg")) ||
|
|
|
|
sourceString.endsWith(QLatin1String(".svgz"))) {
|
|
|
|
m_icon = QIcon(localFile);
|
|
|
|
m_imageIcon = QImage();
|
|
|
|
} else {
|
2018-11-08 16:23:20 +01:00
|
|
|
m_icon = QIcon();
|
|
|
|
m_imageIcon = QImage(localFile);
|
2018-09-19 15:48:27 +02:00
|
|
|
}
|
2016-03-04 23:44:57 +01:00
|
|
|
m_svgIconName.clear();
|
2012-11-26 20:49:16 +01:00
|
|
|
delete m_svgIcon;
|
2018-04-13 09:05:17 +02:00
|
|
|
m_svgIcon = nullptr;
|
2014-11-26 15:13:33 +01:00
|
|
|
} else {
|
|
|
|
if (!m_svgIcon) {
|
|
|
|
m_svgIcon = new Plasma::Svg(this);
|
|
|
|
m_svgIcon->setColorGroup(m_colorGroup);
|
2016-06-01 14:47:56 +02:00
|
|
|
m_svgIcon->setStatus(m_status);
|
2015-03-10 18:02:15 +01:00
|
|
|
m_svgIcon->setDevicePixelRatio((window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()));
|
2016-02-29 22:28:58 +01:00
|
|
|
connect(m_svgIcon, &Plasma::Svg::repaintNeeded, this, &IconItem::schedulePixmapUpdate);
|
2014-11-26 15:13:33 +01:00
|
|
|
}
|
|
|
|
|
2016-01-20 11:28:56 +01:00
|
|
|
if (m_usesPlasmaTheme) {
|
|
|
|
//try as a svg icon from plasma theme
|
2017-12-02 15:12:40 +01:00
|
|
|
m_svgIcon->setImagePath(QLatin1String("icons/") + sourceString.section(QLatin1Char('-'), 0, 0));
|
2016-01-20 11:28:56 +01:00
|
|
|
m_svgIcon->setContainsMultipleImages(true);
|
|
|
|
}
|
2014-11-26 15:13:33 +01:00
|
|
|
|
|
|
|
//success?
|
2017-08-30 16:39:53 +02:00
|
|
|
if (m_usesPlasmaTheme && m_svgIcon->isValid() && m_svgIcon->hasElement(sourceString)) {
|
2014-11-26 15:13:33 +01:00
|
|
|
m_icon = QIcon();
|
2019-03-11 13:27:37 +01:00
|
|
|
m_imageIcon = QImage();
|
2016-03-04 23:44:57 +01:00
|
|
|
m_svgIconName = sourceString;
|
2015-10-20 11:44:52 +02:00
|
|
|
//ok, svg not available from the plasma theme
|
2014-11-26 15:13:33 +01:00
|
|
|
} else {
|
2015-10-20 11:44:52 +02:00
|
|
|
//try to load from iconloader an svg with Plasma::Svg
|
2015-11-25 18:17:57 +01:00
|
|
|
const auto *iconTheme = KIconLoader::global()->theme();
|
|
|
|
QString iconPath;
|
|
|
|
if (iconTheme) {
|
2016-02-27 10:40:54 -08:00
|
|
|
iconPath = iconTheme->iconPath(sourceString + QLatin1String(".svg"), qMin(width(), height()), KIconLoader::MatchBest);
|
2015-11-25 18:17:57 +01:00
|
|
|
if (iconPath.isEmpty()) {
|
2016-02-27 10:40:54 -08:00
|
|
|
iconPath = iconTheme->iconPath(sourceString + QLatin1String(".svgz"), qMin(width(), height()), KIconLoader::MatchBest);
|
2015-11-25 18:17:57 +01:00
|
|
|
}
|
|
|
|
} else {
|
2016-10-19 03:16:16 +09:00
|
|
|
qWarning() << "KIconLoader has no theme set";
|
2015-10-20 11:44:52 +02:00
|
|
|
}
|
|
|
|
|
2016-03-04 23:44:57 +01:00
|
|
|
if (!iconPath.isEmpty()) {
|
2015-10-20 11:44:52 +02:00
|
|
|
m_svgIcon->setImagePath(iconPath);
|
2016-03-04 23:44:57 +01:00
|
|
|
m_svgIconName = sourceString;
|
2015-10-20 11:44:52 +02:00
|
|
|
//fail, use QIcon
|
|
|
|
} else {
|
2016-08-02 22:10:45 +01:00
|
|
|
//if we started with a QIcon use that.
|
|
|
|
m_icon = source.value<QIcon>();
|
2016-02-16 17:59:32 +01:00
|
|
|
if (m_icon.isNull()) {
|
2016-08-02 22:10:45 +01:00
|
|
|
m_icon = QIcon::fromTheme(sourceString);
|
2016-02-16 17:59:32 +01:00
|
|
|
}
|
2018-08-23 11:31:15 +02:00
|
|
|
|
|
|
|
//since QIcon is rendered by KIconLoader, watch for when its configuration changes now and reload as needed.
|
|
|
|
connect(KIconLoader::global(), &KIconLoader::iconChanged, this, &IconItem::iconLoaderIconChanged);
|
|
|
|
|
2016-03-04 23:44:57 +01:00
|
|
|
m_svgIconName.clear();
|
2015-10-20 11:44:52 +02:00
|
|
|
delete m_svgIcon;
|
2018-04-13 09:05:17 +02:00
|
|
|
m_svgIcon = nullptr;
|
2015-10-20 11:44:52 +02:00
|
|
|
m_imageIcon = QImage();
|
|
|
|
}
|
2014-11-26 15:13:33 +01:00
|
|
|
}
|
2012-11-26 20:49:16 +01:00
|
|
|
}
|
|
|
|
|
2016-01-19 10:14:49 +01:00
|
|
|
} else if (source.canConvert<QIcon>()) {
|
|
|
|
m_icon = source.value<QIcon>();
|
|
|
|
m_imageIcon = QImage();
|
2016-03-04 23:44:57 +01:00
|
|
|
m_svgIconName.clear();
|
2016-01-19 10:14:49 +01:00
|
|
|
delete m_svgIcon;
|
2018-04-13 09:05:17 +02:00
|
|
|
m_svgIcon = nullptr;
|
2012-11-26 20:49:16 +01:00
|
|
|
} else if (source.canConvert<QImage>()) {
|
|
|
|
m_icon = QIcon();
|
|
|
|
m_imageIcon = source.value<QImage>();
|
2016-03-04 23:44:57 +01:00
|
|
|
m_svgIconName.clear();
|
2012-11-26 20:49:16 +01:00
|
|
|
delete m_svgIcon;
|
2018-04-13 09:05:17 +02:00
|
|
|
m_svgIcon = nullptr;
|
2012-11-26 20:49:16 +01:00
|
|
|
} else {
|
|
|
|
m_icon = QIcon();
|
|
|
|
m_imageIcon = QImage();
|
2016-03-04 23:44:57 +01:00
|
|
|
m_svgIconName.clear();
|
2012-11-26 20:49:16 +01:00
|
|
|
delete m_svgIcon;
|
2018-04-13 09:05:17 +02:00
|
|
|
m_svgIcon = nullptr;
|
2012-11-26 20:49:16 +01:00
|
|
|
}
|
|
|
|
|
2013-02-14 04:33:26 +01:00
|
|
|
if (width() > 0 && height() > 0) {
|
2015-12-22 18:36:23 +01:00
|
|
|
schedulePixmapUpdate();
|
2013-02-14 04:33:26 +01:00
|
|
|
}
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2017-03-24 06:19:15 +09:00
|
|
|
updateImplicitSize();
|
|
|
|
|
2012-11-26 20:49:16 +01:00
|
|
|
emit sourceChanged();
|
2017-12-02 11:39:43 +01:00
|
|
|
|
|
|
|
if (isValid() != oldValid) {
|
|
|
|
emit validChanged();
|
|
|
|
}
|
2012-11-26 20:49:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariant IconItem::source() const
|
|
|
|
{
|
|
|
|
return m_source;
|
|
|
|
}
|
|
|
|
|
2014-06-18 19:22:02 +02:00
|
|
|
void IconItem::setColorGroup(Plasma::Theme::ColorGroup group)
|
2014-06-09 19:35:58 +02:00
|
|
|
{
|
2014-06-13 15:40:16 +02:00
|
|
|
if (m_colorGroup == group) {
|
2014-06-09 19:35:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-13 15:40:16 +02:00
|
|
|
m_colorGroup = group;
|
2014-06-09 19:35:58 +02:00
|
|
|
|
|
|
|
if (m_svgIcon) {
|
|
|
|
m_svgIcon->setColorGroup(group);
|
|
|
|
}
|
|
|
|
|
2014-06-13 15:40:16 +02:00
|
|
|
emit colorGroupChanged();
|
2014-06-09 19:35:58 +02:00
|
|
|
}
|
|
|
|
|
2014-06-18 19:22:02 +02:00
|
|
|
Plasma::Theme::ColorGroup IconItem::colorGroup() const
|
2014-06-09 19:35:58 +02:00
|
|
|
{
|
2014-06-13 15:40:16 +02:00
|
|
|
return m_colorGroup;
|
2014-06-09 19:35:58 +02:00
|
|
|
}
|
|
|
|
|
2016-08-02 21:43:30 +05:30
|
|
|
|
|
|
|
void IconItem::setOverlays(const QStringList &overlays)
|
|
|
|
{
|
|
|
|
if (overlays == m_overlays) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_overlays = overlays;
|
2017-12-02 18:11:24 +01:00
|
|
|
schedulePixmapUpdate();
|
2016-08-02 21:43:30 +05:30
|
|
|
emit overlaysChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList IconItem::overlays() const
|
|
|
|
{
|
|
|
|
return m_overlays;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-26 20:49:16 +01:00
|
|
|
bool IconItem::isActive() const
|
|
|
|
{
|
|
|
|
return m_active;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IconItem::setActive(bool active)
|
|
|
|
{
|
|
|
|
if (m_active == active) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_active = active;
|
2016-05-31 11:10:47 +02:00
|
|
|
|
2014-12-15 20:21:06 +01:00
|
|
|
if (isComponentComplete()) {
|
2016-03-11 14:07:44 +01:00
|
|
|
m_allowNextAnimation = true;
|
2015-12-22 18:36:23 +01:00
|
|
|
schedulePixmapUpdate();
|
2014-12-15 20:21:06 +01:00
|
|
|
}
|
2012-11-26 20:49:16 +01:00
|
|
|
emit activeChanged();
|
|
|
|
}
|
|
|
|
|
2016-01-06 20:21:15 +01:00
|
|
|
bool IconItem::isAnimated() const
|
|
|
|
{
|
|
|
|
return m_animated;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IconItem::setAnimated(bool animated)
|
|
|
|
{
|
|
|
|
if (m_animated == animated) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_animated = animated;
|
|
|
|
emit animatedChanged();
|
|
|
|
}
|
|
|
|
|
2016-01-20 11:28:56 +01:00
|
|
|
bool IconItem::usesPlasmaTheme() const
|
|
|
|
{
|
|
|
|
return m_usesPlasmaTheme;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IconItem::setUsesPlasmaTheme(bool usesPlasmaTheme)
|
|
|
|
{
|
|
|
|
if (m_usesPlasmaTheme == usesPlasmaTheme) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_usesPlasmaTheme = usesPlasmaTheme;
|
|
|
|
|
|
|
|
// Reload icon with new settings
|
2017-05-05 20:18:19 +02:00
|
|
|
const QVariant src = m_source;
|
|
|
|
m_source.clear();
|
|
|
|
setSource(src);
|
2016-01-20 11:28:56 +01:00
|
|
|
|
2017-05-05 20:18:19 +02:00
|
|
|
update();
|
2016-01-20 11:28:56 +01:00
|
|
|
emit usesPlasmaThemeChanged();
|
|
|
|
}
|
|
|
|
|
2017-02-26 11:27:58 +01:00
|
|
|
bool IconItem::roundToIconSize() const
|
|
|
|
{
|
|
|
|
return m_roundToIconSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IconItem::setRoundToIconSize(bool roundToIconSize)
|
|
|
|
{
|
|
|
|
if (m_roundToIconSize == roundToIconSize) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QSize oldPaintedSize = paintedSize();
|
|
|
|
|
|
|
|
m_roundToIconSize = roundToIconSize;
|
|
|
|
emit roundToIconSizeChanged();
|
|
|
|
|
|
|
|
if (oldPaintedSize != paintedSize()) {
|
|
|
|
emit paintedSizeChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
schedulePixmapUpdate();
|
|
|
|
}
|
|
|
|
|
2012-11-26 20:49:16 +01:00
|
|
|
bool IconItem::isValid() const
|
|
|
|
{
|
2016-03-04 00:20:46 +00:00
|
|
|
return !m_icon.isNull() || m_svgIcon || !m_imageIcon.isNull();
|
2012-11-26 20:49:16 +01:00
|
|
|
}
|
|
|
|
|
2016-01-04 18:17:33 +01:00
|
|
|
int IconItem::paintedWidth() const
|
|
|
|
{
|
2017-01-05 15:15:14 +01:00
|
|
|
return paintedSize(boundingRect().size()).width();
|
2016-01-04 18:17:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int IconItem::paintedHeight() const
|
|
|
|
{
|
2017-01-05 15:15:14 +01:00
|
|
|
return paintedSize(boundingRect().size()).height();
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize IconItem::paintedSize(const QSizeF &containerSize) const
|
|
|
|
{
|
|
|
|
const QSize &actualContainerSize = (containerSize.isValid() ? containerSize : boundingRect().size()).toSize();
|
|
|
|
|
|
|
|
const QSize paintedSize = m_iconPixmap.size().scaled(actualContainerSize, Qt::KeepAspectRatio);
|
|
|
|
|
|
|
|
const int width = paintedSize.width();
|
|
|
|
const int height = paintedSize.height();
|
|
|
|
|
|
|
|
if (width == height) {
|
2017-02-26 11:27:58 +01:00
|
|
|
if (m_roundToIconSize) {
|
|
|
|
return QSize(Units::roundToIconSize(width), Units::roundToIconSize(height));
|
|
|
|
} else {
|
|
|
|
return QSize(width, height);
|
|
|
|
}
|
2017-01-05 15:15:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// if we don't have a square image, we still want it to be rounded to icon size
|
|
|
|
// but we cannot just blindly round both as we might erroneously change a 50x45 image to be 48x32
|
|
|
|
// instead, round the bigger of the two and then downscale the smaller with the ratio
|
|
|
|
if (width > height) {
|
2017-02-26 11:27:58 +01:00
|
|
|
const int roundedWidth = m_roundToIconSize ? Units::roundToIconSize(width) : width;
|
2017-01-05 15:15:14 +01:00
|
|
|
return QSize(roundedWidth, qRound(height * (roundedWidth / static_cast<qreal>(width))));
|
|
|
|
} else {
|
2017-02-26 11:27:58 +01:00
|
|
|
const int roundedHeight = m_roundToIconSize ? Units::roundToIconSize(height) : height;
|
2017-01-05 15:15:14 +01:00
|
|
|
return QSize(qRound(width * (roundedHeight / static_cast<qreal>(height))), roundedHeight);
|
|
|
|
}
|
2016-01-04 18:17:33 +01:00
|
|
|
}
|
|
|
|
|
2016-06-01 14:47:56 +02:00
|
|
|
void IconItem::setStatus(Plasma::Svg::Status status)
|
2016-05-31 11:10:47 +02:00
|
|
|
{
|
2016-06-01 14:47:56 +02:00
|
|
|
if (m_status == status) {
|
2016-05-31 11:10:47 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-01 14:47:56 +02:00
|
|
|
m_status = status;
|
2016-05-31 11:10:47 +02:00
|
|
|
if (m_svgIcon) {
|
2016-06-01 14:47:56 +02:00
|
|
|
m_svgIcon->setStatus(status);
|
2016-05-31 11:10:47 +02:00
|
|
|
}
|
2016-06-01 14:47:56 +02:00
|
|
|
emit statusChanged();
|
2016-05-31 11:10:47 +02:00
|
|
|
}
|
|
|
|
|
2016-06-01 14:47:56 +02:00
|
|
|
Plasma::Svg::Status IconItem::status() const
|
2016-05-31 11:10:47 +02:00
|
|
|
{
|
2016-06-01 14:47:56 +02:00
|
|
|
return m_status;
|
2016-05-31 11:10:47 +02:00
|
|
|
}
|
|
|
|
|
2017-04-03 15:42:29 +02:00
|
|
|
void IconItem::setImplicitHeight2(int height)
|
|
|
|
{
|
|
|
|
m_implicitHeightSetByUser = true;
|
|
|
|
setImplicitHeight(height);
|
|
|
|
emit implicitHeightChanged2();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IconItem::setImplicitWidth2(int width)
|
|
|
|
{
|
|
|
|
m_implicitWidthSetByUser = true;
|
|
|
|
setImplicitWidth(width);
|
|
|
|
emit implicitWidthChanged2();
|
|
|
|
}
|
|
|
|
|
2015-12-22 18:36:23 +01:00
|
|
|
void IconItem::updatePolish()
|
|
|
|
{
|
|
|
|
QQuickItem::updatePolish();
|
|
|
|
loadPixmap();
|
|
|
|
}
|
|
|
|
|
2014-05-12 18:47:49 +02:00
|
|
|
QSGNode* IconItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
|
2012-11-26 20:49:16 +01:00
|
|
|
{
|
2014-05-12 18:47:49 +02:00
|
|
|
Q_UNUSED(updatePaintNodeData)
|
|
|
|
|
2018-04-13 09:05:17 +02:00
|
|
|
if (m_iconPixmap.isNull() || width() == 0.0 || height() == 0.0) {
|
2014-05-12 18:47:49 +02:00
|
|
|
delete oldNode;
|
2017-01-16 18:17:34 +01:00
|
|
|
return nullptr;
|
2012-11-26 20:49:16 +01:00
|
|
|
}
|
2013-02-02 04:43:20 +01:00
|
|
|
|
2014-05-12 18:47:49 +02:00
|
|
|
if (m_animation->state() == QAbstractAnimation::Running) {
|
2014-05-22 07:53:55 +02:00
|
|
|
FadingNode *animatingNode = dynamic_cast<FadingNode*>(oldNode);
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2014-05-12 18:47:49 +02:00
|
|
|
if (!animatingNode || m_textureChanged) {
|
|
|
|
delete oldNode;
|
2014-02-17 15:39:01 +01:00
|
|
|
|
2018-03-06 11:09:55 +00:00
|
|
|
QSGTexture *source = window()->createTextureFromImage(m_oldIconPixmap.toImage(), QQuickWindow::TextureCanUseAtlas);
|
SvgItem, IconItem: drop "smooth" property override, update node on change
Summary:
QQuickItem already has a "smooth" property, which was shadowed by the
custom ones with the same name. As the property was not part of public
symbols, but instead is dynamically looked up without the class name part
of the property, we just remove the custom versions and instead switch
all custom code to use the inherited property.
While doing that the code is also fixed to properly update the
textureNodes to the current value of the "smooth" property.
As well as not set the filtering only on the texture, when it is passed
to a texturenode which will set its own filtering state to the texture
right before the bind call and thus wipe any previous direct setting
of the filter mode on the texture.
This also changed the default to smooth=true for SvgItem, though
effectively smooth was always true, as the texturenode was hardcoded
to get a QSGTexture::Linear filtering (which, as said above, is forced
onto its texture, no matter what was otherwise set before).
Reviewers: #plasma, davidedmundson, mart
Reviewed By: #plasma, davidedmundson
Subscribers: kde-frameworks-devel
Tags: #frameworks
Differential Revision: https://phabricator.kde.org/D20510
2019-04-13 17:23:20 +02:00
|
|
|
source->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
|
2018-03-06 11:09:55 +00:00
|
|
|
QSGTexture *target = window()->createTextureFromImage(m_iconPixmap.toImage(), QQuickWindow::TextureCanUseAtlas);
|
SvgItem, IconItem: drop "smooth" property override, update node on change
Summary:
QQuickItem already has a "smooth" property, which was shadowed by the
custom ones with the same name. As the property was not part of public
symbols, but instead is dynamically looked up without the class name part
of the property, we just remove the custom versions and instead switch
all custom code to use the inherited property.
While doing that the code is also fixed to properly update the
textureNodes to the current value of the "smooth" property.
As well as not set the filtering only on the texture, when it is passed
to a texturenode which will set its own filtering state to the texture
right before the bind call and thus wipe any previous direct setting
of the filter mode on the texture.
This also changed the default to smooth=true for SvgItem, though
effectively smooth was always true, as the texturenode was hardcoded
to get a QSGTexture::Linear filtering (which, as said above, is forced
onto its texture, no matter what was otherwise set before).
Reviewers: #plasma, davidedmundson, mart
Reviewed By: #plasma, davidedmundson
Subscribers: kde-frameworks-devel
Tags: #frameworks
Differential Revision: https://phabricator.kde.org/D20510
2019-04-13 17:23:20 +02:00
|
|
|
target->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
|
2014-05-12 18:47:49 +02:00
|
|
|
animatingNode = new FadingNode(source, target);
|
|
|
|
m_sizeChanged = true;
|
|
|
|
m_textureChanged = false;
|
|
|
|
}
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2014-05-12 18:47:49 +02:00
|
|
|
animatingNode->setProgress(m_animValue);
|
|
|
|
|
|
|
|
if (m_sizeChanged) {
|
2017-01-05 15:15:14 +01:00
|
|
|
const QSize newSize = paintedSize();
|
|
|
|
const QRect destRect(QPointF(boundingRect().center() - QPointF(newSize.width(), newSize.height()) / 2).toPoint(), newSize);
|
2014-05-12 18:47:49 +02:00
|
|
|
animatingNode->setRect(destRect);
|
|
|
|
m_sizeChanged = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return animatingNode;
|
2012-11-26 20:49:16 +01:00
|
|
|
} else {
|
2014-10-15 13:22:27 +02:00
|
|
|
ManagedTextureNode *textureNode = dynamic_cast<ManagedTextureNode*>(oldNode);
|
2014-05-12 18:47:49 +02:00
|
|
|
|
|
|
|
if (!textureNode || m_textureChanged) {
|
|
|
|
delete oldNode;
|
2014-10-15 13:22:27 +02:00
|
|
|
textureNode = new ManagedTextureNode;
|
2017-01-30 10:24:33 +00:00
|
|
|
textureNode->setTexture(QSharedPointer<QSGTexture>(window()->createTextureFromImage(m_iconPixmap.toImage(), QQuickWindow::TextureCanUseAtlas)));
|
2014-05-12 18:47:49 +02:00
|
|
|
m_sizeChanged = true;
|
|
|
|
m_textureChanged = false;
|
|
|
|
}
|
SvgItem, IconItem: drop "smooth" property override, update node on change
Summary:
QQuickItem already has a "smooth" property, which was shadowed by the
custom ones with the same name. As the property was not part of public
symbols, but instead is dynamically looked up without the class name part
of the property, we just remove the custom versions and instead switch
all custom code to use the inherited property.
While doing that the code is also fixed to properly update the
textureNodes to the current value of the "smooth" property.
As well as not set the filtering only on the texture, when it is passed
to a texturenode which will set its own filtering state to the texture
right before the bind call and thus wipe any previous direct setting
of the filter mode on the texture.
This also changed the default to smooth=true for SvgItem, though
effectively smooth was always true, as the texturenode was hardcoded
to get a QSGTexture::Linear filtering (which, as said above, is forced
onto its texture, no matter what was otherwise set before).
Reviewers: #plasma, davidedmundson, mart
Reviewed By: #plasma, davidedmundson
Subscribers: kde-frameworks-devel
Tags: #frameworks
Differential Revision: https://phabricator.kde.org/D20510
2019-04-13 17:23:20 +02:00
|
|
|
textureNode->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
|
2012-11-26 20:49:16 +01:00
|
|
|
|
2014-05-12 18:47:49 +02:00
|
|
|
if (m_sizeChanged) {
|
2017-01-05 15:15:14 +01:00
|
|
|
const QSize newSize = paintedSize();
|
|
|
|
const QRect destRect(QPointF(boundingRect().center() - QPointF(newSize.width(), newSize.height()) / 2).toPoint(), newSize);
|
2014-05-12 18:47:49 +02:00
|
|
|
textureNode->setRect(destRect);
|
|
|
|
m_sizeChanged = false;
|
|
|
|
}
|
|
|
|
return textureNode;
|
2012-11-26 20:49:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IconItem::valueChanged(const QVariant &value)
|
|
|
|
{
|
|
|
|
m_animValue = value.toReal();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
2017-12-02 15:52:22 +01:00
|
|
|
void IconItem::onEnabledChanged()
|
2016-03-11 14:07:44 +01:00
|
|
|
{
|
|
|
|
m_allowNextAnimation = true;
|
|
|
|
schedulePixmapUpdate();
|
|
|
|
}
|
|
|
|
|
2014-05-12 18:47:49 +02:00
|
|
|
void IconItem::animationFinished()
|
|
|
|
{
|
|
|
|
m_oldIconPixmap = QPixmap();
|
|
|
|
m_textureChanged = true;
|
2014-05-22 07:53:55 +02:00
|
|
|
update();
|
2014-05-12 18:47:49 +02:00
|
|
|
}
|
|
|
|
|
2018-08-23 11:31:15 +02:00
|
|
|
void IconItem::iconLoaderIconChanged(int group)
|
|
|
|
{
|
|
|
|
Q_UNUSED(group);
|
|
|
|
schedulePixmapUpdate();
|
|
|
|
}
|
|
|
|
|
2019-02-28 15:58:26 +01:00
|
|
|
void IconItem::windowVisibleChanged(bool visible)
|
|
|
|
{
|
|
|
|
if (visible) {
|
|
|
|
m_blockNextAnimation = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-22 18:36:23 +01:00
|
|
|
void IconItem::schedulePixmapUpdate()
|
|
|
|
{
|
|
|
|
polish();
|
|
|
|
}
|
|
|
|
|
2014-02-17 15:39:01 +01:00
|
|
|
void IconItem::loadPixmap()
|
|
|
|
{
|
2014-12-15 20:21:06 +01:00
|
|
|
if (!isComponentComplete()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-26 11:27:58 +01:00
|
|
|
int size = qMin(qRound(width()), qRound(height()));
|
|
|
|
if (m_roundToIconSize) {
|
|
|
|
size = Units::roundToIconSize(size);
|
|
|
|
}
|
2014-02-17 15:39:01 +01:00
|
|
|
|
2012-11-26 20:49:16 +01:00
|
|
|
//final pixmap to paint
|
|
|
|
QPixmap result;
|
2014-04-26 01:45:47 +02:00
|
|
|
if (size <= 0) {
|
2015-02-12 16:35:28 +01:00
|
|
|
m_iconPixmap = QPixmap();
|
2013-02-14 04:33:26 +01:00
|
|
|
m_animation->stop();
|
|
|
|
update();
|
2013-02-07 12:11:51 +01:00
|
|
|
return;
|
|
|
|
} else if (m_svgIcon) {
|
2018-02-10 01:25:13 +01:00
|
|
|
m_svgIcon->setDevicePixelRatio(window() ? window()->devicePixelRatio() : qApp->devicePixelRatio());
|
2012-11-26 20:49:16 +01:00
|
|
|
m_svgIcon->resize(size, size);
|
2017-05-29 17:18:42 +02:00
|
|
|
if (!m_svgIconName.isEmpty() && m_svgIcon->hasElement(m_svgIconName)) {
|
2016-03-04 23:44:57 +01:00
|
|
|
result = m_svgIcon->pixmap(m_svgIconName);
|
|
|
|
} else if (!m_svgIconName.isEmpty()) {
|
2015-11-25 18:17:57 +01:00
|
|
|
const auto *iconTheme = KIconLoader::global()->theme();
|
|
|
|
if (iconTheme) {
|
2017-05-29 17:18:42 +02:00
|
|
|
QString iconPath = iconTheme->iconPath(m_svgIconName + QLatin1String(".svg"), size, KIconLoader::MatchBest);
|
2015-11-25 18:17:57 +01:00
|
|
|
if (iconPath.isEmpty()) {
|
2017-05-29 17:18:42 +02:00
|
|
|
iconPath = iconTheme->iconPath(m_svgIconName + QLatin1String(".svgz"), size, KIconLoader::MatchBest);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!iconPath.isEmpty()) {
|
|
|
|
m_svgIcon->setImagePath(iconPath);
|
2015-11-25 18:17:57 +01:00
|
|
|
}
|
|
|
|
} else {
|
2016-10-19 03:16:16 +09:00
|
|
|
qWarning() << "KIconLoader has no theme set";
|
2015-10-20 11:44:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
result = m_svgIcon->pixmap();
|
|
|
|
}
|
2014-05-06 16:32:55 +02:00
|
|
|
} else if (!m_icon.isNull()) {
|
2015-03-10 18:02:15 +01:00
|
|
|
result = m_icon.pixmap(QSize(size, size) * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()));
|
2012-11-26 20:49:16 +01:00
|
|
|
} else if (!m_imageIcon.isNull()) {
|
|
|
|
result = QPixmap::fromImage(m_imageIcon);
|
|
|
|
} else {
|
2014-05-12 18:47:49 +02:00
|
|
|
m_iconPixmap = QPixmap();
|
2013-02-14 04:33:26 +01:00
|
|
|
m_animation->stop();
|
|
|
|
update();
|
2012-11-26 20:49:16 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-02 21:43:30 +05:30
|
|
|
// Strangely KFileItem::overlays() returns empty string-values, so
|
|
|
|
// we need to check first whether an overlay must be drawn at all.
|
|
|
|
// It is more efficient to do it here, as KIconLoader::drawOverlays()
|
|
|
|
// assumes that an overlay will be drawn and has some additional
|
|
|
|
// setup time.
|
|
|
|
foreach (const QString& overlay, m_overlays) {
|
|
|
|
if (!overlay.isEmpty()) {
|
|
|
|
// There is at least one overlay, draw all overlays above m_pixmap
|
|
|
|
// and cancel the check
|
|
|
|
KIconLoader::global()->drawOverlays(m_overlays, result, KIconLoader::Desktop);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-26 20:49:16 +01:00
|
|
|
if (!isEnabled()) {
|
|
|
|
result = KIconLoader::global()->iconEffect()->apply(result, KIconLoader::Desktop, KIconLoader::DisabledState);
|
|
|
|
} else if (m_active) {
|
|
|
|
result = KIconLoader::global()->iconEffect()->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
|
|
|
|
}
|
|
|
|
|
2017-01-05 15:15:14 +01:00
|
|
|
const QSize oldPaintedSize = paintedSize();
|
|
|
|
|
2014-05-12 18:47:49 +02:00
|
|
|
m_oldIconPixmap = m_iconPixmap;
|
|
|
|
m_iconPixmap = result;
|
|
|
|
m_textureChanged = true;
|
2014-02-17 15:39:01 +01:00
|
|
|
|
2017-01-05 15:15:14 +01:00
|
|
|
if (oldPaintedSize != paintedSize()) {
|
|
|
|
emit paintedSizeChanged();
|
|
|
|
}
|
|
|
|
|
2014-05-12 18:47:49 +02:00
|
|
|
//don't animate initial setting
|
2017-09-27 15:50:44 +01:00
|
|
|
bool animated = (m_animated || m_allowNextAnimation) && !m_oldIconPixmap.isNull() && !m_sizeChanged && !m_blockNextAnimation;
|
|
|
|
|
|
|
|
if (QQuickWindow::sceneGraphBackend() == QLatin1String("software")) {
|
|
|
|
animated = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (animated) {
|
2016-02-27 21:24:45 +01:00
|
|
|
m_animValue = 0.0;
|
2012-11-26 20:49:16 +01:00
|
|
|
m_animation->setStartValue((qreal)0);
|
|
|
|
m_animation->setEndValue((qreal)1);
|
|
|
|
m_animation->start();
|
2016-03-11 14:07:44 +01:00
|
|
|
m_allowNextAnimation = false;
|
2014-05-12 18:47:49 +02:00
|
|
|
} else {
|
|
|
|
m_animValue = 1.0;
|
2014-12-11 14:48:42 -05:00
|
|
|
m_animation->stop();
|
2016-07-12 10:02:47 +02:00
|
|
|
m_blockNextAnimation = false;
|
2012-11-26 20:49:16 +01:00
|
|
|
}
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
2016-03-10 13:01:29 +01:00
|
|
|
void IconItem::itemChange(ItemChange change, const ItemChangeData &value)
|
|
|
|
{
|
|
|
|
if (change == ItemVisibleHasChanged && value.boolValue) {
|
2016-07-12 10:02:47 +02:00
|
|
|
m_blockNextAnimation = true;
|
2018-08-17 15:46:29 +02:00
|
|
|
} else if (change == ItemEnabledHasChanged) {
|
|
|
|
onEnabledChanged();
|
2017-12-02 18:12:31 +01:00
|
|
|
} else if (change == ItemSceneChange && value.window) {
|
2019-02-28 15:58:26 +01:00
|
|
|
if (m_window) {
|
|
|
|
disconnect(m_window.data(), &QWindow::visibleChanged, this, &IconItem::windowVisibleChanged);
|
|
|
|
}
|
|
|
|
m_window = value.window;
|
|
|
|
if (m_window) {
|
|
|
|
connect(m_window.data(), &QWindow::visibleChanged, this, &IconItem::windowVisibleChanged);
|
|
|
|
}
|
2017-12-02 18:12:31 +01:00
|
|
|
schedulePixmapUpdate();
|
2019-02-28 15:58:26 +01:00
|
|
|
|
2016-03-10 13:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QQuickItem::itemChange(change, value);
|
|
|
|
}
|
|
|
|
|
2012-11-26 20:49:16 +01:00
|
|
|
void IconItem::geometryChanged(const QRectF &newGeometry,
|
|
|
|
const QRectF &oldGeometry)
|
|
|
|
{
|
|
|
|
if (newGeometry.size() != oldGeometry.size()) {
|
2014-05-21 16:54:05 +02:00
|
|
|
m_sizeChanged = true;
|
2013-02-14 04:33:26 +01:00
|
|
|
if (newGeometry.width() > 0 && newGeometry.height() > 0) {
|
2015-12-22 18:36:23 +01:00
|
|
|
schedulePixmapUpdate();
|
|
|
|
} else {
|
|
|
|
update();
|
2013-02-14 04:33:26 +01:00
|
|
|
}
|
2016-01-04 18:17:33 +01:00
|
|
|
|
2017-01-05 15:15:14 +01:00
|
|
|
if (paintedSize(oldGeometry.size()) != paintedSize(newGeometry.size())) {
|
2016-01-04 18:17:33 +01:00
|
|
|
emit paintedSizeChanged();
|
|
|
|
}
|
2013-02-14 04:33:26 +01:00
|
|
|
}
|
2014-02-17 14:32:35 +01:00
|
|
|
|
|
|
|
QQuickItem::geometryChanged(newGeometry, oldGeometry);
|
2012-11-26 20:49:16 +01:00
|
|
|
}
|
|
|
|
|
2014-12-15 20:21:06 +01:00
|
|
|
void IconItem::componentComplete()
|
|
|
|
{
|
|
|
|
QQuickItem::componentComplete();
|
2015-12-22 18:36:23 +01:00
|
|
|
schedulePixmapUpdate();
|
2014-12-15 20:21:06 +01:00
|
|
|
}
|