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