blob: 5d588ccafd9a402258ff245c213ec6f4f53323be [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_slideshow.hxx"
#include <canvas/debug.hxx>
#include <tools/diagnose_ex.h>
#include <canvas/verbosetrace.hxx>
#include "drawshapesubsetting.hxx"
#include "subsettableshapemanager.hxx"
#include "eventqueue.hxx"
#include "eventmultiplexer.hxx"
#include "intrinsicanimationactivity.hxx"
#include "intrinsicanimationeventhandler.hxx"
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/weak_ptr.hpp>
namespace slideshow
{
namespace internal
{
/** Activity for intrinsic shape animations
This is an Activity interface implementation for intrinsic
shape animations. Intrinsic shape animations are
animations directly within a shape, e.g. drawing layer
animations, or GIF animations.
*/
class IntrinsicAnimationActivity : public Activity,
public boost::enable_shared_from_this<IntrinsicAnimationActivity>,
private boost::noncopyable
{
public:
/** Create an IntrinsicAnimationActivity.
@param rContext
Common slideshow objects
@param rDrawShape
Shape to control the intrinsic animation for
@param rWakeupEvent
Externally generated wakeup event, to set this
activity to sleep during inter-frame intervals. Must
come frome the outside, since wakeup event and this
object have mutual references to each other.
@param rTimeouts
Vector of timeout values, to wait before the next
frame is shown.
*/
IntrinsicAnimationActivity( const SlideShowContext& rContext,
const DrawShapeSharedPtr& rDrawShape,
const WakeupEventSharedPtr& rWakeupEvent,
const ::std::vector<double>& rTimeouts,
::std::size_t nNumLoops,
CycleMode eCycleMode );
virtual void dispose();
virtual double calcTimeLag() const;
virtual bool perform();
virtual bool isActive() const;
virtual void dequeued();
virtual void end();
bool enableAnimations();
private:
SlideShowContext maContext;
boost::weak_ptr<DrawShape> mpDrawShape;
WakeupEventSharedPtr mpWakeupEvent;
IntrinsicAnimationEventHandlerSharedPtr mpListener;
::std::vector<double> maTimeouts;
CycleMode meCycleMode;
::std::size_t mnCurrIndex;
::std::size_t mnNumLoops;
::std::size_t mnLoopCount;
bool mbIsActive;
};
//////////////////////////////////////////////////////////////////////
class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler,
private boost::noncopyable
{
public:
explicit IntrinsicAnimationListener( IntrinsicAnimationActivity& rActivity ) :
mrActivity( rActivity )
{}
private:
virtual bool enableAnimations() { return mrActivity.enableAnimations(); }
virtual bool disableAnimations() { mrActivity.end(); return true; }
IntrinsicAnimationActivity& mrActivity;
};
//////////////////////////////////////////////////////////////////////
IntrinsicAnimationActivity::IntrinsicAnimationActivity( const SlideShowContext& rContext,
const DrawShapeSharedPtr& rDrawShape,
const WakeupEventSharedPtr& rWakeupEvent,
const ::std::vector<double>& rTimeouts,
::std::size_t nNumLoops,
CycleMode eCycleMode ) :
maContext( rContext ),
mpDrawShape( rDrawShape ),
mpWakeupEvent( rWakeupEvent ),
mpListener( new IntrinsicAnimationListener(*this) ),
maTimeouts( rTimeouts ),
meCycleMode( eCycleMode ),
mnCurrIndex(0),
mnNumLoops(nNumLoops),
mnLoopCount(0),
mbIsActive(false)
{
ENSURE_OR_THROW( rContext.mpSubsettableShapeManager,
"IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid shape manager" );
ENSURE_OR_THROW( rDrawShape,
"IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid draw shape" );
ENSURE_OR_THROW( rWakeupEvent,
"IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid wakeup event" );
ENSURE_OR_THROW( !rTimeouts.empty(),
"IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Empty timeout vector" );
maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler(
mpListener );
}
void IntrinsicAnimationActivity::dispose()
{
end();
if( mpWakeupEvent )
mpWakeupEvent->dispose();
maContext.dispose();
mpDrawShape.reset();
mpWakeupEvent.reset();
maTimeouts.clear();
mnCurrIndex = 0;
maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler(
mpListener );
}
double IntrinsicAnimationActivity::calcTimeLag() const
{
return 0.0;
}
bool IntrinsicAnimationActivity::perform()
{
if( !isActive() )
return false;
DrawShapeSharedPtr pDrawShape( mpDrawShape.lock() );
if( !pDrawShape || !mpWakeupEvent )
{
// event or draw shape vanished, no sense living on ->
// commit suicide.
dispose();
return false;
}
// mnNumLoops == 0 means infinite looping
if( mnNumLoops != 0 &&
mnLoopCount >= mnNumLoops )
{
// #i55294# After finishing the loops, display the first frame
pDrawShape->setIntrinsicAnimationFrame( 0 );
maContext.mpSubsettableShapeManager->notifyShapeUpdate( pDrawShape );
end();
return false;
}
::std::size_t nNewIndex = 0;
const ::std::size_t nNumFrames(maTimeouts.size());
switch( meCycleMode )
{
case CYCLE_LOOP:
{
pDrawShape->setIntrinsicAnimationFrame( mnCurrIndex );
mpWakeupEvent->start();
mpWakeupEvent->setNextTimeout( maTimeouts[mnCurrIndex] );
mnLoopCount += (mnCurrIndex + 1) / nNumFrames;
nNewIndex = (mnCurrIndex + 1) % nNumFrames;
break;
}
case CYCLE_PINGPONGLOOP:
{
::std::size_t nTrueIndex( mnCurrIndex < nNumFrames ?
mnCurrIndex :
2*nNumFrames - mnCurrIndex - 1 );
pDrawShape->setIntrinsicAnimationFrame( nTrueIndex );
mpWakeupEvent->start();
mpWakeupEvent->setNextTimeout( maTimeouts[nTrueIndex] );
mnLoopCount += (mnCurrIndex + 1) / (2*nNumFrames);
nNewIndex = (mnCurrIndex + 1) % 2*nNumFrames;
break;
}
}
maContext.mrEventQueue.addEvent( mpWakeupEvent );
maContext.mpSubsettableShapeManager->notifyShapeUpdate( pDrawShape );
mnCurrIndex = nNewIndex;
return false; // don't reinsert, WakeupEvent will perform
// that after the given timeout
}
bool IntrinsicAnimationActivity::isActive() const
{
return mbIsActive;
}
void IntrinsicAnimationActivity::dequeued()
{
// not used here
}
void IntrinsicAnimationActivity::end()
{
// there is no dedicated end state, just become inactive:
mbIsActive = false;
}
bool IntrinsicAnimationActivity::enableAnimations()
{
mbIsActive = true;
return maContext.mrActivitiesQueue.addActivity(
shared_from_this() );
}
//////////////////////////////////////////////////////////////////////
ActivitySharedPtr createIntrinsicAnimationActivity(
const SlideShowContext& rContext,
const DrawShapeSharedPtr& rDrawShape,
const WakeupEventSharedPtr& rWakeupEvent,
const ::std::vector<double>& rTimeouts,
::std::size_t nNumLoops,
CycleMode eCycleMode )
{
return ActivitySharedPtr(
new IntrinsicAnimationActivity(rContext,
rDrawShape,
rWakeupEvent,
rTimeouts,
nNumLoops,
eCycleMode) );
}
}
}