diff options
Diffstat (limited to 'slideshow/source/engine/activities/simplecontinuousactivitybase.cxx')
-rw-r--r-- | slideshow/source/engine/activities/simplecontinuousactivitybase.cxx | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/slideshow/source/engine/activities/simplecontinuousactivitybase.cxx b/slideshow/source/engine/activities/simplecontinuousactivitybase.cxx new file mode 100644 index 000000000..01cb3b750 --- /dev/null +++ b/slideshow/source/engine/activities/simplecontinuousactivitybase.cxx @@ -0,0 +1,253 @@ +/* -*- 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 . + */ + + +// must be first + +#include "simplecontinuousactivitybase.hxx" + +#include <sal/log.hxx> + +namespace slideshow::internal +{ + SimpleContinuousActivityBase::SimpleContinuousActivityBase( + const ActivityParameters& rParms ) : + ActivityBase( rParms ), + maTimer( rParms.mrActivitiesQueue.getTimer() ), + mnMinSimpleDuration( rParms.mnMinDuration ), + mnMinNumberOfFrames( rParms.mnMinNumberOfFrames ), + mnCurrPerformCalls( 0 ) + { + } + + void SimpleContinuousActivityBase::startAnimation() + { + // init timer. We measure animation time only when we're + // actually started. + maTimer.reset(); + } + + double SimpleContinuousActivityBase::calcTimeLag() const + { + ActivityBase::calcTimeLag(); + if (! isActive()) + return 0.0; + + // retrieve locally elapsed time + const double nCurrElapsedTime( maTimer.getElapsedTime() ); + + // log time + SAL_INFO("slideshow.verbose", "SimpleContinuousActivityBase::calcTimeLag(): " + "next step is based on time: " << nCurrElapsedTime ); + + // go to great length to ensure a proper animation + // run. Since we don't know how often we will be called + // here, try to spread the animator calls uniquely over + // the [0,1] parameter range. Be aware of the fact that + // perform will be called at least mnMinNumberOfTurns + // times. + + // fraction of time elapsed (clamp to 1.0 for zero-length + // animations) + const double nFractionElapsedTime( + mnMinSimpleDuration != 0.0 ? + nCurrElapsedTime / mnMinSimpleDuration : + 1.0 ); + + // fraction of minimum calls performed + const double nFractionRequiredCalls( + double(mnCurrPerformCalls) / mnMinNumberOfFrames ); + + // okay, so now, the decision is easy: + + // If the fraction of time elapsed is smaller than the + // number of calls required to be performed, then we calc + // the position on the animation range according to + // elapsed time. That is, we're so to say ahead of time. + + // In contrary, if the fraction of time elapsed is larger, + // then we're lagging, and we thus calc the position on + // the animation time line according to the fraction of + // calls performed. Thus, the animation is forced to slow + // down, and take the required minimal number of steps, + // sufficiently equally distributed across the animation + // time line. + if( nFractionElapsedTime < nFractionRequiredCalls ) + { + SAL_INFO("slideshow.verbose", "SimpleContinuousActivityBase::calcTimeLag(): t=" << + nFractionElapsedTime << + " is based on time"); + return 0.0; + } + else + { + SAL_INFO("slideshow.verbose", "SimpleContinuousActivityBase::perform(): t=" << + nFractionRequiredCalls << + " is based on number of calls"); + + // lag global time, so all other animations lag, too: + return ((nFractionElapsedTime - nFractionRequiredCalls) + * mnMinSimpleDuration); + } + } + + bool SimpleContinuousActivityBase::perform() + { + // call base class, for start() calls and end handling + if( !ActivityBase::perform() ) + return false; // done, we're ended + + + // get relative animation position + // =============================== + + const double nCurrElapsedTime( maTimer.getElapsedTime() ); + // clamp to 1.0 for zero animation duration + double nT( mnMinSimpleDuration != 0.0 ? + nCurrElapsedTime / mnMinSimpleDuration : + 1.0 ); + + + // one of the stop criteria reached? + // ================================= + + // will be set to true below, if one of the termination criteria + // matched. + bool bActivityEnding( false ); + + if( isRepeatCountValid() ) + { + // Finite duration + // =============== + + // When we've autoreverse on, the repeat count + // doubles + const double nRepeatCount( getRepeatCount() ); + const double nEffectiveRepeat( isAutoReverse() ? + 2.0*nRepeatCount : + nRepeatCount ); + + // time (or frame count) elapsed? + if( nEffectiveRepeat <= nT ) + { + // okee. done for now. Will not exit right here, + // to give animation the chance to render the last + // frame below + bActivityEnding = true; + + // clamp animation to max permissible value + nT = nEffectiveRepeat; + } + } + + + // need to do auto-reverse? + // ======================== + + double nRepeats; + double nRelativeSimpleTime; + + // TODO(Q3): Refactor this mess + if( isAutoReverse() ) + { + // divert active duration into repeat and + // fractional part. + const double nFractionalActiveDuration( modf(nT, &nRepeats) ); + + // for auto-reverse, map ranges [1,2), [3,4), ... + // to ranges [0,1), [1,2), etc. + if( static_cast<int>(nRepeats) % 2 ) + { + // we're in an odd range, reverse sweep + nRelativeSimpleTime = 1.0 - nFractionalActiveDuration; + } + else + { + // we're in an even range, pass on as is + nRelativeSimpleTime = nFractionalActiveDuration; + } + + // effective repeat count for autoreverse is half of + // the input time's value (each run of an autoreverse + // cycle is half of a repeat) + nRepeats /= 2; + } + else + { + // determine repeat + // ================ + + // calc simple time and number of repeats from nT + // Now, that's easy, since the fractional part of + // nT gives the relative simple time, and the + // integer part the number of full repeats: + nRelativeSimpleTime = modf(nT, &nRepeats); + + // clamp repeats to max permissible value (maRepeats.getValue() - 1.0) + if( isRepeatCountValid() && + nRepeats >= getRepeatCount() ) + { + // Note that this code here only gets + // triggered if maRepeats.getValue() is an + // _integer_. Otherwise, nRepeats will never + // reach nor exceed + // maRepeats.getValue(). Thus, the code below + // does not need to handle cases of fractional + // repeats, and can always assume that a full + // animation run has ended (with + // nRelativeSimpleTime=1.0 for + // non-autoreversed activities). + + // with modf, nRelativeSimpleTime will never + // become 1.0, since nRepeats is incremented and + // nRelativeSimpleTime set to 0.0 then. + + // For the animation to reach its final value, + // nRepeats must although become + // maRepeats.getValue()-1.0, and + // nRelativeSimpleTime=1.0. + nRelativeSimpleTime = 1.0; + nRepeats -= 1.0; + } + } + + // actually perform something + // ========================== + + simplePerform( nRelativeSimpleTime, + // nRepeats is already integer-valued + static_cast<sal_uInt32>( nRepeats ) ); + + + // delayed endActivity() call from end condition check + // below. Issued after the simplePerform() call above, to + // give animations the chance to correctly reach the + // animation end value, without spurious bail-outs because + // of isActive() returning false. + if( bActivityEnding ) + endActivity(); + + // one more frame successfully performed + ++mnCurrPerformCalls; + + return isActive(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |