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 void VisibleAreaManager::RequestVisible ( 98 const model::SharedPageDescriptor& rpDescriptor, 99 const bool bForce) 100 { 101 if (rpDescriptor) 102 { 103 if (mnDisableCount == 0) 104 { 105 maVisibleRequests.push_back( 106 mrSlideSorter.GetView().GetLayouter().GetPageObjectBox( 107 rpDescriptor->GetPageIndex(), 108 true)); 109 } 110 if (bForce && ! mbIsCurrentSlideTrackingActive) 111 ActivateCurrentSlideTracking(); 112 MakeVisible(); 113 } 114 } 115 116 117 118 119 void VisibleAreaManager::RequestCurrentSlideVisible (void) 120 { 121 if (mbIsCurrentSlideTrackingActive && mnDisableCount==0) 122 RequestVisible( 123 mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); 124 } 125 126 127 128 129 void VisibleAreaManager::MakeVisible (void) 130 { 131 if (maVisibleRequests.empty()) 132 return; 133 134 SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); 135 if ( ! pWindow) 136 return; 137 const Point aCurrentTopLeft (pWindow->PixelToLogic(Point(0,0))); 138 139 const ::boost::optional<Point> aNewVisibleTopLeft (GetRequestedTopLeft()); 140 maVisibleRequests.clear(); 141 if ( ! aNewVisibleTopLeft) 142 return; 143 144 // We now know what the visible area shall be. Scroll accordingly 145 // unless that is not already the visible area or a running scroll 146 // animation has it as its target area. 147 if (mnScrollAnimationId!=Animator::NotAnAnimationId 148 && maRequestedVisibleTopLeft==aNewVisibleTopLeft) 149 return; 150 151 // Stop a running animation. 152 if (mnScrollAnimationId != Animator::NotAnAnimationId) 153 mrSlideSorter.GetController().GetAnimator()->RemoveAnimation(mnScrollAnimationId); 154 155 maRequestedVisibleTopLeft = aNewVisibleTopLeft.get(); 156 VisibleAreaScroller aAnimation( 157 mrSlideSorter, 158 aCurrentTopLeft, 159 maRequestedVisibleTopLeft); 160 if (meRequestedAnimationMode==Animator::AM_Animated 161 && mrSlideSorter.GetProperties()->IsSmoothSelectionScrolling()) 162 { 163 mnScrollAnimationId = mrSlideSorter.GetController().GetAnimator()->AddAnimation( 164 aAnimation, 165 0, 166 300); 167 } 168 else 169 { 170 // Execute the animation at its final value. 171 aAnimation(1.0); 172 } 173 meRequestedAnimationMode = Animator::AM_Immediate; 174 } 175 176 177 178 179 ::boost::optional<Point> VisibleAreaManager::GetRequestedTopLeft (void) const 180 { 181 SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); 182 if ( ! pWindow) 183 return ::boost::optional<Point>(); 184 185 // Get the currently visible area and the model area. 186 const Rectangle aVisibleArea (pWindow->PixelToLogic( 187 Rectangle( 188 Point(0,0), 189 pWindow->GetOutputSizePixel()))); 190 const Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); 191 192 sal_Int32 nVisibleTop (aVisibleArea.Top()); 193 const sal_Int32 nVisibleWidth (aVisibleArea.GetWidth()); 194 sal_Int32 nVisibleLeft (aVisibleArea.Left()); 195 const sal_Int32 nVisibleHeight (aVisibleArea.GetHeight()); 196 197 // Find the longest run of boxes whose union fits into the visible area. 198 Rectangle aBoundingBox; 199 for (::std::vector<Rectangle>::const_iterator 200 iBox(maVisibleRequests.begin()), 201 iEnd(maVisibleRequests.end()); 202 iBox!=iEnd; 203 ++iBox) 204 { 205 if (nVisibleTop+nVisibleHeight <= iBox->Bottom()) 206 nVisibleTop = iBox->Bottom()-nVisibleHeight; 207 if (nVisibleTop > iBox->Top()) 208 nVisibleTop = iBox->Top(); 209 210 if (nVisibleLeft+nVisibleWidth <= iBox->Right()) 211 nVisibleLeft = iBox->Right()-nVisibleWidth; 212 if (nVisibleLeft > iBox->Left()) 213 nVisibleLeft = iBox->Left(); 214 215 // Make sure the visible area does not move outside the model area. 216 if (nVisibleTop + nVisibleHeight > aModelArea.Bottom()) 217 nVisibleTop = aModelArea.Bottom() - nVisibleHeight; 218 if (nVisibleTop < aModelArea.Top()) 219 nVisibleTop = aModelArea.Top(); 220 221 if (nVisibleLeft + nVisibleWidth > aModelArea.Right()) 222 nVisibleLeft = aModelArea.Right() - nVisibleWidth; 223 if (nVisibleLeft < aModelArea.Left()) 224 nVisibleLeft = aModelArea.Left(); 225 } 226 227 const Point aRequestedTopLeft (nVisibleLeft, nVisibleTop); 228 if (aRequestedTopLeft == aVisibleArea.TopLeft()) 229 return ::boost::optional<Point>(); 230 else 231 return ::boost::optional<Point>(aRequestedTopLeft); 232 } 233 234 235 236 237 //===== VisibleAreaManager::TemporaryDisabler ================================= 238 239 VisibleAreaManager::TemporaryDisabler::TemporaryDisabler (SlideSorter& rSlideSorter) 240 : mrVisibleAreaManager(rSlideSorter.GetController().GetVisibleAreaManager()) 241 { 242 ++mrVisibleAreaManager.mnDisableCount; 243 } 244 245 246 247 248 VisibleAreaManager::TemporaryDisabler::~TemporaryDisabler (void) 249 { 250 --mrVisibleAreaManager.mnDisableCount; 251 } 252 253 254 255 //===== VerticalVisibleAreaScroller =========================================== 256 257 namespace { 258 259 const static sal_Int32 gnMaxScrollDistance = 300; 260 261 VisibleAreaScroller::VisibleAreaScroller ( 262 SlideSorter& rSlideSorter, 263 const Point aStart, 264 const Point aEnd) 265 : mrSlideSorter(rSlideSorter), 266 maStart(aStart), 267 maEnd(aEnd), 268 maAccelerationFunction( 269 controller::AnimationParametricFunction( 270 controller::AnimationBezierFunction (0.1,0.6))) 271 { 272 // When the distance to scroll is larger than a threshold then first 273 // jump to within this distance of the final value and start the 274 // animation from there. 275 if (abs(aStart.X()-aEnd.X()) > gnMaxScrollDistance) 276 { 277 if (aStart.X() < aEnd.X()) 278 maStart.X() = aEnd.X()-gnMaxScrollDistance; 279 else 280 maStart.X() = aEnd.X()+gnMaxScrollDistance; 281 } 282 if (abs(aStart.Y()-aEnd.Y()) > gnMaxScrollDistance) 283 { 284 if (aStart.Y() < aEnd.Y()) 285 maStart.Y() = aEnd.Y()-gnMaxScrollDistance; 286 else 287 maStart.Y() = aEnd.Y()+gnMaxScrollDistance; 288 } 289 } 290 291 292 293 294 void VisibleAreaScroller::operator() (const double nTime) 295 { 296 const double nLocalTime (maAccelerationFunction(nTime)); 297 mrSlideSorter.GetController().GetScrollBarManager().SetTopLeft( 298 Point( 299 sal_Int32(0.5 + maStart.X() * (1.0 - nLocalTime) + maEnd.X() * nLocalTime), 300 sal_Int32 (0.5 + maStart.Y() * (1.0 - nLocalTime) + maEnd.Y() * nLocalTime))); 301 } 302 303 } // end of anonymous namespace 304 305 } } } // end of namespace ::sd::slidesorter::controller 306