Importing the effect written for Akademy 2010. It displays the score of the football match Argentina vs Germany and would be able to trigger an animation if the match would still be on. It's a nice example on what you can do with EffectFrames and therefore imported to test directory.

svn path=/trunk/KDE/kdebase/workspace/; revision=1146130
icc-effect-5.14.5
Martin Gräßlin 2010-07-05 09:45:36 +00:00
parent 63050326ac
commit 87117b2325
5 changed files with 391 additions and 1 deletions

View File

@ -1,7 +1,7 @@
# Adds effect plugin with given name. Sources are given after the name
macro(KWIN4_ADD_EFFECT name)
kde4_add_plugin(kwin4_effect_${name} ${ARGN})
target_link_libraries(kwin4_effect_${name} kwineffects ${KDE4_KDEUI_LIBS} ${X11_LIBRARIES} kephal)
target_link_libraries(kwin4_effect_${name} kwineffects ${KDE4_KDEUI_LIBS} ${X11_LIBRARIES} ${QT_QTWEBKIT_LIBRARY} kephal)
install(TARGETS kwin4_effect_${name} DESTINATION ${PLUGIN_INSTALL_DIR})
endmacro(KWIN4_ADD_EFFECT)
@ -25,6 +25,7 @@ SET(kwin4_effect_tests_sources
howto.cpp
test_input.cpp
test_thumbnail.cpp
kicker/kicker.cpp
)
install( FILES
demo_shakymove.desktop
@ -34,6 +35,7 @@ install( FILES
howto.desktop
test_input.desktop
test_thumbnail.desktop
kicker/kicker.desktop
DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
if(OPENGL_FOUND)

View File

@ -0,0 +1,29 @@
#######################################
# Effect
# Source files
set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
kicker/kicker.cpp
)
# .desktop files
install( FILES
kicker/kicker.desktop
DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
#######################################
# Config
# Source files
#set( kwin4_effect_builtins_config_sources ${kwin4_effect_builtins_config_sources}
#cube/cube_config.cpp
#cube/cube_config.ui
#cube/cubeslide_config.cpp
#cube/cubeslide_config.ui
#)
# .desktop files
#install( FILES
# cube/cube_config.desktop
# cube/cubeslide_config.desktop
# DESTINATION ${SERVICES_INSTALL_DIR}/kwin )

View File

@ -0,0 +1,258 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2010 Martin Gräßlin <kde@martin-graesslin.com>
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.
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 General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "kicker.h"
#include <QtCore/QTimer>
#include <QtCore/QUrl>
#include <QtWebKit/QWebElement>
#include <QtWebKit/QWebElementCollection>
#include <QtWebKit/QWebFrame>
#include <QtWebKit/QWebPage>
namespace KWin
{
KWIN_EFFECT( kicker, KickerEffect )
KickerEffect::KickerEffect()
: m_page( new QWebPage( this ) )
, m_timer( new QTimer( this ) )
, m_goalTimer( new QTimer( this ) )
, m_goalActive( false )
, m_ascending( false )
{
connect(m_page, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool)));
connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
connect(m_goalTimer, SIGNAL(timeout()), this, SLOT(goalTimeout()));
reconfigure( ReconfigureAll );
// reload the webpage each half a minute
m_timer->start(30*1000);
// goal animation should end after seven seconds
m_goalTimer->setInterval( 7 * 1000 );
m_goalTimer->setSingleShot( true );
// the animations should have a duration of half a second with an
// ease in out curve
m_timeLine.setCurveShape( TimeLine::EaseInOutCurve );
m_timeLine.setDuration( 500 );
// let's download the webpage immediatelly
timeout();
}
KickerEffect::~KickerEffect()
{
while( !m_frames.isEmpty() )
{
delete m_frames.first();
m_frames.removeFirst();
}
while( !m_goalFrames.isEmpty() )
{
delete m_goalFrames.first();
m_goalFrames.removeFirst();
}
}
void KickerEffect::reconfigure( ReconfigureFlags )
{
}
void KickerEffect::prePaintScreen( ScreenPrePaintData& data, int time )
{
// the goal animation uses a KWin::TimeLine to modify the opacity values
// as long as the goal timer has not timed out m_goalActive is true
// after the timeout an animation might still be running, so we continue
// till progress reaches 0.0 again
if( m_goalActive || m_timeLine.progress() != 0.0 )
{
// the animation might either be ascending (increasing opacity) or
// descending (decreasing opacity). In case of ascending we add time
// to the timeline till progress reaches 1.0. There we switch direction
// to descending. In descending case of course vice versa.
if( m_ascending )
{
m_timeLine.addTime( time );
if( m_timeLine.progress() == 1.0 )
{
m_ascending = false;
}
}
else
{
m_timeLine.removeTime( time );
// it is possible that this is the last animation. Therefore the
// anding with goalActive. If it has been the last animation we
// do not need to keep the goal EffectFrame around any more, so
// we delete them.
if( m_timeLine.progress() == 0.0 && m_goalActive )
{
m_ascending = true;
}
else if( m_timeLine.progress() == 0.0 )
{
// goal animation finshed, let's delete the EffectFrames
while( !m_goalFrames.isEmpty() )
{
delete m_goalFrames.first();
m_goalFrames.removeFirst();
}
m_goalFrames.clear();
}
}
}
effects->prePaintScreen( data, time );
}
void KickerEffect::paintScreen( int mask, QRegion region, ScreenPaintData &data )
{
effects->paintScreen( mask, region, data );
if( m_size.isValid() )
{
// let's paint the score EffectFrame with unmodified opacity. As it
// uses Plasma styled textures it's still translucent, but the text
// is fully opaque.
foreach( EffectFrame* frame, m_frames )
frame->render( region, 1.0 );
}
if( m_goalActive || m_timeLine.progress() != 0.0 )
{
// the goal animation changes the opacity. Therefore we modify the
// opacity by multiplying with the timeline's progress.
// The text should be fully opaque (1.0), while the background should
// be translucent (0.75)
foreach( EffectFrame* frame, m_goalFrames )
frame->render( region, 1.0 * m_timeLine.progress(), 0.75 * m_timeLine.progress() );
// we are animating: need a new frame
effects->addRepaintFull();
}
}
void KickerEffect::slotLoadFinished( bool ok )
{
// if connection failed let's keep the last score
if( !ok )
return;
QWebElement doc = m_page->mainFrame()->documentElement();
// CSS selector for the teams
QWebElementCollection teams = doc.findAll("td.lttabver h1 a");
if( teams.count() != 2 )
return;
QString firstTeam = teams[0].toPlainText();
QString secondTeam = teams[1].toPlainText();
// CSS selector for the current score
QString result = doc.findFirst("td.lttaberg h1").toPlainText();
if( m_score != result )
{
// the score changed, a goal might have been scored
bool activate = true;
// but not if the web page has been loaded for the first time
if( m_score.isNull() )
activate = false;
// not if we entered extra time
if( !m_score.contains("i.V.") && result.contains("i.V.") )
activate = false;
// not if extra time ended
if( !m_score.contains("n.V.") && result.contains("n.V.") )
activate = false;
// not if penality shootout begins
if( !m_score.contains("i.E.") && result.contains("i.E.") )
activate = false;
// not if first or second half starts.
if( m_score.count( '-' ) > result.count( '-' ) )
activate = false;
// yeah it's a goal - generate the EffectFrame and start the animation
if( activate )
{
generateGoalImage();
m_goalActive = true;
m_ascending = true;
m_goalTimer->start();
}
m_score = result;
}
QString text = firstTeam + ' ' + result + ' ' + secondTeam;
QFont font;
font.setBold( true );
QFontMetrics fm(font);
m_size = fm.boundingRect(text).adjusted(-10, -10, 10, 10).size();
// we don't want to reposition the EffectFrames, therefore we delete the
// old ones. Normally you wouldn't do that, but as we only update once in
// half a minute and it's easier to code...
while( !m_frames.isEmpty() )
{
delete m_frames.first();
m_frames.removeFirst();
}
m_frames.clear();
// and properly position the frame on each screen
for( int i = 0; i < effects->numScreens(); i++ )
{
QRect area = effects->clientArea( ScreenArea, i, effects->currentDesktop());
QRect geometry = QRect( area.x() + area.width() - m_size.width() - 20, area.y() + 20, m_size.width(), m_size.height() );
EffectFrame *frame = new EffectFrame( EffectFrame::Styled );
frame->setText( text );
frame->setFont( font );
frame->setGeometry( geometry );
m_frames.append(frame);
}
// effect frame changed and animation might have started - we need a full repaint
effects->addRepaintFull();
}
void KickerEffect::timeout()
{
// hard coded URL to the liveticker of the match Argentina vs Germany at World Cup 2010.
// If this URL is not valid anymore you can find newer examples on the referrenced web site.
m_page->mainFrame()->load(QUrl("http://www.kicker.de/news/fussball/wm/spielplan/weltmeisterschaft/2010/5/833353/livematch_argentinien_deutschland.html"));
}
void KickerEffect::generateGoalImage()
{
QFont font( "FreeMono", 172 );
QString goal( "GOAL" );
QFontMetrics fm( font );
QSize size = fm.boundingRect( goal ).adjusted(-10, -10, 10, 10).size();
for( int i = 0; i < effects->numScreens(); i++ )
{
// place one frame on the center of each screen
QRect area = effects->clientArea( ScreenArea, i, effects->currentDesktop());
QRect geometry = QRect( area.x() + (area.width() - size.width())/2,
area.y() + (area.height() - size.height())/2,
size.width(), size.height());
EffectFrame *frame = new EffectFrame( EffectFrame::Unstyled, false );
frame->setText( goal );
frame->setFont( font );
frame->setGeometry( geometry );
m_goalFrames.append(frame);
}
}
void KickerEffect::goalTimeout()
{
// stop the animation
m_goalActive = false;
effects->addRepaintFull();
}
} // namespace

View File

@ -0,0 +1,17 @@
[Desktop Entry]
name=Kicker Liveticker Demo Effect
Icon=preferences-system-windows-effect-kicker
Comment=Demonstration effect for using EffectFrames
Type=Service
X-KDE-ServiceTypes=KWin/Effect
X-KDE-PluginInfo-Author=Martin Gräßlin
X-KDE-PluginInfo-Email=kde@martin-graesslin.com
X-KDE-PluginInfo-Name=kwin4_effect_kicker
X-KDE-PluginInfo-Version=0.1.0
X-KDE-PluginInfo-Category=Candy
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50

View File

@ -0,0 +1,84 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2010 Martin Gräßlin <kde@martin-graesslin.com>
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.
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 General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_KICKER_H
#define KWIN_KICKER_H
#include <kwineffects.h>
#include <QObject>
class QTimer;
class QWebPage;
namespace KWin
{
/**
* This effect was written for a talk at Akademy 2010 to have the current
* score of the 2010 World Cup Quarterfinal Argentina vs Germany on screen
* during the presentation.
*
* The effect connects to the German football website "kicker.de" and parses
* the returned website. This explains the name of the effect - it is unrelated
* to the panel of KDE 3.
*
* The effect is a nice illustration on how to use EffectFrames and animations.
* Therefore it was imported into the test directory in SVN to provide a small
* example.
*
* The effect consists of two parts:
* displaying the current score and showing a goal animation when a goal is
* scored. The first uses a Plasma styled EffectFrame, while the latter uses
* an unstyled effect frame.
*
* @author Martin Gräßlin
*/
class KickerEffect : public QObject, public Effect
{
Q_OBJECT
public:
KickerEffect();
~KickerEffect();
virtual void reconfigure( ReconfigureFlags );
virtual void prePaintScreen( ScreenPrePaintData& data, int time );
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
private Q_SLOTS:
void slotLoadFinished(bool ok);
void timeout();
void goalTimeout();
private:
void generateGoalImage();
QWebPage *m_page;
QTimer *m_timer;
QTimer *m_goalTimer;
QSize m_size;
QList<EffectFrame*> m_frames;
QList<EffectFrame*> m_goalFrames;
bool m_goalActive;
QString m_score;
TimeLine m_timeLine;
bool m_ascending;
};
}
#endif // KWIN_KICKER_H