Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Move QgsAnimatedIcon to a generic implementation (#4272)
  • Loading branch information
m-kuhn committed Mar 19, 2017
1 parent 616b4dd commit 6f430a6
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 163 deletions.
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -20,6 +20,7 @@
%Include qgsactionscope.sip
%Include qgsactionscoperegistry.sip
%Include qgsaggregatecalculator.sip
%Include qgsanimatedicon.sip
%Include qgsattributetableconfig.sip
%Include qgsattributeeditorelement.sip
%Include qgsbearingutils.sip
Expand Down
21 changes: 21 additions & 0 deletions python/core/qgsanimatedicon.sip
@@ -0,0 +1,21 @@

class QgsAnimatedIcon : QObject
{
%TypeHeaderCode
#include <qgsanimatedicon.h>
%End
public:

QgsAnimatedIcon( const QString &iconPath = QString::null );

QString iconPath() const;
void setIconPath( const QString &iconPath );
QIcon icon() const;
bool connectFrameChanged( const QObject *receiver, const char *method );
bool disconnectFrameChanged( const QObject *receiver, const char *method );

int width() const;
int height() const;
signals:
void frameChanged();
};
34 changes: 3 additions & 31 deletions python/core/qgsdataitem.sip
@@ -1,33 +1,3 @@
/** Animated icon is keeping an animation running if there are listeners connected to frameChanged */
class QgsAnimatedIcon : QObject
{
%TypeHeaderCode
#include <qgsdataitem.h>
%End
public:

/** Constructor
* @param iconPath path to a movie, e.g. animated GIF */
QgsAnimatedIcon( const QString & iconPath = QString::null );

QString iconPath() const;
void setIconPath( const QString & iconPath );
QIcon icon() const;

/** Connect listener to frameChanged() signal */
void connectFrameChanged( const QObject * receiver, const char * method );
/** Disconnect listener from frameChanged() signal */
void disconnectFrameChanged( const QObject * receiver, const char * method );

public slots:
void onFrameChanged();

signals:
/** Emitted when icon changed */
void frameChanged();

};

/** Base class for all items in the model.
* Parent/children hierarchy is not based on QObject. */
class QgsDataItem : QObject
Expand Down Expand Up @@ -236,7 +206,6 @@ class QgsDataItem : QObject

virtual void refresh();

void emitDataChanged();
virtual void childrenCreated();

signals:
Expand All @@ -246,6 +215,9 @@ class QgsDataItem : QObject
void endRemoveItems();
void dataChanged( QgsDataItem * item );
void stateChanged( QgsDataItem * item, QgsDataItem::State oldState );

protected slots:
void updateIcon();
};

QFlags<QgsDataItem::Capability> operator|(QgsDataItem::Capability f1, QFlags<QgsDataItem::Capability> f2);
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -93,6 +93,7 @@ SET(QGIS_CORE_SRCS
qgsactionscoperegistry.cpp
qgsactionmanager.cpp
qgsaggregatecalculator.cpp
qgsanimatedicon.cpp
qgsattributetableconfig.cpp
qgsattributeeditorelement.cpp
qgsbearingutils.cpp
Expand Down Expand Up @@ -482,6 +483,7 @@ ENDIF(NOT MSVC)
SET(QGIS_CORE_MOC_HDRS
qgsapplication.h
qgsactionscoperegistry.h
qgsanimatedicon.h
qgsbrowsermodel.h
qgscontexthelp.h
qgscoordinatereferencesystem.h
Expand Down
78 changes: 78 additions & 0 deletions src/core/qgsanimatedicon.cpp
@@ -0,0 +1,78 @@
/***************************************************************************
qgsanimatedicon.cpp - QgsAnimatedIcon
---------------------
begin : 13.3.2017
copyright : (C) 2017 by Matthias Kuhn
email : matthias@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsanimatedicon.h"

QgsAnimatedIcon::QgsAnimatedIcon( const QString &iconPath, QObject *parent )
: QObject( parent )
, mMovie( new QMovie( this ) )
{
if ( !iconPath.isEmpty() )
{
mMovie->setFileName( iconPath );
}
mMovie->setCacheMode( QMovie::CacheAll );
connect( mMovie, &QMovie::frameChanged, this, &QgsAnimatedIcon::onFrameChanged );
}

QString QgsAnimatedIcon::iconPath() const
{
return mMovie->fileName();
}

void QgsAnimatedIcon::setIconPath( const QString &iconPath )
{
mMovie->setFileName( iconPath );
}

QIcon QgsAnimatedIcon::icon() const
{
return mIcon;
}

bool QgsAnimatedIcon::connectFrameChanged( const QObject *receiver, const char *method )
{
if ( connect( this, SIGNAL( frameChanged() ), receiver, method ) )
{
mMovie->setPaused( false );
return true;
}
else
return false;
}

bool QgsAnimatedIcon::disconnectFrameChanged( const QObject *receiver, const char *method )
{
return disconnect( this, SIGNAL( frameChanged() ), receiver, method );
}

int QgsAnimatedIcon::width() const
{
return mMovie->currentPixmap().width();
}

int QgsAnimatedIcon::height() const
{
return mMovie->currentPixmap().height();
}
void QgsAnimatedIcon::onFrameChanged()
{
if ( !isSignalConnected( QMetaMethod::fromSignal( &QgsAnimatedIcon::frameChanged ) ) )
mMovie->setPaused( true );

mIcon = QIcon( mMovie->currentPixmap() );
emit frameChanged();
}
144 changes: 144 additions & 0 deletions src/core/qgsanimatedicon.h
@@ -0,0 +1,144 @@
/***************************************************************************
qgsanimatedicon.h - QgsAnimatedIcon
---------------------
begin : 13.3.2017
copyright : (C) 2017 by Matthias Kuhn
email : matthias@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSANIMATEDICON_H
#define QGSANIMATEDICON_H

#include <QObject>
#include <QMovie>
#include <QIcon>
#include <QMetaMethod>

#include "qgis_core.h"

/** \ingroup core
* Animated icon is keeping an animation running if there are listeners connected to frameChanged
*/
class CORE_EXPORT QgsAnimatedIcon : public QObject
{
Q_OBJECT
public:

/**
* Create a new animated icon. Optionally, the \a iconPath can already be specified.
*/
QgsAnimatedIcon( const QString &iconPath = QString(), QObject *parent = nullptr );

/**
* Path to a movie, e.g. animated GIF
*/
QString iconPath() const;

/**
* Path to a movie, e.g. animated GIF
*/
void setIconPath( const QString &iconPath );

/**
* Get the icons representation in the current frame.
* This will need to be called repeatedly, whenever a frameChanged()
* signal is emitted.
*/
QIcon icon() const;

/**
* Connect a slot that will be notified repeatedly whenever a frame changes and which should
* request the current icon and trigger UI updates.
*
* Connect to the frame changed signal with this method and not directly. This method
* makes sure the annimation is started.
*
* @note Added in QGIS 3.0
* @note Available in python bindings as
* bool connectFrameChanged( const QObject *receiver, const char *method );.
*/
template <typename Func1>
bool connectFrameChanged( const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, Func1 slot )
{
if ( connect( this, &QgsAnimatedIcon::frameChanged, receiver, slot ) )
{
mMovie->setPaused( false );
return true;
}
else
return false;
}

/**
* Connect a slot that will be notified repeatedly whenever a frame changes and which should
* request the current icon and trigger UI updates.
*
* Connect to the frame changed signal with this method and not directly. This method
* makes sure the annimation is started.
*
* @note Added in QGIS 3.0
*/
bool connectFrameChanged( const QObject *receiver, const char *method );

/**
* Convenience function to disconnect the same style that the frame change connection was established.
*
* @note Added in QGIS 3.0
* @note Available in python bindings as
* bool disconnectFrameChanged( const QObject *receiver, const char *method );.
*/
template <typename Func1>
bool disconnectFrameChanged( const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, Func1 slot )
{
return disconnect( this, &QgsAnimatedIcon::frameChanged, receiver, slot );
}

/**
* Convenience function to disconnect the same style that the frame change connection was established.
*
* @note Added in QGIS 3.0
*/
bool disconnectFrameChanged( const QObject *receiver, const char *method );


/**
* The native width of the icon.
*
* @note Added in QGIS 3.0
*/
int width() const;

/**
* The native height of the icon.
*
* @note Added in QGIS 3.0
*/
int height() const;

signals:

/**
* Emitted when the icon changed. You should use connectFrameChanged instead of connecting
* to this signal directly.
* Connecting to this signal directly will cause the animation not to be started.
*
* @see connectFrameChanged
*/
void frameChanged();

private slots:
void onFrameChanged();

private:
QMovie *mMovie = nullptr;
QIcon mIcon;
};

#endif // QGSANIMATEDICON_H

0 comments on commit 6f430a6

Please sign in to comment.