xref: /aoo41x/main/vcl/source/window/scrwnd.cxx (revision cdf0e10c)
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