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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 // #include <math.h> 32 #include <limits.h> 33 #include <tools/time.hxx> 34 #include <tools/debug.hxx> 35 36 #include <svids.hrc> 37 #include <svdata.hxx> 38 #include <scrwnd.hxx> 39 40 #include <vcl/timer.hxx> 41 #include <vcl/event.hxx> 42 43 #include <math.h> 44 #include <limits.h> 45 46 // ----------- 47 // - Defines - 48 // ----------- 49 50 #define WHEEL_WIDTH 25 51 #define WHEEL_RADIUS ((WHEEL_WIDTH) >> 1 ) 52 #define MAX_TIME 300 53 #define MIN_TIME 20 54 #define DEF_TIMEOUT 50 55 56 // ------------------- 57 // - ImplWheelWindow - 58 // ------------------- 59 60 ImplWheelWindow::ImplWheelWindow( Window* pParent ) : 61 FloatingWindow ( pParent, 0 ), 62 mnRepaintTime ( 1UL ), 63 mnTimeout ( DEF_TIMEOUT ), 64 mnWheelMode ( WHEELMODE_NONE ), 65 mnActDist ( 0UL ), 66 mnActDeltaX ( 0L ), 67 mnActDeltaY ( 0L ) 68 { 69 // we need a parent 70 DBG_ASSERT( pParent, "ImplWheelWindow::ImplWheelWindow(): Parent not set!" ); 71 72 const Size aSize( pParent->GetOutputSizePixel() ); 73 const sal_uInt16 nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags; 74 const sal_Bool bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0; 75 const sal_Bool bVert = ( nFlags & AUTOSCROLL_VERT ) != 0; 76 77 // calculate maximum speed distance 78 mnMaxWidth = (sal_uLong) ( 0.4 * hypot( (double) aSize.Width(), aSize.Height() ) ); 79 80 // create wheel window 81 SetTitleType( FLOATWIN_TITLE_NONE ); 82 ImplCreateImageList(); 83 ResMgr* pResMgr = ImplGetResMgr(); 84 Bitmap aBmp; 85 if( pResMgr ) 86 aBmp = Bitmap( ResId( SV_RESID_BITMAP_SCROLLMSK, *pResMgr ) ); 87 ImplSetRegion( aBmp ); 88 89 // set wheel mode 90 if( bHorz && bVert ) 91 ImplSetWheelMode( WHEELMODE_VH ); 92 else if( bHorz ) 93 ImplSetWheelMode( WHEELMODE_H ); 94 else 95 ImplSetWheelMode( WHEELMODE_V ); 96 97 // init timer 98 mpTimer = new Timer; 99 mpTimer->SetTimeoutHdl( LINK( this, ImplWheelWindow, ImplScrollHdl ) ); 100 mpTimer->SetTimeout( mnTimeout ); 101 mpTimer->Start(); 102 103 CaptureMouse(); 104 } 105 106 // ------------------------------------------------------------------------ 107 108 ImplWheelWindow::~ImplWheelWindow() 109 { 110 ImplStop(); 111 delete mpTimer; 112 } 113 114 // ------------------------------------------------------------------------ 115 116 void ImplWheelWindow::ImplStop() 117 { 118 ReleaseMouse(); 119 mpTimer->Stop(); 120 Show(sal_False); 121 } 122 123 // ------------------------------------------------------------------------ 124 125 void ImplWheelWindow::ImplSetRegion( const Bitmap& rRegionBmp ) 126 { 127 Point aPos( GetPointerPosPixel() ); 128 const Size aSize( rRegionBmp.GetSizePixel() ); 129 Point aPoint; 130 const Rectangle aRect( aPoint, aSize ); 131 132 maCenter = maLastMousePos = aPos; 133 aPos.X() -= aSize.Width() >> 1; 134 aPos.Y() -= aSize.Height() >> 1; 135 136 SetPosSizePixel( aPos, aSize ); 137 SetWindowRegionPixel( rRegionBmp.CreateRegion( COL_BLACK, aRect ) ); 138 } 139 140 // ------------------------------------------------------------------------ 141 142 void ImplWheelWindow::ImplCreateImageList() 143 { 144 ResMgr* pResMgr = ImplGetResMgr(); 145 if( pResMgr ) 146 maImgList.InsertFromHorizontalBitmap 147 ( ResId( SV_RESID_BITMAP_SCROLLBMP, *pResMgr ), 6, NULL ); 148 } 149 150 // ------------------------------------------------------------------------ 151 152 void ImplWheelWindow::ImplSetWheelMode( sal_uLong nWheelMode ) 153 { 154 if( nWheelMode != mnWheelMode ) 155 { 156 mnWheelMode = nWheelMode; 157 158 if( WHEELMODE_NONE == mnWheelMode ) 159 { 160 if( IsVisible() ) 161 Hide(); 162 } 163 else 164 { 165 if( !IsVisible() ) 166 Show(); 167 168 ImplDrawWheel(); 169 } 170 } 171 } 172 173 // ------------------------------------------------------------------------ 174 175 void ImplWheelWindow::ImplDrawWheel() 176 { 177 sal_uInt16 nId; 178 179 switch( mnWheelMode ) 180 { 181 case( WHEELMODE_VH ): nId = 1; break; 182 case( WHEELMODE_V ): nId = 2; break; 183 case( WHEELMODE_H ): nId = 3; break; 184 case( WHEELMODE_SCROLL_VH ):nId = 4; break; 185 case( WHEELMODE_SCROLL_V ): nId = 5; break; 186 case( WHEELMODE_SCROLL_H ): nId = 6; break; 187 default: nId = 0; break; 188 } 189 190 if( nId ) 191 DrawImage( Point(), maImgList.GetImage( nId ) ); 192 } 193 194 // ------------------------------------------------------------------------ 195 196 void ImplWheelWindow::ImplRecalcScrollValues() 197 { 198 if( mnActDist < WHEEL_RADIUS ) 199 { 200 mnActDeltaX = mnActDeltaY = 0L; 201 mnTimeout = DEF_TIMEOUT; 202 } 203 else 204 { 205 sal_uLong nCurTime; 206 207 // calc current time 208 if( mnMaxWidth ) 209 { 210 const double fExp = ( (double) mnActDist / mnMaxWidth ) * log10( (double) MAX_TIME / MIN_TIME ); 211 nCurTime = (sal_uLong) ( MAX_TIME / pow( 10., fExp ) ); 212 } 213 else 214 nCurTime = MAX_TIME; 215 216 if( !nCurTime ) 217 nCurTime = 1UL; 218 219 if( mnRepaintTime <= nCurTime ) 220 mnTimeout = nCurTime - mnRepaintTime; 221 else 222 { 223 long nMult = mnRepaintTime / nCurTime; 224 225 if( !( mnRepaintTime % nCurTime ) ) 226 mnTimeout = 0UL; 227 else 228 mnTimeout = ++nMult * nCurTime - mnRepaintTime; 229 230 double fValX = (double) mnActDeltaX * nMult; 231 double fValY = (double) mnActDeltaY * nMult; 232 233 if( fValX > LONG_MAX ) 234 mnActDeltaX = LONG_MAX; 235 else if( fValX < LONG_MIN ) 236 mnActDeltaX = LONG_MIN; 237 else 238 mnActDeltaX = (long) fValX; 239 240 if( fValY > LONG_MAX ) 241 mnActDeltaY = LONG_MAX; 242 else if( fValY < LONG_MIN ) 243 mnActDeltaY = LONG_MIN; 244 else 245 mnActDeltaY = (long) fValY; 246 } 247 } 248 } 249 250 // ------------------------------------------------------------------------ 251 252 PointerStyle ImplWheelWindow::ImplGetMousePointer( long nDistX, long nDistY ) 253 { 254 PointerStyle eStyle; 255 const sal_uInt16 nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags; 256 const sal_Bool bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0; 257 const sal_Bool bVert = ( nFlags & AUTOSCROLL_VERT ) != 0; 258 259 if( bHorz || bVert ) 260 { 261 if( mnActDist < WHEEL_RADIUS ) 262 { 263 if( bHorz && bVert ) 264 eStyle = POINTER_AUTOSCROLL_NSWE; 265 else if( bHorz ) 266 eStyle = POINTER_AUTOSCROLL_WE; 267 else 268 eStyle = POINTER_AUTOSCROLL_NS; 269 } 270 else 271 { 272 double fAngle = atan2( (double) -nDistY, nDistX ) / F_PI180; 273 274 if( fAngle < 0.0 ) 275 fAngle += 360.; 276 277 if( bHorz && bVert ) 278 { 279 if( fAngle >= 22.5 && fAngle <= 67.5 ) 280 eStyle = POINTER_AUTOSCROLL_NE; 281 else if( fAngle >= 67.5 && fAngle <= 112.5 ) 282 eStyle = POINTER_AUTOSCROLL_N; 283 else if( fAngle >= 112.5 && fAngle <= 157.5 ) 284 eStyle = POINTER_AUTOSCROLL_NW; 285 else if( fAngle >= 157.5 && fAngle <= 202.5 ) 286 eStyle = POINTER_AUTOSCROLL_W; 287 else if( fAngle >= 202.5 && fAngle <= 247.5 ) 288 eStyle = POINTER_AUTOSCROLL_SW; 289 else if( fAngle >= 247.5 && fAngle <= 292.5 ) 290 eStyle = POINTER_AUTOSCROLL_S; 291 else if( fAngle >= 292.5 && fAngle <= 337.5 ) 292 eStyle = POINTER_AUTOSCROLL_SE; 293 else 294 eStyle = POINTER_AUTOSCROLL_E; 295 } 296 else if( bHorz ) 297 { 298 if( fAngle >= 270. || fAngle <= 90. ) 299 eStyle = POINTER_AUTOSCROLL_E; 300 else 301 eStyle = POINTER_AUTOSCROLL_W; 302 } 303 else 304 { 305 if( fAngle >= 0. && fAngle <= 180. ) 306 eStyle = POINTER_AUTOSCROLL_N; 307 else 308 eStyle = POINTER_AUTOSCROLL_S; 309 } 310 } 311 } 312 else 313 eStyle = POINTER_ARROW; 314 315 return eStyle; 316 } 317 318 // ------------------------------------------------------------------------ 319 320 void ImplWheelWindow::Paint( const Rectangle& ) 321 { 322 ImplDrawWheel(); 323 } 324 325 // ------------------------------------------------------------------------ 326 327 void ImplWheelWindow::MouseMove( const MouseEvent& rMEvt ) 328 { 329 FloatingWindow::MouseMove( rMEvt ); 330 331 const Point aMousePos( OutputToScreenPixel( rMEvt.GetPosPixel() ) ); 332 const long nDistX = aMousePos.X() - maCenter.X(); 333 const long nDistY = aMousePos.Y() - maCenter.Y(); 334 335 mnActDist = (sal_uLong) hypot( (double) nDistX, nDistY ); 336 337 const PointerStyle eActStyle = ImplGetMousePointer( nDistX, nDistY ); 338 const sal_uInt16 nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags; 339 const sal_Bool bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0; 340 const sal_Bool bVert = ( nFlags & AUTOSCROLL_VERT ) != 0; 341 const sal_Bool bOuter = mnActDist > WHEEL_RADIUS; 342 343 if( bOuter && ( maLastMousePos != aMousePos ) ) 344 { 345 switch( eActStyle ) 346 { 347 case( POINTER_AUTOSCROLL_N ): mnActDeltaX = +0L, mnActDeltaY = +1L; break; 348 case( POINTER_AUTOSCROLL_S ): mnActDeltaX = +0L, mnActDeltaY = -1L; break; 349 case( POINTER_AUTOSCROLL_W ): mnActDeltaX = +1L, mnActDeltaY = +0L; break; 350 case( POINTER_AUTOSCROLL_E ): mnActDeltaX = -1L, mnActDeltaY = +0L; break; 351 case( POINTER_AUTOSCROLL_NW ): mnActDeltaX = +1L, mnActDeltaY = +1L; break; 352 case( POINTER_AUTOSCROLL_NE ): mnActDeltaX = -1L, mnActDeltaY = +1L; break; 353 case( POINTER_AUTOSCROLL_SW ): mnActDeltaX = +1L, mnActDeltaY = -1L; break; 354 case( POINTER_AUTOSCROLL_SE ): mnActDeltaX = -1L, mnActDeltaY = -1L; break; 355 356 default: 357 break; 358 } 359 } 360 361 ImplRecalcScrollValues(); 362 maLastMousePos = aMousePos; 363 SetPointer( eActStyle ); 364 365 if( bHorz && bVert ) 366 ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_VH : WHEELMODE_VH ); 367 else if( bHorz ) 368 ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_H : WHEELMODE_H ); 369 else 370 ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_V : WHEELMODE_V ); 371 } 372 373 // ------------------------------------------------------------------------ 374 375 void ImplWheelWindow::MouseButtonUp( const MouseEvent& rMEvt ) 376 { 377 if( mnActDist > WHEEL_RADIUS ) 378 GetParent()->EndAutoScroll(); 379 else 380 FloatingWindow::MouseButtonUp( rMEvt ); 381 } 382 383 // ------------------------------------------------------------------------ 384 385 IMPL_LINK( ImplWheelWindow, ImplScrollHdl, Timer*, EMPTYARG ) 386 { 387 if ( mnActDeltaX || mnActDeltaY ) 388 { 389 Window* pWindow = GetParent(); 390 const Point aMousePos( pWindow->OutputToScreenPixel( pWindow->GetPointerPosPixel() ) ); 391 Point aCmdMousePos( pWindow->ImplFrameToOutput( aMousePos ) ); 392 CommandScrollData aScrollData( mnActDeltaX, mnActDeltaY ); 393 CommandEvent aCEvt( aCmdMousePos, COMMAND_AUTOSCROLL, sal_True, &aScrollData ); 394 NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt ); 395 396 if ( !ImplCallPreNotify( aNCmdEvt ) ) 397 { 398 const sal_uLong nTime = Time::GetSystemTicks(); 399 ImplDelData aDel( this ); 400 pWindow->Command( aCEvt ); 401 if( aDel.IsDead() ) 402 return 0; 403 mnRepaintTime = Max( Time::GetSystemTicks() - nTime, 1UL ); 404 ImplRecalcScrollValues(); 405 } 406 } 407 408 if ( mnTimeout != mpTimer->GetTimeout() ) 409 mpTimer->SetTimeout( mnTimeout ); 410 mpTimer->Start(); 411 412 return 0L; 413 } 414