|
|
|
/*
|
|
|
|
Copyright (C) 2003 KSVG Team
|
|
|
|
This file is part of the KDE project
|
|
|
|
|
|
|
|
This library 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 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "KSVGCanvas.h"
|
|
|
|
#include "CanvasItem.h"
|
|
|
|
#include "SVGShapeImpl.h"
|
|
|
|
#include "SVGDocumentImpl.h"
|
|
|
|
#include "SVGTimeScheduler.moc"
|
|
|
|
|
|
|
|
using namespace KSVG;
|
|
|
|
|
|
|
|
SVGTimer::SVGTimer(TQObject *scheduler, unsigned int ms, bool singleShot)
|
|
|
|
{
|
|
|
|
m_ms = ms;
|
|
|
|
m_singleShot = singleShot;
|
|
|
|
m_timer = new TQTimer(scheduler);
|
|
|
|
}
|
|
|
|
|
|
|
|
SVGTimer::~SVGTimer()
|
|
|
|
{
|
|
|
|
delete m_timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SVGTimer::operator==(const TQTimer *timer)
|
|
|
|
{
|
|
|
|
return (m_timer == timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQTimer *SVGTimer::qtimer() const
|
|
|
|
{
|
|
|
|
return m_timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimer::start(TQObject *receiver, const char *member)
|
|
|
|
{
|
|
|
|
TQObject::connect(m_timer, TQ_SIGNAL(timeout()), receiver, member);
|
|
|
|
m_timer->start(m_ms, m_singleShot);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimer::stop()
|
|
|
|
{
|
|
|
|
m_timer->stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SVGTimer::isActive() const
|
|
|
|
{
|
|
|
|
return m_timer->isActive();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int SVGTimer::ms() const
|
|
|
|
{
|
|
|
|
return m_ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SVGTimer::singleShot() const
|
|
|
|
{
|
|
|
|
return m_singleShot;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimer::notifyAll()
|
|
|
|
{
|
|
|
|
if(m_notifyList.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQValueList<SVGElementImpl *> elements;
|
|
|
|
for(unsigned int i = m_notifyList.count();i > 0; i--)
|
|
|
|
{
|
|
|
|
SVGElementImpl *element = m_notifyList[i - 1];
|
|
|
|
if(!element)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SVGAnimationElementImpl *animation = dynamic_cast<SVGAnimationElementImpl *>(element);
|
|
|
|
if(animation)
|
|
|
|
{
|
|
|
|
animation->handleTimerEvent();
|
|
|
|
|
|
|
|
SVGElementImpl *target = animation->targetElement();
|
|
|
|
if(!elements.contains(target))
|
|
|
|
elements.append(target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Optimized update logic (to avoid 4 updates, on the same element)
|
|
|
|
TQValueList<SVGElementImpl *>::iterator it2;
|
|
|
|
for(it2 = elements.begin(); it2 != elements.end(); ++it2)
|
|
|
|
{
|
|
|
|
SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(*it2);
|
|
|
|
if(shape && shape->item())
|
|
|
|
shape->item()->update(UPDATE_TRANSFORM);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimer::addNotify(SVGElementImpl *element)
|
|
|
|
{
|
|
|
|
m_notifyList.append(element);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimer::removeNotify(SVGElementImpl *element)
|
|
|
|
{
|
|
|
|
m_notifyList.remove(element);
|
|
|
|
|
|
|
|
if(m_notifyList.isEmpty())
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
const unsigned int SVGTimeScheduler::staticTimerInterval = 15; // milliseconds
|
|
|
|
|
|
|
|
SVGTimeScheduler::SVGTimeScheduler(SVGDocumentImpl *doc) : TQObject(), m_doc(doc)
|
|
|
|
{
|
|
|
|
// Create static interval timers but don't start it yet!
|
|
|
|
m_intervalTimer = new SVGTimer(this, staticTimerInterval, false);
|
|
|
|
m_creationTime.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
SVGTimeScheduler::~SVGTimeScheduler()
|
|
|
|
{
|
|
|
|
// Usually singleShot timers cleanup themselves, after usage
|
|
|
|
SVGTimerList::iterator it;
|
|
|
|
for(it = m_timerList.begin(); it != m_timerList.end(); ++it)
|
|
|
|
{
|
|
|
|
SVGTimer *svgTimer = *it;
|
|
|
|
delete svgTimer;
|
|
|
|
}
|
|
|
|
delete m_intervalTimer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimeScheduler::addTimer(SVGElementImpl *element, unsigned int ms)
|
|
|
|
{
|
|
|
|
SVGTimer *svgTimer = new SVGTimer(this, ms, true);
|
|
|
|
svgTimer->addNotify(element);
|
|
|
|
m_timerList.append(svgTimer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimeScheduler::connectIntervalTimer(SVGElementImpl *element)
|
|
|
|
{
|
|
|
|
m_intervalTimer->addNotify(element);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimeScheduler::disconnectIntervalTimer(SVGElementImpl *element)
|
|
|
|
{
|
|
|
|
m_intervalTimer->removeNotify(element);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimeScheduler::startAnimations()
|
|
|
|
{
|
|
|
|
SVGTimerList::iterator it;
|
|
|
|
for(it = m_timerList.begin(); it != m_timerList.end(); ++it)
|
|
|
|
{
|
|
|
|
SVGTimer *svgTimer = *it;
|
|
|
|
if(svgTimer && !svgTimer->isActive())
|
|
|
|
svgTimer->start(this, TQ_SLOT(slotTimerNotify()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimeScheduler::toggleAnimations()
|
|
|
|
{
|
|
|
|
if(m_intervalTimer->isActive())
|
|
|
|
m_intervalTimer->stop();
|
|
|
|
else
|
|
|
|
m_intervalTimer->start(this, TQ_SLOT(slotTimerNotify()));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SVGTimeScheduler::animationsPaused() const
|
|
|
|
{
|
|
|
|
return !m_intervalTimer->isActive();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGTimeScheduler::slotTimerNotify()
|
|
|
|
{
|
|
|
|
TQTimer *senderTimer = const_cast<TQTimer *>(static_cast<const TQTimer *>(sender()));
|
|
|
|
|
|
|
|
SVGTimer *svgTimer = 0;
|
|
|
|
SVGTimerList::iterator it;
|
|
|
|
for(it = m_timerList.begin(); it != m_timerList.end(); ++it)
|
|
|
|
{
|
|
|
|
SVGTimer *cur = *it;
|
|
|
|
if(*cur == senderTimer)
|
|
|
|
{
|
|
|
|
svgTimer = cur;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!svgTimer)
|
|
|
|
{
|
|
|
|
svgTimer = (*m_intervalTimer == senderTimer) ? m_intervalTimer : 0;
|
|
|
|
|
|
|
|
if(!svgTimer)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
svgTimer->notifyAll();
|
|
|
|
|
|
|
|
// Animations need direct updates
|
|
|
|
if(m_doc->canvas())
|
|
|
|
m_doc->canvas()->update();
|
|
|
|
emit m_doc->finishedRendering();
|
|
|
|
|
|
|
|
if(svgTimer->singleShot())
|
|
|
|
{
|
|
|
|
m_timerList.remove(svgTimer);
|
|
|
|
delete svgTimer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The singleShot timers of ie. <animate> with begin="3s" are notified
|
|
|
|
// by the previous call, and now all connections to the interval timer
|
|
|
|
// are created and now we just need to fire that timer (Niko)
|
|
|
|
if(svgTimer != m_intervalTimer && !m_intervalTimer->isActive())
|
|
|
|
m_intervalTimer->start(this, TQ_SLOT(slotTimerNotify()));
|
|
|
|
}
|
|
|
|
|
|
|
|
float SVGTimeScheduler::elapsed() const
|
|
|
|
{
|
|
|
|
return float(m_creationTime.elapsed()) / 1000.0;
|
|
|
|
}
|