Release 960218
[wine] / windows / scroll.c
1 /*
2  * Scroll windows and DCs
3  *
4  * Copyright  David W. Metcalfe, 1993
5  *            Alex Korobka       1995
6  *
7  *
8  */
9
10 #include <stdlib.h>
11 #include "wintypes.h"
12 #include "class.h"
13 #include "win.h"
14 #include "gdi.h"
15 #include "sysmetrics.h"
16 #include "stddebug.h"
17 /* #define DEBUG_SCROLL */
18 #include "debug.h"
19
20
21
22 extern HRGN DCE_GetVisRgn(HWND, WORD);
23
24 static int RgnType;
25
26
27 /* -----------------------------------------------------------------------
28  *             SCROLL_TraceChildren
29  * 
30  * Returns a region invalidated by children, siblings, and/or ansectors
31  * in the window rectangle or client rectangle
32  *
33  * dcx can have DCX_WINDOW, DCX_CLIPCHILDREN, DCX_CLIPSIBLINGS set
34  */
35
36 HRGN    SCROLL_TraceChildren( HWND hScroll, short dx, short dy, WORD dcx)
37 {
38  WND           *wndScroll = WIN_FindWndPtr( hScroll ); 
39  HRGN           hRgnWnd;
40  HRGN           hUpdateRgn,hCombineRgn;
41
42  if( !wndScroll || ( !dx && !dy) ) return 0;
43
44  if( dcx & DCX_WINDOW )
45          hRgnWnd   = CreateRectRgnIndirect(&wndScroll->rectWindow);
46  else
47         {
48          RECT rect;
49
50          GetClientRect(hScroll,&rect);
51          hRgnWnd   = CreateRectRgnIndirect(&rect);
52         }
53
54  hUpdateRgn  = DCE_GetVisRgn( hScroll, dcx );
55  hCombineRgn = CreateRectRgn(0,0,0,0);
56
57  if( !hUpdateRgn || !hCombineRgn )
58       {
59         DeleteObject( hUpdateRgn? hUpdateRgn : hCombineRgn);
60         DeleteObject(hRgnWnd);
61         return 0;
62       }
63
64  OffsetRgn( hUpdateRgn, dx, dy);
65  CombineRgn(hCombineRgn, hRgnWnd, hUpdateRgn, RGN_DIFF);
66  
67  DeleteObject(hRgnWnd);
68  DeleteObject(hUpdateRgn);
69
70  return hCombineRgn;
71 }
72
73
74 /* ----------------------------------------------------------------------
75  *             SCROLL_ScrollChildren
76  */
77 BOOL    SCROLL_ScrollChildren( HWND hScroll, short dx, short dy)
78 {
79  WND           *wndPtr = WIN_FindWndPtr(hScroll);
80  HWND           hWnd   = wndPtr->hwndChild;
81  HRGN           hUpdateRgn;
82  BOOL           b = 0;
83
84  if( !wndPtr || ( !dx && !dy )) return 0;
85
86  dprintf_scroll(stddeb,"SCROLL_ScrollChildren: hwnd "NPFMT" dx=%i dy=%i\n",hScroll,dx,dy);
87
88  /* get a region in client rect invalidated by siblings and ansectors */
89  hUpdateRgn = SCROLL_TraceChildren(hScroll, dx , dy, DCX_CLIPSIBLINGS);
90
91  /* update children coordinates */
92  while( hWnd )
93   {
94         wndPtr = WIN_FindWndPtr( hWnd );
95
96         /* we can check if window intersects with clipRect parameter
97          * and do not move it if not - just a thought.     - AK
98          */
99
100         SetWindowPos(hWnd,0,wndPtr->rectWindow.left + dx,
101                             wndPtr->rectWindow.top  + dy, 0,0, SWP_NOZORDER |
102                             SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
103                             SWP_DEFERERASE );
104
105         hWnd = wndPtr->hwndNext;
106   } 
107
108  /* invalidate uncovered region and paint frames */
109  b = RedrawWindow( hScroll, NULL, hUpdateRgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE |
110                                               RDW_ERASENOW | RDW_ALLCHILDREN ); 
111
112  DeleteObject( hUpdateRgn);
113  return b;
114 }
115
116
117 /*************************************************************************
118  *             ScrollWindow         (USER.61)
119  *
120  * FIXME: a bit broken
121  */
122
123 void ScrollWindow(HWND hwnd, short dx, short dy, LPRECT rect, LPRECT clipRect)
124 {
125     HDC hdc;
126     HRGN hrgnUpdate,hrgnClip;
127     RECT rc, cliprc;
128
129     dprintf_scroll(stddeb,"ScrollWindow: dx=%d, dy=%d, lpRect =%08lx clipRect=%i,%i,%i,%i\n", 
130             dx, dy, (LONG)rect, (int)((clipRect)?clipRect->left:0),
131                                 (int)((clipRect)?clipRect->top:0),
132                                 (int)((clipRect)?clipRect->right:0), 
133                                 (int)((clipRect)?clipRect->bottom:0));
134
135     /* if rect is NULL children have to be moved */
136     if ( !rect )
137        {
138         GetClientRect(hwnd, &rc);
139           hrgnClip = CreateRectRgnIndirect( &rc );
140
141           /* children will be Blt'ed too */
142           hdc      = GetDCEx(hwnd, hrgnClip, DCX_CACHE | DCX_CLIPSIBLINGS);
143           DeleteObject(hrgnClip);
144        }
145     else
146        {
147           GetClientRect(hwnd,&rc);
148           dprintf_scroll(stddeb,"\trect=%i %i %i %i client=%i %i %i %i\n",
149                          (int)rect->left,(int)rect->top,(int)rect->right,
150                          (int)rect->bottom,(int)rc.left,(int)rc.top,
151                          (int)rc.right,(int)rc.bottom);
152
153         CopyRect(&rc, rect);
154           hdc = GetDC(hwnd);
155        }
156
157     if (clipRect == NULL)
158         GetClientRect(hwnd, &cliprc);
159     else
160         CopyRect(&cliprc, clipRect);
161
162     hrgnUpdate = CreateRectRgn(0, 0, 0, 0);
163     ScrollDC(hdc, dx, dy, &rc, &cliprc, hrgnUpdate, NULL);
164     ReleaseDC(hwnd, hdc);
165
166     if( !rect )
167       {
168          /* FIXME: this doesn't take into account hrgnUpdate */
169          if( !SCROLL_ScrollChildren(hwnd,dx,dy) )
170              InvalidateRgn(hwnd, hrgnUpdate, TRUE);
171       }
172     else
173       {
174         HRGN hrgnInv = SCROLL_TraceChildren(hwnd,dx,dy,DCX_CLIPCHILDREN |
175                                                        DCX_CLIPSIBLINGS );
176         if( hrgnInv )
177           {
178             HRGN hrgnCombine = CreateRectRgn(0,0,0,0);
179
180             CombineRgn(hrgnCombine,hrgnInv,hrgnUpdate,RGN_OR);
181             dprintf_scroll(stddeb,"ScrollWindow: hrgnComb="NPFMT" hrgnInv="NPFMT" hrgnUpd="NPFMT"\n",
182                                                            hrgnCombine,hrgnInv,hrgnUpdate);
183
184             DeleteObject(hrgnUpdate); DeleteObject(hrgnInv);
185             hrgnUpdate = hrgnCombine;
186           }
187
188         RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW);
189       }
190
191     DeleteObject(hrgnUpdate);
192 }
193
194
195 /*************************************************************************
196  *             ScrollDC         (USER.221)
197  *
198  * FIXME: half-broken
199  */
200
201 BOOL ScrollDC(HDC hdc, short dx, short dy, LPRECT rc, LPRECT cliprc,
202               HRGN hrgnUpdate, LPRECT rcUpdate)
203 {
204     HRGN hrgnClip, hrgn1, hrgn2;
205     POINT src, dest;
206     short width, height;
207     DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
208
209     dprintf_scroll(stddeb,"ScrollDC: dx=%d dy=%d, hrgnUpdate="NPFMT" rc=%i %i %i %i\n",
210                                      dx,dy,hrgnUpdate,(int)((rc)?rc->left:0),
211                                                       (int)((rc)?rc->top:0),
212                                                       (int)((rc)?rc->right:0),
213                                                       (int)((rc)?rc->bottom:0)); 
214
215     if (rc == NULL)
216         return FALSE;
217
218     if (cliprc)
219     {
220         hrgnClip = CreateRectRgnIndirect(cliprc);
221         SelectClipRgn(hdc, hrgnClip);
222     }
223
224     if (dx > 0)
225     {
226         src.x = XDPTOLP(dc, rc->left);
227         dest.x = XDPTOLP(dc, rc->left + abs(dx));
228     }
229     else
230     {
231         src.x = XDPTOLP(dc, rc->left + abs(dx));
232         dest.x = XDPTOLP(dc, rc->left);
233     }
234     if (dy > 0)
235     {
236         src.y = YDPTOLP(dc, rc->top);
237         dest.y = YDPTOLP(dc, rc->top + abs(dy));
238     }
239     else
240     {
241         src.y = YDPTOLP(dc, rc->top + abs(dy));
242         dest.y = YDPTOLP(dc, rc->top);
243     }
244
245     width = rc->right - rc->left - abs(dx);
246     height = rc->bottom - rc->top - abs(dy);
247
248     if (!BitBlt(hdc, dest.x, dest.y, width, height, hdc, src.x, src.y, 
249                 SRCCOPY))
250         return FALSE;
251
252     if (hrgnUpdate)
253     {
254         if (dx > 0)
255             hrgn1 = CreateRectRgn(rc->left, rc->top, rc->left+dx, rc->bottom);
256         else if (dx < 0)
257             hrgn1 = CreateRectRgn(rc->right+dx, rc->top, rc->right, 
258                                   rc->bottom);
259         else
260             hrgn1 = CreateRectRgn(0, 0, 0, 0);
261
262         if (dy > 0)
263             hrgn2 = CreateRectRgn(rc->left, rc->top, rc->right, rc->top+dy);
264         else if (dy < 0)
265             hrgn2 = CreateRectRgn(rc->left, rc->bottom+dy, rc->right, 
266                                   rc->bottom);
267         else
268             hrgn2 = CreateRectRgn(0, 0, 0, 0);
269
270         RgnType = CombineRgn(hrgnUpdate, hrgn1, hrgn2, RGN_OR);
271         DeleteObject(hrgn1);
272         DeleteObject(hrgn2);
273     }
274
275     if (rcUpdate) GetRgnBox( hrgnUpdate, rcUpdate );
276     return TRUE;
277 }
278
279
280 /*************************************************************************
281  *             ScrollWindowEx       (USER.319)
282  *
283  * FIXME: broken
284  *
285  * SCROLL_TraceChildren can help
286  */
287
288 int ScrollWindowEx(HWND hwnd, short dx, short dy, LPRECT rect, LPRECT clipRect,
289                    HRGN hrgnUpdate, LPRECT rcUpdate, WORD flags)
290 {
291     HDC hdc;
292     RECT rc, cliprc;
293
294     dprintf_scroll(stddeb,"ScrollWindowEx: dx=%d, dy=%d, wFlags=%04x\n",dx, dy, flags);
295
296     hdc = GetDC(hwnd);
297
298     if (rect == NULL)
299         GetClientRect(hwnd, &rc);
300     else
301         CopyRect(&rc, rect);
302     if (clipRect == NULL)
303         GetClientRect(hwnd, &cliprc);
304     else
305         CopyRect(&cliprc, clipRect);
306
307     ScrollDC(hdc, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate);
308
309     if (flags | SW_INVALIDATE)
310     {
311         RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
312                       ((flags & SW_ERASE) ? RDW_ERASENOW : 0));
313     }
314
315     ReleaseDC(hwnd, hdc);
316     return RgnType;
317 }