Line data Source code
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 :
20 :
21 : #include "view/SlsInsertAnimator.hxx"
22 : #include "controller/SlideSorterController.hxx"
23 : #include "controller/SlsAnimationFunction.hxx"
24 : #include "view/SlideSorterView.hxx"
25 : #include "view/SlsLayouter.hxx"
26 : #include "model/SlideSorterModel.hxx"
27 : #include "model/SlsPageEnumerationProvider.hxx"
28 :
29 : #include <set>
30 : #include <boost/bind.hpp>
31 : #include <boost/enable_shared_from_this.hpp>
32 :
33 : namespace sd { namespace slidesorter { namespace view {
34 :
35 : namespace {
36 :
37 : class PageObjectRun;
38 :
39 0 : class AnimatorAccess
40 : {
41 : public:
42 : virtual void AddRun (const ::boost::shared_ptr<PageObjectRun> pRun) = 0;
43 : virtual void RemoveRun (const ::boost::shared_ptr<PageObjectRun> pRun) = 0;
44 : virtual model::SlideSorterModel& GetModel (void) const = 0;
45 : virtual view::SlideSorterView& GetView (void) const = 0;
46 : virtual ::boost::shared_ptr<controller::Animator> GetAnimator (void) = 0;
47 : virtual SharedSdWindow GetContentWindow (void) = 0;
48 :
49 : protected:
50 0 : ~AnimatorAccess() {}
51 : };
52 :
53 :
54 : /** Controller of the position offsets of all page objects in one row or one
55 : column.
56 : */
57 : class PageObjectRun : public ::boost::enable_shared_from_this<PageObjectRun>
58 : {
59 : public:
60 : PageObjectRun (
61 : AnimatorAccess& rAnimatorAccess,
62 : const sal_Int32 nRunIndex,
63 : const sal_Int32 nStartIndex,
64 : const sal_Int32 nEndIndex);
65 : ~PageObjectRun (void);
66 :
67 : void operator () (const double nTime);
68 :
69 : void UpdateOffsets(
70 : const InsertPosition& rInsertPosition,
71 : const view::Layouter& GetLayouter);
72 : void ResetOffsets (const controller::Animator::AnimationMode eMode);
73 :
74 : /// Index of the row or column that this run represents.
75 : sal_Int32 mnRunIndex;
76 : /// The index at which to make place for the insertion indicator (-1 for
77 : /// no indicator).
78 : sal_Int32 mnLocalInsertIndex;
79 : /// Index of the first page in the run.
80 : sal_Int32 mnStartIndex;
81 : /// Index of the last page in the run.
82 : sal_Int32 mnEndIndex;
83 : /// Offset of each item in the run at the start of the current animation.
84 : ::std::vector<Point> maStartOffset;
85 : /// Target offset of each item in the run at the end of the current animation.
86 : ::std::vector<Point> maEndOffset;
87 : /// Time at which the current animation started.
88 : double mnStartTime;
89 :
90 : class Comparator
91 : {
92 0 : public: bool operator() (
93 : const ::boost::shared_ptr<PageObjectRun>& rpRunA,
94 : const ::boost::shared_ptr<PageObjectRun>& rpRunB) const
95 : {
96 0 : return rpRunA->mnRunIndex < rpRunB->mnRunIndex;
97 : }
98 : };
99 : private:
100 : controller::Animator::AnimationId mnAnimationId;
101 : AnimatorAccess& mrAnimatorAccess;
102 : ::boost::function<double(double)> maAccelerationFunction;
103 :
104 : void RestartAnimation (void);
105 : };
106 : typedef ::boost::shared_ptr<PageObjectRun> SharedPageObjectRun;
107 :
108 :
109 0 : Point Blend (const Point& rPointA, const Point& rPointB, const double nT)
110 : {
111 : return Point(
112 0 : sal_Int32(rPointA.X() * (1-nT) + rPointB.X() * nT),
113 0 : sal_Int32(rPointA.Y() * (1-nT) + rPointB.Y() * nT));
114 : }
115 :
116 : } // end of anonymous namespace
117 :
118 :
119 :
120 : class InsertAnimator::Implementation : public AnimatorAccess
121 : {
122 : public:
123 : Implementation (SlideSorter& rSlideSorter);
124 : virtual ~Implementation (void);
125 :
126 : void SetInsertPosition (
127 : const InsertPosition& rInsertPosition,
128 : const controller::Animator::AnimationMode eAnimationMode);
129 :
130 : virtual void AddRun (const ::boost::shared_ptr<PageObjectRun> pRun);
131 : virtual void RemoveRun (const ::boost::shared_ptr<PageObjectRun> pRun);
132 :
133 0 : virtual model::SlideSorterModel& GetModel (void) const { return mrModel; }
134 0 : virtual view::SlideSorterView& GetView (void) const { return mrView; }
135 0 : virtual ::boost::shared_ptr<controller::Animator> GetAnimator (void) { return mpAnimator; }
136 0 : virtual SharedSdWindow GetContentWindow (void) { return mrSlideSorter.GetContentWindow(); }
137 :
138 : private:
139 : model::SlideSorterModel& mrModel;
140 : view::SlideSorterView& mrView;
141 : SlideSorter& mrSlideSorter;
142 : ::boost::shared_ptr<controller::Animator> mpAnimator;
143 : typedef ::std::set<SharedPageObjectRun, PageObjectRun::Comparator> RunContainer;
144 : RunContainer maRuns;
145 : InsertPosition maInsertPosition;
146 :
147 : void StopAnimation (void);
148 : SharedPageObjectRun GetRun (
149 : view::Layouter& rLayouter,
150 : const InsertPosition& rInsertPosition,
151 : const bool bCreate = true);
152 : RunContainer::const_iterator FindRun (const sal_Int32 nRunIndex) const;
153 : };
154 :
155 :
156 :
157 :
158 :
159 : //===== InsertAnimator ========================================================
160 :
161 0 : InsertAnimator::InsertAnimator (SlideSorter& rSlideSorter)
162 0 : : mpImplementation(new Implementation(rSlideSorter))
163 : {
164 0 : }
165 :
166 :
167 :
168 :
169 0 : void InsertAnimator::SetInsertPosition (const InsertPosition& rInsertPosition)
170 : {
171 0 : mpImplementation->SetInsertPosition(rInsertPosition, controller::Animator::AM_Animated);
172 0 : }
173 :
174 :
175 :
176 :
177 0 : void InsertAnimator::Reset (const controller::Animator::AnimationMode eMode)
178 : {
179 0 : mpImplementation->SetInsertPosition(InsertPosition(), eMode);
180 0 : }
181 :
182 :
183 :
184 :
185 : //===== InsertAnimator::Implementation ========================================
186 :
187 0 : InsertAnimator::Implementation::Implementation (SlideSorter& rSlideSorter)
188 0 : : mrModel(rSlideSorter.GetModel()),
189 0 : mrView(rSlideSorter.GetView()),
190 : mrSlideSorter(rSlideSorter),
191 0 : mpAnimator(rSlideSorter.GetController().GetAnimator()),
192 : maRuns(),
193 0 : maInsertPosition()
194 : {
195 0 : }
196 :
197 :
198 :
199 :
200 0 : InsertAnimator::Implementation::~Implementation (void)
201 : {
202 0 : SetInsertPosition(InsertPosition(), controller::Animator::AM_Immediate);
203 0 : }
204 :
205 :
206 :
207 :
208 0 : void InsertAnimator::Implementation::SetInsertPosition (
209 : const InsertPosition& rInsertPosition,
210 : const controller::Animator::AnimationMode eMode)
211 : {
212 0 : if (maInsertPosition == rInsertPosition)
213 0 : return;
214 :
215 0 : SharedPageObjectRun pOldRun (GetRun(mrView.GetLayouter(), maInsertPosition));
216 0 : SharedPageObjectRun pCurrentRun (GetRun(mrView.GetLayouter(), rInsertPosition));
217 0 : maInsertPosition = rInsertPosition;
218 :
219 : // When the new insert position is in a different run then move the page
220 : // objects in the old run to their default positions.
221 0 : if (pOldRun != pCurrentRun)
222 : {
223 0 : if (pOldRun)
224 0 : pOldRun->ResetOffsets(eMode);
225 : }
226 :
227 0 : if (pCurrentRun)
228 : {
229 0 : pCurrentRun->UpdateOffsets(rInsertPosition, mrView.GetLayouter());
230 0 : }
231 : }
232 :
233 :
234 :
235 :
236 0 : SharedPageObjectRun InsertAnimator::Implementation::GetRun (
237 : view::Layouter& rLayouter,
238 : const InsertPosition& rInsertPosition,
239 : const bool bCreate)
240 : {
241 0 : const sal_Int32 nRow (rInsertPosition.GetRow());
242 0 : if (nRow < 0)
243 0 : return SharedPageObjectRun();
244 :
245 0 : RunContainer::const_iterator iRun (maRuns.end());
246 0 : if (rLayouter.GetColumnCount() == 1)
247 : {
248 : // There is only one run that contains all slides.
249 0 : if (maRuns.empty() && bCreate)
250 : maRuns.insert(SharedPageObjectRun(new PageObjectRun(
251 : *this,
252 : 0,
253 : 0,
254 0 : mrModel.GetPageCount()-1)));
255 0 : iRun = maRuns.begin();
256 : }
257 : else
258 : {
259 0 : iRun = FindRun(nRow);
260 0 : if (iRun == maRuns.end() && bCreate)
261 : {
262 : // Create a new run.
263 0 : const sal_Int32 nStartIndex (rLayouter.GetIndex(nRow, 0));
264 0 : const sal_Int32 nEndIndex (rLayouter.GetIndex(nRow, rLayouter.GetColumnCount()-1));
265 0 : if (nStartIndex <= nEndIndex)
266 : {
267 : iRun = maRuns.insert(SharedPageObjectRun(new PageObjectRun(
268 : *this,
269 : nRow,
270 : nStartIndex,
271 0 : nEndIndex))).first;
272 : OSL_ASSERT(iRun != maRuns.end());
273 : }
274 : }
275 : }
276 :
277 0 : if (iRun != maRuns.end())
278 0 : return *iRun;
279 : else
280 0 : return SharedPageObjectRun();
281 : }
282 :
283 :
284 :
285 :
286 : InsertAnimator::Implementation::RunContainer::const_iterator
287 0 : InsertAnimator::Implementation::FindRun (const sal_Int32 nRunIndex) const
288 : {
289 : return std::find_if(
290 : maRuns.begin(),
291 : maRuns.end(),
292 : ::boost::bind(
293 : ::std::equal_to<sal_Int32>(),
294 : ::boost::bind(&PageObjectRun::mnRunIndex, _1),
295 0 : nRunIndex));
296 : }
297 :
298 :
299 :
300 :
301 0 : void InsertAnimator::Implementation::AddRun (const ::boost::shared_ptr<PageObjectRun> pRun)
302 : {
303 0 : if (pRun)
304 : {
305 0 : maRuns.insert(pRun);
306 : }
307 : else
308 : {
309 : OSL_ASSERT(pRun);
310 : }
311 0 : }
312 :
313 :
314 :
315 :
316 :
317 0 : void InsertAnimator::Implementation::RemoveRun (const ::boost::shared_ptr<PageObjectRun> pRun)
318 : {
319 0 : if (pRun)
320 : {
321 : // Do not remove runs that show the space for the insertion indicator.
322 0 : if (pRun->mnLocalInsertIndex == -1)
323 : {
324 0 : InsertAnimator::Implementation::RunContainer::const_iterator iRun (FindRun(pRun->mnRunIndex));
325 0 : if (iRun != maRuns.end())
326 : {
327 : OSL_ASSERT(*iRun == pRun);
328 0 : maRuns.erase(iRun);
329 : }
330 : }
331 : }
332 : else
333 : {
334 : OSL_ASSERT(pRun);
335 : }
336 0 : }
337 :
338 :
339 :
340 :
341 :
342 : //===== PageObjectRun =========================================================
343 :
344 0 : PageObjectRun::PageObjectRun (
345 : AnimatorAccess& rAnimatorAccess,
346 : const sal_Int32 nRunIndex,
347 : const sal_Int32 nStartIndex,
348 : const sal_Int32 nEndIndex)
349 : : mnRunIndex(nRunIndex),
350 : mnLocalInsertIndex(-1),
351 : mnStartIndex(nStartIndex),
352 : mnEndIndex(nEndIndex),
353 : maStartOffset(),
354 : maEndOffset(),
355 : mnStartTime(-1),
356 : mnAnimationId(controller::Animator::NotAnAnimationId),
357 : mrAnimatorAccess(rAnimatorAccess),
358 : maAccelerationFunction(
359 : controller::AnimationParametricFunction(
360 0 : controller::AnimationBezierFunction (0.1,0.7)))
361 : {
362 0 : maStartOffset.resize(nEndIndex - nStartIndex + 1);
363 0 : maEndOffset.resize(nEndIndex - nStartIndex + 1);
364 0 : }
365 :
366 :
367 :
368 :
369 0 : PageObjectRun::~PageObjectRun (void)
370 : {
371 0 : }
372 :
373 0 : void PageObjectRun::UpdateOffsets(
374 : const InsertPosition& rInsertPosition,
375 : const view::Layouter& rLayouter)
376 : {
377 0 : const bool bIsVertical (rLayouter.GetColumnCount()==1);
378 : const sal_Int32 nLocalInsertIndex(bIsVertical
379 : ? rInsertPosition.GetRow()
380 0 : : rInsertPosition.GetColumn());
381 0 : if (nLocalInsertIndex != mnLocalInsertIndex)
382 : {
383 0 : mnLocalInsertIndex = nLocalInsertIndex;
384 :
385 0 : model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
386 0 : const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1);
387 0 : for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex)
388 : {
389 0 : model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
390 0 : if (pDescriptor)
391 0 : maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
392 0 : maEndOffset[nIndex] = nIndex < mnLocalInsertIndex
393 : ? rInsertPosition.GetLeadingOffset()
394 0 : : rInsertPosition.GetTrailingOffset();
395 0 : if (bIsVertical)
396 0 : maEndOffset[nIndex].X() = 0;
397 : else
398 0 : maEndOffset[nIndex].Y() = 0;
399 0 : }
400 0 : RestartAnimation();
401 : }
402 0 : }
403 :
404 :
405 :
406 :
407 0 : void PageObjectRun::ResetOffsets (const controller::Animator::AnimationMode eMode)
408 : {
409 0 : mnLocalInsertIndex = -1;
410 0 : const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1);
411 0 : model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
412 0 : view::SlideSorterView& rView (mrAnimatorAccess.GetView());
413 0 : for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex)
414 : {
415 0 : model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
416 0 : if (pDescriptor)
417 : {
418 0 : if (eMode == controller::Animator::AM_Animated)
419 0 : maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
420 : else
421 : {
422 0 : const Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
423 0 : pDescriptor->GetVisualState().SetLocationOffset(Point(0,0));
424 0 : rView.RequestRepaint(aOldBoundingBox);
425 0 : rView.RequestRepaint(pDescriptor);
426 : }
427 : }
428 0 : maEndOffset[nIndex] = Point(0,0);
429 0 : }
430 0 : if (eMode == controller::Animator::AM_Animated)
431 0 : RestartAnimation();
432 : else
433 0 : mrAnimatorAccess.RemoveRun(shared_from_this());
434 0 : }
435 :
436 :
437 :
438 :
439 0 : void PageObjectRun::RestartAnimation (void)
440 : {
441 : // Stop the current animation.
442 0 : if (mnAnimationId != controller::Animator::NotAnAnimationId)
443 : {
444 0 : mrAnimatorAccess.GetAnimator()->RemoveAnimation(mnAnimationId);
445 : }
446 :
447 : // Restart the animation.
448 0 : mrAnimatorAccess.AddRun(shared_from_this());
449 0 : mnAnimationId = mrAnimatorAccess.GetAnimator()->AddAnimation(
450 : ::boost::ref(*this),
451 : 0,
452 : 300,
453 : ::boost::bind(
454 : &AnimatorAccess::RemoveRun,
455 : ::boost::ref(mrAnimatorAccess),
456 0 : shared_from_this()));
457 0 : }
458 :
459 :
460 :
461 :
462 0 : void PageObjectRun::operator () (const double nGlobalTime)
463 : {
464 0 : if (mnStartTime < 0)
465 0 : mnStartTime = nGlobalTime;
466 :
467 0 : double nLocalTime (nGlobalTime - mnStartTime);
468 0 : if (nLocalTime > 1.0)
469 0 : nLocalTime = 1.0;
470 0 : nLocalTime = maAccelerationFunction(nLocalTime);
471 :
472 0 : model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
473 0 : view::SlideSorterView& rView (mrAnimatorAccess.GetView());
474 0 : for (sal_Int32 nIndex=mnStartIndex; nIndex<=mnEndIndex; ++nIndex)
475 : {
476 0 : model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
477 0 : if ( ! pDescriptor)
478 0 : continue;
479 0 : const Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
480 0 : pDescriptor->GetVisualState().SetLocationOffset(
481 : Blend(
482 0 : maStartOffset[nIndex-mnStartIndex],
483 0 : maEndOffset[nIndex-mnStartIndex],
484 0 : nLocalTime));
485 :
486 : // Request a repaint of the old and new bounding box (which largely overlap.)
487 0 : rView.RequestRepaint(aOldBoundingBox);
488 0 : rView.RequestRepaint(pDescriptor);
489 0 : }
490 :
491 : // Call Flush to make
492 : // a) animations a bit more smooth and
493 : // b) on Mac without the Flush a Reset of the page locations is not properly
494 : // visualized when the mouse leaves the window during drag-and-drop.
495 0 : mrAnimatorAccess.GetContentWindow()->Flush();
496 0 : }
497 :
498 :
499 :
500 :
501 9 : } } } // end of namespace ::sd::slidesorter::view
502 :
503 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|