Use o3tl::convert in Math
[LibreOffice.git] / slideshow / source / engine / effectrewinder.cxx
blob48a83d591437dbfd14f3a1205d20e88c57be2d94
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 <basecontainernode.hxx>
25 #include <delayevent.hxx>
27 #include <com/sun/star/animations/Event.hpp>
28 #include <com/sun/star/animations/EventTrigger.hpp>
29 #include <com/sun/star/container/XEnumerationAccess.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
32 using ::com::sun::star::uno::Reference;
33 using namespace ::com::sun::star;
35 namespace slideshow::internal {
38 namespace {
40 class RewinderEventHandler : public EventHandler
42 public:
43 typedef ::std::function<bool ()> Action;
44 explicit RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
46 private:
47 const Action maAction;
48 virtual bool handleEvent() override { return maAction(); }
52 class RewinderAnimationEventHandler : public AnimationEventHandler
54 public:
55 typedef ::std::function<bool (const AnimationNodeSharedPtr& rpNode)> Action;
56 explicit RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
58 private:
59 const Action maAction;
60 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode) override
61 { return maAction(rpNode); }
65 } // end of anonymous namespace
68 //----- EffectRewinder --------------------------------------------------------------
70 EffectRewinder::EffectRewinder (
71 EventMultiplexer& rEventMultiplexer,
72 EventQueue& rEventQueue,
73 UserEventQueue& rUserEventQueue)
74 : mrEventMultiplexer(rEventMultiplexer),
75 mrEventQueue(rEventQueue),
76 mrUserEventQueue(rUserEventQueue),
77 mpSlideStartHandler(),
78 mpSlideEndHandler(),
79 mpAnimationStartHandler(),
80 mnMainSequenceEffectCount(0),
81 mpAsynchronousRewindEvent(),
82 mxCurrentAnimationRootNode(),
83 mxCurrentSlide(),
84 mbNonUserTriggeredMainSequenceEffectSeen(false),
85 mbHasAdvancedTimeSetting(false)
87 initialize();
91 void EffectRewinder::initialize()
93 // Add some event handlers so that we are informed when
94 // a) an animation is started (we then check whether that belongs to a
95 // main sequence effect and if so, increase the respective counter),
96 // b,c) a slide was started or ended (in which case the effect counter
97 // is reset.
99 mpAnimationStartHandler =
100 std::make_shared<RewinderAnimationEventHandler>(
101 [this]( const AnimationNodeSharedPtr& pNode)
102 { return this->notifyAnimationStart( pNode ); } );
103 mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler);
105 mpSlideStartHandler =
106 std::make_shared<RewinderEventHandler>(
107 [this]() { return this->resetEffectCount(); } );
108 mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler);
110 mpSlideEndHandler =
111 std::make_shared<RewinderEventHandler>(
112 [this]() { return this->resetEffectCount(); } );
113 mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
117 EffectRewinder::~EffectRewinder()
119 dispose();
123 void EffectRewinder::dispose()
125 if (mpAsynchronousRewindEvent)
127 mpAsynchronousRewindEvent->dispose();
128 mpAsynchronousRewindEvent.reset();
131 if (mpAnimationStartHandler)
133 mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler);
134 mpAnimationStartHandler.reset();
137 if (mpSlideStartHandler)
139 mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler);
140 mpSlideStartHandler.reset();
143 if (mpSlideEndHandler)
145 mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler);
146 mpSlideEndHandler.reset();
151 void EffectRewinder::setRootAnimationNode (
152 const uno::Reference<animations::XAnimationNode>& xRootNode)
154 mxCurrentAnimationRootNode = xRootNode;
157 void EffectRewinder::setCurrentSlide (
158 const uno::Reference<drawing::XDrawPage>& xSlide)
160 mxCurrentSlide = xSlide;
162 // Check if the current slide has advance time setting or not
163 uno::Reference< beans::XPropertySet > xPropSet( mxCurrentSlide, uno::UNO_QUERY );
164 sal_Int32 nChange(0);
166 if( xPropSet.is())
167 getPropertyValue( nChange, xPropSet, "Change");
169 mbHasAdvancedTimeSetting = nChange;
172 bool EffectRewinder::rewind (
173 const ::std::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
174 const ::std::function<void ()>& rSlideRewindFunctor,
175 const ::std::function<void ()>& rPreviousSlideFunctor)
177 mpPaintLock = rpPaintLock;
179 // Do not allow nested rewinds.
180 if (mpAsynchronousRewindEvent)
182 OSL_ASSERT( ! mpAsynchronousRewindEvent);
183 return false;
186 // Abort (and skip over the rest of) any currently active animation.
187 mrUserEventQueue.callSkipEffectEventHandler();
189 if (!mbHasAdvancedTimeSetting)
190 mrEventQueue.forceEmpty();
192 const int nSkipCount (mnMainSequenceEffectCount - 1);
193 if (nSkipCount < 0)
195 if ( ! rPreviousSlideFunctor)
197 OSL_ASSERT(rPreviousSlideFunctor);
198 return false;
201 // No main sequence effects to rewind on the current slide.
202 // Go back to the previous slide.
203 mpAsynchronousRewindEvent = makeEvent(
204 ::std::bind(
205 &EffectRewinder::asynchronousRewindToPreviousSlide,
206 this,
207 rPreviousSlideFunctor),
208 "EffectRewinder::asynchronousRewindToPreviousSlide");
210 else
212 // The actual rewinding is done asynchronously so that we can safely
213 // call other methods.
214 mpAsynchronousRewindEvent = makeEvent(
215 ::std::bind(
216 &EffectRewinder::asynchronousRewind,
217 this,
218 nSkipCount,
219 true,
220 rSlideRewindFunctor),
221 "EffectRewinder::asynchronousRewind");
224 if (mpAsynchronousRewindEvent)
225 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
227 return bool(mpAsynchronousRewindEvent);
231 void EffectRewinder::skipAllMainSequenceEffects()
233 // Do not allow nested rewinds.
234 if (mpAsynchronousRewindEvent)
236 OSL_ASSERT(!mpAsynchronousRewindEvent);
237 return;
240 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
241 mpAsynchronousRewindEvent = makeEvent(
242 ::std::bind(
243 &EffectRewinder::asynchronousRewind,
244 this,
245 nTotalMainSequenceEffectCount,
246 false,
247 ::std::function<void ()>()),
248 "EffectRewinder::asynchronousRewind");
249 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
253 sal_Int32 EffectRewinder::countMainSequenceEffects()
255 // Determine the number of main sequence effects.
256 sal_Int32 nMainSequenceNodeCount (0);
258 ::std::queue<uno::Reference<animations::XAnimationNode> > aNodeQueue;
259 aNodeQueue.push(mxCurrentAnimationRootNode);
260 while ( ! aNodeQueue.empty())
262 const uno::Reference<animations::XAnimationNode> xNode (aNodeQueue.front());
263 aNodeQueue.pop();
265 // Does the current node belong to the main sequence?
266 if (xNode.is())
268 animations::Event aEvent;
269 if (xNode->getBegin() >>= aEvent)
270 if (aEvent.Trigger == animations::EventTrigger::ON_NEXT)
271 ++nMainSequenceNodeCount;
274 // If the current node is a container then prepare its children for investigation.
275 uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY);
276 if (xEnumerationAccess.is())
278 uno::Reference<container::XEnumeration> xEnumeration (
279 xEnumerationAccess->createEnumeration());
280 if (xEnumeration.is())
281 while (xEnumeration->hasMoreElements())
283 aNodeQueue.push(
284 uno::Reference<animations::XAnimationNode>(
285 xEnumeration->nextElement(), uno::UNO_QUERY));
290 return nMainSequenceNodeCount;
294 void EffectRewinder::skipSingleMainSequenceEffects()
296 // This basically just starts the next effect and then skips over its
297 // animation.
298 mrEventMultiplexer.notifyNextEffect();
299 mrEventQueue.forceEmpty();
300 mrUserEventQueue.callSkipEffectEventHandler();
301 mrEventQueue.forceEmpty();
305 bool EffectRewinder::resetEffectCount()
307 mnMainSequenceEffectCount = 0;
308 return false;
312 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr& rpNode)
314 // This notification is only relevant for us when the rpNode belongs to
315 // the main sequence.
316 BaseNodeSharedPtr pBaseNode (::std::dynamic_pointer_cast<BaseNode>(rpNode));
317 if ( ! pBaseNode)
318 return false;
320 BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
321 if ( ! (pParent && pParent->isMainSequenceRootNode()))
322 return false;
324 // This notification is only relevant for us when the effect is user
325 // triggered.
326 bool bIsUserTriggered (false);
328 Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode());
329 if (xNode.is())
331 animations::Event aEvent;
332 if (xNode->getBegin() >>= aEvent)
333 bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT);
336 if (bIsUserTriggered)
337 ++mnMainSequenceEffectCount;
338 else
339 mbNonUserTriggeredMainSequenceEffectSeen = true;
341 return false;
345 void EffectRewinder::asynchronousRewind (
346 sal_Int32 nEffectCount,
347 const bool bRedisplayCurrentSlide,
348 const std::function<void ()>& rSlideRewindFunctor)
350 OSL_ASSERT(mpAsynchronousRewindEvent);
352 if (bRedisplayCurrentSlide)
354 mpPaintLock->Activate();
355 // Re-display the current slide.
356 if (rSlideRewindFunctor)
357 rSlideRewindFunctor();
358 mpAsynchronousRewindEvent = makeEvent(
359 ::std::bind(
360 &EffectRewinder::asynchronousRewind,
361 this,
362 nEffectCount,
363 false,
364 rSlideRewindFunctor),
365 "EffectRewinder::asynchronousRewind");
366 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
368 else
370 // Process initial events and skip any animations that are started
371 // when the slide is shown.
372 mbNonUserTriggeredMainSequenceEffectSeen = false;
374 if (!mbHasAdvancedTimeSetting)
375 mrEventQueue.forceEmpty();
377 if (mbNonUserTriggeredMainSequenceEffectSeen)
379 mrUserEventQueue.callSkipEffectEventHandler();
380 mrEventQueue.forceEmpty();
383 while (--nEffectCount >= 0)
384 skipSingleMainSequenceEffects();
386 mpAsynchronousRewindEvent.reset();
387 mpPaintLock.reset();
392 void EffectRewinder::asynchronousRewindToPreviousSlide (
393 const ::std::function<void ()>& rSlideRewindFunctor)
395 OSL_ASSERT(mpAsynchronousRewindEvent);
397 mpAsynchronousRewindEvent.reset();
398 rSlideRewindFunctor();
402 } // end of namespace ::slideshow::internal
404 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */