| 1 | Unit ControlScrolling; | 
|---|
| 2 |  | 
|---|
| 3 | Interface | 
|---|
| 4 |  | 
|---|
| 5 | uses | 
|---|
| 6 | Forms, Classes; | 
|---|
| 7 |  | 
|---|
| 8 | Procedure ScrollControlRect( Control: TControl; | 
|---|
| 9 | Rect: TRect; | 
|---|
| 10 | XScrollDistance, YScrollDistance: longint; | 
|---|
| 11 | BackGroundColor: TColor; | 
|---|
| 12 | Smooth: boolean ); | 
|---|
| 13 |  | 
|---|
| 14 | Implementation | 
|---|
| 15 |  | 
|---|
| 16 | uses | 
|---|
| 17 | Os2Def, PmWin, PmGpi, Graphics; | 
|---|
| 18 |  | 
|---|
| 19 | Procedure ScrollRect( Control: TControl; | 
|---|
| 20 | Rect: TRect; | 
|---|
| 21 | XScrollDistance, YScrollDistance: longint; | 
|---|
| 22 | BackGroundColor: TColor ); | 
|---|
| 23 | var | 
|---|
| 24 | SourceRect: RECTL; | 
|---|
| 25 | InvalidRegion: HRGN; | 
|---|
| 26 | rc: APIRET; | 
|---|
| 27 | begin | 
|---|
| 28 | SourceRect:= RECTL( Rect ); | 
|---|
| 29 | inc( SourceRect.yTop, 1 ); // WinScrollWindow expects top/right + 1 | 
|---|
| 30 | inc( SourceRect.xRight, 1 ); | 
|---|
| 31 |  | 
|---|
| 32 | InvalidRegion:= GpiCreateRegion( Control.Canvas.Handle, 0, nil ); | 
|---|
| 33 | WinScrollWindow( Control.Handle, | 
|---|
| 34 | XScrollDistance, | 
|---|
| 35 | YScrollDistance, | 
|---|
| 36 | SourceRect, | 
|---|
| 37 | SourceRect, // destination clip | 
|---|
| 38 | InvalidRegion, | 
|---|
| 39 | nil, | 
|---|
| 40 | SW_INVALIDATERGN ); | 
|---|
| 41 |  | 
|---|
| 42 | // Clear the invalidated area. | 
|---|
| 43 | Control.Canvas.Pen.Color := BackgroundColor; | 
|---|
| 44 | Control.Canvas.Brush.Style:= bsSolid; | 
|---|
| 45 | rc:= GpiPaintRegion( Control.Canvas.Handle, InvalidRegion ); | 
|---|
| 46 |  | 
|---|
| 47 | GpiDestroyRegion( Control.Canvas.Handle, InvalidRegion ); | 
|---|
| 48 | end; | 
|---|
| 49 |  | 
|---|
| 50 | Function FSign( arg: double ): double; | 
|---|
| 51 | begin | 
|---|
| 52 | if arg>0 then | 
|---|
| 53 | Result:= 1 | 
|---|
| 54 | else if arg<0 then | 
|---|
| 55 | Result:= -1 | 
|---|
| 56 | else | 
|---|
| 57 | Result:= 0; | 
|---|
| 58 | end; | 
|---|
| 59 |  | 
|---|
| 60 | Function Sign( arg: longint ): longint; | 
|---|
| 61 | begin | 
|---|
| 62 | if arg>0 then | 
|---|
| 63 | Result:= 1 | 
|---|
| 64 | else if arg<0 then | 
|---|
| 65 | Result:= -1 | 
|---|
| 66 | else | 
|---|
| 67 | Result:= 0; | 
|---|
| 68 | end; | 
|---|
| 69 |  | 
|---|
| 70 | Procedure ScrollControlRect( Control: TControl; | 
|---|
| 71 | Rect: TRect; | 
|---|
| 72 | XScrollDistance, YScrollDistance: longint; | 
|---|
| 73 | BackGroundColor: TColor; | 
|---|
| 74 | Smooth: boolean ); | 
|---|
| 75 | var | 
|---|
| 76 | LastTime: ULONG; | 
|---|
| 77 | X, Y: double; | 
|---|
| 78 | XScrolled, YScrolled: longint; | 
|---|
| 79 | NextX, NextY: double; | 
|---|
| 80 | Width: longint; | 
|---|
| 81 | Height: longint; | 
|---|
| 82 | XScrollStep: double; | 
|---|
| 83 | YScrollStep: double; | 
|---|
| 84 | XScrollAmount: longint; | 
|---|
| 85 | YScrollAmount: longint; | 
|---|
| 86 | begin | 
|---|
| 87 | Height:= Rect.Top - Rect.Bottom + 1; | 
|---|
| 88 | Width:= Rect.Right - Rect.Left + 1; | 
|---|
| 89 |  | 
|---|
| 90 | if ( XScrollDistance = 0 ) | 
|---|
| 91 | and ( YScrollDistance = 0 ) then | 
|---|
| 92 | exit; | 
|---|
| 93 |  | 
|---|
| 94 | if   ( Abs( XScrollDistance ) >= Width ) | 
|---|
| 95 | or ( Abs( YScrollDistance ) >= Height ) then | 
|---|
| 96 | begin | 
|---|
| 97 | // scrolling more than a screen in height | 
|---|
| 98 | Control.InvalidateRect( Rect ); | 
|---|
| 99 | exit; | 
|---|
| 100 | end; | 
|---|
| 101 |  | 
|---|
| 102 | if not Smooth then | 
|---|
| 103 | begin | 
|---|
| 104 | ScrollRect( Control, | 
|---|
| 105 | Rect, | 
|---|
| 106 | XScrollDistance, | 
|---|
| 107 | YScrollDistance, | 
|---|
| 108 | BackGroundColor ); | 
|---|
| 109 |  | 
|---|
| 110 | exit; | 
|---|
| 111 | end; | 
|---|
| 112 | Y:= 0; | 
|---|
| 113 | X:= 0; | 
|---|
| 114 | XScrolled:= 0; | 
|---|
| 115 | YScrolled:= 0; | 
|---|
| 116 |  | 
|---|
| 117 | if XScrollDistance <> 0 then | 
|---|
| 118 | begin | 
|---|
| 119 | XScrollStep:= Abs( XScrollDistance ) / 10.0 | 
|---|
| 120 | + 0.0001; // add a small amount so we always add up to at least scrolldistance | 
|---|
| 121 | // no less than 1 pixel | 
|---|
| 122 | if XScrollStep < 1 then | 
|---|
| 123 | XScrollStep:= 1; | 
|---|
| 124 | end | 
|---|
| 125 | else | 
|---|
| 126 | XScrollStep:= 0; | 
|---|
| 127 |  | 
|---|
| 128 | if YScrollDistance <> 0 then | 
|---|
| 129 | begin | 
|---|
| 130 | YScrollStep:= Abs( YScrollDistance ) / 10.0 | 
|---|
| 131 | + 0.0001; // add a small amount so we always add up to at least scrolldistance | 
|---|
| 132 |  | 
|---|
| 133 | if YScrollStep < 1 then | 
|---|
| 134 | YScrollStep:= 1; | 
|---|
| 135 | end | 
|---|
| 136 | else | 
|---|
| 137 | YScrollStep:= 0; | 
|---|
| 138 |  | 
|---|
| 139 | while ( XScrolled < Abs( XScrollDistance ) ) | 
|---|
| 140 | or ( YScrolled < Abs( YScrollDistance ) ) do | 
|---|
| 141 | begin | 
|---|
| 142 | LastTime:= WinGetCurrentTime( AppHandle ); | 
|---|
| 143 |  | 
|---|
| 144 | NextX:= X + XScrollStep; | 
|---|
| 145 | NextY:= Y + YScrollStep; | 
|---|
| 146 |  | 
|---|
| 147 | XScrollAmount:= trunc( NextX ) - trunc( X ); | 
|---|
| 148 | YScrollAmount:= trunc( NextY ) - trunc( Y ); | 
|---|
| 149 |  | 
|---|
| 150 | ScrollRect( Control, | 
|---|
| 151 | Rect, | 
|---|
| 152 | XScrollAmount * sign( XScrollDistance ), | 
|---|
| 153 | YScrollAmount * sign( YScrollDistance ), | 
|---|
| 154 | BackGroundColor ); | 
|---|
| 155 |  | 
|---|
| 156 | X:= X + XScrollStep; | 
|---|
| 157 | Y:= Y + YScrollStep; | 
|---|
| 158 |  | 
|---|
| 159 | inc( XScrolled, XScrollAmount ); | 
|---|
| 160 | inc( YScrolled, YScrollAmount ); | 
|---|
| 161 |  | 
|---|
| 162 | // wait at least 5 ms | 
|---|
| 163 | while WinGetCurrentTime( AppHandle ) - LastTime < 5 do | 
|---|
| 164 | ; | 
|---|
| 165 | end; | 
|---|
| 166 | end; | 
|---|
| 167 |  | 
|---|
| 168 | Initialization | 
|---|
| 169 | End. | 
|---|