1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <SlideSorter.hxx>
28 #include <osl/diagnose.h>
33 namespace sd::slidesorter::view
{
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;
50 ~AnimatorAccess() COVERITY_NOEXCEPT_FALSE
{}
53 /** Controller of the position offsets of all page objects in one row or one
56 class PageObjectRun
: public std::enable_shared_from_this
<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
);
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.
74 /// The index at which to make place for the insertion indicator (-1 for
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.
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.
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
;
98 controller::Animator::AnimationId mnAnimationId
;
99 AnimatorAccess
& mrAnimatorAccess
;
100 ::std::function
<double (double)> maAccelerationFunction
;
102 void RestartAnimation();
104 typedef std::shared_ptr
<PageObjectRun
> SharedPageObjectRun
;
106 Point
Blend (const Point
& rPointA
, const Point
& rPointB
, const double nT
)
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
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(); }
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
;
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(std::make_shared
<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())
175 InsertAnimator::Implementation::~Implementation()
177 SetInsertPosition(InsertPosition(), controller::Animator::AM_Immediate
);
180 void InsertAnimator::Implementation::SetInsertPosition (
181 const InsertPosition
& rInsertPosition
,
182 const controller::Animator::AnimationMode eMode
)
184 if (maInsertPosition
== rInsertPosition
)
187 SharedPageObjectRun
pOldRun (GetRun(mrView
.GetLayouter(), maInsertPosition
));
188 SharedPageObjectRun
pCurrentRun (GetRun(mrView
.GetLayouter(), rInsertPosition
));
189 maInsertPosition
= rInsertPosition
;
191 // When the new insert position is in a different run then move the page
192 // objects in the old run to their default positions.
193 if (pOldRun
!= pCurrentRun
&& pOldRun
)
194 pOldRun
->ResetOffsets(eMode
);
198 pCurrentRun
->UpdateOffsets(rInsertPosition
, mrView
.GetLayouter());
202 SharedPageObjectRun
InsertAnimator::Implementation::GetRun (
203 view::Layouter
const & rLayouter
,
204 const InsertPosition
& rInsertPosition
)
206 const sal_Int32
nRow (rInsertPosition
.GetRow());
208 return SharedPageObjectRun();
210 RunContainer::const_iterator
iRun (maRuns
.end());
211 if (rLayouter
.GetColumnCount() == 1)
213 // There is only one run that contains all slides.
215 maRuns
.insert(std::make_shared
<PageObjectRun
>(
219 mrModel
.GetPageCount()-1));
220 iRun
= maRuns
.begin();
224 iRun
= FindRun(nRow
);
225 if (iRun
== maRuns
.end())
228 const sal_Int32
nStartIndex (rLayouter
.GetIndex(nRow
, 0));
229 const sal_Int32
nEndIndex (rLayouter
.GetIndex(nRow
, rLayouter
.GetColumnCount()-1));
230 if (nStartIndex
<= nEndIndex
)
232 iRun
= maRuns
.insert(std::make_shared
<PageObjectRun
>(
237 OSL_ASSERT(iRun
!= maRuns
.end());
242 if (iRun
!= maRuns
.end())
245 return SharedPageObjectRun();
248 InsertAnimator::Implementation::RunContainer::const_iterator
249 InsertAnimator::Implementation::FindRun (const sal_Int32 nRunIndex
) const
254 [nRunIndex
] (std::shared_ptr
<PageObjectRun
> const& rRun
)
255 { return rRun
->mnRunIndex
== nRunIndex
; });
258 void InsertAnimator::Implementation::AddRun (const std::shared_ptr
<PageObjectRun
>& rRun
)
270 void InsertAnimator::Implementation::RemoveRun (const std::shared_ptr
<PageObjectRun
>& rRun
)
274 // Do not remove runs that show the space for the insertion indicator.
275 if (rRun
->mnLocalInsertIndex
== -1)
277 InsertAnimator::Implementation::RunContainer::const_iterator
iRun (FindRun(rRun
->mnRunIndex
));
278 if (iRun
!= maRuns
.end())
280 OSL_ASSERT(*iRun
== rRun
);
291 //===== PageObjectRun =========================================================
293 PageObjectRun::PageObjectRun (
294 AnimatorAccess
& rAnimatorAccess
,
295 const sal_Int32 nRunIndex
,
296 const sal_Int32 nStartIndex
,
297 const sal_Int32 nEndIndex
)
298 : mnRunIndex(nRunIndex
),
299 mnLocalInsertIndex(-1),
300 mnStartIndex(nStartIndex
),
301 mnEndIndex(nEndIndex
),
303 mnAnimationId(controller::Animator::NotAnAnimationId
),
304 mrAnimatorAccess(rAnimatorAccess
),
305 maAccelerationFunction(
306 controller::AnimationParametricFunction(
307 controller::AnimationBezierFunction (0.1,0.7)))
309 maStartOffset
.resize(nEndIndex
- nStartIndex
+ 1);
310 maEndOffset
.resize(nEndIndex
- nStartIndex
+ 1);
313 void PageObjectRun::UpdateOffsets(
314 const InsertPosition
& rInsertPosition
,
315 const view::Layouter
& rLayouter
)
317 const bool bIsVertical (rLayouter
.GetColumnCount()==1);
318 const sal_Int32
nLocalInsertIndex(bIsVertical
319 ? rInsertPosition
.GetRow()
320 : rInsertPosition
.GetColumn());
321 if (nLocalInsertIndex
== mnLocalInsertIndex
)
324 mnLocalInsertIndex
= nLocalInsertIndex
;
326 model::SlideSorterModel
& rModel (mrAnimatorAccess
.GetModel());
327 const sal_Int32
nRunLength (mnEndIndex
- mnStartIndex
+ 1);
328 for (sal_Int32 nIndex
=0; nIndex
<nRunLength
; ++nIndex
)
330 model::SharedPageDescriptor
pDescriptor(rModel
.GetPageDescriptor(nIndex
+mnStartIndex
));
332 maStartOffset
[nIndex
] = pDescriptor
->GetVisualState().GetLocationOffset();
333 maEndOffset
[nIndex
] = nIndex
< mnLocalInsertIndex
334 ? rInsertPosition
.GetLeadingOffset()
335 : rInsertPosition
.GetTrailingOffset();
337 maEndOffset
[nIndex
].setX( 0 );
339 maEndOffset
[nIndex
].setY( 0 );
344 void PageObjectRun::ResetOffsets (const controller::Animator::AnimationMode eMode
)
346 mnLocalInsertIndex
= -1;
347 const sal_Int32
nRunLength (mnEndIndex
- mnStartIndex
+ 1);
348 model::SlideSorterModel
& rModel (mrAnimatorAccess
.GetModel());
349 view::SlideSorterView
& rView (mrAnimatorAccess
.GetView());
350 for (sal_Int32 nIndex
=0; nIndex
<nRunLength
; ++nIndex
)
352 model::SharedPageDescriptor
pDescriptor(rModel
.GetPageDescriptor(nIndex
+mnStartIndex
));
355 if (eMode
== controller::Animator::AM_Animated
)
356 maStartOffset
[nIndex
] = pDescriptor
->GetVisualState().GetLocationOffset();
359 const ::tools::Rectangle
aOldBoundingBox (pDescriptor
->GetBoundingBox());
360 pDescriptor
->GetVisualState().SetLocationOffset(Point(0,0));
361 rView
.RequestRepaint(aOldBoundingBox
);
362 rView
.RequestRepaint(pDescriptor
);
365 maEndOffset
[nIndex
] = Point(0,0);
367 if (eMode
== controller::Animator::AM_Animated
)
370 mrAnimatorAccess
.RemoveRun(shared_from_this());
373 void PageObjectRun::RestartAnimation()
375 // Stop the current animation.
376 if (mnAnimationId
!= controller::Animator::NotAnAnimationId
)
378 mrAnimatorAccess
.GetAnimator()->RemoveAnimation(mnAnimationId
);
381 // Restart the animation.
382 mrAnimatorAccess
.AddRun(shared_from_this());
383 auto sharedThis(shared_from_this());
384 mnAnimationId
= mrAnimatorAccess
.GetAnimator()->AddAnimation(
385 [this] (double const val
) { (*this)(val
); },
386 [sharedThis
=std::move(sharedThis
)] () { sharedThis
->mrAnimatorAccess
.RemoveRun(sharedThis
); }
390 void PageObjectRun::operator () (const double nGlobalTime
)
393 mnStartTime
= nGlobalTime
;
395 double nLocalTime (nGlobalTime
- mnStartTime
);
396 if (nLocalTime
> 1.0)
398 nLocalTime
= maAccelerationFunction(nLocalTime
);
400 model::SlideSorterModel
& rModel (mrAnimatorAccess
.GetModel());
401 view::SlideSorterView
& rView (mrAnimatorAccess
.GetView());
402 for (sal_Int32 nIndex
=mnStartIndex
; nIndex
<=mnEndIndex
; ++nIndex
)
404 model::SharedPageDescriptor
pDescriptor (rModel
.GetPageDescriptor(nIndex
));
407 const ::tools::Rectangle
aOldBoundingBox (pDescriptor
->GetBoundingBox());
408 pDescriptor
->GetVisualState().SetLocationOffset(
410 maStartOffset
[nIndex
-mnStartIndex
],
411 maEndOffset
[nIndex
-mnStartIndex
],
414 // Request a repaint of the old and new bounding box (which largely overlap.)
415 rView
.RequestRepaint(aOldBoundingBox
);
416 rView
.RequestRepaint(pDescriptor
);
419 // Call Flush to make
420 // a) animations a bit more smooth and
421 // b) on Mac without the Flush a Reset of the page locations is not properly
422 // visualized when the mouse leaves the window during drag-and-drop.
423 mrAnimatorAccess
.GetContentWindow()->GetOutDev()->Flush();
426 } // end of namespace ::sd::slidesorter::view
428 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */