diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /slideshow/source/engine/animationfactory.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'slideshow/source/engine/animationfactory.cxx')
-rw-r--r-- | slideshow/source/engine/animationfactory.cxx | 1515 |
1 files changed, 1515 insertions, 0 deletions
diff --git a/slideshow/source/engine/animationfactory.cxx b/slideshow/source/engine/animationfactory.cxx new file mode 100644 index 000000000..0d160e3f5 --- /dev/null +++ b/slideshow/source/engine/animationfactory.cxx @@ -0,0 +1,1515 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + + +#include <tools/diagnose_ex.h> +#include <sal/log.hxx> + +#include <animationfactory.hxx> +#include <attributemap.hxx> + +#include <com/sun/star/animations/AnimationAdditiveMode.hpp> +#include <com/sun/star/animations/AnimationTransformType.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/awt/FontSlant.hpp> + +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> + +#include <box2dtools.hxx> + +using namespace ::com::sun::star; + + +namespace slideshow::internal +{ + namespace + { + // attention, there is a similar implementation of Animation in + // transitions/transitionfactory.cxx + + template< typename ValueT > class TupleAnimation : public PairAnimation + { + public: + TupleAnimation( const ShapeManagerSharedPtr& rShapeManager, + int nFlags, + bool (ShapeAttributeLayer::*pIs1stValid)() const, + bool (ShapeAttributeLayer::*pIs2ndValid)() const, + const ValueT& rDefaultValue, + const ::basegfx::B2DSize& rReferenceSize, + double (ShapeAttributeLayer::*pGet1stValue)() const, + double (ShapeAttributeLayer::*pGet2ndValue)() const, + void (ShapeAttributeLayer::*pSetValue)( const ValueT& ) ) : + mpShape(), + mpAttrLayer(), + mpShapeManager( rShapeManager ), + mpIs1stValidFunc(pIs1stValid), + mpIs2ndValidFunc(pIs2ndValid), + mpGet1stValueFunc(pGet1stValue), + mpGet2ndValueFunc(pGet2ndValue), + mpSetValueFunc(pSetValue), + mnFlags( nFlags ), + maReferenceSize( rReferenceSize ), + maDefaultValue( rDefaultValue ), + mbAnimationStarted( false ) + { + ENSURE_OR_THROW( rShapeManager, + "TupleAnimation::TupleAnimation(): Invalid ShapeManager" ); + ENSURE_OR_THROW( pIs1stValid && pIs2ndValid && pGet1stValue && pGet2ndValue && pSetValue, + "TupleAnimation::TupleAnimation(): One of the method pointers is NULL" ); + } + + virtual ~TupleAnimation() override + { + end_(); + } + + // Animation interface + + virtual void prefetch() override + {} + + virtual void start( const AnimatableShapeSharedPtr& rShape, + const ShapeAttributeLayerSharedPtr& rAttrLayer ) override + { + OSL_ENSURE( !mpShape, + "TupleAnimation::start(): Shape already set" ); + OSL_ENSURE( !mpAttrLayer, + "TupleAnimation::start(): Attribute layer already set" ); + + mpShape = rShape; + mpAttrLayer = rAttrLayer; + + ENSURE_OR_THROW( rShape, + "TupleAnimation::start(): Invalid shape" ); + ENSURE_OR_THROW( rAttrLayer, + "TupleAnimation::start(): Invalid attribute layer" ); + + if( !mbAnimationStarted ) + { + mbAnimationStarted = true; + + if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) + mpShapeManager->enterAnimationMode( mpShape ); + } + } + + virtual void end() override { end_(); } + void end_() + { + if( mbAnimationStarted ) + { + mbAnimationStarted = false; + + if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) + mpShapeManager->leaveAnimationMode( mpShape ); + + if( mpShape->isContentChanged() ) + mpShapeManager->notifyShapeUpdate( mpShape ); + } + } + + // PairAnimation interface + + + virtual bool operator()( const ::basegfx::B2DTuple& rValue ) override + { + ENSURE_OR_RETURN_FALSE( mpAttrLayer && mpShape, + "TupleAnimation::operator(): Invalid ShapeAttributeLayer" ); + + ValueT aValue( rValue.getX(), + rValue.getY() ); + + // Activities get values from the expression parser, + // which returns _relative_ sizes/positions. + // Convert back relative to reference coordinate system + aValue *= maReferenceSize; + + ((*mpAttrLayer).*mpSetValueFunc)( aValue ); + + if( mpShape->isContentChanged() ) + mpShapeManager->notifyShapeUpdate( mpShape ); + + return true; + } + + virtual ::basegfx::B2DTuple getUnderlyingValue() const override + { + ENSURE_OR_THROW( mpAttrLayer, + "TupleAnimation::getUnderlyingValue(): Invalid ShapeAttributeLayer" ); + + ::basegfx::B2DTuple aRetVal; + + // deviated from the (*shared_ptr).*mpFuncPtr + // notation here, since gcc does not seem to parse + // that as a member function call anymore. + aRetVal.setX( (mpAttrLayer.get()->*mpIs1stValidFunc)() ? + (mpAttrLayer.get()->*mpGet1stValueFunc)() : + maDefaultValue.getX() ); + aRetVal.setY( (mpAttrLayer.get()->*mpIs2ndValidFunc)() ? + (mpAttrLayer.get()->*mpGet2ndValueFunc)() : + maDefaultValue.getY() ); + + // Activities get values from the expression + // parser, which returns _relative_ + // sizes/positions. Convert start value to the + // same coordinate space (i.e. relative to given + // reference size). + aRetVal /= maReferenceSize; + + return aRetVal; + } + + private: + AnimatableShapeSharedPtr mpShape; + ShapeAttributeLayerSharedPtr mpAttrLayer; + ShapeManagerSharedPtr mpShapeManager; + bool (ShapeAttributeLayer::*mpIs1stValidFunc)() const; + bool (ShapeAttributeLayer::*mpIs2ndValidFunc)() const; + double (ShapeAttributeLayer::*mpGet1stValueFunc)() const; + double (ShapeAttributeLayer::*mpGet2ndValueFunc)() const; + void (ShapeAttributeLayer::*mpSetValueFunc)( const ValueT& ); + + const int mnFlags; + + const ::basegfx::B2DSize maReferenceSize; + const ValueT maDefaultValue; + bool mbAnimationStarted; + }; + + + class PathAnimation : public NumberAnimation + { + public: + PathAnimation( std::u16string_view rSVGDPath, + sal_Int16 nAdditive, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& rSlideSize, + int nFlags, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld ) : + maPathPoly(), + mpShape(), + mpAttrLayer(), + mpShapeManager( rShapeManager ), + maPageSize( rSlideSize ), + maShapeOrig(), + mnFlags( nFlags ), + mbAnimationStarted( false ), + mbAnimationFirstUpdate( true ), + mnAdditive( nAdditive ), + mpBox2DWorld( pBox2DWorld ) + { + ENSURE_OR_THROW( rShapeManager, + "PathAnimation::PathAnimation(): Invalid ShapeManager" ); + + ::basegfx::B2DPolyPolygon aPolyPoly; + + ENSURE_OR_THROW( ::basegfx::utils::importFromSvgD( aPolyPoly, rSVGDPath, false, nullptr ), + "PathAnimation::PathAnimation(): failed to parse SVG:d path" ); + ENSURE_OR_THROW( aPolyPoly.count() == 1, + "PathAnimation::PathAnimation(): motion path consists of multiple/zero polygon(s)" ); + + maPathPoly = aPolyPoly.getB2DPolygon(0); + } + + virtual ~PathAnimation() override + { + end_(); + } + + // Animation interface + + virtual void prefetch() override + {} + + virtual void start( const AnimatableShapeSharedPtr& rShape, + const ShapeAttributeLayerSharedPtr& rAttrLayer ) override + { + OSL_ENSURE( !mpShape, + "PathAnimation::start(): Shape already set" ); + OSL_ENSURE( !mpAttrLayer, + "PathAnimation::start(): Attribute layer already set" ); + + mpShape = rShape; + mpAttrLayer = rAttrLayer; + + ENSURE_OR_THROW( rShape, + "PathAnimation::start(): Invalid shape" ); + ENSURE_OR_THROW( rAttrLayer, + "PathAnimation::start(): Invalid attribute layer" ); + + // TODO(F1): Check whether _shape_ bounds are correct here. + // Theoretically, our AttrLayer is way down the stack, and + // we only have to consider _that_ value, not the one from + // the top of the stack as returned by Shape::getBounds() + if( mnAdditive == animations::AnimationAdditiveMode::SUM ) + maShapeOrig = mpShape->getBounds().getCenter(); + else + maShapeOrig = mpShape->getDomBounds().getCenter(); + + if( !mbAnimationStarted ) + { + mbAnimationStarted = true; + + if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) + mpShapeManager->enterAnimationMode( mpShape ); + } + } + + virtual void end() override { end_(); } + void end_() + { + if( !mbAnimationStarted ) + return; + + mbAnimationStarted = false; + + if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) + mpShapeManager->leaveAnimationMode( mpShape ); + + if( mpShape->isContentChanged() ) + mpShapeManager->notifyShapeUpdate( mpShape ); + + // if there is a physics animation going on report the animation ending + // and zero out the velocity of the shape + if( mpBox2DWorld->isInitialized() ) + mpBox2DWorld->queueLinearVelocityUpdate( mpShape->getXShape(), {0,0}); + } + + // NumberAnimation interface + + + virtual bool operator()( double nValue ) override + { + ENSURE_OR_RETURN_FALSE( mpAttrLayer && mpShape, + "PathAnimation::operator(): Invalid ShapeAttributeLayer" ); + + ::basegfx::B2DPoint rOutPos = ::basegfx::utils::getPositionRelative( maPathPoly, + nValue ); + + // TODO(F1): Determine whether the path is + // absolute, or shape-relative. + + // interpret path as page-relative. Scale up with page size + rOutPos *= maPageSize; + + // TODO(F1): Determine whether the path origin is + // absolute, or shape-relative. + + // interpret path as shape-originated. Offset to shape position + + rOutPos += maShapeOrig; + + mpAttrLayer->setPosition( rOutPos ); + + if( mpShape->isContentChanged() ) + { + mpShapeManager->notifyShapeUpdate( mpShape ); + + // if there's a physics animation going on report the change to it + if ( mpBox2DWorld->isInitialized() ) + { + mpBox2DWorld->queueShapePathAnimationUpdate( mpShape->getXShape(), + mpAttrLayer, + mbAnimationFirstUpdate ); + } + } + + if( mbAnimationFirstUpdate ) mbAnimationFirstUpdate = false; + + return true; + } + + virtual double getUnderlyingValue() const override + { + ENSURE_OR_THROW( mpAttrLayer, + "PathAnimation::getUnderlyingValue(): Invalid ShapeAttributeLayer" ); + + return 0.0; // though this should be used in concert with + // ActivitiesFactory::createSimpleActivity, better + // explicitly name our start value. + // Permissible range for operator() above is [0,1] + } + + private: + ::basegfx::B2DPolygon maPathPoly; + AnimatableShapeSharedPtr mpShape; + ShapeAttributeLayerSharedPtr mpAttrLayer; + ShapeManagerSharedPtr mpShapeManager; + const ::basegfx::B2DSize maPageSize; + ::basegfx::B2DPoint maShapeOrig; + const int mnFlags; + bool mbAnimationStarted; + bool mbAnimationFirstUpdate; + sal_Int16 mnAdditive; + box2d::utils::Box2DWorldSharedPtr mpBox2DWorld; + }; + + class PhysicsAnimation : public NumberAnimation + { + public: + PhysicsAnimation( const ::box2d::utils::Box2DWorldSharedPtr& pBox2DWorld, + const double fDuration, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& rSlideSize, + const ::basegfx::B2DVector& rStartVelocity, + const double fDensity, + const double fBounciness, + int nFlags ) : + mpShape(), + mpAttrLayer(), + mpShapeManager( rShapeManager ), + maPageSize( rSlideSize ), + mnFlags( nFlags ), + mbAnimationStarted( false ), + mpBox2DBody(), + mpBox2DWorld( pBox2DWorld ), + mfDuration(fDuration), + maStartVelocity(rStartVelocity), + mfDensity(fDensity), + mfBounciness(fBounciness), + mfPreviousElapsedTime(0.00f), + mbIsBox2dWorldStepper(false) + { + ENSURE_OR_THROW( rShapeManager, + "PhysicsAnimation::PhysicsAnimation(): Invalid ShapeManager" ); + } + + virtual ~PhysicsAnimation() override + { + end_(); + } + + // Animation interface + + virtual void prefetch() override + {} + + virtual void start( const AnimatableShapeSharedPtr& rShape, + const ShapeAttributeLayerSharedPtr& rAttrLayer ) override + { + OSL_ENSURE( !mpShape, + "PhysicsAnimation::start(): Shape already set" ); + OSL_ENSURE( !mpAttrLayer, + "PhysicsAnimation::start(): Attribute layer already set" ); + + mpShape = rShape; + mpAttrLayer = rAttrLayer; + + ENSURE_OR_THROW( rShape, + "PhysicsAnimation::start(): Invalid shape" ); + ENSURE_OR_THROW( rAttrLayer, + "PhysicsAnimation::start(): Invalid attribute layer" ); + + if( !mbAnimationStarted ) + { + mbAnimationStarted = true; + + mpBox2DWorld->alertPhysicsAnimationStart(maPageSize, mpShapeManager); + mpBox2DBody = mpBox2DWorld->makeShapeDynamic( mpShape->getXShape(), maStartVelocity, mfDensity, mfBounciness ); + + if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) + mpShapeManager->enterAnimationMode( mpShape ); + } + } + + virtual void end() override { end_(); } + void end_() + { + if( mbIsBox2dWorldStepper ) + { + mbIsBox2dWorldStepper = false; + mpBox2DWorld->setHasWorldStepper(false); + } + + if( !mbAnimationStarted ) + return; + + mbAnimationStarted = false; + + if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) + mpShapeManager->leaveAnimationMode( mpShape ); + + if( mpShape->isContentChanged() ) + mpShapeManager->notifyShapeUpdate( mpShape ); + + mpBox2DWorld->alertPhysicsAnimationEnd(mpShape); + // if this was the only physics animation effect going on + // all box2d bodies were destroyed on alertPhysicsAnimationEnd + // except the one owned by the animation. + // Try to destroy the remaining body - if it is unique + // (it being unique means all physics animation effects have ended + // since otherwise mpBox2DWorld would own a copy of the shared_ptr ) + mpBox2DBody.reset(); + + } + + // NumberAnimation interface + + + virtual bool operator()( double nValue ) override + { + ENSURE_OR_RETURN_FALSE( mpAttrLayer && mpShape, + "PhysicsAnimation::operator(): Invalid ShapeAttributeLayer" ); + + // if there are multiple physics animations going in parallel + // Only one of them should step the box2d world + if( !mpBox2DWorld->hasWorldStepper() ) + { + mbIsBox2dWorldStepper = true; + mpBox2DWorld->setHasWorldStepper(true); + } + + if( mbIsBox2dWorldStepper ) + { + double fPassedTime = (mfDuration * nValue) - mfPreviousElapsedTime; + mfPreviousElapsedTime += mpBox2DWorld->stepAmount( fPassedTime ); + } + + mpAttrLayer->setPosition( mpBox2DBody->getPosition() ); + mpAttrLayer->setRotationAngle( mpBox2DBody->getAngle() ); + + if( mpShape->isContentChanged() ) + mpShapeManager->notifyShapeUpdate( mpShape ); + + return true; + } + + virtual double getUnderlyingValue() const override + { + ENSURE_OR_THROW( mpAttrLayer, + "PhysicsAnimation::getUnderlyingValue(): Invalid ShapeAttributeLayer" ); + + return 0.0; + } + + private: + AnimatableShapeSharedPtr mpShape; + ShapeAttributeLayerSharedPtr mpAttrLayer; + ShapeManagerSharedPtr mpShapeManager; + const ::basegfx::B2DSize maPageSize; + const int mnFlags; + bool mbAnimationStarted; + box2d::utils::Box2DBodySharedPtr mpBox2DBody; + box2d::utils::Box2DWorldSharedPtr mpBox2DWorld; + double mfDuration; + const ::basegfx::B2DVector maStartVelocity; + const double mfDensity; + const double mfBounciness; + double mfPreviousElapsedTime; + bool mbIsBox2dWorldStepper; + }; + + /** GenericAnimation template + + This template makes heavy use of SFINAE, only one of + the operator()() methods will compile for each of the + base classes. + + Note that we omit the virtual keyword on the + operator()() overrides and getUnderlyingValue() methods on + purpose; those that actually do override baseclass + virtual methods inherit the property, and the others + won't increase our vtable. What's more, having all + those methods in the vtable actually creates POIs for + them, which breaks the whole SFINAE concept (IOW, this + template won't compile any longer). + + @tpl AnimationBase + Type of animation to generate (determines the + interface GenericAnimation will implement). Must be + one of NumberAnimation, ColorAnimation, + StringAnimation, PairAnimation or BoolAnimation. + + @tpl ModifierFunctor + Type of a functor object, which can optionally be used to + modify the getter/setter values. + */ + template< typename AnimationBase, typename ModifierFunctor > class GenericAnimation : public AnimationBase + { + public: + typedef typename AnimationBase::ValueType ValueT; + + /** Create generic animation + + @param pIsValid + Function pointer to one of the is*Valid + methods. Used to either take the given getter + method, or the given default value for the start value. + + @param rDefaultValue + Default value, to take as the start value if + is*Valid returns false. + + @param pGetValue + Getter method, to fetch start value if valid. + + @param pSetValue + Setter method. This one puts the current animation + value to the ShapeAttributeLayer. + + @param rGetterModifier + Modifies up values retrieved from the pGetValue method. + Must provide operator()( const ValueT& ) method. + + @param rSetterModifier + Modifies up values before passing them to the pSetValue method. + Must provide operator()( const ValueT& ) method. + */ + GenericAnimation( const ShapeManagerSharedPtr& rShapeManager, + int nFlags, + bool (ShapeAttributeLayer::*pIsValid)() const, + const ValueT& rDefaultValue, + ValueT (ShapeAttributeLayer::*pGetValue)() const, + void (ShapeAttributeLayer::*pSetValue)( const ValueT& ), + const ModifierFunctor& rGetterModifier, + const ModifierFunctor& rSetterModifier, + const AttributeType eAttrType, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld ) : + mpShape(), + mpAttrLayer(), + mpShapeManager( rShapeManager ), + mpIsValidFunc(pIsValid), + mpGetValueFunc(pGetValue), + mpSetValueFunc(pSetValue), + maGetterModifier( rGetterModifier ), + maSetterModifier( rSetterModifier ), + mnFlags( nFlags ), + maDefaultValue(rDefaultValue), + mbAnimationStarted( false ), + mbAnimationFirstUpdate( true ), + meAttrType( eAttrType ), + mpBox2DWorld ( pBox2DWorld ) + { + ENSURE_OR_THROW( rShapeManager, + "GenericAnimation::GenericAnimation(): Invalid ShapeManager" ); + ENSURE_OR_THROW( pIsValid && pGetValue && pSetValue, + "GenericAnimation::GenericAnimation(): One of the method pointers is NULL" ); + } + + ~GenericAnimation() + { + end(); + } + + // Animation interface + + virtual void prefetch() + {} + + virtual void start( const AnimatableShapeSharedPtr& rShape, + const ShapeAttributeLayerSharedPtr& rAttrLayer ) + { + OSL_ENSURE( !mpShape, + "GenericAnimation::start(): Shape already set" ); + OSL_ENSURE( !mpAttrLayer, + "GenericAnimation::start(): Attribute layer already set" ); + + mpShape = rShape; + mpAttrLayer = rAttrLayer; + + ENSURE_OR_THROW( rShape, + "GenericAnimation::start(): Invalid shape" ); + ENSURE_OR_THROW( rAttrLayer, + "GenericAnimation::start(): Invalid attribute layer" ); + + // only start animation once per repeated start() call, + // and only if sprites should be used for display + if( !mbAnimationStarted ) + { + mbAnimationStarted = true; + + if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) + mpShapeManager->enterAnimationMode( mpShape ); + } + } + + void end() + { + // TODO(Q2): Factor out common code (most + // prominently start() and end()) into base class + + // only stop animation once per repeated end() call, + // and only if sprites are used for display + if( !mbAnimationStarted ) + return; + + mbAnimationStarted = false; + + if( mpBox2DWorld && mpBox2DWorld->isInitialized() ) + { + // if there's a physics animation going on report the animation ending to it + mpBox2DWorld->queueShapeAnimationEndUpdate( mpShape->getXShape(), meAttrType ); + } + + if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) + mpShapeManager->leaveAnimationMode( mpShape ); + + // Attention, this notifyShapeUpdate() is + // somewhat delicate here. Calling it + // unconditional (i.e. not guarded by + // mbAnimationStarted) will lead to shapes + // snapping back to their original state just + // before the slide ends. Not calling it at + // all might swallow final animation + // states. The current implementation relies + // on the fact that end() is either called by + // the Activity (then, the last animation + // state has been set, and corresponds to the + // shape's hold state), or by the animation + // node (then, it's a forced end, and we + // _have_ to snap back). + + // To reiterate: normally, we're called from + // the Activity first, thus the + // notifyShapeUpdate() below will update to + // the last activity value. + + // force shape update, activity might have changed + // state in the last round. + if( mpShape->isContentChanged() ) + mpShapeManager->notifyShapeUpdate( mpShape ); + } + + // Derived Animation interface + + + /** For by-reference interfaces (B2DTuple, OUString) + */ + bool operator()( const ValueT& x ) + { + ENSURE_OR_RETURN_FALSE( mpAttrLayer && mpShape, + "GenericAnimation::operator(): Invalid ShapeAttributeLayer" ); + + ((*mpAttrLayer).*mpSetValueFunc)( maSetterModifier( x ) ); + + if( mpShape->isContentChanged() ) + mpShapeManager->notifyShapeUpdate( mpShape ); + + if( mbAnimationFirstUpdate ) mbAnimationFirstUpdate = false; + + return true; + } + + /** For by-value interfaces (bool, double) + */ + bool operator()( ValueT x ) + { + ENSURE_OR_RETURN_FALSE( mpAttrLayer && mpShape, + "GenericAnimation::operator(): Invalid ShapeAttributeLayer" ); + + ((*mpAttrLayer).*mpSetValueFunc)( maSetterModifier( x ) ); + + if( mpBox2DWorld && mpBox2DWorld->isInitialized() ) + { + // if there's a physics animation going on report the change to it + mpBox2DWorld->queueShapeAnimationUpdate( mpShape->getXShape(), mpAttrLayer, meAttrType, mbAnimationFirstUpdate ); + } + + if( mpShape->isContentChanged() ) + mpShapeManager->notifyShapeUpdate( mpShape ); + + if( mbAnimationFirstUpdate ) mbAnimationFirstUpdate = false; + + return true; + } + + ValueT getUnderlyingValue() const + { + ENSURE_OR_THROW( mpAttrLayer, + "GenericAnimation::getUnderlyingValue(): Invalid ShapeAttributeLayer" ); + + // deviated from the (*shared_ptr).*mpFuncPtr + // notation here, since gcc does not seem to parse + // that as a member function call anymore. + if( (mpAttrLayer.get()->*mpIsValidFunc)() ) + return maGetterModifier( ((*mpAttrLayer).*mpGetValueFunc)() ); + else + return maDefaultValue; + } + + private: + AnimatableShapeSharedPtr mpShape; + ShapeAttributeLayerSharedPtr mpAttrLayer; + ShapeManagerSharedPtr mpShapeManager; + bool (ShapeAttributeLayer::*mpIsValidFunc)() const; + ValueT (ShapeAttributeLayer::*mpGetValueFunc)() const; + void (ShapeAttributeLayer::*mpSetValueFunc)( const ValueT& ); + + ModifierFunctor maGetterModifier; + ModifierFunctor maSetterModifier; + + const int mnFlags; + + const ValueT maDefaultValue; + bool mbAnimationStarted; + bool mbAnimationFirstUpdate; + + const AttributeType meAttrType; + const box2d::utils::Box2DWorldSharedPtr mpBox2DWorld; + }; + + //Current c++0x draft (apparently) has std::identity, but not operator() + template<typename T> struct SGI_identity + { + T& operator()(T& x) const { return x; } + const T& operator()(const T& x) const { return x; } + }; + + /** Function template wrapper around GenericAnimation template + + @tpl AnimationBase + Type of animation to generate (determines the + interface GenericAnimation will implement). + */ + template< typename AnimationBase > ::std::shared_ptr< AnimationBase > + makeGenericAnimation( const ShapeManagerSharedPtr& rShapeManager, + int nFlags, + bool (ShapeAttributeLayer::*pIsValid)() const, + const typename AnimationBase::ValueType& rDefaultValue, + typename AnimationBase::ValueType (ShapeAttributeLayer::*pGetValue)() const, + void (ShapeAttributeLayer::*pSetValue)( const typename AnimationBase::ValueType& ), + const AttributeType eAttrType, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld ) + { + return std::make_shared<GenericAnimation< AnimationBase, + SGI_identity< typename AnimationBase::ValueType > >>( + rShapeManager, + nFlags, + pIsValid, + rDefaultValue, + pGetValue, + pSetValue, + // no modification necessary, use identity functor here + SGI_identity< typename AnimationBase::ValueType >(), + SGI_identity< typename AnimationBase::ValueType >(), + eAttrType, + pBox2DWorld ); + } + + class Scaler + { + public: + explicit Scaler( double nScale ) : + mnScale( nScale ) + { + } + + double operator()( double nVal ) const + { + return mnScale * nVal; + } + + private: + double mnScale; + }; + + /** Overload for NumberAnimations which need scaling (width,height,x,y currently) + */ + NumberAnimationSharedPtr makeGenericAnimation( const ShapeManagerSharedPtr& rShapeManager, + int nFlags, + bool (ShapeAttributeLayer::*pIsValid)() const, + double nDefaultValue, + double (ShapeAttributeLayer::*pGetValue)() const, + void (ShapeAttributeLayer::*pSetValue)( const double& ), + double nScaleValue, + const AttributeType eAttrType, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld ) + { + return std::make_shared<GenericAnimation< NumberAnimation, Scaler >>( rShapeManager, + nFlags, + pIsValid, + nDefaultValue / nScaleValue, + pGetValue, + pSetValue, + Scaler( 1.0/nScaleValue ), + Scaler( nScaleValue ), + eAttrType, + pBox2DWorld ); + } + + + uno::Any getShapeDefault( const AnimatableShapeSharedPtr& rShape, + const OUString& rPropertyName ) + { + uno::Reference< drawing::XShape > xShape( rShape->getXShape() ); + + if( !xShape.is() ) + return uno::Any(); // no regular shape, no defaults available + + + // extract relevant value from XShape's PropertySet + uno::Reference< beans::XPropertySet > xPropSet( xShape, + uno::UNO_QUERY ); + + ENSURE_OR_THROW( xPropSet.is(), + "getShapeDefault(): Cannot query property set from shape" ); + + return xPropSet->getPropertyValue( rPropertyName ); + } + + template< typename ValueType > ValueType getDefault( const AnimatableShapeSharedPtr& rShape, + const OUString& rPropertyName ) + { + const uno::Any& rAny( getShapeDefault( rShape, + rPropertyName ) ); + + if( !rAny.hasValue() ) + { + SAL_WARN("slideshow", "getDefault(): cannot get shape property " << rPropertyName ); + return ValueType(); + } + else + { + ValueType aValue = ValueType(); + + if( !(rAny >>= aValue) ) + { + SAL_WARN("slideshow", "getDefault(): cannot extract shape property " << rPropertyName); + return ValueType(); + } + + return aValue; + } + } + + template<> RGBColor getDefault< RGBColor >( const AnimatableShapeSharedPtr& rShape, + const OUString& rPropertyName ) + { + const uno::Any& rAny( getShapeDefault( rShape, + rPropertyName ) ); + + if( !rAny.hasValue() ) + { + SAL_WARN("slideshow", "getDefault(): cannot get shape color property " << rPropertyName); + return RGBColor(); + } + else + { + sal_Int32 nValue = 0; + + if( !(rAny >>= nValue) ) + { + SAL_INFO("slideshow", "getDefault(): cannot extract shape color property " << rPropertyName); + return RGBColor(); + } + + // convert from 0xAARRGGBB API color to 0xRRGGBB00 + // canvas color + return RGBColor( (nValue << 8U) & 0xFFFFFF00U ); + } + } + } + + AnimationFactory::AttributeClass AnimationFactory::classifyAttributeName( const OUString& rAttrName ) + { + // ATTENTION: When changing this map, also the create*PropertyAnimation() methods must + // be checked and possibly adapted in their switch statements + + // TODO(Q2): Since this map must be coherent with the various switch statements + // in the create*PropertyAnimation methods, try to unify into a single method or table + switch( mapAttributeName( rAttrName ) ) + { + default: + case AttributeType::Invalid: + return CLASS_UNKNOWN_PROPERTY; + + case AttributeType::CharColor: + case AttributeType::Color: + case AttributeType::DimColor: + case AttributeType::FillColor: + case AttributeType::LineColor: + return CLASS_COLOR_PROPERTY; + + case AttributeType::CharFontName: + return CLASS_STRING_PROPERTY; + + case AttributeType::Visibility: + return CLASS_BOOL_PROPERTY; + + case AttributeType::CharHeight: + case AttributeType::CharWeight: + case AttributeType::Height: + case AttributeType::Opacity: + case AttributeType::Rotate: + case AttributeType::SkewX: + case AttributeType::SkewY: + case AttributeType::Width: + case AttributeType::PosX: + case AttributeType::PosY: + return CLASS_NUMBER_PROPERTY; + + case AttributeType::CharUnderline: + case AttributeType::FillStyle: + case AttributeType::LineStyle: + case AttributeType::CharPosture: + return CLASS_ENUM_PROPERTY; + } + } + + NumberAnimationSharedPtr AnimationFactory::createNumberPropertyAnimation( const OUString& rAttrName, + const AnimatableShapeSharedPtr& rShape, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& rSlideSize, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld, + int nFlags ) + { + // ATTENTION: When changing this map, also the classifyAttributeName() method must + // be checked and possibly adapted in their switch statement + AttributeType eAttrType = mapAttributeName(rAttrName); + switch( eAttrType ) + { + default: + case AttributeType::Invalid: + ENSURE_OR_THROW( false, + "AnimationFactory::createNumberPropertyAnimation(): Unknown attribute" ); + break; + + case AttributeType::CharColor: + case AttributeType::CharFontName: + case AttributeType::CharPosture: + case AttributeType::CharUnderline: + case AttributeType::Color: + case AttributeType::DimColor: + case AttributeType::FillColor: + case AttributeType::FillStyle: + case AttributeType::LineColor: + case AttributeType::LineStyle: + case AttributeType::Visibility: + ENSURE_OR_THROW( false, + "AnimationFactory::createNumberPropertyAnimation(): Attribute type mismatch" ); + break; + + case AttributeType::CharHeight: + return makeGenericAnimation<NumberAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isCharScaleValid, + 1.0, // CharHeight is a relative attribute, thus + // default is 1.0 + &ShapeAttributeLayer::getCharScale, + &ShapeAttributeLayer::setCharScale, + eAttrType, + pBox2DWorld ); + + case AttributeType::CharWeight: + return makeGenericAnimation<NumberAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isCharWeightValid, + getDefault<double>( rShape, rAttrName ), + &ShapeAttributeLayer::getCharWeight, + &ShapeAttributeLayer::setCharWeight, + eAttrType, + pBox2DWorld ); + + case AttributeType::Height: + return makeGenericAnimation( rShapeManager, + nFlags, + &ShapeAttributeLayer::isHeightValid, + // TODO(F1): Check whether _shape_ bounds are correct here. + // Theoretically, our AttrLayer is way down the stack, and + // we only have to consider _that_ value, not the one from + // the top of the stack as returned by Shape::getBounds() + rShape->getBounds().getHeight(), + &ShapeAttributeLayer::getHeight, + &ShapeAttributeLayer::setHeight, + // convert expression parser value from relative page size + rSlideSize.getY(), + eAttrType, + pBox2DWorld ); + + case AttributeType::Opacity: + return makeGenericAnimation<NumberAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isAlphaValid, + // TODO(F1): Provide shape default here (FillTransparency?) + 1.0, + &ShapeAttributeLayer::getAlpha, + &ShapeAttributeLayer::setAlpha, + eAttrType, + pBox2DWorld ); + + case AttributeType::Rotate: + return makeGenericAnimation<NumberAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isRotationAngleValid, + // NOTE: Since we paint the shape as-is from metafile, + // rotation angle is always 0.0, even for rotated shapes + 0.0, + &ShapeAttributeLayer::getRotationAngle, + &ShapeAttributeLayer::setRotationAngle, + eAttrType, + pBox2DWorld ); + + case AttributeType::SkewX: + return makeGenericAnimation<NumberAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isShearXAngleValid, + // TODO(F1): Is there any shape property for skew? + 0.0, + &ShapeAttributeLayer::getShearXAngle, + &ShapeAttributeLayer::setShearXAngle, + eAttrType, + pBox2DWorld ); + + case AttributeType::SkewY: + return makeGenericAnimation<NumberAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isShearYAngleValid, + // TODO(F1): Is there any shape property for skew? + 0.0, + &ShapeAttributeLayer::getShearYAngle, + &ShapeAttributeLayer::setShearYAngle, + eAttrType, + pBox2DWorld ); + + case AttributeType::Width: + return makeGenericAnimation( rShapeManager, + nFlags, + &ShapeAttributeLayer::isWidthValid, + // TODO(F1): Check whether _shape_ bounds are correct here. + // Theoretically, our AttrLayer is way down the stack, and + // we only have to consider _that_ value, not the one from + // the top of the stack as returned by Shape::getBounds() + rShape->getBounds().getWidth(), + &ShapeAttributeLayer::getWidth, + &ShapeAttributeLayer::setWidth, + // convert expression parser value from relative page size + rSlideSize.getX(), + eAttrType, + pBox2DWorld ); + + case AttributeType::PosX: + return makeGenericAnimation( rShapeManager, + nFlags, + &ShapeAttributeLayer::isPosXValid, + // TODO(F1): Check whether _shape_ bounds are correct here. + // Theoretically, our AttrLayer is way down the stack, and + // we only have to consider _that_ value, not the one from + // the top of the stack as returned by Shape::getBounds() + rShape->getBounds().getCenterX(), + &ShapeAttributeLayer::getPosX, + &ShapeAttributeLayer::setPosX, + // convert expression parser value from relative page size + rSlideSize.getX(), + eAttrType, + pBox2DWorld ); + + case AttributeType::PosY: + return makeGenericAnimation( rShapeManager, + nFlags, + &ShapeAttributeLayer::isPosYValid, + // TODO(F1): Check whether _shape_ bounds are correct here. + // Theoretically, our AttrLayer is way down the stack, and + // we only have to consider _that_ value, not the one from + // the top of the stack as returned by Shape::getBounds() + rShape->getBounds().getCenterY(), + &ShapeAttributeLayer::getPosY, + &ShapeAttributeLayer::setPosY, + // convert expression parser value from relative page size + rSlideSize.getY(), + eAttrType, + pBox2DWorld ); + } + + return NumberAnimationSharedPtr(); + } + + EnumAnimationSharedPtr AnimationFactory::createEnumPropertyAnimation( const OUString& rAttrName, + const AnimatableShapeSharedPtr& rShape, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& /*rSlideSize*/, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld, + int nFlags ) + { + // ATTENTION: When changing this map, also the classifyAttributeName() method must + // be checked and possibly adapted in their switch statement + AttributeType eAttrType = mapAttributeName( rAttrName ); + switch( eAttrType ) + { + default: + case AttributeType::Invalid: + ENSURE_OR_THROW( false, + "AnimationFactory::createEnumPropertyAnimation(): Unknown attribute" ); + break; + + case AttributeType::CharColor: + case AttributeType::CharFontName: + case AttributeType::Color: + case AttributeType::DimColor: + case AttributeType::FillColor: + case AttributeType::LineColor: + case AttributeType::Visibility: + case AttributeType::CharHeight: + case AttributeType::CharWeight: + case AttributeType::Height: + case AttributeType::Opacity: + case AttributeType::Rotate: + case AttributeType::SkewX: + case AttributeType::SkewY: + case AttributeType::Width: + case AttributeType::PosX: + case AttributeType::PosY: + ENSURE_OR_THROW( false, + "AnimationFactory::createEnumPropertyAnimation(): Attribute type mismatch" ); + break; + + + case AttributeType::FillStyle: + return makeGenericAnimation<EnumAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isFillStyleValid, + sal::static_int_cast<sal_Int16>( + getDefault<drawing::FillStyle>( rShape, rAttrName )), + &ShapeAttributeLayer::getFillStyle, + &ShapeAttributeLayer::setFillStyle, + eAttrType, + pBox2DWorld ); + + case AttributeType::LineStyle: + return makeGenericAnimation<EnumAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isLineStyleValid, + sal::static_int_cast<sal_Int16>( + getDefault<drawing::LineStyle>( rShape, rAttrName )), + &ShapeAttributeLayer::getLineStyle, + &ShapeAttributeLayer::setLineStyle, + eAttrType, + pBox2DWorld ); + + case AttributeType::CharPosture: + return makeGenericAnimation<EnumAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isCharPostureValid, + sal::static_int_cast<sal_Int16>( + getDefault<awt::FontSlant>( rShape, rAttrName )), + &ShapeAttributeLayer::getCharPosture, + &ShapeAttributeLayer::setCharPosture, + eAttrType, + pBox2DWorld ); + + case AttributeType::CharUnderline: + return makeGenericAnimation<EnumAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isUnderlineModeValid, + getDefault<sal_Int16>( rShape, rAttrName ), + &ShapeAttributeLayer::getUnderlineMode, + &ShapeAttributeLayer::setUnderlineMode, + eAttrType, + pBox2DWorld ); + } + + return EnumAnimationSharedPtr(); + } + + ColorAnimationSharedPtr AnimationFactory::createColorPropertyAnimation( const OUString& rAttrName, + const AnimatableShapeSharedPtr& rShape, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& /*rSlideSize*/, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld, + int nFlags ) + { + // ATTENTION: When changing this map, also the classifyAttributeName() method must + // be checked and possibly adapted in their switch statement + AttributeType eAttrType = mapAttributeName(rAttrName); + switch( eAttrType ) + { + default: + case AttributeType::Invalid: + ENSURE_OR_THROW( false, + "AnimationFactory::createColorPropertyAnimation(): Unknown attribute" ); + break; + + case AttributeType::CharFontName: + case AttributeType::CharHeight: + case AttributeType::CharPosture: + case AttributeType::CharUnderline: + case AttributeType::CharWeight: + case AttributeType::FillStyle: + case AttributeType::Height: + case AttributeType::LineStyle: + case AttributeType::Opacity: + case AttributeType::Rotate: + case AttributeType::SkewX: + case AttributeType::SkewY: + case AttributeType::Visibility: + case AttributeType::Width: + case AttributeType::PosX: + case AttributeType::PosY: + ENSURE_OR_THROW( false, + "AnimationFactory::createColorPropertyAnimation(): Attribute type mismatch" ); + break; + + case AttributeType::CharColor: + return makeGenericAnimation<ColorAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isCharColorValid, + getDefault<RGBColor>( rShape, rAttrName ), + &ShapeAttributeLayer::getCharColor, + &ShapeAttributeLayer::setCharColor, + eAttrType, + pBox2DWorld ); + + case AttributeType::Color: + // TODO(F2): This is just mapped to fill color to make it work + return makeGenericAnimation<ColorAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isFillColorValid, + getDefault<RGBColor>( rShape, rAttrName ), + &ShapeAttributeLayer::getFillColor, + &ShapeAttributeLayer::setFillColor, + eAttrType, + pBox2DWorld ); + + case AttributeType::DimColor: + return makeGenericAnimation<ColorAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isDimColorValid, + getDefault<RGBColor>( rShape, rAttrName ), + &ShapeAttributeLayer::getDimColor, + &ShapeAttributeLayer::setDimColor, + eAttrType, + pBox2DWorld ); + + case AttributeType::FillColor: + return makeGenericAnimation<ColorAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isFillColorValid, + getDefault<RGBColor>( rShape, rAttrName ), + &ShapeAttributeLayer::getFillColor, + &ShapeAttributeLayer::setFillColor, + eAttrType, + pBox2DWorld ); + + case AttributeType::LineColor: + return makeGenericAnimation<ColorAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isLineColorValid, + getDefault<RGBColor>( rShape, rAttrName ), + &ShapeAttributeLayer::getLineColor, + &ShapeAttributeLayer::setLineColor, + eAttrType, + pBox2DWorld ); + } + + return ColorAnimationSharedPtr(); + } + + PairAnimationSharedPtr AnimationFactory::createPairPropertyAnimation( const AnimatableShapeSharedPtr& rShape, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& rSlideSize, + sal_Int16 nTransformType, + int nFlags ) + { + const ::basegfx::B2DRectangle& rBounds( rShape->getBounds() ); + + switch( nTransformType ) + { + case animations::AnimationTransformType::SCALE: + return std::make_shared<TupleAnimation< ::basegfx::B2DSize >>( + rShapeManager, + nFlags, + &ShapeAttributeLayer::isWidthValid, + &ShapeAttributeLayer::isHeightValid, + // TODO(F1): Check whether _shape_ bounds are correct here. + // Theoretically, our AttrLayer is way down the stack, and + // we only have to consider _that_ value, not the one from + // the top of the stack as returned by Shape::getBounds() + rBounds.getRange(), + rBounds.getRange(), + &ShapeAttributeLayer::getWidth, + &ShapeAttributeLayer::getHeight, + &ShapeAttributeLayer::setSize ); + + case animations::AnimationTransformType::TRANSLATE: + return std::make_shared<TupleAnimation< ::basegfx::B2DPoint >>( + rShapeManager, + nFlags, + &ShapeAttributeLayer::isPosXValid, + &ShapeAttributeLayer::isPosYValid, + // TODO(F1): Check whether _shape_ bounds are correct here. + // Theoretically, our AttrLayer is way down the stack, and + // we only have to consider _that_ value, not the one from + // the top of the stack as returned by Shape::getBounds() + rBounds.getCenter(), + rSlideSize, + &ShapeAttributeLayer::getPosX, + &ShapeAttributeLayer::getPosY, + &ShapeAttributeLayer::setPosition ); + + default: + ENSURE_OR_THROW( false, + "AnimationFactory::createPairPropertyAnimation(): Attribute type mismatch" ); + break; + } + + return PairAnimationSharedPtr(); + } + + StringAnimationSharedPtr AnimationFactory::createStringPropertyAnimation( const OUString& rAttrName, + const AnimatableShapeSharedPtr& rShape, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& /*rSlideSize*/, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld, + int nFlags ) + { + // ATTENTION: When changing this map, also the classifyAttributeName() method must + // be checked and possibly adapted in their switch statement + AttributeType eAttrType = mapAttributeName(rAttrName); + switch( eAttrType ) + { + default: + case AttributeType::Invalid: + ENSURE_OR_THROW( false, + "AnimationFactory::createStringPropertyAnimation(): Unknown attribute" ); + break; + + case AttributeType::CharColor: + case AttributeType::CharHeight: + case AttributeType::CharUnderline: + case AttributeType::Color: + case AttributeType::DimColor: + case AttributeType::FillColor: + case AttributeType::Height: + case AttributeType::LineColor: + case AttributeType::Opacity: + case AttributeType::Rotate: + case AttributeType::SkewX: + case AttributeType::SkewY: + case AttributeType::Visibility: + case AttributeType::Width: + case AttributeType::PosX: + case AttributeType::PosY: + case AttributeType::CharPosture: + case AttributeType::CharWeight: + case AttributeType::FillStyle: + case AttributeType::LineStyle: + ENSURE_OR_THROW( false, + "AnimationFactory::createStringPropertyAnimation(): Attribute type mismatch" ); + break; + + case AttributeType::CharFontName: + return makeGenericAnimation<StringAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isFontFamilyValid, + getDefault< OUString >( rShape, rAttrName ), + &ShapeAttributeLayer::getFontFamily, + &ShapeAttributeLayer::setFontFamily, + eAttrType, + pBox2DWorld ); + } + + return StringAnimationSharedPtr(); + } + + BoolAnimationSharedPtr AnimationFactory::createBoolPropertyAnimation( const OUString& rAttrName, + const AnimatableShapeSharedPtr& /*rShape*/, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& /*rSlideSize*/, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld, + int nFlags ) + { + // ATTENTION: When changing this map, also the classifyAttributeName() method must + // be checked and possibly adapted in their switch statement + AttributeType eAttrType = mapAttributeName(rAttrName); + switch( eAttrType ) + { + default: + case AttributeType::Invalid: + ENSURE_OR_THROW( false, + "AnimationFactory::createBoolPropertyAnimation(): Unknown attribute" ); + break; + + case AttributeType::CharColor: + case AttributeType::CharFontName: + case AttributeType::CharHeight: + case AttributeType::CharPosture: + case AttributeType::CharWeight: + case AttributeType::Color: + case AttributeType::DimColor: + case AttributeType::FillColor: + case AttributeType::FillStyle: + case AttributeType::Height: + case AttributeType::LineColor: + case AttributeType::LineStyle: + case AttributeType::Opacity: + case AttributeType::Rotate: + case AttributeType::SkewX: + case AttributeType::SkewY: + case AttributeType::Width: + case AttributeType::PosX: + case AttributeType::PosY: + case AttributeType::CharUnderline: + ENSURE_OR_THROW( false, + "AnimationFactory::createBoolPropertyAnimation(): Attribute type mismatch" ); + break; + + case AttributeType::Visibility: + return makeGenericAnimation<BoolAnimation>( rShapeManager, + nFlags, + &ShapeAttributeLayer::isVisibilityValid, + // TODO(F1): Is there a corresponding shape property? + true, + &ShapeAttributeLayer::getVisibility, + &ShapeAttributeLayer::setVisibility, + eAttrType, + pBox2DWorld ); + } + + return BoolAnimationSharedPtr(); + } + + NumberAnimationSharedPtr AnimationFactory::createPathMotionAnimation( const OUString& rSVGDPath, + sal_Int16 nAdditive, + const AnimatableShapeSharedPtr& /*rShape*/, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& rSlideSize, + const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld, + int nFlags ) + { + return std::make_shared<PathAnimation>( rSVGDPath, nAdditive, + rShapeManager, + rSlideSize, + nFlags, + pBox2DWorld); + } + + NumberAnimationSharedPtr AnimationFactory::createPhysicsAnimation( const box2d::utils::Box2DWorldSharedPtr& pBox2DWorld, + const double fDuration, + const ShapeManagerSharedPtr& rShapeManager, + const ::basegfx::B2DVector& rSlideSize, + const ::basegfx::B2DVector& rStartVelocity, + const double fDensity, + const double fBounciness, + int nFlags ) + { + return std::make_shared<PhysicsAnimation>( pBox2DWorld, fDuration, + rShapeManager, + rSlideSize, + rStartVelocity, + fDensity, + fBounciness, + nFlags ); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |