253 lines
9.7 KiB
C++
253 lines
9.7 KiB
C++
/* -*- 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: */
|