| /************************************************************** |
| * |
| * 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 from 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) ); |
| } |
| } |
| } |