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