LibreOffice Module sd (master) 1
SlsInsertAnimator.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
24#include <view/SlsLayouter.hxx>
26#include <SlideSorter.hxx>
27#include <Window.hxx>
28#include <osl/diagnose.h>
29
30#include <memory>
31#include <set>
32
33namespace sd::slidesorter::view {
34
35namespace {
36
37class PageObjectRun;
38
39class AnimatorAccess
40{
41public:
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;
48
49protected:
50 ~AnimatorAccess() COVERITY_NOEXCEPT_FALSE {}
51};
52
56class PageObjectRun : public std::enable_shared_from_this<PageObjectRun>
57{
58public:
59 PageObjectRun (
60 AnimatorAccess& rAnimatorAccess,
61 const sal_Int32 nRunIndex,
62 const sal_Int32 nStartIndex,
63 const sal_Int32 nEndIndex);
64
65 void operator () (const double nTime);
66
67 void UpdateOffsets(
68 const InsertPosition& rInsertPosition,
69 const view::Layouter& GetLayouter);
70 void ResetOffsets (const controller::Animator::AnimationMode eMode);
71
73 sal_Int32 mnRunIndex;
78 sal_Int32 mnStartIndex;
80 sal_Int32 mnEndIndex;
82 ::std::vector<Point> maStartOffset;
84 ::std::vector<Point> maEndOffset;
87
88 class Comparator
89 {
90 public: bool operator() (
91 const std::shared_ptr<PageObjectRun>& rpRunA,
92 const std::shared_ptr<PageObjectRun>& rpRunB) const
93 {
94 return rpRunA->mnRunIndex < rpRunB->mnRunIndex;
95 }
96 };
97private:
99 AnimatorAccess& mrAnimatorAccess;
100 ::std::function<double (double)> maAccelerationFunction;
101
102 void RestartAnimation();
103};
104typedef std::shared_ptr<PageObjectRun> SharedPageObjectRun;
105
106Point Blend (const Point& rPointA, const Point& rPointB, const double nT)
107{
108 return Point(
109 sal_Int32(rPointA.X() * (1-nT) + rPointB.X() * nT),
110 sal_Int32(rPointA.Y() * (1-nT) + rPointB.Y() * nT));
111}
112
113} // end of anonymous namespace
114
115class InsertAnimator::Implementation : public AnimatorAccess
116{
117public:
118 explicit Implementation (SlideSorter& rSlideSorter);
119 virtual ~Implementation();
120
121 void SetInsertPosition (
122 const InsertPosition& rInsertPosition,
123 const controller::Animator::AnimationMode eAnimationMode);
124
125 virtual void AddRun (const std::shared_ptr<PageObjectRun>& rRun) override;
126 virtual void RemoveRun (const std::shared_ptr<PageObjectRun>& rRun) override;
127
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; }
132
133private:
137 std::shared_ptr<controller::Animator> mpAnimator;
138 typedef ::std::set<SharedPageObjectRun, PageObjectRun::Comparator> RunContainer;
141
142 SharedPageObjectRun GetRun (
143 view::Layouter const & rLayouter,
144 const InsertPosition& rInsertPosition);
145 RunContainer::const_iterator FindRun (const sal_Int32 nRunIndex) const;
146};
147
148//===== InsertAnimator ========================================================
149
151 : mpImplementation(std::make_shared<Implementation>(rSlideSorter))
152{
153}
154
156{
157 mpImplementation->SetInsertPosition(rInsertPosition, controller::Animator::AM_Animated);
158}
159
161{
162 mpImplementation->SetInsertPosition(InsertPosition(), eMode);
163}
164
165//===== InsertAnimator::Implementation ========================================
166
168 : mrModel(rSlideSorter.GetModel()),
169 mrView(rSlideSorter.GetView()),
170 mrSlideSorter(rSlideSorter),
171 mpAnimator(rSlideSorter.GetController().GetAnimator())
172{
173}
174
176{
178}
179
181 const InsertPosition& rInsertPosition,
183{
184 if (maInsertPosition == rInsertPosition)
185 return;
186
187 SharedPageObjectRun pOldRun (GetRun(mrView.GetLayouter(), maInsertPosition));
188 SharedPageObjectRun pCurrentRun (GetRun(mrView.GetLayouter(), rInsertPosition));
189 maInsertPosition = rInsertPosition;
190
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);
195
196 if (pCurrentRun)
197 {
198 pCurrentRun->UpdateOffsets(rInsertPosition, mrView.GetLayouter());
199 }
200}
201
203 view::Layouter const & rLayouter,
204 const InsertPosition& rInsertPosition)
205{
206 const sal_Int32 nRow (rInsertPosition.GetRow());
207 if (nRow < 0)
208 return SharedPageObjectRun();
209
210 RunContainer::const_iterator iRun (maRuns.end());
211 if (rLayouter.GetColumnCount() == 1)
212 {
213 // There is only one run that contains all slides.
214 if (maRuns.empty())
215 maRuns.insert(std::make_shared<PageObjectRun>(
216 *this,
217 0,
218 0,
219 mrModel.GetPageCount()-1));
220 iRun = maRuns.begin();
221 }
222 else
223 {
224 iRun = FindRun(nRow);
225 if (iRun == maRuns.end())
226 {
227 // Create a new run.
228 const sal_Int32 nStartIndex (rLayouter.GetIndex(nRow, 0));
229 const sal_Int32 nEndIndex (rLayouter.GetIndex(nRow, rLayouter.GetColumnCount()-1));
230 if (nStartIndex <= nEndIndex)
231 {
232 iRun = maRuns.insert(std::make_shared<PageObjectRun>(
233 *this,
234 nRow,
235 nStartIndex,
236 nEndIndex)).first;
237 OSL_ASSERT(iRun != maRuns.end());
238 }
239 }
240 }
241
242 if (iRun != maRuns.end())
243 return *iRun;
244 else
245 return SharedPageObjectRun();
246}
247
248InsertAnimator::Implementation::RunContainer::const_iterator
249 InsertAnimator::Implementation::FindRun (const sal_Int32 nRunIndex) const
250{
251 return std::find_if(
252 maRuns.begin(),
253 maRuns.end(),
254 [nRunIndex] (std::shared_ptr<PageObjectRun> const& rRun)
255 { return rRun->mnRunIndex == nRunIndex; });
256}
257
258void InsertAnimator::Implementation::AddRun (const std::shared_ptr<PageObjectRun>& rRun)
259{
260 if (rRun)
261 {
262 maRuns.insert(rRun);
263 }
264 else
265 {
266 OSL_ASSERT(rRun);
267 }
268}
269
270void InsertAnimator::Implementation::RemoveRun (const std::shared_ptr<PageObjectRun>& rRun)
271{
272 if (rRun)
273 {
274 // Do not remove runs that show the space for the insertion indicator.
275 if (rRun->mnLocalInsertIndex == -1)
276 {
277 InsertAnimator::Implementation::RunContainer::const_iterator iRun (FindRun(rRun->mnRunIndex));
278 if (iRun != maRuns.end())
279 {
280 OSL_ASSERT(*iRun == rRun);
281 maRuns.erase(iRun);
282 }
283 }
284 }
285 else
286 {
287 OSL_ASSERT(rRun);
288 }
289}
290
291//===== PageObjectRun =========================================================
292
293PageObjectRun::PageObjectRun (
294 AnimatorAccess& rAnimatorAccess,
295 const sal_Int32 nRunIndex,
296 const sal_Int32 nStartIndex,
297 const sal_Int32 nEndIndex)
298 : mnRunIndex(nRunIndex),
300 mnStartIndex(nStartIndex),
301 mnEndIndex(nEndIndex),
302 mnStartTime(-1),
303 mnAnimationId(controller::Animator::NotAnAnimationId),
304 mrAnimatorAccess(rAnimatorAccess),
306 controller::AnimationParametricFunction(
307 controller::AnimationBezierFunction (0.1,0.7)))
308{
309 maStartOffset.resize(nEndIndex - nStartIndex + 1);
310 maEndOffset.resize(nEndIndex - nStartIndex + 1);
311}
312
313void PageObjectRun::UpdateOffsets(
314 const InsertPosition& rInsertPosition,
315 const view::Layouter& rLayouter)
316{
317 const bool bIsVertical (rLayouter.GetColumnCount()==1);
318 const sal_Int32 nLocalInsertIndex(bIsVertical
319 ? rInsertPosition.GetRow()
320 : rInsertPosition.GetColumn());
321 if (nLocalInsertIndex == mnLocalInsertIndex)
322 return;
323
324 mnLocalInsertIndex = nLocalInsertIndex;
325
326 model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
327 const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1);
328 for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex)
329 {
330 model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
331 if (pDescriptor)
332 maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
334 ? rInsertPosition.GetLeadingOffset()
335 : rInsertPosition.GetTrailingOffset();
336 if (bIsVertical)
337 maEndOffset[nIndex].setX( 0 );
338 else
339 maEndOffset[nIndex].setY( 0 );
340 }
341 RestartAnimation();
342}
343
344void PageObjectRun::ResetOffsets (const controller::Animator::AnimationMode eMode)
345{
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)
351 {
352 model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
353 if (pDescriptor)
354 {
356 maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
357 else
358 {
359 const ::tools::Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
360 pDescriptor->GetVisualState().SetLocationOffset(Point(0,0));
361 rView.RequestRepaint(aOldBoundingBox);
362 rView.RequestRepaint(pDescriptor);
363 }
364 }
365 maEndOffset[nIndex] = Point(0,0);
366 }
368 RestartAnimation();
369 else
370 mrAnimatorAccess.RemoveRun(shared_from_this());
371}
372
373void PageObjectRun::RestartAnimation()
374{
375 // Stop the current animation.
377 {
378 mrAnimatorAccess.GetAnimator()->RemoveAnimation(mnAnimationId);
379 }
380
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] () { sharedThis->mrAnimatorAccess.RemoveRun(sharedThis); }
387 );
388}
389
390void PageObjectRun::operator () (const double nGlobalTime)
391{
392 if (mnStartTime < 0)
393 mnStartTime = nGlobalTime;
394
395 double nLocalTime (nGlobalTime - mnStartTime);
396 if (nLocalTime > 1.0)
397 nLocalTime = 1.0;
398 nLocalTime = maAccelerationFunction(nLocalTime);
399
400 model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
401 view::SlideSorterView& rView (mrAnimatorAccess.GetView());
402 for (sal_Int32 nIndex=mnStartIndex; nIndex<=mnEndIndex; ++nIndex)
403 {
404 model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
405 if ( ! pDescriptor)
406 continue;
407 const ::tools::Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
408 pDescriptor->GetVisualState().SetLocationOffset(
409 Blend(
412 nLocalTime));
413
414 // Request a repaint of the old and new bounding box (which largely overlap.)
415 rView.RequestRepaint(aOldBoundingBox);
416 rView.RequestRepaint(pDescriptor);
417 }
418
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();
424}
425
426} // end of namespace ::sd::slidesorter::view
427
428/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Blend
ChartModel & mrModel
SlideSorterView & mrView
sal_Int32 mnEndIndex
Index of the last page in the run.
double mnStartTime
Time at which the current animation started.
sal_Int32 mnLocalInsertIndex
The index at which to make place for the insertion indicator (-1 for no indicator).
sal_Int32 mnRunIndex
Index of the row or column that this run represents.
::std::vector< Point > maEndOffset
Target offset of each item in the run at the end of the current animation.
::std::function< double(double)> maAccelerationFunction
AnimatorAccess & mrAnimatorAccess
sal_Int32 mnStartIndex
Index of the first page in the run.
::std::vector< Point > maStartOffset
Offset of each item in the run at the start of the current animation.
controller::Animator::AnimationId mnAnimationId
SlideSorter & mrSlideSorter
constexpr tools::Long Y() const
constexpr tools::Long X() const
Show previews for all the slides in a document and allow the user to insert or delete slides and modi...
Definition: SlideSorter.hxx:62
const VclPtr< sd::Window > & GetContentWindow() const
Return the content window.
Definition: SlideSorter.hxx:99
static const AnimationId NotAnAnimationId
Definition: SlsAnimator.hxx:64
AnimationMode
In some circumstances we have to avoid animation and jump to the final animation state immediately.
Definition: SlsAnimator.hxx:45
The model of the slide sorter gives access to the slides that are to be displayed in the slide sorter...
virtual VclPtr< sd::Window > GetContentWindow() override
void SetInsertPosition(const InsertPosition &rInsertPosition, const controller::Animator::AnimationMode eAnimationMode)
virtual model::SlideSorterModel & GetModel() const override
virtual void RemoveRun(const std::shared_ptr< PageObjectRun > &rRun) override
virtual void AddRun(const std::shared_ptr< PageObjectRun > &rRun) override
::std::set< SharedPageObjectRun, PageObjectRun::Comparator > RunContainer
virtual std::shared_ptr< controller::Animator > GetAnimator() override
SharedPageObjectRun GetRun(view::Layouter const &rLayouter, const InsertPosition &rInsertPosition)
std::shared_ptr< controller::Animator > mpAnimator
virtual view::SlideSorterView & GetView() const override
RunContainer::const_iterator FindRun(const sal_Int32 nRunIndex) const
void Reset(const controller::Animator::AnimationMode eMode)
Restore the normal position of all page objects.
InsertAnimator(SlideSorter &rSlideSorter)
std::shared_ptr< Implementation > mpImplementation
void SetInsertPosition(const InsertPosition &rInsertPosition)
Set the position at which we have to make room for the display of an icon.
Collect all values concerning the logical and visual properties of the insertion position that is use...
const Point & GetLeadingOffset() const
const Point & GetTrailingOffset() const
Calculate the size and position of page objects displayed by a slide sorter.
Definition: SlsLayouter.hxx:60
sal_Int32 GetIndex(const sal_Int32 nRow, const sal_Int32 nColumn) const
sal_Int32 GetColumnCount() const
Return the number of columns.
virtual std::shared_ptr< SfxDialogController > GetController() override
sal_Int32 nIndex
Mode eMode
std::shared_ptr< T > make_shared(Args &&... args)
std::shared_ptr< PageDescriptor > SharedPageDescriptor