1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
25*b1cdbd2cSJim Jagielski #include "precompiled_slideshow.hxx"
26*b1cdbd2cSJim Jagielski 
27*b1cdbd2cSJim Jagielski // must be first
28*b1cdbd2cSJim Jagielski #include <canvas/debug.hxx>
29*b1cdbd2cSJim Jagielski #include <canvas/verbosetrace.hxx>
30*b1cdbd2cSJim Jagielski 
31*b1cdbd2cSJim Jagielski #include <simplecontinuousactivitybase.hxx>
32*b1cdbd2cSJim Jagielski 
33*b1cdbd2cSJim Jagielski 
34*b1cdbd2cSJim Jagielski namespace slideshow
35*b1cdbd2cSJim Jagielski {
36*b1cdbd2cSJim Jagielski     namespace internal
37*b1cdbd2cSJim Jagielski     {
SimpleContinuousActivityBase(const ActivityParameters & rParms)38*b1cdbd2cSJim Jagielski         SimpleContinuousActivityBase::SimpleContinuousActivityBase(
39*b1cdbd2cSJim Jagielski             const ActivityParameters& rParms ) :
40*b1cdbd2cSJim Jagielski             ActivityBase( rParms ),
41*b1cdbd2cSJim Jagielski             maTimer( rParms.mrActivitiesQueue.getTimer() ),
42*b1cdbd2cSJim Jagielski             mnMinSimpleDuration( rParms.mnMinDuration ),
43*b1cdbd2cSJim Jagielski             mnMinNumberOfFrames( rParms.mnMinNumberOfFrames ),
44*b1cdbd2cSJim Jagielski             mnCurrPerformCalls( 0 )
45*b1cdbd2cSJim Jagielski         {
46*b1cdbd2cSJim Jagielski         }
47*b1cdbd2cSJim Jagielski 
startAnimation()48*b1cdbd2cSJim Jagielski         void SimpleContinuousActivityBase::startAnimation()
49*b1cdbd2cSJim Jagielski         {
50*b1cdbd2cSJim Jagielski             // init timer. We measure animation time only when we're
51*b1cdbd2cSJim Jagielski             // actually started.
52*b1cdbd2cSJim Jagielski             maTimer.reset();
53*b1cdbd2cSJim Jagielski         }
54*b1cdbd2cSJim Jagielski 
calcTimeLag() const55*b1cdbd2cSJim Jagielski         double SimpleContinuousActivityBase::calcTimeLag() const
56*b1cdbd2cSJim Jagielski         {
57*b1cdbd2cSJim Jagielski             ActivityBase::calcTimeLag();
58*b1cdbd2cSJim Jagielski             if (! isActive())
59*b1cdbd2cSJim Jagielski                 return 0.0;
60*b1cdbd2cSJim Jagielski 
61*b1cdbd2cSJim Jagielski             // retrieve locally elapsed time
62*b1cdbd2cSJim Jagielski             const double nCurrElapsedTime( maTimer.getElapsedTime() );
63*b1cdbd2cSJim Jagielski 
64*b1cdbd2cSJim Jagielski             // log time
65*b1cdbd2cSJim Jagielski             VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): "
66*b1cdbd2cSJim Jagielski                            "next step is based on time: %f", nCurrElapsedTime );
67*b1cdbd2cSJim Jagielski 
68*b1cdbd2cSJim Jagielski             // go to great length to ensure a proper animation
69*b1cdbd2cSJim Jagielski             // run. Since we don't know how often we will be called
70*b1cdbd2cSJim Jagielski             // here, try to spread the animator calls uniquely over
71*b1cdbd2cSJim Jagielski             // the [0,1] parameter range. Be aware of the fact that
72*b1cdbd2cSJim Jagielski             // perform will be called at least mnMinNumberOfTurns
73*b1cdbd2cSJim Jagielski             // times.
74*b1cdbd2cSJim Jagielski 
75*b1cdbd2cSJim Jagielski             // fraction of time elapsed
76*b1cdbd2cSJim Jagielski             const double nFractionElapsedTime(
77*b1cdbd2cSJim Jagielski                 nCurrElapsedTime / mnMinSimpleDuration );
78*b1cdbd2cSJim Jagielski 
79*b1cdbd2cSJim Jagielski             // fraction of minimum calls performed
80*b1cdbd2cSJim Jagielski             const double nFractionRequiredCalls(
81*b1cdbd2cSJim Jagielski                 double(mnCurrPerformCalls) / mnMinNumberOfFrames );
82*b1cdbd2cSJim Jagielski 
83*b1cdbd2cSJim Jagielski             // okay, so now, the decision is easy:
84*b1cdbd2cSJim Jagielski             //
85*b1cdbd2cSJim Jagielski             // If the fraction of time elapsed is smaller than the
86*b1cdbd2cSJim Jagielski             // number of calls required to be performed, then we calc
87*b1cdbd2cSJim Jagielski             // the position on the animation range according to
88*b1cdbd2cSJim Jagielski             // elapsed time. That is, we're so to say ahead of time.
89*b1cdbd2cSJim Jagielski             //
90*b1cdbd2cSJim Jagielski             // In contrary, if the fraction of time elapsed is larger,
91*b1cdbd2cSJim Jagielski             // then we're lagging, and we thus calc the position on
92*b1cdbd2cSJim Jagielski             // the animation time line according to the fraction of
93*b1cdbd2cSJim Jagielski             // calls performed. Thus, the animation is forced to slow
94*b1cdbd2cSJim Jagielski             // down, and take the required minimal number of steps,
95*b1cdbd2cSJim Jagielski             // sufficiently equally distributed across the animation
96*b1cdbd2cSJim Jagielski             // time line.
97*b1cdbd2cSJim Jagielski             if( nFractionElapsedTime < nFractionRequiredCalls )
98*b1cdbd2cSJim Jagielski             {
99*b1cdbd2cSJim Jagielski                 VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): "
100*b1cdbd2cSJim Jagielski                                "t=%f is based on time", nFractionElapsedTime );
101*b1cdbd2cSJim Jagielski                 return 0.0;
102*b1cdbd2cSJim Jagielski             }
103*b1cdbd2cSJim Jagielski             else
104*b1cdbd2cSJim Jagielski             {
105*b1cdbd2cSJim Jagielski                 VERBOSE_TRACE( "SimpleContinuousActivityBase::perform(): "
106*b1cdbd2cSJim Jagielski                                "t=%f is based on number of calls",
107*b1cdbd2cSJim Jagielski                                nFractionRequiredCalls );
108*b1cdbd2cSJim Jagielski 
109*b1cdbd2cSJim Jagielski                 // lag global time, so all other animations lag, too:
110*b1cdbd2cSJim Jagielski                 return ((nFractionElapsedTime - nFractionRequiredCalls)
111*b1cdbd2cSJim Jagielski                         * mnMinSimpleDuration);
112*b1cdbd2cSJim Jagielski             }
113*b1cdbd2cSJim Jagielski         }
114*b1cdbd2cSJim Jagielski 
perform()115*b1cdbd2cSJim Jagielski         bool SimpleContinuousActivityBase::perform()
116*b1cdbd2cSJim Jagielski         {
117*b1cdbd2cSJim Jagielski             // call base class, for start() calls and end handling
118*b1cdbd2cSJim Jagielski             if( !ActivityBase::perform() )
119*b1cdbd2cSJim Jagielski                 return false; // done, we're ended
120*b1cdbd2cSJim Jagielski 
121*b1cdbd2cSJim Jagielski 
122*b1cdbd2cSJim Jagielski             // get relative animation position
123*b1cdbd2cSJim Jagielski             // ===============================
124*b1cdbd2cSJim Jagielski 
125*b1cdbd2cSJim Jagielski             const double nCurrElapsedTime( maTimer.getElapsedTime() );
126*b1cdbd2cSJim Jagielski             double nT( nCurrElapsedTime / mnMinSimpleDuration );
127*b1cdbd2cSJim Jagielski 
128*b1cdbd2cSJim Jagielski 
129*b1cdbd2cSJim Jagielski             // one of the stop criteria reached?
130*b1cdbd2cSJim Jagielski             // =================================
131*b1cdbd2cSJim Jagielski 
132*b1cdbd2cSJim Jagielski             // will be set to true below, if one of the termination criteria
133*b1cdbd2cSJim Jagielski             // matched.
134*b1cdbd2cSJim Jagielski             bool bActivityEnding( false );
135*b1cdbd2cSJim Jagielski 
136*b1cdbd2cSJim Jagielski             if( isRepeatCountValid() )
137*b1cdbd2cSJim Jagielski             {
138*b1cdbd2cSJim Jagielski                 // Finite duration
139*b1cdbd2cSJim Jagielski                 // ===============
140*b1cdbd2cSJim Jagielski 
141*b1cdbd2cSJim Jagielski                 // When we've autoreverse on, the repeat count
142*b1cdbd2cSJim Jagielski                 // doubles
143*b1cdbd2cSJim Jagielski                 const double nRepeatCount( getRepeatCount() );
144*b1cdbd2cSJim Jagielski                 const double nEffectiveRepeat( isAutoReverse() ?
145*b1cdbd2cSJim Jagielski                                                2.0*nRepeatCount :
146*b1cdbd2cSJim Jagielski                                                nRepeatCount );
147*b1cdbd2cSJim Jagielski 
148*b1cdbd2cSJim Jagielski                 // time (or frame count) elapsed?
149*b1cdbd2cSJim Jagielski                 if( nEffectiveRepeat <= nT )
150*b1cdbd2cSJim Jagielski                 {
151*b1cdbd2cSJim Jagielski                     // okee. done for now. Will not exit right here,
152*b1cdbd2cSJim Jagielski                     // to give animation the chance to render the last
153*b1cdbd2cSJim Jagielski                     // frame below
154*b1cdbd2cSJim Jagielski                     bActivityEnding = true;
155*b1cdbd2cSJim Jagielski 
156*b1cdbd2cSJim Jagielski                     // clamp animation to max permissible value
157*b1cdbd2cSJim Jagielski                     nT = nEffectiveRepeat;
158*b1cdbd2cSJim Jagielski                 }
159*b1cdbd2cSJim Jagielski             }
160*b1cdbd2cSJim Jagielski 
161*b1cdbd2cSJim Jagielski 
162*b1cdbd2cSJim Jagielski             // need to do auto-reverse?
163*b1cdbd2cSJim Jagielski             // ========================
164*b1cdbd2cSJim Jagielski 
165*b1cdbd2cSJim Jagielski             double nRepeats;
166*b1cdbd2cSJim Jagielski             double nRelativeSimpleTime;
167*b1cdbd2cSJim Jagielski 
168*b1cdbd2cSJim Jagielski             // TODO(Q3): Refactor this mess
169*b1cdbd2cSJim Jagielski             if( isAutoReverse() )
170*b1cdbd2cSJim Jagielski             {
171*b1cdbd2cSJim Jagielski                 // divert active duration into repeat and
172*b1cdbd2cSJim Jagielski                 // fractional part.
173*b1cdbd2cSJim Jagielski                 const double nFractionalActiveDuration( modf(nT, &nRepeats) );
174*b1cdbd2cSJim Jagielski 
175*b1cdbd2cSJim Jagielski                 // for auto-reverse, map ranges [1,2), [3,4), ...
176*b1cdbd2cSJim Jagielski                 // to ranges [0,1), [1,2), etc.
177*b1cdbd2cSJim Jagielski                 if( ((int)nRepeats) % 2 )
178*b1cdbd2cSJim Jagielski                 {
179*b1cdbd2cSJim Jagielski                     // we're in an odd range, reverse sweep
180*b1cdbd2cSJim Jagielski                     nRelativeSimpleTime = 1.0 - nFractionalActiveDuration;
181*b1cdbd2cSJim Jagielski                 }
182*b1cdbd2cSJim Jagielski                 else
183*b1cdbd2cSJim Jagielski                 {
184*b1cdbd2cSJim Jagielski                     // we're in an even range, pass on as is
185*b1cdbd2cSJim Jagielski                     nRelativeSimpleTime = nFractionalActiveDuration;
186*b1cdbd2cSJim Jagielski                 }
187*b1cdbd2cSJim Jagielski 
188*b1cdbd2cSJim Jagielski                 // effective repeat count for autoreverse is half of
189*b1cdbd2cSJim Jagielski                 // the input time's value (each run of an autoreverse
190*b1cdbd2cSJim Jagielski                 // cycle is half of a repeat)
191*b1cdbd2cSJim Jagielski                 nRepeats /= 2;
192*b1cdbd2cSJim Jagielski             }
193*b1cdbd2cSJim Jagielski             else
194*b1cdbd2cSJim Jagielski             {
195*b1cdbd2cSJim Jagielski                 // determine repeat
196*b1cdbd2cSJim Jagielski                 // ================
197*b1cdbd2cSJim Jagielski 
198*b1cdbd2cSJim Jagielski                 // calc simple time and number of repeats from nT
199*b1cdbd2cSJim Jagielski                 // Now, that's easy, since the fractional part of
200*b1cdbd2cSJim Jagielski                 // nT gives the relative simple time, and the
201*b1cdbd2cSJim Jagielski                 // integer part the number of full repeats:
202*b1cdbd2cSJim Jagielski                 nRelativeSimpleTime = modf(nT, &nRepeats);
203*b1cdbd2cSJim Jagielski 
204*b1cdbd2cSJim Jagielski                 // clamp repeats to max permissible value (maRepeats.getValue() - 1.0)
205*b1cdbd2cSJim Jagielski                 if( isRepeatCountValid() &&
206*b1cdbd2cSJim Jagielski                     nRepeats >= getRepeatCount() )
207*b1cdbd2cSJim Jagielski                 {
208*b1cdbd2cSJim Jagielski                     // Note that this code here only gets
209*b1cdbd2cSJim Jagielski                     // triggered if maRepeats.getValue() is an
210*b1cdbd2cSJim Jagielski                     // _integer_. Otherwise, nRepeats will never
211*b1cdbd2cSJim Jagielski                     // reach nor exceed
212*b1cdbd2cSJim Jagielski                     // maRepeats.getValue(). Thus, the code below
213*b1cdbd2cSJim Jagielski                     // does not need to handle cases of fractional
214*b1cdbd2cSJim Jagielski                     // repeats, and can always assume that a full
215*b1cdbd2cSJim Jagielski                     // animation run has ended (with
216*b1cdbd2cSJim Jagielski                     // nRelativeSimpleTime=1.0 for
217*b1cdbd2cSJim Jagielski                     // non-autoreversed activities).
218*b1cdbd2cSJim Jagielski 
219*b1cdbd2cSJim Jagielski                     // with modf, nRelativeSimpleTime will never
220*b1cdbd2cSJim Jagielski                     // become 1.0, since nRepeats is incremented and
221*b1cdbd2cSJim Jagielski                     // nRelativeSimpleTime set to 0.0 then.
222*b1cdbd2cSJim Jagielski                     //
223*b1cdbd2cSJim Jagielski                     // For the animation to reach its final value,
224*b1cdbd2cSJim Jagielski                     // nRepeats must although become
225*b1cdbd2cSJim Jagielski                     // maRepeats.getValue()-1.0, and
226*b1cdbd2cSJim Jagielski                     // nRelativeSimpleTime=1.0.
227*b1cdbd2cSJim Jagielski                     nRelativeSimpleTime = 1.0;
228*b1cdbd2cSJim Jagielski                     nRepeats -= 1.0;
229*b1cdbd2cSJim Jagielski                 }
230*b1cdbd2cSJim Jagielski             }
231*b1cdbd2cSJim Jagielski 
232*b1cdbd2cSJim Jagielski             // actually perform something
233*b1cdbd2cSJim Jagielski             // ==========================
234*b1cdbd2cSJim Jagielski 
235*b1cdbd2cSJim Jagielski             simplePerform( nRelativeSimpleTime,
236*b1cdbd2cSJim Jagielski                            // nRepeats is already integer-valued
237*b1cdbd2cSJim Jagielski                            static_cast<sal_uInt32>( nRepeats ) );
238*b1cdbd2cSJim Jagielski 
239*b1cdbd2cSJim Jagielski 
240*b1cdbd2cSJim Jagielski             // delayed endActivity() call from end condition check
241*b1cdbd2cSJim Jagielski             // below. Issued after the simplePerform() call above, to
242*b1cdbd2cSJim Jagielski             // give animations the chance to correctly reach the
243*b1cdbd2cSJim Jagielski             // animation end value, without spurious bail-outs because
244*b1cdbd2cSJim Jagielski             // of isActive() returning false.
245*b1cdbd2cSJim Jagielski             if( bActivityEnding )
246*b1cdbd2cSJim Jagielski                 endActivity();
247*b1cdbd2cSJim Jagielski 
248*b1cdbd2cSJim Jagielski             // one more frame successfully performed
249*b1cdbd2cSJim Jagielski             ++mnCurrPerformCalls;
250*b1cdbd2cSJim Jagielski 
251*b1cdbd2cSJim Jagielski             return isActive();
252*b1cdbd2cSJim Jagielski         }
253*b1cdbd2cSJim Jagielski     }
254*b1cdbd2cSJim Jagielski }
255