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