bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsInsertAnimator.cxx
blob63ebfe3ddf9a6660ed5957604987efe73c37983e
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>
27 #include <SlideSorter.hxx>
28 #include <Window.hxx>
30 #include <memory>
31 #include <set>
33 namespace sd { namespace slidesorter { namespace view {
35 namespace {
37 class PageObjectRun;
39 class AnimatorAccess
41 public:
42 virtual void AddRun (const std::shared_ptr<PageObjectRun>& rRun) = 0;
43 virtual void RemoveRun (const std::shared_ptr<PageObjectRun>& rRun) = 0;
44 virtual model::SlideSorterModel& GetModel () const = 0;
45 virtual view::SlideSorterView& GetView () const = 0;
46 virtual std::shared_ptr<controller::Animator> GetAnimator () = 0;
47 virtual VclPtr<sd::Window> GetContentWindow () = 0;
49 protected:
50 ~AnimatorAccess() COVERITY_NOEXCEPT_FALSE {}
53 /** Controller of the position offsets of all page objects in one row or one
54 column.
56 class PageObjectRun : public std::enable_shared_from_this<PageObjectRun>
58 public:
59 PageObjectRun (
60 AnimatorAccess& rAnimatorAccess,
61 const sal_Int32 nRunIndex,
62 const sal_Int32 nStartIndex,
63 const sal_Int32 nEndIndex);
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 const 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 const mnStartIndex;
79 /// Index of the last page in the run.
80 sal_Int32 const 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 std::shared_ptr<PageObjectRun>& rpRunA,
92 const std::shared_ptr<PageObjectRun>& rpRunB) const
94 return rpRunA->mnRunIndex < rpRunB->mnRunIndex;
97 private:
98 controller::Animator::AnimationId mnAnimationId;
99 AnimatorAccess& mrAnimatorAccess;
100 ::std::function<double (double)> const maAccelerationFunction;
102 void RestartAnimation();
104 typedef std::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 explicit Implementation (SlideSorter& rSlideSorter);
119 virtual ~Implementation();
121 void SetInsertPosition (
122 const InsertPosition& rInsertPosition,
123 const controller::Animator::AnimationMode eAnimationMode);
125 virtual void AddRun (const std::shared_ptr<PageObjectRun>& rRun) override;
126 virtual void RemoveRun (const std::shared_ptr<PageObjectRun>& rRun) override;
128 virtual model::SlideSorterModel& GetModel() const override { return mrModel; }
129 virtual view::SlideSorterView& GetView() const override { return mrView; }
130 virtual std::shared_ptr<controller::Animator> GetAnimator() override { return mpAnimator; }
131 virtual VclPtr<sd::Window> GetContentWindow() override { return mrSlideSorter.GetContentWindow(); }
133 private:
134 model::SlideSorterModel& mrModel;
135 view::SlideSorterView& mrView;
136 SlideSorter& mrSlideSorter;
137 std::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 const & rLayouter,
144 const InsertPosition& rInsertPosition);
145 RunContainer::const_iterator FindRun (const sal_Int32 nRunIndex) const;
148 //===== InsertAnimator ========================================================
150 InsertAnimator::InsertAnimator (SlideSorter& rSlideSorter)
151 : mpImplementation(new Implementation(rSlideSorter))
155 void InsertAnimator::SetInsertPosition (const InsertPosition& rInsertPosition)
157 mpImplementation->SetInsertPosition(rInsertPosition, controller::Animator::AM_Animated);
160 void InsertAnimator::Reset (const controller::Animator::AnimationMode eMode)
162 mpImplementation->SetInsertPosition(InsertPosition(), eMode);
165 //===== InsertAnimator::Implementation ========================================
167 InsertAnimator::Implementation::Implementation (SlideSorter& rSlideSorter)
168 : mrModel(rSlideSorter.GetModel()),
169 mrView(rSlideSorter.GetView()),
170 mrSlideSorter(rSlideSorter),
171 mpAnimator(rSlideSorter.GetController().GetAnimator()),
172 maRuns(),
173 maInsertPosition()
177 InsertAnimator::Implementation::~Implementation()
179 SetInsertPosition(InsertPosition(), controller::Animator::AM_Immediate);
182 void InsertAnimator::Implementation::SetInsertPosition (
183 const InsertPosition& rInsertPosition,
184 const controller::Animator::AnimationMode eMode)
186 if (maInsertPosition == rInsertPosition)
187 return;
189 SharedPageObjectRun pOldRun (GetRun(mrView.GetLayouter(), maInsertPosition));
190 SharedPageObjectRun pCurrentRun (GetRun(mrView.GetLayouter(), rInsertPosition));
191 maInsertPosition = rInsertPosition;
193 // When the new insert position is in a different run then move the page
194 // objects in the old run to their default positions.
195 if (pOldRun != pCurrentRun && pOldRun)
196 pOldRun->ResetOffsets(eMode);
198 if (pCurrentRun)
200 pCurrentRun->UpdateOffsets(rInsertPosition, mrView.GetLayouter());
204 SharedPageObjectRun InsertAnimator::Implementation::GetRun (
205 view::Layouter const & rLayouter,
206 const InsertPosition& rInsertPosition)
208 const sal_Int32 nRow (rInsertPosition.GetRow());
209 if (nRow < 0)
210 return SharedPageObjectRun();
212 RunContainer::const_iterator iRun (maRuns.end());
213 if (rLayouter.GetColumnCount() == 1)
215 // There is only one run that contains all slides.
216 if (maRuns.empty())
217 maRuns.insert(std::make_shared<PageObjectRun>(
218 *this,
221 mrModel.GetPageCount()-1));
222 iRun = maRuns.begin();
224 else
226 iRun = FindRun(nRow);
227 if (iRun == maRuns.end())
229 // Create a new run.
230 const sal_Int32 nStartIndex (rLayouter.GetIndex(nRow, 0));
231 const sal_Int32 nEndIndex (rLayouter.GetIndex(nRow, rLayouter.GetColumnCount()-1));
232 if (nStartIndex <= nEndIndex)
234 iRun = maRuns.insert(std::make_shared<PageObjectRun>(
235 *this,
236 nRow,
237 nStartIndex,
238 nEndIndex)).first;
239 OSL_ASSERT(iRun != maRuns.end());
244 if (iRun != maRuns.end())
245 return *iRun;
246 else
247 return SharedPageObjectRun();
250 InsertAnimator::Implementation::RunContainer::const_iterator
251 InsertAnimator::Implementation::FindRun (const sal_Int32 nRunIndex) const
253 return std::find_if(
254 maRuns.begin(),
255 maRuns.end(),
256 [nRunIndex] (std::shared_ptr<PageObjectRun> const& rRun)
257 { return rRun->mnRunIndex == nRunIndex; });
260 void InsertAnimator::Implementation::AddRun (const std::shared_ptr<PageObjectRun>& rRun)
262 if (rRun)
264 maRuns.insert(rRun);
266 else
268 OSL_ASSERT(rRun);
272 void InsertAnimator::Implementation::RemoveRun (const std::shared_ptr<PageObjectRun>& rRun)
274 if (rRun)
276 // Do not remove runs that show the space for the insertion indicator.
277 if (rRun->mnLocalInsertIndex == -1)
279 InsertAnimator::Implementation::RunContainer::const_iterator iRun (FindRun(rRun->mnRunIndex));
280 if (iRun != maRuns.end())
282 OSL_ASSERT(*iRun == rRun);
283 maRuns.erase(iRun);
287 else
289 OSL_ASSERT(rRun);
293 //===== PageObjectRun =========================================================
295 PageObjectRun::PageObjectRun (
296 AnimatorAccess& rAnimatorAccess,
297 const sal_Int32 nRunIndex,
298 const sal_Int32 nStartIndex,
299 const sal_Int32 nEndIndex)
300 : mnRunIndex(nRunIndex),
301 mnLocalInsertIndex(-1),
302 mnStartIndex(nStartIndex),
303 mnEndIndex(nEndIndex),
304 maStartOffset(),
305 maEndOffset(),
306 mnStartTime(-1),
307 mnAnimationId(controller::Animator::NotAnAnimationId),
308 mrAnimatorAccess(rAnimatorAccess),
309 maAccelerationFunction(
310 controller::AnimationParametricFunction(
311 controller::AnimationBezierFunction (0.1,0.7)))
313 maStartOffset.resize(nEndIndex - nStartIndex + 1);
314 maEndOffset.resize(nEndIndex - nStartIndex + 1);
317 void PageObjectRun::UpdateOffsets(
318 const InsertPosition& rInsertPosition,
319 const view::Layouter& rLayouter)
321 const bool bIsVertical (rLayouter.GetColumnCount()==1);
322 const sal_Int32 nLocalInsertIndex(bIsVertical
323 ? rInsertPosition.GetRow()
324 : rInsertPosition.GetColumn());
325 if (nLocalInsertIndex == mnLocalInsertIndex)
326 return;
328 mnLocalInsertIndex = nLocalInsertIndex;
330 model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
331 const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1);
332 for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex)
334 model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
335 if (pDescriptor)
336 maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
337 maEndOffset[nIndex] = nIndex < mnLocalInsertIndex
338 ? rInsertPosition.GetLeadingOffset()
339 : rInsertPosition.GetTrailingOffset();
340 if (bIsVertical)
341 maEndOffset[nIndex].setX( 0 );
342 else
343 maEndOffset[nIndex].setY( 0 );
345 RestartAnimation();
348 void PageObjectRun::ResetOffsets (const controller::Animator::AnimationMode eMode)
350 mnLocalInsertIndex = -1;
351 const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1);
352 model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
353 view::SlideSorterView& rView (mrAnimatorAccess.GetView());
354 for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex)
356 model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
357 if (pDescriptor)
359 if (eMode == controller::Animator::AM_Animated)
360 maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
361 else
363 const ::tools::Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
364 pDescriptor->GetVisualState().SetLocationOffset(Point(0,0));
365 rView.RequestRepaint(aOldBoundingBox);
366 rView.RequestRepaint(pDescriptor);
369 maEndOffset[nIndex] = Point(0,0);
371 if (eMode == controller::Animator::AM_Animated)
372 RestartAnimation();
373 else
374 mrAnimatorAccess.RemoveRun(shared_from_this());
377 void PageObjectRun::RestartAnimation()
379 // Stop the current animation.
380 if (mnAnimationId != controller::Animator::NotAnAnimationId)
382 mrAnimatorAccess.GetAnimator()->RemoveAnimation(mnAnimationId);
385 // Restart the animation.
386 mrAnimatorAccess.AddRun(shared_from_this());
387 auto sharedThis(shared_from_this());
388 mnAnimationId = mrAnimatorAccess.GetAnimator()->AddAnimation(
389 [this] (double const val) { (*this)(val); },
390 [sharedThis] () { sharedThis->mrAnimatorAccess.RemoveRun(sharedThis); }
394 void PageObjectRun::operator () (const double nGlobalTime)
396 if (mnStartTime < 0)
397 mnStartTime = nGlobalTime;
399 double nLocalTime (nGlobalTime - mnStartTime);
400 if (nLocalTime > 1.0)
401 nLocalTime = 1.0;
402 nLocalTime = maAccelerationFunction(nLocalTime);
404 model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
405 view::SlideSorterView& rView (mrAnimatorAccess.GetView());
406 for (sal_Int32 nIndex=mnStartIndex; nIndex<=mnEndIndex; ++nIndex)
408 model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
409 if ( ! pDescriptor)
410 continue;
411 const ::tools::Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
412 pDescriptor->GetVisualState().SetLocationOffset(
413 Blend(
414 maStartOffset[nIndex-mnStartIndex],
415 maEndOffset[nIndex-mnStartIndex],
416 nLocalTime));
418 // Request a repaint of the old and new bounding box (which largely overlap.)
419 rView.RequestRepaint(aOldBoundingBox);
420 rView.RequestRepaint(pDescriptor);
423 // Call Flush to make
424 // a) animations a bit more smooth and
425 // b) on Mac without the Flush a Reset of the page locations is not properly
426 // visualized when the mouse leaves the window during drag-and-drop.
427 mrAnimatorAccess.GetContentWindow()->Flush();
430 } } } // end of namespace ::sd::slidesorter::view
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */