summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorMarco Cecchetti <mrcekets@gmail.com>2012-07-15 10:54:49 +0200
committerMarco Cecchetti <mrcekets@gmail.com>2012-07-15 11:51:47 +0200
commit821b01bf2c5046f6731fa537bc034a45c176f265 (patch)
tree02d6b72b4485c9d8aa4751c68eb9b6204f70cc36 /filter
parentc78e929b42e68d0ca21a1f9c5bb495ffbb716a6a (diff)
JavaScript engine: added support for skipping/rewinding an effect belonging to an interactive animation sequence.
Moreover now when the mouse pointer is over an event-source shape, through which the user can start an interactive animation, the cursor appearance is changed to a hand
Diffstat (limited to 'filter')
-rw-r--r--filter/source/svg/presentation_engine.js486
1 files changed, 406 insertions, 80 deletions
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index cccbcd04c622..88d8de068431 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -3006,7 +3006,7 @@ function skipEffects(dir)
{
if( dir == 1 )
{
- var bRet = aSlideShow.skipEffect();
+ var bRet = aSlideShow.skipPlayingOrNextEffect();
if( !bRet )
{
@@ -5145,6 +5145,7 @@ function BaseNode( aAnimElem, aParentNode, aNodeContext )
this.aDuration = null;
this.aEnd = null;
this.bMainSequenceRootNode = false;
+ this.bInteractiveSequenceRootNode = false;
this.eFillMode = FILL_MODE_FREEZE;
this.eRestartMode = RESTART_MODE_NEVER;
this.nReapeatCount = undefined;
@@ -5462,6 +5463,11 @@ BaseNode.prototype.isMainSequenceRootNode = function()
return this.bMainSequenceRootNode;
};
+BaseNode.prototype.isInteractiveSequenceRootNode = function()
+{
+ return this.bInteractiveSequenceRootNode;
+};
+
BaseNode.prototype.makeDeactivationEvent = function( nDelay )
{
if( this.aDeactivationEvent )
@@ -5528,6 +5534,8 @@ BaseNode.prototype.notifyEndListeners = function()
}
this.aContext.aEventMultiplexer.notifyEvent( EVENT_TRIGGER_END_EVENT, this.getId() );
+ if( this.getParentNode() && this.getParentNode().isMainSequenceRootNode() )
+ this.aContext.aEventMultiplexer.notifyNextEffectEndEvent();
};
BaseNode.prototype.getContext = function()
@@ -6123,6 +6131,7 @@ BaseContainerNode.prototype.parseElement= function()
if( sNodeTypeAttr && aImpressNodeTypeInMap[ sNodeTypeAttr ] )
this.eImpressNodeType = aImpressNodeTypeInMap[ sNodeTypeAttr ];
this.bMainSequenceRootNode = ( this.eImpressNodeType == IMPRESS_MAIN_SEQUENCE_NODE );
+ this.bInteractiveSequenceRootNode = ( this.eImpressNodeType == IMPRESS_INTERACTIVE_SEQUENCE_NODE );
// preset-class attribute
this.ePresetClass = undefined;
@@ -6554,6 +6563,7 @@ SequentialTimeContainer.prototype.rewindCurrentEffect = function( aChildNode )
// resolve it again.
aChildNode.init();
this.resolveChild( aChildNode );
+ this.notifyRewindedEvent( aChildNode );
this.bIsRewinding = false;
}
else
@@ -6582,12 +6592,17 @@ SequentialTimeContainer.prototype.rewindLastEffect = function( aChildNode )
// immediately without increment the finished children counter and
// resolve the next child.
this.bIsRewinding = true;
- // We end the current effect and remove any change it applies on the
- // animated shape.
+ // We end the current effect.
this.getContext().aTimerEventQueue.forceEmpty();
this.getContext().aActivityQueue.clear();
aChildNode.end();
- aChildNode.removeEffect();
+ // Invoking the end method on the current child node that has not yet
+ // been activated should not lead to any change on the animated shape.
+ // However for safety we used to call the removeEffect method but
+ // lately we noticed that when interactive animation sequences are
+ // involved into the shape effect invoking such a method causes
+ // some issue.
+ //aChildNode.removeEffect();
// As we rewind the previous effect we need to decrease the finished
// children counter.
@@ -6603,6 +6618,7 @@ SequentialTimeContainer.prototype.rewindLastEffect = function( aChildNode )
// in ENDED state now, On the contrary it cannot be resolved again later.
aChildNode.init();
this.resolveChild( aPreviousChildNode );
+ this.notifyRewindedEvent( aChildNode );
this.bIsRewinding = false;
}
else
@@ -6629,29 +6645,50 @@ SequentialTimeContainer.prototype.resolveChild = function( aChildNode )
{
var bResolved = aChildNode.resolve();
- if( bResolved && this.isMainSequenceRootNode() )
+ if( bResolved && ( this.isMainSequenceRootNode() || this.isInteractiveSequenceRootNode() ) )
{
if( this.aCurrentSkipEvent )
this.aCurrentSkipEvent.dispose();
-
this.aCurrentSkipEvent = makeEvent( bind2( SequentialTimeContainer.prototype.skipEffect, this, aChildNode ) );
- this.aContext.aEventMultiplexer.registerSkipEffectEvent( this.aCurrentSkipEvent );
if( this.aRewindCurrentEffectEvent )
this.aRewindCurrentEffectEvent.dispose();
-
this.aRewindCurrentEffectEvent = makeEvent( bind2( SequentialTimeContainer.prototype.rewindCurrentEffect, this, aChildNode ) );
- this.aContext.aEventMultiplexer.registerRewindCurrentEffectEvent( this.aRewindCurrentEffectEvent );
if( this.aRewindLastEffectEvent )
this.aRewindLastEffectEvent.dispose();
-
this.aRewindLastEffectEvent = makeEvent( bind2( SequentialTimeContainer.prototype.rewindLastEffect, this, aChildNode ) );
- this.aContext.aEventMultiplexer.registerRewindLastEffectEvent( this.aRewindLastEffectEvent );
+
+ if( this.isMainSequenceRootNode() )
+ {
+ this.aContext.aEventMultiplexer.registerSkipEffectEvent( this.aCurrentSkipEvent );
+ this.aContext.aEventMultiplexer.registerRewindCurrentEffectEvent( this.aRewindCurrentEffectEvent );
+ this.aContext.aEventMultiplexer.registerRewindLastEffectEvent( this.aRewindLastEffectEvent );
+ }
+ else if( this.isInteractiveSequenceRootNode() )
+ {
+ this.aContext.aEventMultiplexer.registerSkipInteractiveEffectEvent( aChildNode.getId(), this.aCurrentSkipEvent );
+ this.aContext.aEventMultiplexer.registerRewindRunningInteractiveEffectEvent( aChildNode.getId(), this.aRewindCurrentEffectEvent );
+ this.aContext.aEventMultiplexer.registerRewindEndedInteractiveEffectEvent( aChildNode.getId(), this.aRewindLastEffectEvent );
+ }
}
return bResolved;
};
+SequentialTimeContainer.prototype.notifyRewindedEvent = function( aChildNode )
+{
+ if( this.isInteractiveSequenceRootNode() )
+ {
+ this.aContext.aEventMultiplexer.notifyRewindedEffectEvent( aChildNode.getId() );
+
+ var sId = aChildNode.getBegin().getEventBaseElementId();
+ if( sId )
+ {
+ this.aContext.aEventMultiplexer.notifyRewindedEffectEvent( sId );
+ }
+ }
+};
+
SequentialTimeContainer.prototype.dispose = function()
{
if( this.aCurrentSkipEvent )
@@ -8714,7 +8751,6 @@ AnimatedElement.prototype.restoreState = function( nAnimationNodeId )
}
ANIMDBG.print( 'AnimatedElement(' + this.getId() + ').restoreState(' + nAnimationNodeId +')' );
-
var aState = this.aStateSet[ nAnimationNodeId ];
var bRet = this.setToElement( aState.aElement );
if( bRet )
@@ -9670,6 +9706,8 @@ function registerEvent( nNodeId, aTiming, aEvent, aNodeContext )
{
case EVENT_TRIGGER_ON_CLICK:
aEventMultiplexer.registerEvent( eEventType, aSourceEventElement.getId(), aEvent );
+ aEventMultiplexer.registerRewindedEffectHandler( aSourceEventElement.getId(),
+ bind2( aSourceEventElement.charge, aSourceEventElement ) );
bEventRegistered = true;
break;
default:
@@ -9681,6 +9719,11 @@ function registerEvent( nNodeId, aTiming, aEvent, aNodeContext )
var aEndEvent = aInteractiveAnimationSequenceMap[ nNodeId ].getEndEvent();
aEventMultiplexer.registerEvent( eEventType, aSourceEventElement.getId(), aStartEvent );
aEventMultiplexer.registerEvent( EVENT_TRIGGER_END_EVENT, nNodeId, aEndEvent );
+ aEventMultiplexer.registerRewindedEffectHandler(
+ nNodeId,
+ bind2( InteractiveAnimationSequence.prototype.chargeEvents,
+ aInteractiveAnimationSequenceMap[ nNodeId ] )
+ );
}
}
else // no base event element present
@@ -9754,16 +9797,19 @@ SourceEventElement.prototype.getId = function()
SourceEventElement.prototype.onMouseEnter = function()
{
this.bIsPointerOver = true;
+ this.setPointerCursor();
};
SourceEventElement.prototype.onMouseLeave = function()
{
this.bIsPointerOver = false;
+ this.setDefaultCursor();
};
SourceEventElement.prototype.charge = function()
{
this.bClickHandled = false;
+ this.setPointerCursor();
};
SourceEventElement.prototype.handleClick = function( aMouseEvent )
@@ -9771,14 +9817,27 @@ SourceEventElement.prototype.handleClick = function( aMouseEvent )
if( !this.bIsPointerOver ) return false;
if( this.bClickHandled )
- return true;
+ return false;
this.aEventMultiplexer.notifyEvent( EVENT_TRIGGER_ON_CLICK, this.getId() );
aSlideShow.update();
this.bClickHandled = true;
+ this.setDefaultCursor();
return true;
};
+SourceEventElement.prototype.setPointerCursor = function()
+{
+ if( this.bClickHandled )
+ return;
+
+ this.aElement.setAttribute( 'style', 'cursor: pointer' );
+};
+
+SourceEventElement.prototype.setDefaultCursor = function()
+{
+ this.aElement.setAttribute( 'style', 'cursor: default' );
+};
// ------------------------------------------------------------------------------------------ //
@@ -9876,10 +9935,15 @@ function EventMultiplexer( aTimerEventQueue )
{
this.aTimerEventQueue = aTimerEventQueue;
this.aEventMap = new Object();
+ this.aSkipEffectEndHandlerSet = new Array();
this.aMouseClickHandlerSet = new PriorityQueue( PriorityEntry.compare );
this.aSkipEffectEvent = null;
this.aRewindCurrentEffectEvent = null;
this.aRewindLastEffectEvent = null;
+ this.aSkipInteractiveEffectEventSet = new Object();
+ this.aRewindRunningInteractiveEffectEventSet = new Object();
+ this.aRewindEndedInteractiveEffectEventSet = new Object();
+ this.aRewindedEffectHandlerSet = new Object();
}
EventMultiplexer.prototype.registerMouseClickHandler = function( aHandler, nPriority )
@@ -9932,6 +9996,21 @@ EventMultiplexer.prototype.notifyEvent = function( eEventType, aNotifierId )
}
};
+EventMultiplexer.prototype.registerNextEffectEndHandler = function( aHandler )
+{
+ this.aSkipEffectEndHandlerSet.push( aHandler );
+};
+
+EventMultiplexer.prototype.notifyNextEffectEndEvent = function()
+{
+ var nSize = this.aSkipEffectEndHandlerSet.length;
+ for( var i = 0; i < nSize; ++i )
+ {
+ (this.aSkipEffectEndHandlerSet[i])();
+ }
+ this.aSkipEffectEndHandlerSet = new Array();
+};
+
EventMultiplexer.prototype.registerSkipEffectEvent = function( aEvent )
{
this.aSkipEffectEvent = aEvent;
@@ -9974,6 +10053,59 @@ EventMultiplexer.prototype.notifyRewindLastEffectEvent = function()
}
};
+EventMultiplexer.prototype.registerSkipInteractiveEffectEvent = function( nNotifierId, aEvent )
+{
+ this.aSkipInteractiveEffectEventSet[ nNotifierId ] = aEvent;
+};
+
+EventMultiplexer.prototype.notifySkipInteractiveEffectEvent = function( nNotifierId )
+{
+ if( this.aSkipInteractiveEffectEventSet[ nNotifierId ] )
+ {
+ this.aTimerEventQueue.addEvent( this.aSkipInteractiveEffectEventSet[ nNotifierId ] );
+ }
+};
+
+EventMultiplexer.prototype.registerRewindRunningInteractiveEffectEvent = function( nNotifierId, aEvent )
+{
+ this.aRewindRunningInteractiveEffectEventSet[ nNotifierId ] = aEvent;
+};
+
+EventMultiplexer.prototype.notifyRewindRunningInteractiveEffectEvent = function( nNotifierId )
+{
+ if( this.aRewindRunningInteractiveEffectEventSet[ nNotifierId ] )
+ {
+ this.aTimerEventQueue.addEvent( this.aRewindRunningInteractiveEffectEventSet[ nNotifierId ] );
+ }
+};
+
+EventMultiplexer.prototype.registerRewindEndedInteractiveEffectEvent = function( nNotifierId, aEvent )
+{
+ this.aRewindEndedInteractiveEffectEventSet[ nNotifierId ] = aEvent;
+};
+
+EventMultiplexer.prototype.notifyRewindEndedInteractiveEffectEvent = function( nNotifierId )
+{
+ if( this.aRewindEndedInteractiveEffectEventSet[ nNotifierId ] )
+ {
+ this.aTimerEventQueue.addEvent( this.aRewindEndedInteractiveEffectEventSet[ nNotifierId ] );
+ }
+};
+
+EventMultiplexer.prototype.registerRewindedEffectHandler = function( aNotifierId, aHandler )
+{
+ this.aRewindedEffectHandlerSet[ aNotifierId ] = aHandler;
+};
+
+EventMultiplexer.prototype.notifyRewindedEffectEvent = function( aNotifierId )
+{
+ if( this.aRewindedEffectHandlerSet[ aNotifierId ] )
+ {
+ (this.aRewindedEffectHandlerSet[ aNotifierId ])();
+ }
+};
+
+
EventMultiplexer.DEBUG = aEventMultiplexerDebugPrinter.isEnabled();
EventMultiplexer.prototype.DBG = function( sMethodName, eEventType, aNotifierId, nTime )
@@ -11419,6 +11551,49 @@ var PREFERRED_FRAMES_PER_SECONDS = 50;
var PREFERRED_FRAME_RATE = 1.0 / PREFERRED_FRAMES_PER_SECONDS;
+function Effect( nId )
+{
+ this.nId = ( typeof( nId ) === typeof( 1 ) ) ? nId : -1;
+ this.eState = Effect.NOT_STARTED;
+};
+
+Effect.NOT_STARTED = 0;
+Effect.PLAYING = 1;
+Effect.ENDED = 2;
+
+Effect.prototype.getId = function()
+{
+ return this.nId;
+};
+
+Effect.prototype.isMainEffect = function()
+{
+ return ( this.nId === -1 );
+};
+
+Effect.prototype.isPlaying = function()
+{
+ return ( this.eState === Effect.PLAYING );
+};
+
+Effect.prototype.isEnded = function()
+{
+ return ( this.eState === Effect.ENDED );
+};
+
+Effect.prototype.start = function()
+{
+ assert( this.eState === Effect.NOT_STARTED, 'Effect.start: wrong state.' );
+ this.eState = Effect.PLAYING;
+};
+
+Effect.prototype.end = function()
+{
+ assert( this.eState === Effect.PLAYING, 'Effect.end: wrong state.' );
+ this.eState = Effect.ENDED;
+};
+
+// ------------------------------------------------------------------------------------------ //
function SlideShow()
{
@@ -11435,18 +11610,21 @@ function SlideShow()
this.aNextEffectEventArray,
this.aInteractiveAnimationSequenceMap,
this.aActivityQueue );
- this.nCurrentEffect = 0;
- this.eDirection = FORWARD;
- this.nTotalInteracAnimSeqRunning = 0;
this.bIsIdle = true;
this.bIsEnabled = true;
+ this.bNoSlideTransition = false;
+
+ this.nCurrentEffect = 0;
+ this.bIsNextEffectRunning = false;
this.bIsRewinding = false;
this.bIsSkipping = false;
this.bIsSkippingAll = false;
- this.bNoSlideTransition = false;
+ this.nTotalInteractivePlayingEffects = 0;
+ this.aStartedEffectList = new Array();
+ this.aStartedEffectIndexMap = new Object();
+ this.aStartedEffectIndexMap[ -1 ] = undefined;
}
-
SlideShow.prototype.setSlideEvents = function( aNextEffectEventArray,
aInteractiveAnimationSequenceMap,
aEventMultiplexer )
@@ -11467,7 +11645,6 @@ SlideShow.prototype.setSlideEvents = function( aNextEffectEventArray,
this.aContext.aEventMultiplexer = aEventMultiplexer;
this.aEventMultiplexer = aEventMultiplexer;
this.nCurrentEffect = 0;
- this.nTotalInteracAnimSeqRunning = 0;
};
SlideShow.prototype.createSlideTransition = function( aSlideTransitionHandler, aLeavingSlide, aEnteringSlide, aTransitionEndEvent )
@@ -11512,30 +11689,74 @@ SlideShow.prototype.createSlideTransition = function( aSlideTransitionHandler, a
};
+SlideShow.prototype.isEnabled = function()
+{
+ return this.bIsEnabled;
+};
+
SlideShow.prototype.isRunning = function()
{
return !this.bIsIdle;
};
-SlideShow.prototype.isInterAnimSeqRunning = function()
+SlideShow.prototype.isMainEffectPlaying = function()
{
- return ( this.nTotalInteracAnimSeqRunning > 0 );
+ return this.bIsNextEffectRunning;
};
-SlideShow.prototype.isEnabled = function()
+SlideShow.prototype.isInteractiveEffectPlaying = function()
{
- return this.bIsEnabled;
+ return ( this.nTotalInteractivePlayingEffects > 0 );
+};
+
+SlideShow.prototype.isAnyEffectPlaying = function()
+{
+ return ( this.isMainEffectPlaying() || this.isInteractiveEffectPlaying() );
+};
+
+SlideShow.prototype.hasAnyEffectStarted = function()
+{
+ return ( this.aStartedEffectList.length > 0 );
};
SlideShow.prototype.notifyNextEffectStart = function()
{
+ assert( !this.bIsNextEffectRunning,
+ 'SlideShow.notifyNextEffectStart: an effect is already started.' );
+ this.bIsNextEffectRunning = true;
+ this.aEventMultiplexer.registerNextEffectEndHandler( bind2( SlideShow.prototype.notifyNextEffectEnd, this ) );
+ var aEffect = new Effect();
+ aEffect.start();
+ this.aStartedEffectIndexMap[ -1 ] = this.aStartedEffectList.length;
+ this.aStartedEffectList.push( aEffect );
+
+
var aAnimatedElementMap = theMetaDoc.aMetaSlideSet[nCurSlide].aSlideAnimationsHandler.aAnimatedElementMap;
for( var sId in aAnimatedElementMap )
aAnimatedElementMap[ sId ].notifyNextEffectStart( this.nCurrentEffect );
};
+SlideShow.prototype.notifyNextEffectEnd = function()
+{
+ assert( this.bIsNextEffectRunning,
+ 'SlideShow.notifyNextEffectEnd: effect already ended.' );
+ this.bIsNextEffectRunning = false;
+
+ this.aStartedEffectList[ this.aStartedEffectIndexMap[ -1 ] ].end();
+};
+
SlideShow.prototype.notifySlideStart = function( nSlideIndex )
{
+ this.nCurrentEffect = 0;
+ this.bIsRewinding = false;
+ this.bIsSkipping = false;
+ this.bIsSkippingAll = false;
+ this.nTotalInteractivePlayingEffects = 0;
+ this.aStartedEffectList = new Array();
+ this.aStartedEffectIndexMap = new Object();
+ this.aStartedEffectIndexMap[ -1 ] = undefined;
+
+
var aAnimatedElementMap = theMetaDoc.aMetaSlideSet[nSlideIndex].aSlideAnimationsHandler.aAnimatedElementMap;
for( var sId in aAnimatedElementMap )
aAnimatedElementMap[ sId ].notifySlideStart();
@@ -11556,88 +11777,108 @@ SlideShow.prototype.notifyTransitionEnd = function( nSlideIndex )
SlideShow.prototype.notifyInteractiveAnimationSequenceStart = function( nNodeId )
{
- ++this.nTotalInteracAnimSeqRunning;
+ ++this.nTotalInteractivePlayingEffects;
+ var aEffect = new Effect( nNodeId );
+ aEffect.start();
+ this.aStartedEffectIndexMap[ nNodeId ] = this.aStartedEffectList.length;
+ this.aStartedEffectList.push( aEffect );
};
SlideShow.prototype.notifyInteractiveAnimationSequenceEnd = function( nNodeId )
{
- assert( this.nTotalInteracAnimSeqRunning > 0,
- 'SlideShow.notifyInteractiveAnimationSequenceStart: ' +
- 'the total number of running interactive application is zero' );
- --this.nTotalInteracAnimSeqRunning;
+ assert( this.isInteractiveEffectPlaying(),
+ 'SlideShow.notifyInteractiveAnimationSequenceEnd: no interactive effect playing.' )
+
+ this.aStartedEffectList[ this.aStartedEffectIndexMap[ nNodeId ] ].end();
+ --this.nTotalInteractivePlayingEffects;
};
+/** nextEffect
+ * Start the next effect belonging to the main animation sequence if any.
+ * If there is an already playing effect belonging to any animation sequence
+ * it is skipped.
+ *
+ * @return {Boolean}
+ * False if there is no more effect to start, true otherwise.
+ */
SlideShow.prototype.nextEffect = function()
{
if( !this.isEnabled() )
return false;
- if( this.isInterAnimSeqRunning() )
- return true;
-
- if( this.isRunning() )
+ if( this.isAnyEffectPlaying() )
{
- this.skipCurrentEffect();
+ this.skipAllPlayingEffects();
return true;
}
if( !this.aNextEffectEventArray )
return false;
- this.notifyNextEffectStart();
-
if( this.nCurrentEffect >= this.aNextEffectEventArray.size() )
return false;
- this.eDirection = FORWARD;
+ this.notifyNextEffectStart();
+
this.aNextEffectEventArray.at( this.nCurrentEffect ).fire();
++this.nCurrentEffect;
this.update();
return true;
};
-/** skipCurrentEffect
- * Skip the current playing effect.
+/** skipAllPlayingEffects
+ * Skip all playing effect, independently to which animation sequence they
+ * belong.
*
*/
-SlideShow.prototype.skipCurrentEffect = function()
+SlideShow.prototype.skipAllPlayingEffects = function()
{
if( this.bIsSkipping || this.bIsRewinding )
- return;
+ return true;
this.bIsSkipping = true;
- this.aEventMultiplexer.notifySkipEffectEvent();
+ // TODO: The correct order should be based on the left playing time.
+ for( var i = 0; i < this.aStartedEffectList.length; ++i )
+ {
+ var aEffect = this.aStartedEffectList[i];
+ if( aEffect.isPlaying() )
+ {
+ if( aEffect.isMainEffect() )
+ this.aEventMultiplexer.notifySkipEffectEvent();
+ else
+ this.aEventMultiplexer.notifySkipInteractiveEffectEvent( aEffect.getId() );
+ }
+ }
this.update();
this.bIsSkipping = false;
+ return true;
};
-/** skipEffect
- * Skip the next effect to be played.
+/** skipNextEffect
+ * Skip the next effect to be played (if any) that belongs to the main
+ * animation sequence.
+ * Require: no effect is playing.
*
+ * @return {Boolean}
+ * False if there is no more effect to skip, true otherwise.
*/
-SlideShow.prototype.skipEffect = function()
+SlideShow.prototype.skipNextEffect = function()
{
if( this.bIsSkipping || this.bIsRewinding )
return true;
- if( this.isInterAnimSeqRunning() )
- return true;
-
- if( this.isRunning() )
- {
- this.skipCurrentEffect();
- return true;
- }
+ assert( !this.isAnyEffectPlaying(),
+ 'SlideShow.skipNextEffect' );
if( !this.aNextEffectEventArray )
return false;
- this.notifyNextEffectStart();
if( this.nCurrentEffect >= this.aNextEffectEventArray.size() )
return false;
+ this.notifyNextEffectStart();
+
this.bIsSkipping = true;
- this.eDirection = FORWARD;
this.aNextEffectEventArray.at( this.nCurrentEffect ).fire();
this.aEventMultiplexer.notifySkipEffectEvent();
++this.nCurrentEffect;
@@ -11646,8 +11887,25 @@ SlideShow.prototype.skipEffect = function()
return true;
};
+/** skipPlayingOrNextEffect
+ * Skip the next effect to be played that belongs to the main animation
+ * sequence or all playing effects.
+ *
+ * @return {Boolean}
+ * False if there is no more effect to skip, true otherwise.
+ */
+SlideShow.prototype.skipPlayingOrNextEffect = function()
+{
+ if( this.isAnyEffectPlaying() )
+ return this.skipAllPlayingEffects();
+ else
+ return this.skipNextEffect();
+};
+
+
/** skipAllEffects
- * Skip all left effects on the current slide.
+ * Skip all left effects that belongs to the main animation sequence and all
+ * playing effects on the current slide.
*
* @return {Boolean}
* True if it already skipping or when it has ended skipping,
@@ -11658,13 +11916,11 @@ SlideShow.prototype.skipAllEffects = function()
if( this.bIsSkippingAll )
return true;
- if( this.isInterAnimSeqRunning() )
- return true;
-
this.bIsSkippingAll = true;
- if( this.isRunning() )
+
+ if( this.isAnyEffectPlaying() )
{
- this.skipCurrentEffect();
+ this.skipAllPlayingEffects();
}
else if( !this.aNextEffectEventArray
|| ( this.nCurrentEffect >= this.aNextEffectEventArray.size() ) )
@@ -11681,14 +11937,16 @@ SlideShow.prototype.skipAllEffects = function()
// aNextEffectEventArray will going on increasing after every skip action.
while( this.nCurrentEffect < this.aNextEffectEventArray.size() )
{
- this.skipEffect();
+ this.skipNextEffect();
}
this.bIsSkippingAll = false;
return true;
};
/** rewindEffect
- * Rewind the current playing effect or the last played one.
+ * Rewind all the effects started after at least one of the current playing
+ * effects. If there is no playing effect, it rewinds the last played one,
+ * both in case it belongs to the main or to an interactive animation sequence.
*
*/
SlideShow.prototype.rewindEffect = function()
@@ -11696,37 +11954,105 @@ SlideShow.prototype.rewindEffect = function()
if( this.bIsSkipping || this.bIsRewinding )
return;
- if( this.isInterAnimSeqRunning() )
- return true;
-
- if( this.nCurrentEffect == 0 )
+ if( !this.hasAnyEffectStarted() )
{
this.rewindToPreviousSlide();
return;
}
this.bIsRewinding = true;
- if( this.isRunning() )
+
+ var nFirstPlayingEffectIndex = undefined;
+
+ var i = 0;
+ for( ; i < this.aStartedEffectList.length; ++i )
{
- this.aEventMultiplexer.notifyRewindCurrentEffectEvent();
+ var aEffect = this.aStartedEffectList[i];
+ if( aEffect.isPlaying() )
+ {
+ nFirstPlayingEffectIndex = i;
+ break;
+ }
}
- else
+
+ // There is at least one playing effect.
+ if( nFirstPlayingEffectIndex !== undefined )
+ {
+ i = this.aStartedEffectList.length - 1;
+ for( ; i >= nFirstPlayingEffectIndex; --i )
+ {
+ aEffect = this.aStartedEffectList[i];
+ if( aEffect.isPlaying() )
+ {
+ if( aEffect.isMainEffect() )
+ {
+ this.aEventMultiplexer.notifyRewindCurrentEffectEvent();
+ if( this.nCurrentEffect > 0 )
+ --this.nCurrentEffect;
+ }
+ else
+ {
+ this.aEventMultiplexer.notifyRewindRunningInteractiveEffectEvent( aEffect.getId() );
+ }
+ }
+ else if( aEffect.isEnded() )
+ {
+ if( aEffect.isMainEffect() )
+ {
+ this.aEventMultiplexer.notifyRewindLastEffectEvent();
+ if( this.nCurrentEffect > 0 )
+ --this.nCurrentEffect;
+ }
+ else
+ {
+ this.aEventMultiplexer.notifyRewindEndedInteractiveEffectEvent( aEffect.getId() );
+ }
+ }
+ }
+ this.update();
+
+ // Pay attention here: we need to remove all rewinded effects from
+ // the started effect list only after updating.
+ i = this.aStartedEffectList.length - 1;
+ for( ; i >= nFirstPlayingEffectIndex; --i )
+ {
+ aEffect = this.aStartedEffectList.pop();
+ if( !aEffect.isMainEffect() )
+ delete this.aStartedEffectIndexMap[ aEffect.getId() ];
+ }
+ }
+ else // there is no playing effect
{
- this.aEventMultiplexer.notifyRewindLastEffectEvent();
+ aEffect = this.aStartedEffectList.pop();
+ if( !aEffect.isMainEffect() )
+ delete this.aStartedEffectIndexMap[ aEffect.getId() ];
+ if( aEffect.isEnded() ) // Well that is almost an assertion.
+ {
+ if( aEffect.isMainEffect() )
+ {
+ this.aEventMultiplexer.notifyRewindLastEffectEvent();
+ if( this.nCurrentEffect > 0 )
+ --this.nCurrentEffect;
+ }
+ else
+ {
+ this.aEventMultiplexer.notifyRewindEndedInteractiveEffectEvent( aEffect.getId() );
+ }
+ }
+ this.update();
}
- if( this.nCurrentEffect > 0 )
- --this.nCurrentEffect;
- this.update();
+
this.bIsRewinding = false;
};
/** rewindToPreviousSlide
- * Displays the previous slide with all effects played.
+ * Displays the previous slide with all effects, that belong to the main
+ * animation sequence, played.
*
*/
SlideShow.prototype.rewindToPreviousSlide = function()
{
- if( this.isRunning() )
+ if( this.isAnyEffectPlaying() )
return;
var nNewSlide = nCurSlide - 1;
this.displaySlide( nNewSlide, true );
@@ -11739,16 +12065,16 @@ SlideShow.prototype.rewindToPreviousSlide = function()
*/
SlideShow.prototype.rewindAllEffects = function()
{
- if( this.nCurrentEffect == 0 )
+ if( !this.hasAnyEffectStarted() )
{
this.rewindToPreviousSlide();
return;
}
- while( this.nCurrentEffect > 0 )
- {
- this.rewindEffect();
- }
+ while( this.hasAnyEffectStarted() )
+ {
+ this.rewindEffect();
+ }
};
SlideShow.prototype.displaySlide = function( nNewSlide, bSkipSlideTransition )