xref: /trunk/main/vcl/source/window/scrwnd.cxx (revision 7540865d44c9eb37aba9b6e1796cf4bc266ae9a2)
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 
ImplWheelWindow(Window * pParent)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 
~ImplWheelWindow()102 ImplWheelWindow::~ImplWheelWindow()
103 {
104     ImplStop();
105     delete mpTimer;
106 }
107 
108 // ------------------------------------------------------------------------
109 
ImplStop()110 void ImplWheelWindow::ImplStop()
111 {
112     ReleaseMouse();
113     mpTimer->Stop();
114     Show(sal_False);
115 }
116 
117 // ------------------------------------------------------------------------
118 
ImplSetRegion(const Bitmap & rRegionBmp)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 
ImplCreateImageList()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 
ImplSetWheelMode(sal_uLong nWheelMode)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 
ImplDrawWheel()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 
ImplRecalcScrollValues()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 
ImplGetMousePointer(long nDistX,long nDistY)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 
Paint(const Rectangle &)314 void ImplWheelWindow::Paint( const Rectangle& )
315 {
316     ImplDrawWheel();
317 }
318 
319 // ------------------------------------------------------------------------
320 
MouseMove(const MouseEvent & rMEvt)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 
MouseButtonUp(const MouseEvent & rMEvt)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 
IMPL_LINK(ImplWheelWindow,ImplScrollHdl,Timer *,EMPTYARG)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