1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "precompiled_sd.hxx"
25 
26 #include "controller/SlsVisibleAreaManager.hxx"
27 #include "controller/SlideSorterController.hxx"
28 #include "controller/SlsProperties.hxx"
29 #include "controller/SlsAnimationFunction.hxx"
30 #include "controller/SlsScrollBarManager.hxx"
31 #include "controller/SlsCurrentSlideManager.hxx"
32 
33 
34 namespace sd { namespace slidesorter { namespace controller {
35 
36 namespace {
37     class VisibleAreaScroller
38     {
39     public:
40         VisibleAreaScroller (
41             SlideSorter& rSlideSorter,
42             const Point aStart,
43             const Point aEnd);
44         void operator() (const double nValue);
45     private:
46         SlideSorter& mrSlideSorter;
47         Point maStart;
48         const Point maEnd;
49         const ::boost::function<double(double)> maAccelerationFunction;
50     };
51 
52 } // end of anonymous namespace
53 
54 
55 
VisibleAreaManager(SlideSorter & rSlideSorter)56 VisibleAreaManager::VisibleAreaManager (SlideSorter& rSlideSorter)
57     : mrSlideSorter(rSlideSorter),
58       maVisibleRequests(),
59       mnScrollAnimationId(Animator::NotAnAnimationId),
60       maRequestedVisibleTopLeft(),
61       meRequestedAnimationMode(Animator::AM_Immediate),
62       mbIsCurrentSlideTrackingActive(true),
63       mnDisableCount(0)
64 {
65 }
66 
67 
68 
69 
~VisibleAreaManager(void)70 VisibleAreaManager::~VisibleAreaManager (void)
71 {
72 }
73 
74 
75 
76 
ActivateCurrentSlideTracking(void)77 void VisibleAreaManager::ActivateCurrentSlideTracking (void)
78 {
79     mbIsCurrentSlideTrackingActive = true;
80 }
81 
82 
83 
84 
DeactivateCurrentSlideTracking(void)85 void VisibleAreaManager::DeactivateCurrentSlideTracking (void)
86 {
87     mbIsCurrentSlideTrackingActive = false;
88 }
89 
90 
91 
92 
IsCurrentSlideTrackingActive(void) const93 bool VisibleAreaManager::IsCurrentSlideTrackingActive (void) const
94 {
95     return mbIsCurrentSlideTrackingActive;
96 }
97 
98 
99 
100 
RequestVisible(const model::SharedPageDescriptor & rpDescriptor,const bool bForce)101 void VisibleAreaManager::RequestVisible (
102     const model::SharedPageDescriptor& rpDescriptor,
103     const bool bForce)
104 {
105     if (rpDescriptor)
106     {
107         if (mnDisableCount == 0)
108         {
109             maVisibleRequests.push_back(
110                 mrSlideSorter.GetView().GetLayouter().GetPageObjectBox(
111                     rpDescriptor->GetPageIndex(),
112                     true));
113         }
114         if (bForce && ! mbIsCurrentSlideTrackingActive)
115             ActivateCurrentSlideTracking();
116         MakeVisible();
117     }
118 }
119 
120 
121 
122 
RequestCurrentSlideVisible(void)123 void VisibleAreaManager::RequestCurrentSlideVisible (void)
124 {
125     if (mbIsCurrentSlideTrackingActive && mnDisableCount==0)
126         RequestVisible(
127             mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide());
128 }
129 
130 
131 
132 
MakeVisible(void)133 void VisibleAreaManager::MakeVisible (void)
134 {
135     if (maVisibleRequests.empty())
136         return;
137 
138     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
139     if ( ! pWindow)
140         return;
141     const Point aCurrentTopLeft (pWindow->PixelToLogic(Point(0,0)));
142 
143     const ::boost::optional<Point> aNewVisibleTopLeft (GetRequestedTopLeft());
144     maVisibleRequests.clear();
145     if ( ! aNewVisibleTopLeft)
146         return;
147 
148     // We now know what the visible area shall be.  Scroll accordingly
149     // unless that is not already the visible area or a running scroll
150     // animation has it as its target area.
151     if (mnScrollAnimationId!=Animator::NotAnAnimationId
152         && maRequestedVisibleTopLeft==aNewVisibleTopLeft)
153         return;
154 
155     // Stop a running animation.
156     if (mnScrollAnimationId != Animator::NotAnAnimationId)
157         mrSlideSorter.GetController().GetAnimator()->RemoveAnimation(mnScrollAnimationId);
158 
159     maRequestedVisibleTopLeft = aNewVisibleTopLeft.get();
160     VisibleAreaScroller aAnimation(
161         mrSlideSorter,
162         aCurrentTopLeft,
163         maRequestedVisibleTopLeft);
164     if (meRequestedAnimationMode==Animator::AM_Animated
165         && mrSlideSorter.GetProperties()->IsSmoothSelectionScrolling())
166     {
167         mnScrollAnimationId = mrSlideSorter.GetController().GetAnimator()->AddAnimation(
168             aAnimation,
169             0,
170             300);
171     }
172     else
173     {
174         // Execute the animation at its final value.
175         aAnimation(1.0);
176     }
177     meRequestedAnimationMode = Animator::AM_Immediate;
178 }
179 
180 
181 
182 
GetRequestedTopLeft(void) const183 ::boost::optional<Point> VisibleAreaManager::GetRequestedTopLeft (void) const
184 {
185     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
186     if ( ! pWindow)
187         return ::boost::optional<Point>();
188 
189     // Get the currently visible area and the model area.
190     const Rectangle aVisibleArea (pWindow->PixelToLogic(
191         Rectangle(
192             Point(0,0),
193             pWindow->GetOutputSizePixel())));
194     const Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea());
195 
196     sal_Int32 nVisibleTop (aVisibleArea.Top());
197     const sal_Int32 nVisibleWidth (aVisibleArea.GetWidth());
198     sal_Int32 nVisibleLeft (aVisibleArea.Left());
199     const sal_Int32 nVisibleHeight (aVisibleArea.GetHeight());
200 
201     // Find the longest run of boxes whose union fits into the visible area.
202     Rectangle aBoundingBox;
203     for (::std::vector<Rectangle>::const_iterator
204              iBox(maVisibleRequests.begin()),
205              iEnd(maVisibleRequests.end());
206          iBox!=iEnd;
207          ++iBox)
208     {
209         if (nVisibleTop+nVisibleHeight <= iBox->Bottom())
210             nVisibleTop = iBox->Bottom()-nVisibleHeight;
211         if (nVisibleTop > iBox->Top())
212             nVisibleTop = iBox->Top();
213 
214         if (nVisibleLeft+nVisibleWidth <= iBox->Right())
215             nVisibleLeft = iBox->Right()-nVisibleWidth;
216         if (nVisibleLeft > iBox->Left())
217             nVisibleLeft = iBox->Left();
218 
219         // Make sure the visible area does not move outside the model area.
220         if (nVisibleTop + nVisibleHeight > aModelArea.Bottom())
221             nVisibleTop = aModelArea.Bottom() - nVisibleHeight;
222         if (nVisibleTop < aModelArea.Top())
223             nVisibleTop = aModelArea.Top();
224 
225         if (nVisibleLeft + nVisibleWidth > aModelArea.Right())
226             nVisibleLeft = aModelArea.Right() - nVisibleWidth;
227         if (nVisibleLeft < aModelArea.Left())
228             nVisibleLeft = aModelArea.Left();
229     }
230 
231     const Point aRequestedTopLeft (nVisibleLeft, nVisibleTop);
232     if (aRequestedTopLeft == aVisibleArea.TopLeft())
233         return ::boost::optional<Point>();
234     else
235         return ::boost::optional<Point>(aRequestedTopLeft);
236 }
237 
238 
239 
240 
241 //===== VisibleAreaManager::TemporaryDisabler =================================
242 
TemporaryDisabler(SlideSorter & rSlideSorter)243 VisibleAreaManager::TemporaryDisabler::TemporaryDisabler (SlideSorter& rSlideSorter)
244     : mrVisibleAreaManager(rSlideSorter.GetController().GetVisibleAreaManager())
245 {
246     ++mrVisibleAreaManager.mnDisableCount;
247 }
248 
249 
250 
251 
~TemporaryDisabler(void)252 VisibleAreaManager::TemporaryDisabler::~TemporaryDisabler (void)
253 {
254     --mrVisibleAreaManager.mnDisableCount;
255 }
256 
257 
258 
259 //===== VerticalVisibleAreaScroller ===========================================
260 
261 namespace {
262 
263 const static sal_Int32 gnMaxScrollDistance = 300;
264 
VisibleAreaScroller(SlideSorter & rSlideSorter,const Point aStart,const Point aEnd)265 VisibleAreaScroller::VisibleAreaScroller (
266     SlideSorter& rSlideSorter,
267     const Point aStart,
268     const Point aEnd)
269     : mrSlideSorter(rSlideSorter),
270       maStart(aStart),
271       maEnd(aEnd),
272       maAccelerationFunction(
273           controller::AnimationParametricFunction(
274               controller::AnimationBezierFunction (0.1,0.6)))
275 {
276     // When the distance to scroll is larger than a threshold then first
277     // jump to within this distance of the final value and start the
278     // animation from there.
279     if (abs(aStart.X()-aEnd.X()) > gnMaxScrollDistance)
280     {
281         if (aStart.X() < aEnd.X())
282             maStart.X() = aEnd.X()-gnMaxScrollDistance;
283         else
284             maStart.X() = aEnd.X()+gnMaxScrollDistance;
285     }
286     if (abs(aStart.Y()-aEnd.Y()) > gnMaxScrollDistance)
287     {
288         if (aStart.Y() < aEnd.Y())
289             maStart.Y() = aEnd.Y()-gnMaxScrollDistance;
290         else
291             maStart.Y() = aEnd.Y()+gnMaxScrollDistance;
292     }
293 }
294 
295 
296 
297 
operator ()(const double nTime)298 void VisibleAreaScroller::operator() (const double nTime)
299 {
300     const double nLocalTime (maAccelerationFunction(nTime));
301     mrSlideSorter.GetController().GetScrollBarManager().SetTopLeft(
302         Point(
303             sal_Int32(0.5 + maStart.X() * (1.0 - nLocalTime) + maEnd.X() * nLocalTime),
304             sal_Int32 (0.5 + maStart.Y() * (1.0 - nLocalTime) + maEnd.Y() * nLocalTime)));
305 }
306 
307 } // end of anonymous namespace
308 
309 } } } // end of namespace ::sd::slidesorter::controller
310