blob: aa737c47ddf6dc6bf26730c141aa81a54f8de43b [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/elapsedtime.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <comphelper/anytostring.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <rtl/math.hxx>
#include <vcl/metric.hxx>
#include <vcl/salbtype.hxx>
#include <vcl/canvastools.hxx>
#include <vcl/metaact.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/drawing/TextAnimationKind.hpp>
#include <com/sun/star/drawing/TextAnimationDirection.hpp>
#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
#include <com/sun/star/drawing/HomogenMatrix3.hpp>
#include <com/sun/star/awt/Rectangle.hpp>
#include "activity.hxx"
#include "wakeupevent.hxx"
#include "eventqueue.hxx"
#include "drawshapesubsetting.hxx"
#include "drawshape.hxx"
#include "shapesubset.hxx"
#include "shapeattributelayerholder.hxx"
#include "slideshowcontext.hxx"
#include "tools.hxx"
#include "gdimtftools.hxx"
#include "eventmultiplexer.hxx"
#include "intrinsicanimationactivity.hxx"
#include "intrinsicanimationeventhandler.hxx"
#include <boost/weak_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <vector>
using namespace com::sun::star;
using namespace ::slideshow::internal;
namespace {
class ScrollTextAnimNode
{
sal_uInt32 mnDuration; // single duration
sal_uInt32 mnRepeat; // 0 -> endless
double mfStart;
double mfStop;
sal_uInt32 mnFrequency; // in ms
// forth and back change at mnRepeat%2:
bool mbAlternate;
public:
ScrollTextAnimNode(
sal_uInt32 nDuration, sal_uInt32 nRepeat, double fStart, double fStop,
sal_uInt32 nFrequency, bool bAlternate)
: mnDuration(nDuration),
mnRepeat(nRepeat),
mfStart(fStart),
mfStop(fStop),
mnFrequency(nFrequency),
mbAlternate(bAlternate)
{}
sal_uInt32 GetDuration() const { return mnDuration; }
sal_uInt32 GetRepeat() const { return mnRepeat; }
sal_uInt32 GetFullTime() const { return mnDuration * mnRepeat; }
double GetStart() const { return mfStart; }
double GetStop() const { return mfStop; }
sal_uInt32 GetFrequency() const { return mnFrequency; }
bool DoAlternate() const { return mbAlternate; }
double GetStateAtRelativeTime(sal_uInt32 nRelativeTime) const;
};
double ScrollTextAnimNode::GetStateAtRelativeTime(
sal_uInt32 nRelativeTime) const
{
// #151174# Avoid division by zero.
if( mnDuration == 0 )
return mfStop;
if(mnRepeat)
{
// ending
const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
sal_uInt32 nFrameTime(nRelativeTime - (nRepeatCount * mnDuration));
if(DoAlternate() && (nRepeatCount + 1L) % 2L)
nFrameTime = mnDuration - nFrameTime;
return mfStart + ((mfStop - mfStart) *
(double(nFrameTime) / mnDuration));
}
else
{
// endless
sal_uInt32 nFrameTime(nRelativeTime % mnDuration);
if(DoAlternate())
{
const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
if((nRepeatCount + 1L) % 2L)
nFrameTime = mnDuration - nFrameTime;
}
return mfStart + ((mfStop - mfStart) * (double(nFrameTime) / mnDuration));
}
}
class ActivityImpl : public Activity,
public boost::enable_shared_from_this<ActivityImpl>,
private boost::noncopyable
{
public:
virtual ~ActivityImpl();
ActivityImpl(
SlideShowContext const& rContext,
boost::shared_ptr<WakeupEvent> const& pWakeupEvent,
boost::shared_ptr<DrawShape> const& pDrawShape );
bool enableAnimations();
// Disposable:
virtual void dispose();
// Activity:
virtual double calcTimeLag() const;
virtual bool perform();
virtual bool isActive() const;
virtual void dequeued();
virtual void end();
private:
void updateShapeAttributes( double fTime,
basegfx::B2DRectangle const& parentBounds );
// Access to VisibleWhenSTarted flags
sal_Bool IsVisibleWhenStarted() const { return mbVisibleWhenStarted; }
sal_Bool IsVisibleWhenStopped() const { return mbVisibleWhenStopped; }
// scroll horizontal? if sal_False, scroll is vertical.
bool ScrollHorizontal() const {
return (drawing::TextAnimationDirection_LEFT == meDirection ||
drawing::TextAnimationDirection_RIGHT == meDirection);
}
// Access to StepWidth in logical units
sal_uInt32 GetStepWidthLogic() const;
// is the animation direction opposite?
bool DoScrollForward() const {
return (drawing::TextAnimationDirection_RIGHT == meDirection ||
drawing::TextAnimationDirection_DOWN == meDirection);
}
// do alternate text directions?
bool DoAlternate() const { return mbAlternate; }
// do scroll in?
bool DoScrollIn() const { return mbScrollIn; }
// Scroll helper methods
void ImpForceScrollTextAnimNodes();
ScrollTextAnimNode* ImpGetScrollTextAnimNode(
sal_uInt32 nTime, sal_uInt32& rRelativeTime );
sal_uInt32 ImpRegisterAgainScrollTextMixerState(
sal_uInt32 nTime);
// calculate the MixerState value for given time
double GetMixerState(sal_uInt32 nTime);
////////////////////////////////////////////////////////////////////
SlideShowContext maContext;
boost::shared_ptr<WakeupEvent> mpWakeupEvent;
boost::weak_ptr<DrawShape> mpParentDrawShape;
DrawShapeSharedPtr mpDrawShape;
ShapeAttributeLayerHolder maShapeAttrLayer;
GDIMetaFileSharedPtr mpMetaFile;
IntrinsicAnimationEventHandlerSharedPtr mpListener;
canvas::tools::ElapsedTime maTimer;
double mfRotationAngle;
bool mbIsShapeAnimated;
bool mbIsDisposed;
bool mbIsActive;
drawing::TextAnimationKind meAnimKind;
// The blink frequency in ms
sal_uInt32 mnFrequency;
// The repeat count, init to 0L which means endless
sal_uInt32 mnRepeat;
// Flag to decide if text will be shown when animation has ended
bool mbVisibleWhenStopped;
bool mbVisibleWhenStarted;
// Flag decides if TextScroll alternates. Default is sal_False.
bool mbAlternate;
// Flag to remember if this is a simple scrollin text
bool mbScrollIn;
// start time for this animation
sal_uInt32 mnStartTime;
// The AnimationDirection
drawing::TextAnimationDirection meDirection;
// Get width per Step. Negative means pixel, positive logical units
sal_Int32 mnStepWidth;
// The single anim steps
std::vector< ScrollTextAnimNode > maVector;
// the scroll rectangle
Rectangle maScrollRectangleLogic;
// the paint rectangle
Rectangle maPaintRectangleLogic;
};
//////////////////////////////////////////////////////////////////////
class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler,
private boost::noncopyable
{
public:
explicit IntrinsicAnimationListener( ActivityImpl& rActivity ) :
mrActivity( rActivity )
{}
private:
virtual bool enableAnimations() { return mrActivity.enableAnimations(); }
virtual bool disableAnimations() { mrActivity.end(); return true; }
ActivityImpl& mrActivity;
};
//////////////////////////////////////////////////////////////////////
double ActivityImpl::GetMixerState( sal_uInt32 nTime )
{
if( meAnimKind == drawing::TextAnimationKind_BLINK )
{
// from AInfoBlinkText:
double fRetval(0.0);
sal_Bool bDone(sal_False);
const sal_uInt32 nLoopTime(2 * mnFrequency);
if(mnRepeat)
{
const sal_uInt32 nEndTime(mnRepeat * nLoopTime);
if(nTime >= nEndTime)
{
if(mbVisibleWhenStopped)
fRetval = 0.0;
else
fRetval = 1.0;
bDone = sal_True;
}
}
if(!bDone)
{
sal_uInt32 nTimeInLoop(nTime % nLoopTime);
fRetval = double(nTimeInLoop) / nLoopTime;
}
return fRetval;
}
else
{
// from AInfoScrollText:
double fRetval(0.0);
ImpForceScrollTextAnimNodes();
if(!maVector.empty())
{
sal_uInt32 nRelativeTime;
ScrollTextAnimNode* pNode =
ImpGetScrollTextAnimNode(nTime, nRelativeTime);
if(pNode)
{
// use node
fRetval = pNode->GetStateAtRelativeTime(nRelativeTime);
}
else
{
// end of animation, take last entry's end
fRetval = maVector[maVector.size() - 1L].GetStop();
}
}
return fRetval;
}
}
// Access to StepWidth in logical units
sal_uInt32 ActivityImpl::GetStepWidthLogic() const
{
// #i69847# Assuming higher DPI
sal_uInt32 const PIXEL_TO_LOGIC = 30;
sal_uInt32 nRetval(0L);
if(mnStepWidth < 0L)
{
// is in pixels, convert to logical units
nRetval = (-mnStepWidth * PIXEL_TO_LOGIC);
}
else if(mnStepWidth > 0L)
{
// is in logical units
nRetval = mnStepWidth;
}
if(0L == nRetval)
{
// step 1 pixel, canned value
// #128389# with very high DPIs like in PDF export, this can
// still get zero. for that cases, set a default, too (taken
// from ainfoscrolltext.cxx)
nRetval = 100L;
}
return nRetval;
}
void ActivityImpl::ImpForceScrollTextAnimNodes()
{
if(maVector.empty())
{
// prepare values
sal_uInt32 nLoopTime;
double fZeroLogic, fOneLogic, fInitLogic, fDistanceLogic;
double fZeroLogicAlternate = 0.0, fOneLogicAlternate = 0.0;
double fZeroRelative, fOneRelative, fInitRelative,fDistanceRelative;
if(ScrollHorizontal())
{
if(DoAlternate())
{
if(maPaintRectangleLogic.GetWidth() >
maScrollRectangleLogic.GetWidth())
{
fZeroLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
fOneLogicAlternate = maScrollRectangleLogic.Left();
}
else
{
fZeroLogicAlternate = maScrollRectangleLogic.Left();
fOneLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
}
}
fZeroLogic = maScrollRectangleLogic.Left() - maPaintRectangleLogic.GetWidth();
fOneLogic = maScrollRectangleLogic.Right();
fInitLogic = maPaintRectangleLogic.Left();
}
else
{
if(DoAlternate())
{
if(maPaintRectangleLogic.GetHeight() > maScrollRectangleLogic.GetHeight())
{
fZeroLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
fOneLogicAlternate = maScrollRectangleLogic.Top();
}
else
{
fZeroLogicAlternate = maScrollRectangleLogic.Top();
fOneLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
}
}
fZeroLogic = maScrollRectangleLogic.Top() - maPaintRectangleLogic.GetHeight();
fOneLogic = maScrollRectangleLogic.Bottom();
fInitLogic = maPaintRectangleLogic.Top();
}
fDistanceLogic = fOneLogic - fZeroLogic;
fInitRelative = (fInitLogic - fZeroLogic) / fDistanceLogic;
if(DoAlternate())
{
fZeroRelative =
(fZeroLogicAlternate - fZeroLogic) / fDistanceLogic;
fOneRelative =
(fOneLogicAlternate - fZeroLogic) / fDistanceLogic;
fDistanceRelative = fOneRelative - fZeroRelative;
}
else
{
fZeroRelative = 0.0;
fOneRelative = 1.0;
fDistanceRelative = 1.0;
}
if(mnStartTime)
{
// Start time loop
ScrollTextAnimNode aStartNode(
mnStartTime, 1L, 0.0, 0.0, mnStartTime, false);
maVector.push_back(aStartNode);
}
if(IsVisibleWhenStarted())
{
double fRelativeStartValue, fRelativeEndValue,fRelativeDistance;
if(DoScrollForward())
{
fRelativeStartValue = fInitRelative;
fRelativeEndValue = fOneRelative;
fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
}
else
{
fRelativeStartValue = fInitRelative;
fRelativeEndValue = fZeroRelative;
fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
}
const double fNumberSteps =
(fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
nLoopTime = FRound(fNumberSteps * mnFrequency);
// init loop
ScrollTextAnimNode aInitNode(
nLoopTime, 1L,
fRelativeStartValue, fRelativeEndValue,
mnFrequency, false);
maVector.push_back(aInitNode);
}
// prepare main loop values
{
double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
if(DoScrollForward())
{
fRelativeStartValue = fZeroRelative;
fRelativeEndValue = fOneRelative;
fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
}
else
{
fRelativeStartValue = fOneRelative;
fRelativeEndValue = fZeroRelative;
fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
}
const double fNumberSteps =
(fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
nLoopTime = FRound(fNumberSteps * mnFrequency);
if(0L == mnRepeat)
{
if(!DoScrollIn())
{
// endless main loop
ScrollTextAnimNode aMainNode(
nLoopTime, 0L,
fRelativeStartValue, fRelativeEndValue,
mnFrequency, DoAlternate());
maVector.push_back(aMainNode);
}
}
else
{
sal_uInt32 nNumRepeat(mnRepeat);
if(DoAlternate() && (nNumRepeat + 1L) % 2L)
nNumRepeat += 1L;
// ending main loop
ScrollTextAnimNode aMainNode(
nLoopTime, nNumRepeat,
fRelativeStartValue, fRelativeEndValue,
mnFrequency, DoAlternate());
maVector.push_back(aMainNode);
}
}
if(IsVisibleWhenStopped())
{
double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
if(DoScrollForward())
{
fRelativeStartValue = fZeroRelative;
fRelativeEndValue = fInitRelative;
fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
}
else
{
fRelativeStartValue = fOneRelative;
fRelativeEndValue = fInitRelative;
fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
}
const double fNumberSteps =
(fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
nLoopTime = FRound(fNumberSteps * mnFrequency);
// exit loop
ScrollTextAnimNode aExitNode(
nLoopTime, 1L,
fRelativeStartValue, fRelativeEndValue, mnFrequency, false);
maVector.push_back(aExitNode);
}
}
}
ScrollTextAnimNode* ActivityImpl::ImpGetScrollTextAnimNode(
sal_uInt32 nTime, sal_uInt32& rRelativeTime )
{
ScrollTextAnimNode* pRetval = 0L;
ImpForceScrollTextAnimNodes();
if(!maVector.empty())
{
rRelativeTime = nTime;
for(sal_uInt32 a(0L); !pRetval && a < maVector.size(); a++)
{
ScrollTextAnimNode & rNode = maVector[a];
if(!rNode.GetRepeat())
{
// endless loop, use it
pRetval = &rNode;
}
else if(rNode.GetFullTime() > rRelativeTime)
{
// ending node
pRetval = &rNode;
}
else
{
// look at next
rRelativeTime -= rNode.GetFullTime();
}
}
}
return pRetval;
}
sal_uInt32 ActivityImpl::ImpRegisterAgainScrollTextMixerState(sal_uInt32 nTime)
{
sal_uInt32 nRetval(0L);
ImpForceScrollTextAnimNodes();
if(maVector.size())
{
sal_uInt32 nRelativeTime;
ScrollTextAnimNode* pNode = ImpGetScrollTextAnimNode(nTime, nRelativeTime);
if(pNode)
{
// take register time
nRetval = pNode->GetFrequency();
}
}
else
{
// #i38135# not initialized, return default
nRetval = mnFrequency;
}
return nRetval;
}
void ActivityImpl::updateShapeAttributes(
double fTime, basegfx::B2DRectangle const& parentBounds )
{
OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
if( meAnimKind == drawing::TextAnimationKind_NONE )
return;
double const fMixerState = GetMixerState(
static_cast<sal_uInt32>(fTime * 1000.0) );
if( meAnimKind == drawing::TextAnimationKind_BLINK )
{
// show/hide text:
maShapeAttrLayer.get()->setVisibility( fMixerState < 0.5 );
}
else if(mpMetaFile) // scroll mode:
{
//
// keep care: the below code is highly sensible to changes...
//
// rectangle of the pure text:
double const fPaintWidth = maPaintRectangleLogic.GetWidth();
double const fPaintHeight = maPaintRectangleLogic.GetHeight();
// rectangle where the scrolling takes place (-> clipping):
double const fScrollWidth = maScrollRectangleLogic.GetWidth();
double const fScrollHeight = maScrollRectangleLogic.GetHeight();
basegfx::B2DPoint pos, clipPos;
if(ScrollHorizontal())
{
double const fOneEquiv( fScrollWidth );
double const fZeroEquiv( -fPaintWidth );
pos.setX( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
clipPos.setX( -pos.getX() );
clipPos.setY( -pos.getY() );
// #i69844# Compensation for text-wider-than-shape case
if( fPaintWidth > fScrollWidth )
pos.setX( pos.getX() + (fPaintWidth-fScrollWidth) / 2.0 );
}
else
{
// scroll vertical:
double const fOneEquiv( fScrollHeight );
double const fZeroEquiv( -fPaintHeight );
pos.setY( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
clipPos.setX( -pos.getX() );
clipPos.setY( -pos.getY() );
// #i69844# Compensation for text-higher-than-shape case
if( fPaintHeight > fScrollHeight )
pos.setY( pos.getY() + (fPaintHeight-fScrollHeight) / 2.0 );
}
basegfx::B2DPolygon clipPoly(
basegfx::tools::createPolygonFromRect(
basegfx::B2DRectangle( clipPos.getX(),
clipPos.getY(),
clipPos.getX() + fScrollWidth,
clipPos.getY() + fScrollHeight ) ) );
if( !::basegfx::fTools::equalZero( mfRotationAngle ))
{
maShapeAttrLayer.get()->setRotationAngle( mfRotationAngle );
double const fRotate = (mfRotationAngle * M_PI / 180.0);
basegfx::B2DHomMatrix aTransform;
// position:
aTransform.rotate( fRotate );
pos *= aTransform;
}
pos += parentBounds.getCenter();
maShapeAttrLayer.get()->setPosition( pos );
maShapeAttrLayer.get()->setClip( basegfx::B2DPolyPolygon(clipPoly) );
}
}
bool ActivityImpl::perform()
{
if( !isActive() )
return false;
ENSURE_OR_RETURN_FALSE(
mpDrawShape,
"ActivityImpl::perform(): still active, but NULL draw shape" );
DrawShapeSharedPtr const pParentDrawShape( mpParentDrawShape );
if( !pParentDrawShape )
return false; // parent has vanished
if( pParentDrawShape->isVisible() )
{
if( !mbIsShapeAnimated )
{
mpDrawShape->setVisibility(true); // shape may be initially hidden
maContext.mpSubsettableShapeManager->enterAnimationMode( mpDrawShape );
maTimer.reset();
mbIsShapeAnimated = true;
}
// update attributes related to current time:
basegfx::B2DRectangle const parentBounds(
pParentDrawShape->getBounds() );
const double nCurrTime( maTimer.getElapsedTime() );
updateShapeAttributes( nCurrTime, parentBounds );
const sal_uInt32 nFrequency(
ImpRegisterAgainScrollTextMixerState(
static_cast<sal_uInt32>(nCurrTime * 1000.0)) );
if(nFrequency)
{
mpWakeupEvent->start();
mpWakeupEvent->setNextTimeout(
std::max(0.1,nFrequency/1000.0) );
maContext.mrEventQueue.addEvent( mpWakeupEvent );
if( mpDrawShape->isContentChanged() )
maContext.mpSubsettableShapeManager->notifyShapeUpdate( mpDrawShape );
}
// else: finished, not need to wake up again.
}
else
{
// busy-wait, until parent shape gets visible
mpWakeupEvent->start();
mpWakeupEvent->setNextTimeout( 2.0 );
}
// don't reinsert, WakeupEvent will perform that after the given timeout:
return false;
}
ActivityImpl::ActivityImpl(
SlideShowContext const& rContext,
boost::shared_ptr<WakeupEvent> const& pWakeupEvent,
boost::shared_ptr<DrawShape> const& pParentDrawShape )
: maContext(rContext),
mpWakeupEvent(pWakeupEvent),
mpParentDrawShape(pParentDrawShape),
mpListener( new IntrinsicAnimationListener(*this) ),
maTimer(rContext.mrEventQueue.getTimer()),
mbIsShapeAnimated(false),
mbIsDisposed(false),
mbIsActive(true),
meAnimKind(drawing::TextAnimationKind_NONE),
mnStartTime(0L)
{
// get doctreenode:
sal_Int32 const nNodes = pParentDrawShape->getNumberOfTreeNodes(
DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH );
DocTreeNode scrollTextNode(
pParentDrawShape->getTreeNode(
0, DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ));
// xxx todo: remove this hack
if( nNodes > 1 )
scrollTextNode.setEndIndex(
pParentDrawShape->getTreeNode(
nNodes - 1,
DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ).getEndIndex());
// TODO(Q3): Doing this manually, instead of using
// ShapeSubset. This is because of lifetime issues (ShapeSubset
// generates circular references to parent shape)
mpDrawShape = boost::dynamic_pointer_cast<DrawShape>(
maContext.mpSubsettableShapeManager->getSubsetShape(
pParentDrawShape,
scrollTextNode ));
mpMetaFile = mpDrawShape->forceScrollTextMetaFile();
// make scroll text invisible for slide transition bitmaps
mpDrawShape->setVisibility(false);
basegfx::B2DRectangle aScrollRect, aPaintRect;
ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect,
aPaintRect,
mpMetaFile ),
"ActivityImpl::ActivityImpl(): Could not extract "
"scroll anim rectangles from mtf" );
maScrollRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
aScrollRect );
maPaintRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
aPaintRect );
maShapeAttrLayer.createAttributeLayer(mpDrawShape);
uno::Reference<drawing::XShape> const xShape( mpDrawShape->getXShape() );
uno::Reference<beans::XPropertySet> const xProps( xShape, uno::UNO_QUERY_THROW );
getPropertyValue( meAnimKind, xProps, OUSTR("TextAnimationKind") );
OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
mbAlternate = (meAnimKind == drawing::TextAnimationKind_ALTERNATE);
mbScrollIn = (meAnimKind == drawing::TextAnimationKind_SLIDE);
// adopted from in AInfoBlinkText::ImplInit():
sal_Int16 nRepeat(0);
getPropertyValue( nRepeat, xProps, OUSTR("TextAnimationCount") );
mnRepeat = nRepeat;
if(mbAlternate)
{
// force visible when started for scroll-forth-and-back, because
// slide has been coming in with visible text in the middle:
mbVisibleWhenStarted = true;
}
else
{
getPropertyValue( mbVisibleWhenStarted, xProps,
OUSTR("TextAnimationStartInside") );
}
// set visible when stopped
getPropertyValue( mbVisibleWhenStopped, xProps,
OUSTR("TextAnimatiogonStopInside") );
// rotation:
getPropertyValue( mfRotationAngle, xProps,
OUSTR("RotateAngle") );
mfRotationAngle /= -100.0; // (switching direction)
// set frequency
sal_Int16 nDelay(0);
getPropertyValue( nDelay, xProps, OUSTR("TextAnimationDelay") );
// set delay if not automatic
mnFrequency = (nDelay ? nDelay :
// default:
meAnimKind == drawing::TextAnimationKind_BLINK
? 250L : 50L );
// adopted from in AInfoScrollText::ImplInit():
// If it is a simple m_bScrollIn, reset some parameters
if( DoScrollIn() )
{
// most parameters are set correctly from the dialog logic, but
// eg VisisbleWhenStopped is grayed out and needs to be corrected here.
mbVisibleWhenStopped = true;
mbVisibleWhenStarted = false;
mnRepeat = 0L;
}
// Get animation direction
getPropertyValue( meDirection, xProps, OUSTR("TextAnimationDirection") );
// Get step width. Negative means pixel, positive logical units
getPropertyValue( mnStepWidth, xProps, OUSTR("TextAnimationAmount") );
maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler(
mpListener );
}
bool ActivityImpl::enableAnimations()
{
mbIsActive = true;
return maContext.mrActivitiesQueue.addActivity(
shared_from_this() );
}
ActivityImpl::~ActivityImpl()
{
}
void ActivityImpl::dispose()
{
if( !mbIsDisposed )
{
end();
// only remove subset here, since end() is called on slide end
// (and we must not spoil the slide preview bitmap with scroll
// text)
maShapeAttrLayer.reset();
if( mpDrawShape )
{
// TODO(Q3): Doing this manually, instead of using
// ShapeSubset. This is because of lifetime issues
// (ShapeSubset generates circular references to parent
// shape)
DrawShapeSharedPtr pParent( mpParentDrawShape.lock() );
if( pParent )
maContext.mpSubsettableShapeManager->revokeSubset(
pParent,
mpDrawShape );
}
mpMetaFile.reset();
mpDrawShape.reset();
mpParentDrawShape.reset();
mpWakeupEvent.reset();
maContext.dispose();
mbIsDisposed = true;
maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler(
mpListener );
}
}
double ActivityImpl::calcTimeLag() const
{
return 0.0;
}
bool ActivityImpl::isActive() const
{
return mbIsActive;
}
void ActivityImpl::dequeued()
{
// not used here
}
void ActivityImpl::end()
{
// not used here
mbIsActive = false;
if( mbIsShapeAnimated )
{
maContext.mpSubsettableShapeManager->leaveAnimationMode( mpDrawShape );
mbIsShapeAnimated = false;
}
}
} // anon namespace
namespace slideshow {
namespace internal {
boost::shared_ptr<Activity> createDrawingLayerAnimActivity(
SlideShowContext const& rContext,
boost::shared_ptr<DrawShape> const& pDrawShape )
{
boost::shared_ptr<Activity> pActivity;
try
{
boost::shared_ptr<WakeupEvent> const pWakeupEvent(
new WakeupEvent( rContext.mrEventQueue.getTimer(),
rContext.mrActivitiesQueue ) );
pActivity.reset( new ActivityImpl( rContext, pWakeupEvent, pDrawShape ) );
pWakeupEvent->setActivity( pActivity );
}
catch( uno::RuntimeException& )
{
throw;
}
catch( uno::Exception& )
{
// translate any error into empty factory product.
OSL_ENSURE( false,
rtl::OUStringToOString(
comphelper::anyToString( cppu::getCaughtException() ),
RTL_TEXTENCODING_UTF8 ).getStr() );
}
return pActivity;
}
} // namespace internal
} // namespace presentation