/* -*- 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 .
*/
// Activities get values from the expression parser, // which returns _relative_ sizes/positions. // Convert back relative to reference coordinate system
aValue *= basegfx::B2DPoint(maReferenceSize);
// deviated from the (*shared_ptr).*mpFuncPtr // notation here, since gcc does not seem to parse // that as a member function call anymore.
basegfx::B2DPoint aPoint(maDefaultValue);
aRetVal.setX( (mpAttrLayer.get()->*mpIs1stValidFunc)() ?
(mpAttrLayer.get()->*mpGet1stValueFunc)() :
aPoint.getX() );
aRetVal.setY( (mpAttrLayer.get()->*mpIs2ndValidFunc)() ?
(mpAttrLayer.get()->*mpGet2ndValueFunc)() :
aPoint.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 /= basegfx::B2DPoint(maReferenceSize);
// 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 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}, 0);
}
// if there's a physics animation going on report the change to it if ( mpBox2DWorld->isInitialized() )
{
mpBox2DWorld->queueShapePathAnimationUpdate( mpShape->getXShape(),
mpAttrLayer,
mbAnimationFirstUpdate );
}
}
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]
}
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();
// 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);
}
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: typedeftypename 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,
ValueT aDefaultValue,
ValueT (ShapeAttributeLayer::*pGetValue)() const, void (ShapeAttributeLayer::*pSetValue)( const ValueT& ), const ModifierFunctor& rGetterModifier, const ModifierFunctor& rSetterModifier, const AttributeType eAttrType,
box2d::utils::Box2DWorldSharedPtr pBox2DWorld ) :
mpShape(),
mpAttrLayer(),
mpShapeManager( rShapeManager ),
mpIsValidFunc(pIsValid),
mpGetValueFunc(pGetValue),
mpSetValueFunc(pSetValue),
maGetterModifier( rGetterModifier ),
maSetterModifier( rSetterModifier ),
mnFlags( nFlags ),
maDefaultValue(std::move(aDefaultValue)),
mbAnimationStarted( false ),
mbAnimationFirstUpdate( true ),
meAttrType( eAttrType ),
mpBox2DWorld (std::move( pBox2DWorld ))
{
ENSURE_OR_THROW( rShapeManager, "GenericAnimation::GenericAnimation(): Invalid ShapeManager" );
ENSURE_OR_THROW( pIsValid && pGetValue && pSetValue, "GenericAnimation::GenericAnimation(): One of the method pointers is NULL" );
}
// only start animation once per repeated start() call, // and only if sprites should be used for display if( !mbAnimationStarted )
{
mbAnimationStarted = true;
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 );
}
// 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 );
}
/** For by-value interfaces (bool, double)
*/ booloperator()( 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 );
}
// 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;
}
// 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::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;
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,
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.