bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsInsertAnimator.cxx
blobad3a4a9ae83dec315d04f5b3ef81dcd955847e14
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 .
20 #include "view/SlsInsertAnimator.hxx"
21 #include "controller/SlideSorterController.hxx"
22 #include "controller/SlsAnimationFunction.hxx"
23 #include "view/SlideSorterView.hxx"
24 #include "view/SlsLayouter.hxx"
25 #include "model/SlideSorterModel.hxx"
26 #include "model/SlsPageEnumerationProvider.hxx"
28 #include <set>
29 #include <boost/bind.hpp>
30 #include <boost/enable_shared_from_this.hpp>
32 namespace sd { namespace slidesorter { namespace view {
34 namespace {
36 class PageObjectRun;
38 class AnimatorAccess
40 public:
41 virtual void AddRun (const ::boost::shared_ptr<PageObjectRun>& rRun) = 0;
42 virtual void RemoveRun (const ::boost::shared_ptr<PageObjectRun>& rRun) = 0;
43 virtual model::SlideSorterModel& GetModel (void) const = 0;
44 virtual view::SlideSorterView& GetView (void) const = 0;
45 virtual ::boost::shared_ptr<controller::Animator> GetAnimator (void) = 0;
46 virtual VclPtr<sd::Window> GetContentWindow (void) = 0;
48 protected:
49 ~AnimatorAccess() {}
52 /** Controller of the position offsets of all page objects in one row or one
53 column.
55 class PageObjectRun : public ::boost::enable_shared_from_this<PageObjectRun>
57 public:
58 PageObjectRun (
59 AnimatorAccess& rAnimatorAccess,
60 const sal_Int32 nRunIndex,
61 const sal_Int32 nStartIndex,
62 const sal_Int32 nEndIndex);
63 ~PageObjectRun();
65 void operator () (const double nTime);
67 void UpdateOffsets(
68 const InsertPosition& rInsertPosition,
69 const view::Layouter& GetLayouter);
70 void ResetOffsets (const controller::Animator::AnimationMode eMode);
72 /// Index of the row or column that this run represents.
73 sal_Int32 mnRunIndex;
74 /// The index at which to make place for the insertion indicator (-1 for
75 /// no indicator).
76 sal_Int32 mnLocalInsertIndex;
77 /// Index of the first page in the run.
78 sal_Int32 mnStartIndex;
79 /// Index of the last page in the run.
80 sal_Int32 mnEndIndex;
81 /// Offset of each item in the run at the start of the current animation.
82 ::std::vector<Point> maStartOffset;
83 /// Target offset of each item in the run at the end of the current animation.
84 ::std::vector<Point> maEndOffset;
85 /// Time at which the current animation started.
86 double mnStartTime;
88 class Comparator
90 public: bool operator() (
91 const ::boost::shared_ptr<PageObjectRun>& rpRunA,
92 const ::boost::shared_ptr<PageObjectRun>& rpRunB) const
94 return rpRunA->mnRunIndex < rpRunB->mnRunIndex;
97 private:
98 controller::Animator::AnimationId mnAnimationId;
99 AnimatorAccess& mrAnimatorAccess;
100 ::boost::function<double(double)> maAccelerationFunction;
102 void RestartAnimation();
104 typedef ::boost::shared_ptr<PageObjectRun> SharedPageObjectRun;
106 Point Blend (const Point& rPointA, const Point& rPointB, const double nT)
108 return Point(
109 sal_Int32(rPointA.X() * (1-nT) + rPointB.X() * nT),
110 sal_Int32(rPointA.Y() * (1-nT) + rPointB.Y() * nT));
113 } // end of anonymous namespace
115 class InsertAnimator::Implementation : public AnimatorAccess
117 public:
118 Implementation (SlideSorter& rSlideSorter);
119 virtual ~Implementation();
121 void SetInsertPosition (
122 const InsertPosition& rInsertPosition,
123 const controller::Animator::AnimationMode eAnimationMode);
125 virtual void AddRun (const ::boost::shared_ptr<PageObjectRun>& rRun) SAL_OVERRIDE;
126 virtual void RemoveRun (const ::boost::shared_ptr<PageObjectRun>& rRun) SAL_OVERRIDE;
128 virtual model::SlideSorterModel& GetModel() const SAL_OVERRIDE { return mrModel; }
129 virtual view::SlideSorterView& GetView() const SAL_OVERRIDE { return mrView; }
130 virtual ::boost::shared_ptr<controller::Animator> GetAnimator() SAL_OVERRIDE { return mpAnimator; }
131 virtual VclPtr<sd::Window> GetContentWindow() SAL_OVERRIDE { return mrSlideSorter.GetContentWindow(); }
133 private:
134 model::SlideSorterModel& mrModel;
135 view::SlideSorterView& mrView;
136 SlideSorter& mrSlideSorter;
137 ::boost::shared_ptr<controller::Animator> mpAnimator;
138 typedef ::std::set<SharedPageObjectRun, PageObjectRun::Comparator> RunContainer;
139 RunContainer maRuns;
140 InsertPosition maInsertPosition;
142 SharedPageObjectRun GetRun (
143 view::Layouter& rLayouter,
144 const InsertPosition& rInsertPosition,
145 const bool bCreate = true);
146 RunContainer::const_iterator FindRun (const sal_Int32 nRunIndex) const;
149 //===== InsertAnimator ========================================================
151 InsertAnimator::InsertAnimator (SlideSorter& rSlideSorter)
152 : mpImplementation(new Implementation(rSlideSorter))
156 void InsertAnimator::SetInsertPosition (const InsertPosition& rInsertPosition)
158 mpImplementation->SetInsertPosition(rInsertPosition, controller::Animator::AM_Animated);
161 void InsertAnimator::Reset (const controller::Animator::AnimationMode eMode)
163 mpImplementation->SetInsertPosition(InsertPosition(), eMode);
166 //===== InsertAnimator::Implementation ========================================
168 InsertAnimator::Implementation::Implementation (SlideSorter& rSlideSorter)
169 : mrModel(rSlideSorter.GetModel()),
170 mrView(rSlideSorter.GetView()),
171 mrSlideSorter(rSlideSorter),
172 mpAnimator(rSlideSorter.GetController().GetAnimator()),
173 maRuns(),
174 maInsertPosition()
178 InsertAnimator::Implementation::~Implementation()
180 SetInsertPosition(InsertPosition(), controller::Animator::AM_Immediate);
183 void InsertAnimator::Implementation::SetInsertPosition (
184 const InsertPosition& rInsertPosition,
185 const controller::Animator::AnimationMode eMode)
187 if (maInsertPosition == rInsertPosition)
188 return;
190 SharedPageObjectRun pOldRun (GetRun(mrView.GetLayouter(), maInsertPosition));
191 SharedPageObjectRun pCurrentRun (GetRun(mrView.GetLayouter(), rInsertPosition));
192 maInsertPosition = rInsertPosition;
194 // When the new insert position is in a different run then move the page
195 // objects in the old run to their default positions.
196 if (pOldRun != pCurrentRun)
198 if (pOldRun)
199 pOldRun->ResetOffsets(eMode);
202 if (pCurrentRun)
204 pCurrentRun->UpdateOffsets(rInsertPosition, mrView.GetLayouter());
208 SharedPageObjectRun InsertAnimator::Implementation::GetRun (
209 view::Layouter& rLayouter,
210 const InsertPosition& rInsertPosition,
211 const bool bCreate)
213 const sal_Int32 nRow (rInsertPosition.GetRow());
214 if (nRow < 0)
215 return SharedPageObjectRun();
217 RunContainer::const_iterator iRun (maRuns.end());
218 if (rLayouter.GetColumnCount() == 1)
220 // There is only one run that contains all slides.
221 if (maRuns.empty() && bCreate)
222 maRuns.insert(SharedPageObjectRun(new PageObjectRun(
223 *this,
226 mrModel.GetPageCount()-1)));
227 iRun = maRuns.begin();
229 else
231 iRun = FindRun(nRow);
232 if (iRun == maRuns.end() && bCreate)
234 // Create a new run.
235 const sal_Int32 nStartIndex (rLayouter.GetIndex(nRow, 0));
236 const sal_Int32 nEndIndex (rLayouter.GetIndex(nRow, rLayouter.GetColumnCount()-1));
237 if (nStartIndex <= nEndIndex)
239 iRun = maRuns.insert(SharedPageObjectRun(new PageObjectRun(
240 *this,
241 nRow,
242 nStartIndex,
243 nEndIndex))).first;
244 OSL_ASSERT(iRun != maRuns.end());
249 if (iRun != maRuns.end())
250 return *iRun;
251 else
252 return SharedPageObjectRun();
255 InsertAnimator::Implementation::RunContainer::const_iterator
256 InsertAnimator::Implementation::FindRun (const sal_Int32 nRunIndex) const
258 return std::find_if(
259 maRuns.begin(),
260 maRuns.end(),
261 ::boost::bind(
262 ::std::equal_to<sal_Int32>(),
263 ::boost::bind(&PageObjectRun::mnRunIndex, _1),
264 nRunIndex));
267 void InsertAnimator::Implementation::AddRun (const ::boost::shared_ptr<PageObjectRun>& rRun)
269 if (rRun)
271 maRuns.insert(rRun);
273 else
275 OSL_ASSERT(rRun);
279 void InsertAnimator::Implementation::RemoveRun (const ::boost::shared_ptr<PageObjectRun>& rRun)
281 if (rRun)
283 // Do not remove runs that show the space for the insertion indicator.
284 if (rRun->mnLocalInsertIndex == -1)
286 InsertAnimator::Implementation::RunContainer::const_iterator iRun (FindRun(rRun->mnRunIndex));
287 if (iRun != maRuns.end())
289 OSL_ASSERT(*iRun == rRun);
290 maRuns.erase(iRun);
294 else
296 OSL_ASSERT(rRun);
300 //===== PageObjectRun =========================================================
302 PageObjectRun::PageObjectRun (
303 AnimatorAccess& rAnimatorAccess,
304 const sal_Int32 nRunIndex,
305 const sal_Int32 nStartIndex,
306 const sal_Int32 nEndIndex)
307 : mnRunIndex(nRunIndex),
308 mnLocalInsertIndex(-1),
309 mnStartIndex(nStartIndex),
310 mnEndIndex(nEndIndex),
311 maStartOffset(),
312 maEndOffset(),
313 mnStartTime(-1),
314 mnAnimationId(controller::Animator::NotAnAnimationId),
315 mrAnimatorAccess(rAnimatorAccess),
316 maAccelerationFunction(
317 controller::AnimationParametricFunction(
318 controller::AnimationBezierFunction (0.1,0.7)))
320 maStartOffset.resize(nEndIndex - nStartIndex + 1);
321 maEndOffset.resize(nEndIndex - nStartIndex + 1);
324 PageObjectRun::~PageObjectRun()
328 void PageObjectRun::UpdateOffsets(
329 const InsertPosition& rInsertPosition,
330 const view::Layouter& rLayouter)
332 const bool bIsVertical (rLayouter.GetColumnCount()==1);
333 const sal_Int32 nLocalInsertIndex(bIsVertical
334 ? rInsertPosition.GetRow()
335 : rInsertPosition.GetColumn());
336 if (nLocalInsertIndex != mnLocalInsertIndex)
338 mnLocalInsertIndex = nLocalInsertIndex;
340 model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
341 const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1);
342 for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex)
344 model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
345 if (pDescriptor)
346 maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
347 maEndOffset[nIndex] = nIndex < mnLocalInsertIndex
348 ? rInsertPosition.GetLeadingOffset()
349 : rInsertPosition.GetTrailingOffset();
350 if (bIsVertical)
351 maEndOffset[nIndex].X() = 0;
352 else
353 maEndOffset[nIndex].Y() = 0;
355 RestartAnimation();
359 void PageObjectRun::ResetOffsets (const controller::Animator::AnimationMode eMode)
361 mnLocalInsertIndex = -1;
362 const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1);
363 model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
364 view::SlideSorterView& rView (mrAnimatorAccess.GetView());
365 for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex)
367 model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
368 if (pDescriptor)
370 if (eMode == controller::Animator::AM_Animated)
371 maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
372 else
374 const Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
375 pDescriptor->GetVisualState().SetLocationOffset(Point(0,0));
376 rView.RequestRepaint(aOldBoundingBox);
377 rView.RequestRepaint(pDescriptor);
380 maEndOffset[nIndex] = Point(0,0);
382 if (eMode == controller::Animator::AM_Animated)
383 RestartAnimation();
384 else
385 mrAnimatorAccess.RemoveRun(shared_from_this());
388 void PageObjectRun::RestartAnimation()
390 // Stop the current animation.
391 if (mnAnimationId != controller::Animator::NotAnAnimationId)
393 mrAnimatorAccess.GetAnimator()->RemoveAnimation(mnAnimationId);
396 // Restart the animation.
397 mrAnimatorAccess.AddRun(shared_from_this());
398 mnAnimationId = mrAnimatorAccess.GetAnimator()->AddAnimation(
399 ::boost::ref(*this),
401 300,
402 ::boost::bind(
403 &AnimatorAccess::RemoveRun,
404 ::boost::ref(mrAnimatorAccess),
405 shared_from_this()));
408 void PageObjectRun::operator () (const double nGlobalTime)
410 if (mnStartTime < 0)
411 mnStartTime = nGlobalTime;
413 double nLocalTime (nGlobalTime - mnStartTime);
414 if (nLocalTime > 1.0)
415 nLocalTime = 1.0;
416 nLocalTime = maAccelerationFunction(nLocalTime);
418 model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
419 view::SlideSorterView& rView (mrAnimatorAccess.GetView());
420 for (sal_Int32 nIndex=mnStartIndex; nIndex<=mnEndIndex; ++nIndex)
422 model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
423 if ( ! pDescriptor)
424 continue;
425 const Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
426 pDescriptor->GetVisualState().SetLocationOffset(
427 Blend(
428 maStartOffset[nIndex-mnStartIndex],
429 maEndOffset[nIndex-mnStartIndex],
430 nLocalTime));
432 // Request a repaint of the old and new bounding box (which largely overlap.)
433 rView.RequestRepaint(aOldBoundingBox);
434 rView.RequestRepaint(pDescriptor);
437 // Call Flush to make
438 // a) animations a bit more smooth and
439 // b) on Mac without the Flush a Reset of the page locations is not properly
440 // visualized when the mouse leaves the window during drag-and-drop.
441 mrAnimatorAccess.GetContentWindow()->Flush();
444 } } } // end of namespace ::sd::slidesorter::view
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */