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 <model/SlsPageEnumerationProvider.hxx>
27 #include <SlideSorter.hxx>
33 namespace sd
{ namespace slidesorter
{ namespace 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.
73 sal_Int32
const mnRunIndex
;
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
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.
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)> const 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(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()),
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
)
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
);
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());
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.
217 maRuns
.insert(std::make_shared
<PageObjectRun
>(
221 mrModel
.GetPageCount()-1));
222 iRun
= maRuns
.begin();
226 iRun
= FindRun(nRow
);
227 if (iRun
== maRuns
.end())
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
>(
239 OSL_ASSERT(iRun
!= maRuns
.end());
244 if (iRun
!= maRuns
.end())
247 return SharedPageObjectRun();
250 InsertAnimator::Implementation::RunContainer::const_iterator
251 InsertAnimator::Implementation::FindRun (const sal_Int32 nRunIndex
) const
256 [nRunIndex
] (std::shared_ptr
<PageObjectRun
> const& rRun
)
257 { return rRun
->mnRunIndex
== nRunIndex
; });
260 void InsertAnimator::Implementation::AddRun (const std::shared_ptr
<PageObjectRun
>& rRun
)
272 void InsertAnimator::Implementation::RemoveRun (const std::shared_ptr
<PageObjectRun
>& 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
);
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
),
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
)
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
));
336 maStartOffset
[nIndex
] = pDescriptor
->GetVisualState().GetLocationOffset();
337 maEndOffset
[nIndex
] = nIndex
< mnLocalInsertIndex
338 ? rInsertPosition
.GetLeadingOffset()
339 : rInsertPosition
.GetTrailingOffset();
341 maEndOffset
[nIndex
].setX( 0 );
343 maEndOffset
[nIndex
].setY( 0 );
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
));
359 if (eMode
== controller::Animator::AM_Animated
)
360 maStartOffset
[nIndex
] = pDescriptor
->GetVisualState().GetLocationOffset();
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
)
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
)
397 mnStartTime
= nGlobalTime
;
399 double nLocalTime (nGlobalTime
- mnStartTime
);
400 if (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
));
411 const ::tools::Rectangle
aOldBoundingBox (pDescriptor
->GetBoundingBox());
412 pDescriptor
->GetVisualState().SetLocationOffset(
414 maStartOffset
[nIndex
-mnStartIndex
],
415 maEndOffset
[nIndex
-mnStartIndex
],
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: */