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