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