fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / slideshow / source / engine / effectrewinder.cxx
blob94985986a02cce741cf2a4345a5499563f209819
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 "animationnodes/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>
32 #include <boost/function.hpp>
33 #include <boost/bind.hpp>
34 #include <boost/enable_shared_from_this.hpp>
36 using ::com::sun::star::uno::Reference;
37 using namespace ::com::sun::star;
39 namespace slideshow { namespace internal {
42 namespace {
44 class RewinderEventHandler : public EventHandler
46 public:
47 typedef ::boost::function<bool()> Action;
48 RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
49 virtual ~RewinderEventHandler() {}
50 private:
51 const Action maAction;
52 virtual bool handleEvent() SAL_OVERRIDE { return maAction(); }
57 class RewinderAnimationEventHandler : public AnimationEventHandler
59 public:
60 typedef ::boost::function<bool(const AnimationNodeSharedPtr& rpNode)> Action;
61 RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
62 virtual ~RewinderAnimationEventHandler() {}
63 private:
64 const Action maAction;
65 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode) SAL_OVERRIDE
66 { return maAction(rpNode); }
71 } // end of anonymous namespace
74 //----- EffectRewinder --------------------------------------------------------------
76 EffectRewinder::EffectRewinder (
77 EventMultiplexer& rEventMultiplexer,
78 EventQueue& rEventQueue,
79 UserEventQueue& rUserEventQueue)
80 : mrEventMultiplexer(rEventMultiplexer),
81 mrEventQueue(rEventQueue),
82 mrUserEventQueue(rUserEventQueue),
83 mpSlideStartHandler(),
84 mpSlideEndHandler(),
85 mpAnimationStartHandler(),
86 mnMainSequenceEffectCount(0),
87 mpAsynchronousRewindEvent(),
88 mxCurrentAnimationRootNode(),
89 mbNonUserTriggeredMainSequenceEffectSeen(false)
91 initialize();
97 void EffectRewinder::initialize()
99 // Add some event handlers so that we are informed when
100 // a) an animation is started (we then check whether that belongs to a
101 // main sequence effect and if so, increase the respective counter),
102 // b,c) a slide was started or ended (in which case the effect counter
103 // is reset.
105 mpAnimationStartHandler.reset(
106 new RewinderAnimationEventHandler(
107 ::boost::bind(&EffectRewinder::notifyAnimationStart, this, _1)));
108 mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler);
110 mpSlideStartHandler.reset(
111 new RewinderEventHandler(
112 ::boost::bind(&EffectRewinder::resetEffectCount, this)));
113 mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler);
115 mpSlideEndHandler.reset(
116 new RewinderEventHandler(
117 ::boost::bind(&EffectRewinder::resetEffectCount, this)));
118 mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
124 EffectRewinder::~EffectRewinder()
126 dispose();
132 void EffectRewinder::dispose()
134 if (mpAsynchronousRewindEvent)
136 mpAsynchronousRewindEvent->dispose();
137 mpAsynchronousRewindEvent.reset();
140 if (mpAnimationStartHandler)
142 mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler);
143 mpAnimationStartHandler.reset();
146 if (mpSlideStartHandler)
148 mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler);
149 mpSlideStartHandler.reset();
152 if (mpSlideEndHandler)
154 mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler);
155 mpSlideEndHandler.reset();
162 void EffectRewinder::setRootAnimationNode (
163 const uno::Reference<animations::XAnimationNode>& xRootNode)
165 mxCurrentAnimationRootNode = xRootNode;
171 bool EffectRewinder::rewind (
172 const ::boost::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
173 const ::boost::function<void()>& rSlideRewindFunctor,
174 const ::boost::function<void()>& rPreviousSlideFunctor)
176 mpPaintLock = rpPaintLock;
178 // Do not allow nested rewinds.
179 if (mpAsynchronousRewindEvent)
181 OSL_ASSERT( ! mpAsynchronousRewindEvent);
182 return false;
185 // Abort (and skip over the rest of) any currently active animation.
186 mrUserEventQueue.callSkipEffectEventHandler();
187 mrEventQueue.forceEmpty();
189 const int nSkipCount (mnMainSequenceEffectCount - 1);
190 if (nSkipCount < 0)
192 if ( ! rPreviousSlideFunctor)
194 OSL_ASSERT(rPreviousSlideFunctor);
195 return false;
198 // No main sequence effects to rewind on the current slide.
199 // Go back to the previous slide.
200 mpAsynchronousRewindEvent = makeEvent(
201 ::boost::bind(
202 &EffectRewinder::asynchronousRewindToPreviousSlide,
203 this,
204 rPreviousSlideFunctor),
205 "EffectRewinder::asynchronousRewindToPreviousSlide");
207 else
209 // The actual rewinding is done asynchronously so that we can safely
210 // call other methods.
211 mpAsynchronousRewindEvent = makeEvent(
212 ::boost::bind(
213 &EffectRewinder::asynchronousRewind,
214 this,
215 nSkipCount,
216 true,
217 rSlideRewindFunctor),
218 "EffectRewinder::asynchronousRewind");
221 if (mpAsynchronousRewindEvent)
222 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
224 return mpAsynchronousRewindEvent.get()!=NULL;
230 void EffectRewinder::skipAllMainSequenceEffects()
232 // Do not allow nested rewinds.
233 if (mpAsynchronousRewindEvent)
235 OSL_ASSERT(!mpAsynchronousRewindEvent);
236 return;
239 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
240 mpAsynchronousRewindEvent = makeEvent(
241 ::boost::bind(
242 &EffectRewinder::asynchronousRewind,
243 this,
244 nTotalMainSequenceEffectCount,
245 false,
246 ::boost::function<void()>()),
247 "EffectRewinder::asynchronousRewind");
248 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
254 sal_Int32 EffectRewinder::countMainSequenceEffects()
256 // Determine the number of main sequence effects.
257 sal_Int32 nMainSequenceNodeCount (0);
259 ::std::queue<uno::Reference<animations::XAnimationNode> > aNodeQueue;
260 aNodeQueue.push(mxCurrentAnimationRootNode);
261 while ( ! aNodeQueue.empty())
263 const uno::Reference<animations::XAnimationNode> xNode (aNodeQueue.front());
264 aNodeQueue.pop();
266 // Does the current node belong to the main sequence?
267 if (xNode.is())
269 animations::Event aEvent;
270 if (xNode->getBegin() >>= aEvent)
271 if (aEvent.Trigger == animations::EventTrigger::ON_NEXT)
272 ++nMainSequenceNodeCount;
275 // If the current node is a container then prepare its children for investigation.
276 uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY);
277 if (xEnumerationAccess.is())
279 uno::Reference<container::XEnumeration> xEnumeration (
280 xEnumerationAccess->createEnumeration());
281 if (xEnumeration.is())
282 while (xEnumeration->hasMoreElements())
284 aNodeQueue.push(
285 uno::Reference<animations::XAnimationNode>(
286 xEnumeration->nextElement(), uno::UNO_QUERY));
291 return nMainSequenceNodeCount;
297 void EffectRewinder::skipSingleMainSequenceEffects()
299 // This basically just starts the next effect and then skips over its
300 // animation.
301 mrEventMultiplexer.notifyNextEffect();
302 mrEventQueue.forceEmpty();
303 mrUserEventQueue.callSkipEffectEventHandler();
304 mrEventQueue.forceEmpty();
310 bool EffectRewinder::resetEffectCount()
312 mnMainSequenceEffectCount = 0;
313 return false;
319 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr& rpNode)
321 // This notification is only relevant for us when the rpNode belongs to
322 // the main sequence.
323 BaseNodeSharedPtr pBaseNode (::boost::dynamic_pointer_cast<BaseNode>(rpNode));
324 if ( ! pBaseNode)
325 return false;
327 BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
328 if ( ! (pParent && pParent->isMainSequenceRootNode()))
329 return false;
331 // This notification is only relevant for us when the effect is user
332 // triggered.
333 bool bIsUserTriggered (false);
335 Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode());
336 if (xNode.is())
338 animations::Event aEvent;
339 if ((xNode->getBegin() >>= aEvent))
340 bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT);
343 if (bIsUserTriggered)
344 ++mnMainSequenceEffectCount;
345 else
346 mbNonUserTriggeredMainSequenceEffectSeen = true;
348 return false;
354 void EffectRewinder::asynchronousRewind (
355 sal_Int32 nEffectCount,
356 const bool bRedisplayCurrentSlide,
357 const boost::function<void()>& rSlideRewindFunctor)
359 OSL_ASSERT(mpAsynchronousRewindEvent);
361 if (bRedisplayCurrentSlide)
363 mpPaintLock->Activate();
364 // Re-display the current slide.
365 if (rSlideRewindFunctor)
366 rSlideRewindFunctor();
367 mpAsynchronousRewindEvent = makeEvent(
368 ::boost::bind(
369 &EffectRewinder::asynchronousRewind,
370 this,
371 nEffectCount,
372 false,
373 rSlideRewindFunctor),
374 "EffectRewinder::asynchronousRewind");
375 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
377 else
379 // Process initial events and skip any animations that are started
380 // when the slide is shown.
381 mbNonUserTriggeredMainSequenceEffectSeen = false;
382 mrEventQueue.forceEmpty();
383 if (mbNonUserTriggeredMainSequenceEffectSeen)
385 mrUserEventQueue.callSkipEffectEventHandler();
386 mrEventQueue.forceEmpty();
389 while (--nEffectCount >= 0)
390 skipSingleMainSequenceEffects();
392 mpAsynchronousRewindEvent.reset();
393 mpPaintLock.reset();
400 void EffectRewinder::asynchronousRewindToPreviousSlide (
401 const ::boost::function<void()>& rSlideRewindFunctor)
403 OSL_ASSERT(mpAsynchronousRewindEvent);
405 mpAsynchronousRewindEvent.reset();
406 rSlideRewindFunctor();
412 } } // end of namespace ::slideshow::internal
414 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */