Bump version to 6.0-36
[LibreOffice.git] / slideshow / source / engine / effectrewinder.cxx
blobd920bdd4ad06cae6c50932a1834ef707a0adc694
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 "effectrewinder.hxx"
22 #include <eventqueue.hxx>
23 #include <usereventqueue.hxx>
24 #include <mouseeventhandler.hxx>
25 #include <basecontainernode.hxx>
26 #include <delayevent.hxx>
28 #include <com/sun/star/awt/MouseEvent.hpp>
29 #include <com/sun/star/animations/Event.hpp>
30 #include <com/sun/star/animations/EventTrigger.hpp>
31 #include <com/sun/star/container/XEnumerationAccess.hpp>
33 using ::com::sun::star::uno::Reference;
34 using namespace ::com::sun::star;
36 namespace slideshow { namespace internal {
39 namespace {
41 class RewinderEventHandler : public EventHandler
43 public:
44 typedef ::std::function<bool ()> Action;
45 explicit RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
47 private:
48 const Action maAction;
49 virtual bool handleEvent() override { return maAction(); }
53 class RewinderAnimationEventHandler : public AnimationEventHandler
55 public:
56 typedef ::std::function<bool (const AnimationNodeSharedPtr& rpNode)> Action;
57 explicit RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
59 private:
60 const Action maAction;
61 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode) override
62 { return maAction(rpNode); }
66 } // end of anonymous namespace
69 //----- EffectRewinder --------------------------------------------------------------
71 EffectRewinder::EffectRewinder (
72 EventMultiplexer& rEventMultiplexer,
73 EventQueue& rEventQueue,
74 UserEventQueue& rUserEventQueue)
75 : mrEventMultiplexer(rEventMultiplexer),
76 mrEventQueue(rEventQueue),
77 mrUserEventQueue(rUserEventQueue),
78 mpSlideStartHandler(),
79 mpSlideEndHandler(),
80 mpAnimationStartHandler(),
81 mnMainSequenceEffectCount(0),
82 mpAsynchronousRewindEvent(),
83 mxCurrentAnimationRootNode(),
84 mbNonUserTriggeredMainSequenceEffectSeen(false)
86 initialize();
90 void EffectRewinder::initialize()
92 // Add some event handlers so that we are informed when
93 // a) an animation is started (we then check whether that belongs to a
94 // main sequence effect and if so, increase the respective counter),
95 // b,c) a slide was started or ended (in which case the effect counter
96 // is reset.
98 mpAnimationStartHandler.reset(
99 new RewinderAnimationEventHandler(
100 [this]( const AnimationNodeSharedPtr& pNode)
101 { return this->notifyAnimationStart( pNode ); } ) );
102 mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler);
104 mpSlideStartHandler.reset(
105 new RewinderEventHandler(
106 [this]() { return this->resetEffectCount(); } ) );
107 mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler);
109 mpSlideEndHandler.reset(
110 new RewinderEventHandler(
111 [this]() { return this->resetEffectCount(); } ) );
112 mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
116 EffectRewinder::~EffectRewinder()
118 dispose();
122 void EffectRewinder::dispose()
124 if (mpAsynchronousRewindEvent)
126 mpAsynchronousRewindEvent->dispose();
127 mpAsynchronousRewindEvent.reset();
130 if (mpAnimationStartHandler)
132 mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler);
133 mpAnimationStartHandler.reset();
136 if (mpSlideStartHandler)
138 mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler);
139 mpSlideStartHandler.reset();
142 if (mpSlideEndHandler)
144 mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler);
145 mpSlideEndHandler.reset();
150 void EffectRewinder::setRootAnimationNode (
151 const uno::Reference<animations::XAnimationNode>& xRootNode)
153 mxCurrentAnimationRootNode = xRootNode;
157 bool EffectRewinder::rewind (
158 const ::std::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
159 const ::std::function<void ()>& rSlideRewindFunctor,
160 const ::std::function<void ()>& rPreviousSlideFunctor)
162 mpPaintLock = rpPaintLock;
164 // Do not allow nested rewinds.
165 if (mpAsynchronousRewindEvent)
167 OSL_ASSERT( ! mpAsynchronousRewindEvent);
168 return false;
171 // Abort (and skip over the rest of) any currently active animation.
172 mrUserEventQueue.callSkipEffectEventHandler();
173 mrEventQueue.forceEmpty();
175 const int nSkipCount (mnMainSequenceEffectCount - 1);
176 if (nSkipCount < 0)
178 if ( ! rPreviousSlideFunctor)
180 OSL_ASSERT(rPreviousSlideFunctor);
181 return false;
184 // No main sequence effects to rewind on the current slide.
185 // Go back to the previous slide.
186 mpAsynchronousRewindEvent = makeEvent(
187 ::std::bind(
188 &EffectRewinder::asynchronousRewindToPreviousSlide,
189 this,
190 rPreviousSlideFunctor),
191 "EffectRewinder::asynchronousRewindToPreviousSlide");
193 else
195 // The actual rewinding is done asynchronously so that we can safely
196 // call other methods.
197 mpAsynchronousRewindEvent = makeEvent(
198 ::std::bind(
199 &EffectRewinder::asynchronousRewind,
200 this,
201 nSkipCount,
202 true,
203 rSlideRewindFunctor),
204 "EffectRewinder::asynchronousRewind");
207 if (mpAsynchronousRewindEvent)
208 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
210 return mpAsynchronousRewindEvent.get()!=nullptr;
214 void EffectRewinder::skipAllMainSequenceEffects()
216 // Do not allow nested rewinds.
217 if (mpAsynchronousRewindEvent)
219 OSL_ASSERT(!mpAsynchronousRewindEvent);
220 return;
223 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
224 mpAsynchronousRewindEvent = makeEvent(
225 ::std::bind(
226 &EffectRewinder::asynchronousRewind,
227 this,
228 nTotalMainSequenceEffectCount,
229 false,
230 ::std::function<void ()>()),
231 "EffectRewinder::asynchronousRewind");
232 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
236 sal_Int32 EffectRewinder::countMainSequenceEffects()
238 // Determine the number of main sequence effects.
239 sal_Int32 nMainSequenceNodeCount (0);
241 ::std::queue<uno::Reference<animations::XAnimationNode> > aNodeQueue;
242 aNodeQueue.push(mxCurrentAnimationRootNode);
243 while ( ! aNodeQueue.empty())
245 const uno::Reference<animations::XAnimationNode> xNode (aNodeQueue.front());
246 aNodeQueue.pop();
248 // Does the current node belong to the main sequence?
249 if (xNode.is())
251 animations::Event aEvent;
252 if (xNode->getBegin() >>= aEvent)
253 if (aEvent.Trigger == animations::EventTrigger::ON_NEXT)
254 ++nMainSequenceNodeCount;
257 // If the current node is a container then prepare its children for investigation.
258 uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY);
259 if (xEnumerationAccess.is())
261 uno::Reference<container::XEnumeration> xEnumeration (
262 xEnumerationAccess->createEnumeration());
263 if (xEnumeration.is())
264 while (xEnumeration->hasMoreElements())
266 aNodeQueue.push(
267 uno::Reference<animations::XAnimationNode>(
268 xEnumeration->nextElement(), uno::UNO_QUERY));
273 return nMainSequenceNodeCount;
277 void EffectRewinder::skipSingleMainSequenceEffects()
279 // This basically just starts the next effect and then skips over its
280 // animation.
281 mrEventMultiplexer.notifyNextEffect();
282 mrEventQueue.forceEmpty();
283 mrUserEventQueue.callSkipEffectEventHandler();
284 mrEventQueue.forceEmpty();
288 bool EffectRewinder::resetEffectCount()
290 mnMainSequenceEffectCount = 0;
291 return false;
295 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr& rpNode)
297 // This notification is only relevant for us when the rpNode belongs to
298 // the main sequence.
299 BaseNodeSharedPtr pBaseNode (::std::dynamic_pointer_cast<BaseNode>(rpNode));
300 if ( ! pBaseNode)
301 return false;
303 BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
304 if ( ! (pParent && pParent->isMainSequenceRootNode()))
305 return false;
307 // This notification is only relevant for us when the effect is user
308 // triggered.
309 bool bIsUserTriggered (false);
311 Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode());
312 if (xNode.is())
314 animations::Event aEvent;
315 if (xNode->getBegin() >>= aEvent)
316 bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT);
319 if (bIsUserTriggered)
320 ++mnMainSequenceEffectCount;
321 else
322 mbNonUserTriggeredMainSequenceEffectSeen = true;
324 return false;
328 void EffectRewinder::asynchronousRewind (
329 sal_Int32 nEffectCount,
330 const bool bRedisplayCurrentSlide,
331 const std::function<void ()>& rSlideRewindFunctor)
333 OSL_ASSERT(mpAsynchronousRewindEvent);
335 if (bRedisplayCurrentSlide)
337 mpPaintLock->Activate();
338 // Re-display the current slide.
339 if (rSlideRewindFunctor)
340 rSlideRewindFunctor();
341 mpAsynchronousRewindEvent = makeEvent(
342 ::std::bind(
343 &EffectRewinder::asynchronousRewind,
344 this,
345 nEffectCount,
346 false,
347 rSlideRewindFunctor),
348 "EffectRewinder::asynchronousRewind");
349 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
351 else
353 // Process initial events and skip any animations that are started
354 // when the slide is shown.
355 mbNonUserTriggeredMainSequenceEffectSeen = false;
356 mrEventQueue.forceEmpty();
357 if (mbNonUserTriggeredMainSequenceEffectSeen)
359 mrUserEventQueue.callSkipEffectEventHandler();
360 mrEventQueue.forceEmpty();
363 while (--nEffectCount >= 0)
364 skipSingleMainSequenceEffects();
366 mpAsynchronousRewindEvent.reset();
367 mpPaintLock.reset();
372 void EffectRewinder::asynchronousRewindToPreviousSlide (
373 const ::std::function<void ()>& rSlideRewindFunctor)
375 OSL_ASSERT(mpAsynchronousRewindEvent);
377 mpAsynchronousRewindEvent.reset();
378 rSlideRewindFunctor();
382 } } // end of namespace ::slideshow::internal
384 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */