1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <basecontainernode.hxx>
22 #include <com/sun/star/animations/AnimationRestart.hpp>
23 #include <com/sun/star/animations/AnimationFill.hpp>
24 #include <eventqueue.hxx>
25 #include "nodetools.hxx"
26 #include <delayevent.hxx>
27 #include <o3tl/safeint.hxx>
28 #include <sal/log.hxx>
33 using namespace com::sun::star
;
35 namespace slideshow::internal
{
37 bool isRepeatIndefinite(const uno::Reference
<animations::XAnimationNode
>& xNode
)
39 return xNode
->getRepeatCount().hasValue() && isIndefiniteTiming(xNode
->getRepeatCount());
42 bool isRestart(const uno::Reference
<animations::XAnimationNode
>& xNode
)
44 sal_Int16 nRestart
= xNode
->getRestart();
45 return nRestart
== animations::AnimationRestart::WHEN_NOT_ACTIVE
||
46 nRestart
== animations::AnimationRestart::ALWAYS
;
50 BaseContainerNode::BaseContainerNode(
51 const uno::Reference
< animations::XAnimationNode
>& xNode
,
52 const BaseContainerNodeSharedPtr
& rParent
,
53 const NodeContext
& rContext
)
54 : BaseNode( xNode
, rParent
, rContext
),
56 mnFinishedChildren(0),
58 mbRepeatIndefinite(isRepeatIndefinite(xNode
)),
59 mbRestart(isRestart(xNode
)),
60 mbDurationIndefinite( isIndefiniteTiming( xNode
->getEnd() ) &&
61 isIndefiniteTiming( xNode
->getDuration() ) )
65 void BaseContainerNode::dispose()
67 forEachChildNode( std::mem_fn(&Disposable::dispose
), -1 );
72 bool BaseContainerNode::init_st()
74 if( !(getXAnimationNode()->getRepeatCount() >>= mnLeftIterations
) )
75 mnLeftIterations
= 1.0;
76 return init_children();
79 bool BaseContainerNode::init_children()
81 mnFinishedChildren
= 0;
83 // initialize all children
84 return (o3tl::make_unsigned(std::count_if(
85 maChildren
.begin(), maChildren
.end(),
86 std::mem_fn(&AnimationNode::init
) )) ==
90 void BaseContainerNode::deactivate_st( NodeState eDestState
)
92 mnLeftIterations
= 0; // in order to make skip effect work correctly
93 if (eDestState
== FROZEN
) {
94 // deactivate all children that are not FROZEN or ENDED:
95 forEachChildNode( std::mem_fn(&AnimationNode::deactivate
),
99 // end all children that are not ENDED:
100 forEachChildNode( std::mem_fn(&AnimationNode::end
), ~ENDED
);
104 bool BaseContainerNode::hasPendingAnimation() const
106 // does any of our children returns "true" on
107 // AnimationNode::hasPendingAnimation()?
108 // If yes, we, too, return true
110 maChildren
.begin(), maChildren
.end(),
111 std::mem_fn(&AnimationNode::hasPendingAnimation
) );
114 void BaseContainerNode::appendChildNode( AnimationNodeSharedPtr
const& pNode
)
116 if (! checkValidNode())
119 // register derived classes as end listeners at all children.
120 // this is necessary to control the children animation
121 // sequence, and to determine our own end event
122 if (pNode
->registerDeactivatingListener( getSelf() )) {
123 maChildren
.push_back( pNode
);
127 bool BaseContainerNode::isChildNode( AnimationNodeSharedPtr
const& pNode
) const
129 // find given notifier in child vector
130 VectorOfNodes::const_iterator
const iEnd( maChildren
.end() );
131 VectorOfNodes::const_iterator
const iFind(
132 std::find( maChildren
.begin(), iEnd
, pNode
) );
133 return (iFind
!= iEnd
);
136 bool BaseContainerNode::notifyDeactivatedChild(
137 AnimationNodeSharedPtr
const& pChildNode
)
139 OSL_ASSERT( pChildNode
->getState() == FROZEN
||
140 pChildNode
->getState() == ENDED
);
141 // early exit on invalid nodes
142 OSL_ASSERT( getState() != INVALID
);
143 if( getState() == INVALID
)
146 if (! isChildNode(pChildNode
)) {
147 OSL_FAIL( "unknown notifier!" );
151 std::size_t const nSize
= maChildren
.size();
152 OSL_ASSERT( mnFinishedChildren
< nSize
);
153 ++mnFinishedChildren
;
154 bool bFinished
= (mnFinishedChildren
>= nSize
);
156 // Handle repetition here.
158 if(!mbRepeatIndefinite
&& mnLeftIterations
>= 1.0)
160 mnLeftIterations
-= 1.0;
162 if(mnLeftIterations
>= 1.0 || mbRestart
)
164 // SMIL spec said that "Accumulate" controls whether or not the animation
165 // is cumulative, but XTimeContainer do not have this attribute, so always
166 // remove the effect before next repeat.
167 forEachChildNode(std::mem_fn(&AnimationNode::removeEffect
), -1);
169 if (mnLeftIterations
>= 1.0)
172 EventSharedPtr aRepetitionEvent
=
173 makeDelay( [this] () { this->repeat(); },
175 u
"BaseContainerNode::repeat"_ustr
);
176 getContext().mrEventQueue
.addEvent( aRepetitionEvent
);
178 else if (isDurationIndefinite())
180 if (getFillMode() == animations::AnimationFill::REMOVE
)
181 forEachChildNode(std::mem_fn(&AnimationNode::removeEffect
), -1);
189 void BaseContainerNode::repeat()
191 // Prevent repeat event scheduled before deactivation.
192 if (getState() == FROZEN
|| getState() == ENDED
)
195 forEachChildNode( std::mem_fn(&AnimationNode::end
), ~ENDED
);
196 bool bState
= init_children();
201 #if defined(DBG_UTIL)
202 void BaseContainerNode::showState() const
204 for(const auto & i
: maChildren
)
206 BaseNodeSharedPtr pNode
=
207 std::dynamic_pointer_cast
<BaseNode
>(i
);
208 SAL_INFO("slideshow.verbose",
209 "Node connection: n" <<
210 debugGetNodeName(this) <<
212 debugGetNodeName(pNode
.get()));
216 BaseNode::showState();
220 } // namespace slideshow::internal
222 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */