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 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 70 VisibleAreaManager::~VisibleAreaManager (void) 71 { 72 } 73 74 75 76 77 void VisibleAreaManager::ActivateCurrentSlideTracking (void) 78 { 79 mbIsCurrentSlideTrackingActive = true; 80 } 81 82 83 84 85 void VisibleAreaManager::DeactivateCurrentSlideTracking (void) 86 { 87 mbIsCurrentSlideTrackingActive = false; 88 } 89 90 91 92 93 bool VisibleAreaManager::IsCurrentSlideTrackingActive (void) const 94 { 95 return mbIsCurrentSlideTrackingActive; 96 } 97 98 99 100 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 123 void VisibleAreaManager::RequestCurrentSlideVisible (void) 124 { 125 if (mbIsCurrentSlideTrackingActive && mnDisableCount==0) 126 RequestVisible( 127 mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); 128 } 129 130 131 132 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 183 ::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 243 VisibleAreaManager::TemporaryDisabler::TemporaryDisabler (SlideSorter& rSlideSorter) 244 : mrVisibleAreaManager(rSlideSorter.GetController().GetVisibleAreaManager()) 245 { 246 ++mrVisibleAreaManager.mnDisableCount; 247 } 248 249 250 251 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 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 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