Various cosmetic changes.
[wine] / dlls / comctl32 / pager.c
1 /*
2  * Pager control
3  *
4  * Copyright 1998, 1999 Eric Kohl
5  *
6  * NOTES
7  *    Tested primarily with the controlspy Pager application.
8  *       Susan Farley (susan@codeweavers.com)
9  *
10  * TODO:
11  *    Implement repetitive button press.
12  *    Adjust arrow size relative to size of button.
13  *    Allow border size changes.
14  *    Implement drag and drop style.
15  */
16
17 #include <string.h>
18 #include "winbase.h"
19 #include "commctrl.h"
20 #include "debugtools.h"
21
22 DEFAULT_DEBUG_CHANNEL(pager);
23
24 typedef struct
25 {
26     HWND   hwndChild;  /* handle of the contained wnd */
27     BOOL   bNoResize;  /* set when created with CCS_NORESIZE */
28     COLORREF clrBk;    /* background color */
29     INT    nBorder;    /* border size for the control */
30     INT    nButtonSize;/* size of the pager btns */
31     INT    nPos;       /* scroll position */
32     INT    nWidth;     /* from child wnd's response to PGN_CALCSIZE */
33     INT    nHeight;    /* from child wnd's response to PGN_CALCSIZE */ 
34     BOOL   bForward;   /* forward WM_MOUSEMOVE msgs to the contained wnd */
35     INT    TLbtnState; /* state of top or left btn */
36     INT    BRbtnState; /* state of bottom or right btn */
37     INT    direction;  /* direction of the scroll, (e.g. PGF_SCROLLUP) */
38 } PAGER_INFO;
39
40 #define PAGER_GetInfoPtr(hwnd) ((PAGER_INFO *)GetWindowLongA(hwnd, 0))
41 #define PAGER_IsHorizontal(hwnd) ((GetWindowLongA (hwnd, GWL_STYLE) & PGS_HORZ))
42
43 #define MIN_ARROW_WIDTH  8
44 #define MIN_ARROW_HEIGHT 5
45
46 #define TIMERID1         1
47 #define TIMERID2         2
48 #define INITIAL_DELAY    500
49 #define REPEAT_DELAY     50
50
51 /* the horizontal arrows are: 
52  *
53  * 01234    01234
54  * 1  *      *
55  * 2 **      **
56  * 3***      ***
57  * 4***      ***
58  * 5 **      **
59  * 6  *      *
60  * 7  
61  *
62  */
63 static void
64 PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left)
65 {
66     INT x, y, w, h;
67     HPEN hOldPen;
68     
69     w = r.right - r.left + 1;
70     h = r.bottom - r.top + 1;
71     if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
72         return;  /* refuse to draw partial arrow */
73
74     hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
75     if (left)
76     {
77         x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3;
78         y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
79         MoveToEx (hdc, x, y, NULL);
80         LineTo (hdc, x--, y+5); y++;
81         MoveToEx (hdc, x, y, NULL);
82         LineTo (hdc, x--, y+3); y++;
83         MoveToEx (hdc, x, y, NULL);
84         LineTo (hdc, x, y+1);
85     }
86     else
87     {
88         x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
89         y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
90         MoveToEx (hdc, x, y, NULL);
91         LineTo (hdc, x++, y+5); y++;
92         MoveToEx (hdc, x, y, NULL);
93         LineTo (hdc, x++, y+3); y++;
94         MoveToEx (hdc, x, y, NULL);
95         LineTo (hdc, x, y+1);
96     }
97
98     SelectObject( hdc, hOldPen );
99 }
100
101 /* the vertical arrows are: 
102  *
103  * 01234567    01234567
104  * 1******        **  
105  * 2 ****        ****
106  * 3  **        ******
107  * 4
108  *
109  */
110 static void
111 PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up)
112 {
113     INT x, y, w, h;
114     HPEN hOldPen;
115     
116     w = r.right - r.left + 1;
117     h = r.bottom - r.top + 1;
118     if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
119         return;  /* refuse to draw partial arrow */
120
121     hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
122     if (up)
123     {
124         x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
125         y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3;
126         MoveToEx (hdc, x, y, NULL);
127         LineTo (hdc, x+5, y--); x++;
128         MoveToEx (hdc, x, y, NULL);
129         LineTo (hdc, x+3, y--); x++;
130         MoveToEx (hdc, x, y, NULL);
131         LineTo (hdc, x+1, y);
132     }
133     else
134     {
135         x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
136         y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
137         MoveToEx (hdc, x, y, NULL);
138         LineTo (hdc, x+5, y++); x++;
139         MoveToEx (hdc, x, y, NULL);
140         LineTo (hdc, x+3, y++); x++;
141         MoveToEx (hdc, x, y, NULL);
142         LineTo (hdc, x+1, y);
143     }
144
145     SelectObject( hdc, hOldPen );
146 }
147
148 static void
149 PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect,
150                  BOOL horz, BOOL topLeft, INT btnState)
151 {
152     HBRUSH   hBrush, hOldBrush;
153     RECT     rc = arrowRect;
154
155     if (!btnState) /* PGF_INVISIBLE */
156         return;
157
158     if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0))
159         return;  
160
161     hBrush = CreateSolidBrush(clrBk);
162     hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
163
164     FillRect(hdc, &rc, hBrush);
165
166     if (btnState == PGF_HOT) 
167     {
168        DrawEdge( hdc, &rc, BDR_RAISEDINNER, BF_RECT);
169        if (horz)
170            PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
171        else
172            PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
173     }
174     else if (btnState == PGF_NORMAL) 
175     {
176        DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
177        if (horz)
178            PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
179        else
180            PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
181     }
182     else if (btnState == PGF_DEPRESSED) 
183     {
184        DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
185        if (horz)
186            PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
187        else
188            PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
189     }
190     else if (btnState == PGF_GRAYED) 
191     {
192        DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
193        if (horz)
194        {
195            PAGER_DrawHorzArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
196            rc.left++, rc.top++; rc.right++, rc.bottom++;
197            PAGER_DrawHorzArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
198        }
199        else
200        {
201            PAGER_DrawVertArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
202            rc.left++, rc.top++; rc.right++, rc.bottom++;
203            PAGER_DrawVertArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
204        }
205     }
206
207     SelectObject( hdc, hOldBrush );
208     DeleteObject(hBrush);
209 }
210
211 /* << PAGER_GetDropTarget >> */
212
213 static inline LRESULT
214 PAGER_ForwardMouse (HWND hwnd, WPARAM wParam)
215 {
216     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
217     TRACE("[%04x]\n", hwnd);
218
219     infoPtr->bForward = (BOOL)wParam;
220
221     return 0;
222 }
223
224 static inline LRESULT
225 PAGER_GetButtonState (HWND hwnd, WPARAM wParam, LPARAM lParam)
226 {
227     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd); 
228     LRESULT btnState = PGF_INVISIBLE;
229     INT btn = (INT)lParam;
230     TRACE("[%04x]\n", hwnd);
231
232     if (btn == PGB_TOPORLEFT)
233         btnState = infoPtr->TLbtnState;
234     else if (btn == PGB_BOTTOMORRIGHT)
235         btnState = infoPtr->BRbtnState;
236
237     return btnState;
238 }
239
240
241 static inline LRESULT
242 PAGER_GetPos(HWND hwnd)
243 {
244     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd); 
245     TRACE("[%04x] returns %d\n", hwnd, infoPtr->nPos);
246     return (LRESULT)infoPtr->nPos;
247 }
248
249 static inline LRESULT
250 PAGER_GetButtonSize(HWND hwnd)
251 {
252     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd); 
253     TRACE("[%04x] returns %d\n", hwnd, infoPtr->nButtonSize);
254     return (LRESULT)infoPtr->nButtonSize;
255 }
256
257 static inline LRESULT
258 PAGER_GetBorder(HWND hwnd)
259 {
260     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd); 
261     TRACE("[%04x] returns %d\n", hwnd, infoPtr->nBorder);
262     return (LRESULT)infoPtr->nBorder;
263 }
264
265 static inline LRESULT
266 PAGER_GetBkColor(HWND hwnd)
267 {
268     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd); 
269     TRACE("[%04x] returns %06lx\n", hwnd, infoPtr->clrBk);
270     return (LRESULT)infoPtr->clrBk;
271 }
272
273 static void 
274 PAGER_CalcSize (HWND hwnd, INT* size, BOOL getWidth) 
275 {
276     NMPGCALCSIZE nmpgcs;
277     ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE));
278     nmpgcs.hdr.hwndFrom = hwnd;
279     nmpgcs.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
280     nmpgcs.hdr.code = PGN_CALCSIZE;
281     nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT;
282     nmpgcs.iWidth = getWidth ? *size : 0;
283     nmpgcs.iHeight = getWidth ? 0 : *size;
284     SendMessageA (GetParent (hwnd), WM_NOTIFY,
285                   (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs);
286
287     *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight;
288
289     TRACE("[%04x] PGN_CALCSIZE returns %s=%d\n", hwnd,
290                   getWidth ? "width" : "height", *size);
291 }
292
293 static void
294 PAGER_PositionChildWnd(HWND hwnd, PAGER_INFO* infoPtr)
295 {
296     if (infoPtr->hwndChild)
297     {
298         RECT rcClient;
299         int nPos = infoPtr->nPos;
300
301         /* compensate for a grayed btn, which will soon become invisible */
302         if (infoPtr->TLbtnState == PGF_GRAYED)
303             nPos += infoPtr->nButtonSize;
304
305         GetClientRect(hwnd, &rcClient);
306
307         if (PAGER_IsHorizontal(hwnd))
308         {
309             int wndSize = max(0, rcClient.right - rcClient.left);
310             if (infoPtr->nWidth < wndSize)
311                 infoPtr->nWidth = wndSize;
312
313             TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd,
314                          infoPtr->nWidth, infoPtr->nHeight,
315                          -nPos, 0);
316             SetWindowPos(infoPtr->hwndChild, 0,
317                          -nPos, 0,
318                          infoPtr->nWidth, infoPtr->nHeight,
319                          SWP_NOZORDER);
320         }
321         else
322         {
323             int wndSize = max(0, rcClient.bottom - rcClient.top);
324             if (infoPtr->nHeight < wndSize)
325                 infoPtr->nHeight = wndSize;
326
327             TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd, 
328                          infoPtr->nWidth, infoPtr->nHeight,
329                          0, -nPos);
330             SetWindowPos(infoPtr->hwndChild, 0,
331                          0, -nPos,
332                          infoPtr->nWidth, infoPtr->nHeight,
333                          SWP_NOZORDER);
334         }
335
336         InvalidateRect(infoPtr->hwndChild, NULL, TRUE);
337     }
338 }
339
340 static INT
341 PAGER_GetScrollRange(HWND hwnd, PAGER_INFO* infoPtr)
342 {
343     INT scrollRange = 0;
344
345     if (infoPtr->hwndChild)
346     {
347         INT wndSize, childSize;
348         RECT wndRect;
349         GetWindowRect(hwnd, &wndRect);
350
351         if (PAGER_IsHorizontal(hwnd))
352         {
353             wndSize = wndRect.right - wndRect.left;
354             PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
355             childSize = infoPtr->nWidth;
356         }
357         else
358         {
359             wndSize = wndRect.bottom - wndRect.top;
360             PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
361             childSize = infoPtr->nHeight;
362         }
363
364         TRACE("childSize = %d,  wndSize = %d\n", childSize, wndSize);
365         if (childSize > wndSize)
366             scrollRange = childSize - wndSize + infoPtr->nButtonSize;
367     }
368
369     TRACE("[%04x] returns %d\n", hwnd, scrollRange);
370     return scrollRange;
371 }
372
373 static void 
374 PAGER_GrayAndRestoreBtns(PAGER_INFO* infoPtr, INT scrollRange,
375                          BOOL* needsResize, BOOL* needsRepaint)
376 {
377     if (infoPtr->nPos > 0)
378     {
379         *needsResize |= !infoPtr->TLbtnState; /* PGF_INVISIBLE */
380         if (infoPtr->TLbtnState != PGF_DEPRESSED)
381             infoPtr->TLbtnState = PGF_NORMAL;
382     }
383     else
384     {
385         *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
386         infoPtr->TLbtnState = PGF_GRAYED;
387     }
388
389     if (scrollRange <= 0)
390     {
391         *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
392         infoPtr->TLbtnState = PGF_GRAYED;
393         *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
394         infoPtr->BRbtnState = PGF_GRAYED;
395     }
396     else if (infoPtr->nPos < scrollRange)
397     {
398         *needsResize |= !infoPtr->BRbtnState; /* PGF_INVISIBLE */
399         if (infoPtr->BRbtnState != PGF_DEPRESSED)
400             infoPtr->BRbtnState = PGF_NORMAL;
401     }
402     else
403     {
404         *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
405         infoPtr->BRbtnState = PGF_GRAYED;
406     }
407 }
408
409
410 static void 
411 PAGER_NormalizeBtns(PAGER_INFO* infoPtr, BOOL* needsRepaint)
412 {
413     if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED))
414     {
415         infoPtr->TLbtnState = PGF_NORMAL;
416         *needsRepaint = TRUE;
417     }
418
419     if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED))
420     {
421         infoPtr->BRbtnState = PGF_NORMAL;
422         *needsRepaint = TRUE;
423     }
424 }
425
426 static void 
427 PAGER_HideGrayBtns(PAGER_INFO* infoPtr, BOOL* needsResize)
428 {
429     if (infoPtr->TLbtnState == PGF_GRAYED)
430     {
431         infoPtr->TLbtnState = PGF_INVISIBLE;
432         *needsResize = TRUE;
433     }
434
435     if (infoPtr->BRbtnState == PGF_GRAYED)
436     {
437         infoPtr->BRbtnState = PGF_INVISIBLE;
438         *needsResize = TRUE;
439     }
440 }
441
442 static void
443 PAGER_UpdateBtns(HWND hwnd, PAGER_INFO *infoPtr,
444                  INT scrollRange, BOOL hideGrayBtns)
445 {
446     BOOL resizeClient = FALSE;
447     BOOL repaintBtns = FALSE;
448
449     if (scrollRange < 0)
450         PAGER_NormalizeBtns(infoPtr, &repaintBtns);
451     else
452         PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
453
454     if (hideGrayBtns)
455         PAGER_HideGrayBtns(infoPtr, &resizeClient);
456
457     if (resizeClient) /* initiate NCCalcSize to resize client wnd */ {
458         SetWindowPos(hwnd, 0,0,0,0,0, 
459                      SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
460                      SWP_NOZORDER | SWP_NOACTIVATE);
461     }
462
463     if (repaintBtns)
464         SendMessageA(hwnd, WM_NCPAINT, 0, 0); 
465 }
466
467 static LRESULT  
468 PAGER_SetPos(HWND hwnd, INT newPos, BOOL fromBtnPress)
469 {
470     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
471     INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
472     INT oldPos = infoPtr->nPos;
473
474     if ((scrollRange <= 0) || (newPos < 0))
475         infoPtr->nPos = 0;
476     else if (newPos > scrollRange)
477         infoPtr->nPos = scrollRange;
478     else
479         infoPtr->nPos = newPos;
480
481     TRACE("[%04x] pos=%d\n", hwnd, infoPtr->nPos);
482
483     if (infoPtr->nPos != oldPos)
484     {
485         /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
486         PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, !fromBtnPress);
487         PAGER_PositionChildWnd(hwnd, infoPtr);
488     }
489
490     return 0;
491 }
492
493 static LRESULT
494 PAGER_HandleWindowPosChanging(HWND hwnd, WPARAM wParam, WINDOWPOS *winpos)
495 {
496     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
497
498     if (infoPtr->bNoResize && !(winpos->flags & SWP_NOSIZE))
499     {
500         /* don't let the app resize the nonscrollable dimension of a control
501          * that was created with CCS_NORESIZE style
502          * (i.e. height for a horizontal pager, or width for a vertical one) */
503
504         /* except if the current dimension is 0 and app is setting for
505          * first time, then save amount as dimension. - GA 8/01 */
506
507         if (PAGER_IsHorizontal(hwnd))
508             if (!infoPtr->nHeight && winpos->cy)
509                 infoPtr->nHeight = winpos->cy;
510             else
511                 winpos->cy = infoPtr->nHeight;
512         else
513             if (!infoPtr->nWidth && winpos->cx)
514                 infoPtr->nWidth = winpos->cx;
515             else
516                 winpos->cx = infoPtr->nWidth;
517         return 0;
518     }
519
520     DefWindowProcA (hwnd, WM_WINDOWPOSCHANGING, wParam, (LPARAM)winpos);
521
522     return 1;
523 }
524
525 static INT 
526 PAGER_SetFixedWidth(HWND hwnd, PAGER_INFO* infoPtr)
527 {
528   /* Must set the non-scrollable dimension to be less than the full height/width
529    * so that NCCalcSize is called.  The Msoft docs mention 3/4 factor for button
530    * size, and experimentation shows that affect is almost right. */
531
532     RECT wndRect;
533     INT delta, h;
534     GetWindowRect(hwnd, &wndRect);
535
536     /* see what the app says for btn width */
537     PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
538
539     if (infoPtr->bNoResize)
540     {
541         delta = wndRect.right - wndRect.left - infoPtr->nWidth;
542         if (delta > infoPtr->nButtonSize)
543             infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3;
544         else if (delta > 0)
545             infoPtr->nWidth +=  infoPtr->nButtonSize / 3;
546     }
547
548     h = wndRect.bottom - wndRect.top + infoPtr->nButtonSize;
549
550     TRACE("[%04x] infoPtr->nWidth set to %d\n",
551                hwnd, infoPtr->nWidth);
552
553     return h;
554 }
555
556 static INT 
557 PAGER_SetFixedHeight(HWND hwnd, PAGER_INFO* infoPtr)
558 {
559   /* Must set the non-scrollable dimension to be less than the full height/width
560    * so that NCCalcSize is called.  The Msoft docs mention 3/4 factor for button
561    * size, and experimentation shows that affect is almost right. */
562
563     RECT wndRect;
564     INT delta, w;
565     GetWindowRect(hwnd, &wndRect);
566
567     /* see what the app says for btn height */
568     PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
569
570     if (infoPtr->bNoResize)
571     {
572         delta = wndRect.bottom - wndRect.top - infoPtr->nHeight;
573         if (delta > infoPtr->nButtonSize)
574             infoPtr->nHeight += infoPtr->nButtonSize;
575         else if (delta > 0)
576             infoPtr->nHeight +=  infoPtr->nButtonSize / 3;
577     }
578
579     w = wndRect.right - wndRect.left + infoPtr->nButtonSize;
580
581     TRACE("[%04x] infoPtr->nHeight set to %d\n",
582                hwnd, infoPtr->nHeight);
583
584     return w;
585 }
586
587 static LRESULT
588 PAGER_RecalcSize(HWND hwnd)
589 {
590     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
591
592     TRACE("[%04x]\n", hwnd);
593
594     if (infoPtr->hwndChild)
595     {
596         INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
597
598         if (scrollRange <= 0)
599         {
600             infoPtr->nPos = -1;
601             PAGER_SetPos(hwnd, 0, FALSE);
602         }
603         else 
604         {
605             PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, TRUE);
606             PAGER_PositionChildWnd(hwnd, infoPtr);
607         }
608     }
609
610     return 1;
611 }
612
613
614 static LRESULT
615 PAGER_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
616 {
617     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
618     COLORREF clrTemp = infoPtr->clrBk;
619
620     infoPtr->clrBk = (COLORREF)lParam;
621     TRACE("[%04x] %06lx\n", hwnd, infoPtr->clrBk);
622
623     PAGER_RecalcSize(hwnd);
624     SendMessageA(hwnd, WM_NCPAINT, (WPARAM)0, (LPARAM)0);
625
626     return (LRESULT)clrTemp;
627 }
628
629
630 static LRESULT
631 PAGER_SetBorder (HWND hwnd, WPARAM wParam, LPARAM lParam)
632 {
633     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
634     INT nTemp = infoPtr->nBorder;
635
636     infoPtr->nBorder = (INT)lParam;
637     TRACE("[%04x] %d\n", hwnd, infoPtr->nBorder);
638
639     PAGER_RecalcSize(hwnd);
640
641     return (LRESULT)nTemp;
642 }
643
644
645 static LRESULT
646 PAGER_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
647 {
648     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
649     INT nTemp = infoPtr->nButtonSize;
650
651     infoPtr->nButtonSize = (INT)lParam;
652     TRACE("[%04x] %d\n", hwnd, infoPtr->nButtonSize);
653
654     PAGER_RecalcSize(hwnd);
655
656     return (LRESULT)nTemp;
657 }
658
659
660 static LRESULT
661 PAGER_SetChild (HWND hwnd, WPARAM wParam, LPARAM lParam)
662 {
663     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
664     INT hw;
665
666     infoPtr->hwndChild = IsWindow ((HWND)lParam) ? (HWND)lParam : 0;
667
668     if (infoPtr->hwndChild)
669     {
670         TRACE("[%04x] hwndChild=%04x\n", hwnd, infoPtr->hwndChild);
671
672         if (PAGER_IsHorizontal(hwnd)) {
673             hw = PAGER_SetFixedHeight(hwnd, infoPtr);
674             /* adjust non-scrollable dimension to fit the child */
675             SetWindowPos(hwnd, 0, 0,0, hw, infoPtr->nHeight, 
676                          SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
677                          SWP_NOSIZE | SWP_NOACTIVATE);
678         }
679         else {
680             hw = PAGER_SetFixedWidth(hwnd, infoPtr);
681             /* adjust non-scrollable dimension to fit the child */
682             SetWindowPos(hwnd, 0, 0,0, infoPtr->nWidth, hw, 
683                          SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
684                          SWP_NOSIZE | SWP_NOACTIVATE);
685         }
686
687         /* position child within the page scroller */
688         SetWindowPos(infoPtr->hwndChild, HWND_TOP,
689                      0,0,0,0,
690                      SWP_SHOWWINDOW | SWP_NOSIZE);  /* native is 0 */
691
692         infoPtr->nPos = -1;
693         PAGER_SetPos(hwnd, 0, FALSE);
694     }
695
696     return 0;
697 }
698
699 static void
700 PAGER_Scroll(HWND hwnd, INT dir)
701 {
702     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
703     NMPGSCROLL nmpgScroll;
704     RECT rcWnd;
705
706     if (infoPtr->hwndChild)
707     {
708         ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
709         nmpgScroll.hdr.hwndFrom = hwnd;
710         nmpgScroll.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
711         nmpgScroll.hdr.code = PGN_SCROLL;
712
713         GetWindowRect(hwnd, &rcWnd);  
714         GetClientRect(hwnd, &nmpgScroll.rcParent);  
715         nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
716         nmpgScroll.iDir = dir;
717
718         if (PAGER_IsHorizontal(hwnd))
719         {
720             nmpgScroll.iScroll = rcWnd.right - rcWnd.left;
721             nmpgScroll.iXpos = infoPtr->nPos;
722         }
723         else
724         {
725             nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top;
726             nmpgScroll.iYpos = infoPtr->nPos;
727         }
728         nmpgScroll.iScroll -= 2*infoPtr->nButtonSize;
729   
730         SendMessageA (hwnd, WM_NOTIFY,
731                     (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll);
732   
733         TRACE("[%04x] PGN_SCROLL returns iScroll=%d\n", hwnd, nmpgScroll.iScroll);
734
735         if (nmpgScroll.iScroll > 0)
736         {
737             infoPtr->direction = dir;
738
739             if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
740                 PAGER_SetPos(hwnd, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
741             else
742                 PAGER_SetPos(hwnd, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
743         }
744         else
745             infoPtr->direction = -1;
746     }
747 }
748
749 static LRESULT
750 PAGER_FmtLines(HWND hwnd)
751 {
752     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
753
754     /* initiate NCCalcSize to resize client wnd and get size */
755     SetWindowPos(hwnd, 0, 0,0,0,0, 
756                  SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
757                  SWP_NOZORDER | SWP_NOACTIVATE);
758
759     SetWindowPos(infoPtr->hwndChild, 0, 
760                  0,0,infoPtr->nWidth,infoPtr->nHeight, 
761                  0);
762
763     return DefWindowProcA (hwnd, EM_FMTLINES, 0, 0);
764 }
765
766 static LRESULT
767 PAGER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
768 {
769     PAGER_INFO *infoPtr;
770     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
771
772     /* allocate memory for info structure */
773     infoPtr = (PAGER_INFO *)COMCTL32_Alloc (sizeof(PAGER_INFO));
774     SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
775
776     /* set default settings */
777     infoPtr->hwndChild = (HWND)NULL;
778     infoPtr->bNoResize = dwStyle & CCS_NORESIZE;
779     infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
780     infoPtr->nBorder = 0;
781     infoPtr->nButtonSize = 12;
782     infoPtr->nPos = 0;
783     infoPtr->nWidth = 0;
784     infoPtr->nHeight = 0;
785     infoPtr->bForward = FALSE;
786     infoPtr->TLbtnState = PGF_INVISIBLE;
787     infoPtr->BRbtnState = PGF_INVISIBLE;
788     infoPtr->direction = -1;
789
790     if (dwStyle & PGS_AUTOSCROLL)
791         FIXME("[%04x] Autoscroll style is not implemented yet.\n", hwnd);
792     if (dwStyle & PGS_DRAGNDROP)
793         FIXME("[%04x] Drag and Drop style is not implemented yet.\n", hwnd);
794     /*
795          * If neither horizontal nor vertical style specified, default to vertical.
796          * This is probably not necessary, since the style may be set later on as
797          * the control is initialized, but just in case it isn't, set it here.
798          */
799     if (!(dwStyle & PGS_HORZ) && !(dwStyle & PGS_VERT))
800     {
801         dwStyle |= PGS_VERT;
802         SetWindowLongA(hwnd, GWL_STYLE, dwStyle);
803     }
804
805     return 0;
806 }
807
808
809 static LRESULT
810 PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
811 {
812     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
813     /* free pager info data */
814     COMCTL32_Free (infoPtr);
815     SetWindowLongA (hwnd, 0, 0);
816     return 0;
817 }
818
819 static LRESULT
820 PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
821 {
822     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
823     LPRECT lpRect = (LPRECT)lParam;
824     RECT rcChildw, rcmyw, wnrc, lbrc, rbrc;
825     POINT cursor;
826
827     /*
828      * lParam points to a RECT struct.  On entry, the struct
829      * contains the proposed wnd rectangle for the window. 
830      * On exit, the struct should contain the screen
831      * coordinates of the corresponding window's client area.
832      */
833         
834     DefWindowProcA (hwnd, WM_NCCALCSIZE, wParam, lParam);
835
836     if (PAGER_IsHorizontal(hwnd))
837     {
838         infoPtr->nWidth = lpRect->right - lpRect->left;
839         PAGER_CalcSize (hwnd, &infoPtr->nWidth, TRUE);
840         GetWindowRect (infoPtr->hwndChild, &rcChildw);
841         MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
842         GetCursorPos (&cursor);
843         GetWindowRect (hwnd, &rcmyw);
844         if (PtInRect (&rcmyw, cursor)) {
845             GetWindowRect (hwnd, &wnrc);
846             lbrc = wnrc;
847             lbrc.right = lbrc.left + infoPtr->nButtonSize;
848             rbrc = wnrc;
849             rbrc.left = rbrc.right - infoPtr->nButtonSize;
850             TRACE("horz lb rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
851                   lbrc.left, lbrc.top, lbrc.right, lbrc.bottom,
852                   rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
853             if (PtInRect (&lbrc, cursor) && infoPtr->TLbtnState)
854                 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
855             if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
856                 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
857         }
858         if (infoPtr->TLbtnState) /* != PGF_INVISIBLE */
859             lpRect->left += infoPtr->nButtonSize;
860         if (infoPtr->BRbtnState) 
861             lpRect->right -= infoPtr->nButtonSize;
862     }
863     else
864     {
865         /* native does: (from trace of IE4 opening "Favorites" frame) 
866          *        DefWindowProc
867          *        WM_NOITFY  PGN_CALCSIZE w/ dwFlag=2
868          *        GetWindowRect (child, &rc)
869          *        MapWindowPoints (0, syspager, &rc, 2)
870          *        GetCursorPos( &cur )
871          *        GetWindowRect (syspager, &rc2)
872          *        PtInRect (&rc2, cur.x, cur.y) rtns 0
873          *        returns with rect empty
874          */
875         infoPtr->nHeight = lpRect->bottom - lpRect->top;
876         PAGER_CalcSize (hwnd, &infoPtr->nHeight, FALSE);
877         GetWindowRect (infoPtr->hwndChild, &rcChildw);
878         MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
879         GetCursorPos (&cursor);
880         GetWindowRect (hwnd, &rcmyw);
881         if (PtInRect (&rcmyw, cursor)) {
882
883             /* native does:
884              *    GetWindowRect(pager, &rc)
885              *    PtInRect(btn-left????, cur.x, cur.y)
886              *    if true -> ???
887              *    PtInRect(btn-right????, cur.x, cur.y)
888              *    if true
889              *      RedrawWindow(pager, 0, 0, 5)
890              *      return TRUE
891              */
892
893             GetWindowRect (hwnd, &wnrc);
894             lbrc = wnrc;
895             lbrc.right = lbrc.left + infoPtr->nButtonSize;
896             rbrc = wnrc;
897             rbrc.left = rbrc.right - infoPtr->nButtonSize;
898             TRACE("vert lb rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
899                   lbrc.left, lbrc.top, lbrc.right, lbrc.bottom,
900                   rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
901             if (PtInRect (&lbrc, cursor) && infoPtr->TLbtnState)
902                 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
903             if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
904                 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
905         }
906         if (infoPtr->TLbtnState)
907             lpRect->top += infoPtr->nButtonSize;
908         if (infoPtr->BRbtnState)
909             lpRect->bottom -= infoPtr->nButtonSize;
910         /* ???? */
911         if ((lpRect->bottom < 0) || (lpRect->bottom > infoPtr->nHeight))
912             lpRect->bottom = infoPtr->nHeight;
913     }
914
915     TRACE("[%04x] client rect set to %dx%d at (%d,%d)\n", hwnd,
916                 lpRect->right-lpRect->left,
917                 lpRect->bottom-lpRect->top,
918                 lpRect->left, lpRect->top);
919
920     return 0;
921 }
922
923 static LRESULT
924 PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
925 {
926     PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
927     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
928     RECT rcWindow, rcBottomRight, rcTopLeft;
929     HDC hdc;
930     BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
931
932     if (dwStyle & WS_MINIMIZE)
933         return 0;
934
935     DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
936
937     if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
938         return 0;
939
940     GetWindowRect (hwnd, &rcWindow);
941     OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
942
943     rcTopLeft = rcBottomRight = rcWindow;
944     if (bHorizontal)
945     {
946         rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
947         rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
948     }
949     else
950     {
951         rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
952         rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
953     }
954
955     PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
956                      bHorizontal, TRUE, infoPtr->TLbtnState);
957     PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
958                      bHorizontal, FALSE, infoPtr->BRbtnState); 
959
960     ReleaseDC( hwnd, hdc );
961     return 0;
962 }
963
964 static INT 
965 PAGER_HitTest (HWND hwnd, LPPOINT pt)
966 {
967     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
968     RECT clientRect;
969     BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
970
971     GetClientRect (hwnd, &clientRect);
972
973     if (PtInRect(&clientRect, *pt))
974     {
975        /* TRACE("HTCLIENT\n"); */
976         return HTCLIENT;
977     }
978
979     if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
980     {
981         if (bHorizontal)
982         {
983             if (pt->x < clientRect.left)
984             {
985                 /* TRACE("HTLEFT\n"); */
986                 return HTLEFT;
987             }
988         }
989         else
990         {
991             if (pt->y < clientRect.top)
992             {
993                 /* TRACE("HTTOP\n"); */
994                 return HTTOP;
995             }
996         }
997     }
998
999     if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
1000     {
1001         if (bHorizontal)
1002         {
1003             if (pt->x > clientRect.right)
1004             {
1005                 /* TRACE("HTRIGHT\n"); */
1006                 return HTRIGHT;
1007             }
1008         }
1009         else
1010         {
1011             if (pt->y > clientRect.bottom)
1012             {
1013                /* TRACE("HTBOTTOM\n"); */
1014                 return HTBOTTOM;
1015             }
1016         }
1017     }
1018
1019     /* TRACE("HTNOWHERE\n"); */
1020     return HTNOWHERE;
1021 }
1022
1023 static LRESULT
1024 PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
1025 {
1026     POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
1027     ScreenToClient (hwnd, &pt);
1028     return PAGER_HitTest(hwnd, &pt);
1029 }
1030
1031 static LRESULT
1032 PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1033 {
1034     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1035     BOOL notCaptured = FALSE;
1036
1037     switch(LOWORD(lParam))
1038     {
1039         case HTLEFT:
1040         case HTTOP:
1041             if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
1042                 infoPtr->TLbtnState = PGF_HOT;
1043             break;
1044         case HTRIGHT:
1045         case HTBOTTOM:
1046             if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
1047                infoPtr->BRbtnState = PGF_HOT;
1048             break;
1049         default:
1050             return FALSE;
1051     }
1052
1053     if (notCaptured)
1054     {
1055         TRACKMOUSEEVENT trackinfo;
1056
1057         TRACE("[%04x] SetCapture\n", hwnd);
1058         SetCapture(hwnd);
1059
1060         trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1061         trackinfo.dwFlags = TME_QUERY;
1062         trackinfo.hwndTrack = hwnd;
1063         trackinfo.dwHoverTime = HOVER_DEFAULT;
1064
1065         /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
1066         _TrackMouseEvent(&trackinfo);
1067
1068         /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
1069         if(!(trackinfo.dwFlags & TME_LEAVE)) {
1070             trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
1071  
1072            /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
1073            /* and can properly deactivate the hot button */
1074            _TrackMouseEvent(&trackinfo);
1075         }
1076
1077         SendMessageA(hwnd, WM_NCPAINT, 0, 0); 
1078     }
1079
1080     return TRUE;
1081 }
1082
1083 static LRESULT
1084 PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
1085 {
1086     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1087
1088     KillTimer (hwnd, TIMERID1);
1089     KillTimer (hwnd, TIMERID2);
1090
1091     TRACE("[%04x] ReleaseCapture\n", hwnd);
1092     ReleaseCapture();
1093
1094     /* Notify parent of released mouse capture */
1095     {
1096         NMHDR nmhdr;
1097         ZeroMemory (&nmhdr, sizeof (NMHDR));
1098         nmhdr.hwndFrom = hwnd;
1099         nmhdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
1100         nmhdr.code = NM_RELEASEDCAPTURE;
1101         SendMessageA (GetParent(hwnd), WM_NOTIFY,
1102                         (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1103     }
1104
1105     /* make HOT btns NORMAL and hide gray btns */
1106     PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);
1107
1108     return TRUE;
1109 }
1110
1111 static LRESULT
1112 PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1113 {
1114     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1115     BOOL repaintBtns = FALSE;
1116     POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
1117     INT hit;
1118
1119     TRACE("[%04x]\n", hwnd);
1120         
1121     hit = PAGER_HitTest(hwnd, &pt);
1122
1123     /* put btn in DEPRESSED state */
1124     if (hit == HTLEFT || hit == HTTOP)
1125     {
1126         repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
1127         infoPtr->TLbtnState = PGF_DEPRESSED;
1128         SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0); 
1129     }
1130     else if (hit == HTRIGHT || hit == HTBOTTOM)
1131     {
1132         repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
1133         infoPtr->BRbtnState = PGF_DEPRESSED;
1134         SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0); 
1135     }
1136
1137     if (repaintBtns)
1138         SendMessageA(hwnd, WM_NCPAINT, 0, 0); 
1139
1140     switch(hit)
1141     {
1142     case HTLEFT:
1143         TRACE("[%04x] PGF_SCROLLLEFT\n", hwnd);
1144         PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
1145         break;
1146     case HTTOP:
1147         TRACE("[%04x] PGF_SCROLLUP\n", hwnd);
1148         PAGER_Scroll(hwnd, PGF_SCROLLUP);
1149         break;
1150     case HTRIGHT:
1151         TRACE("[%04x] PGF_SCROLLRIGHT\n", hwnd);
1152         PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
1153         break;
1154     case HTBOTTOM:
1155         TRACE("[%04x] PGF_SCROLLDOWN\n", hwnd);
1156         PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
1157         break;
1158     default:
1159         break;
1160     }
1161
1162     return TRUE;
1163 }
1164
1165 static LRESULT
1166 PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1167 {
1168     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1169     TRACE("[%04x]\n", hwnd);
1170
1171     KillTimer (hwnd, TIMERID1);
1172     KillTimer (hwnd, TIMERID2);
1173
1174     /* make PRESSED btns NORMAL but don't hide gray btns */
1175     PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
1176
1177     return 0;
1178 }
1179
1180 static LRESULT
1181 PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1182 {
1183     POINT pt, ptorig;
1184     HDC hdc = (HDC)wParam;
1185     HWND parent;
1186
1187     /* native does:
1188      *   parent = GetParent(pager)
1189      *   pt.x=0; pt.y=0; ?????
1190      *   MapWindowPoints(pager, parent, &pt, 1)
1191      *   OffsetWindowOrgEx(hdc, pt.x, pt.y, &ptorg)
1192      *   SendMessageA(parent, WM_ERASEBKGND, hdc, 0)
1193      *   SetWindowOrgEx(hdc, 0, 0, 0)
1194      */
1195
1196     pt.x = 0;
1197     pt.y = 0;
1198     parent = GetParent(hwnd);
1199     MapWindowPoints(hwnd, parent, &pt, 1);
1200     OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
1201     SendMessageA (parent, WM_ERASEBKGND, wParam, lParam);
1202     SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
1203
1204
1205 #if 0
1206     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1207     HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
1208     RECT rect;
1209
1210     GetClientRect (hwnd, &rect);
1211     FillRect ((HDC)wParam, &rect, hBrush);
1212
1213     /* background color of the child should be the same as the pager */
1214     if (infoPtr->hwndChild)
1215     {
1216         GetClientRect (infoPtr->hwndChild, &rect);
1217         FillRect ((HDC)wParam, &rect, hBrush);
1218     }
1219
1220     DeleteObject (hBrush);
1221 #endif
1222
1223     return TRUE;
1224 }
1225
1226
1227 static LRESULT
1228 PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1229 {
1230     /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
1231
1232     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1233     TRACE("[%04x] %dx%d\n", hwnd, LOWORD(lParam), HIWORD(lParam));
1234
1235     if (PAGER_IsHorizontal(hwnd))
1236         infoPtr->nHeight = HIWORD(lParam);
1237     else
1238         infoPtr->nWidth = LOWORD(lParam);
1239
1240     return PAGER_RecalcSize(hwnd);
1241 }
1242
1243
1244 static LRESULT WINAPI
1245 PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1246 {
1247     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1248
1249     if (!infoPtr && (uMsg != WM_CREATE))
1250         return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1251
1252     switch (uMsg)
1253     {
1254         case EM_FMTLINES:
1255             return PAGER_FmtLines(hwnd);
1256
1257         case PGM_FORWARDMOUSE:
1258             return PAGER_ForwardMouse (hwnd, wParam);
1259
1260         case PGM_GETBKCOLOR:
1261             return PAGER_GetBkColor(hwnd);
1262
1263         case PGM_GETBORDER:
1264             return PAGER_GetBorder(hwnd);
1265
1266         case PGM_GETBUTTONSIZE:
1267             return PAGER_GetButtonSize(hwnd);
1268
1269         case PGM_GETPOS:
1270             return PAGER_GetPos(hwnd);
1271
1272         case PGM_GETBUTTONSTATE:
1273             return PAGER_GetButtonState (hwnd, wParam, lParam);
1274
1275 /*      case PGM_GETDROPTARGET: */
1276
1277         case PGM_RECALCSIZE:
1278             return PAGER_RecalcSize(hwnd);
1279     
1280         case PGM_SETBKCOLOR:
1281             return PAGER_SetBkColor (hwnd, wParam, lParam);
1282
1283         case PGM_SETBORDER:
1284             return PAGER_SetBorder (hwnd, wParam, lParam);
1285
1286         case PGM_SETBUTTONSIZE:
1287             return PAGER_SetButtonSize (hwnd, wParam, lParam);
1288
1289         case PGM_SETCHILD:
1290             return PAGER_SetChild (hwnd, wParam, lParam);
1291
1292         case PGM_SETPOS:
1293             return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
1294
1295         case WM_CREATE:
1296             return PAGER_Create (hwnd, wParam, lParam);
1297
1298         case WM_DESTROY:
1299             return PAGER_Destroy (hwnd, wParam, lParam);
1300
1301         case WM_SIZE:
1302             return PAGER_Size (hwnd, wParam, lParam);
1303
1304         case WM_NCPAINT:
1305             return PAGER_NCPaint (hwnd, wParam, lParam);
1306
1307         case WM_WINDOWPOSCHANGING:
1308             return PAGER_HandleWindowPosChanging (hwnd, wParam, (WINDOWPOS*)lParam);
1309
1310         case WM_NCCALCSIZE:
1311             return PAGER_NCCalcSize (hwnd, wParam, lParam);
1312
1313         case WM_NCHITTEST:
1314             return PAGER_NCHitTest (hwnd, wParam, lParam);
1315
1316         case WM_SETCURSOR:
1317         {
1318             if (hwnd == (HWND)wParam)
1319                 return PAGER_SetCursor(hwnd, wParam, lParam);
1320             else /* its for the child */
1321                 return 0;
1322         }
1323
1324         case WM_MOUSEMOVE:
1325             if (infoPtr->bForward && infoPtr->hwndChild)
1326                 PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1327             return TRUE;                        
1328
1329         case WM_MOUSELEAVE:
1330             return PAGER_MouseLeave (hwnd, wParam, lParam);     
1331
1332         case WM_LBUTTONDOWN:
1333             return PAGER_LButtonDown (hwnd, wParam, lParam);
1334
1335         case WM_LBUTTONUP:
1336             return PAGER_LButtonUp (hwnd, wParam, lParam);
1337
1338         case WM_ERASEBKGND:
1339             return PAGER_EraseBackground (hwnd, wParam, lParam);
1340 /*
1341         case WM_PAINT:
1342             return PAGER_Paint (hwnd, wParam); 
1343 */
1344         case WM_TIMER:
1345             /* if initial timer, kill it and start the repeat timer */
1346             if (wParam == TIMERID1)
1347             {
1348                 KillTimer(hwnd, TIMERID1);
1349                 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);
1350             }
1351
1352             KillTimer(hwnd, TIMERID2);
1353             if (infoPtr->direction > 0)
1354             {
1355                 PAGER_Scroll(hwnd, infoPtr->direction);
1356                 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);          
1357             }
1358             break;
1359
1360         case WM_NOTIFY:
1361         case WM_COMMAND:
1362             return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
1363
1364         default:
1365             return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1366     }
1367
1368     return 0;
1369 }
1370
1371
1372 VOID
1373 PAGER_Register (void)
1374 {
1375     WNDCLASSA wndClass;
1376
1377     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1378     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1379     wndClass.lpfnWndProc   = (WNDPROC)PAGER_WindowProc;
1380     wndClass.cbClsExtra    = 0;
1381     wndClass.cbWndExtra    = sizeof(PAGER_INFO *);
1382     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
1383     wndClass.hbrBackground = 0;
1384     wndClass.lpszClassName = WC_PAGESCROLLERA;
1385  
1386     RegisterClassA (&wndClass);
1387 }
1388
1389
1390 VOID
1391 PAGER_Unregister (void)
1392 {
1393     UnregisterClassA (WC_PAGESCROLLERA, (HINSTANCE)NULL);
1394 }
1395